uid > 0 && drupal_match_path($path, $auth_users_blacklist)) { return; } if ($stats) { cdn_load_include('stats'); $start = microtime(); } // Load the include file that contains the logic for the mode that's // currently enabled. cdn_load_include(($mode == CDN_MODE_BASIC) ? 'basic' : 'advanced'); // Depending on the mode, use a different function to get the servers on // which the file is available. $servers = ($mode == CDN_MODE_BASIC) ? cdn_basic_get_servers($path) : cdn_advanced_get_servers($path); // The file is not available on any server. if (count($servers) == 0) { $cdn_url = FALSE; $server = FALSE; } // If the file is available from multiple servers, then allow a special // function to pick the desired server. The decision can be made on any // desired criteria: user's location, user's role, current date … elseif (count($servers) > 1 && function_exists('cdn_pick_server')) { $picked_server = cdn_pick_server($servers); $cdn_url = $picked_server['url']; $server = $picked_server['server']; } // Allow this special function to be defined as a Drupal variable; this // Drupal variable then contains the body of this function. This is handy // for experimentation and novice Drupal users. elseif (count($servers) > 1 && variable_get(CDN_PICK_SERVER_PHP_CODE_VARIABLE, FALSE) !== FALSE) { $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']; } // The file is available from at least one server, simply pick the first. else { $cdn_url = $servers[0]['url']; $server = $servers[0]['server']; } // If the current page is being served via HTTPS, and the CDN supports // HTTPS, then use the HTTPS file URL. if ($is_https_page && $https_support) { $cdn_url = preg_replace('/^http/', 'https', $cdn_url); } // If the user can access it, add this to the per-page statistics. if ($stats) { $end = microtime(); _cdn_devel_page_stats($path, $cdn_url, $server, $end - $start); } // Override the path with the corresponding CDN URL, *if* the file is // available on the CDN (it may only be not available in advanced mode). if ($cdn_url !== FALSE) { $path = $cdn_url; } } } /** * Implements hook_menu(). */ function cdn_menu() { $items['admin/config/development/cdn'] = array( 'title' => 'CDN', 'description' => 'Configure CDN integration.', 'access arguments' => array('administer site configuration'), 'page callback' => 'drupal_get_form', 'page arguments' => array('cdn_admin_general_settings_form'), 'type' => MENU_NORMAL_ITEM, 'file' => 'cdn.admin.inc', ); $items['admin/config/development/cdn/general'] = array( 'title' => 'General', 'description' => 'General settings.', 'access arguments' => array('administer site configuration'), 'weight' => -10, 'type' => MENU_DEFAULT_LOCAL_TASK, 'file' => 'cdn.admin.inc', ); $items['admin/config/development/cdn/details'] = array( 'title' => 'Details', 'access arguments' => array('administer site configuration'), 'page callback' => 'drupal_get_form', 'page arguments' => array('cdn_admin_details_form'), 'weight' => -8, 'type' => MENU_LOCAL_TASK, 'file' => 'cdn.admin.inc', ); $items['admin/config/development/cdn/other'] = array( 'title' => 'Other', 'description' => 'Other settings.', 'access arguments' => array('administer site configuration'), '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', ); return $items; } /** * Implements hook_permission(). */ function cdn_permission() { return array( CDN_PERM_ACCESS_STATS => array( 'title' => t('Access per-page statistics'), ), CDN_PERM_ACCESS_TESTING => array( 'title' => t('Access files on the CDN when in testing mode'), 'description' => t('Users with this permission will get files from the CDN when testing mode is enabled.'), ), CDN_PERM_TOUCH => array( 'title' => t('Touch files'), 'description' => t("'Touch' files through the links provided by the per-page statistics. This will change the last modification time of the file, and depending on your set-up, may cause a resync of the file."), ) ); } /** * Implements hook_node_view_alter(). */ function cdn_node_view_alter(&$build) { cdn_load_include('fallback'); $build['#post_render'][] = 'cdn_post_render_html_alter'; } /** * Implements hook_theme(). */ function cdn_theme() { return array( 'cdn_page_stats' => array( 'file' => 'theme.inc', 'variables' => 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', 'variables' => array( 'file' => NULL, 'absolute_path' => NULL, 'synced' => NULL, 'cdn_url' => NULL, 'server' => NULL, ), ), ); } /** * Implements hook_init(). */ function cdn_init() { // When per-page statistics are enabled, add the CSS that will be used to // make these statistics more usable. if (variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED) != CDN_DISABLED && variable_get(CDN_STATS_VARIABLE, FALSE) && user_access(CDN_PERM_ACCESS_STATS) ) { drupal_add_css(drupal_get_path('module', 'cdn') . '/cdn.css', array('every_page' => TRUE)); } } /** * Implements hook_exit(). */ function cdn_exit($destination = NULL) { // When the _cdn_devel_page_stats() function does not exist, there are no // stats to show, hence we can return immediately. // This can happen when the stats are disabled (for the current user or // entirely), or when a cached page is being served. if (!function_exists('_cdn_devel_page_stats')) { return; } // Try not to break non-HTML pages. if (function_exists('drupal_get_http_header') && !strstr(drupal_get_http_header('Content-Type'), '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', array( 'file_count' => $file_count, 'cdn_file_count' => $cdn_file_count, 'synced_files_per_server_count' => $synced_files_per_server_count, 'total_time' => $total_time, 'synced_files' => $synced_files, 'unsynced_files' => $unsynced_files )); } } //---------------------------------------------------------------------------- // Public functions. /** * Get all domains from which files might be served. This information is * necessary for some modules, e.g. Boost. * * @return * An array of domain names. */ function cdn_get_domains() { $domains = array(); // Origin Pull mode domains. if (variable_get(CDN_MODE_VARIABLE, FALSE) == CDN_MODE_BASIC) { cdn_load_include('basic'); $mapping = variable_get(CDN_BASIC_MAPPING_VARIABLE, ''); $lines = preg_split("/[\n\r]+/", $mapping, -1, PREG_SPLIT_NO_EMPTY); foreach ($lines as $line) { // Parse this line. It may or may not limit the CDN URL to a list of // file extensions. if (strpos($line, '|') !== FALSE) { $parts = explode('|', $line); $domains[] = parse_url(trim($parts[0]), PHP_URL_HOST); } else { $domains[] = parse_url(trim($line), PHP_URL_HOST); } } } // File Conveyor mode domains. elseif (variable_get(CDN_MODE_VARIABLE, FALSE) == CDN_MODE_ADVANCED) { cdn_load_include('advanced'); $db = _cdn_advanced_get_db_connection(); // In case no connection to the database could be made, pretend no // domains are being used. if (!$db) { return array(); } // Retrieve all unique domains (by retrieving one URL per server) and then // parsing the domain names in those URLs. $sql = "SELECT url FROM synced_files 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); } /** * Helper function to efficiently load include files for this module. */ function cdn_load_include($basename) { static $used = array(); static $base_path; if (!isset($base_path)) { $base_path = './' . drupal_get_path('module', 'cdn'); } if (!isset($used[$basename])) { require $base_path . "/cdn.$basename.inc"; } $used[$basename] = TRUE; } /** * Alter file URLs in the given HTML (currently only image file URLs). * * Can be used as a #post_render callback. */ function cdn_post_render_html_alter($html, $elements) { cdn_html_alter_image_urls($html); return $html; } //---------------------------------------------------------------------------- // Private functions. /** * Helper function to evaluate CDN_PICK_SERVER_PHP_CODE_VARIABLE, when that is * being used instead of an actual cdn_pick_server() function. * * @param $php_code * The PHP code to be evaluated. * @param $servers_for_file * The $servers_for_file parameter, as it will be available to the eval()'d * $php_code. This variable is not passed by reference, hence it will not be * changed outside the scope of this function. */ function _cdn_eval_pick_server($php_code, $servers_for_file) { ob_start(); $result = @eval($php_code); ob_end_clean(); return $result; }