【问题标题】:PHP : Multiple cURL with same URLPHP:具有相同 URL 的多个 cURL
【发布时间】:2017-08-06 14:11:41
【问题描述】:

我的网站上有一个表单,通过 cURL 调用 web 服务,并在提交时发布数据。

这很好用,除了在一种情况下,当远程 Web 服务服务器关闭时(它经常发生) 所以我正在尝试开发一个缓存系统,其工作方式如下:

  • 如果表单提交上的 curl 执行返回 false,我将其保存在数据库中
  • 我每天都在运行一个 CRON 作业来检查我是否有一些失败的提交
  • 我正在对我的结果集进行 foreach 并为每个提交运行 curl 调用

问题是如何进行最后一步? URL 总是相同的(只是每次调用的 POST 字段都会发生变化),我想检查每个调用是否有效(假设远程服务器在第 10 次提交后关闭,我想在我的数据库中保存第一个10 个还可以,其他的不行)

我尝试了我发现的这个功能:

function curl_multiRequest($data, $options = array()) {

  // array of curl handles
  $curly = array();
  // data to be returned
  $result = array();

  // multi handle
  $mh = curl_multi_init();

  // loop through $data and create curl handles
  // then add them to the multi-handle
  foreach ($data as $id => $d) {

    $curly[$id] = curl_init();

    $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;

    curl_setopt($curly[$id], CURLOPT_URL,            $url);
    curl_setopt($curly[$id], CURLOPT_HEADER,         0);
    curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);

    // post?
    if (is_array($d)) {
      if (!empty($d['post'])) {
        curl_setopt($curly[$id], CURLOPT_POST,       1);
        curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
      }
    }

    // extra options?
    if (!empty($options)) {
      curl_setopt_array($curly[$id], $options);
    }

    curl_multi_add_handle($mh, $curly[$id]);
  }

  // execute the handles
  $running = null;
  do {
    curl_multi_exec($mh, $running);
  } while($running > 0);


  // get content and remove handles
  foreach($curly as $id => $c) {
    $result[$id] = curl_multi_getcontent($c);
    curl_multi_remove_handle($mh, $c);
  }

  // all done
  curl_multi_close($mh);

  return $result;
}

我的数组看起来像:

    array(5) {
  [0]=>
  array(6) {
    ["id"]=>
    string(1) "7"
    ["post"]=>
    string(1644) "Surname=Test&Name=Test"
    ["url"]=>
    string(28) "http://www.mywebsite.fr/"
  }
  [1]=>
  array(6) {
    ["id"]=>
    string(1) "6"
    ["post"]=>
    string(1644) "Surname=Test1&Name=Test1"
    ["url"]=>
    string(28) "http://www.mywebsite.fr/"
  }
  [2]=>
  array(6) {
    ["id"]=>
    string(1) "5"
     ["post"]=>
    string(1644) "Surname=Test2&Name=Test2"
    ["url"]=>
    string(28) "http://www.mywebsite.fr/"
  }

}

但是当 URL 无效时(我尝试使用无效 URL 来模拟停机服务器)我有这个:

    Fatal error: Maximum execution time of 30 seconds exceeded in /home/www/myscript.php on line 63

Warning: (null)(): 560 is not a valid cURL handle resource in Unknown on line 0

我做错了吗?

谢谢

编辑 1:我尝试像这样实现主教的回答:

$myarray=array(
    array(
        "id"=>"1",
        "post"=>"Surname=Test&Name=Test",
        "url"=>"http://www.mywebsite.fr/",
    )
  ,  array(
        "id"=>"1",
        "post"=>"Surname=Test&Name=Test",
        "url"=>"http://www.mywebsite.fr/",
    )
);

    $mh = curl_multi_init();
    foreach($myarray as $k=>$failed){

            $myarray[$k]["handle"] = curl_init();
            curl_setopt($myarray[$k]["handle"], CURLOPT_URL, $failed["url"]);
        curl_setopt($myarray[$k]["handle"], CURLOPT_POST, true);
            curl_setopt($myarray[$k]["handle"], CURLOPT_POSTFIELDS, $failed["post"]);
            curl_multi_add_handle($mh, $myarray[$k]["handle"]);
        }


 foreach (multiread($mh) as $info) {
    var_dump($info);
}

但如果远程 URL 无法访问,请求似乎永远不会停止。有没有办法限制每个请求的执行时间?

编辑 2: 在定义选项时使用它是一种好方法吗?

curl_setopt($chs[$key], CURLOPT_CONNECTTIMEOUT , 10);

在脚本的顶部

set_time_limit(0);

如果没问题,我的最后一个问题是收集有关每个呼叫的信息。如何分别检索有关每个处理程序的信息(以保存此调用成功的数据库?)像一个 ID 左右?

【问题讨论】:

  • 给定的示例对我有用(即,它返回相当快的响应)。有没有给您带来麻烦的特定 URL?
  • 不,我只是在尝试使用不存在的 URL 来模拟远程服务器。我从另一台服务器上试过,它似乎工作得更好,但回声只是:NULL
  • 默认情况下,curl 输出结果。您想返回结果。在初始化循环中,添加:curl_setopt($myarray[$k]["handle"], CURLOPT_RETURNTRANSFER, true);
  • 好的,很高兴知道。但是我正在调用三个 URL,并且我希望对每次传输都有一个响应,以了解是否所有内容都没有问题地发送(并将此调用成功保存到数据库中)。在那里,我在三个电话中只有一次“0”。

标签: php forms curl


【解决方案1】:

您在多手柄上的循环似乎不完整。更健壮的实现:

function multiread($mh, $timeout = .5) {
    $output = array ();
    $runCnt = 0;
    do {
        // start requests, or update status of pending requests: returns by
        // reference (in $runCnt) the number of outstanding requests
        $status = curl_multi_exec($mh, $runCnt);
        if (CURLM_OK !== $status) throw new \RuntimeException;

        // take a breath, so as to not eat 100% CPU
        do {
            $status = curl_multi_select($mh, $timeout);
            if (-1 === $status) {
                usleep(10);
            }
        } while (0 === $status);

        // gather the results and yield back what we know
        while (false !== ($info = curl_multi_info_read($mh))) {
            if (CURLE_OK === $info['result']) {
                $output[] = [ $info, curl_multi_getcontent($info['handle']) ];
            } else {
                $output[] = [ $info, null ];
            }
        }
    } while (0 < $runCnt);
    return $output;
}

现在做一些循环:

$mh = curl_multi_init();
// ... add your easy handles

foreach (multiread($mh) as list ($info, $content)) {
    // $info['handle'] contains the cURL easy handle
    // $info['result'] contains the result code, see also curl_strerror
    // $content contains whatever the URL returned
}

【讨论】:

  • 谢谢!但由于我的 PHP 版本是 5.2 并且我无法更改它,您认为我可以通过其他方式实现吗? :(
  • 有什么办法可以用其他东西代替产量吗?
  • @pepichoc 已编辑为支持 PHP
  • 好的,它正在工作(在 PHP
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-09
  • 2016-07-24
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
相关资源
最近更新 更多