Curl_multi在文件下载时过早退出

时间:2013-12-26 13:58:12

标签: php multithreading curl proxy

使用单个线程运行文件下载到文件指针时,它可以正常工作。使用多线程时,它不会下载完整文件(停在中间某处)

单线程(有效)

$fp = fopen('php://output', 'w');
$ch = curl_init(str_replace(" ", "%20", $url)); //Here is the file we are downloading, replace spaces with %20
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$return = curl_exec($ch); // get curl response
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
fclose($fp);

多线程(不完整下载)

$bodyStream = fopen('php://output', 'w');
$headerStream = fopen('php://temp', 'rw');

$ch = curl_init(str_replace(" ", "%20", $url)); //Here is the file we are downloading, replace spaces with %20
curl_setopt($ch, CURLOPT_WRITEHEADER, $headerStream);
curl_setopt($ch, CURLOPT_FILE, $bodyStream);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

$mh = curl_multi_init();
curl_multi_add_handle($mh, $ch);
$headerProcessed = false;
ob_start(); // Buffer body output until headers are ready
do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    do {
        $mrc = curl_multi_exec($mh, $active);
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);

    // Process headers
    if (!$headerProcessed) {
        $currentPos = ftell($headerStream);
        rewind($headerStream);
        $header = stream_get_contents($headerStream);
        fseek($headerStream, $currentPos); // Is this really needed?
        if (strpos($header, "\r\n\r\n") !== false) {
            // Copy headers such as Content-Length etc.
            $this->generateProxyHeader($header);

            // Headers set. Now send output to browser
            $headerProcessed = true;
            ob_end_flush();
        }
    }
}
curl_multi_remove_handle($mh, $ch);
curl_multi_close($mh);
exit; // Download complete, stop processing

我在输出之前需要标头的主要原因是捕获后端的错误。 (单线程方法将导致200OK标头,即使服务器响应404或500)。这将有效地破坏文件中的数据。

如何确保在PHP停止向浏览器发送数据之前将完整文件发送到php://输出,并仍然使用curl_multi(这样我可以代理大文件,包括标题)?

1 个答案:

答案 0 :(得分:0)

我在PHP & curl_multi and CURLOPT_FILE = No File Contents

中找到了答案

使用CURLOPT_FILE和curl_multi时似乎有一些意想不到的行为。解决方法是明确调用fclose($bodyStream)