Advertisement
Guest User

Zend Multi Client Adapter

a guest
Jan 5th, 2011
491
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.35 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Аналог  Zend_Http_Client_Adapter_Curl, только использует curl_multi для параллельных запросов.
  4.  * @author mapron
  5.  * @see Zend_Http_Client_Adapter_Curl
  6.  */
  7. class App_Http_ClientAdapter_Multi extends Zend_Http_Client_Adapter_Curl
  8. {
  9.     protected $_mcurl = null; // handle мультикурла;
  10.     protected $_handles = array();  // массив с handle curl-запросов.
  11.  
  12.     /**
  13.      * Выполнение запросов с помощью curl_multi
  14.      * @param array $requests массив с запросами
  15.      * @throws Zend_Http_Client_Adapter_Exception
  16.      * @throws Zend_Http_Client_Exception
  17.      */
  18.     public function execute(array $requests)
  19.     {
  20.        
  21.         $this->_mcurl = curl_multi_init();
  22.        
  23.         foreach ($requests as $id => $request) {       
  24.             $this->setConfig($request['_config']); 
  25.             // Do the actual connection
  26.             $_curl = curl_init();
  27.             if ($request['port'] != 80) {
  28.                 curl_setopt($_curl, CURLOPT_PORT, intval($request['port']));
  29.             }
  30.            
  31.             // Set timeout
  32.             curl_setopt($_curl, CURLOPT_CONNECTTIMEOUT, $this->_config['timeout']);
  33.            
  34.             // Set Max redirects
  35.             curl_setopt($_curl, CURLOPT_MAXREDIRS, $this->_config['maxredirects']);
  36.            
  37.             if (!$_curl){          
  38.                 throw new Zend_Http_Client_Adapter_Exception('Unable to Connect to ' . $request['host'] . ':' .
  39.                     $request['port']);
  40.             }
  41.            
  42.             if ($request['scheme'] !== false)
  43.             {
  44.                 // Behave the same like Zend_Http_Adapter_Socket on SSL options.
  45.                 if (isset($this->_config['sslcert']))
  46.                 {
  47.                     curl_setopt($_curl, CURLOPT_SSLCERT, $this->_config['sslcert']);
  48.                 }
  49.                 if (isset($this->_config['sslpassphrase'])) {
  50.                     curl_setopt($_curl, CURLOPT_SSLCERTPASSWD, $this->_config['sslpassphrase']);
  51.                 }
  52.             }
  53.            
  54.             // Update connected_to
  55.             $this->_connected_to = array($request['host'], $request['port']);
  56.            
  57.             if (!$_curl) {
  58.                 throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are not connected');
  59.             }
  60.            
  61.             if ($this->_connected_to[0] != $request['uri']->getHost() || $this->_connected_to[1] != $request['uri']->
  62.                 getPort()) {
  63.                 throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are connected to the wrong host');
  64.             }
  65.            
  66.             // set URL
  67.             curl_setopt($_curl, CURLOPT_URL, $request['uri']->__toString());
  68.            
  69.             // ensure correct curl call
  70.             $curlValue = true;
  71.             switch ($request['method'])
  72.             {
  73.                 case Zend_Http_Client::GET:
  74.                     $curlMethod = CURLOPT_HTTPGET;
  75.                     break;
  76.                
  77.                 case Zend_Http_Client::POST:
  78.                     $curlMethod = CURLOPT_POST;
  79.                     break;
  80.                
  81.                 case Zend_Http_Client::PUT:
  82.                     // There are two different types of PUT request, either a Raw Data string has been set
  83.                     // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used.
  84.                     if (isset($this->_config['curloptions'][CURLOPT_INFILE]))
  85.                     {
  86.                         if (!isset($this->_config['curloptions'][CURLOPT_INFILESIZE])) {
  87.                             //require_once 'Zend/Http/Client/Adapter/Exception.php';
  88.                             throw new Zend_Http_Client_Adapter_Exception(
  89.                             'Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE.'
  90.                             );
  91.                         }
  92.                        
  93.                         // Now we will probably already have Content-Length set, so that we have to delete it
  94.                         // from $headers at this point:
  95.                         foreach ($request['headers'] AS $k => $header)
  96.                         {
  97.                             if (stristr($header, 'Content-Length:') !== false) {
  98.                                 unset($request['headers'][$k]);
  99.                             }
  100.                         }
  101.                        
  102.                         $curlMethod = CURLOPT_PUT;
  103.                     } else {
  104.                         $curlMethod = CURLOPT_CUSTOMREQUEST;
  105.                         $curlValue = 'PUT';
  106.                     }
  107.                     break;
  108.                
  109.                 case Zend_Http_Client::DELETE:
  110.                     $curlMethod = CURLOPT_CUSTOMREQUEST;
  111.                     $curlValue = 'DELETE';
  112.                     break;
  113.                
  114.                 case Zend_Http_Client::OPTIONS:
  115.                     $curlMethod = CURLOPT_CUSTOMREQUEST;
  116.                     $curlValue = 'OPTIONS';
  117.                     break;
  118.                
  119.                 case Zend_Http_Client::TRACE:
  120.                     $curlMethod = CURLOPT_CUSTOMREQUEST;
  121.                     $curlValue = 'TRACE';
  122.                     break;
  123.                
  124.                 default:
  125.                     // For now, through an exception for unsupported request methods
  126.                     //require_once 'Zend/Http/Client/Adapter/Exception.php';
  127.                     throw new Zend_Http_Client_Adapter_Exception('Method currently not supported');
  128.             }
  129.            
  130.             // get http version to use
  131.             $curlHttp = ($request['httpversion'] = 1.1) ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0;
  132.            
  133.             // mark as HTTP request and set HTTP method
  134.             curl_setopt($_curl, $curlHttp, true);
  135.             curl_setopt($_curl, $curlMethod, $curlValue);
  136.            
  137.             // ensure headers are also returned
  138.             curl_setopt($_curl, CURLOPT_HEADER, true);
  139.            
  140.             // ensure actual response is returned
  141.             curl_setopt($_curl, CURLOPT_RETURNTRANSFER, true);
  142.            
  143.             // set additional headers
  144.             $request['headers']['Accept'] = '';
  145.             curl_setopt($_curl, CURLOPT_HTTPHEADER, $request['headers']);
  146.            
  147.             /**
  148.              * Make sure POSTFIELDS is set after $curlMethod is set:
  149.              * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161
  150.              */
  151.             if ($request['method'] == Zend_Http_Client::POST) {
  152.                 curl_setopt($_curl, CURLOPT_POSTFIELDS, $request['body']);
  153.             }elseif ($curlMethod == CURLOPT_PUT) {
  154.                 // this covers a PUT by file-handle:
  155.                 // Make the setting of this options explicit (rather than setting it through the loop following a bit
  156.                 // lower)
  157.                 // to group common functionality together.
  158.                 curl_setopt($_curl, CURLOPT_INFILE, $this->_config['curloptions'][CURLOPT_INFILE]);
  159.                 curl_setopt($_curl, CURLOPT_INFILESIZE, $this->_config['curloptions'][CURLOPT_INFILESIZE]);
  160.                 unset($this->_config['curloptions'][CURLOPT_INFILE]);
  161.                 unset($this->_config['curloptions'][CURLOPT_INFILESIZE]);
  162.             }elseif ($request['method'] == Zend_Http_Client::PUT) {
  163.                 // This is a PUT by a setRawData string, not by file-handle
  164.                 curl_setopt($_curl, CURLOPT_POSTFIELDS, $request['body']);
  165.             }
  166.            
  167.             // set additional curl options
  168.             if (isset($this->_config['curloptions'])) {
  169.                 foreach ((array)$this->_config['curloptions'] as $k => $v) {
  170.                     if (!in_array($k, $this->_invalidOverwritableCurlOptions)) {
  171.                         //echo $k.'=>'.$v."\r\n";
  172.                         if (curl_setopt($_curl, $k, $v) == false) {
  173.                             //require_once 'Zend/Http/Client/Exception.php';
  174.                             throw new Zend_Http_Client_Exception(sprintf("Unknown or erroreous cURL option '%s' set",
  175.                             $k));
  176.                         }
  177.                     }
  178.                 }
  179.             }          
  180.             curl_multi_add_handle($this->_mcurl, $_curl);
  181.             $this->_handles[$id] = $_curl;
  182.         }
  183.        
  184.         $running = null;
  185.         do{
  186.             curl_multi_exec($this->_mcurl, $running);
  187.             // added a usleep for 0.10 seconds to reduce load
  188.             usleep (100000);
  189.         }
  190.         while ($running > 0);
  191.        
  192.         // get the content of the urls (if there is any)
  193.         $this->_response = array();
  194.         $requestsTexts = array();
  195.         foreach ($this->_handles as $id => $ch) {
  196.             // get the content of the handle
  197.             $resp = curl_multi_getcontent($ch);
  198.            
  199.             // remove the handle from the multi handle
  200.             curl_multi_remove_handle($this->_mcurl, $ch);              
  201.                
  202.            
  203.             $request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
  204.             $request .= $requests[$id]['body'];
  205.             $requestsTexts[$id] = $request;
  206.            
  207.             if (empty($resp))  {
  208.                 // require_once 'Zend/Http/Client/Exception.php';
  209.                 throw new Zend_Http_Client_Exception('Error in cURL request: ' . curl_error($ch));
  210.             }
  211.            
  212.             // cURL automatically decodes chunked-messages, this means we have to disallow the Zend_Http_Response to do
  213.             // it again
  214.             if (stripos($resp, "Transfer-Encoding: chunked\r\n")){
  215.                 $resp = str_ireplace("Transfer-Encoding: chunked\r\n", '', $resp);
  216.             }
  217.            
  218.             // Eliminate multiple HTTP responses.
  219.             do {
  220.                 $parts = preg_split('|(?:\r?\n){2}|m', $resp, 2);
  221.                 $again = false;
  222.                
  223.                 if (isset($parts[1]) && preg_match("|^HTTP/1\.[01](.*?)\r\n|mi", $parts[1])) {
  224.                     $resp = $parts[1];
  225.                     $again = true;
  226.                 }
  227.             }
  228.             while ($again);
  229.            
  230.             // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string:
  231.             if (stripos($resp, "HTTP/1.0 200 Connection established\r\n\r\n") !== false)  {
  232.                 $resp = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $resp);
  233.             }
  234.            
  235.             $this->_response[$id] = $resp;
  236.            
  237.             if (is_resource($ch)) {
  238.                 curl_close($ch);
  239.             }
  240.         }
  241.         curl_multi_close($this->_mcurl);
  242.  
  243.         return $requestsTexts;
  244.     }
  245. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement