当前位置:首页 > PHP教程 > php高级应用 > 列表

php curl批处理实现可控并发异步操作示例

发布:smiling 来源: PHP粉丝网  添加日期:2021-09-17 09:54:44 浏览: 评论:0 

这篇文章主要介绍了php curl批处理实现可控并发异步操作,结合实例形式分析了php使用curl的curl_multi_*族函数进行并发操作相关实现技巧,需要的朋友可以参考下

本文实例讲述了php curl批处理实现可控并发异步操作,分享给大家供大家参考,具体如下:

通常情况下 PHP 中的 cURL 是阻塞运行的,就是说创建一个 cURL 请求以后必须等它执行成功或者超时才会执行下一个请求:API接口访问一般会首选CURL

在实际项目或者自己编写小工具(比如新闻聚合,商品价格监控,比价)的过程中, 通常需要从第3方网站或者API接口获取数据, 在需要处理1个URL队列时, 为了提高性能, 可以采用cURL提供的curl_multi_*族函数实现简单的并发.

  1. <?php 
  2. include 'curl.class.php'; 
  3. function callback($response, $info, $error, $request) 
  4. { 
  5.  echo 'response:<br>'; 
  6.  print_r($response); 
  7.  echo '<br>' . date("Y-m-d H:i:s") . '&nbsp;&nbsp;&nbsp;<br>'; 
  8.  echo '<br>' . str_repeat("-", 100) . '<br>'; 
  9. } 
  10. $USER_COOKIE = (!emptyempty($_REQUEST['cookie'])) ? $_REQUEST['cookie'] : file_get_contents("cookie.txt"); 
  11. $curl = new Curl ("callback"); 
  12. $data = array( 
  13.  array( 
  14.   'url' => 'http://dyactive2.vip.xunlei.com/com_sign/?game=qmr&type=rec_gametime&referfrom=&rt=0.42521539455332336', //秦美人 
  15.   'method' => 'POST', 
  16.   'post_data' => '', 
  17.   'header' => null, 
  18.   'options' => array( 
  19.    CURLOPT_REFERER => "http://niu.xunlei.com/entergame/?gameNo=qmr&fenQuNum=3", 
  20.    CURLOPT_COOKIE => $USER_COOKIE, 
  21.   ) 
  22.  ), 
  23.  array( 
  24.   'url' => 'http://dyactive2.vip.xunlei.com/com_sign/?game=sq&type=rec_gametime&referfrom=&rt=0.42521539455332336', //神曲 
  25.   'method' => 'POST', 
  26.   'post_data' => '', 
  27.   'header' => null, 
  28.   'options' => array( 
  29.    CURLOPT_REFERER => "http://niu.xunlei.com/entergame/?gameNo=sq&fenQuNum=41", 
  30.    CURLOPT_COOKIE => $USER_COOKIE, 
  31.   ) 
  32.  ), 
  33.  array( 
  34.   'url' => 'http://dyactive2.vip.xunlei.com/com_sign/?game=frxz&type=rec_gametime&referfrom=&rt=0.42521539455332336', //凡人修真 
  35.   'method' => 'POST', 
  36.   'post_data' => '', 
  37.   'header' => null, 
  38.   'options' => array( 
  39.    CURLOPT_REFERER => "http://niu.xunlei.com/entergame/?gameNo=frxz&fenQuNum=3", 
  40.    CURLOPT_COOKIE => $USER_COOKIE, 
  41.   ) 
  42.  ), 
  43.  array( 
  44.   'url' => 'http://dyactive2.vip.xunlei.com/com_sign/?game=smxj&type=rec_gametime&referfrom=&rt=0.42521539455332336', //神魔仙界 
  45.   'method' => 'POST', 
  46.   'post_data' => '', 
  47.   'header' => null, 
  48.   'options' => array( 
  49.    CURLOPT_REFERER => "http://niu.xunlei.com/entergame/?gameNo=smxj&fenQuNum=2", 
  50.    CURLOPT_COOKIE => $USER_COOKIE, 
  51.   ) 
  52.  ), 
  53.  array( 
  54.   'url' => 'http://dyactive2.vip.xunlei.com/com_sign/?game=qsqy&type=rec_gametime&referfrom=&rt=0.42521539455332336', //倾世情缘 
  55.   'method' => 'POST', 
  56.   'post_data' => '', 
  57.   'header' => null, 
  58.   'options' => array( 
  59.    CURLOPT_REFERER => "http://niu.xunlei.com/entergame/?gameNo=qsqy&fenQuNum=11", 
  60.    CURLOPT_COOKIE => $USER_COOKIE, 
  61.   ) 
  62.  ), 
  63. ); 
  64. foreach ($data as $val) { 
  65.  $request = new Curl_request ($val ['url'], $val ['method'], $val ['post_data'], $val ['header'], $val ['options']); 
  66.  $curl->add($request); 
  67. } 
  68. $curl->execute(); 
  69. echo $curl->display_errors(); 

