Я несколько часов стучал головой о стену, пытаясь понять, почему файл cookie cookie cURL был пуст, когда я пытался его прочитать. Я только что обнаружил, что мой код работает, если я вызываю curl_close()
дважды, а не один раз, и мне интересно, является ли это ошибкой cURL.
Вот пример:
curl_close($chInfo['handle']);
var_dump(is_resource($chInfo['handle']));
Это выводит boolean true
. Другими словами, дескриптор не закрыт, несмотря на то, что я назвал curl_close()
.
Моя следующая мысль заключалась в том, что, возможно, для закрытия дескриптора требуется некоторое время, поэтому я попытался использовать sleep()
в течение нескольких секунд после вызова curl_close()
, но не было никакой разницы.
Из отчаяния я попытался скопировать строку curl_close()
, например:
curl_close($chInfo['handle']);
curl_close($chInfo['handle']);
var_dump(is_resource($chInfo['handle']));
Это выводит boolean false
, что означает, что дескриптор закрыт, и я могу читать из файла jar файла cookie (cURL записывает файлы cookie в файл, когда дескриптор закрыт).
Итак, что здесь происходит? Это кажется ужасным, как ошибка!
EDIT: я не могу опубликовать свой полный код (вы все равно не хотели бы его читать!), но вот упрощенный пример (обратите внимание, что в этом примере извлекается только один URL-адрес, тогда как в моем реальном коде curl_multi
используется для извлечения многих URL одновременно):
$curlOptions = array(
CURLOPT_USERAGENT => 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101',
CURLOPT_CONNECTTIMEOUT => 5, // the number of seconds to wait while trying to connect.
CURLOPT_TIMEOUT => 5, // the maximum number of seconds to allow cURL functions to execute.
CURLOPT_RETURNTRANSFER => 1, // TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_MAXREDIRS => 10,
CURLOPT_AUTOREFERER => 1,
CURLOPT_REFERER => null,
CURLOPT_POST => 0, // GET request by default
CURLOPT_POSTFIELDS => '', // no POST data by default
CURLINFO_HEADER_OUT => 1, // allows the request header to be retrieved
CURLOPT_HEADER => 1, // returns the response header along with the page body
CURLOPT_URL => 'http://www.example.com/',
CURLOPT_COOKIEJAR => __DIR__ . '/cookie.txt',
CURLOPT_COOKIEFILE => __DIR__ . '/cookie.txt'
);
$ch = curl_init();
curl_setopt_array($ch, $curlOptions); // set the options for this handle
$mh = curl_multi_init();
$responses = array();
curl_multi_add_handle($mh, $ch); // add the handle to the curl_multi object
do
{
$result = curl_multi_exec($mh, $running);
$activity = curl_multi_select($mh); // blocks until there activity on the curl_multi connection (in which case it returns a number > 0), or until 1 sec has passed
while($chInfo = curl_multi_info_read($mh))
{
$chStatus = curl_getinfo($chInfo['handle']);
if($chStatus['http_code'] == 200) // if the page was retrieved successfully
{
$response = curl_multi_getcontent($chInfo['handle']); // get the response
curl_multi_remove_handle($mh, $chInfo['handle']); // remove the curl handle that was just completed
curl_close($chInfo['handle']); // close the curl handle that was just completed (cookies are saved when the handle is closed?)
curl_close($chInfo['handle']);
var_dump(is_resource($chInfo['handle']));
}
else // request failed
{
echo 'Error: Request failed with http_code: ' . $chStatus['http_code'] . ', curl error: ' . curl_error($chInfo['handle']). PHP_EOL;
}
}
} while ($running > 0);
curl_multi_close($mh);
Если вы запустите указанный выше код, выход будет
boolean false
Указание на то, что ручка закрыта. Однако, если вы удалите второй вызов curl_close()
, то выход изменится на
boolean true
Указание на то, что ручка не закрыта.