使用单个线程运行文件下载到文件指针时,它可以正常工作。使用多线程时,它不会下载完整文件(停在中间某处)
单线程(有效)
$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(这样我可以代理大文件,包括标题)?
答案 0 :(得分:0)
我在PHP & curl_multi and CURLOPT_FILE = No File Contents
中找到了答案使用CURLOPT_FILE和curl_multi时似乎有一些意想不到的行为。解决方法是明确调用fclose($bodyStream)