[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/zend/Zend/Http/Client/Adapter/ -> Curl.php (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1