public function authenticate($operation, $payload)
{
// Extract data from payload
$querystring = null;
$opt = ($payload) ? $payload : array();
$method = $operation;
$path = isset($opt['path']) ? $opt['path'] : null;
$xml = isset($opt['xml']) ? $opt['xml'] : null;
$etag = isset($opt['etag']) ? $opt['etag'] : null;
$method_arguments = func_get_args();
// 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) . '_' . $method . sha1($path) . '_' . 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;
}
// Generate query string
if (isset($opt['query_string']) && count($opt['query_string']))
{
$querystring = '?' . $this->util->to_query_string($opt['query_string']);
}
// Gather information to pass along to other classes.
$helpers = array(
'utilities' => $this->utilities_class,
'request' => $this->request_class,
'response' => $this->response_class,
);
// Compose the endpoint URL.
$request_url = 'https://' . $this->hostname . '/' . $this->api_version;
$request_url .= ($path) ? $path : '';
$request_url .= ($querystring) ? $querystring : '';
// Compose the request.
$request = new $this->request_class($request_url, $this->proxy, $helpers, $this->credentials);
// Update RequestCore settings
$request->request_class = $this->request_class;
$request->response_class = $this->response_class;
$request->ssl_verification = $this->ssl_verification;
// Pass along registered stream callbacks
if ($this->registered_streaming_read_callback)
{
$request->register_streaming_read_callback($this->registered_streaming_read_callback);
}
if ($this->registered_streaming_write_callback)
{
$request->register_streaming_write_callback($this->registered_streaming_write_callback);
}
// Generate required headers.
$request->set_method($method);
$canonical_date = gmdate($this->util->konst($this->util, 'DATE_FORMAT_RFC2616'));
$request->add_header('x-amz-date', $canonical_date);
$signature = base64_encode(hash_hmac('sha1', $canonical_date, $this->secret_key, true));
$request->add_header('Authorization', 'AWS ' . $this->key . ':' . $signature);
// Add configuration XML if we have it.
if ($xml)
{
$request->add_header('Content-Length', strlen($xml));
$request->add_header('Content-Type', 'application/xml');
$request->set_body($xml);
}
// Set If-Match: ETag header if we have one.
if ($etag)
{
$request->add_header('If-Match', $etag);
}
$curlopts = array();
// Set custom CURLOPT settings
if (isset($opt['curlopts']))
{
$curlopts = $opt['curlopts'];
}
// Debug mode
if ($this->debug_mode)
{
$curlopts[CURLOPT_VERBOSE] = true;
}
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 (isset($opt['returnCurlHandle']) && $opt['returnCurlHandle'] == (bool) true)
{
return $request->prep_request();
}
// Send!
$request->send_request();
// Prepare the response.
$headers = $request->get_response_header();
if ($xml) $headers['x-aws-body'] = $xml;
$data = new $this->response_class($headers, $this->parse_callback($request->get_response_body()), $request->get_response_code());
// Was it Amazon's fault the request failed? Retry the request until we reach $max_retries.
if ((integer) $request->get_response_code() === 500 || (integer) $request->get_response_code() === 503)
{
if ($this->redirects <= $this->max_retries)
{
// Exponential backoff
$delay = (integer) (pow(4, $this->redirects) * 100000);
usleep($delay);
$this->redirects++;
$data = $this->authenticate($method, $opt);
}
}
$this->redirects = 0;
return $data;
}