我需要通过PHP发送所有Web资源请求以进行用户身份验证,并且不通过Apache直接提供任何文件。这是我的.htaccess:
# All requests are routed to PHP (images, css, js, everything)
RewriteRule ^(.*)$ index.php?query=$1&%{QUERY_STRING} [L]
然后我处理请求,验证用户是否有权访问资源,然后使用以下PHP读取函数输出任何不需要处理的文件。事实证明,与让Apache做其事情相比,这是非常缓慢的。
有人可以推荐一种方法来帮助我提高性能吗?
static function read($path) {
if(!File::exists($path)) {
//echo 'File does not exist.';
header("HTTP/1.0 404 Not Found");
return;
}
$fileName = String::explode('/', $path);
if(Arr::size($fileName) > 0) {
$fileName = $fileName[Arr::size($fileName) - 1];
}
$size = File::size($path);
$time = date('r', filemtime($path));
$fm = @fopen($path, 'rb');
if(!$fm) {
header("HTTP/1.0 505 Internal server error");
return;
}
$begin = 0;
$end = $size;
if(isset($_SERVER['HTTP_RANGE'])) {
if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
$begin = intval($matches[0]);
if(!empty($matches[1]))
$end = intval($matches[1]);
}
}
if ($begin > 0 || $end < $size)
header('HTTP/1.0 206 Partial Content');
else
header('HTTP/1.0 200 OK');
// Find the mime type of the file
$mimeType = 'application/octet-stream';
//$finfo = @new finfo(FILEINFO_MIME);
//print_r($finfo);
//$fres = @$finfo->file($path);
//if(is_string($fres) && !empty($fres)) {
//$mimeType = $fres;
//}
// Handle CSS files
if(String::endsWith('.css', $path)) {
$mimeType = 'text/css';
}
header('Content-Type: '.$mimeType);
//header('Cache-Control: public, must-revalidate, max-age=0');
//header('Pragma: no-cache');
header('Accept-Ranges: bytes');
header('Content-Length:' . ($end - $begin));
header("Content-Range: bytes $begin-$end/$size");
header("Content-Disposition: inline; filename=$fileName");
header("Content-Transfer-Encoding: binary\n");
header("Last-Modified: $time");
header('Connection: close');
$cur = $begin;
fseek($fm, $begin, 0);
while(!feof($fm) && $cur < $end && (connection_status() == 0)) {
print fread($fm, min(1024 * 16, $end - $cur));
$cur += 1024 * 16;
}
}
答案 0 :(得分:2)
如果使用PHP作为Apache模块,最好的办法就是调用virtual
。
否则,您将不得不接受readfile
。
另一种可能性是完全绕过PHP并使用Apache的authorization, authentication and access control工具。如果有必要,您甚至可以使用自己的身份验证/授权逻辑编写Apache模块。
答案 1 :(得分:1)
如果请求的文件不存在,您可以使用apach重写规则通过PHP路由请求。这样,如果您有/images/logo.png
的请求,并且它存在,则apache将像平常一样提供服务。
这可能有用(我有点生疏,我讨厌mod_rewrite规则:P)
# Route requests through PHP if the file does not exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?query=$1&%{QUERY_STRING} [L]
<强>更新强>
您也可以定义哪些目录包含静态内容并将其排除
RewriteCond %{REQUEST_URI} !^/images/.* [AND]
RewriteCond %{REQUEST_URI} !^/css/.*
RewriteRule ^(.*)$ index.php?query=$1&%{QUERY_STRING} [L]
答案 2 :(得分:1)
事实证明,与让Apache做其事情相比,这是非常缓慢的。
我认为在这个低水平上加快操作还有很多工作要做。遗憾的是,没有简单的方法让PHP执行“登录”检查,然后将文件的实际服务传递给Apache。
据说像nginx这样的其他网络服务器在这个领域有更多的可能性。也许值得一试。
我前段时间问essentially the same question。也许反馈中有一些想法。我确实在我要求的项目中实现了接受答案的变体。
答案 3 :(得分:1)
添加Joe Hopfgartner的答案..
是的,输出缓冲可能会有所帮助,但是您应该检查客户端是否接受gzip压缩响应,如果确实如此,那么您也应该gzip缓冲区,响应将会很小,因此速度更快。 检查ob_ *函数上的php.net网站文档或谷歌如何gzip你的内容。
此外,
你应该调用set_time_limit(0)。如果你的脚本运行时间太长,它会中途转移中止,你会得到一个腐败的响应。
你也应该选择你所服务的内容,限制像css这样的文件可能无关紧要。
答案 4 :(得分:1)
首先关闭 - 您的代码只能提供应用程序/八位字节流和text / css,并且您正试图强制下载所有内容。
有人可以推荐一种方法来帮助我提高性能吗?
是
gzip如其他地方所述(但要选择它并缓存服务器端的压缩版本)
使用mod_php或fastCGI优先于CGI
使用操作码缓存,例如APC
发送一些缓存信息(但如果您需要对所有内容进行身份验证,请包含Varies:Cookies标头)
使用fpassthru而不是while循环
使用反向代理
在反向代理上进行身份验证(使用squid的url-rewriter简单)
还有其他方法可以在不使用重写的情况下解决问题(例如404处理程序,自动预置所有内容类型) - 您可以偶尔使用mod_rewrite获得内部递归问题。
答案 5 :(得分:0)
看起来你正试图在那里编写自己的小型Web服务器。所有你想要做的事情,Apache已经可以做得更高效了。我建议重新考虑你的方法。
答案 6 :(得分:0)
您的问题有更好的解决方案。
但你的答案是:使用输出缓冲 ob_start();冲洗(); 它会提高你的表现。
但是你有更好的方法:
对于经过身份验证的用户提供的链接包括当前时间戳和文件名/ id的哈希值,时间戳和秘密令牌。 maby喜欢这样。 $ link = $ timetamp。“/”。md5($ secret_token。$ timestamp。$ filename)。“/”。$ filename。
然后在重写映射中传递这些参数并使用服务器上的秘密令牌,传递的时间戳和文件重新创建哈希。如果哈希匹配,则返回文件的路径,如果超时或错误页面无效。
通过这种方式,您可以直接提供通过apache保护的文件。你还包括一个IP。你还可以查看一下名为mod_secdownload的模块中存在类似taht的lighttpd。我认为还有apache的插件,我相信nginx
为您提供的一些链接:
http://redmine.lighttpd.net/wiki/1/Docs:ModSecDownload http://httpd.apache.org/docs/current/mod/mod_rewrite.html
答案 7 :(得分:0)
使用mod_mysql_auth进行apache。它几乎与你试图做的一样 以mod Auth MySQL Under Apache 2 and Debian为例。
我只用了一次,但它似乎对我有用。
答案 8 :(得分:0)
你能做什么:
这只是安全的一半,尤其是如果路径没有通过https。
OR: