通过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_get_contents),至少我觉得它很贵!
答案 0 :(得分:1)
readfile是你的朋友 它读取磁盘上的文件并将其流式传输到客户端。
脚本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));
?>
答案 1 :(得分:1)
此脚本应限制它将返回的位置和文件类型。
想想有人试图这样做:
http://www.yoursite.com/yourscript.php?textFile=../../../etc/passwd(或类似的东西)
尝试找出延迟发生的位置.. HTTP请求需要很长时间,或者文件太大以至于读取时间很长。
如果请求很慢,请尝试在本地缓存结果。
如果文件很大,那么您可以设置一个cron作业,定期(或每次更改)提取文件的最后一行,并将其保存到您的其他脚本可以直接访问的文件中。
答案 2 :(得分:0)
如果文件不变,则应缓存最后一行。
如果文件正在更改并且您控制它们的生成方式,则可能会或可能不会改变反转订单行的写入,具体取决于在其生命周期内读取行的频率。
编辑:
您的服务器可以弄清楚它要写入日志的内容,将其放入内存缓存中,然后将其写入日志。最后一行的请求可以通过memcache而不是文件读取来完成。
答案 3 :(得分:0)
首先要做的事情:你真的需要优化吗?这是你用例中最慢的部分吗?您是否使用xdebug来验证?如果你已经这样做了,请继续阅读:
您无法真正有效地优化第一个脚本:如果您需要http请求,则需要http请求。跳过http请求可能是性能提升,但是,如果可能的话(即如果第一个脚本可以访问第二个脚本将操作的相同文件)。
至于第二个脚本:将整个文件读入内存确实看起来有些开销,但如果文件很小,则可以忽略不计。代码看起来非常易读,在这种情况下我会保留原样。
但是,如果您的文件较大,则可能需要使用fopen()
及其朋友fseek()
和fread()
# 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);
答案 4 :(得分:0)
最可能的延迟来源是跨服务器HTTP请求。如果文件很小,fopen / fread / fclose的成本与整个HTTP请求相比毫无结果。
(不久前,我使用HTTP来检索图像以动态生成基于图像的菜单。通过本地文件读取替换HTTP请求可将延迟从秒减少到十分之一秒。)
我认为直接访问文件服务器文件系统的明显解决方案是不可能的。如果没有,那么这是最好也是最简单的选择。
如果没有,您可以使用缓存。您只需发出HEAD请求并将时间戳与本地副本进行比较,而不是获取整个文件。
此外,如果您基于相同的文件更新了许多客户端,您可能会考虑使用comet(例如meteor)。它用于聊天等内容,必须向多个客户广播单个更改。