Default, shared method for authenticating a connection to AWS.
Access
public
Parameters
Parameter |
Type |
Required |
Description |
|---|---|---|---|
|
|
Required |
Indicates the operation to perform. |
|
|
|
Required |
An associative array of parameters for authenticating. See the individual methods for allowed keys. |
Returns
Type |
Description |
|---|---|
|
Object containing a parsed HTTP response. |
Source
Method defined in sdk.class.php | Toggle source view (178 lines) | View on GitHub
public function authenticate($operation, $payload)
{
$original_payload = $payload;
$method_arguments = func_get_args();
$curlopts = array();
$return_curl_handle = false;
if (substr($operation, 0, strlen($this->operation_prefix)) !== $this->operation_prefix)
{
$operation = $this->operation_prefix . $operation;
}
// Extract the custom CURLOPT settings from the payload
if (is_array($payload) && isset($payload['curlopts']))
{
$curlopts = $payload['curlopts'];
unset($payload['curlopts']);
}
// Determine whether the response or curl handle should be returned
if (is_array($payload) && isset($payload['returnCurlHandle']))
{
$return_curl_handle = isset($payload['returnCurlHandle']) ? $payload['returnCurlHandle'] : false;
unset($payload['returnCurlHandle']);
}
// Use the caching flow to determine if we need to do a round-trip to the server.
if ($this->use_cache_flow)
{
// Generate an identifier specific to this particular set of arguments.
$cache_id = $this->key . '_' . get_class($this) . '_' . $operation . '_' . sha1(serialize($method_arguments));
// Instantiate the appropriate caching object.
$this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
if ($this->delete_cache)
{
$this->use_cache_flow = false;
$this->delete_cache = false;
return $this->cache_object->delete();
}
// Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
$data = $this->cache_object->response_manager(array($this, 'cache_callback'), $method_arguments);
// Parse the XML body
$data = $this->parse_callback($data);
// End!
return $data;
}
/*%******************************************************************************************%*/
// Signer
$signer = new $this->auth_class($this->hostname, $operation, $payload, $this->credentials);
$signer->key = $this->key;
$signer->secret_key = $this->secret_key;
$signer->auth_token = $this->auth_token;
$signer->api_version = $this->api_version;
$signer->utilities_class = $this->utilities_class;
$signer->request_class = $this->request_class;
$signer->response_class = $this->response_class;
$signer->use_ssl = $this->use_ssl;
$signer->proxy = $this->proxy;
$signer->util = $this->util;
$signer->registered_streaming_read_callback = $this->registered_streaming_read_callback;
$signer->registered_streaming_write_callback = $this->registered_streaming_write_callback;
$request = $signer->authenticate();
// Update RequestCore settings
$request->request_class = $this->request_class;
$request->response_class = $this->response_class;
$request->ssl_verification = $this->ssl_verification;
/*%******************************************************************************************%*/
// Debug mode
if ($this->debug_mode)
{
$request->debug_mode = $this->debug_mode;
}
// Set custom CURLOPT settings
if (count($curlopts))
{
$request->set_curlopts($curlopts);
}
// Manage the (newer) batch request API or the (older) returnCurlHandle setting.
if ($this->use_batch_flow)
{
$handle = $request->prep_request();
$this->batch_object->add($handle);
$this->use_batch_flow = false;
return $handle;
}
elseif ($return_curl_handle)
{
return $request->prep_request();
}
// Send!
$request->send_request();
// Prepare the response.
$headers = $request->get_response_header();
$headers['x-aws-stringtosign'] = $signer->string_to_sign;
if (isset($signer->canonical_request))
{
$headers['x-aws-canonicalrequest'] = $signer->canonical_request;
}
$headers['x-aws-request-headers'] = $request->request_headers;
$headers['x-aws-body'] = $signer->querystring;
$data = new $this->response_class($headers, ($this->parse_the_response === true) ? $this->parse_callback($request->get_response_body()) : $request->get_response_body(), $request->get_response_code());
$response_body = (string) $request->get_response_body();
// Was it Amazon's fault the request failed? Retry the request until we reach $max_retries.
if (
(integer) $request->get_response_code() === 500 || // Internal Error (presumably transient)
(integer) $request->get_response_code() === 503) // Service Unavailable (presumably transient)
{
if ($this->redirects <= $this->max_retries)
{
// Exponential backoff
$delay = (integer) (pow(4, $this->redirects) * 100000);
usleep($delay);
$this->redirects++;
$data = $this->authenticate($operation, $original_payload);
}
}
// DynamoDB has additional, custom logic for retrying requests
else
{
// If the request to DynamoDB was throttled, we need to retry
$need_to_retry_dynamodb_request = (
(integer) $request->get_response_code() === 400 &&
stripos($response_body, 'com.amazonaws.dynamodb.') !== false &&
stripos($response_body, 'ProvisionedThroughputExceededException') !== false
);
// If the CRC32 of the response does not match the expected value, we need to retry
$response_headers = $request->get_response_header();
if (!$need_to_retry_dynamodb_request && isset($response_headers['x-amz-crc32']))
{
$crc32_expected = $response_headers['x-amz-crc32'];
$crc32_actual = hexdec(hash('crc32b', $response_body));
$need_to_retry_dynamodb_request = ($crc32_expected != $crc32_actual);
}
// Perform retry if necessary using a more aggressive exponential backoff
if ($need_to_retry_dynamodb_request)
{
if ($this->redirects === 0)
{
$this->redirects++;
$data = $this->authenticate($operation, $original_payload);
}
elseif ($this->redirects <= max($this->max_retries, 10))
{
// Exponential backoff
$delay = (integer) (pow(2, ($this->redirects - 1)) * 50000);
usleep($delay);
$this->redirects++;
$data = $this->authenticate($operation, $original_payload);
}
}
}
$this->redirects = 0;
return $data;
}

