CURLOPT_FILE, curl_multi_exec и fclose

Я создал класс curl, который может загружать изображения параллельно с помощью curl_multi_init .

Функция загрузки ниже

 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); } 

destructor класса вызывает выполнение параллельных запросов.

Мой вопрос: как я могу вернуть ресурс файла из curl_multi_exec , чтобы закрыть его с помощью fclose() ?

Закрывает ли curl автоматический дескриптор файла для меня?

благодаря

Ни cURL, ни PHP автоматически не закрывают дескриптор файла после выполнения запроса cURL. PHP закрывает его автоматически, когда весь скрипт завершается, но если скрипт продолжает работать некоторое время после выполнения запросов cURL, файлы остаются открытыми.

Весь PHP делает это данные файла flush на диск, когда запрос завершается.

Вы можете легко протестировать это с помощью простого кода:

 <?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 

После запуска вы увидите дополнительные данные, записанные в конце этих файлов, показывая, что дескрипторы все еще действительны после завершения cURL. Примечание. Я проверил эти тесты на PHP 7.0.5 и 5.6.20.

Если вы чувствуете себя авантюрно, вы можете вникнуть в источник PHP / cURL и сами убедиться. CURLOPT_FILE представляет собой ch->handlers->write->fp по всему файлу.

Невозможно вернуть дескриптор файла, чтобы вы сами отслеживали их.

Это может быть так же просто, как добавить их в массив:

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

И затем завершаем их все, когда curl_multi_exec завершает:

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

Но ответ заключается в том, что они не будут автоматически закрыты cURL или PHP до тех пор, пока PHP не завершится.

Если это произойдет очень скоро после завершения курса cURL, вам действительно не нужно делать это самостоятельно. Но если это длинный сценарий, который многократно повторяет несколько запросов много раз, может быть, неплохая идея отслеживать их и закрывать по мере завершения запросов.