protected function httpRequest($url, $payload, $headers = null, &$statusCode = null, &$responseHeaders = array(), $encodePayload = false)
    {
        $payload = (is_array($payload) && (true === $encodePayload))
            ? http_build_query($payload, null, '&')
            : $payload;

        // Force removal of the Expect: 100-continue header automatically added by cURL
        $headers[] = 'Expect:';

        // cURL options
        $options = array(
            CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_PROXY          => $this->proxy,
            CURLOPT_PROXYUSERPWD   => $this->proxyCredentials,
            CURLOPT_USERAGENT      => sprintf('Dailymotion-PHP/%s (PHP %s; %s)', self::VERSION, PHP_VERSION, php_sapi_name()),
            CURLOPT_HEADER         => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_URL            => $url,
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_NOPROGRESS     => !($this->debug && is_array($payload) && array_key_exists('file', $payload)),
        );
        // There is no constructor to this class and I don't intend to add one just for this (PHP 4 legacy and all).
        if (is_null($this->followRedirects))
        {
            // We use filter_var() here because depending on PHP's version, these ini_get() may or may not return:
            // true/false or even the strings 'on', 'off', 'true' or 'false' or folder paths... better safe than sorry.
            $this->followRedirects =
                (false === filter_var(ini_get('open_basedir'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE))
                && (false === filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE));
        }
        // If the current server supports it, we follow redirects
        if ($this->followRedirects === true)
        {
            $options[CURLOPT_FOLLOWLOCATION] = true;
            $options[CURLOPT_MAXREDIRS]      = self::CURLOPT_MAXREDIRS;
        }
        $this->debugRequest($url, $payload, $headers);

        // Execute the cURL request
        $ch = curl_init();
        curl_setopt_array($ch, $options);
        $response = curl_exec($ch);

        // CURLE_SSL_CACERT error
        if (curl_errno($ch) == 60)
        {
            error_log('Invalid or no certificate authority found, using bundled information');
            curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/dm_ca_chain_bundle.crt');
            $response = curl_exec($ch);
        }
        // Invalid empty response
        if ($response === false)
        {
            $e = new DailymotionTransportException(curl_error($ch), curl_errno($ch));
            curl_close($ch);
            throw $e;
        }
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        list($responseHeadersString, $payload) = explode("\r\n\r\n", $response, 2);
        strtok($responseHeadersString, "\r\n"); // skip status code

        while(($name = trim(strtok(":"))) && ($value = trim(strtok("\r\n"))))
        {
            $responseHeaders[strtolower($name)] = (isset($responseHeaders[$name])
                ? $responseHeaders[$name] . '; '
                : null) . $value;
        }
        $this->debugResponse($url, $payload, $responseHeaders);
        return $payload;
    }