Sunday, 8 September 2013

PHP script hangs for a minute on connection abort

PHP script hangs for a minute on connection abort

With PHP 5.4.5 on a 32 bit Windows Server 2003 machine with Apache 2.4, I
was having a hard time to detect when the user aborts the data transfer:
header("Content-Disposition: attachment; filename=\"$filename\"");
$ctx = stream_context_create();
stream_context_set_params($ctx, array('notification' =>
function($code, $sev, $message, $msgcode, $bytes, $length) {
// This function is called also every time a chunk of data is transferred
if (connection_aborted()) {
write_log(' * Connection aborted');
exit();
}
if ($code === STREAM_NOTIFY_FILE_SIZE_IS)
header("Content-Length: $length");
}));
ignore_user_abort(true);
set_time_limit(0);
write_log("- Download start");
@readfile($url, false, $ctx);
write_log("- Download end");
The script is quite straight-forward, but when the user aborts the
transfer the script sort of hangs for a minute or so (I registered a range
of 59-80 seconds), then it writes " * Connection aborted" in the log file.
What's worse, all the following requests from the same user that use a
script are halted until the hanged script finally restores its execution.
A similar test script didn't suffer the same fate:
$lorem = 'Lorem ipsum dolor sit amet ... [continues to 1024 characters]';
$c = 10000;
header('Content-Disposition: attachment; filename="lorem.txt"');
header('Content-Length: '.(strlen($lorem) * $c));
write_log("- Download start");
for ($i = 0; $i < $c; $i++) {
if (connection_aborted()) {
write_log(' * Connection aborted');
exit();
}
echo $lorem;
flush();
}
write_log("- Download end");
The "connection aborted" message was logged immediately. But when I
changed the first line to
$lorem = str_repeat('Lorem ipsum...', 9);
the test script had the same problem (with $lorem with a length of 9 KB).
Using 8 or 10 as the repeat count is good, while 9 hangs the script in the
way mentioned above.
So, what's happening? Why is 9 KB a critical limit?
I can't do tests at the moment, but can I make the readfile script work
using stream_set_write_buffer (and with what, php://output)?

No comments:

Post a Comment