提问人:Nate 提问时间:3/31/2014 最后编辑:Nate 更新时间:4/11/2014 访问量:1800
在句柄关闭之前必须调用 curl_close() 两次,并且可以读取 cookie jar。这是一个错误吗?
Have to call curl_close() twice before handle is closed and cookie jar can be read. Is this a bug?
问:
几个小时来,我一直在用头撞墙,试图理解为什么当我尝试阅读 cURL 的 cookie jar 文件时它是空的。但是,我刚刚发现如果我调用两次而不是一次,我的代码就可以工作,我想知道这是否是 cURL 的错误。curl_close()
下面是一个示例:
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']));
输出 ,这意味着句柄已关闭,并且我能够从 cookie jar 文件中读取(当句柄关闭时,cURL 将 cookie 写入文件)。boolean false
那么这是怎么回事呢?这似乎很像一个错误!
编辑:我无法发布我的完整代码(无论如何你都不想阅读它!),但这是一个简化的例子(请注意,在这个例子中只获取了一个 URL,而在我的实际代码中用于同时获取多个 URL):curl_multi
$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's 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
指示手柄未关闭。
答:
我认为在查看代码后只有 1 个错误,即
while($chInfo = curl_multi_info_read($mh))
更改为
while($chInfo == curl_multi_info_read($mh))
评论
“句柄”在循环中未闭合 循环后,您可以移除手柄
curl_multi_remove_handle($mh, $ch1); /* this is not suppose to be required but the remove sometimes fails to close the connection */ curl_close($ch1); curl_multi_remove_handle($mh, $ch2); curl_close($ch2); if you set up your connections as an array you can remove them through a separate loop after the main loop. /* init and add connection */ foreach ($multi_urls as $i => $url) { $ch[$i] = curl_init($url); curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1); curl_multi_add_handle ($mh, $ch[$i]); } main loop { .... } /* remove and close connection */ foreach($ch AS $i => $conn) { curl_multi_remove_handle($mh, $ch[$i]); curl_close($ch[$i]); }
这不是一个真正的错误,而只是它的工作方式。如果你看一下源代码,你可以看到发生了什么。
首先,您打开手柄并查看源代码,您可以看到它在内部设置$ch = curl_init();
ext\curl\interface.c
ch->uses = 0;
然后你调用并查看此方法确实.在这一点上curl_multi_add_handle($mh, $ch);
ext\curl\multi.c
ch->uses++;
ch->uses==1
现在最后一部分,再看一下,其中有如下代码:curl_close($chInfo['handle']);
ext\curl\interface.c
if (ch->uses) {
ch->uses--;
} else {
zend_list_delete(Z_LVAL_P(zid));
}
因此,第一次尝试关闭它会减少,第二次尝试实际上会关闭它。ch->uses
此内部指针仅在使用 或使用 时增加。所以我想这个想法是为了使用句柄的副本,而不是实际的句柄。curl_multi_add_handle
curl_copy_handle
curl_multi_add_handle
评论
curl_multi_add_handle
curl_multi_remove_handle
--ch->uses
close;close;
remove;close
这里没有问题。使用时无需调用 .相反,您必须调用每个使用的句柄。因此,代码中的调用是多余的。multi-curl
curl_close
curl_multi_remove_handle
curl_close
评论
curl_close()
multi-curl
multi-curl
评论
curl_close()
curl_multi_close()
curl_multi
curl_multi_close()
curl_multi_remove_handle()
curl_close()
curl_multi_close()