我一直在按照本教程了解如何使用curl_multi
. http://arguments.callee.info/2010/02/21/multiple-curl-requests-with-php/
说不出我做错了什么,但curl_multi_getcontent
返回 null。应该返回 JSON。我知道这不是 mysql 调用,因为我让它与 while 循环和标准curl_exec
一起工作,但页面加载时间太长。(为了安全起见,我更改了一些设置选项的详细信息)
相关的 PHP 代码片段。我最终会关闭 while 循环。
$i = 0;
$ch = array();
$mh = curl_multi_init();
while($row = $result->fetch_object()){
$ch[$i] = curl_init();
curl_setopt($ch[$i], CURLOPT_CAINFO, 'cacert.pem');
curl_setopt($ch[$i], CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch[$i], CURLOPT_URL, 'https://mysite.com/search/'.$row->username.'/');
curl_multi_add_handle($mh, $ch[$i]);
$i++;
}
$running = 0;
do {
curl_multi_exec($mh, $running);
} while ($running > 0);
$result->data_seek(0);
$i = 0;
while ($row = $result->fetch_object()) {
$data = curl_multi_getcontent($ch[$i]);
$json_data = json_decode($data);
var_dump($json_data);
编辑
这是当前有效的代码,但会导致页面加载太慢
$ch = curl_init();
curl_setopt($ch, CURLOPT_CAINFO, 'cacert.pem');
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
while($row = $result->fetch_object()){
curl_setopt($ch, CURLOPT_URL, 'https://mysite.com/search/'.$row->username.'/');
$data = curl_exec($ch);
$json_data = json_decode($data);
var_dump($json_data);
}
我想知道:
$i = 0;
while ($row = $result->fetch_object()) {
$data = curl_multi_getcontent($ch[$i]);
$json_data = json_decode($data);
var_dump($json_data);
您是否忘记增加$i?如果是这样,您已经获取了 $ch[0] 的内容,然后再次调用curl_multi_getcontent。
另外,我还写了一篇博客文章,介绍了 PHP 的 cURL 扩展的并发请求,它包含一个用于 curl multi 请求的通用函数。可以按以下方式调用此函数:
$responses = multi([
$requests = [
['url' => 'https://example.com/search/username1/'],
['url' => 'https://example.com/search/username2/'],
['url' => 'https://example.com/search/username3/']
]
$opts = [
CURLOPT_CAINFO => 'cacert.pem',
CURLOPT_USERPWD => "username:password"
]
]);
然后,循环浏览响应数组:
foreach ($responses as $response) {
if ($response['error']) {
// handle error
continue;
}
// check for empty response
if ($response['data'] === null) {
// examine $response['info']
continue;
}
// handle data
$data = json_decode($response['data']);
// do something
}
使用此函数,您可以使用以下调用对访问 https 站点进行简单测试:
multi(
$requests = [
'google' => ['url' => 'https://www.google.com'],
'linkedin' => ['url'=> 'https://www.linkedin.com/']
],
$opts = [
CURLOPT_CAINFO => '/path/to/your/cacert.pem',
CURLOPT_SSL_VERIFYPEER => true
]
);
我看到您的执行循环与PHP文档中建议的执行循环不同:
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
请注意,在while
中比较函数返回,而不是第二个参数。
编辑:多亏了亚当的评论,我已经测试了这两种语法,并看到它们是相等和异步的。下面是将内容放入变量的异步多请求的工作示例:
<?php
$ch = array();
$mh = curl_multi_init();
$total = 100;
echo 'Start: ' . microtime(true) . "'n";
for ($i = 0; $i < $total; $i++) {
$ch[$i] = curl_init();
curl_setopt($ch[$i], CURLOPT_URL, 'http://localhost/sleep.php?t=' . $i);
curl_setopt($ch[$i], CURLOPT_HEADER, 0);
curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch[$i]);
}
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
usleep(100); // Maybe needed to limit CPU load (See P.S.)
} while ($active);
foreach ($ch AS $i => $c) {
$r = curl_multi_getcontent($c);
var_dump($r);
curl_multi_remove_handle($mh, $c);
}
curl_multi_close($mh);
echo 'End: ' . microtime(true) . "'n";
并测试文件睡眠.php:
<?php
$start = microtime(true);
sleep( rand(3, 5) );
$end = microtime(true);
echo $_GET['t'], ': ', $start, ' - ', $end, ' - ', ($end - $start);
echo "'n";
附言:在循环中使用usleep
的最初想法是暂停它一点,从而减少cUrl等待响应时的操作数量。一开始,它似乎是这样工作的。但最近对 top
的测试显示 CPU 负载差异很小(usleep
为 17%,没有 CPU 负载为 20%)。所以,我不知道是否使用它。也许在真实服务器上的测试会显示另一个结果。
编辑2:我已经测试了我的代码,向受密码保护的HTTPS页面发出请求(CURLOPT_CAINFO
和CURLOPT_USERPWD
与问题中的页面相同)。它按预期工作。可能您的PHP或cURL版本中存在错误。我的版本是"PHP 版本 5.3.10-1ubuntu3.8"和 7.22.0。他们没有问题。
使用 $running = null;
代替 $running = 0;
。
根据链接:
-
多卷曲请求与 PHP
-
http://www.php.net/manual/en/function.curl-multi-exec.php
在这两种情况下,变量都被定义为 NULL,这是因为
curl_multi_exec ( resource $mh , int &$still_running )
第二个参数是对变量的引用。
另外,您可能会发现这很有用:php 单卷曲有效,但多卷曲不起作用
curl_multi_getcontent() 将返回 null,没有错误,如果以下任何一种情况:
- 请求中未设置CURLOPT_RETURNTRANSFER
- 您正在使用自定义写入函数,使用CURLOPT_WRITEFUNCTION
在其他情况下,它可能会返回 null 并显示错误,您可以使用 curl_errno() 和 curl_error() 进行检查。
curl_multi_exec
执行多通道 HTTP 请求,并且请求可能不是按顺序完成的,而不是将它们添加到多处理程序$mh
。要获得已完成请求的响应,您应该使用curl_multi_info_read
函数。您可以在 php.net http://php.net/manual/ru/function.curl-multi-info-read.php 上阅读更多相关信息
您是否将CURLOPT_SSL_VERIFYPEER设置为 true?