wemersonrv

ACurl

Sep 7th, 2012
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 6.52 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4.  * ACurl.php
  5.  *
  6.  * Run multiple cURL parallel requests in Asynchronous way
  7.  *
  8.  *  - Uses a curl_multi handler to make the requests in parallel
  9.  *  - when response is returned from the host, the class call an
  10.  *    external callback function with the response data as a parameter
  11.  *  - The programmer defines the number of simultaneous request to prevent
  12.  *    server overload useing a queue to manipulate the remaining requests
  13.  *    after the first requests returns.
  14.  *  - And on each request returned, a new queued request is started.
  15.  *
  16.  * @author Wemerson C. Guimarães <[email protected]>
  17.  * @version 0.1
  18.  * @copyright Copyright &copy; 2012 Wemerson C. Guimarães
  19.  * @access public
  20.  */
  21. Class ACurl{
  22.    
  23.     /**
  24.      * Array with the sources of URLs to be loaded
  25.      * @access private
  26.      * @var $sources
  27.      * @example array(
  28.      *      array(
  29.      *          "ID"=>"328",
  30.      *          "name"=>"Celebridades | Terra - Gente",
  31.      *          "url"   => "http://rss.terra.com.br/0,,EI13419,00.xml"
  32.      *      ),
  33.      *      array(
  34.      *          "ID"    => "304",
  35.      *          "feed"  => "Notícias pelo Mundo | G1 - Mundo" ,
  36.      *          "url"   => "http://g1.globo.com/dynamo/mundo/rss2.xml"
  37.      *      )
  38.      *  )
  39.      */
  40.     private $sources = array();
  41.  
  42.     /**
  43.      * Last sources item index... This will be incremented on each new request queued
  44.      * @access private
  45.      * @var $last_index
  46.      */
  47.     private $last_index;
  48.  
  49.     /**
  50.      * Qtd of simultaneous requests in parallel
  51.      * @access private
  52.      * @var $parallels
  53.      */
  54.     private $parallels;
  55.  
  56.     /**
  57.      * The multiple cURL handle
  58.      * @access private
  59.      * @var $cMulti_handle
  60.      */
  61.     private $cMulti_handle;
  62.    
  63.  
  64.     /**
  65.      * The class Constructor
  66.      *
  67.      * @param Array $sources        Array of URLs to be loaded
  68.      * @param Integer $parallels    Qtd of simultaneous requests in parallel
  69.      * @param Array $custom_options User custom options
  70.      * @todo  $custom_options is not working yet... do this in the future versions
  71.      *
  72.      */
  73.     public function __construct($sources=null,  $parallels=5, $custom_options=null){
  74.        
  75.         // Set sources
  76.         $this->setSources($sources);
  77.        
  78.         // Fix the max of simultaneous requests.
  79.         $this->parallels = $parallels;
  80.         $this->parallels = (sizeof($this->sources) < $this->parallels) ? sizeof($this->sources) : $this->parallels;
  81.     }
  82.  
  83.     /**
  84.      * Fill the Array of sources with the URLs
  85.      *
  86.      * @param Array $sources            Array of URLs to be loaded
  87.      *
  88.      */
  89.     public function setSources($sources){
  90.         $this->sources = $sources;
  91.     }
  92.  
  93.     /**
  94.      * Run and Process the requests and each callbacks.
  95.      *
  96.      * @param Function $callback            External asynchronous function to manipulate the response of the requests.
  97.      * @return Array
  98.      *
  99.      */
  100.     public function run($callback){
  101.        
  102.         /**
  103.          * Create the asynchronous cURL multi-handle
  104.          * This will receive the queue of requests
  105.          */
  106.         $this->cMulti_handle = curl_multi_init();
  107.  
  108.         /**
  109.          * Fill the queue with the first requests
  110.          * The size of queue is defined in $this->parallels
  111.          */
  112.         for ($this->last_index = 0; $this->last_index < $this->parallels; $this->last_index++){
  113.             $this->createRequest($this->last_index);
  114.         }
  115.  
  116.         /**
  117.          * Array with the requests failed to be processed ( http_code != 200 )
  118.          * It will be returned bye this method
  119.          */
  120.         $fail = array();    // URLS que tiveram retorno diferente de 200
  121.         do {
  122.             while(($execrun = curl_multi_exec($this->cMulti_handle, $running)) == CURLM_CALL_MULTI_PERFORM);
  123.  
  124.             if($execrun != CURLM_OK)
  125.                 break; 
  126.            
  127.             /**
  128.              * A request was completed with http_code 200 (Read OK), or any error
  129.              */
  130.             while($done = curl_multi_info_read($this->cMulti_handle)) {
  131.                 $info = curl_getinfo($done['handle']);
  132.  
  133.                 /**
  134.                  * Find the currect URL in the sources Array,
  135.                  * Doing a foreach in $this->sources and compare
  136.                  * the handle stored in each element of the array with
  137.                  * the handle of the request response
  138.                  */
  139.                 $queue_handle = null;
  140.                 foreach($this->sources as $source){
  141.                     if($source['handle'] === $done['handle']){
  142.                         $queue_handle = $source['handle'];
  143.                         unset($source['handle']);
  144.                         $source['response_url'] = $info['url'];
  145.                         break;
  146.                     }
  147.                 }
  148.  
  149.                 /**
  150.                  * Check if the response is Ok (200) and call the external callback function
  151.                  * passing the response data loaded to be processed on it
  152.                  */
  153.                 if ($info['http_code'] == 200)  {
  154.  
  155.                     /**
  156.                      * Do a second compare of the both handles of queued and response
  157.                      * before call a callback
  158.                      */
  159.                     if($queue_handle === $done['handle']){
  160.                         unset($source['handle']);
  161.                         $callback($source, curl_multi_getcontent($done['handle']));
  162.                     }
  163.                            
  164.                     /**
  165.                      * Add a new request to the queue to be processed
  166.                      */
  167.                     $this->createRequest($this->last_index++);
  168.  
  169.                 }else{
  170.                    
  171.                     /**
  172.                      * store a response failed to be returned by this method
  173.                      * when the queue was finished
  174.                      */
  175.                     $source['http_code'] = $info['http_code'];
  176.                     array_push($fail, $source);
  177.                 }
  178.  
  179.                 /**
  180.                  * Remove the handle because he is just finished.
  181.                  */
  182.                 curl_multi_remove_handle($this->cMulti_handle, $done['handle']);
  183.             }
  184.  
  185.         } while ($running);
  186.  
  187.         /**
  188.          *  Close the cURL multi hande
  189.          */
  190.         curl_multi_close($this->cMulti_handle);
  191.  
  192.         /**
  193.          * Return a array of requests with http_code != 200 or NULL
  194.          */
  195.         return $fail;
  196.     }
  197.  
  198.     /**
  199.      * Create a new request, add it in the cURL multi handle and store his handle in
  200.      * the sources array.
  201.      *
  202.      * @param Integer $i            Last sources item index
  203.      *
  204.      */
  205.     private function createRequest($i){
  206.        
  207.         if($i > count($this->sources) - 1)
  208.             return false;
  209.  
  210.         /**
  211.          * Start a new handle
  212.          */
  213.                
  214.         $current = curl_init($this->sources[$i]['url']);
  215.  
  216.         /**
  217.          * Define options before add this handle
  218.          */
  219.         $ua = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36";
  220.         curl_setopt($current, CURLOPT_RETURNTRANSFER    , true);
  221.         curl_setopt($current, CURLOPT_FOLLOWLOCATION, true);
  222.         curl_setopt($current, CURLOPT_MAXREDIRS, 5);
  223.         curl_setopt($current, CURLOPT_CONNECTTIMEOUT, 30);
  224.         curl_setopt($current, CURLOPT_USERAGENT, $ua);
  225.        
  226.  
  227.         /**
  228.          *
  229.          * @todo here comes the custom options of the user
  230.          *
  231.          */
  232.         // TODO
  233.  
  234.         /**
  235.          * Store the handle for future comparison
  236.          */
  237.         $this->sources[$i]['handle'] = $current;
  238.  
  239.         /**
  240.          * Add a new handle to the cURL multi handle
  241.          * It will be started instantly
  242.          */
  243.         curl_multi_add_handle($this->cMulti_handle, $current);
  244.     }
  245.  
  246. }
Advertisement
Add Comment
Please, Sign In to add comment