在继续之前进行卷曲多次完成下载?

时间:2017-02-15 23:02:31

标签: php curl

我有一组重定向的网址,我想使用curl_ multi加速进程以获取最终网址。但是当我访问CURLINFO_EFFECTIVE_URL因为它返回原始网址时,似乎curl_multi没有完成跟随重定向。

function processUrls($urls){
    $handlers = [];
    $cleanUrls = [];
    $mh = curl_multi_init();
    foreach ($urls as $key => $url){
        $handlers[$key] = curl_init();

        curl_setopt($handlers[$key], CURLOPT_URL, $url);
        curl_setopt($handlers[$key], CURLOPT_HEADER, true);
        curl_setopt($handlers[$key], CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($handlers[$key], CURLOPT_RETURNTRANSFER, true);
        curl_setopt($handlers[$key], CURLOPT_NOBODY, true);
        curl_setopt($handlers[$key], CURLOPT_HEADER, true);
        curl_multi_add_handle($mh, $handlers[$key]);
    }

    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh);
    } while ($running > 0);

    foreach($handlers as $key => $ch){
        $cleanUrls [$key] = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL) ;
    }

    curl_multi_close($mh);

    return $cleanUrls;
}

我认为问题是这段代码:

    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh);
    } while ($running > 0);

1 个答案:

答案 0 :(得分:1)

使用stream_socket_client()有一种更有效,更灵活的方法。每个网址都没有延迟。来自一个网址的响应缓慢不会影响其他网址响应时间。回复将以先到先得的方式回复。如有必要,您可以按顺序获取响应。

如果我理解正确,你想做一些HTTP请求,其中响应时间可能无法预测或者太长而无法连续运行并希望同时运行请求。

我在运行W3C验证工具时这样做 我做CSS验证,HTML验证和XHTML验证。 (我喜欢我的代码使用和XHTML一样多,只在必要时使用HTML5。老W3C移动最佳习惯习惯。)

在传输HTML的<body>之前,我使用stream_socket_client()启动并发请求。

这与PHP获得的多任务处理非常接近。这是我使用了几年的实际工作代码。

初始化变量。

$ url是受测试网页的完全限定网址,例如http://example.com/index.html

  $url = $_POST['url'];
  $webPageTestKey = ' [key for WebPageTest.org goes here] ';
  $timeout = 120; 
  $result = array(); 
  $sockets = array(); 
  $buffer_size = 8192;
  $id = 0;
  $urls = array();
  $path = $url;
  $url = urlencode("$url");

使用stream_socket_client()

进行请求

请求网址存储在$ urls []数组

  $urls[] = array('host' => "jigsaw.w3.org",'path' => "/css-validator/validator?uri=$url&profile=css3&usermedium=all&warning=no&lang=en&output=text");
  $urls[] = array('host' => "validator.w3.org",'path' => "/check?uri=$url&charset=%28detect+automatically%29&doctype=Inline&group=0&output=json");
  $urls[] = array('host' => "validator.w3.org",'path' => "/check?uri=$url&charset=%28detect+automatically%29&doctype=XHTML+Basic+1.1&group=0&output=json");
  $urls[] = array('host' => "www.webpagetest.org",'path' => "/runtest.php?f=xml&bwDown=10000&bwUp=1500&latency=40&fvonly=1&k=$webPageTestKey&url=$url");

套接字需要主机和路径 如果你不能轻易看到url的格式转储数组

var_export($urls);

续:

  $err = '';
  foreach($urls as $path){
    $host = $path['host'];
    $path = $path['path'];
    $http = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";
    $stream = stream_socket_client("$host:80", $errno,$errstr, 120,STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); 
    if ($stream) {
      $sockets[] = $stream;  // supports multiple sockets
      $start[] = microtime(true);
      fwrite($stream, $http);
    }
    else { 
   $err .=  "$id Failed<br>\n";
    }
  }

请求套接字存储在数组$ sockets []

然后我在等待请求完成时传输HTML。强文

使用stream_select()

检索对请求的响应

回复按照收到的顺序返回。请求的顺序无关紧要。

通过8K缓冲区读入响应。如果响应超过8K,则一次检索8K多个块。

while (count($sockets)) {
  $read = $sockets; 
  stream_select($read, $write = NULL, $except = NULL, $timeout);
  if (count($read)) {
    foreach ($read as $r) { 
      $id = array_search($r, $sockets); 
      $data = fread($r, $buffer_size); 
      if (strlen($data) == 0) { 
        $closed[$id] = microtime(true);  // not necessary
        fclose($r); 
        unset($sockets[$id]);

        // check $response[$id] for redirect here


      } 
      else {
        $result[$id] .= $data; 
      }
    }
  }
  else { 
 //   echo 'Timeout: ' . date('h:i:s') . "\n\n\n";
    break;
  }
}

HTTP响应存储在$ result []数组中。

您必须添加重定向响应的搜索,然后发出后续请求。

此代码可让您完全控制。没有任何隐藏,没有未知数。

如果您想放弃一些易于使用的控件。请求您自己的脚本并使用常规curl来执行请求和重定向。