View source
<?php
require_once 'cdn.constants.inc';
function cdn_file_url_alter(&$path) {
$mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
$farfuture = variable_get(CDN_BASIC_FARFUTURE_VARIABLE, CDN_BASIC_FARFUTURE_DEFAULT);
$stats = variable_get(CDN_STATS_VARIABLE, FALSE) && user_access(CDN_PERM_ACCESS_STATS);
$https_support = variable_get(CDN_HTTPS_SUPPORT_VARIABLE, FALSE);
$maintenance_mode = variable_get('maintenance_mode', FALSE);
$is_https_page = cdn_request_is_https();
if (defined('MAINTENANCE_MODE')) {
return;
}
if (cdn_status_is_enabled()) {
$fragments = parse_url($path);
if (isset($fragments['host']) || drupal_substr($path, 0, 2) == '//') {
return;
}
if (!cdn_check_protocol()) {
return;
}
if (!cdn_check_drupal_path($_GET['q'])) {
return;
}
if (!cdn_check_file($path)) {
return;
}
if ($stats) {
cdn_load_include('stats');
$start = microtime();
}
if ($mode == CDN_MODE_BASIC && $farfuture && !$maintenance_mode) {
cdn_load_include('basic.farfuture');
$path = urldecode($path);
if (!file_exists($path) && !_cdn_basic_farfuture_generate_file($path)) {
$path = drupal_urlencode($path);
return;
}
$ufi = cdn_basic_farfuture_get_identifier($path);
$path = drupal_urlencode($path);
$path_before_farfuture = $path;
$path_info = pathinfo(urldecode($path));
$token = _cdn_hmac_base64($ufi . $path_info['filename'], drupal_get_private_key() . _cdn_get_hash_salt());
$path = "cdn/farfuture/{$token}/{$ufi}/{$path}";
}
cdn_load_include($mode == CDN_MODE_BASIC ? 'basic' : 'advanced');
$servers = $mode == CDN_MODE_BASIC ? cdn_basic_get_servers($path) : cdn_advanced_get_servers($path);
if (count($servers) == 0) {
$cdn_url = FALSE;
$server = FALSE;
}
elseif (count($servers) > 1 && function_exists('cdn_pick_server')) {
$picked_server = cdn_pick_server($servers);
$cdn_url = $picked_server['url'];
$server = $picked_server['server'];
}
elseif (count($servers) > 1 && variable_get(CDN_PICK_SERVER_PHP_CODE_VARIABLE, '') !== '') {
$php_code = variable_get(CDN_PICK_SERVER_PHP_CODE_VARIABLE, '');
$picked_server = _cdn_eval_pick_server($php_code, $servers);
$cdn_url = $picked_server['url'];
$server = $picked_server['server'];
}
elseif (count($servers > 1)) {
$filename = basename($servers[0]['url']);
$unique_file_id = hexdec(substr(md5($filename), 0, 5));
$choice = $unique_file_id % count($servers);
$cdn_url = $servers[$choice]['url'];
$server = $servers[$choice]['server'];
}
else {
$cdn_url = $servers[0]['url'];
$server = $servers[0]['server'];
}
if ($is_https_page && $https_support && !empty($cdn_url)) {
$cdn_url = preg_replace('/^http:/', 'https:', $cdn_url);
}
if ($stats) {
$end = microtime();
$source_path = $mode == CDN_MODE_BASIC && $farfuture && !$maintenance_mode ? $path_before_farfuture : $path;
_cdn_devel_page_stats($source_path, $cdn_url, $server, $end - $start);
}
if ($cdn_url !== FALSE) {
$path = $cdn_url;
}
else {
if ($mode == CDN_MODE_BASIC && $farfuture) {
$path = $path_before_farfuture;
}
}
}
}
function cdn_cdn_unique_file_identifier_info() {
return array(
'md5_hash' => array(
'label' => t('MD5 hash'),
'prefix' => 'md5',
'description' => t('MD5 hash of the file.'),
'filesystem' => TRUE,
'callback' => 'md5_file',
),
'mtime' => array(
'label' => t('Last modification time'),
'prefix' => 'mtime',
'description' => t('Last modification time of the file.'),
'filesystem' => TRUE,
'callback' => 'filemtime',
),
'perpetual' => array(
'label' => t('Perpetual'),
'prefix' => 'perpetual',
'description' => t('Perpetual files never change (or are never cached
by the browser, e.g. video files).'),
'filesystem' => FALSE,
'value' => 'forever',
),
'drupal_version' => array(
'label' => t('Drupal version'),
'prefix' => 'drupal',
'description' => t('Drupal core version — this should only be applied
to files that ship with Drupal core.'),
'filesystem' => FALSE,
'value' => VERSION,
),
'drupal_cache' => array(
'label' => t('Drupal cache'),
'prefix' => 'drupal-cache',
'description' => t('Uses the current Drupal cache ID
(<code>css_js_query_string</code>). This ID is
updated automatically whenever the Drupal cache is
flushed (e.g. when you submit the modules form). Be
aware that this can change relatively often, forcing
redownloads by your visitors.'),
'filesystem' => FALSE,
'value' => variable_get('css_js_query_string', 0),
),
'deployment_id' => array(
'label' => t('Deployment ID'),
'prefix' => 'deployment',
'description' => t('A developer-defined deployment ID. Can be an
arbitrary string or number, as long as it uniquely
identifies deployments and therefore the affected
files.<br />
Define this deployment ID in any enabled module or
in <code>settings.php</code> as the
<code>CDN_DEPLOYMENT_ID</code>
constant, and it will be picked up instantaneously.'),
'filesystem' => FALSE,
'callback' => '_cdn_ufi_deployment_id',
),
);
}
function cdn_theme_registry_alter(&$theme_registry) {
if (!cdn_status_is_enabled()) {
return;
}
$mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
if ($mode == CDN_MODE_BASIC && !module_exists('advagg')) {
$theme_registry['page']['preprocess functions'][] = '_cdn_css_aggregate';
}
if (variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE)) {
cdn_load_include('fallback');
_cdn_fallback_theme_registry_alter($theme_registry);
}
}
function cdn_menu() {
$items['admin/settings/cdn'] = array(
'title' => 'CDN',
'description' => 'Configure CDN integration.',
'access arguments' => array(
CDN_PERM_ADMIN,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'cdn_admin_general_settings_form',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'cdn.admin.inc',
);
$items['admin/settings/cdn/general'] = array(
'title' => 'General',
'description' => 'General settings.',
'access arguments' => array(
CDN_PERM_ADMIN,
),
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'cdn.admin.inc',
);
$items['admin/settings/cdn/details'] = array(
'title' => 'Details',
'access arguments' => array(
CDN_PERM_ADMIN,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'cdn_admin_details_form',
),
'weight' => -8,
'type' => MENU_LOCAL_TASK,
'file' => 'cdn.admin.inc',
);
$items['admin/settings/cdn/other'] = array(
'title' => 'Other',
'description' => 'Other settings.',
'access arguments' => array(
CDN_PERM_ADMIN,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'cdn_admin_other_settings_form',
),
'weight' => -4,
'type' => MENU_LOCAL_TASK,
'file' => 'cdn.admin.inc',
);
$items['admin/cdn/touch/%'] = array(
'title' => 'Touch file',
'description' => 'Touch a file to force a resync with File Conveyor.',
'access arguments' => array(
CDN_PERM_TOUCH,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'cdn_touch_file_form',
3,
),
'type' => MENU_CALLBACK,
'file' => 'cdn.stats.inc',
);
$items['cdn/farfuture/%/%/%cdn_basic_farfuture_tail'] = array(
'title' => 'Download a far futured file',
'access callback' => TRUE,
'page callback' => 'cdn_basic_farfuture_download',
'page arguments' => array(
2,
3,
4,
),
'type' => MENU_CALLBACK,
'load arguments' => array(
'%map',
'%index',
),
'file' => 'cdn.basic.farfuture.inc',
);
$items['cdn/farfuture/reverse-proxy-test/%'] = array(
'title' => 'Far Future reverse proxy test',
'access callback' => TRUE,
'page callback' => 'cdn_basic_farfuture_reverseproxy_test',
'page arguments' => array(
3,
),
'type' => MENU_CALLBACK,
'file' => 'cdn.basic.farfuture.inc',
);
return $items;
}
function cdn_perm() {
return array(
CDN_PERM_ADMIN,
CDN_PERM_ACCESS_STATS,
CDN_PERM_ACCESS_TESTING,
CDN_PERM_TOUCH,
);
}
function cdn_form_system_performance_settings_alter(&$form, &$form_state) {
$form['bandwidth_optimizations']['#attributes']['id'] = 'bw-optimizations';
$form['clear_cache']['#attributes']['id'] = 'clear-cache';
}
function cdn_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
if ($op == 'alter') {
cdn_load_include('fallback');
if (isset($node->body)) {
cdn_html_alter_image_urls($node->body);
}
elseif (isset($node->teaser)) {
cdn_html_alter_image_urls($node->teaser);
}
if (isset($node->content) && is_array($node->content['body']) && isset($node->content['body']['#value'])) {
cdn_html_alter_image_urls($node->content['body']['#value']);
}
}
}
function cdn_theme() {
return array(
'cdn_page_stats' => array(
'file' => 'theme.inc',
'arguments' => array(
'file_count' => NULL,
'cdn_file_count' => NULL,
'synced_files_per_server_count' => NULL,
'total_time' => NULL,
'synced_files' => NULL,
'unsynced_files' => NULL,
),
),
'cdn_page_stats_file_link' => array(
'file' => 'theme.inc',
'arguments' => array(
'file' => NULL,
),
),
);
}
function cdn_init() {
if (!cdn_status_is_enabled()) {
return;
}
_cdn_prefetch_dns();
$mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
if ($mode == CDN_MODE_BASIC && !module_exists('advagg')) {
cdn_load_include('basic.css');
}
if (variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE)) {
cdn_load_include('fallback');
}
if (variable_get(CDN_STATS_VARIABLE, FALSE) && user_access(CDN_PERM_ACCESS_STATS)) {
drupal_add_css(drupal_get_path('module', 'cdn') . '/cdn.css');
}
}
function cdn_exit($destination = NULL) {
if (!function_exists('_cdn_devel_page_stats')) {
return;
}
if (function_exists('drupal_get_headers') && !strstr(drupal_get_headers(), 'html')) {
return;
}
if (!$destination && variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED) != CDN_DISABLED && variable_get(CDN_STATS_VARIABLE, FALSE) && user_access(CDN_PERM_ACCESS_STATS)) {
list($file_count, $cdn_file_count, $synced_files_per_server_count, $total_time, $synced_files, $unsynced_files, ) = _cdn_devel_page_stats();
print theme('cdn_page_stats', $file_count, $cdn_file_count, $synced_files_per_server_count, $total_time, $synced_files, $unsynced_files);
}
}
function cdn_flush_caches() {
cdn_get_blacklist(TRUE);
}
function cdn_cdn_blacklist() {
$blacklist = array();
if (module_exists('wysiwyg')) {
foreach (wysiwyg_get_all_editors() as $editor) {
if (!$editor['installed']) {
continue;
}
$blacklist[] = $editor['library path'] . '/*';
}
}
$blacklist[] = 'image_captcha*';
return $blacklist;
}
function cdn_basic_farfuture_tail_to_arg($arg, $map, $index) {
return implode('/', array_slice($map, $index));
}
function cdn_basic_farfuture_tail_load($arg, $map, $index) {
$arg = implode('/', array_slice($map, $index));
$map = array_slice($map, 0, $index);
return $arg;
}
function cdn_cacheaudit() {
$results = array(
array(
'Settings',
'Value',
),
);
$status = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED);
if ($status == CDN_ENABLED) {
$status_value = 'enabled';
}
elseif ($status == CDN_TESTING) {
$status_value = 'testing';
}
else {
$status_value = 'disabled';
}
$results[] = array(
'Status',
$status_value,
);
$mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
$results[] = array(
'Mode',
$mode ? 'Origin Pull' : 'File Conveyor',
);
if ($mode == CDN_MODE_BASIC) {
cdn_load_include('basic');
$results[] = array(
' mappings',
count(_cdn_basic_parse_raw_mapping(cdn_basic_get_mapping())),
);
$results[] = array(
' Far Future expiration',
variable_get(CDN_BASIC_FARFUTURE_VARIABLE, CDN_BASIC_FARFUTURE_DEFAULT),
);
}
$results[] = array(
'Domains',
count(cdn_get_domains()),
);
return array(
'cdn' => $results,
);
}
function cdn_get_domains() {
$domains = array();
if (variable_get(CDN_MODE_VARIABLE, FALSE) == CDN_MODE_BASIC) {
cdn_load_include('basic');
$mapping = cdn_basic_get_mapping();
$lines = preg_split("/[\n\r]+/", $mapping, -1, PREG_SPLIT_NO_EMPTY);
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) {
continue;
}
$parts = explode('|', $line);
foreach (explode(' ', $parts[0]) as $part) {
$part = trim($part);
if (strpos($part, '//') === 0) {
$part = 'http:' . $part;
}
$domains[] = parse_url($part, PHP_URL_HOST);
}
}
}
elseif (variable_get(CDN_MODE_VARIABLE, FALSE) == CDN_MODE_ADVANCED) {
cdn_load_include('advanced');
$db = _cdn_advanced_get_db_connection();
if (!$db) {
return array();
}
$sql = "SELECT url\n FROM synced_files\n GROUP BY server";
$stmt = $db
->prepare($sql);
$stmt
->execute();
$rows = $stmt
->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$domains[] = parse_url($row['url'], PHP_URL_HOST);
}
}
return array_unique($domains);
}
function cdn_get_blacklist($reset = FALSE) {
static $blacklist = NULL;
if (is_null($blacklist) || $reset) {
$cache = cache_get('cdn_blacklist');
if (!isset($cache->data) || $reset) {
$blacklist = module_invoke_all('cdn_blacklist');
drupal_alter('cdn_blacklist', $blacklist);
$blacklist = array_unique($blacklist);
$blacklist = implode("\n", $blacklist);
cache_set('cdn_blacklist', $blacklist, 'cache', CACHE_TEMPORARY);
}
else {
$blacklist = $cache->data;
}
}
return $blacklist;
}
function cdn_serve_from_https() {
return variable_get(CDN_HTTPS_SUPPORT_VARIABLE, FALSE) && cdn_request_is_https();
}
function cdn_request_is_https() {
return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || isset($_SERVER['HTTP_X_FORWARDED_PROTOCOL']) && $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] == 'https';
}
function cdn_status_is_enabled() {
$status = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED);
return $status == CDN_ENABLED || $status == CDN_TESTING && user_access(CDN_PERM_ACCESS_TESTING);
}
function cdn_check_protocol() {
$https_support = variable_get(CDN_HTTPS_SUPPORT_VARIABLE, FALSE);
if (cdn_request_is_https() && !$https_support) {
return FALSE;
}
return TRUE;
}
function cdn_check_drupal_path($path) {
global $user;
$blacklist = variable_get(CDN_EXCEPTION_DRUPAL_PATH_BLACKLIST_VARIABLE, CDN_EXCEPTION_DRUPAL_PATH_BLACKLIST_DEFAULT);
$auth_blacklist = variable_get(CDN_EXCEPTION_AUTH_USERS_BLACKLIST_VARIABLE, CDN_EXCEPTION_AUTH_USERS_BLACKLIST_DEFAULT);
if (drupal_match_path($path, $blacklist)) {
return FALSE;
}
if ($user->uid > 0 && drupal_match_path($path, $auth_blacklist)) {
return FALSE;
}
return TRUE;
}
function cdn_check_file($path) {
$file_path_blacklist = variable_get(CDN_EXCEPTION_FILE_PATH_BLACKLIST_VARIABLE, CDN_EXCEPTION_FILE_PATH_BLACKLIST_DEFAULT);
$file_path_whitelist = variable_get(CDN_EXCEPTION_FILE_PATH_WHITELIST_VARIABLE, CDN_EXCEPTION_FILE_PATH_WHITELIST_DEFAULT);
$module_blacklist = cdn_get_blacklist();
if ((drupal_match_path($path, $file_path_blacklist) || drupal_match_path($path, $module_blacklist)) && !drupal_match_path($path, $file_path_whitelist)) {
return FALSE;
}
return TRUE;
}
function cdn_load_include($basename) {
module_load_include('inc', 'cdn', "cdn.{$basename}");
}
function _cdn_ufi_deployment_id($path) {
return CDN_DEPLOYMENT_ID;
}
function _cdn_eval_pick_server($php_code, $servers_for_file) {
ob_start();
$result = @eval($php_code);
ob_end_clean();
return $result;
}
function _cdn_prefetch_dns() {
$domains = cdn_get_domains();
if (count($domains)) {
drupal_set_html_head('<meta http-equiv="x-dns-prefetch-control" content="on" />');
foreach ($domains as $domain) {
drupal_set_html_head('<link rel="dns-prefetch" href="//' . $domain . '" />');
}
}
}