Back to CurlTransport class

Method request

public \Joomla\CMS\Http\Response
request
(mixed $method, \Joomla\Uri\UriInterface $uri, mixed $data = null, array $headers = [], mixed $timeout = null, mixed $userAgent = null)
Send a request to the server and return a Response object with the response.
Parameters
  • string $method The HTTP method for sending the request.
  • \Joomla\Uri\UriInterface $uri The URI to the resource to request.
  • mixed $data Either an associative array or a string to be sent with the request.
  • array $headers An array of request headers to send with the request.
  • int $timeout Read timeout in seconds.
  • string $userAgent The optional user agent string to send with the request.
Returns
  • \Joomla\CMS\Http\Response
Since
  • 1.7.3
-
  • \RuntimeException
Class: CurlTransport
Project: Joomla

Method request - Source code

/**
 * Send a request to the server and return a Response object with the response.
 *
 * @param   string        $method     The HTTP method for sending the request.
 * @param   UriInterface  $uri        The URI to the resource to request.
 * @param   mixed         $data       Either an associative array or a string to be sent with the request.
 * @param   array         $headers    An array of request headers to send with the request.
 * @param   integer       $timeout    Read timeout in seconds.
 * @param   string        $userAgent  The optional user agent string to send with the request.
 *
 * @return  Response
 *
 * @since   1.7.3
 * @throws  \RuntimeException
 */
public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null)
{
    // Setup the cURL handle.
    $ch = curl_init();
    $options = array();
    // Set the request method.
    switch (strtoupper($method)) {
        case 'GET':
            $options[CURLOPT_HTTPGET] = true;
            break;
        case 'POST':
            $options[CURLOPT_POST] = true;
            break;
        case 'PUT':
        default:
            $options[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
            break;
    }
    // Don't wait for body when $method is HEAD
    $options[CURLOPT_NOBODY] = $method === 'HEAD';
    // Initialize the certificate store
    $options[CURLOPT_CAINFO] = $this->getOption('curl.certpath', CaBundle::getBundledCaBundlePath());
    // If data exists let's encode it and make sure our Content-type header is set.
    if (isset($data)) {
        // If the data is a scalar value simply add it to the cURL post fields.
        if (is_scalar($data) || isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'multipart/form-data') === 0) {
            $options[CURLOPT_POSTFIELDS] = $data;
        } else {
            $options[CURLOPT_POSTFIELDS] = http_build_query($data);
        }
        if (!isset($headers['Content-Type'])) {
            $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
        }
        // Add the relevant headers.
        if (is_scalar($options[CURLOPT_POSTFIELDS])) {
            $headers['Content-Length'] = \strlen($options[CURLOPT_POSTFIELDS]);
        }
    }
    // Build the headers string for the request.
    $headerArray = array();
    if (isset($headers)) {
        foreach ($headers as $key => $value) {
            $headerArray[] = $key . ': ' . $value;
        }
        // Add the headers string into the stream context options array.
        $options[CURLOPT_HTTPHEADER] = $headerArray;
    }
    // Curl needs the accepted encoding header as option
    if (isset($headers['Accept-Encoding'])) {
        $options[CURLOPT_ENCODING] = $headers['Accept-Encoding'];
    }
    // If an explicit timeout is given user it.
    if (isset($timeout)) {
        $options[CURLOPT_TIMEOUT] = (int) $timeout;
        $options[CURLOPT_CONNECTTIMEOUT] = (int) $timeout;
    }
    // If an explicit user agent is given use it.
    if (isset($userAgent)) {
        $options[CURLOPT_USERAGENT] = $userAgent;
    }
    // Set the request URL.
    $options[CURLOPT_URL] = (string) $uri;
    // 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
    if ($this->redirectsAllowed()) {
        $options[CURLOPT_FOLLOWLOCATION] = (bool) $this->getOption('follow_location', true);
    }
    // Proxy configuration
    $app = Factory::getApplication();
    if ($app->get('proxy_enable')) {
        $options[CURLOPT_PROXY] = $app->get('proxy_host') . ':' . $app->get('proxy_port');
        if ($user = $app->get('proxy_user')) {
            $options[CURLOPT_PROXYUSERPWD] = $user . ':' . $app->get('proxy_pass');
        }
    }
    // Set any custom transport options
    foreach ($this->getOption('transport.curl', array()) as $key => $value) {
        $options[$key] = $value;
    }
    // Authentication, if needed
    if ($this->getOption('userauth') && $this->getOption('passwordauth')) {
        $options[CURLOPT_USERPWD] = $this->getOption('userauth') . ':' . $this->getOption('passwordauth');
        $options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
    }
    // Set the cURL options.
    curl_setopt_array($ch, $options);
    // Execute the request and close the connection.
    $content = curl_exec($ch);
    // Check if the content is a string. If it is not, it must be an error.
    if (!\is_string($content)) {
        $message = curl_error($ch);
        if (empty($message)) {
            // Error but nothing from cURL? Create our own
            $message = 'No HTTP response received';
        }
        throw new \RuntimeException($message);
    }
    // Get the request information.
    $info = curl_getinfo($ch);
    // Close the connection.
    curl_close($ch);
    $response = $this->getResponse($content, $info);
    // Manually follow redirects if server doesn't allow to follow location using curl
    if ($response->code >= 301 && $response->code < 400 && isset($response->headers['Location']) && (bool) $this->getOption('follow_location', true)) {
        $redirect_uri = new Uri($response->headers['Location']);
        if (\in_array($redirect_uri->getScheme(), array('file', 'scp'))) {
            throw new \RuntimeException('Curl redirect cannot be used in file or scp requests.');
        }
        $response = $this->request($method, $redirect_uri, $data, $headers, $timeout, $userAgent);
    }
    return $response;
}