/** * Class init. * * @param string $body * @param int $status * @param array $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; }
/** * 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; }
/** * 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); }
/** * 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); }
/** * 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; }