使用下来效果很好,没有副作用,并发数可控,应用之处多多,自己发挥想象吧

  1. <?php 
  2. /** 
  3.  * cURL批量处理 工具类 
  4.  *  
  5.  * @since Version 1.0 
  6.  * @author Justmepzy <justmepzy@gmail.com> 
  7.  * @link http://t.qq.com/JustPzy 
  8.  */ 
  9. /** 
  10.  *单一的请求对象 
  11.  */ 
  12. class Curl_request { 
  13.  public $url   = ''; 
  14.  public $method   = 'GET'; 
  15.  public $post_data  = null; 
  16.  public $headers  = null; 
  17.  public $options  = null; 
  18.  /** 
  19.   *  
  20.   * @param string $url 
  21.   * @param string $method 
  22.   * @param string $post_data 
  23.   * @param string $headers 
  24.   * @param array $options 
  25.   * @return void 
  26.   */ 
  27.  public function __construct($url, $method = 'GET', $post_data = null, $headers = null, $options = null) { 
  28.   $this->url = $url; 
  29.   $this->method = strtoupper( $method ); 
  30.   $this->post_data = $post_data; 
  31.   $this->headers = $headers; 
  32.   $this->options = $options; 
  33.  } 
  34.  /** 
  35.   * @return void 
  36.   */ 
  37.  public function __destruct() { 
  38.   unset ( $this->url, $this->method, $this->post_data, $this->headers, $this->options ); 
  39.  } 
  40. } 
  41. /** 
  42.  * 包含请求列队处理 
  43.  */ 
  44. class Curl { 
  45.  /** 
  46.   * 请求url个数 
  47.   * @var int 
  48.   */ 
  49.  private $size    = 5; 
  50.  /** 
  51.   * 等待所有cURL批处理中的活动连接等待响应时间 
  52.   * @var int 
  53.   */ 
  54.  private $timeout   = 5; 
  55.  /** 
  56.   * 完成请求回调函数 
  57.   * @var string 
  58.   */ 
  59.  private $callback   = null; 
  60.  /** 
  61.   * cRUL配置 
  62.   * @var array 
  63.   */ 
  64.  private $options   = array (CURLOPT_SSL_VERIFYPEER => 0,CURLOPT_RETURNTRANSFER => 1,CURLOPT_CONNECTTIMEOUT => 30 ); 
  65.  /** 
  66.   * 请求头 
  67.   * @var array 
  68.   */ 
  69.  private $headers   = array (); 
  70.  /** 
  71.   * 请求列队 
  72.   * @var array 
  73.   */ 
  74.  private $requests   = array (); 
  75.  /** 
  76.   * 请求列队索引 
  77.   * @var array 
  78.   */ 
  79.  private $request_map  = array (); 
  80.  /** 
  81.   * 错误 
  82.   * @var array 
  83.   */ 
  84.  private $errors   = array (); 
  85.  /** 
  86.   * @access public 
  87.   * @param string $callback 回调函数 
  88.   * 该函数有4个参数($response,$info,$error,$request) 
  89.   * $response url返回的body 
  90.   * $info  cURL连接资源句柄的信息 
  91.   * $error  错误 
  92.   * $request  请求对象 
  93.   */ 
  94.  public function __construct($callback = null) { 
  95.   $this->callback = $callback; 
  96.  } 
  97.  /** 
  98.   * 添加一个请求对象到列队 
  99.   * @access public 
  100.   * @param object $request 
  101.   * @return boolean 
  102.   */ 
  103.  public function add($request) { 
  104.   $this->requests [] = $request; 
  105.   return TRUE; 
  106.  } 
  107.  /** 
  108.   * 创建一个请求对象并添加到列队 
  109.   * @access public 
  110.   * @param string $url 
  111.   * @param string $method 
  112.   * @param string $post_data 
  113.   * @param string $headers 
  114.   * @param array $options 
  115.   * @return boolean 
  116.   */ 
  117.  public function request($url, $method = 'GET', $post_data = null, $headers = null, $options = null) { 
  118.   $this->requests [] = new Curl_request ( $url, $method, $post_data, $headers, $options ); 
  119.   return TRUE; 
  120.  } 
  121.  /** 
  122.   * 创建GET请求对象 
  123.   * @access public 
  124.   * @param string $url 
  125.   * @param string $headers 
  126.   * @param array $options 
  127.   * @return boolean 
  128.   */ 
  129.  public function get($url, $headers = null, $options = null) { 
  130.   return $this->request ( $url, "GET", null, $headers, $options ); 
  131.  } 
  132.  /** 
  133.   * 创建一个POST请求对象 
  134.   * @access public 
  135.   * @param string $url 
  136.   * @param string $post_data 
  137.   * @param string $headers 
  138.   * @param array $options 
  139.   * @return boolean 
  140.   */ 
  141.  public function post($url, $post_data = null, $headers = null, $options = null) { 
  142.   return $this->request ( $url, "POST", $post_data, $headers, $options ); 
  143.  } 
  144.  /** 
  145.   * 执行cURL 
  146.   * @access public 
  147.   * @param int $size 最大连接数 
  148.   * @return Ambigous <boolean, mixed>|boolean 
  149.   */ 
  150.  public function execute($size = null) { 
  151.   if (sizeof ( $this->requests ) == 1) { 
  152.    return $this->single_curl (); 
  153.   } else { 
  154.    return $this->rolling_curl ( $size ); 
  155.   } 
  156.  } 
  157.  /** 
  158.   * 单个url请求 
  159.   * @access private 
  160.   * @return mixed|boolean 
  161.   */ 
  162.  private function single_curl() { 
  163.   $ch = curl_init (); 
  164.   $request = array_shift ( $this->requests ); 
  165.   $options = $this->get_options ( $request ); 
  166.   curl_setopt_array ( $ch, $options ); 
  167.   $output = curl_exec ( $ch ); 
  168.   $info = curl_getinfo ( $ch ); 
  169.   // it's not neccesary to set a callback for one-off requests 
  170.   if ($this->callback) { 
  171.    $callback = $this->callback; 
  172.    if (is_callable ( $this->callback )) { 
  173.     call_user_func ( $callback, $output, $info, $request ); 
  174.    } 
  175.   } else 
  176.    return $output; 
  177.   return true; 
  178.  } 
  179.  /** 
  180.   * 多个url请求 
  181.   * @access private 
  182.   * @param int $size 最大连接数 
  183.   * @return boolean 
  184.   */ 
  185.  private function rolling_curl($size = null) { 
  186.   if ($size) 
  187.    $this->size = $size; 
  188.   else 
  189.    $this->size = count($this->requests); 
  190.   if (sizeof ( $this->requests ) < $this->size) 
  191.    $this->size = sizeof ( $this->requests ); 
  192.   if ($this->size < 2) 
  193.    $this->set_error ( 'size must be greater than 1' ); 
  194.   $master = curl_multi_init (); 
  195.   //添加cURL连接资源句柄到map索引 
  196.   for($i = 0; $i < $this->size; $i ++) { 
  197.    $ch = curl_init (); 
  198.    $options = $this->get_options ( $this->requests [$i] ); 
  199.    curl_setopt_array ( $ch, $options ); 
  200.    curl_multi_add_handle ( $master, $ch ); 
  201.    $key = ( string ) $ch; 
  202.    $this->request_map [$key] = $i; 
  203.   } 
  204.   $active = $done = null; 
  205.   do { 
  206.    while ( ($execrun = curl_multi_exec ( $master, $active )) == CURLM_CALL_MULTI_PERFORM ) 
  207.     ; 
  208.    if ($execrun != CURLM_OK) 
  209.     break; 
  210.    //有一个请求完成则回调 
  211.    while ( $done = curl_multi_info_read ( $master ) ) { 
  212.     //$done 完成的请求句柄 
  213.     $info = curl_getinfo ( $done ['handle'] );// 
  214.     $output = curl_multi_getcontent ( $done ['handle'] );// 
  215.     $error = curl_error ( $done ['handle'] );// 
  216.     $this->set_error ( $error ); 
  217.     //调用回调函数,如果存在的话 
  218.     $callback = $this->callback; 
  219.     if (is_callable ( $callback )) { 
  220.      $key = ( string ) $done ['handle']; 
  221.      $request = $this->requests [$this->request_map [$key]]; 
  222.      unset ( $this->request_map [$key] ); 
  223.      call_user_func ( $callback, $output, $info, $error, $request ); 
  224.     } 
  225.     curl_close ( $done ['handle'] ); 
  226.     //从列队中移除已经完成的request 
  227.     curl_multi_remove_handle ( $master, $done ['handle'] ); 
  228.    } 
  229.    //等待所有cURL批处理中的活动连接 
  230.    if ($active) 
  231.     curl_multi_select ( $master, $this->timeout ); 
  232.   } while ( $active ); 
  233.   //完成关闭 
  234.   curl_multi_close ( $master ); 
  235.   return true; 
  236.  } 
  237.  /** 
  238.   * 获取没得请求对象的cURL配置 
  239.   * @access private 
  240.   * @param object $request 
  241.   * @return array 
  242.   */ 
  243.  private function get_options($request) { 
  244.   $options = $this->__get ( 'options' ); 
  245.   if (ini_get ( 'safe_mode' ) == 'Off' || ! ini_get ( 'safe_mode' )) { 
  246.    $options [CURLOPT_FOLLOWLOCATION] = 1; 
  247.    $options [CURLOPT_MAXREDIRS] = 5; 
  248.   } 
  249.   $headers = $this->__get ( 'headers' ); 
  250.   if ($request->options) { 
  251.    $options = $request->options + $options; 
  252.   } 
  253.   $options [CURLOPT_URL] = $request->url; 
  254.   if ($request->post_data && strtolower($request->method) == 'post' ) { 
  255.    $options [CURLOPT_POST] = 1; 
  256.    $options [CURLOPT_POSTFIELDS] = $request->post_data; 
  257.   } 
  258.   if ($headers) { 
  259.    $options [CURLOPT_HEADER] = 0; 
  260.    $options [CURLOPT_HTTPHEADER] = $headers; 
  261.   } 
  262.   return $options; 
  263.  } 
  264.  /** 
  265.   * 设置错误信息 
  266.   * @access public 
  267.   * @param string $msg 
  268.   */ 
  269.  public function set_error($msg) { 
  270.   if (! emptyempty ( $msg )) 
  271.    $this->errors [] = $msg; 
  272.  } 
  273.  /** 
  274.   * 获取错误信息 
  275.   * @access public 
  276.   * @param string $open 
  277.   * @param string $close 
  278.   * @return string 
  279.   */ 
  280.  public function display_errors($open = '<p>', $close = '</p>') { 
  281.   $str = ''; 
  282.   foreach ( $this->errors as $val ) { 
  283.    $str .= $open . $val . $close; 
  284.   } 
  285.   return $str; 
  286.  } 
  287.  /** 
  288.   * @access public 
  289.   * @param string $name 
  290.   * @param string $value 
  291.   * @return boolean 
  292.   */ 
  293.  public function __set($name, $value) { 
  294.   if ($name == 'options' || $name == 'headers') { 
  295.    $this->{$name} = $value + $this->{$name}; 
  296.   } else { 
  297.    $this->{$name} = $value; 
  298.   } 
  299.   return TRUE; 
  300.  } 
  301.  /** 
  302.   *  
  303.   * @param string $name 
  304.   * @return mixed 
  305.   * @access public 
  306.   */ 
  307.  public function __get($name) { 
  308.   return (isset ( $this->{$name} )) ? $this->{$name} : null; 
  309.  } 
  310.  /** 
  311.   * @return void 
  312.   * @access public 
  313.   */ 
  314.  public function __destruct() { 
  315.   unset ( $this->size, $this->timeout, $this->callback, $this->options, $this->headers, $this->requests, $this->request_map, $this->errors ); 
  316.  } 
  317. } 
  318. // END Curl Class 
  319. /* End of file curl.class.php */

Tags: curl批处理 php并发异步

分享到: