PHP readfile() 永远不会结束并使 Apache 服务器挂起
PHP readfile() never ends and makes Apache server hang
我的 apache 服务器有一个大问题,php 应用程序。
服务器正在为一个流量很高的网站提供服务,该网站是 运行 php。
每隔 24 小时或 48 小时,apache 就会挂起,我必须重新启动它才能再次访问该网站。我必须重新启动它,因为 apache 达到允许的最大数量 processes/servers(对我来说是 16000),并且它无法释放其他进程,因为其他进程都处于活动状态。
此服务器上托管的网站是一个 php 应用程序,最后提供一个文件:假设它是一个下载服务器。
浏览器通过提交 POST 请求的表单请求文件。
问题是这个post请求似乎永远不会结束(我可以看到我的服务器状态上几乎所有的16000个进程都是POST请求)。
提供的文件是大文件(10M 到 2G),我用 php readfile 函数来提供它们(我不想用 href link 来提供它们,所以我使用表单 POST 请求,这样用户永远不会看到文件在我的文件系统中的位置。
使用 php readfile 的函数似乎永远不会结束,即使我在它的末尾使用 exit() 也是如此(参见下面的代码片段)。
我在这里寻求一种方法来避免这种由我的 php 代码引起的永无止境的 POST 请求。我想保留 POST 提供文件的方式。
首先是我的会议:[=72=]
- Ubuntu 服务器 14.04
- 带有 mpm prefork 的 Apache 2.4
- php 5.5.9 (mod php)
- 硬件:128G内存
我的mpm_prefork.conf文件:
<IfModule mpm_prefork_module>
StartServers 512
MinSpareServers 512
MaxSpareServers 1024
ServerLimit 16000 # no problem with my server ram
MaxRequestWorkers 16000
MaxConnectionsPerChild 10000
</IfModule>
我的apache2.conf文件:
...
Timeout 300
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 5
...
我的php.ini文件:
max_execution_time = 7200
我的 apache 日志文件: 我的问题没有什么有趣的
显示问题何时发生的图表:
我的 apache 服务器状态看起来是这样的:
我的服务器class(导致问题的代码):
class Server
{
/* the file is served from a remote url source */
public function serveFileFromUrl()
{
if (empty($_POST)) {
return;
}
$url = $_POST['file_url'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
/* file is served from my filesystem */
public function serveFileFromPath()
{
if (empty($_POST)) {
return;
}
$url = APP_PATH . '/download/' . $_POST['file_name'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . '-' . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
}
有人有解决方案来避免永无止境的 POST 请求吗?
如果可以解决问题,我可以通过 php 以外的方式提供文件。
请不要重复,我已经添加了足够的代码、conf 片段和图片来使这个问题变得具体:)
mod_xsendfile 是 PHP 传送文件的一个很好的替代方法。
https://tn123.org/mod_xsendfile/
否则您可以简单地为您的 PHP 脚本添加一个时间限制,因此它不能永远 运行。
我的 apache 服务器有一个大问题,php 应用程序。
服务器正在为一个流量很高的网站提供服务,该网站是 运行 php。
每隔 24 小时或 48 小时,apache 就会挂起,我必须重新启动它才能再次访问该网站。我必须重新启动它,因为 apache 达到允许的最大数量 processes/servers(对我来说是 16000),并且它无法释放其他进程,因为其他进程都处于活动状态。
此服务器上托管的网站是一个 php 应用程序,最后提供一个文件:假设它是一个下载服务器。
浏览器通过提交 POST 请求的表单请求文件。
问题是这个post请求似乎永远不会结束(我可以看到我的服务器状态上几乎所有的16000个进程都是POST请求)。
提供的文件是大文件(10M 到 2G),我用 php readfile 函数来提供它们(我不想用 href link 来提供它们,所以我使用表单 POST 请求,这样用户永远不会看到文件在我的文件系统中的位置。
使用 php readfile 的函数似乎永远不会结束,即使我在它的末尾使用 exit() 也是如此(参见下面的代码片段)。
我在这里寻求一种方法来避免这种由我的 php 代码引起的永无止境的 POST 请求。我想保留 POST 提供文件的方式。
首先是我的会议:[=72=]
- Ubuntu 服务器 14.04
- 带有 mpm prefork 的 Apache 2.4
- php 5.5.9 (mod php)
- 硬件:128G内存
我的mpm_prefork.conf文件:
<IfModule mpm_prefork_module>
StartServers 512
MinSpareServers 512
MaxSpareServers 1024
ServerLimit 16000 # no problem with my server ram
MaxRequestWorkers 16000
MaxConnectionsPerChild 10000
</IfModule>
我的apache2.conf文件:
...
Timeout 300
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 5
...
我的php.ini文件:
max_execution_time = 7200
我的 apache 日志文件: 我的问题没有什么有趣的
显示问题何时发生的图表:
我的 apache 服务器状态看起来是这样的:
我的服务器class(导致问题的代码):
class Server
{
/* the file is served from a remote url source */
public function serveFileFromUrl()
{
if (empty($_POST)) {
return;
}
$url = $_POST['file_url'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
/* file is served from my filesystem */
public function serveFileFromPath()
{
if (empty($_POST)) {
return;
}
$url = APP_PATH . '/download/' . $_POST['file_name'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . '-' . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
}
有人有解决方案来避免永无止境的 POST 请求吗? 如果可以解决问题,我可以通过 php 以外的方式提供文件。
请不要重复,我已经添加了足够的代码、conf 片段和图片来使这个问题变得具体:)
mod_xsendfile 是 PHP 传送文件的一个很好的替代方法。
https://tn123.org/mod_xsendfile/
否则您可以简单地为您的 PHP 脚本添加一个时间限制,因此它不能永远 运行。