如果下载中断,PHP + Fcgid 将挂起

如果下载中断,PHP + Fcgid 将挂起

笔记:管理员,请投票迁移到 ServerFault。

我使用的是 LAMP 设置,其中 PHP 正在运行mod_fcgid。对于大多数请求,这都运行良好,但我注意到,当我下载文件但在完成之前中断下载时,为文件提供服务的 php-cgi 进程会阻止尝试写入更多数据,直到达到超时时间IPCCommTimeout。一旦达到超时时间,进程就会中断,然后进程会再次开始为其他请求提供服务。

是否有一些可用的 fcgid 设置,我可以设置它以在未捕获任何输出时中止?我可以在 PHP 中做些什么来处理它吗?

如果下载没有中断,则不会发生此问题;事实上,我之所以注意到这个问题,是因为我试图使用 gddflvplayer 传输 FLV 文件,它似乎发送了一个简短的请求来获取前几帧,然后再发送另一个请求来播放它,这导致了同样的问题。

仅供参考,这是挂起的 cgi 进程的 strace;它一直处于这种状态,直到最终被中断,大概是IPCCommTimeout到达时被进程管理器中断。我猜它挂起并试图输出调用的结果readfile(),但 Apache 不再监听(因为请求已被用户取消)。

root@some-machine:~# strace -p 24837
Process 24837 attached - interrupt to quit
write(3, "\5|A\313%\35\337\376\275\237\230\266\242\371\37YjzD<\322\215\357\336:M\362P\335\242\214\341"..., 17432

日志表明该请求最终因超时而被回收

mod_fcgid: read data timeout in 240 seconds

下载代码或多或少只是用于readfile提供文件,同时还涉及一些标题(注意:在此代码中,Header或多或少只是一个包装器,header()以避免测试中出现问题)。

$filepath    = '/some/path/foo.flv';
$filename    = 'foo.flv';
$disposition = 'inline';

$h = Header::get();
$h->send('Pragma: public');
$h->send('Content-Transfer-Encoding: binary');
$h->send('Content-type: ' . FileSystem::get()->getMimeType($filepath));
$h->send('Content-Length: ' . FileSystem::get()->getFileSize($filepath));
$h->send('Content-Disposition: ' . $disposition . '; filename="' . $filename . '"');
$h->send('Content-transfer-encoding: 8bit');
$h->send('Expires: 0');
$h->send('Pragma: cache');
$h->send('Cache-Control: private');

flush();
readfile($filepath);

相关内容