uid > 0 && drupal_match_path($path, $exclusions_logged_in)) { return; } if ($stats) { require_once(drupal_get_path('module', 'cdn') . '/cdn.stats.inc'); } if ($status == CDN_ENABLED || ($status == CDN_TESTING && user_access(CDN_PERM_ACCESS_TESTING))) { if ($stats) { $start = microtime(); } // Depending on the mode, use a different function to get the URL. if ($mode == CDN_MODE_BASIC) { $cdn_url = cdn_basic_get_url($path); $server = FALSE; } else { list($cdn_url, $server) = cdn_advanced_get_url($path); } // 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; } } } /** * Implementation of hook_menu(). */ function cdn_menu() { $items['admin/settings/cdn'] = array( 'title' => 'CDN integration', '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/settings/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/settings/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/settings/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; } /** * Implementation of hook_perm(). */ function cdn_perm() { return array(CDN_PERM_ACCESS_STATS, CDN_PERM_ACCESS_TESTING, CDN_PERM_TOUCH); } /** * Implementation of hook_form_alter(). */ function cdn_form_system_performance_settings_alter(&$form, &$form_state) { // Add an id to the "Clear cached data" fieldset in the // "system_performance_settings" form, so we can link to it directly. $form['clear_cache']['#attributes']['id'] = 'clear-cache'; } /** * Implementation of hook_theme(). */ 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), ), ); } /** * Implementation of 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'); } } /** * Implementation of 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_headers')) { $headers = drupal_get_headers(); $formats = array('xml', 'javascript', 'json', 'plain', 'image', 'application', 'csv', 'x-comma-separated-values'); foreach ($formats as $format) { if (strstr($headers, $format)) { 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 ); } } /** * Implementation of hook_requirements(). */ function cdn_requirements($phase) { $requirements = array(); $t = get_t(); switch ($phase) { case 'install' : case 'runtime' : require_once drupal_get_path('module', 'cdn') . '/cdn.requirements.inc'; // CDN integration core patch. _cdn_requirements_generate_requirement_for_patch( $requirements, 'core', $t('CDN integration — Drupal core patch') ); if (module_exists('imagecache')) { // CDN integration ImageCache patch. _cdn_requirements_generate_requirement_for_patch( $requirements, 'imagecache', $t('CDN integration — ImageCache module patch') ); } // CDN integration status. $status = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED); $mode = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC); $requirements['cdn']['title'] = $t('CDN integration'); // Set the basic info: disabled/testing/enabled. if ($status == CDN_DISABLED) { $requirements['cdn'] += array( 'description' => $t('CDN integration is disabled for all users.'), 'severity' => REQUIREMENT_WARNING, 'value' => $t('Disabled'), ); } elseif ($status == CDN_TESTING) { $requirements['cdn'] += array( 'description' => $t( 'CDN integration is only enabled for users with the %cdn-testing-mode-permission permission', array('%cdn-testing-mode-permission' => CDN_PERM_ACCESS_TESTING) ), 'severity' => REQUIREMENT_WARNING, 'value' => $t('In testing mode'), ); } else { $requirements['cdn'] += array( 'description' => $t('CDN integration is enabled for all users.'), 'severity' => REQUIREMENT_OK, 'value' => $t('Enabled'), ); } // When CDN integration is enabled, add on more information. if ($status != CDN_DISABLED) { if ($mode == CDN_MODE_BASIC) { $requirements['cdn']['value'] .= ' – '. t('basic mode'); } else { $requirements['cdn']['value'] .= ' – '. t('advanced mode'); $items = array(); $synced_files_db = variable_get(CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE, FALSE); if ($synced_files_db !== FALSE) { $daemon_pid_file = str_replace(CDN_DAEMON_SYNCED_FILES_DB, CDN_DAEMON_PID_FILE, $synced_files_db); $persistent_data_db = str_replace(CDN_DAEMON_SYNCED_FILES_DB, CDN_DAEMON_PERSISTENT_DATA_DB, $synced_files_db); $drupal_root_path = variable_get(CDN_DRUPAL_ROOT_VARIABLE, realpath('.')); $synced_files_db_exists = file_exists($synced_files_db); $synced_files_db_readable = @fopen($synced_files_db, 'r'); $persistent_data_db_exists = file_exists($persistent_data_db); $persistent_data_db_readable = @fopen($persistent_data_db, 'r'); $daemon_pid_file_exists = file_exists($daemon_pid_file); $db = _cdn_advanced_get_db_connection(); if ($db !== FALSE) { $input_file_mask = $drupal_root_path .'%'; $sql = "SELECT COUNT(*) AS count, server FROM synced_files WHERE input_file LIKE :input_file GROUP BY server"; $stmt = $db->prepare($sql); $stmt->bindParam(':input_file', $input_file_mask, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetchAll(); $synced_file_stats = $result; } if ($persistent_data_db_exists && $persistent_data_db_readable) { try { $db = new PDO('sqlite:' . $persistent_data_db); } catch (PDOException $e) { $items[] = t("Could not connect to persistent data database."); } if ($db !== FALSE) { $sql = "SELECT COUNT(*) FROM pipeline_queue"; $stmt = $db->prepare($sql); $stmt->execute(); $result = $stmt->fetchAll(); $pipeline_queue_count = $result[0][0]; $sql = "SELECT COUNT(*) FROM pipeline_list"; $stmt = $db->prepare($sql); $stmt->execute(); $result = $stmt->fetchAll(); $pipeline_list_count = $result[0][0]; } } $items[] = ($synced_files_db_exists) ? t('The synced files database exists.') : t("The synced files database doesn't exist."); $items[] = ($synced_files_db_readable) ? t('The synced files database is readable.') : t("The synced files database isn't readable."); if ($synced_files_db_readable) { foreach ($synced_file_stats as $row) { $items[] = t('!synced-file-count files have been synced to the %server server.', array('!synced-file-count' => $row['count'], '%server' => $row['server'])); } } else { $items[] = t("Number of synced files is unknown."); } $items[] = ($daemon_pid_file_exists) ? t('The daemon is currently running.') : '' . t('The daemon is currently not running.') . ''; if (isset($pipeline_queue_count)) { $items[] = t("!pipeline-queue-count files are waiting to be synced.", array('!pipeline-queue-count' => $pipeline_queue_count)); $items[] = t("!pipeline-list-count files are currently being synced.", array('!pipeline-list-count' => $pipeline_list_count)); } // If either of these 3 checks failed, mark this requirement's // severity as being an error. if (!($synced_files_db_exists && $synced_files_db_readable && $daemon_pid_file_exists)) { $requirements['cdn']['severity'] = REQUIREMENT_ERROR; } } else { $items[] = t('The synced files database setting has not yet been configured.'); $requirements['cdn']['severity'] = REQUIREMENT_ERROR; } $requirements['cdn']['description'] .= '
' . theme('item_list', $items); } } } return $requirements; } //---------------------------------------------------------------------------- // Public functions. /** * Gets the URL for a file when the basic mode is enabled. * * @param $path * The path to get the URL for. */ function cdn_basic_get_url($path) { // Ensure the configuration is correct. if (variable_get(CDN_BASIC_URL_VARIABLE, FALSE) === FALSE) { return FALSE; } $extensions = str_replace(array(' ', '.'), array('|', '\.'), variable_get(CDN_BASIC_EXTENSIONS_VARIABLE, CDN_BASIC_EXTENSIONS_DEFAULT)); if (preg_match("/($extensions)$/i", $path)) { $base_path = base_path(); $cdn_url = variable_get(CDN_BASIC_URL_VARIABLE, 'http://yourcdn.com'); // If the current page is being served via HTTPS, and the CDN supports // HTTPS, then use the HTTPS file URL. if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') && variable_get(CDN_BASIC_HTTPS_VARIABLE, FALSE)) { $cdn_url = preg_replace('/^http/', 'https', $cdn_url); } return $cdn_url . $base_path . $path; } else { return FALSE; } } /** * Gets the URL for a file when the basic mode is enabled. * * @param $path * The path to get the URL for. */ function cdn_advanced_get_url($path) { $db = _cdn_advanced_get_db_connection(); // In case no connection to the database could be made, pretend the file was // not found in the synced files database. if (!$db) { return array(FALSE, FALSE); } // Get the real path to the file (resolves symbolic links). $input_file = realpath('./' . $path); // Retrieve the URLs of the file on the CDN. $sql = "SELECT url, server FROM synced_files WHERE input_file = :input_file"; $stmt = $db->prepare($sql); $stmt->bindParam(':input_file', $input_file, PDO::PARAM_STR); $stmt->execute(); $servers = $stmt->fetchAll(PDO::FETCH_ASSOC); // The file is not available from any server. if (count($servers) == 0) { $url = FALSE; $server = FALSE; } // If the file is available from multiple servers, then allow a special // function to pic 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_advanced_pick_server')) { $picked_server = cdn_advanced_pick_server($servers); $url = $picked_server['url']; $server = $picked_server['server']; } // The file is available from at least one server, simply pick the first. else { $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 ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') && variable_get(CDN_ADVANCED_HTTPS_VARIABLE, FALSE)) { $url = preg_replace('/^http/', 'https', $url); } return array($url, $server); } //---------------------------------------------------------------------------- // Private functions. /** * Get a connection to the database. The resulting PDO object is statically * cached. * * @return * A database connection (through PDO), or FALSE in case of failure. */ function _cdn_advanced_get_db_connection() { static $db; $synced_files_db = variable_get(CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE, FALSE); if ($synced_files_db === FALSE || !file_exists($synced_files_db) || filesize($synced_files_db) == 0) { $db = FALSE; } elseif (!isset($db)) { try { $db = new PDO('sqlite:' . variable_get(CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE, '')); } catch (PDOException $e) { watchdog('cdn', t("Could not open synced files DB: %error.", array('%error' => $e))); $db = FALSE; } } return $db; }