如何优化这个简单的PHP脚本?

如何优化这个简单的PHP脚本?,php,optimization,file,performance,Php,Optimization,File,Performance,第一个脚本通过AJAX请求为每个用户调用数次。它在不同的服务器上调用另一个脚本以获取文本文件的最后一行。它工作得很好,但我认为还有很大的改进空间,但我不是一个很好的PHP程序员,因此我希望在社区的帮助下,我可以优化它的速度和效率: 对该脚本发出的AJAX POST请求 <?php session_start(); $fileName = $_POST['textFile']; $result = file_get_contents($_SESSION['serverURL']."fileR

第一个脚本通过AJAX请求为每个用户调用数次。它在不同的服务器上调用另一个脚本以获取文本文件的最后一行。它工作得很好,但我认为还有很大的改进空间,但我不是一个很好的PHP程序员,因此我希望在社区的帮助下,我可以优化它的速度和效率:

对该脚本发出的AJAX POST请求

<?php session_start();
$fileName = $_POST['textFile'];
$result = file_get_contents($_SESSION['serverURL']."fileReader.php?textFile=$fileName");
echo $result;
?>

它向读取文本文件的外部脚本发出GET请求

<?php
$fileName = $_GET['textFile'];
if (file_exists('text/'.$fileName.'.txt')) {
    $lines = file('text/'.$fileName.'.txt');
    echo $lines[sizeof($lines)-1];
}
else{
    echo 0;
}
?>


我将感谢任何帮助。我认为在第一个脚本中可以做更多的改进。它做了一个昂贵的函数调用(file\u get\u contents),至少我认为它很昂贵

如果文件不变,则应缓存最后一行

如果文件正在更改,并且您可以控制生成它们的方式,那么根据行在其生命周期中的读取频率,反转写入顺序可能是一种改进,也可能不是一种改进

编辑:

您的服务器可以找出要写入日志的内容,将其放入memcache,然后将其写入日志。最后一行的请求可以从memcache而不是从文件读取中得到满足。

是您的朋友吗 它读取磁盘上的文件并将其流式传输到客户端

脚本1:

<?php
  session_start();
  // added basic argument filtering
  $fileName = preg_replace('/[^A-Za-z0-9_]/', '', $_POST['textFile']);

  $fileName = $_SESSION['serverURL'].'text/'.$fileName.'.txt';
  if (file_exists($fileName)) {

      // script 2 could be pasted here

      //for the entire file
      //readfile($fileName);

      //for just the last line
      $lines = file($fileName);
      echo $lines[count($lines)-1];


      exit(0);
  }

  echo 0;
?>

通过向脚本中添加缓存,可以进一步改进该脚本。但这更复杂。 非常的基本缓存可以是

脚本2:

<?php

  $lastModifiedTimeStamp filemtime($fileName);

  if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
      $browserCachedCopyTimestamp = strtotime(preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']));
      if ($browserCachedCopyTimestamp >= $lastModifiedTimeStamp) {
          header("HTTP/1.0 304 Not Modified");
          exit(0);
      }
  }

  header('Content-Length: '.filesize($fileName));
  header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + 604800)); // (3600 * 24 * 7)
  header('Last-Modified: '.date('D, d M Y H:i:s \G\M\T', $lastModifiedTimeStamp));
?>

此脚本应限制要返回的位置和文件类型

想象一下有人尝试这样做:

(或类似的东西)

试着找出发生延误的地方。。HTTP请求需要很长时间,还是文件太大以至于读取它需要很长时间

如果请求很慢,请尝试在本地缓存结果


如果文件很大,则可以设置cron作业,定期(或每次更改)提取文件的最后一行,并将其保存到其他脚本可以直接访问的文件中

第一件事:你真的需要优化它吗?这是用例中最慢的部分吗?你曾经验证过吗?如果您已经这样做了,请继续阅读:

您无法真正有效地优化第一个脚本:如果需要http请求,则需要http请求。如果可能的话,跳过http请求可能会提高性能(例如,如果第一个脚本可以访问第二个脚本将要操作的相同文件)

至于第二个脚本:将整个文件读入内存看起来确实有些开销,但如果文件很小,这是可以忽略的。代码看起来可读性很强,我会保持原样

但是,如果您的文件很大,您可能希望使用及其好友和


最可能的延迟源是跨服务器HTTP请求。如果文件很小,那么fopen/fread/fclose的成本与整个HTTP请求相比是微不足道的

(不久前,我使用HTTP检索图像,以友好方式生成基于图像的菜单。用本地文件读取代替HTTP请求将延迟从秒减少到十分之一秒。)

我认为直接访问文件服务器文件系统的明显解决方案是不可能的。如果不是,那么这是最好、最简单的选择

如果没有,您可以使用缓存。您只需发出HEAD请求并将时间戳与本地副本进行比较,而不是获取整个文件


此外,如果您是基于相同文件更新Ajax的许多客户端,您可能会考虑使用慧星(例如,流星)。它用于诸如聊天之类的事情,其中一个更改必须广播到多个客户端

谢谢你富有洞察力的答复。我以前没有使用过它(xdebug),但现在我正在研究它。我读到的文本文件不超过20行,行长约为5/6个字。那么,我就不会碰代码了。解释循环的开销甚至可能大于该大小文件的收益:)如果客户端只需要最后一行,您认为我应该使用它吗?“脚本1”替换您的2个脚本。readfile()读取整个文件并将其发送到浏览器。如果您不确定,请忘记“脚本2”是的,文件一直在更改。我喜欢最后一个想法,颠倒行的顺序,所以我只检索第一行。我需要我能获得的每一点性能提升!我知道它没有什么问题,因为它可以工作,但我只是在尝试改进它,因为这个脚本将被称为100000s of times.:)
# Do not forget to sanitize the file name here!
# An attacker could demand the last line of your password
# file or similar! ($fileName = '../../passwords.txt')
$filePointer = fopen($fileName, 'r');
$i = 1;
$chunkSize = 200;
# Read 200 byte chunks from the file and check if the chunk
# contains a newline
do {
    fseek($filePointer, -($i * $chunkSize), SEEK_END);
    $line = fread($filePointer, $i++ * $chunkSize);
} while (($pos = strrpos($line, "\n")) === false);
return substr($line, $pos + 1);