AcquiaPurgeExecutorBase.php in Acquia Purge 7
Contains AcquiaPurgeExecutorBase.
File
lib/executor/AcquiaPurgeExecutorBase.phpView source
<?php
/**
* @file
* Contains AcquiaPurgeExecutorBase.
*/
/**
* Provides an executor, which is responsible for taking a set of invalidation
* objects and wiping these paths/URLs from an external cache.
*/
abstract class AcquiaPurgeExecutorBase implements AcquiaPurgeExecutorInterface {
/**
* The invalidation class to instantiate invalidation objects from.
*
* @var string
*/
protected $class_request;
/**
* The unique identifier for this executor.
*
* @var string
*/
protected $id;
/**
* Whether to log successes or not.
*
* @var bool
*/
protected $log_successes;
/**
* The Acquia Purge service object.
*
* @var AcquiaPurgeService
*/
protected $service;
/**
* Construct a new AcquiaPurgeExecutorBase instance.
*
* @param AcquiaPurgeService $service
* The Acquia Purge service object.
*/
public function __construct(AcquiaPurgeService $service) {
$this->id = get_class($this);
$this->service = $service;
$this->log_successes = _acquia_purge_variable('acquia_purge_log_success');
$this->class_request = _acquia_purge_load(array(
'_acquia_purge_executor_request_interface',
'_acquia_purge_executor_request',
));
}
/**
* Turn a PHP variable into a string with data type information for debugging.
*
* @param mixed $data
* Arbitrary PHP variable, assumed to be an associative array.
*
* @return string
* A one line representation of the data.
*/
protected function exportDebugSymbols($data) {
if (is_array($data)) {
$i = array();
foreach ($data as $k => $v) {
$i[] = (is_string($k) ? "{$k}: " : '') . $this
->exportDebugSymbols($v);
}
return '[' . implode(', ', $i) . ']';
}
elseif (is_null($data)) {
return 'NULL';
}
elseif (is_int($data)) {
return "{$data}";
}
elseif (is_float($data)) {
return $data . 'f';
}
elseif (is_bool($data)) {
return $data ? 'TRUE' : 'FALSE';
}
elseif (is_string($data)) {
return "'" . $data . "'";
}
else {
return '?';
}
}
/**
* {@inheritdoc}
*/
public function getId() {
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getRequest($uri = NULL) {
return new $this->class_request($uri);
}
/**
* {@inheritdoc}
*/
public function requestsExecute($requests, $no_ssl_verify = FALSE) {
$single_mode = count($requests) === 1;
$processed = array();
// Initialize the cURL multi handler.
if (!$single_mode) {
$curl_multi = curl_multi_init();
}
// Enter our event loop and keep on requesting until $unprocessed is empty.
$unprocessed = count($requests);
while ($unprocessed > 0) {
// Group requests per sets that we can run in parallel.
for ($i = 0; $i < AcquiaPurgeCapacity::HTTP_PARALLEL_REQUESTS; $i++) {
if ($r = array_shift($requests)) {
$r->curl = curl_init();
// Instantiate the cURL resource and configure its runtime parameters.
curl_setopt($r->curl, CURLOPT_URL, $r->uri);
curl_setopt($r->curl, CURLOPT_HTTPHEADER, $r->headers);
curl_setopt($r->curl, CURLOPT_CUSTOMREQUEST, $r->method);
curl_setopt($r->curl, CURLOPT_FAILONERROR, TRUE);
curl_setopt($r->curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($r->curl, CURLOPT_TIMEOUT, AcquiaPurgeCapacity::HTTP_REQUEST_TIMEOUT);
// For SSL purging, we disable SSL host and peer verification. This
// should trigger red flags to the security concerned user, but it
// also avoids purges to fail on sites with self-signed certs. This
// therefore is a risk worth taking in return for a better user
// experience as compromised cache invalidation requests couldn't
// cause much harm anyway.
if ($no_ssl_verify && $r->scheme === 'https') {
curl_setopt($r->curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($r->curl, CURLOPT_SSL_VERIFYPEER, FALSE);
}
// Add our handle to the multiple cURL handle.
if (!$single_mode) {
curl_multi_add_handle($curl_multi, $r->curl);
}
$processed[] = $r;
$unprocessed--;
}
}
// Execute the created handles in parallel.
if (!$single_mode) {
$active = NULL;
do {
$mrc = curl_multi_exec($curl_multi, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($curl_multi) != -1) {
do {
$mrc = curl_multi_exec($curl_multi, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
}
else {
curl_exec($processed[0]->curl);
$single_info = array(
'result' => curl_errno($processed[0]->curl),
);
}
// Iterate the set of results and fetch cURL result and resultcodes. Only
// process those with the 'curl' property as the property will be removed.
foreach ($processed as $i => $r) {
if (!isset($r->curl)) {
continue;
}
$info = $single_mode ? $single_info : curl_multi_info_read($curl_multi);
$processed[$i]->result = $info['result'] == CURLE_OK ? TRUE : FALSE;
$processed[$i]->error_curl = $info['result'];
$processed[$i]->response_code = curl_getinfo($r->curl, CURLINFO_HTTP_CODE);
// Collect debugging information if necessary.
$processed[$i]->error_debug = '';
if (!$processed[$i]->result) {
$debug = array(
'method' => $r->method,
'headers' => $r->headers,
);
$debug = array_merge($debug, curl_getinfo($r->curl));
unset($debug['certinfo']);
$processed[$i]->error_debug = $this
->exportDebugSymbols($debug);
}
// Remove the handle if parallel processing occurred.
if (!$single_mode) {
curl_multi_remove_handle($curl_multi, $r->curl);
}
curl_close($r->curl);
$r->curl = NULL;
}
}
if (!$single_mode) {
curl_multi_close($curl_multi);
}
}
/**
* {@inheritdoc}
*/
public function requestsLog($requests, $consequence = 'goes back to queue!') {
$id = $this
->getId();
foreach ($requests as $r) {
$vars = array(
'%id' => $id,
'%uri' => $r->uri,
'%host' => parse_url($r->uri, PHP_URL_HOST),
'%method' => $r->method,
'%response_code' => $r->response_code,
);
if (isset($r->_host)) {
$vars['%uri'] = sprintf("%s (host=%s)", $r->uri, $r->_host);
}
// Log success or failure, depending on $r->result.
if ($r->result) {
if ($this->log_successes) {
watchdog('acquia_purge', "%id: %uri succeeded (%method, %response_code).", $vars, WATCHDOG_INFO);
}
}
else {
$vars['%path'] = $r->path;
$vars['%curl'] = (string) curl_strerror($r->error_curl);
$vars['%debug'] = $r->error_debug;
$vars['%timeout'] = AcquiaPurgeCapacity::HTTP_REQUEST_TIMEOUT;
switch ($r->error_curl) {
case CURLE_COULDNT_CONNECT:
$msg = "%id: unable to connect to %host, ";
$msg .= $consequence;
break;
case CURLE_COULDNT_RESOLVE_HOST:
$msg = "%id: cannot resolve host for %uri, ";
$msg .= $consequence;
break;
case CURLE_OPERATION_TIMEOUTED:
$msg = "%id: %uri exceeded %timeout sec., ";
$msg .= $consequence;
break;
case CURLE_URL_MALFORMAT:
$msg = "%id: %uri failed: URL malformed, ";
$msg .= $consequence;
$msg .= ' DEBUG: %debug';
break;
default:
$msg = "%id: %uri failed, ";
$msg .= $consequence;
$msg .= ' cURL: %curl; DEBUG: %debug';
break;
}
watchdog('acquia_purge', $msg, $vars, WATCHDOG_ERROR);
}
}
}
}
Classes
Name | Description |
---|---|
AcquiaPurgeExecutorBase | Provides an executor, which is responsible for taking a set of invalidation objects and wiping these paths/URLs from an external cache. |