View source
<?php
define('HTTPRL_BACKGROUND_CALLBACK', TRUE);
define('HTTPRL_TIMEOUT', 30.0);
define('HTTPRL_DNS_TIMEOUT', 5.0);
define('HTTPRL_CONNECT_TIMEOUT', 5.0);
define('HTTPRL_TTFB_TIMEOUT', 20.0);
define('HTTPRL_GLOBAL_TIMEOUT', 120.0);
define('HTTPRL_REQUEST_ALLOWED_REDIRECTS_EXHAUSTED', -2);
define('HTTPRL_REQUEST_FWRITE_FAIL', -3);
define('HTTPRL_FUNCTION_TIMEOUT', -4);
define('HTTPRL_STREAM_SELECT_TIMEOUT', -5);
define('HTTPRL_URL_PARSE_ERROR', -1001);
define('HTTPRL_URL_MISSING_SCHEMA', -1002);
define('HTTPRL_URL_INVALID_SCHEMA', -1003);
define('HTTPRL_ERROR_INITIALIZING_STREAM', -1004);
define('HTTPRL_REQUEST_ABORTED', -10053);
define('HTTPRL_CONNECTION_RESET', -10054);
define('HTTPRL_REQUEST_TIMEOUT', -10060);
define('HTTPRL_CONNECTION_REFUSED', -10061);
define('HTTPRL_HOST_NOT_FOUND', -11001);
define('HTTPRL_MULTIPART_BOUNDARY', '---------------------------' . str_replace('.', '', microtime(TRUE)));
define('HTTPRL_PR_MAX_STRING_LENGTH', 262144);
define('HTTPRL_URL_INBOUND_ALTER', TRUE);
define('HTTPRL_SERVER_SCHEMA', 0);
define('HTTPRL_NON_BLOCKING_FCLOSE_DELAY', 0);
define('HTTPRL_SERVER_PORT', '');
function httprl_url_inbound_alter(&$path, $original_path, $path_language) {
if (!variable_get('httprl_url_inbound_alter', HTTPRL_URL_INBOUND_ALTER)) {
return;
}
$request_path = request_path();
if ($path != $request_path && strpos($request_path, 'httprl_async_function_callback') !== FALSE) {
$path = $request_path;
}
}
function httprl_menu() {
$items = array();
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
$config_url = 'admin/config/development/httprl';
}
else {
$config_url = 'admin/settings/httprl';
}
$items[$config_url] = array(
'title' => 'HTTPRL',
'description' => 'Configure HTTPRL settings.',
'access arguments' => array(
'administer site configuration',
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'httprl_admin_settings_form',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'httprl.admin.inc',
);
$items['httprl_async_function_callback'] = array(
'title' => 'HTTPRL',
'page callback' => 'httprl_async_page',
'access callback' => TRUE,
'description' => 'URL for async function workers.',
'type' => MENU_CALLBACK,
'file' => 'httprl.async.inc',
);
return $items;
}
function httprl_cron() {
$fuzz_factor = 300;
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
db_delete('semaphore')
->condition('value', 'httprl')
->condition('expire', REQUEST_TIME - $fuzz_factor, '<')
->execute();
}
else {
db_query("DELETE FROM {semaphore} WHERE value = 'httprl' AND expire < %f", time() - $fuzz_factor);
}
$fuzz_factor = 3600;
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
db_delete('semaphore')
->condition('name', db_like('httprl_') . '%', 'LIKE')
->condition('expire', REQUEST_TIME - $fuzz_factor, '<')
->execute();
}
else {
db_query("DELETE FROM {semaphore} WHERE name LIKE 'httprl_%' AND expire < %f", time() - $fuzz_factor);
}
}
function httprl_override_core($url, $options = array()) {
httprl_send_request();
httprl_request($url, $options);
$response = httprl_send_request();
return is_array($response) && is_string($url) && array_key_exists($url, $response) ? $response[$url] : (is_array($response) ? array_pop($response) : $response);
}
function _httprl_build_drupal_root($level = 0, $hostname_mode = 0) {
static $webroot;
$root_path = '/';
if ($level > 0) {
if (!isset($webroot)) {
$webroot = str_replace('\\', '/', dirname(__FILE__));
while (!empty($webroot)) {
if (file_exists($webroot . '/index.php') && strpos(file_get_contents($webroot . '/index.php'), 'menu_execute_active_handler();') !== FALSE) {
break;
}
$new_webroot = str_replace('\\', '/', dirname($webroot));
if ($new_webroot == $webroot) {
$webroot = str_replace('\\', '/', getcwd());
break;
}
$webroot = $new_webroot;
}
}
$root_path = '';
$webroot_array = explode('/', $webroot);
while ($level > 0 && count($webroot_array) != 0) {
$level--;
$root_path = array_pop($webroot_array) . '/' . $root_path;
}
$root_path = '/' . $root_path;
$root_path = str_replace('//', '/', $root_path);
}
else {
if (!empty($GLOBALS['base_path'])) {
$root_path = $GLOBALS['base_path'];
}
}
$auth = '';
if (module_exists('shield')) {
$auth = variable_get('shield_user', '') . ':' . variable_get('shield_pass', '') . '@';
}
elseif (isset($_SERVER['AUTH_TYPE']) && $_SERVER['AUTH_TYPE'] == 'Basic' || isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'])) {
$auth = $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'] . '@';
}
static $dns_cache;
$hostname = httprl_get_hostname();
$ip = httprl_variable_get('httprl_server_addr', FALSE);
if ($ip == -1 || $hostname_mode == 1) {
$ip = $hostname;
if (is_callable('drupal_is_cli') && drupal_is_cli() || !isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)) {
if (!isset($dns_cache[$hostname])) {
$dns_cache[$hostname] = gethostbyname($hostname);
}
if ($dns_cache[$hostname] == $hostname) {
$ip = '';
}
}
}
if (empty($ip) || $hostname_mode == 2) {
$ip = empty($_SERVER['SERVER_ADDR']) ? '127.0.0.1' : $_SERVER['SERVER_ADDR'];
if (strpos($ip, ':') !== FALSE) {
if ($_SERVER['SERVER_ADDR'] == '::1') {
$ip = "127.0.0.1";
}
elseif (preg_match('/^::\\d+.\\d+.\\d+.\\d+$/', $ip)) {
$ip = substr($ip, 2);
}
elseif (!empty($hostname)) {
if (!isset($dns_cache[$hostname])) {
$dns_cache[$hostname] = gethostbyname($hostname);
}
$ip = $dns_cache[$hostname];
if ($dns_cache[$hostname] == $hostname) {
$ip = '';
}
}
}
}
if ($hostname_mode == 3) {
$ip = httprl_variable_get('httprl_server_hostname', FALSE);
}
if (empty($ip) || $hostname_mode == 4) {
$ip = '127.0.0.1';
}
$port = httprl_variable_get('httprl_server_port', HTTPRL_SERVER_PORT);
if (!empty($port)) {
$port = ':' . $port;
}
elseif (isset($_SERVER['SERVER_PORT']) && is_numeric($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
$port = ':' . $_SERVER['SERVER_PORT'];
}
$schema_var = httprl_variable_get('httprl_server_schema', HTTPRL_SERVER_SCHEMA);
if ($schema_var == 0) {
$schema = httprl_get_server_schema() . '://';
}
elseif ($schema_var == 1) {
$schema = 'http://';
}
elseif ($schema_var == 2) {
$schema = 'https://';
}
if (!variable_get('clean_url', 0)) {
$path_parts = @parse_url('http://example.com/' . $path);
if (!empty($path_parts)) {
$path_parts_query = array();
if (isset($path_parts['query'])) {
parse_str($path_parts['query'], $path_parts_query);
}
$path_parts_query['q'] = ltrim($path_parts['path'], '/');
$path = '?' . http_build_query($path_parts_query, '', '&');
}
}
return $schema . $auth . $ip . $port . $root_path;
}
function httprl_build_url_self($path = '', $detect_schema = FALSE, $reset = FALSE) {
static $drupal_root;
if (!isset($drupal_root) || $reset) {
$drupal_root = _httprl_build_drupal_root();
if (is_callable('drupal_is_cli') && drupal_is_cli() || !isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)) {
$level = 0;
$found = FALSE;
$mode = 0;
while (!$found) {
$override_function = httprl_variable_get('drupal_http_request_function', FALSE);
$GLOBALS['conf']['drupal_http_request_function'] = FALSE;
$test_request = drupal_http_request($drupal_root . 'httprl_async_function_callback');
$GLOBALS['conf']['drupal_http_request_function'] = $override_function;
$headers = isset($test_request->headers) ? $test_request->headers : array();
if (!empty($headers)) {
foreach ($headers as $key => $value) {
if (stripos($key, 'X-HTTPRL') !== FALSE || stripos($value, 'X-HTTPRL') !== FALSE) {
$found = TRUE;
break;
}
}
}
if (!$found) {
$level++;
$new_drupal_root = _httprl_build_drupal_root($level, $mode);
if ($new_drupal_root == $drupal_root) {
$mode++;
$level = 0;
if ($mode > 4) {
$drupal_root = _httprl_build_drupal_root();
break;
}
}
$drupal_root = $new_drupal_root;
}
}
}
}
return $drupal_root . $path;
}
function httprl_parse_url($url, &$result) {
$uri = @parse_url($url);
$t = function_exists('t') ? 't' : 'httprl_pr';
if (empty($uri)) {
$result->error = $t('Unable to parse URL.');
$result->code = HTTPRL_URL_PARSE_ERROR;
}
elseif (!isset($uri['scheme'])) {
$result->error = $t('Missing schema.');
$result->code = HTTPRL_URL_MISSING_SCHEMA;
}
return $uri;
}
function httprl_set_default_options(array &$options) {
global $base_root;
$options += array(
'headers' => array(),
'method' => 'GET',
'data' => NULL,
'max_redirects' => 3,
'timeout' => httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT),
'dns_timeout' => httprl_variable_get('httprl_dns_timeout', HTTPRL_DNS_TIMEOUT),
'connect_timeout' => httprl_variable_get('httprl_connect_timeout', HTTPRL_CONNECT_TIMEOUT),
'ttfb_timeout' => httprl_variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT),
'context' => NULL,
'secure_socket_transport' => 'ssl',
'blocking' => TRUE,
'version' => '1.0',
'referrer' => FALSE,
'domain_connections' => 2,
'global_connections' => 128,
'global_timeout' => httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT),
'chunk_size_read' => 32768,
'chunk_size_write' => 1024,
'async_connect' => TRUE,
'ping_db' => 20,
'ignore_empty_chunk' => FALSE,
'url_encoding' => array(),
);
if ($options['timeout'] > httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT) && $options['ttfb_timeout'] == httprl_variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT)) {
$options['ttfb_timeout'] = $options['timeout'] - max(1, httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT) - httprl_variable_get('httprl_ttfb_timeout', HTTPRL_TTFB_TIMEOUT));
}
if ($options['timeout'] > httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT) && $options['global_timeout'] == httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT)) {
$options['global_timeout'] = $options['timeout'] + max(1, httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT) - httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT));
}
$options['headers'] += array(
'User-Agent' => 'Drupal (+http://drupal.org/)',
'Connection' => 'close',
);
if (isset($options['headers']['User-Agent']) && $options['headers']['User-Agent'] === FALSE) {
unset($options['headers']['User-Agent']);
}
if (isset($options['headers']['Connection']) && $options['headers']['Connection'] === FALSE) {
unset($options['headers']['Connection']);
}
$options['url_encoding'] += array(
'space' => array(),
);
$options['url_encoding']['space'] += array(
'path' => '%20',
'query' => '%20',
);
if (!isset($options['headers']['Referer']) && !empty($options['referrer'])) {
if (function_exists('request_uri')) {
$options['headers']['Referer'] = $base_root . request_uri();
if (strpos($options['headers']['Referer'], 'httprl_async_function_callback') === TRUE) {
$options['headers']['Referer'] = $_SERVER['HTTP_REFERER'];
}
}
}
$options['timeout'] = (double) $options['timeout'];
}
function httprl_setup_proxy(&$uri, &$options, $url) {
$proxy_server = httprl_variable_get('proxy_server', '');
if ($proxy_server && _httprl_use_proxy($uri['host'])) {
$uri['scheme'] = 'proxy';
$uri['path'] = $url;
unset($uri['query']);
if ($proxy_username = httprl_variable_get('proxy_username', '')) {
$proxy_password = httprl_variable_get('proxy_password', '');
$options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . ':' . $proxy_password);
}
$proxy_user_agent = httprl_variable_get('proxy_user_agent', '');
if (is_null($proxy_user_agent)) {
unset($options['headers']['User-Agent']);
}
elseif ($proxy_user_agent) {
$options['headers']['User-Agent'] = $proxy_user_agent;
}
}
return $proxy_server;
}
function httprl_set_socket($uri, &$options, $proxy_server, &$result) {
$socket = '';
switch ($uri['scheme']) {
case 'proxy':
$socket = 'tcp://' . $proxy_server . ':' . httprl_variable_get('proxy_port', 8080);
$options['headers']['Host'] = $uri['host'];
$options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
break;
case 'http':
case 'feed':
$port = isset($uri['port']) ? $uri['port'] : 80;
$socket = 'tcp://' . $uri['host'] . ':' . $port;
if (empty($options['headers']['Host'])) {
$options['headers']['Host'] = $uri['host'];
}
if ($port != 80) {
$options['headers']['Host'] .= ':' . $port;
}
break;
case 'https':
$port = isset($uri['port']) ? $uri['port'] : 443;
$socket = $options['secure_socket_transport'] . '://' . $uri['host'] . ':' . $port;
if (empty($options['headers']['Host'])) {
$options['headers']['Host'] = $uri['host'];
}
if ($port != 443) {
$options['headers']['Host'] .= ':' . $port;
}
if (empty($options['context'])) {
$drupal_ssl_context_options = variable_get('drupal_ssl_context_options', array(
'verify_peer' => TRUE,
));
if (!defined('OPENSSL_VERSION_NUMBER') || OPENSSL_VERSION_NUMBER >= 0x1000009f && OPENSSL_VERSION_NUMBER <= 0x1000102f) {
$drupal_ssl_context_options += array(
'SNI_enabled' => FALSE,
);
}
$options['context'] = stream_context_create(array(
'ssl' => $drupal_ssl_context_options,
));
}
break;
default:
$t = function_exists('t') ? 't' : 'httprl_pr';
$result->error = $t('Invalid schema @scheme.', array(
'@scheme' => $uri['scheme'],
));
$result->code = HTTPRL_URL_INVALID_SCHEMA;
}
return $socket;
}
function httprl_set_connection_flag(&$options, $uri) {
$flags = STREAM_CLIENT_CONNECT;
if ($options['async_connect']) {
if ($uri['scheme'] == 'https' && (version_compare(PHP_VERSION, '5.2.11', '<') || version_compare(PHP_VERSION, '5.3.0', '='))) {
$options['async_connect'] = FALSE;
}
else {
$flags = STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT;
}
}
return $flags;
}
function httprl_handle_data(&$options) {
if (isset($options['data']) && !is_string($options['data'])) {
$options['data-input'] = $options['data'];
if (!empty($options['headers']['Content-Type']) && strpos($options['headers']['Content-Type'], 'multipart/related') === 0 && !empty($options['data'])) {
$options['headers']['Content-Type'] = trim($options['headers']['Content-Type']);
if (substr_compare($options['headers']['Content-Type'], ';', -1, 1) === 0) {
$options['headers']['Content-Type'] = substr($options['headers']['Content-Type'], -1);
}
$options['headers']['Content-Type'] .= '; boundary=' . HTTPRL_MULTIPART_BOUNDARY;
$data_stream = '';
foreach ($options['data'] as $part) {
$data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
foreach ($part['headers'] as $key => $value) {
$data_stream .= $key . ': ' . $value . "\r\n";
}
$data_stream .= "\r\n";
if (isset($part['file'])) {
$data_stream .= file_get_contents($part['file']) . "\r\n";
}
elseif (isset($part['string'])) {
$data_stream .= $part['string'] . "\r\n";
}
}
$data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "--\r\n";
$options['data'] = $data_stream;
}
elseif (!empty($options['data']['file']) || !empty($options['data']['files'])) {
$data_stream = '';
$data_array = $options['data'];
if (isset($options['data']['files'])) {
foreach ($options['data']['files'] as $field_name => $info) {
$multi_field = '[]';
if (is_string($info)) {
$multi_field = '';
$temp = $info;
unset($info);
$info[] = $temp;
}
foreach ($info as $fullpath) {
if (substr($fullpath, 0, 1) == "@") {
$fullpath = substr($fullpath, 1);
}
$filename = basename($fullpath);
$mimetype = 'application/octet-stream';
$data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
$data_stream .= 'Content-Disposition: form-data; name="files[' . $field_name . ']' . $multi_field . '"; filename="' . $filename . "\"\r\n";
$data_stream .= 'Content-Transfer-Encoding: binary' . "\r\n";
$data_stream .= 'Content-Type: ' . $mimetype . "\r\n\r\n";
$data_stream .= file_get_contents($fullpath) . "\r\n";
}
}
unset($data_array['files']);
}
elseif (isset($options['data']['file'])) {
$fullpath = $options['data']['file'];
if (substr($fullpath, 0, 1) == "@") {
$fullpath = substr($fullpath, 1);
}
$filename = basename($fullpath);
$mimetype = 'application/octet-stream';
$data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
$data_stream .= 'Content-Disposition: form-data; name="file"; filename="' . $filename . "\"\r\n";
$data_stream .= 'Content-Transfer-Encoding: binary' . "\r\n";
$data_stream .= 'Content-Type: ' . $mimetype . "\r\n\r\n";
$data_stream .= file_get_contents($fullpath) . "\r\n";
unset($data_array['file']);
}
httprl_multipart_encoder($data_stream, $data_array);
$data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "--\r\n";
$options['data'] = $data_stream;
if (!empty($options['data']) && !isset($options['headers']['Content-Type']) && ($options['method'] == 'POST' || $options['method'] == 'PUT')) {
$options['headers']['Content-Type'] = 'multipart/form-data; boundary=' . HTTPRL_MULTIPART_BOUNDARY;
}
}
else {
$options['data'] = http_build_query($options['data'], '', '&');
if (!empty($options['data']) && !isset($options['headers']['Content-Type']) && ($options['method'] == 'POST' || $options['method'] == 'PUT')) {
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
}
}
}
if (strlen($options['data']) > 0 || $options['method'] == 'POST' || $options['method'] == 'PUT') {
$options['headers']['Content-Length'] = httprl_strlen($options['data']);
}
}
function httprl_multipart_encoder(&$data_stream, $data_array, $prepend = array()) {
foreach ($data_array as $key => $value) {
$key_array = $prepend;
$key_array[] = $key;
if (is_array($value)) {
httprl_multipart_encoder($data_stream, $value, $key_array);
}
elseif (is_scalar($value)) {
$key_string = array_shift($key_array);
if (!empty($key_array)) {
$key_string .= '[' . implode('][', $key_array) . ']';
}
$data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n";
$data_stream .= 'Content-Disposition: form-data; name="' . $key_string . "\"\r\n\r\n";
$data_stream .= $value . "\r\n";
}
}
}
function httprl_basic_auth($uri, &$options) {
if (isset($uri['user'])) {
$options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . ':' . (isset($uri['pass']) ? $uri['pass'] : ''));
}
}
function httprl_build_request_string($uri, $options) {
$path = isset($uri['path']) ? str_replace(' ', $options['url_encoding']['space']['path'], $uri['path']) : '/';
if (isset($uri['query'])) {
$path .= '?' . str_replace(' ', $options['url_encoding']['space']['query'], $uri['query']);
}
$request = $options['method'] . ' ' . $path . ' HTTP/' . sprintf("%.1F", $options['version']) . "\r\n";
foreach ($options['headers'] as $name => $value) {
$request .= $name . ': ' . trim($value) . "\r\n";
}
return $request . "\r\n" . $options['data'];
}
function httprl_stream_connection_error_formatter($errno, $errstr, &$result) {
$t = function_exists('t') ? 't' : 'httprl_pr';
if (function_exists('t')) {
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
require_once DRUPAL_ROOT . '/includes/unicode.inc';
}
else {
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/unicode.inc';
}
$errstr = trim(drupal_convert_to_utf8($errstr, 'ISO-8859-1'));
}
if (!$errno) {
if (empty($errstr)) {
$result->code = HTTPRL_ERROR_INITIALIZING_STREAM;
$result->error = $t('Error initializing socket @socket.', array(
'@socket' => $result->socket,
));
}
elseif (stripos($errstr, 'network_getaddresses: getaddrinfo failed:') !== FALSE) {
$result->code = HTTPRL_HOST_NOT_FOUND;
$result->error = $errstr;
}
}
elseif ($errno == 110) {
$result->code = HTTPRL_REQUEST_TIMEOUT;
$result->error = !empty($errstr) ? $errstr : $t('Connection timed out. TCP.');
}
else {
$result->code = (int) -$errno;
$result->error = !empty($errstr) ? $errstr : $t('Error opening socket @socket.', array(
'@socket' => $result->socket,
));
}
}
function httprl_establish_stream_connection(&$result) {
$start_time = microtime(TRUE);
$result->fp = FALSE;
$count = 0;
while (!$result->fp && $count < 3) {
if ($count > 0) {
if ($result->flags === STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT && $result->uri['scheme'] == 'https') {
$result->flags = STREAM_CLIENT_CONNECT;
$result->options['async_connect'] = FALSE;
}
else {
break;
}
}
$timeout = $result->options['dns_timeout'];
if (!$result->options['async_connect']) {
$timeout += $result->options['connect_timeout'];
}
if (empty($result->options['context'])) {
$result->fp = @stream_socket_client($result->socket, $errno, $errstr, $timeout, $result->flags);
}
else {
$result->fp = @stream_socket_client($result->socket, $errno, $errstr, $timeout, $result->flags, $result->options['context']);
}
$count++;
}
if ($result->fp && !$result->options['async_connect'] && !stream_socket_get_name($result->fp, TRUE)) {
$errno = HTTPRL_CONNECTION_REFUSED;
$errstr = 'Connection refused. No connection could be made because the target machine actively refused it.';
$result->fp = FALSE;
}
if (!$result->fp) {
httprl_stream_connection_error_formatter($errno, $errstr, $result);
}
else {
stream_set_blocking($result->fp, 0);
}
$end_time = microtime(TRUE);
$extra = 0;
if (isset($result->options['internal_states']['running_time'])) {
$extra = $result->options['internal_states']['running_time'];
unset($result->options['internal_states']['running_time']);
}
$result->running_time = $end_time - $start_time + $extra;
}
function httprl_request($urls, array $options = array()) {
$full_bootstrap = httprl_drupal_full_bootstrap();
if (!is_array($urls)) {
$temp =& $urls;
unset($urls);
$urls = array(
&$temp,
);
unset($temp);
}
if ($full_bootstrap) {
$data = array(
$urls,
$options,
);
drupal_alter('pre_httprl_request', $data);
list($urls, $options) = $data;
}
$connections = array();
$return = array();
foreach ($urls as &$url) {
$result = new stdClass();
$result->url =& $url;
$result->status = 'Connecting.';
$result->code = 0;
$result->chunk_size = 1024;
$result->data = '';
$these_options = $options;
httprl_set_default_options($these_options);
$uri = httprl_parse_url($url, $result);
if (isset($result->error)) {
$connections[] = array(
NULL,
NULL,
$uri,
$url,
$these_options,
$result,
NULL,
);
$return[$url] = FALSE;
continue;
}
$proxy_server = httprl_setup_proxy($uri, $these_options, $url);
$socket = httprl_set_socket($uri, $these_options, $proxy_server, $result, $return, $url);
if (isset($result->error)) {
$connections[] = array(
$socket,
NULL,
$uri,
$url,
$these_options,
$result,
NULL,
);
$return[$url] = FALSE;
continue;
}
$flags = httprl_set_connection_flag($these_options, $uri);
httprl_basic_auth($uri, $these_options);
httprl_handle_data($these_options);
$response = httprl_build_request_string($uri, $these_options);
$connections[] = array(
$socket,
$flags,
$uri,
$url,
$these_options,
$result,
$response,
);
$return[$url] = TRUE;
}
$results = array();
foreach ($connections as $connection) {
list($socket, $flags, $uri, $url, $options, $result, $response) = $connection;
$result->request = $response;
$result->options = $options;
$result->socket = $socket;
$result->flags = $flags;
$result->uri = $uri;
$result->running_time = 0;
$results[] = $result;
}
if ($full_bootstrap) {
drupal_alter('httprl_request', $results);
}
if (httprl_send_request($results)) {
return $return;
}
else {
return FALSE;
}
}
function httprl_send_request($results = NULL) {
static $responses = array();
static $counter = 0;
static $output = array();
static $static_stall_freads = FALSE;
if (!is_null($results)) {
if (empty($results)) {
return FALSE;
}
foreach ($results as $result) {
$responses[$counter] = $result;
$counter++;
}
return TRUE;
}
if (empty($responses)) {
return FALSE;
}
$t = function_exists('t') ? 't' : 'httprl_pr';
$global_timeout = 1;
$global_connection_limit = 1;
$stall_freads = FALSE;
foreach ($responses as $id => &$result) {
if (!empty($result->error)) {
$result->status = 'Connection not made.';
httprl_post_processing($id, $responses, $output);
continue;
}
if (!empty($result->cached)) {
$output[$result->cached->url] = $result->cached;
unset($responses[$id]);
continue;
}
$global_connection_limit = max($global_connection_limit, $result->options['global_connections']);
if (!isset($domain_connection_limit[$result->options['headers']['Host']])) {
$domain_connection_limit[$result->options['headers']['Host']] = max(1, $result->options['domain_connections']);
}
else {
$domain_connection_limit[$result->options['headers']['Host']] = max($domain_connection_limit[$result->options['headers']['Host']], $result->options['domain_connections']);
}
$global_timeout = max($global_timeout, $result->options['global_timeout']);
if (!empty($result->options['stall_fread']) && !$static_stall_freads) {
$static_stall_freads = TRUE;
$stall_freads = TRUE;
}
}
$start_time_this_run = $start_time_global = microtime(TRUE);
$ping_db_counts = array();
$full_bootstrap = httprl_drupal_full_bootstrap();
$stream_select_timeout = 1;
$stream_write_count = 0;
while (!empty($responses)) {
$this_run = array();
$global_connection_count = 0;
$domain_connection_count = array();
$restart_timers = FALSE;
$now = microtime(TRUE);
$elapsed_time = $now - $start_time_this_run;
$start_time_this_run = $now;
$global_time = $global_timeout - ($start_time_this_run - $start_time_global);
$rounded_time = floor($elapsed_time);
if ($full_bootstrap && !empty($result->options['ping_db']) && $rounded_time >= $result->options['ping_db'] && $rounded_time % $result->options['ping_db'] == 0 && empty($ping_db_counts[$rounded_time])) {
$empty_array = array();
system_get_files_database($empty_array, 'ping_db');
$ping_db_counts[$rounded_time] = 1;
}
foreach ($responses as $id => &$result) {
if ($global_time <= 0) {
if ($result->status == 'Connecting.') {
$result->error = $t('Function timed out. TCP.');
if (isset($result->fp)) {
$stream_write_count--;
}
}
elseif ($result->status == 'Writing to server.') {
$result->error = $t('Function timed out. Write.');
if (isset($result->fp)) {
$stream_write_count--;
}
}
else {
$result->error = $t('Function timed out. Read');
}
$result->code = HTTPRL_FUNCTION_TIMEOUT;
$result->status = 'Done.';
httprl_post_processing($id, $responses, $output, $global_time);
continue;
}
if (isset($result->fp)) {
$result->running_time += $elapsed_time;
$timeout = $result->options['timeout'] - $result->running_time;
if ($timeout <= 0) {
$result->error = $t('Connection timed out.');
if ($result->status == 'Writing to server.') {
$result->error .= ' ' . $t('Write.');
$stream_write_count--;
}
else {
$result->error .= ' ' . $t('Read.');
}
$result->code = HTTPRL_REQUEST_TIMEOUT;
$result->status = 'Done.';
httprl_post_processing($id, $responses, $output, $timeout);
continue;
}
if ($result->status == 'Connecting.' && $result->running_time > $result->options['connect_timeout']) {
$socket_name = stream_socket_get_name($result->fp, TRUE);
if (empty($socket_name) || $result->running_time > $result->options['connect_timeout'] * 1.5) {
$result->error = $t('Connection timed out.');
if ($result->status == 'Connecting.') {
$result->error .= ' ' . $t('TCP Connect Timeout.');
$stream_write_count--;
}
$result->code = HTTPRL_REQUEST_TIMEOUT;
$result->status = 'Done.';
httprl_post_processing($id, $responses, $output, $timeout);
continue;
}
}
if (!isset($responses[$id]->time_to_first_byte) && $result->running_time > $result->options['ttfb_timeout']) {
$result->error = $t('Connection timed out. Time to First Byte Timeout.');
$result->code = HTTPRL_REQUEST_ABORTED;
$result->status = 'Done.';
httprl_post_processing($id, $responses, $output, $timeout);
continue;
}
}
if (!isset($result->fp) && $result->status != 'Connecting.') {
httprl_post_processing($id, $responses, $output);
continue;
}
$host = $result->options['headers']['Host'];
if (!isset($domain_connection_limit[$host])) {
$domain_connection_limit[$host] = max(1, $result->options['domain_connections']);
}
$global_connection_count++;
if (empty($domain_connection_count[$host])) {
$domain_connection_count[$host] = 1;
}
else {
$domain_connection_count[$host]++;
}
if ($global_connection_limit >= $global_connection_count && $domain_connection_limit[$host] >= $domain_connection_count[$host]) {
if (!isset($result->fp) && $result->status == 'Connecting.') {
httprl_establish_stream_connection($result);
$restart_timers = TRUE;
if (!empty($result->options['lock_name'])) {
httprl_acquire_lock($result);
}
if (!$result->fp) {
httprl_post_processing($id, $responses, $output);
$domain_connection_count[$host]--;
$global_connection_count--;
continue;
}
$stream_write_count++;
}
if (!empty($result->fp)) {
$this_run[$id] = $result->fp;
}
}
}
if (empty($responses)) {
break;
}
if ($restart_timers) {
$start_time_this_run = microtime(TRUE);
}
if (empty($this_run)) {
continue;
}
$read = $write = $this_run;
$except = array();
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$n = @stream_select($read, $write, $except, $stream_select_timeout, 25000);
}
else {
$n = stream_select($read, $write, $except, $stream_select_timeout, 25000);
}
$stream_select_timeout = 0;
if ($n === FALSE) {
$merged = array_unique(array_merge($read, $write, $except));
foreach ($merged as $m) {
$id = array_search($m, $this_run);
@fclose($m);
if ($id !== FALSE && isset($responses[$id])) {
watchdog('httprl', 'The following url had a stream_select error and had to be terminated: %info', array(
'%info' => $responses[$id]->url,
), WATCHDOG_ERROR);
unset($responses[$id]);
}
}
}
$rw_done = FALSE;
if (!empty($n)) {
if (!empty($read) && is_array($read)) {
foreach ($read as $r) {
$id = array_search($r, $this_run);
if ($id === FALSE) {
@fclose($r);
continue;
}
if (!array_key_exists($id, $responses)) {
@fclose($r);
continue;
}
if (empty($responses[$id]->options['blocking'])) {
httprl_post_processing($id, $responses, $output);
continue;
}
$chunk = fread($r, $responses[$id]->chunk_size);
if (strlen($chunk) > 0) {
$rw_done = TRUE;
if (!isset($responses[$id]->time_to_first_byte)) {
$responses[$id]->time_to_first_byte = $result->running_time + microtime(TRUE) - $start_time_this_run;
}
}
$responses[$id]->data .= $chunk;
if (!empty($responses[$id]->data) && empty($responses[$id]->headers) && (strpos($responses[$id]->data, "\r\n\r\n") || strpos($responses[$id]->data, "\n\n") || strpos($responses[$id]->data, "\r\r"))) {
httprl_parse_data($responses[$id]);
if (!empty($responses[$id]->headers)) {
if (!empty($responses[$id]->options['internal_states']['kill'])) {
fclose($r);
unset($responses[$id]);
continue;
}
$responses[$id]->chunk_size = $responses[$id]->options['chunk_size_read'];
if (!empty($responses[$id]->options['headers']['Range']) && $responses[$id]->code == 200 && $responses[$id]->options['method'] == 'GET') {
$responses[$id]->ranges = httprl_get_ranges($responses[$id]->options['headers']['Range']);
$responses[$id]->options['max_data_size'] = httprl_get_last_byte_from_range($responses[$id]->ranges);
}
}
}
if (!empty($responses[$id]->options['max_data_size']) && is_numeric($responses[$id]->options['max_data_size']) && (!isset($result->headers['transfer-encoding']) || $result->headers['transfer-encoding'] != 'chunked') && (!isset($result->headers['content-encoding']) || $result->headers['content-encoding'] != 'gzip' && $result->headers['content-encoding'] != 'deflate') && $responses[$id]->options['max_data_size'] < httprl_strlen($responses[$id]->data)) {
$responses[$id]->status = 'Done.';
httprl_post_processing($id, $responses, $output);
continue;
}
$info = stream_get_meta_data($r);
$alive = !$info['eof'] && !feof($r) && !$info['timed_out'];
if ($alive && !$responses[$id]->options['ignore_empty_chunk'] && !strlen($chunk)) {
$alive = FALSE;
}
if (!$alive) {
if ($responses[$id]->status == 'Connecting.') {
$responses[$id]->error = $t('Connection refused by destination. TCP.');
$responses[$id]->code = HTTPRL_CONNECTION_REFUSED;
}
if ($responses[$id]->status == 'Writing to server.') {
$responses[$id]->error = $t('Connection refused by destination. Write.');
$responses[$id]->code = HTTPRL_CONNECTION_REFUSED;
}
$responses[$id]->status = 'Done.';
httprl_post_processing($id, $responses, $output);
continue;
}
else {
$responses[$id]->status = 'Reading data';
}
}
}
if ($stream_write_count > 0 && !empty($write) && is_array($write)) {
foreach ($write as $w) {
$id = array_search($w, $this_run);
if ($id === FALSE || empty($responses[$id]->status) || $responses[$id]->status != 'Connecting.' && $responses[$id]->status != 'Writing to server.') {
continue;
}
if (!isset($responses[$id]->bytes_sent)) {
$responses[$id]->bytes_sent = 0;
}
$data_to_send = substr($responses[$id]->request, $responses[$id]->bytes_sent, 2 * $responses[$id]->options['chunk_size_write']);
$len = httprl_strlen($data_to_send);
if ($len > 0) {
$bytes = fwrite($w, $data_to_send, min($responses[$id]->options['chunk_size_write'], $len));
}
else {
$bytes = $len;
}
if ($bytes === FALSE) {
$responses[$id]->error = $t('fwrite() failed.');
$responses[$id]->code = HTTPRL_REQUEST_FWRITE_FAIL;
$responses[$id]->status = 'Done.';
$stream_write_count--;
httprl_post_processing($id, $responses, $output);
continue;
}
elseif ($bytes >= $len) {
$stream_write_count--;
if (empty($responses[$id]->options['blocking'])) {
$responses[$id]->status = 'Non-Blocking request sent out. Not waiting for the response.';
httprl_post_processing($id, $responses, $output);
continue;
}
else {
$responses[$id]->status = "Request sent, waiting for response.";
}
$responses[$id]->bytes_sent += $bytes;
$rw_done = TRUE;
}
else {
if ($responses[$id]->status = 'Connecting.') {
$responses[$id]->status = 'Writing to server.';
}
$responses[$id]->bytes_sent += $bytes;
$rw_done = TRUE;
}
}
}
elseif ($stall_freads) {
return;
}
}
if (!$rw_done) {
usleep(5000);
}
}
$return = $output;
$responses = array();
$counter = 0;
$output = array();
$static_stall_freads = FALSE;
return $return;
}
function httprl_parse_data(&$result) {
if (empty($result->options['blocking'])) {
return;
}
if (!empty($result->headers)) {
return;
}
$t = function_exists('t') ? 't' : 'httprl_pr';
$response = $result->data;
list($response, $result->data) = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
$response = preg_split("/\r\n|\n|\r/", $response);
$protocol_code_array = explode(' ', trim(array_shift($response)), 3);
$result->protocol = $protocol_code_array[0];
$code = (int) $protocol_code_array[1];
$result->status_message = isset($protocol_code_array[2]) ? $protocol_code_array[2] : '';
unset($protocol_code_array);
$result->headers = array();
$cookie_primary_counter = 0;
while ($line = trim(array_shift($response))) {
list($name, $value) = explode(':', $line, 2);
$name = strtolower($name);
if ($name == 'set-cookie') {
foreach (explode(';', $value) as $cookie_name_value) {
$temp = explode('=', trim($cookie_name_value));
$cookie_key = trim($temp[0]);
$cookie_value = isset($temp[1]) ? trim($temp[1]) : '';
unset($temp);
if (!isset($result->cookies[$cookie_primary_counter])) {
$result->cookies[$cookie_primary_counter] = array(
'name' => $cookie_key,
'value' => $cookie_value,
);
}
else {
$result->cookies[$cookie_primary_counter] += array(
$cookie_key => $cookie_value,
);
}
}
$cookie_primary_counter++;
}
if (isset($result->headers[$name]) && $name == 'set-cookie') {
$result->headers[$name] .= ',' . trim($value);
}
else {
$result->headers[$name] = trim($value);
}
}
$responses = array(
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Large',
415 => 'Unsupported Media Type',
416 => 'Requested range not satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
);
if (!isset($responses[$code])) {
$code = floor($code / 100) * 100;
}
$result->code = $code;
switch ($code) {
case 200:
case 201:
case 202:
case 206:
case 304:
break;
case 301:
case 302:
case 307:
$location = @parse_url($result->headers['location']);
if (empty($location['scheme']) || empty($location['host'])) {
$hostname = httprl_get_hostname();
$original_location = @parse_url($result->url);
$location['scheme'] = !empty($location['scheme']) ? $location['scheme'] : $original_location['scheme'];
$location['host'] = !empty($location['host']) ? $location['host'] : (!empty($original_location['host']) ? $original_location['host'] : $hostname);
$location['port'] = !empty($location['port']) ? $location['port'] : (!empty($original_location['port']) ? $original_location['port'] : '');
$location = httprl_glue_url($location);
}
else {
$location = $result->headers['location'];
}
$result->options['internal_states']['redirect_code_array'][] = $code;
$result->options['internal_states']['redirect_url_array'][] = $location;
if (!isset($result->options['internal_states']['original_url'])) {
$result->options['internal_states']['original_url'] = $result->url;
}
if ($result->options['max_redirects'] <= 0) {
$result->code = HTTPRL_REQUEST_ALLOWED_REDIRECTS_EXHAUSTED;
$result->error = $t('Maximum allowed redirects exhausted.');
}
else {
$cookie_string = '';
$parsed_location = parse_url($location);
if (isset($result->cookies)) {
foreach ($result->cookies as $cookie) {
$cookie_domain = ltrim($cookie['domain'], '.');
if (strpos($parsed_location['host'], $cookie_domain) !== FALSE) {
if (!empty($cookie_string)) {
$cookie_string .= ';';
}
$cookie_string .= $cookie['name'] . '=' . $cookie['value'];
}
}
if (!empty($cookie_string)) {
$result->options['headers']['Cookie'] = $cookie_string;
}
}
$result->options['max_redirects']--;
if (isset($result->options['headers']['Referer'])) {
$result->options['headers']['Referer'] = $result->url;
}
unset($result->options['headers']['Host']);
$result->options['internal_states']['running_time'] = $result->running_time;
httprl_request($location, $result->options);
$result->options['internal_states']['kill'] = TRUE;
}
break;
default:
$result->error = $result->status_message;
}
}
function httprl_get_ranges($input) {
$ranges = array();
$string = preg_match('/^bytes=((\\d*-\\d*,? ?)+)$/', $input, $matches) ? $matches[1] : FALSE;
if (!empty($string)) {
foreach (explode(',', $string) as $range) {
$values = explode('-', $range);
if (count($values) != 2) {
return FALSE;
}
$ranges[] = array(
'start' => $values[0],
'end' => $values[1],
);
}
}
return $ranges;
}
function httprl_get_last_byte_from_range($ranges) {
$max = 0;
if (empty($ranges)) {
return NULL;
}
foreach ($ranges as $range) {
if (!is_numeric($range['start']) || !is_numeric($range['end'])) {
return NULL;
}
$max = max($range['end'] + 1, $max);
}
return $max;
}
function httprl_post_processing($id, &$responses, &$output, $time_left = NULL) {
$result =& $responses[$id];
if (isset($result->fp)) {
if (empty($responses[$id]->options['blocking'])) {
$ms_delay = httprl_variable_get('httprl_non_blocking_fclose_delay', HTTPRL_NON_BLOCKING_FCLOSE_DELAY);
if (!empty($ms_delay)) {
usleep($ms_delay * 1000);
}
}
@fclose($result->fp);
unset($result->fp);
}
if (is_null($time_left)) {
$time_left = $result->options['timeout'] - $result->running_time;
}
$result->options['timeout'] = $time_left;
httprl_reconstruct_redirects($result);
httprl_decode_data($result);
if (isset($result->options['internal_states']) && array_key_exists('background_function_return', $result->options['internal_states']) && isset($result->headers['content-type']) && strpos($result->headers['content-type'], 'application/x-www-form-urlencoded') !== FALSE) {
httprl_extract_background_callback_data($result);
unset($responses[$id]);
return;
}
$full_bootstrap = httprl_drupal_full_bootstrap();
if ($full_bootstrap && !empty($result->options['alter_all_streams_function']) && function_exists($result->options['alter_all_streams_function'])) {
$result->options['alter_all_streams_function']($id, $responses);
}
unset($responses[$id]);
if ($full_bootstrap) {
drupal_alter('httprl_post_processing', $result);
}
if ($full_bootstrap && !empty($result->options['callback']) && is_array($result->options['callback']) && !empty($result->options['callback'][0]) && is_array($result->options['callback'][0]) && !empty($result->options['callback'][0]['function'])) {
httprl_run_callback($result);
}
if (!empty($result->options['background_callback']) && is_array($result->options['background_callback']) && !empty($result->options['background_callback'][0]) && is_array($result->options['background_callback'][0]) && !empty($result->options['background_callback'][0]['function'])) {
$call_is_queued = httprl_queue_background_callback($result->options['background_callback'], $result);
if (is_null($call_is_queued)) {
watchdog('httprl', 'Background callback attempted but it is disabled. Going to use a normal callback');
unset($result->options['callback']);
$result->options['callback'] = $result->options['background_callback'];
unset($result->options['background_callback']);
httprl_run_callback($result);
}
}
if (isset($result->url)) {
$output[$result->url] = $result;
}
}
function httprl_extract_background_callback_data(&$result) {
$data = array();
parse_str($result->data, $data);
$serialized_string = trim(base64_decode(strtr(current($data), array(
'-' => '+',
'_' => '/',
))));
$data = @unserialize($serialized_string);
if ($data !== 'b:0;' && $data === FALSE) {
return;
}
if (isset($data['return'])) {
$result->options['internal_states']['background_function_return'] = $data['return'];
}
if (isset($data['printed'])) {
$result->options['internal_states']['background_function_printed'] = $data['printed'];
}
if (isset($data['args'])) {
httprl_recursive_array_reference_extract($result->options['internal_states']['background_function_args'], $data['args']);
}
}
function httprl_recursive_array_reference_extract(&$array, $data, $depth = 0) {
$depth++;
foreach ($array as $key => &$value) {
if (isset($data[$key])) {
if (is_array($data[$key]) && is_array($value) && $depth < 10) {
$value = httprl_recursive_array_reference_extract($value, $data[$key], $depth);
}
else {
$value = $data[$key];
}
}
else {
$value = NULL;
}
}
foreach ($data as $key => $value) {
if (isset($array[$key])) {
continue;
}
$array[$key] = $value;
}
}
function httprl_run_callback(&$result) {
$callback_options = $result->options['callback'][0];
$result->options['callback'][0] =& $result;
ob_start();
$callback_options['return'] = call_user_func_array($callback_options['function'], $result->options['callback']);
if (array_key_exists('printed', $callback_options)) {
$callback_options['printed'] = ob_get_contents();
}
ob_end_clean();
if (isset($result->options['callback'])) {
array_unshift($result->options['callback'], $callback_options);
}
}
function httprl_queue_background_callback(&$args, &$result = NULL) {
static $counter;
if (!isset($counter)) {
$counter = 0;
}
$counter++;
if (!httprl_is_background_callback_capable()) {
return NULL;
}
if (empty($callback_options['url'])) {
$url = httprl_build_url_self('httprl_async_function_callback?count=' . $counter);
}
else {
$url = $callback_options['url'];
}
$callback_options = $args[0];
if (is_null($result)) {
array_shift($args);
}
else {
$args[0] =& $result;
}
if (isset($callback_options['return']) || isset($callback_options['printed'])) {
$mode = TRUE;
}
else {
$mode = FALSE;
}
if (!isset($callback_options['return'])) {
$callback_options['return'] = '';
}
if (!isset($callback_options['function'])) {
$callback_options['function'] = '';
}
$times = array(
httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT),
httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT),
);
if (isset($callback_options['options']['timeout'])) {
$times[] = $callback_options['options']['timeout'];
}
if (isset($callback_options['options']['global_timeout'])) {
$times[] = $callback_options['options']['global_timeout'];
}
$available = FALSE;
$lock_counter = 0;
while (!$available && $lock_counter < 20) {
if (function_exists('drupal_random_bytes')) {
$name = 'httprl_' . hash('sha512', drupal_random_bytes(64));
}
elseif (function_exists('openssl_random_pseudo_bytes')) {
$name = 'httprl_' . hash('sha512', openssl_random_pseudo_bytes(64));
}
else {
$name = 'httprl_' . hash('sha512', mt_rand() . microtime(TRUE) . serialize($_SERVER));
}
$available = lock_may_be_available($name);
$lock_counter++;
}
$callback_options['options']['lock_name'] = $name;
$options = array(
'data' => array(
'master_key' => hash('sha512', httprl_drupal_get_private_key()),
'temp_key' => $name,
'mode' => $mode,
'php_timeout' => max($times),
'function' => $callback_options['function'],
'context' => isset($callback_options['context']) ? $callback_options['context'] : array(),
'args' => strtr(base64_encode(serialize($args)), array(
'+' => '-',
'/' => '_',
)),
),
'internal_states' => array(
'background_function_return' => &$callback_options['return'],
'background_function_args' => &$args,
),
'blocking' => $mode,
'method' => 'POST',
'referrer' => 'TRUE',
);
if (isset($callback_options['printed'])) {
$options['internal_states']['background_function_printed'] =& $callback_options['printed'];
}
if (isset($callback_options['options']) && is_array($callback_options['options'])) {
$options += $callback_options['options'];
}
if (empty($options['headers']['Host'])) {
$hostname = httprl_get_hostname();
if (!empty($hostname)) {
$options['headers']['Host'] = $hostname;
}
}
if (!empty($callback_options['context']['session']) && !empty($_COOKIE[session_name()])) {
if (!isset($options['headers']['Cookie'])) {
$options['headers']['Cookie'] = '';
}
$options['headers']['Cookie'] = session_name() . '=' . $_COOKIE[session_name()] . ';';
}
return httprl_request($url, $options);
}
function httprl_acquire_lock(&$result) {
if (empty($result->options['lock_name'])) {
return FALSE;
}
$times = array(
httprl_variable_get('httprl_timeout', HTTPRL_TIMEOUT),
httprl_variable_get('httprl_global_timeout', HTTPRL_GLOBAL_TIMEOUT),
);
if (isset($result->options['timeout'])) {
$times[] = $result->options['timeout'];
}
if (isset($result->options['global_timeout'])) {
$times[] = $result->options['global_timeout'];
}
$time = max($times);
$name = $result->options['lock_name'];
return httprl_acquire_headless_lock($name, $time);
}
function httprl_acquire_headless_lock($name, $time = 60) {
$locked = FALSE;
$lock_counter = 0;
while (!$locked && $lock_counter < 3) {
$locked = lock_acquire($name, $time);
$lock_counter++;
}
if (!$locked) {
return FALSE;
}
unset($GLOBALS['locks'][$name]);
$lock_inc = httprl_variable_get('lock_inc', './includes/lock.inc');
if ($lock_inc === './includes/lock.inc') {
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
db_update('semaphore')
->fields(array(
'value' => 'httprl',
))
->condition('name', $name)
->condition('value', _lock_id())
->execute();
}
else {
db_query("UPDATE {semaphore} SET value = '%s' WHERE name = '%s' AND value = '%s'", 'httprl', $name, _lock_id());
}
}
elseif (strpos($lock_inc, '/apdqc/apdqc.lock.inc') !== FALSE) {
lock_change_lock_id($name, _lock_id(), 'httprl');
}
return TRUE;
}
function httprl_decode_data(&$result) {
if (isset($result->headers['transfer-encoding']) && $result->headers['transfer-encoding'] == 'chunked') {
$stream_position = 0;
$output = '';
$data = $result->data;
while ($stream_position < httprl_strlen($data)) {
$rawnum = substr($data, $stream_position, strpos(substr($data, $stream_position), "\r\n") + 2);
$num = hexdec(trim($rawnum));
$stream_position += httprl_strlen($rawnum);
$chunk = substr($data, $stream_position, $num);
if (isset($result->headers['content-encoding'])) {
if ($result->headers['content-encoding'] === 'gzip') {
$chunk = @gzinflate(substr($chunk, 10));
}
elseif ($result->headers['content-encoding'] === 'deflate') {
$chunk = @gzinflate($chunk);
}
elseif ($result->headers['content-encoding'] === 'br' && is_callable('brotli_uncompress')) {
$chunk = @brotli_uncompress($chunk);
}
if ($chunk === FALSE) {
break;
}
}
$output .= $chunk;
$stream_position += httprl_strlen($chunk);
}
if ($chunk !== FALSE) {
$result->data = $output;
}
}
elseif (isset($result->headers['content-encoding'])) {
if ($result->headers['content-encoding'] === 'gzip') {
$chunk = @gzinflate(substr($result->data, 10));
}
elseif ($result->headers['content-encoding'] === 'deflate') {
$chunk = @gzinflate($result->data);
}
elseif ($result->headers['content-encoding'] === 'br' && is_callable('brotli_uncompress')) {
$chunk = @brotli_uncompress($result->data);
}
if (isset($chunk) && $chunk !== FALSE) {
$result->data = $chunk;
}
}
if (array_key_exists('max_data_size', $result->options)) {
$result->code = 206;
$new_data = array();
foreach ($result->ranges as $range) {
if (!is_numeric($range['start'])) {
$new_data[] = substr($result->data, -$range['end']);
}
elseif (!is_numeric($range['end'])) {
$new_data[] = substr($result->data, $range['start']);
}
else {
$new_data[] = substr($result->data, $range['start'], $range['end'] + 1 - $range['start']);
}
}
$result->data = implode('', $new_data);
if (isset($result->headers['content-length'])) {
$result->headers['content-length'] = httprl_strlen($result->data);
}
}
if (isset($result->headers['content-type']) && strpos($result->headers['content-type'], 'multipart/byteranges; boundary=') !== FALSE) {
$boundary = "\r\n--" . substr($result->headers['content-type'], 31);
$datas = explode($boundary, $result->data);
$result->data = '';
foreach ($datas as $data) {
$split = preg_split("/\r\n\r\n|\n\n|\r\r/", $data, 2);
if (count($split) < 2) {
continue;
}
list($response, $data) = $split;
$response = array_filter(preg_split("/\r\n|\n|\r/", $response));
while ($line = trim(array_shift($response))) {
list($name, $value) = explode(':', $line, 2);
$name = strtolower($name);
if ($name != 'content-range') {
$result->headers[$name] = trim($value);
}
}
$result->data .= $data;
}
if (isset($result->headers['content-length'])) {
$result->headers['content-length'] = httprl_strlen($result->data);
}
}
}
function httprl_reconstruct_redirects(&$result) {
if (empty($result->options['internal_states']['original_url'])) {
return;
}
$result->url = $result->options['internal_states']['original_url'];
$result->redirect_code_array = $result->options['internal_states']['redirect_code_array'];
$result->redirect_code = array_pop($result->options['internal_states']['redirect_code_array']);
$result->redirect_url_array = $result->options['internal_states']['redirect_url_array'];
$result->redirect_url = array_pop($result->options['internal_states']['redirect_url_array']);
unset($result->options['internal_states']['original_url'], $result->options['internal_states']['redirect_code_array'], $result->options['internal_states']['redirect_url_array']);
if (empty($result->options['internal_states'])) {
unset($result->options['internal_states']);
}
}
function httprl_background_processing($output, $wait = TRUE, $content_type = "text/html; charset=utf-8", $length = 0) {
if (headers_sent()) {
return FALSE;
}
@ob_end_clean();
$loop = 0;
while (ob_get_level() && $loop < 25) {
@ob_end_clean();
$loop++;
}
ignore_user_abort(TRUE);
ob_start();
header("HTTP/1.0 200 OK");
header("Content-type: " . $content_type);
header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
header("Cache-Control: no-cache");
header("Cache-Control: must-revalidate");
header("Connection: close");
header('Etag: "' . microtime(TRUE) . '"');
print $output;
$size = ob_get_length();
header("Content-Length: " . $size);
@ob_end_flush();
@ob_flush();
@flush();
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
if ($wait) {
sleep(1);
}
return TRUE;
}
function httprl_strlen($string) {
static $mb_strlen;
if (!isset($mb_strlen)) {
$mb_strlen = function_exists('mb_strlen');
}
if ($mb_strlen) {
return mb_strlen($string, '8bit');
}
else {
return strlen($string);
}
}
function httprl_glue_url($parsed) {
if (!is_array($parsed)) {
return FALSE;
}
$uri = isset($parsed['scheme']) ? $parsed['scheme'] . ':' . (strtolower($parsed['scheme']) == 'mailto' ? '' : '//') : '';
$uri .= isset($parsed['user']) ? $parsed['user'] . (isset($parsed['pass']) ? ':' . $parsed['pass'] : '') . '@' : '';
$uri .= isset($parsed['host']) ? $parsed['host'] : '';
$uri .= !empty($parsed['port']) ? ':' . $parsed['port'] : '';
if (isset($parsed['path'])) {
$uri .= substr($parsed['path'], 0, 1) == '/' ? $parsed['path'] : (!empty($uri) ? '/' : '') . $parsed['path'];
}
$uri .= isset($parsed['query']) ? '?' . $parsed['query'] : '';
$uri .= isset($parsed['fragment']) ? '#' . $parsed['fragment'] : '';
return $uri;
}
function httprl_get_server_schema() {
return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || isset($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] == 'on' ? 'https' : 'http';
}
function httprl_fast403($msg = '') {
global $base_path;
if (!headers_sent()) {
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
header('X-HTTPRL: Forbidden.');
}
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n";
print '<html>';
print '<head><title>403 Forbidden</title></head>';
print '<body><h1>Forbidden</h1>';
print '<p>You are not authorized to access this page.</p>';
print '<p><a href="' . $base_path . '">Home</a></p>';
print '<!-- httprl_fast403 ' . $msg . ' -->';
print '</body></html>';
httprl_call_exit();
}
function httprl_lock_release($name) {
$lock_inc = httprl_variable_get('lock_inc', './includes/lock.inc');
if ($lock_inc === './includes/lock.inc') {
unset($GLOBALS['locks'][$name]);
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
db_delete('semaphore')
->condition('name', $name)
->execute();
}
else {
db_query("DELETE FROM {semaphore} WHERE name = '%s'", $name);
}
}
elseif (strpos($lock_inc, '/memcache_storage/includes/lock.inc') !== FALSE) {
unset($GLOBALS['locks'][$name]);
if (MemcacheStorageAPI::get($name, 'semaphore')) {
MemcacheStorageAPI::delete($name, 'semaphore');
}
}
elseif (strpos($lock_inc, '/memcache/memcache-lock.inc') !== FALSE) {
unset($GLOBALS['locks'][$name]);
if (dmemcache_get($name, 'semaphore')) {
dmemcache_delete($name, 'semaphore');
}
}
elseif (strpos($lock_inc, '/apdqc/apdqc.lock.inc') !== FALSE) {
lock_release_fuzzy($name);
}
else {
lock_release($name);
}
}
function httprl_print_empty(&$data, $level = 0, $output_plain_text) {
$level++;
if ($level < 5) {
if (is_object($data)) {
$new_object = new stdClass();
$new_object->__original_class_name__ = get_class($data);
foreach ($data as $key => $values) {
$new_object->{$key} = httprl_print_empty($values, $level, $output_plain_text);
}
$data = $new_object;
}
elseif (is_array($data)) {
foreach ($data as &$values) {
$values = httprl_print_empty($values, $level, $output_plain_text);
}
}
elseif (is_bool($data) || strlen((string) $data) == 0) {
$data = strtoupper(var_export($data, TRUE));
}
elseif (!$output_plain_text && is_string($data) && strlen($data) > HTTPRL_PR_MAX_STRING_LENGTH) {
$data = substr($data, 0, HTTPRL_PR_MAX_STRING_LENGTH);
}
}
return $data;
}
function httprl_pr($input) {
$output_plain_text = FALSE;
if (strpos(implode("\n", array_map('strtolower', headers_list())), 'content-type: text/plain') !== FALSE || function_exists('drupal_is_cli') && drupal_is_cli()) {
$output_plain_text = TRUE;
}
$old_setting = ini_set('mbstring.substitute_character', '"none"');
$input = func_get_args();
$data = httprl_print_empty($input, 0, $output_plain_text);
if (count($data) == 1) {
$data = array_pop($data);
}
$output = print_r($data, TRUE);
$encoded = FALSE;
if (function_exists('mb_convert_encoding')) {
$track_errors = ini_set('track_errors', '1');
$php_errormsg = '';
$translated = @mb_convert_encoding($output, 'UTF-8', 'auto');
if (empty($php_errormsg)) {
$encoded = TRUE;
}
$php_errormsg = '';
ini_set('track_errors', $track_errors);
}
if (!$encoded) {
$translated = @iconv('utf-8', 'utf-8//TRANSLIT//IGNORE', $output);
}
$options = ENT_QUOTES;
if (defined('ENT_SUBSTITUTE')) {
$options = ENT_QUOTES | ENT_SUBSTITUTE;
}
elseif (defined('ENT_IGNORE')) {
$options = ENT_QUOTES | ENT_IGNORE;
}
$translated = htmlentities($translated, $options, 'UTF-8');
$original_size = strlen($output);
$translated_size = strlen($translated);
$ratio = 0;
if ($original_size != 0) {
$ratio = ($original_size - $translated_size) / $original_size;
}
if (!empty($translated_size) && !empty($ratio) && $ratio < 0.5 && !$output_plain_text) {
$html_output = TRUE;
$output = $translated;
}
else {
if (!$output_plain_text) {
$output = str_replace(array(
'<',
'>',
), array(
'<',
'>',
), $output);
}
$output = "<pre>\n" . $output . "\n</pre>";
}
$output = array_filter(explode("\n", $output), 'strlen');
foreach ($output as $key => $value) {
if (str_replace(' ', '', $value) == "(") {
$output[$key - 1] .= ' (';
unset($output[$key]);
}
}
$output = implode("\n", $output);
if (!empty($html_output)) {
$output = str_replace(' ', ' ', nl2br($output)) . '<br />';
}
else {
$output .= "\n";
}
ini_set('mbstring.substitute_character', $old_setting);
return $output;
}
function _httprl_use_proxy($host) {
$proxy_exceptions = httprl_variable_get('proxy_exceptions', array(
'localhost',
'127\\.0\\.0\\.1',
));
$use_proxy = TRUE;
if (is_array($proxy_exceptions) && count($proxy_exceptions)) {
foreach ($proxy_exceptions as $exception) {
$match = preg_match("/{$exception}/is", $host);
if ($match) {
$use_proxy = FALSE;
break;
}
}
}
return $use_proxy;
}
function httprl_variable_get($name, $default = NULL) {
global $conf;
if (isset($conf[$name])) {
return $conf[$name];
}
if (function_exists('db_query') && !httprl_drupal_full_bootstrap()) {
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
$variables = array_map('unserialize', db_query('SELECT name, value FROM {variable} WHERE name = :name', array(
':name' => $name,
))
->fetchAllKeyed());
return isset($variables[$name]) ? $variables[$name] : $default;
}
else {
$result = db_query("SELECT value FROM {variable} WHERE name = '%s'", $name);
if (!empty($result)) {
$result = db_result($result);
if (!empty($result)) {
$value = @unserialize($result);
}
}
return isset($value) ? $value : $default;
}
}
else {
return $default;
}
}
function httprl_run_array(&$array) {
$last = NULL;
foreach ($array as &$data) {
if (!isset($data['type'])) {
continue;
}
if (isset($data['last'])) {
$last = $data['last'];
}
if (isset($data['args']) && array_key_exists('last', $data['args'])) {
$data['args']['last'] = $last;
$data['args'] = array_values($data['args']);
}
if (array_key_exists('printed', $data)) {
ob_start();
}
$args = array();
if (isset($data['args']) && is_array($data['args'])) {
foreach ($data['args'] as &$arg) {
$args[] =& $arg;
}
}
$track_errors = ini_set('track_errors', '1');
$php_errormsg = '';
switch ($data['type']) {
case 'function':
if (function_exists($data['call'])) {
$last = call_user_func_array($data['call'], $args);
}
else {
$php_errormsg = 'Recoverable Fatal error: Call to undefined function ' . $data['call'] . '()';
}
break;
case 'method':
if (method_exists($last, $data['call'])) {
$last = call_user_func_array(array(
$last,
$data['call'],
), $args);
}
else {
$php_errormsg = 'Recoverable Fatal error: Call to undefined method ' . get_class($last) . '::' . $data['call'] . '()';
}
break;
}
if (!empty($php_errormsg)) {
$data['error'] = $php_errormsg;
ini_set('track_errors', $track_errors);
watchdog('httprl', 'Error thrown in httprl_run_array(). <br /> @error', array(
'@error' => $php_errormsg,
), WATCHDOG_ERROR);
}
if (array_key_exists('printed', $data)) {
$data['printed'] = ob_get_contents();
ob_end_clean();
}
if (array_key_exists('return', $data)) {
$data['return'] = $last;
}
}
return array(
'args' => array(
$array,
),
);
}
function httprl_run_function($function, &$input_args) {
$args = array();
foreach ($input_args as &$arg) {
$args[] =& $arg;
}
ob_start();
$track_errors = ini_set('track_errors', '1');
$php_errormsg = '';
$return = NULL;
try {
if (function_exists($function)) {
$return = call_user_func_array($function, $args);
}
else {
$php_errormsg = 'Recoverable Fatal error: Call to undefined function ' . $function . '()';
}
} catch (Exception $e) {
$php_errormsg = $e;
}
$printed = ob_get_contents();
ob_end_clean();
$data = array(
'return' => $return,
'args' => $args,
'printed' => $printed,
);
if (!empty($php_errormsg)) {
$data['error'] = $php_errormsg;
ini_set('track_errors', $track_errors);
watchdog('httprl', 'Error thrown in httprl_run_function(). <br /> @error', array(
'@error' => $php_errormsg,
), WATCHDOG_ERROR);
}
return $data;
}
function httprl_boot() {
global $base_root;
$full_url = $base_root . request_uri();
if (strpos($full_url, '/httprl_async_function_callback') === FALSE || $_SERVER['REQUEST_METHOD'] !== 'POST' || empty($_POST['master_key']) || empty($_POST['temp_key']) || strpos($_POST['temp_key'], 'httprl_') !== 0 || !empty($_POST['function'])) {
return NULL;
}
if (defined('DRUPAL_ROOT')) {
require_once DRUPAL_ROOT . '/' . dirname(drupal_get_filename('module', 'httprl')) . '/httprl.async.inc';
}
else {
require_once './' . dirname(drupal_get_filename('module', 'httprl')) . '/httprl.async.inc';
}
httprl_async_page();
}
function httprl_drupal_get_private_key() {
$full_bootstrap = httprl_drupal_full_bootstrap();
$private_key = $full_bootstrap ? drupal_get_private_key() : httprl_variable_get('drupal_private_key', 0);
return $private_key;
}
function httprl_call_exit() {
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7 && drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) {
drupal_save_session(FALSE);
drupal_exit();
}
else {
session_save_session(FALSE);
exit;
}
}
function httprl_drupal_full_bootstrap() {
static $full_bootstrap;
if (!isset($full_bootstrap)) {
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
$level = drupal_bootstrap();
$full_bootstrap = $level == DRUPAL_BOOTSTRAP_FULL ? TRUE : FALSE;
}
else {
$full_bootstrap = isset($GLOBALS['multibyte']) ? TRUE : FALSE;
}
}
return $full_bootstrap;
}
function httprl_is_background_callback_capable() {
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7 && httprl_variable_get('maintenance_mode', 0) || httprl_variable_get('site_offline', 0)) {
return FALSE;
}
if (!httprl_variable_get('httprl_background_callback', HTTPRL_BACKGROUND_CALLBACK)) {
return FALSE;
}
if (httprl_drupal_full_bootstrap() && function_exists('menu_get_item') && !menu_get_item('httprl_async_function_callback')) {
return FALSE;
}
return TRUE;
}
function httprl_set_user($uid) {
$account = user_load($uid);
if (!empty($account)) {
$GLOBALS['user'] = $account;
if (defined('VERSION') && substr(VERSION, 0, 1) >= 7) {
drupal_save_session(FALSE);
}
else {
session_save_session(FALSE);
}
return TRUE;
}
}
function httprl_set_q($q) {
$_GET['q'] = $q;
}
function &httprl_qcinp($callback, $param_arr = array(), $return = TRUE, $httprl_options = array()) {
$return_var = NULL;
$callback_options[0]['function'] = $callback;
if ($return) {
$return_var = '';
$callback_options[0]['return'] =& $return_var;
}
if (isset($httprl_options['context'])) {
$callback_options[0]['context'] = $httprl_options['context'];
unset($httprl_options['context']);
}
$callback_options[0]['options'] = $httprl_options;
$callback_options = array_merge($callback_options, $param_arr);
httprl_queue_background_callback($callback_options);
return $return_var;
}
function httprl_batch_callback($callback, $data, $options = array()) {
$results = array();
$unified_result = NULL;
$number_of_items = count($data);
$options += array(
'max_batchsize' => 30,
'threads' => 3,
'timeout' => 120,
'multiple_helper' => FALSE,
);
if ($number_of_items < $options['max_batchsize'] * $options['threads']) {
$options['max_batchsize'] = ceil($number_of_items / $options['threads']);
}
$data = array_chunk($data, $options['max_batchsize'], TRUE);
unset($options['max_batchsize']);
$options['domain_connections'] = $options['threads'];
unset($options['threads']);
$multiple = $options['multiple_helper'];
unset($options['multiple_helper']);
if ($multiple) {
foreach ($data as $key => $values) {
$results[$key] =& httprl_qcinp('httprl_run_multiple', array(
$callback,
$values,
), TRUE, $options);
}
}
else {
foreach ($data as $key => $values) {
$results[$key] =& httprl_qcinp($callback, array(
$values,
), TRUE, $options);
}
}
httprl_send_request();
$unified = TRUE;
$is_assoc = TRUE;
foreach ($results as $key => $value) {
if (is_null($unified_result)) {
$unified_result = $results[$key];
}
elseif (is_string($results[$key]) && is_string($unified_result)) {
$unified_result .= $results[$key];
}
elseif (is_array($results[$key]) && is_array($unified_result)) {
if ($is_assoc && httprl_is_array_assoc($results[$key]) && httprl_is_array_assoc($unified_result)) {
$unified_result = httprl_lossless_assoc_array_merge($unified_result, $results[$key]);
}
else {
$is_assoc = FALSE;
$unified_result += $results[$key];
}
}
else {
$unified = FALSE;
break;
}
}
if ($unified) {
return $unified_result;
}
else {
return $results;
}
}
function httprl_is_array_assoc($array) {
return ctype_digit(implode('', array_keys($array)));
}
function httprl_lossless_assoc_array_merge() {
$arrays = func_get_args();
$data = array();
foreach ($arrays as $a) {
foreach ($a as $k => $v) {
if (isset($data[$k])) {
$data[] = $v;
}
else {
$data[$k] = $v;
}
}
}
return $data;
}
function httprl_run_multiple($callback, $data) {
$results = array();
foreach ($data as $key => $values) {
$results[$key] = call_user_func_array($callback, array(
$values,
));
}
return $results;
}
function httprl_call_user_func_array_async($callback, array $param_arr) {
if (!httprl_is_background_callback_capable()) {
call_user_func_array($callback, $param_arr);
}
else {
$callback_options = array_merge(array(
array(
'function' => $callback,
),
), $param_arr);
httprl_queue_background_callback($callback_options);
httprl_send_request();
}
}
function httprl_call_user_func_array_cache($callback, array $param_arr = array(), array $options = array()) {
$options += array(
'cache_lifetime_min' => 0,
'cache_lifetime_max' => 3600,
'bin' => 'cache',
'lock_timeout' => 30.0,
'return_null_cache_miss' => FALSE,
);
if (is_string($callback)) {
$cid = __FUNCTION__ . ':' . $callback . ':' . drupal_hash_base64(serialize(array(
$param_arr,
)));
}
else {
$cid = __FUNCTION__ . ':' . drupal_hash_base64(serialize(array(
$callback,
$param_arr,
)));
}
$cache = cache_get($cid, $options['bin']);
if (empty($options['return_null_cache_miss']) && (!isset($cache->data) || $cache->created < REQUEST_TIME - $options['cache_lifetime_max'])) {
if (httprl_acquire_headless_lock($cid . ':run_function', $options['lock_timeout'])) {
$cache = new stdClass();
$cache->data = call_user_func_array($callback, $param_arr);
cache_set($cid, $cache->data, $options['bin'], $options['cache_lifetime_max'] + time());
httprl_lock_release($cid . ':run_function');
}
else {
lock_wait($cid . ':run_function', $options['lock_timeout']);
$cache = cache_get($cid);
if (!isset($cache->data)) {
$cache = new stdClass();
$cache->data = call_user_func_array($callback, $param_arr);
cache_set($cid, $cache->data, $options['bin'], $options['cache_lifetime_max'] + time());
}
}
if ($options['cache_lifetime_max'] == 0) {
httprl_lock_release($cid);
}
}
else {
if (empty($cache) || $cache->created < REQUEST_TIME - $options['cache_lifetime_min'] && lock_may_be_available($cid . ':run_function') && httprl_acquire_headless_lock($cid, $options['lock_timeout'])) {
$options['cache_lifetime_max'] = 0;
$options['return_null_cache_miss'] = FALSE;
$args = array(
$callback,
$param_arr,
$options,
);
if (!httprl_is_background_callback_capable()) {
_httprl_run_functions_once_on_shutdown_array_cache($args);
}
else {
httprl_call_user_func_array_async('httprl_call_user_func_array_cache', $args);
}
}
}
return isset($cache->data) ? $cache->data : NULL;
}
function _httprl_run_functions_once_on_shutdown_array_cache($args = array()) {
$run_list =& drupal_static('_httprl_run_functions_once_on_shutdown_array_cache', array());
if (!empty($args)) {
if (empty($run_list)) {
register_shutdown_function('_httprl_run_functions_once_on_shutdown_array_cache');
}
$run_list[] = $args;
}
else {
unset($args);
$will_run = array();
$already_ran = array();
foreach ($run_list as $key => $args) {
if (empty($args)) {
unset($run_list[$key]);
continue;
}
if (is_string($args[0])) {
$cid = __FUNCTION__ . ':' . $args[0] . ':' . drupal_hash_base64(serialize(array(
$args[1],
)));
}
else {
$cid = __FUNCTION__ . ':' . drupal_hash_base64(serialize(array(
$args[0],
$args[1],
)));
}
if (empty($already_ran[$cid])) {
$already_ran[$cid] = TRUE;
$will_run[] = $args;
}
}
if (!empty($will_run)) {
httprl_call_user_func_array_async('_httprl_run_cache_functions', array(
$will_run,
));
}
unset($run_list[$key]);
}
}
function _httprl_run_cache_functions($functions_to_cache) {
@ob_end_flush();
@ob_flush();
@flush();
sleep(1);
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
foreach ($functions_to_cache as $args) {
call_user_func_array('httprl_call_user_func_array_cache', $args);
}
}
function httprl_get_hostname() {
if (!empty($_SERVER['HTTP_HOST'])) {
if (strpos($_SERVER['HTTP_HOST'], ':') !== FALSE) {
return $_SERVER['SERVER_NAME'];
}
return $_SERVER['HTTP_HOST'];
}
elseif (!empty($_SERVER['SERVER_NAME'])) {
return $_SERVER['SERVER_NAME'];
}
return '';
}