简体   繁体   English

CURLOPT_FILE,curl_multi_exec和fclose

[英]CURLOPT_FILE, curl_multi_exec and fclose

I have built a curl class that can download images in parallel using curl_multi_init . 我已经构建了一个curl类,可以使用curl_multi_init并行下载图像。

The download function is below 下载功能如下

public function download(AbstractRequest $request, $f) {

    // Initiate a new curl
    $ch = curl_init();
    // Set curl options
    curl_setopt_array($ch, [
        CURLOPT_URL => $request->getUrl(),
        CURLOPT_FILE => $f,
        CURLOPT_TIMEOUT => 99,
    ]);
    // Add to curl multi handle
    curl_multi_add_handle($this->multiCh, $ch);
}

The destructor for the class calls the execution of the parallel requests. 该类的destructor调用并行请求的执行。

My question is, how can I get the file resource back from the curl_multi_exec in order to close it with fclose() ? 我的问题是,如何从curl_multi_exec中恢复文件资源以便用fclose()关闭它?

Does curl automatically close the file handle for me? curl会自动关闭文件句柄吗?

Thanks 谢谢

Neither cURL nor PHP automatically close the file handle after the cURL request executes. 执行cURL请求后,cURL和PHP都不会自动关闭文件句柄。 PHP will close it automatically when the entire script terminates, but if the script continues to run for a while doing other things after the cURL requests complete, the files remain open. 当整个脚本终止时,PHP将自动关闭它,但如果脚本在cURL请求完成后继续运行一段时间做其他事情,则文件将保持打开状态。

All PHP does is flush file data to disk when the request completes. 当请求完成时,所有PHP都会将磁盘文件数据刷新到磁盘。

You can easily test this with some simple code: 您可以使用一些简单的代码轻松测试:

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

// create both cURL resources
$ch1 = curl_init();
$ch2 = curl_init();

// open two temp files for requests
$fp1 = fopen('/tmp/1.txt', 'w+');
$fp2 = fopen('/tmp/2.txt', 'w+');

// set URL and other appropriate options
curl_setopt($ch1, CURLOPT_URL, "http://php.net/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch1, CURLOPT_FILE, $fp1);

curl_setopt($ch2, CURLOPT_URL, "http://lxr.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_FILE, $fp2);

//create the multiple cURL handle
$mh = curl_multi_init();

//add the two handles
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);

$active = null;
//execute the handles
echo "Begin requests\n";
do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) != -1) {
        do {
            $mrc = curl_multi_exec($mh, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}

echo "Done\n";

var_dump($fp1, $fp2); // valid resources

echo "Sleep\n";
sleep(10);

//close the handles
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);

fwrite($fp1, "\n\nTEST MORE DATA\n");
fwrite($fp2, "\n\nAND MORE TEST DATA\n");

var_dump($fp1, $fp2); // valid file handles

echo "Last sleep\n";
sleep(10);

// data automatically flushed to disk here
// file handles will be closed by PHP when script terminates here

After running, you will see the extra data written to the end of those files, showing that the handles were still valid after cURL completed. 运行后,您将看到写入这些文件末尾的额外数据,表明在cURL完成后句柄仍然有效。 Note: I ran these tests on PHP 7.0.5 and 5.6.20. 注意:我在PHP 7.0.5和5.6.20上运行了这些测试。

If you're feeling adventurous, you can dig into the PHP/cURL source and see for yourself. 如果您喜欢冒险,可以深入了解PHP / cURL源代码并亲眼看看。 The CURLOPT_FILE handle is ch->handlers->write->fp throughout the file. CURLOPT_FILE句柄在整个文件中是ch->handlers->write->fp

There is no way to get the file handle back so you'll have to keep track of them yourself. 无法恢复文件句柄,因此您必须自己跟踪它们。

It could be as simple as adding them all to an array: 它可以像将它们全部添加到数组一样简单:

$fileHandles = array();
//..
$fileHandles[] = $fp1;
$fileHandles[] = $fp2;

And then closing them all when curl_multi_exec completes: 然后在curl_multi_exec完成时关闭它们:

foreach($fileHandles as $fp) {
    fclose($fp);
}

But the answer is, they will not be closed automatically by cURL or PHP until PHP terminates. 但答案是,在PHP终止之前,它们不会被cURL或PHP自动关闭。

If this happens very shortly after cURL finishes, there's really no need to do it yourself. 如果在cURL完成后很快就会发生这种情况,那么就没有必要自己动手了。 But if this is a long running script that repeats multi requests over and over for a long period of time, it might not be a bad idea to keep track of them and close them as the requests finish. 但是,如果这是一个长时间运行的脚本,会长时间反复重复多个请求,那么跟踪它们并在请求完成时关闭它们可能并不是一个坏主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM