/** * Get the S3 response * * @return Response */ public function getResponse() { $this->processParametersIntoResource(); $schema = 'http://'; if ($this->configuration->isSSL()) { $schema = 'https://'; } $url = $schema . $this->headers['Host'] . $this->uri; // Basic setup $curl = curl_init(); curl_setopt($curl, CURLOPT_USERAGENT, 'keek/s3-client'); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 1); curl_setopt($curl, CURLOPT_TIMEOUT, 5); if ($this->configuration->isSSL()) { // Set the CA certificate cache location $caCert = $this->getCaCertLocation(); if (!empty($caCert)) { if (is_dir($caCert)) { @curl_setopt($curl, CURLOPT_CAPATH, $caCert); } else { @curl_setopt($curl, CURLOPT_CAINFO, $caCert); } } // Verify the host name in the certificate and the certificate itself. However, if your bucket contains dots // we have to turn off host verification. Sorry, that's a limitation of Amazon S3. Since they recommend // always using virtual hosting style hostnames while their SSL certificate is set up to only allow // subdomains (bucket names) without dots the direct implication is that if you want to use SSL you MUST NOT // use dots in your bucket name. Of course this contradicts another part of their documentation which // suggests using bucket names with dots (same as your domain name) but YOU CAN'T MAKE SENSE OF THEIR BLOODY // DOCS, CAN YOU? For what is worth their own SDK uses path-style access which they tell everyone else to // not use. // // TL;DR: Amazon is a bunch of jerks. $isAmazonS3 = substr($this->headers['Host'], -14) == '.amazonaws.com'; $tooManyDots = substr_count($this->headers['Host'], '.') > 3; $verifyHost = $isAmazonS3 && $tooManyDots ? 0 : 2; curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $verifyHost); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); } curl_setopt($curl, CURLOPT_URL, $url); $signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod()); $signer->preProcessHeaders($this->headers, $this->amzHeaders); // Headers $headers = array(); foreach ($this->amzHeaders as $header => $value) { if (strlen($value) > 0) { $headers[] = $header . ': ' . $value; } } foreach ($this->headers as $header => $value) { if (strlen($value) > 0) { $headers[] = $header . ': ' . $value; } } $headers[] = 'Authorization: ' . $signer->getAuthorizationHeader(); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, false); curl_setopt($curl, CURLOPT_WRITEFUNCTION, array($this, '__responseWriteCallback')); curl_setopt($curl, CURLOPT_HEADERFUNCTION, array($this, '__responseHeaderCallback')); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // Optimize the Object Store Request Caching if (!in_array($this->verb, ['PUT', 'POST'])) { curl_setopt($curl, CURLOPT_FRESH_CONNECT, false); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 1000); // Disabled execution timeout to allow streaming to complete //curl_setopt($curl, CURLOPT_TIMEOUT_MS, 8000); curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 604800); } // Request types switch ($this->verb) { case 'GET': break; case 'PUT': case 'POST': if (!is_object($this->input) || !$this->input instanceof Input) { $this->input = new Input(); } $size = $this->input->getSize(); $type = $this->input->getInputType(); if ($type == Input::INPUT_DATA) { curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb); $data = $this->input->getDataReference(); if (strlen($data)) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } if ($size > 0) { curl_setopt($curl, CURLOPT_BUFFERSIZE, $size); } } else { curl_setopt($curl, CURLOPT_PUT, true); curl_setopt($curl, CURLOPT_INFILE, $this->input->getFp()); if ($size > 0) { curl_setopt($curl, CURLOPT_INFILESIZE, $size); } } break; case 'HEAD': curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD'); curl_setopt($curl, CURLOPT_NOBODY, true); break; case 'DELETE': curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); break; default: break; } // Execute, grab errors $this->response->resetBody(); if (curl_exec($curl)) { $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE); } else { $this->response->error = new Error(curl_errno($curl), curl_error($curl), $this->resource); } @curl_close($curl); // Set the body data $this->response->finaliseBody(); // Clean up file resources if (!is_null($this->fp) && is_resource($this->fp)) { fclose($this->fp); } return $this->response; }