public static function makeRequest(HttpRequest $request) { $requestUri = $request->getRequestUri()->getUri(); // if the request is towards a file URL, return the response constructed // from file if (0 === strpos($requestUri, "file:///")) { return HttpResponse::fromFile($requestUri); } $httpResponse = new HttpResponse(); $curlChannel = curl_init(); curl_setopt($curlChannel, CURLOPT_URL, $requestUri); curl_setopt($curlChannel, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($curlChannel, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curlChannel, CURLOPT_TIMEOUT, 10); if ($request->getRequestMethod() === "POST") { curl_setopt($curlChannel, CURLOPT_POST, 1); curl_setopt($curlChannel, CURLOPT_POSTFIELDS, $request->getContent()); } $basicAuthUser = $request->getBasicAuthUser(); $basicAuthPass = $request->getBasicAuthPass(); if (NULL !== $basicAuthUser) { $request->setHeader("Authorization", "Basic " . base64_encode($basicAuthUser . ":" . $basicAuthPass)); } // Including HTTP headers in request $headers = $request->getHeaders(TRUE); if (!empty($headers)) { curl_setopt($curlChannel, CURLOPT_HTTPHEADER, $headers); } // Connect to SSL/TLS server, validate certificate and host if ($request->getRequestUri()->getScheme() === "https") { curl_setopt($curlChannel, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($curlChannel, CURLOPT_SSL_VERIFYHOST, 2); } // Callback to extract all the HTTP headers from the response... // In order to really correctly parse HTTP headers one would have to look at RFC 2616... curl_setopt($curlChannel, CURLOPT_HEADERFUNCTION, function ($curlChannel, $header) use($httpResponse) { // Ignore Status-Line (RFC 2616, section 6.1) if (0 === preg_match('|^HTTP/\\d+.\\d+ [1-5]\\d\\d|', $header)) { // Only deal with header lines that contain a colon if (strpos($header, ":") !== FALSE) { // Only deal with header lines that contain a colon list($key, $value) = explode(":", trim($header)); $httpResponse->setHeader(trim($key), trim($value)); } } return strlen($header); }); $output = curl_exec($curlChannel); if ($errorNumber = curl_errno($curlChannel)) { throw new OutgoingHttpRequestException(curl_error($curlChannel)); } $httpResponse->setStatusCode(curl_getinfo($curlChannel, CURLINFO_HTTP_CODE)); $httpResponse->setContent($output); curl_close($curlChannel); return $httpResponse; }
/** * Executes an HTTP transaction and returns the response. * * @param HttpRequest $request * @return HttpResponse */ public function getResponse(HttpRequest $request) { $uri = $request->getUrl(); $headers = $request->getHeaders(); $flatHeaders = []; foreach ($headers as $key => $value) { $flatHeaders[] = $key . ": " . $value; } $flatHeaders[] = 'Connection: Keep-Alive'; $flatHeaders[] = 'Expect:'; $flatHeaders[] = 'Accept-Language: en-GB'; $flatHeaders[] = 'Cache-Control: no-cache'; $flatHeaders[] = 'User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'; $curl = curl_init($uri); curl_setopt($curl, CURLOPT_HEADER, false); $payload = $request->getPayload(); switch ($request->getMethod()) { case "head": curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "HEAD"); break; case "delete": curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break; case "post": curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); break; case "put": curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $payload); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); break; } curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_HTTPHEADER, $flatHeaders); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($curl); $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); $httpResponse = new HttpResponse(); $httpResponse->setResponseBody($response); $httpResponse->setResponseCode($responseCode); return $httpResponse; }
/** * Signs request with signature v3 * * @param \HttpRequest $request Http request * @param string $subdomain optional A subdomain */ protected function signRequestV3($request, $subdomain = null) { $time = time(); //Gets the http method name $httpMethod = self::$httpMethods[$request->getMethod()]; $components = parse_url($request->getUrl()); //Retrieves headers from request $options = $request->getHeaders(); //Adding timestamp if (!isset($options['Date'])) { $options['Date'] = gmdate('r', $time); $request->addHeaders(['Date' => $options['Date']]); } //This also includes a mock objects which look like "Mock_S3QueryClient_d65a1dc1". if (preg_match('#(?<=[_\\\\])S3QueryClient(?=_|$)#', get_class($this))) { $amzHeaders = []; foreach ($options as $key => $val) { if (preg_match('/^x-amz-/i', $key)) { //Saves amz headers which are used to sign the request $amzHeaders[strtolower($key)] = $val; } } //S3 Client has a special Authorization string $canonicalizedAmzHeaders = ''; if (!empty($amzHeaders)) { ksort($amzHeaders); foreach ($amzHeaders as $k => $v) { $canonicalizedAmzHeaders .= $k . ':' . trim(preg_replace('/#( *[\\r\\n]+ *)+#/', ' ', $v)) . "\n"; } } //Note that in case of multiple sub-resources, sub-resources must be lexicographically sorted //by sub-resource name and separated by '&'. e.g. ?acl&versionId=value. if (!empty($components['query'])) { $canonPath = $components['path'] . '?'; parse_str($components['query'], $subresources); ksort($subresources); $allowed = $this->getAllowedSubResources(); foreach ($subresources as $k => $v) { if (in_array($k, $allowed)) { $canonPath .= $k . ($v !== '' ? '=' . $v : '') . '&'; } } $canonPath = substr($canonPath, 0, -1); } $canonicalizedResource = (isset($subdomain) ? '/' . strtolower($subdomain) : '') . (isset($canonPath) ? $canonPath : $components['path'] . (!empty($components['query']) ? '?' . $components['query'] : '') . (!empty($components['fragment']) ? '#' . $components['fragment'] : '')); $stringToSign = $httpMethod . "\n" . (!empty($options['Content-Md5']) ? $options['Content-Md5'] . '' : '') . "\n" . (!empty($options['Content-Type']) ? $options['Content-Type'] . '' : '') . "\n" . (isset($amzHeaders['x-amz-date']) ? '' : $options['Date'] . "\n") . $canonicalizedAmzHeaders . $canonicalizedResource; $options['Authorization'] = "AWS " . $this->awsAccessKeyId . ":" . base64_encode(hash_hmac('sha1', $stringToSign, $this->secretAccessKey, 1)); } else { $options['Authorization'] = "AWS " . $this->awsAccessKeyId . ":" . base64_encode(hash_hmac('sha1', $options['Date'], $this->secretAccessKey, 1)); } $request->addHeaders(['Authorization' => $options['Authorization']]); }
/** * Signs request with signature version 4 * * @param \HttpRequest $request Http Request * @param string $region optional Overrides region as destination region for multiregional operations * @throws QueryClientException */ protected function signRequestV4($request, $region = null) { $time = time(); //Gets the http method name $httpMethod = self::$httpMethods[$request->getMethod()]; //Region is mandatory part for this type of authentication $region = $region ?: $this->getAws()->getRegion(); //Gets host from the url $components = parse_url($request->getUrl()); $crd = gmdate('Ymd', $time) . '/' . $region . '/' . $this->getServiceName() . '/aws4_request'; $opt = ['X-Amz-Algorithm' => 'AWS4-HMAC-SHA256', 'X-Amz-Credential' => $this->awsAccessKeyId . '/' . $crd, 'X-Amz-Date' => gmdate('Ymd\\THis\\Z', $time), 'X-Amz-Expires' => '86400']; $headers = ['X-Amz-Date' => $opt['X-Amz-Date']]; //Calculating canonicalized query string $canonicalizedQueryString = ''; if (!empty($components['query'])) { parse_str($components['query'], $pars); ksort($pars); foreach ($pars as $k => $v) { $canonicalizedQueryString .= '&' . rawurlencode($k) . '=' . rawurlencode($v); } $canonicalizedQueryString = ltrim($canonicalizedQueryString, '&'); } //Calculating payload $payload = ''; if ($httpMethod == 'POST') { if ($request->getBody() != '') { $payload = $request->getBody(); } else { $pars = $request->getPostFields(); foreach ($pars as $k => $v) { //We do not use rawurlencode because httpRequest does not do this, and we need to hash payload $payload .= '&' . urlencode($k) . '=' . urlencode($v); } $payload = ltrim($payload, '&'); } } elseif ($httpMethod == 'PUT') { $payload = $request->getPutData(); if (empty($payload) && $request->getPutFile()) { $headers['X-Amz-Content-Sha256'] = hash_file('sha256', $request->getPutFile()); } } if (!isset($headers['X-Amz-Content-Sha256'])) { $headers['X-Amz-Content-Sha256'] = hash('sha256', $payload); } //Adding x-amz headers $request->addHeaders($headers); //Calculating canonical headers $allHeaders = $request->getHeaders(); $allHeaders['X-Amz-SignedHeaders'] = 'host'; $signedHeaders = ['host' => $components['host']]; foreach ($allHeaders as $k => $v) { $lk = strtolower($k); //This x-amz header does not have to be signed if ($lk == 'x-amz-signedheaders') { continue; } if (preg_match('/x-amz-/i', $k) || $lk == 'content-type' || $lk == 'content-md5') { $signedHeaders[$lk] = $v; } } ksort($signedHeaders); $allHeaders['X-Amz-SignedHeaders'] = join(';', array_keys($signedHeaders)); $canonicalHeaders = ''; foreach ($signedHeaders as $k => $v) { $canonicalHeaders .= $k . ':' . $v . "\n"; } $canonicalRequest = $httpMethod . "\n" . $components['path'] . "\n" . $canonicalizedQueryString . "\n" . $canonicalHeaders . "\n" . $allHeaders['X-Amz-SignedHeaders'] . "\n" . $headers['X-Amz-Content-Sha256']; $stringToSign = $opt['X-Amz-Algorithm'] . "\n" . $opt['X-Amz-Date'] . "\n" . $crd . "\n" . hash('sha256', $canonicalRequest); $dateKey = hash_hmac('sha256', gmdate('Ymd', $time), "AWS4" . $this->secretAccessKey, true); $dateRegionKey = hash_hmac('sha256', $region, $dateKey, true); $dateRegionServiceKey = hash_hmac('sha256', $this->getServiceName(), $dateRegionKey, true); $signingKey = hash_hmac('sha256', 'aws4_request', $dateRegionServiceKey, true); //X-Amz-Signature $signature = hash_hmac('sha256', $stringToSign, $signingKey); $headers['Authorization'] = $opt['X-Amz-Algorithm'] . ' ' . 'Credential=' . $opt['X-Amz-Credential'] . ',' . 'SignedHeaders=' . $allHeaders['X-Amz-SignedHeaders'] . ',' . 'Signature=' . $signature; $request->addHeaders($headers); }
private function _get_modified_since() { $requestHeaders = null; if (function_exists('apache_request_headers')) { $requestHeaders = apache_request_headers(); } elseif (class_exists('HttpRequest')) { $requestHeaders = HttpRequest::getHeaders(); } $modified_since = !empty($requestHeaders) ? $requestHeaders['If-Modified-Since'] : $_SERVER['HTTP_IF_MODIFIED_SINCE']; unset($requestHeaders); $date = $this->parse_http_date($modified_since); return $date !== false ? $date["timestamp"] : false; }