Created
November 30, 2015 21:11
-
-
Save wwhurley/c71592a05265bd136a41 to your computer and use it in GitHub Desktop.
Working purge.inc file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Contains the main purging functionality and error handling | |
*/ | |
/** | |
* Purges urls from reverse proxy caches | |
* | |
* @param $purge_urls | |
* Array of urls to remove from the proxy cache using the http purge method. | |
* | |
* @return | |
* Array of urls and their http status codes after purging. | |
*/ | |
function purge_urls($purge_urls) { | |
// Get settings | |
$proxy_urls = explode(' ', variable_get('purge_proxy_urls', 'http://localhost:80')); | |
$purge_requests = array(); | |
$current_purge_request = 0; | |
// Find out the url parts we need from the urls to be purged | |
foreach ($purge_urls as $purge_url) { | |
$purge_url_parts = parse_url($purge_url); | |
// Determine the host | |
$purge_url_host = $purge_url_parts['host']; | |
// Add portnames to the host if any are set | |
if (array_key_exists('port', $purge_url_parts)) { | |
$purge_url_host = $purge_url_host . ":" . $purge_url_parts['port']; | |
} | |
// Process all urls for each proxy | |
foreach ($proxy_urls as $proxy_url) { | |
// Add url and proxy url to the array for later processing | |
$purge_requests[$current_purge_request]['purge_url'] = $purge_url; | |
$purge_requests[$current_purge_request]['proxy_url'] = $proxy_url; | |
// Select which method to use | |
$proxy_url_parts = parse_url($proxy_url); | |
if (array_key_exists('query', $proxy_url_parts)) { | |
if (strstr($proxy_url_parts['query'], 'purge_method=get')) { | |
$method = 'get'; | |
} | |
} | |
else { | |
$method = 'purge'; | |
} | |
// The default PURGE method. Native to Squid and configurable in Varnish and Nginx | |
if ($method == 'purge') { | |
// Make it a PURGE request (not GET or POST) | |
$purge_requests[$current_purge_request]['request_method'] = 'PURGE'; | |
// Construct a new url | |
$proxy_url_base = $proxy_url_parts['scheme'] . "://" . $proxy_url_parts['host']; | |
if (array_key_exists('port', $proxy_url_parts)) { | |
$proxy_url_base = $proxy_url_base . ":" . $proxy_url_parts['port']; | |
} | |
// Construct a new path retaining the url query string (#1299776 by djboddydrake) | |
$purge_path = array_key_exists('query', $purge_url_parts) ? $purge_url_parts['path'] | |
. '?' . $purge_url_parts['query'] : $purge_url_parts['path']; | |
$purge_requests[$current_purge_request]['purge_url'] = $proxy_url_base . $purge_path; | |
// Set the host header to the sites hostname | |
$purge_requests[$current_purge_request]['headers'] = array("Host: " . $purge_url_host); | |
} | |
// The GET method, native suport on nginx | |
elseif ($method == 'get') { | |
$purge_requests[$current_purge_request]['request_method'] = 'GET'; | |
// Construct a new url | |
$proxy_url_base = $proxy_url_parts['scheme'] . "://" . $proxy_url_parts['host']; | |
if (array_key_exists('port', $proxy_url_parts)) { | |
$proxy_url_base = $proxy_url_base . ":" . $proxy_url_parts['port']; | |
} | |
// Construct a new path retaining the proxy url path (needed for nginx/get methods) | |
if (array_key_exists('path', $proxy_url_parts)) { | |
$purge_path = '/' . trim($proxy_url_parts['path'], '/') . '/' . ltrim($purge_url_parts['path'], '/'); | |
} | |
else { | |
$purge_path = $purge_url_parts['path']; | |
} | |
// Check for a query and add it | |
if (array_key_exists('query', $purge_url_parts)) { | |
$purge_path = $purge_path . '?' . $purge_url_parts['query']; | |
} | |
$purge_requests[$current_purge_request]['purge_url'] = $proxy_url_base . $purge_path; | |
// Set the host header to the sites hostname | |
$purge_requests[$current_purge_request]['headers'] = array("Host: " . $purge_url_host); | |
} | |
$current_purge_request++; | |
} | |
} | |
// Issue the requests using curl (for now) | |
$purge_request_results = purge_issue_requests_curl($purge_requests); | |
return $purge_request_results; | |
} | |
/** | |
* Wrapper for curl_multi_exec(). | |
*/ | |
function purge_curl_multi_exec($curl_purges, &$active) { | |
do { | |
$multi_result = curl_multi_exec($curl_purges, $active); | |
} while ($multi_result == CURLM_CALL_MULTI_PERFORM); | |
return $multi_result; | |
} | |
/** | |
* Issue purge request using curl | |
* | |
*/ | |
function purge_issue_requests_curl($purges) { | |
// Initialise a curl_multi object | |
$curl_purges = curl_multi_init(); | |
foreach ($purges as $i => $purge) { | |
$curl_purge[$i] = curl_init(); | |
curl_setopt($curl_purge[$i], CURLOPT_CUSTOMREQUEST, $purge['request_method']); | |
curl_setopt($curl_purge[$i], CURLOPT_URL, $purge['purge_url']); | |
curl_setopt($curl_purge[$i], CURLOPT_HEADER, 1); | |
curl_setopt($curl_purge[$i], CURLOPT_HTTPHEADER, $purge['headers']); | |
curl_setopt($curl_purge[$i], CURLOPT_RETURNTRANSFER, 0); | |
curl_multi_add_handle($curl_purges, $curl_purge[$i]); | |
} | |
// Execute the purge requests | |
ob_start(); | |
$active = 0; | |
$multi_result = purge_curl_multi_exec($curl_purges, $active); | |
while ($active && $multi_result == CURLM_OK) { | |
if (curl_multi_select($curl_purges) == -1) { | |
usleep(100000); | |
} | |
$multi_result = purge_curl_multi_exec($curl_purges, $active); | |
} | |
ob_end_clean(); | |
// Result collection. Collects the http code returned for each url purged | |
foreach ($purges as $i => $purge) { | |
$info = curl_getinfo($curl_purge[$i]); | |
$purges[$i]['http_code'] = $info['http_code']; | |
curl_multi_remove_handle($curl_purges, $curl_purge[$i]); | |
} | |
curl_multi_close($curl_purges); | |
return $purges; | |
} | |
/** | |
* Logs successful purges and errors to the watchdog. | |
* | |
* @param $purge_request_results | |
* array of url with their http status code | |
*/ | |
function purge_logging($purge_request_results) { | |
$purge_success = 0; | |
$purge_blocking = array(); | |
$purge_success_log = array(); | |
$purge_error_log = array(); | |
foreach ($purge_request_results as $purge_request_result) { | |
switch ($purge_request_result['http_code']) { | |
// First check if everything went ok. | |
case 200: | |
$purge_success_log[] = $purge_request_result['purge_url'] . ' on ' . $purge_request_result['proxy_url'] . ' Ok'; | |
$purge_success++; | |
break; | |
// Redirects are acceptable | |
case 301: | |
$purge_success_log[] = $purge_request_result['purge_url'] . ' on ' . $purge_request_result['proxy_url'] . ' Permanent Redirect'; | |
$purge_success++; | |
break; | |
case 302: | |
$purge_success_log[] = $purge_request_result['purge_url'] . ' on ' . $purge_request_result['proxy_url'] . ' Temporary Redirect'; | |
$purge_success++; | |
break; | |
// Notice if the request was not found in the proxy cache | |
case 404: | |
$purge_success_log[] = $purge_request_result['purge_url'] . ' on ' . $purge_request_result['proxy_url'] . ' Not Found'; | |
$purge_success++; | |
break; | |
// Collect all proxy hosts that are blocking the url requests | |
case 405: | |
$purge_error_log[] = $purge_request_result['purge_url'] . ' on ' . $purge_request_result['proxy_url'] . ' Forbidden'; | |
$purge_blocking[] = parse_url($purge_request_result['proxy_url'], PHP_URL_HOST); | |
break; | |
// Collect all urls and their http error codes | |
default: | |
$purge_error_log[] = $purge_request_result['purge_url'] . ' on ' . $purge_request_result['proxy_url'] . ' ' . $purge_request_result['http_code']; | |
break; | |
} | |
} | |
// Watchdog barking | |
$purge_errors = count($purge_request_results) - $purge_success; | |
// Just a notice when all is ok | |
if ($purge_errors === 0) { | |
if ($purge_success === 1) { | |
watchdog( | |
'purge', | |
'1 URL has been successfully purged from the reverse proxy caches: !$purge_success_log', | |
array('!$purge_success_log' => purge_print_r($purge_success_log)) | |
); | |
} | |
else { | |
watchdog( | |
'purge', | |
'!purge_success_count URLs have been successfully purged from the reverse proxy caches: !$purge_success_log', | |
array('!purge_success_count' => $purge_success, '!$purge_success_log' => purge_print_r($purge_success_log)) | |
); | |
} | |
} | |
else { | |
// Report all urls with errors | |
if ($purge_errors === 1) { | |
watchdog( | |
'purge', | |
'1 error has been encountered when purging URLs !$purge_error_log', | |
array('!$purge_error_log' => purge_print_r($purge_error_log)), | |
$severity = WATCHDOG_ERROR | |
); | |
} | |
else { | |
watchdog( | |
'purge', | |
'!purge_errors_count errors have been encountered when purging these URLs. !$purge_error_log', | |
array('!purge_errors_count' => $purge_errors, '!$purge_error_log' => purge_print_r($purge_error_log)), | |
$severity = WATCHDOG_ERROR | |
); | |
} | |
// Report on proxy servers that block the purge requests. | |
if (!empty($purge_blocking)) { | |
foreach ($purge_blocking as $purge_blocking_server) { | |
watchdog( | |
'purge', | |
'The proxy server host %blocking_server is blocking purge requests. Please review the proxy configuration.', | |
array('%blocking_server' => $purge_blocking_server), | |
$severity = WATCHDOG_ERROR | |
); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment