예제 #1
0
 /**
  * Constructor.
  *
  * @param  string  $body     The body data.
  * @param  int     $status   The status code.
  * @param  array   $headers  The custom headers.
  */
 public function __construct($body = 'php://memory', $status = 200, array $headers = array())
 {
     if (!$body instanceof StreamInterface) {
         $body = new Stream($body, Stream::MODE_READ_WRITE_RESET);
     }
     foreach ($headers as $name => $value) {
         $value = HeaderHelper::allToArray($value);
         if (!HeaderHelper::arrayOnlyContainsString($value)) {
             throw new \InvalidArgumentException('Header values should ony have string.');
         }
         if (!HeaderHelper::isValidName($name)) {
             throw new \InvalidArgumentException('Invalid header name');
         }
         $normalized = strtolower($name);
         $this->headerNames[$normalized] = $name;
         $this->headers[$name] = $value;
     }
     $this->stream = $body;
     $this->statusCode = $status;
 }
예제 #2
0
 /**
  * Class init.
  *
  * @param string|UriInterface    $uri
  * @param string                 $method
  * @param string|StreamInterface $body
  * @param array                  $headers
  */
 public function __construct($uri = null, $method = null, $body = 'php://memory', $headers = array())
 {
     if (!$body instanceof StreamInterface) {
         $body = new Stream($body, Stream::MODE_READ_WRITE_RESET);
     }
     if (!$uri instanceof UriInterface) {
         $uri = new PsrUri((string) $uri);
     }
     foreach ($headers as $name => $value) {
         $value = HeaderHelper::allToArray($value);
         if (!HeaderHelper::arrayOnlyContainsString($value)) {
             throw new \InvalidArgumentException('Header values should ony have string.');
         }
         if (!HeaderHelper::isValidName($name)) {
             throw new \InvalidArgumentException('Invalid header name');
         }
         $normalized = strtolower($name);
         $this->headerNames[$normalized] = $name;
         $this->headers[$name] = $value;
     }
     $this->stream = $body;
     $this->method = $this->validateMethod($method);
     $this->uri = $uri;
 }
