[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/externals/httpful/src/Httpful/ -> Request.php (source)

   1  <?php
   2  
   3  namespace Httpful;
   4  
   5  use Httpful\Exception\ConnectionErrorException;
   6  
   7  /**
   8   * Clean, simple class for sending HTTP requests
   9   * in PHP.
  10   *
  11   * There is an emphasis of readability without loosing concise
  12   * syntax.  As such, you will notice that the library lends
  13   * itself very nicely to "chaining".  You will see several "alias"
  14   * methods: more readable method definitions that wrap
  15   * their more concise counterparts.  You will also notice
  16   * no public constructor.  This two adds to the readability
  17   * and "chainabilty" of the library.
  18   *
  19   * @author Nate Good <[email protected]>
  20   */
  21  class Request
  22  {
  23  
  24      // Option constants
  25      const SERIALIZE_PAYLOAD_NEVER   = 0;
  26      const SERIALIZE_PAYLOAD_ALWAYS  = 1;
  27      const SERIALIZE_PAYLOAD_SMART   = 2;
  28  
  29      const MAX_REDIRECTS_DEFAULT     = 25;
  30  
  31      public $uri,
  32             $method                  = Http::GET,
  33             $headers                 = array(),
  34             $raw_headers             = '',
  35             $strict_ssl              = false,
  36             $content_type,
  37             $expected_type,
  38             $additional_curl_opts    = array(),
  39             $auto_parse              = true,
  40             $serialize_payload_method = self::SERIALIZE_PAYLOAD_SMART,
  41             $username,
  42             $password,
  43             $serialized_payload,
  44             $payload,
  45             $parse_callback,
  46             $error_callback,
  47             $follow_redirects        = false,
  48             $max_redirects           = self::MAX_REDIRECTS_DEFAULT,
  49             $payload_serializers     = array();
  50  
  51      // Options
  52      // private $_options = array(
  53      //     'serialize_payload_method' => self::SERIALIZE_PAYLOAD_SMART
  54      //     'auto_parse' => true
  55      // );
  56  
  57      // Curl Handle
  58      public $_ch,
  59             $_debug;
  60  
  61      // Template Request object
  62      private static $_template;
  63  
  64      /**
  65       * We made the constructor private to force the factory style.  This was
  66       * done to keep the syntax cleaner and better the support the idea of
  67       * "default templates".  Very basic and flexible as it is only intended
  68       * for internal use.
  69       * @param array $attrs hash of initial attribute values
  70       */
  71      private function __construct($attrs = null)
  72      {
  73          if (!is_array($attrs)) return;
  74          foreach ($attrs as $attr => $value) {
  75              $this->$attr = $value;
  76          }
  77      }
  78  
  79      // Defaults Management
  80  
  81      /**
  82       * Let's you configure default settings for this
  83       * class from a template Request object.  Simply construct a
  84       * Request object as much as you want to and then pass it to
  85       * this method.  It will then lock in those settings from
  86       * that template object.
  87       * The most common of which may be default mime
  88       * settings or strict ssl settings.
  89       * Again some slight memory overhead incurred here but in the grand
  90       * scheme of things as it typically only occurs once
  91       * @param Request $template
  92       */
  93      public static function ini(Request $template)
  94      {
  95          self::$_template = clone $template;
  96      }
  97  
  98      /**
  99       * Reset the default template back to the
 100       * library defaults.
 101       */
 102      public static function resetIni()
 103      {
 104          self::_initializeDefaults();
 105      }
 106  
 107      /**
 108       * Get default for a value based on the template object
 109       * @return mixed default value
 110       * @param string|null $attr Name of attribute (e.g. mime, headers)
 111       *    if null just return the whole template object;
 112       */
 113      public static function d($attr)
 114      {
 115          return isset($attr) ? self::$_template->$attr : self::$_template;
 116      }
 117  
 118      // Accessors
 119  
 120      /**
 121       * @return bool does the request have a timeout?
 122       */
 123      public function hasTimeout()
 124      {
 125          return isset($this->timeout);
 126      }
 127  
 128      /**
 129       * @return bool has the internal curl request been initialized?
 130       */
 131      public function hasBeenInitialized()
 132      {
 133          return isset($this->_ch);
 134      }
 135  
 136      /**
 137       * @return bool Is this request setup for basic auth?
 138       */
 139      public function hasBasicAuth()
 140      {
 141          return isset($this->password) && isset($this->username);
 142      }
 143  
 144      /**
 145       * @return bool Is this request setup for digest auth?
 146       */
 147      public function hasDigestAuth()
 148      {
 149          return isset($this->password) && isset($this->username) && $this->additional_curl_opts['CURLOPT_HTTPAUTH'] = CURLAUTH_DIGEST;
 150      }    
 151  
 152      /**
 153       * Specify a HTTP timeout
 154       * @return Request $this
 155       * @param |int $timeout seconds to timeout the HTTP call
 156       */
 157      public function timeout($timeout)
 158      {
 159          $this->timeout = $timeout;
 160          return $this;
 161      }
 162  
 163      /**
 164       * If the response is a 301 or 302 redirect, automatically
 165       * send off another request to that location
 166       * @return Request $this
 167       * @param bool|int $follow follow or not to follow or maximal number of redirects
 168       */
 169      public function followRedirects($follow = true)
 170      {
 171          $this->max_redirects = $follow === true ? self::MAX_REDIRECTS_DEFAULT : max(0, $follow);
 172          $this->follow_redirects = (bool) $follow;
 173          return $this;
 174      }
 175  
 176      /**
 177       * @return Request $this
 178       * @see Request::followRedirects()
 179       */
 180      public function doNotFollowRedirects()
 181      {
 182          return $this->followRedirects(false);
 183      }
 184  
 185      /**
 186       * Actually send off the request, and parse the response
 187       * @return string|associative array of parsed results
 188       * @throws ConnectionErrorException when unable to parse or communicate w server
 189       */
 190      public function send()
 191      {
 192          if (!$this->hasBeenInitialized())
 193              $this->_curlPrep();
 194  
 195          $result = curl_exec($this->_ch);
 196  
 197          if ($result === false) {
 198              $this->_error(curl_error($this->_ch));
 199              throw new ConnectionErrorException('Unable to connect.');
 200          }
 201  
 202          $info = curl_getinfo($this->_ch);
 203          $response = explode("\r\n\r\n", $result, 2 + $info['redirect_count']);
 204  
 205          $body = array_pop($response);
 206          $headers = array_pop($response);
 207  
 208          return new Response($body, $headers, $this);
 209      }
 210      public function sendIt()
 211      {
 212          return $this->send();
 213      }
 214  
 215      // Setters
 216  
 217      /**
 218       * @return Request this
 219       * @param string $uri
 220       */
 221      public function uri($uri)
 222      {
 223          $this->uri = $uri;
 224          return $this;
 225      }
 226  
 227      /**
 228       * User Basic Auth.
 229       * Only use when over SSL/TSL/HTTPS.
 230       * @return Request this
 231       * @param string $username
 232       * @param string $password
 233       */
 234      public function basicAuth($username, $password)
 235      {
 236          $this->username = $username;
 237          $this->password = $password;
 238          return $this;
 239      }
 240      // @alias of basicAuth
 241      public function authenticateWith($username, $password)
 242      {
 243          return $this->basicAuth($username, $password);
 244      }
 245      // @alias of basicAuth
 246      public function authenticateWithBasic($username, $password)
 247      {
 248          return $this->basicAuth($username, $password);
 249      }
 250  
 251      /**
 252       * User Digest Auth.
 253       * @return Request this
 254       * @param string $username
 255       * @param string $password
 256       */
 257      public function digestAuth($username, $password)
 258      {
 259          $this->addOnCurlOption(CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
 260          return $this->basicAuth($username, $password);
 261      }
 262  
 263      // @alias of digestAuth
 264      public function authenticateWithDigest($username, $password)
 265      {
 266          return $this->digestAuth($username, $password);
 267      } 
 268  
 269      /**
 270       * @return is this request setup for client side cert?
 271       */
 272      public function hasClientSideCert() {
 273          return isset($this->client_cert) && isset($this->client_key);
 274      }
 275  
 276      /**
 277       * Use Client Side Cert Authentication
 278       * @return Response $this
 279       * @param string $key file path to client key
 280       * @param string $cert file path to client cert
 281       * @param string $passphrase for client key
 282       * @param string $encoding default PEM
 283       */
 284      public function clientSideCert($cert, $key, $passphrase = null, $encoding = 'PEM')
 285      {
 286          $this->client_cert          = $cert;
 287          $this->client_key           = $key;
 288          $this->client_passphrase    = $passphrase;
 289          $this->client_encoding      = $encoding;
 290  
 291          return $this;
 292      }
 293      // @alias of basicAuth
 294      public function authenticateWithCert($cert, $key, $passphrase = null, $encoding = 'PEM')
 295      {
 296          return $this->clientSideCert($cert, $key, $passphrase, $encoding);
 297      }
 298  
 299      /**
 300       * Set the body of the request
 301       * @return Request this
 302       * @param mixed $payload
 303       * @param string $mimeType
 304       */
 305      public function body($payload, $mimeType = null)
 306      {
 307          $this->mime($mimeType);
 308          $this->payload = $payload;
 309          // Iserntentially don't call _serializePayload yet.  Wait until
 310          // we actually send off the request to convert payload to string.
 311          // At that time, the `serialized_payload` is set accordingly.
 312          return $this;
 313      }
 314  
 315      /**
 316       * Helper function to set the Content type and Expected as same in
 317       * one swoop
 318       * @return Request this
 319       * @param string $mime mime type to use for content type and expected return type
 320       */
 321      public function mime($mime)
 322      {
 323          if (empty($mime)) return $this;
 324          $this->content_type = $this->expected_type = Mime::getFullMime($mime);
 325          return $this;
 326      }
 327      // @alias of mime
 328      public function sendsAndExpectsType($mime)
 329      {
 330          return $this->mime($mime);
 331      }
 332      // @alias of mime
 333      public function sendsAndExpects($mime)
 334      {
 335          return $this->mime($mime);
 336      }
 337  
 338      /**
 339       * Set the method.  Shouldn't be called often as the preferred syntax
 340       * for instantiation is the method specific factory methods.
 341       * @return Request this
 342       * @param string $method
 343       */
 344      public function method($method)
 345      {
 346          if (empty($method)) return $this;
 347          $this->method = $method;
 348          return $this;
 349      }
 350  
 351      /**
 352       * @return Request this
 353       * @param string $mime
 354       */
 355      public function expects($mime)
 356      {
 357          if (empty($mime)) return $this;
 358          $this->expected_type = Mime::getFullMime($mime);
 359          return $this;
 360      }
 361      // @alias of expects
 362      public function expectsType($mime)
 363      {
 364          return $this->expects($mime);
 365      }
 366  
 367      /**
 368       * @return Request this
 369       * @param string $mime
 370       */
 371      public function contentType($mime)
 372      {
 373          if (empty($mime)) return $this;
 374          $this->content_type  = Mime::getFullMime($mime);
 375          return $this;
 376      }
 377      // @alias of contentType
 378      public function sends($mime)
 379      {
 380          return $this->contentType($mime);
 381      }
 382      // @alias of contentType
 383      public function sendsType($mime)
 384      {
 385          return $this->contentType($mime);
 386      }
 387  
 388      /**
 389       * Do we strictly enforce SSL verification?
 390       * @return Request this
 391       * @param bool $strict
 392       */
 393      public function strictSSL($strict)
 394      {
 395          $this->strict_ssl = $strict;
 396          return $this;
 397      }
 398      public function withoutStrictSSL()
 399      {
 400          return $this->strictSSL(false);
 401      }
 402      public function withStrictSSL()
 403      {
 404          return $this->strictSSL(true);
 405      }
 406  
 407      /**
 408       * Determine how/if we use the built in serialization by
 409       * setting the serialize_payload_method
 410       * The default (SERIALIZE_PAYLOAD_SMART) is...
 411       *  - if payload is not a scalar (object/array)
 412       *    use the appropriate serialize method according to
 413       *    the Content-Type of this request.
 414       *  - if the payload IS a scalar (int, float, string, bool)
 415       *    than just return it as is.
 416       * When this option is set SERIALIZE_PAYLOAD_ALWAYS,
 417       * it will always use the appropriate
 418       * serialize option regardless of whether payload is scalar or not
 419       * When this option is set SERIALIZE_PAYLOAD_NEVER,
 420       * it will never use any of the serialization methods.
 421       * Really the only use for this is if you want the serialize methods
 422       * to handle strings or not (e.g. Blah is not valid JSON, but "Blah"
 423       * is).  Forcing the serialization helps prevent that kind of error from
 424       * happening.
 425       * @return Request $this
 426       * @param int $mode
 427       */
 428      public function serializePayload($mode)
 429      {
 430          $this->serialize_payload_method = $mode;
 431          return $this;
 432      }
 433  
 434      /**
 435       * @see Request::serializePayload()
 436       * @return Request
 437       */
 438      public function neverSerializePayload()
 439      {
 440          return $this->serializePayload(self::SERIALIZE_PAYLOAD_NEVER);
 441      }
 442  
 443      /**
 444       * This method is the default behavior
 445       * @see Request::serializePayload()
 446       * @return Request
 447       */
 448      public function smartSerializePayload()
 449      {
 450          return $this->serializePayload(self::SERIALIZE_PAYLOAD_SMART);
 451      }
 452  
 453      /**
 454       * @see Request::serializePayload()
 455       * @return Request
 456       */
 457      public function alwaysSerializePayload()
 458      {
 459          return $this->serializePayload(self::SERIALIZE_PAYLOAD_ALWAYS);
 460      }
 461  
 462      /**
 463       * Add an additional header to the request
 464       * Can also use the cleaner syntax of
 465       * $Request->withMyHeaderName($my_value);
 466       * @see Request::__call()
 467       *
 468       * @return Request this
 469       * @param string $header_name
 470       * @param string $value
 471       */
 472      public function addHeader($header_name, $value)
 473      {
 474          $this->headers[$header_name] = $value;
 475          return $this;
 476      }
 477  
 478      /**
 479       * Add group of headers all at once.  Note: This is
 480       * here just as a convenience in very specific cases.
 481       * The preferred "readable" way would be to leverage
 482       * the support for custom header methods.
 483       * @return Response $this
 484       * @param array $headers
 485       */
 486      public function addHeaders(array $headers)
 487      {
 488          foreach ($headers as $header => $value) {
 489              $this->addHeader($header, $value);
 490          }
 491          return $this;
 492      }
 493  
 494      /**
 495       * @return Request
 496       * @param bool $auto_parse perform automatic "smart"
 497       *    parsing based on Content-Type or "expectedType"
 498       *    If not auto parsing, Response->body returns the body
 499       *    as a string.
 500       */
 501      public function autoParse($auto_parse = true)
 502      {
 503          $this->auto_parse = $auto_parse;
 504          return $this;
 505      }
 506  
 507      /**
 508       * @see Request::autoParse()
 509       * @return Request
 510       */
 511      public function withoutAutoParsing()
 512      {
 513          return $this->autoParse(false);
 514      }
 515  
 516      /**
 517       * @see Request::autoParse()
 518       * @return Request
 519       */
 520      public function withAutoParsing()
 521      {
 522          return $this->autoParse(true);
 523      }
 524  
 525      /**
 526       * Use a custom function to parse the response.
 527       * @return Request this
 528       * @param \Closure $callback Takes the raw body of
 529       *    the http response and returns a mixed
 530       */
 531      public function parseWith(\Closure $callback)
 532      {
 533          $this->parse_callback = $callback;
 534          return $this;
 535      }
 536  
 537      /**
 538       * @see Request::parseResponsesWith()
 539       * @return Request $this
 540       * @param \Closure $callback
 541       */
 542      public function parseResponsesWith(\Closure $callback)
 543      {
 544          return $this->parseWith($callback);
 545      }
 546  
 547      /**
 548       * Register a callback that will be used to serialize the payload
 549       * for a particular mime type.  When using "*" for the mime
 550       * type, it will use that parser for all responses regardless of the mime
 551       * type.  If a custom '*' and 'application/json' exist, the custom
 552       * 'application/json' would take precedence over the '*' callback.
 553       *
 554       * @return Request $this
 555       * @param string $mime mime type we're registering
 556       * @param Closure $callback takes one argument, $payload,
 557       *    which is the payload that we'll be
 558       */
 559      public function registerPayloadSerializer($mime, \Closure $callback)
 560      {
 561          $this->payload_serializers[Mime::getFullMime($mime)] = $callback;
 562          return $this;
 563      }
 564  
 565      /**
 566       * @see Request::registerPayloadSerializer()
 567       * @return Request $this
 568       * @param Closure $callback
 569       */
 570      public function serializePayloadWith(\Closure $callback)
 571      {
 572          return $this->regregisterPayloadSerializer('*', $callback);
 573      }
 574  
 575      /**
 576       * Magic method allows for neatly setting other headers in a
 577       * similar syntax as the other setters.  This method also allows
 578       * for the sends* syntax.
 579       * @return Request this
 580       * @param string $method "missing" method name called
 581       *    the method name called should be the name of the header that you
 582       *    are trying to set in camel case without dashes e.g. to set a
 583       *    header for Content-Type you would use contentType() or more commonly
 584       *    to add a custom header like X-My-Header, you would use xMyHeader().
 585       *    To promote readability, you can optionally prefix these methods with
 586       *    "with"  (e.g. withXMyHeader("blah") instead of xMyHeader("blah")).
 587       * @param array $args in this case, there should only ever be 1 argument provided
 588       *    and that argument should be a string value of the header we're setting
 589       */
 590      public function __call($method, $args)
 591      {
 592          // This method supports the sends* methods
 593          // like sendsJSON, sendsForm
 594          //!method_exists($this, $method) &&
 595          if (substr($method, 0, 5) === 'sends') {
 596              $mime = strtolower(substr($method, 5));
 597              if (Mime::supportsMimeType($mime)) {
 598                  $this->sends(Mime::getFullMime($mime));
 599                  return $this;
 600              }
 601              // else {
 602              //     throw new \Exception("Unsupported Content-Type $mime");
 603              // }
 604          }
 605          if (substr($method, 0, 7) === 'expects') {
 606              $mime = strtolower(substr($method, 7));
 607              if (Mime::supportsMimeType($mime)) {
 608                  $this->expects(Mime::getFullMime($mime));
 609                  return $this;
 610              }
 611              // else {
 612              //     throw new \Exception("Unsupported Content-Type $mime");
 613              // }
 614          }
 615  
 616          // This method also adds the custom header support as described in the
 617          // method comments
 618          if (count($args) === 0)
 619              return;
 620  
 621          // Strip the sugar.  If it leads with "with", strip.
 622          // This is okay because: No defined HTTP headers begin with with,
 623          // and if you are defining a custom header, the standard is to prefix it
 624          // with an "X-", so that should take care of any collisions.
 625          if (substr($method, 0, 4) === 'with')
 626              $method = substr($method, 4);
 627  
 628          // Precede upper case letters with dashes, uppercase the first letter of method
 629          $header = ucwords(implode('-', preg_split('/([A-Z][^A-Z]*)/', $method, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)));
 630          $this->addHeader($header, $args[0]);
 631          return $this;
 632      }
 633  
 634      // Internal Functions
 635  
 636      /**
 637       * This is the default template to use if no
 638       * template has been provided.  The template
 639       * tells the class which default values to use.
 640       * While there is a slight overhead for object
 641       * creation once per execution (not once per
 642       * Request instantiation), it promotes readability
 643       * and flexibility within the class.
 644       */
 645      private static function _initializeDefaults()
 646      {
 647          // This is the only place you will
 648          // see this constructor syntax.  It
 649          // is only done here to prevent infinite
 650          // recusion.  Do not use this syntax elsewhere.
 651          // It goes against the whole readability
 652          // and transparency idea.
 653          self::$_template = new Request(array('method' => Http::GET));
 654  
 655          // This is more like it...
 656          self::$_template
 657              ->withoutStrictSSL();
 658      }
 659  
 660      /**
 661       * Set the defaults on a newly instantiated object
 662       * Doesn't copy variables prefixed with _
 663       * @return Request this
 664       */
 665      private function _setDefaults()
 666      {
 667          if (!isset(self::$_template))
 668              self::_initializeDefaults();
 669          foreach (self::$_template as $k=>$v) {
 670              if ($k[0] != '_')
 671                  $this->$k = $v;
 672          }
 673          return $this;
 674      }
 675  
 676      private function _error($error)
 677      {
 678          // Default actions write to error log
 679          // TODO add in support for various Loggers
 680          error_log($error);
 681      }
 682  
 683      /**
 684       * Factory style constructor works nicer for chaining.  This
 685       * should also really only be used internally.  The Request::get,
 686       * Request::post syntax is preferred as it is more readable.
 687       * @return Request
 688       * @param string $method Http Method
 689       * @param string $mime Mime Type to Use
 690       */
 691      public static function init($method = null, $mime = null)
 692      {
 693          // Setup our handlers, can call it here as it's idempotent
 694          Bootstrap::init();
 695  
 696          // Setup the default template if need be
 697          if (!isset(self::$_template))
 698              self::_initializeDefaults();
 699  
 700          $request = new Request();
 701          return $request
 702                 ->_setDefaults()
 703                 ->method($method)
 704                 ->sendsType($mime)
 705                 ->expectsType($mime);
 706      }
 707  
 708      /**
 709       * Does the heavy lifting.  Uses de facto HTTP
 710       * library cURL to set up the HTTP request.
 711       * Note: It does NOT actually send the request
 712       * @return Request $this;
 713       */
 714      public function _curlPrep()
 715      {
 716          // Check for required stuff
 717          if (!isset($this->uri))
 718              throw new \Exception('Attempting to send a request before defining a URI endpoint.');
 719  
 720          $ch = curl_init($this->uri);
 721  
 722          curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method);
 723  
 724          if ($this->hasBasicAuth()) {
 725              curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password);
 726          }
 727  
 728          if ($this->hasClientSideCert()) {
 729  
 730              if (!file_exists($this->client_key))
 731                  throw new \Exception('Could not read Client Key');
 732  
 733              if (!file_exists($this->client_cert))
 734                  throw new \Exception('Could not read Client Certificate');
 735  
 736              curl_setopt($ch, CURLOPT_SSLCERTTYPE,   $this->client_encoding);
 737              curl_setopt($ch, CURLOPT_SSLKEYTYPE,    $this->client_encoding);
 738              curl_setopt($ch, CURLOPT_SSLCERT,       $this->client_cert);
 739              curl_setopt($ch, CURLOPT_SSLKEY,        $this->client_key);
 740              curl_setopt($ch, CURLOPT_SSLKEYPASSWD,  $this->client_passphrase);
 741              // curl_setopt($ch, CURLOPT_SSLCERTPASSWD,  $this->client_cert_passphrase);
 742          }
 743  
 744          if ($this->hasTimeout()) {
 745              curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
 746          }
 747          
 748          if ($this->follow_redirects) {
 749              curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
 750              curl_setopt($ch, CURLOPT_MAXREDIRS, $this->max_redirects);
 751          }
 752  
 753          curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->strict_ssl);
 754          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 755  
 756          $headers = array();
 757          // https://github.com/nategood/httpful/issues/37
 758          // Except header removes any HTTP 1.1 Continue from response headers
 759          $headers[] = 'Expect:';
 760  
 761          if (!isset($this->headers['User-Agent'])) {
 762              $headers[] = $this->buildUserAgent();
 763          }
 764  
 765          $headers[] = "Content-Type: {$this->content_type}";
 766  
 767          // allow custom Accept header if set
 768          if (!isset($this->headers['Accept'])) {
 769              // http://pretty-rfc.herokuapp.com/RFC2616#header.accept
 770              $accept = 'Accept: */*; q=0.5, text/plain; q=0.8, text/html;level=3;';
 771  
 772              if (!empty($this->expected_type)) {
 773                  $accept .= "q=0.9, {$this->expected_type}";
 774              }
 775  
 776              $headers[] = $accept;
 777          }
 778  
 779          foreach ($this->headers as $header => $value) {
 780              $headers[] = "$header: $value";
 781          }
 782  
 783          $url = \parse_url($this->uri);
 784          $path = (isset($url['path']) ? $url['path'] : '/').(isset($url['query']) ? '?'.$url['query'] : '');
 785          $this->raw_headers = "{$this->method} $path HTTP/1.1\r\n";
 786          $host = (isset($url['host']) ? $url['host'] : 'localhost').(isset($url['port']) ? ':'.$url['port'] : '');
 787          $this->raw_headers .= "Host: $host\r\n";
 788          $this->raw_headers .= \implode("\r\n", $headers);
 789          $this->raw_headers .= "\r\n";
 790  
 791          curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 792  
 793          if (isset($this->payload)) {
 794              $this->serialized_payload = $this->_serializePayload($this->payload);
 795              curl_setopt($ch, CURLOPT_POSTFIELDS, $this->serialized_payload);
 796          }
 797  
 798          if ($this->_debug) {
 799              curl_setopt($ch, CURLOPT_VERBOSE, true);
 800          }
 801  
 802          curl_setopt($ch, CURLOPT_HEADER, 1);
 803  
 804          // If there are some additional curl opts that the user wants
 805          // to set, we can tack them in here
 806          foreach ($this->additional_curl_opts as $curlopt => $curlval) {
 807              curl_setopt($ch, $curlopt, $curlval);
 808          }
 809  
 810          $this->_ch = $ch;
 811  
 812          return $this;
 813      }
 814  
 815      public function buildUserAgent() {
 816          $user_agent = 'User-Agent: Httpful/' . Httpful::VERSION . ' (cURL/';
 817          $curl = \curl_version();
 818  
 819          if (isset($curl['version'])) {
 820              $user_agent .= $curl['version'];
 821          } else {
 822              $user_agent .= '?.?.?';
 823          }
 824  
 825          $user_agent .= ' PHP/'. PHP_VERSION . ' (' . PHP_OS . ')';
 826  
 827          if (isset($_SERVER['SERVER_SOFTWARE'])) {
 828              $user_agent .= ' ' . \preg_replace('~PHP/[\d\.]+~U', '',
 829                  $_SERVER['SERVER_SOFTWARE']);
 830          } else {
 831              if (isset($_SERVER['TERM_PROGRAM'])) {
 832                  $user_agent .= " {$_SERVER['TERM_PROGRAM']}";
 833              }
 834  
 835              if (isset($_SERVER['TERM_PROGRAM_VERSION'])) {
 836                  $user_agent .= "/{$_SERVER['TERM_PROGRAM_VERSION']}";
 837              }
 838          }
 839  
 840          if (isset($_SERVER['HTTP_USER_AGENT'])) {
 841              $user_agent .= " {$_SERVER['HTTP_USER_AGENT']}";
 842          }
 843  
 844          $user_agent .= ')';
 845  
 846          return $user_agent;
 847      }
 848  
 849      /**
 850       * Semi-reluctantly added this as a way to add in curl opts
 851       * that are not otherwise accessible from the rest of the API.
 852       * @return Request $this
 853       * @param string $curlopt
 854       * @param mixed $curloptval
 855       */
 856      public function addOnCurlOption($curlopt, $curloptval)
 857      {
 858          $this->additional_curl_opts[$curlopt] = $curloptval;
 859          return $this;
 860      }
 861  
 862      /**
 863       * Turn payload from structured data into
 864       * a string based on the current Mime type.
 865       * This uses the auto_serialize option to determine
 866       * it's course of action.  See serialize method for more.
 867       * Renamed from _detectPayload to _serializePayload as of
 868       * 2012-02-15.
 869       *
 870       * Added in support for custom payload serializers.
 871       * The serialize_payload_method stuff still holds true though.
 872       * @see Request::registerPayloadSerializer()
 873       *
 874       * @return string
 875       * @param mixed $payload
 876       */
 877      private function _serializePayload($payload)
 878      {
 879          if (empty($payload) || $this->serialize_payload_method === self::SERIALIZE_PAYLOAD_NEVER)
 880              return $payload;
 881  
 882          // When we are in "smart" mode, don't serialize strings/scalars, assume they are already serialized
 883          if ($this->serialize_payload_method === self::SERIALIZE_PAYLOAD_SMART && is_scalar($payload))
 884              return $payload;
 885  
 886          // Use a custom serializer if one is registered for this mime type
 887          if (isset($this->payload_serializers['*']) || isset($this->payload_serializers[$this->content_type])) {
 888              $key = isset($this->payload_serializers[$this->content_type]) ? $this->content_type : '*';
 889              return call_user_func($this->payload_serializers[$key], $payload);
 890          }
 891  
 892          return Httpful::get($this->content_type)->serialize($payload);
 893      }
 894  
 895      /**
 896       * HTTP Method Get
 897       * @return Request
 898       * @param string $uri optional uri to use
 899       * @param string $mime expected
 900       */
 901      public static function get($uri, $mime = null)
 902      {
 903          return self::init(Http::GET)->uri($uri)->mime($mime);
 904      }
 905  
 906  
 907      /**
 908       * Like Request:::get, except that it sends off the request as well
 909       * returning a response
 910       * @return Response
 911       * @param string $uri optional uri to use
 912       * @param string $mime expected
 913       */
 914      public static function getQuick($uri, $mime = null)
 915      {
 916          return self::get($uri, $mime)->send();
 917      }
 918  
 919      /**
 920       * HTTP Method Post
 921       * @return Request
 922       * @param string $uri optional uri to use
 923       * @param string $payload data to send in body of request
 924       * @param string $mime MIME to use for Content-Type
 925       */
 926      public static function post($uri, $payload = null, $mime = null)
 927      {
 928          return self::init(Http::POST)->uri($uri)->body($payload, $mime);
 929      }
 930  
 931      /**
 932       * HTTP Method Put
 933       * @return Request
 934       * @param string $uri optional uri to use
 935       * @param string $payload data to send in body of request
 936       * @param string $mime MIME to use for Content-Type
 937       */
 938      public static function put($uri, $payload = null, $mime = null)
 939      {
 940          return self::init(Http::PUT)->uri($uri)->body($payload, $mime);
 941      }
 942  
 943      /**
 944       * HTTP Method Patch
 945       * @return Request
 946       * @param string $uri optional uri to use
 947       * @param string $payload data to send in body of request
 948       * @param string $mime MIME to use for Content-Type
 949       */
 950      public static function patch($uri, $payload = null, $mime = null)
 951      {
 952          return self::init(Http::PATCH)->uri($uri)->body($payload, $mime);
 953      }
 954  
 955      /**
 956       * HTTP Method Delete
 957       * @return Request
 958       * @param string $uri optional uri to use
 959       */
 960      public static function delete($uri, $mime = null)
 961      {
 962          return self::init(Http::DELETE)->uri($uri)->mime($mime);
 963      }
 964  
 965      /**
 966       * HTTP Method Head
 967       * @return Request
 968       * @param string $uri optional uri to use
 969       */
 970      public static function head($uri)
 971      {
 972          return self::init(Http::HEAD)->uri($uri);
 973      }
 974  
 975      /**
 976       * HTTP Method Options
 977       * @return Request
 978       * @param string $uri optional uri to use
 979       */
 980      public static function options($uri)
 981      {
 982          return self::init(Http::OPTIONS)->uri($uri);
 983      }
 984  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1