php curl批处理--可控并发异步

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值