예제 #3
0
 /**
  * Send a request to the server and return a Response object with the response.
  *
  * @param   RequestInterface  $request  The request object to store request params.
  *
  * @return  ResponseInterface
  *
  * @since    2.1
  */
 protected function doRequest(RequestInterface $request)
 {
     // Setup the cURL handle.
     $ch = curl_init();
     // Set the request method.
     $options[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
     // Don't wait for body when $method is HEAD
     $options[CURLOPT_NOBODY] = $request->getMethod() === 'HEAD';
     // Initialize the certificate store
     $options[CURLOPT_CAINFO] = $this->getOption('certpath', __DIR__ . '/cacert.pem');
     // Set HTTP Version
     switch ($request->getProtocolVersion()) {
         case '1.0':
             $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
             break;
         case '1.1':
             $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
             break;
         case '2.0':
             if (defined('CURL_HTTP_VERSION_2_0')) {
                 $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
             }
     }
     // If data exists let's encode it and make sure our Content-type header is set.
     $data = (string) $request->getBody();
     if (isset($data)) {
         // If the data is a scalar value simply add it to the cURL post fields.
         if (is_scalar($data) || strpos($request->getHeaderLine('Content-Type'), 'multipart/form-data') === 0) {
             $options[CURLOPT_POSTFIELDS] = $data;
         } else {
             $options[CURLOPT_POSTFIELDS] = http_build_query($data);
         }
         if (!$request->getHeaderLine('Content-Type')) {
             $request = $request->withHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
         }
         // Add the relevant headers.
         if (is_scalar($options[CURLOPT_POSTFIELDS])) {
             $request = $request->withHeader('Content-Length', strlen($options[CURLOPT_POSTFIELDS]));
         }
     }
     // Build the headers string for the request.
     if ($headers = $request->getHeaders()) {
         // Add the headers string into the stream context options array.
         $options[CURLOPT_HTTPHEADER] = HeaderHelper::toHeaderLine($headers);
     }
     // If an explicit timeout is given user it.
     if ($timeout = $this->getOption('timeout')) {
         $options[CURLOPT_TIMEOUT] = (int) $timeout;
         $options[CURLOPT_CONNECTTIMEOUT] = (int) $timeout;
     }
     // If an explicit user agent is given use it.
     if ($userAgent = $this->getOption('userAgent')) {
         $options[CURLOPT_USERAGENT] = $userAgent;
     }
     // Set the request URL.
     $options[CURLOPT_URL] = (string) $request->getRequestTarget();
     // We want our headers. :-)
     $options[CURLOPT_HEADER] = true;
     // Return it... echoing it would be tacky.
     $options[CURLOPT_RETURNTRANSFER] = true;
     // Override the Expect header to prevent cURL from confusing itself in its own stupidity.
     // Link: http://the-stickman.com/web-development/php-and-curl-disabling-100-continue-header/
     $options[CURLOPT_HTTPHEADER][] = 'Expect:';
     /*
      * Follow redirects if server config allows
      * @deprecated  safe_mode is removed in PHP 5.4, check will be dropped when PHP 5.3 support is dropped
      */
     if (!ini_get('safe_mode') && !ini_get('open_basedir')) {
         $options[CURLOPT_FOLLOWLOCATION] = (bool) isset($this->options['follow_location']) ? $this->options['follow_location'] : true;
     }
     // Set any custom transport options
     if ($this->getOption('options')) {
         foreach ((array) $this->getOption('options') as $key => $value) {
             $options[$key] = $value;
         }
     }
     // Set the cURL options.
     curl_setopt_array($ch, $options);
     // Execute the request and close the connection.
     $content = curl_exec($ch);
     if (!$this->getOption('allow_empty_result', false) && !trim($content)) {
         $message = curl_error($ch);
         // Error but nothing from cURL? Create our own
         $message = $message ?: 'No HTTP response received';
         throw new \RuntimeException($message);
     }
     // Get the request information.
     $info = curl_getinfo($ch);
     // Close the connection.
     curl_close($ch);
     return $this->getResponse($content, $info);
 }
예제 #4
0
 /**
  * createHeader
  *
  * @param string $name
  *
  * @return  static
  */
 protected function createHeader($name)
 {
     $new = clone $this;
     $normalized = strtolower($name);
     $name = HeaderHelper::normalizeHeaderName($name);
     $new->headerNames[$normalized] = $name;
     $new->headers[$name] = array();
     return $new;
 }
예제 #5
0
 /**
  * Send a request to the server and return a Response object with the response.
  *
  * @param   RequestInterface  $request  The request object to store request params.
  *
  * @return  ResponseInterface
  *
  * @since   2.1
  */
 protected function doRequest(RequestInterface $request)
 {
     // Create the stream context options array with the required method offset.
     $options = array('method' => $request->getMethod());
     // Set HTTP Version
     $options['protocol_version'] = $request->getProtocolVersion();
     // If data exists let's encode it and make sure our Content-Type header is set.
     $data = (string) $request->getBody();
     if (isset($data)) {
         // If the data is a scalar value simply add it to the stream context options.
         if (is_scalar($data)) {
             $options['content'] = $data;
         } else {
             $options['content'] = http_build_query($data);
         }
         if (!$request->getHeader('Content-Type')) {
             $request = $request->withHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
         }
         // Add the relevant headers.
         $request = $request->withHeader('Content-Length', strlen($options['content']));
     }
     // Speed up stream get URL
     // @see http://stackoverflow.com/questions/3629504/php-file-get-contents-very-slow-when-using-full-url
     // @see http://stackoverflow.com/questions/13679976/how-to-speed-up-file-get-contents
     $request = $request->withHeader('Connection', 'Close');
     // Build the headers string for the request.
     if ($headers = $request->getHeaders()) {
         // Add the headers string into the stream context options array.
         $options['header'] = HeaderHelper::toHeaderLine($headers, true);
     }
     // If an explicit timeout is given user it.
     if ($this->getOption('timeout')) {
         $options['timeout'] = (int) $this->getOption('timeout');
     }
     // If an explicit user agent is given use it.
     if ($this->getOption('userAgent')) {
         $options['user_agent'] = $this->getOption('userAgent');
     }
     // Ignore HTTP errors so that we can capture them.
     $options['ignore_errors'] = 1;
     // Follow redirects.
     $options['follow_location'] = (int) $this->getOption('follow_location', 1);
     foreach ((array) $this->getOption('options') as $key => $value) {
         $options[$key] = $value;
     }
     // Create the stream context for the request.
     $context = stream_context_create(array('http' => $options));
     // Capture PHP errors
     $php_errormsg = '';
     $track_errors = ini_get('track_errors');
     ini_set('track_errors', true);
     $connection = @fopen($request->getRequestTarget(), Stream::MODE_READ_ONLY_FROM_BEGIN, false, $context);
     if (!$connection) {
         if (!$php_errormsg) {
             // Error but nothing from php? Create our own
             $php_errormsg = sprintf('Could not connect to resource: %s', $request->getRequestTarget());
         }
         // Restore error tracking to give control to the exception handler
         ini_set('track_errors', $track_errors);
         throw new \RuntimeException($php_errormsg);
     }
     $stream = new Stream($connection);
     if ($dest = $this->getOption('target_file')) {
         $content = '';
         StreamHelper::copyTo($stream, $dest);
     } else {
         $content = $stream->getContents();
     }
     $metadata = $stream->getMetadata();
     $stream->close();
     if (isset($metadata['wrapper_data']['headers'])) {
         $headers = $metadata['wrapper_data']['headers'];
     } elseif (isset($metadata['wrapper_data'])) {
         $headers = $metadata['wrapper_data'];
     } else {
         $headers = array();
     }
     return $this->getResponse($headers, $content);
 }
예제 #6
0
 /**
  * A simple method to quickly send attachment stream download.
  *
  * @param   string|resource    $source    The file source, can be file path or resource.
  * @param   ResponseInterface  $response  A custom Response object to contain your headers.
  * @param   array              $options   Options to provide some settings, currently supports
  *                                        "delay" and "filename".
  *
  * @return  void
  */
 public static function sendAttachment($source, ResponseInterface $response = null, $options = array())
 {
     $stream = new Stream($source, 'r');
     /** @var MessageInterface|ResponseInterface $response */
     $response = $response ?: new Response();
     $filename = null;
     if (is_string($source)) {
         $filename = pathinfo($source, PATHINFO_BASENAME);
     }
     if (isset($options['filename'])) {
         $filename = $options['filename'];
     }
     $response = HeaderHelper::prepareAttachmentHeaders($response, $filename);
     $response = $response->withBody($stream);
     $output = static::$outputObject;
     if (!$output instanceof StreamOutput) {
         $output = new StreamOutput();
     }
     if (isset($options['delay'])) {
         $output->setDelay($options['delay']);
     }
     $output->respond($response);
 }
예제 #7
0
 /**
  * Return an instance with the specified header appended with the given value.
  *
  * Existing values for the specified header will be maintained. The new
  * value(s) will be appended to the existing list. If the header did not
  * exist previously, it will be added.
  *
  * This method MUST be implemented in such a way as to retain the
  * immutability of the message, and MUST return an instance that has the
  * new header and/or value.
  *
  * @param string  $name  Case-insensitive header field name to add.
  * @param mixed   $value Header value(s).
  *
  * @return static
  * @throws \InvalidArgumentException for invalid header names or values.
  */
 public function withAddedHeader($name, $value)
 {
     $value = HeaderHelper::allToArray($value);
     if (!HeaderHelper::arrayOnlyContainsString($value)) {
         throw new \InvalidArgumentException('Header values should ony have string.');
     }
     if (!HeaderHelper::isValidName($name)) {
         throw new \InvalidArgumentException('Invalid header name');
     }
     $new = clone $this;
     if (!$this->hasHeader($name)) {
         $new = $new->createHeader($name);
     }
     $name = $new->getHeaderName($name);
     $new->headers[$name] = array_merge($new->headers[$name], $value);
     return $new;
 }
 /**
  * testPrepareAttachmentHeaders
  *
  * @return  void
  *
  * @covers \Windwalker\Http\Helper\HeaderHelper::prepareAttachmentHeaders
  */
 public function testPrepareAttachmentHeaders()
 {
     $response = HeaderHelper::prepareAttachmentHeaders(new Response());
     $this->assertEquals(array('application/octet-stream'), $response->getHeader('Content-Type'));
     $this->assertEquals(array('binary'), $response->getHeader('Content-Transfer-Encoding'));
     $this->assertEquals(array('no-store, no-cache, must-revalidate'), $response->getHeader('Cache-Control'));
     $this->assertEquals(array(), $response->getHeader('Content-Disposition'));
     $response = HeaderHelper::prepareAttachmentHeaders(new Response(), 'foo.zip');
     $this->assertEquals(array('attachment; filename="foo.zip"'), $response->getHeader('Content-Disposition'));
 }
 /**
  * Marshal the host and port from HTTP headers and/or the PHP environment
  *
  * @param   string  $host     The uri host.
  * @param   string  $port     The request port.
  * @param   array   $server   The $_SERVER superglobal.
  * @param   array   $headers  The headers variable from server.
  */
 public static function getHostAndPortFromHeaders(&$host, &$port, array $server, array $headers)
 {
     if (HeaderHelper::getValue($headers, 'host', false)) {
         static::getHostAndPortFromHeader($host, $port, HeaderHelper::getValue($headers, 'host'));
         return;
     }
     if (!isset($server['SERVER_NAME'])) {
         return;
     }
     $host = $server['SERVER_NAME'];
     if (isset($server['SERVER_PORT'])) {
         $port = (int) $server['SERVER_PORT'];
     }
     if (!isset($server['SERVER_ADDR']) || !preg_match('/^\\[[0-9a-fA-F\\:]+\\]$/', $host)) {
         return;
     }
     // Handle Ipv6
     $host = '[' . $server['SERVER_ADDR'] . ']';
     $port = $port ?: 80;
     if ($port . ']' === substr($host, strrpos($host, ':') + 1)) {
         // The last digit of the IPv6-Address has been taken as port
         // Unset the port so the default port can be used
         $port = null;
     }
 }
예제 #10
0
 /**
  * Send all response headers.
  *
  * @param   ResponseInterface  $response  Response object to contain headers.
  *
  * @return  Output  Instance of $this to allow chaining.
  */
 public function sendHeaders(ResponseInterface $response)
 {
     foreach ($response->getHeaders() as $header => $values) {
         $first = true;
         $header = HeaderHelper::normalizeHeaderName($header);
         foreach ($values as $value) {
             $this->header(sprintf('%s: %s', $header, $value), $first);
             $first = false;
         }
     }
     return $this;
 }