Microsoft_Http
[ class tree: Microsoft_Http ] [ index: Microsoft_Http ] [ all elements ]

Source for file Curl.php

Documentation is available at Curl.php

  1. <?php
  2.  
  3. /**
  4.  * Zend Framework
  5.  *
  6.  * LICENSE
  7.  *
  8.  * This source file is subject to the new BSD license that is bundled
  9.  * with this package in the file LICENSE.txt.
  10.  * It is also available through the world-wide-web at this URL:
  11.  * http://framework.zend.com/license/new-bsd
  12.  * If you did not receive a copy of the license and are unable to
  13.  * obtain it through the world-wide-web, please send an email
  14.  * to license@zend.com so we can send you a copy immediately.
  15.  *
  16.  * @category   Microsoft
  17.  * @package    Microsoft_Http
  18.  * @subpackage Client_Adapter
  19.  * @version    $Id: Curl.php 19238 2009-11-25 17:13:38Z bate $
  20.  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  21.  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  22.  */
  23.  
  24. /**
  25.  * @see Microsoft_AutoLoader
  26.  */
  27. require_once dirname(__FILE__'/../../../AutoLoader.php';
  28.  
  29. /**
  30.  * An adapter class for Microsoft_Http_Client based on the curl extension.
  31.  * Curl requires libcurl. See for full requirements the PHP manual: http://php.net/curl
  32.  *
  33.  * @category   Microsoft
  34.  * @package    Microsoft_Http
  35.  * @subpackage Client_Adapter
  36.  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  37.  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  38.  */
  39. class Microsoft_Http_Client_Adapter_Curl implements Microsoft_Http_Client_Adapter_InterfaceMicrosoft_Http_Client_Adapter_Stream
  40. {
  41.     /**
  42.      * Parameters array
  43.      *
  44.      * @var array 
  45.      */
  46.     protected $_config = array();
  47.  
  48.     /**
  49.      * What host/port are we connected to?
  50.      *
  51.      * @var array 
  52.      */
  53.     protected $_connected_to = array(nullnull);
  54.  
  55.     /**
  56.      * The curl session handle
  57.      *
  58.      * @var resource|null
  59.      */
  60.     protected $_curl = null;
  61.  
  62.     /**
  63.      * List of cURL options that should never be overwritten
  64.      *
  65.      * @var array 
  66.      */
  67.     protected $_invalidOverwritableCurlOptions = array(
  68.         CURLOPT_HTTPGET,
  69.         CURLOPT_POST,
  70.         CURLOPT_PUT,
  71.         CURLOPT_CUSTOMREQUEST,
  72.         CURLOPT_HEADER,
  73.         CURLOPT_RETURNTRANSFER,
  74.         CURLOPT_HTTPHEADER,
  75.         CURLOPT_POSTFIELDS,
  76.         CURLOPT_INFILE,
  77.         CURLOPT_INFILESIZE,
  78.         CURLOPT_PORT,
  79.         CURLOPT_MAXREDIRS,
  80.         CURLOPT_CONNECTTIMEOUT,
  81.         CURL_HTTP_VERSION_1_1,
  82.         CURL_HTTP_VERSION_1_0,
  83.     );
  84.  
  85.     /**
  86.      * Response gotten from server
  87.      *
  88.      * @var string 
  89.      */
  90.     protected $_response = null;
  91.  
  92.     /**
  93.      * Stream for storing output
  94.      *
  95.      * @var resource 
  96.      */
  97.     protected $out_stream;
  98.  
  99.     /**
  100.      * Adapter constructor
  101.      *
  102.      * Config is set using setConfig()
  103.      *
  104.      * @return void 
  105.      * @throws Microsoft_Http_Client_Adapter_Exception
  106.      */
  107.     public function __construct()
  108.     {
  109.         if (!extension_loaded('curl')) {
  110.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  111.             throw new Microsoft_Http_Client_Adapter_Exception('cURL extension has to be loaded to use this Microsoft_Http_Client adapter.');
  112.         }
  113.     }
  114.  
  115.     /**
  116.      * Set the configuration array for the adapter
  117.      *
  118.      * @throws Microsoft_Http_Client_Adapter_Exception
  119.      * @param  array $config 
  120.      * @return Microsoft_Http_Client_Adapter_Curl 
  121.      */
  122.     public function setConfig($config array())
  123.     {
  124.         if (is_array($config)) {
  125.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  126.             throw new Microsoft_Http_Client_Adapter_Exception(
  127.                 'Array expected, got ' gettype($config)
  128.             );
  129.         }
  130.  
  131.         if(isset($config['proxy_user']&& isset($config['proxy_pass'])) {
  132.             $this->setCurlOption(CURLOPT_PROXYUSERPWD$config['proxy_user'].":".$config['proxy_pass']);
  133.             unset($config['proxy_user']$config['proxy_pass']);
  134.         }
  135.  
  136.         foreach ($config as $k => $v{
  137.             $option strtolower($k);
  138.             switch($option{
  139.                 case 'proxy_host':
  140.                     $this->setCurlOption(CURLOPT_PROXY$v);
  141.                     break;
  142.                 case 'proxy_port':
  143.                     $this->setCurlOption(CURLOPT_PROXYPORT$v);
  144.                     break;
  145.                 default:
  146.                     $this->_config[$option$v;
  147.                     break;
  148.             }
  149.         }
  150.  
  151.         return $this;
  152.     }
  153.  
  154.     /**
  155.       * Retrieve the array of all configuration options
  156.       *
  157.       * @return array 
  158.       */
  159.      public function getConfig()
  160.      {
  161.          return $this->_config;
  162.      }
  163.  
  164.     /**
  165.      * Direct setter for cURL adapter related options.
  166.      *
  167.      * @param  string|int$option 
  168.      * @param  mixed $value 
  169.      * @return Microsoft_Http_Adapter_Curl 
  170.      */
  171.     public function setCurlOption($option$value)
  172.     {
  173.         if (!isset($this->_config['curloptions'])) {
  174.             $this->_config['curloptions'array();
  175.         }
  176.         $this->_config['curloptions'][$option$value;
  177.         return $this;
  178.     }
  179.  
  180.     /**
  181.      * Initialize curl
  182.      *
  183.      * @param  string  $host 
  184.      * @param  int     $port 
  185.      * @param  boolean $secure 
  186.      * @return void 
  187.      * @throws Microsoft_Http_Client_Adapter_Exception if unable to connect
  188.      */
  189.     public function connect($host$port 80$secure false)
  190.     {
  191.         // If we're already connected, disconnect first
  192.         if ($this->_curl{
  193.             $this->close();
  194.         }
  195.  
  196.         // If we are connected to a different server or port, disconnect first
  197.         if ($this->_curl
  198.             && is_array($this->_connected_to)
  199.             && ($this->_connected_to[0!= $host
  200.             || $this->_connected_to[1!= $port)
  201.         {
  202.             $this->close();
  203.         }
  204.  
  205.         // Do the actual connection
  206.         $this->_curl = curl_init();
  207.         if ($port != 80{
  208.             curl_setopt($this->_curlCURLOPT_PORTintval($port));
  209.         }
  210.  
  211.         // Set timeout
  212.         curl_setopt($this->_curlCURLOPT_CONNECTTIMEOUT$this->_config['timeout']);
  213.  
  214.         // Set Max redirects
  215.         curl_setopt($this->_curlCURLOPT_MAXREDIRS$this->_config['maxredirects']);
  216.  
  217.         if (!$this->_curl{
  218.             $this->close();
  219.  
  220.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  221.             throw new Microsoft_Http_Client_Adapter_Exception('Unable to Connect to ' .  $host ':' $port);
  222.         }
  223.  
  224.         if ($secure !== false{
  225.             // Behave the same like Microsoft_Http_Adapter_Socket on SSL options.
  226.             if (isset($this->_config['sslcert'])) {
  227.                 curl_setopt($this->_curlCURLOPT_SSLCERT$this->_config['sslcert']);
  228.             }
  229.             if (isset($this->_config['sslpassphrase'])) {
  230.                 curl_setopt($this->_curlCURLOPT_SSLCERTPASSWD$this->_config['sslpassphrase']);
  231.             }
  232.         }
  233.  
  234.         // Update connected_to
  235.         $this->_connected_to = array($host$port);
  236.     }
  237.  
  238.     /**
  239.      * Send request to the remote server
  240.      *
  241.      * @param  string        $method 
  242.      * @param  Microsoft_Uri_Http $uri 
  243.      * @param  float         $http_ver 
  244.      * @param  array         $headers 
  245.      * @param  string        $body 
  246.      * @return string        $request
  247.      * @throws Microsoft_Http_Client_Adapter_Exception If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option
  248.      */
  249.     public function write($method$uri$httpVersion 1.1$headers array()$body '')
  250.     {
  251.         // Make sure we're properly connected
  252.         if (!$this->_curl{
  253.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  254.             throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are not connected");
  255.         }
  256.  
  257.         if ($this->_connected_to[0!= $uri->getHost(|| $this->_connected_to[1!= $uri->getPort()) {
  258.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  259.             throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong host");
  260.         }
  261.  
  262.         // set URL
  263.         curl_setopt($this->_curlCURLOPT_URL$uri->__toString());
  264.  
  265.         // ensure correct curl call
  266.         $curlValue true;
  267.         switch ($method{
  268.             case Microsoft_Http_Client::GET:
  269.                 $curlMethod CURLOPT_HTTPGET;
  270.                 break;
  271.  
  272.             case Microsoft_Http_Client::POST:
  273.                 $curlMethod CURLOPT_POST;
  274.                 break;
  275.  
  276.             case Microsoft_Http_Client::PUT:
  277.                 // There are two different types of PUT request, either a Raw Data string has been set
  278.                 // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used.
  279.                 if(is_resource($body)) {
  280.                     $this->_config['curloptions'][CURLOPT_INFILE$body;
  281.                 }
  282.                 if (isset($this->_config['curloptions'][CURLOPT_INFILE])) {
  283.                     // Now we will probably already have Content-Length set, so that we have to delete it
  284.                     // from $headers at this point:
  285.                     foreach ($headers AS $k => $header{
  286.                         if (preg_match('/Content-Length:\s*(\d+)/i'$header$m)) {
  287.                             if(is_resource($body)) {
  288.                                 $this->_config['curloptions'][CURLOPT_INFILESIZE= (int)$m[1];
  289.                             }
  290.                             unset($headers[$k]);
  291.                         }
  292.                     }
  293.  
  294.                     if (!isset($this->_config['curloptions'][CURLOPT_INFILESIZE])) {
  295.                         require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  296.                         throw new Microsoft_Http_Client_Adapter_Exception("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE.");
  297.                     }
  298.  
  299.                     if(is_resource($body)) {
  300.                         $body '';
  301.                     }
  302.  
  303.                     $curlMethod CURLOPT_PUT;
  304.                 else {
  305.                     $curlMethod CURLOPT_CUSTOMREQUEST;
  306.                     $curlValue "PUT";
  307.                 }
  308.                 break;
  309.  
  310.             case Microsoft_Http_Client::DELETE:
  311.                 $curlMethod CURLOPT_CUSTOMREQUEST;
  312.                 $curlValue "DELETE";
  313.                 break;
  314.  
  315.             case Microsoft_Http_Client::OPTIONS:
  316.                 $curlMethod CURLOPT_CUSTOMREQUEST;
  317.                 $curlValue "OPTIONS";
  318.                 break;
  319.  
  320.             case Microsoft_Http_Client::TRACE:
  321.                 $curlMethod CURLOPT_CUSTOMREQUEST;
  322.                 $curlValue "TRACE";
  323.                 break;
  324.  
  325.             default:
  326.                 // For now, through an exception for unsupported request methods
  327.                 require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  328.                 throw new Microsoft_Http_Client_Adapter_Exception("Method currently not supported");
  329.         }
  330.  
  331.         if(is_resource($body&& $curlMethod != CURLOPT_PUT{
  332.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  333.             throw new Microsoft_Http_Client_Adapter_Exception("Streaming requests are allowed only with PUT");
  334.         }
  335.  
  336.         // get http version to use
  337.         $curlHttp ($httpVersion == 1.1CURL_HTTP_VERSION_1_1 CURL_HTTP_VERSION_1_0;
  338.  
  339.         // mark as HTTP request and set HTTP method
  340.         curl_setopt($this->_curl$curlHttptrue);
  341.         curl_setopt($this->_curl$curlMethod$curlValue);
  342.  
  343.         if($this->out_stream{
  344.             // headers will be read into the response
  345.             curl_setopt($this->_curlCURLOPT_HEADERfalse);
  346.             curl_setopt($this->_curlCURLOPT_HEADERFUNCTIONarray($this"readHeader"));
  347.             // and data will be written into the file
  348.             curl_setopt($this->_curlCURLOPT_FILE$this->out_stream);
  349.         else {
  350.             // ensure headers are also returned
  351.             curl_setopt($this->_curlCURLOPT_HEADERtrue);
  352.  
  353.             // ensure actual response is returned
  354.             curl_setopt($this->_curlCURLOPT_RETURNTRANSFERtrue);
  355.         }
  356.  
  357.         // set additional headers
  358.         $headers['Accept''';
  359.         curl_setopt($this->_curlCURLOPT_HTTPHEADER$headers);
  360.  
  361.         /**
  362.          * Make sure POSTFIELDS is set after $curlMethod is set:
  363.          * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161
  364.          */
  365.         if ($method == Microsoft_Http_Client::POST{
  366.             curl_setopt($this->_curlCURLOPT_POSTFIELDS$body);
  367.         elseif ($curlMethod == CURLOPT_PUT{
  368.             // this covers a PUT by file-handle:
  369.             // Make the setting of this options explicit (rather than setting it through the loop following a bit lower)
  370.             // to group common functionality together.
  371.             curl_setopt($this->_curlCURLOPT_INFILE$this->_config['curloptions'][CURLOPT_INFILE]);
  372.             curl_setopt($this->_curlCURLOPT_INFILESIZE$this->_config['curloptions'][CURLOPT_INFILESIZE]);
  373.             unset($this->_config['curloptions'][CURLOPT_INFILE]);
  374.             unset($this->_config['curloptions'][CURLOPT_INFILESIZE]);
  375.         elseif ($method == Microsoft_Http_Client::PUT{
  376.             // This is a PUT by a setRawData string, not by file-handle
  377.             curl_setopt($this->_curlCURLOPT_POSTFIELDS$body);
  378.         }
  379.  
  380.         // set additional curl options
  381.         if (isset($this->_config['curloptions'])) {
  382.             foreach ((array)$this->_config['curloptions'as $k => $v{
  383.                 if (!in_array($k$this->_invalidOverwritableCurlOptions)) {
  384.                     if (curl_setopt($this->_curl$k$v== false{
  385.                         require_once 'Microsoft/Http/Client/Exception.php';
  386.                         throw new Microsoft_Http_Client_Exception(sprintf("Unknown or erroreous cURL option '%s' set"$k));
  387.                     }
  388.                 }
  389.             }
  390.         }
  391.  
  392.         // send the request
  393.         $response curl_exec($this->_curl);
  394.  
  395.         // if we used streaming, headers are already there
  396.         if(!is_resource($this->out_stream)) {
  397.             $this->_response = $response;
  398.         }
  399.  
  400.         $request  curl_getinfo($this->_curlCURLINFO_HEADER_OUT);
  401.         $request .= $body;
  402.  
  403.         if (empty($this->_response)) {
  404.             require_once 'Microsoft/Http/Client/Exception.php';
  405.             throw new Microsoft_Http_Client_Exception("Error in cURL request: " curl_error($this->_curl));
  406.         }
  407.  
  408.         // cURL automatically decodes chunked-messages, this means we have to disallow the Microsoft_Http_Response to do it again
  409.         if (stripos($this->_response"Transfer-Encoding: chunked\r\n")) {
  410.             $this->_response = str_ireplace("Transfer-Encoding: chunked\r\n"''$this->_response);
  411.         }
  412.  
  413.         // Eliminate multiple HTTP responses.
  414.         do {
  415.             $parts  preg_split('|(?:\r?\n){2}|m'$this->_response2);
  416.             $again  false;
  417.  
  418.             if (isset($parts[1]&& preg_match("|^HTTP/1\.[01](.*?)\r\n|mi"$parts[1])) {
  419.                 $this->_response    = $parts[1];
  420.                 $again              true;
  421.             }
  422.         while ($again);
  423.  
  424.         // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string:
  425.         if (stripos($this->_response"HTTP/1.0 200 Connection established\r\n\r\n"!== false{
  426.             $this->_response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n"''$this->_response);
  427.         }
  428.  
  429.         return $request;
  430.     }
  431.  
  432.     /**
  433.      * Return read response from server
  434.      *
  435.      * @return string 
  436.      */
  437.     public function read()
  438.     {
  439.         return $this->_response;
  440.     }
  441.  
  442.     /**
  443.      * Close the connection to the server
  444.      *
  445.      */
  446.     public function close()
  447.     {
  448.         if(is_resource($this->_curl)) {
  449.             curl_close($this->_curl);
  450.         }
  451.         $this->_curl         = null;
  452.         $this->_connected_to = array(nullnull);
  453.     }
  454.  
  455.     /**
  456.      * Get cUrl Handle
  457.      *
  458.      * @return resource 
  459.      */
  460.     public function getHandle()
  461.     {
  462.         return $this->_curl;
  463.     }
  464.  
  465.     /**
  466.      * Set output stream for the response
  467.      *
  468.      * @param resource $stream 
  469.      * @return Microsoft_Http_Client_Adapter_Socket 
  470.      */
  471.     public function setOutputStream($stream)
  472.     {
  473.         $this->out_stream = $stream;
  474.         return $this;
  475.     }
  476.  
  477.     /**
  478.      * Header reader function for CURL
  479.      *
  480.      * @param resource $curl 
  481.      * @param string $header 
  482.      * @return int 
  483.      */
  484.     public function readHeader($curl$header)
  485.     {
  486.         $this->_response .= $header;
  487.         return strlen($header);
  488.     }
  489. }

Documentation generated on Wed, 18 May 2011 12:06:29 +0200 by phpDocumentor 1.4.3