'admin/settings/cdn', 'title' => t('CDN integration'), 'callback' => 'drupal_get_form', 'callback arguments' => array('cdn_admin_settings_form'), 'access' => user_access('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); } return $items; } /** * Implementation of hook_requirements(). */ function cdn_requirements($phase) { $requirements = array(); $t = get_t(); switch ($phase) { case 'install' : case 'runtime' : $path = drupal_get_path('module', 'cdn') .'/cdn_cron.php'; $cdn_cron_last = variable_get('cdn_cron_last', NULL); $cdn_cron_method = variable_get('cdn_cron_method', 'cdn'); $requirements['cdn_cron']['title'] = $t('CDN synchronization'); if ($cdn_cron_method == 'cdn' && !file_exists('cdn_cron.php') || (file_exists($path) && file_exists('cdn_cron.php') && md5_file($path) != md5_file('cdn_cron.php'))) { $requirements['cdn_cron'] += array( 'description' => $t( "In order for the CDN integration module to work correctly, it has to be able to synchronize. This can be done automatically through cron, but you will have to copy the file %file to the same directory as Drupal's cron.php.", array('%file' => $path) ), 'severity' => $phase == 'install' ? REQUIREMENT_WARNING : REQUIREMENT_ERROR, 'value' => $t('Copy cdn_cron.php'), ); } elseif ($cdn_cron_method == 'cdn' && !file_exists($path)) { $requirements['cdn_cron'] += array( 'description' => $t( "You probably moved rather than copied the cdn_cron.php file from %file to the same directory as Drupal's cron.php. You should leave a copy of this file in the CDN integration module directory so that you will not lose this file when you upgrade to another revision of Drupal.", array('%file' => $path) ), 'severity' => $phase == 'install' ? REQUIREMENT_WARNING : REQUIREMENT_ERROR, 'value' => $t('Copy cdn_corn.php back'), ); } elseif (is_numeric($cdn_cron_last)) { $requirements['cdn_cron']['value'] = $t('Last run !time ago', array('!time' => format_interval(time() - $cdn_cron_last))); $requirements['cdn_cron']['description'] = variable_get('cdn_cron_last_stats', ''. $t('No statistics available.') .''); } else { $requirements['cdn_cron'] += array( 'description' => $t( 'CDN synchronization cron job has not run -- it appears it has not been setup on your system. Please check the help pages for configuring cron jobs.', array('@url' => 'http://drupal.org/cron') ), 'severity' => REQUIREMENT_ERROR, 'value' => $t('Never run'), ); } } return $requirements; } /** * Implementation of hook_exit(). */ function cdn_exit($destination = NULL) { if (!$destination && user_access('administer site configuration') && variable_get('cdn_dev_page_stats', 0)) { list( $file_count, $remote_file_count, $local_files, $remote_files, $synced_files, $unsynced_files, ) = _cdn_devel_page_stats(); print theme('cdn_page_stats', $file_count, $remote_file_count, $local_files, $remote_files, $synced_files, $unsynced_files ); } } /** * Implementation of hook_cron(). */ function cdn_cron() { if (variable_get('cdn_cron_method', 'cdn') == 'core') { $cdn_dir = drupal_get_path('module', 'cdn'); require_once "$cdn_dir/cdn.inc"; require_once "$cdn_dir/cdn_cron.inc"; cdn_cron_run(); } } //---------------------------------------------------------------------------- // Form API callbacks. /** * Form definition: CDN admin settings form. */ function cdn_admin_settings_form() { $form['settings'] = array( '#type' => 'fieldset', '#title' => t('Settings'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['settings']['cdn_cron_method'] = array( '#type' => 'radios', '#title' => t('Cron method'), '#description' => t( "Since CDN synchronization typically takes a lot of time (relatively), you may want to run it as a separate cron, so it doesn't slow down the 'normal' cron of Drupal core." ), '#options' => array( 'core' => t("Drupal core's cron"), 'cdn' => t("CDN integration's cron"), ), '#default_value' => variable_get('cdn_cron_method', 'cdn'), ); $form['dev'] = array( '#type' => 'fieldset', '#title' => t('Development'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['dev']['cdn_dev_page_stats'] = array( '#type' => 'radios', '#title' => t('Show statistics for the current page'), '#description' => t( 'Shows the CDN integration statistics of the current page, to users with adminster site configuration permissions.' ), '#options' => array( '0' => t('Disabled'), '1' => t('Enabled'), ), '#default_value' => variable_get('cdn_dev_page_stats', 0), ); $form['stats'] = array( '#type' => 'fieldset', '#title' => t('Site-wide statistics'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $cdn_cron_last = variable_get('cdn_cron_last', NULL); $form['stats']['last_run'] = array( '#type' => 'fieldset', '#title' => t('Last run'), '#description' => t('Results from the last CDN synchronization'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); if (isset($cdn_cron_last)) { $form['stats']['last_run']['#value'] = '

'. t('Last run was !time ago.', array('!time' => format_interval(time() - $cdn_cron_last))) .'

'. variable_get('cdn_cron_last_stats', '

'. t('No statistics available.') .'

'); } else { $form['stats']['last_run']['#value'] = '

'. t('No CDN synchronization run has been performed yet. Please check the !status-report to find out what you have to do.', array('!status-report' => l('Status report', 'admin/logs/status'))) .'

'; } require_once 'cdn_cron.inc'; list($files_scheduled, $files_unique_settings, $files_update_settings) = _cdn_cron_get_files_to_sync(variable_get('cdn_sync_filters', array())); unset($files_unique_settings, $files_update_settings); $files_scheduled_size = 0; foreach ($files_scheduled as $file => $size) { $files_scheduled_size += $size; } $files_synced = variable_get('cdn_files_synced', array()); $files_scheduled_unsynced = array_diff(array_keys($files_scheduled), array_keys($files_synced)); $files_unscheduled_synced = array_diff(array_keys($files_synced), array_keys($files_scheduled)); $coverage = (count($files_scheduled) == 0) ? 1 : (count($files_scheduled) - count($files_scheduled_unsynced)) / count($files_scheduled); $form['stats']['numbers'] = array( '#value' => theme('cdn_numbers', $files_scheduled, $files_scheduled_size, $files_synced, $coverage), ); $form['stats']['list_scheduled_unsynced'] = array( '#type' => 'fieldset', '#title' => t('Files that are scheduled but not yet synchronized'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['stats']['list_scheduled_unsynced']['table'] = array( '#value' => theme('cdn_scheduled_unsynced_files_list', $files_scheduled_unsynced), ); $form['stats']['list_unscheduled_synced'] = array( '#type' => 'fieldset', '#title' => t('Files that are queued for deletion'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['stats']['list_unscheduled_synced']['table'] = array( '#value' => theme('cdn_unscheduled_synced_files_list', $files_unscheduled_synced, $files_synced), ); $form['stats']['list_synced'] = array( '#type' => 'fieldset', '#title' => t('Synchronized files'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['stats']['list_synced']['table'] = array( '#value' => theme('cdn_synced_files_list', $files_synced), ); return system_settings_form($form); } //---------------------------------------------------------------------------- // Private functions. /** * Collects per-page CDN integration statistics. * * @param $file * The local file path. * @param $remote_file * The remote file path. * @param $remote_file_exists * TRUE if the remote file exists, FALSE otherwise. * @return * Only if no parameters were passed: the collected statistics. */ function _cdn_devel_page_stats($file = FALSE, $remote_file = '', $remote_file_exists = FALSE) { static $file_count, $remote_file_count, $all_requests, $local_files, $remote_files, $synced_files, $unsynced_files; if (!isset($all_requests)) { $file_count = 0; $remote_file_count = 0; $all_requests = array(); $local_files = array(); $remote_files = array(); $synced_files = array(); $unsynced_files = array(); } // If the function is called with parameters set, save the statistics. If no // parameters are passed, return the collected statistics. if ($file && !isset($all_requests[$file])) { $all_requests[$file] = TRUE; $file_count++; $local_files[] = $file; $remote_files[$file] = $remote_file; if ($remote_file_exists) { $remote_file_count++; $synced_files[] = $file; } else { $unsynced_files[] = $file; } } elseif (!$file) { return array( $file_count, $remote_file_count, $local_files, $remote_files, $synced_files, $unsynced_files, ); } } //---------------------------------------------------------------------------- // Themeing functions. /** * @ingroup themeable * @{ */ /** * Renders site-wide CDN integration statistics. * * @param $files_scheduled * Array of files that are scheduled for synchronization. * @param $files_scheduled_size * Total size of files that are scheduled for synchronization, in bytes. * @param $files_synced * Array of files that are already synchronized to the CDN. * @param $coverage * Floating point number, indicating the percentage of synchronized * scheduled files * @return * The rendered HTML. */ function theme_cdn_numbers($files_scheduled, $files_scheduled_size, $files_synced, $coverage) { $output = ''; $header = array( array('data' => t('Scheduled files')), array('data' => t('Size of scheduled files')), array('data' => t('Synchronized files')), array('data' => t('Coverage')) ); $rows[0] = array( 'data' => array( count($files_scheduled), number_format($files_scheduled_size / 1024) .' KB', count($files_synced), number_format($coverage * 100, 2) .'%' ), ); $output .= theme('table', $header, $rows); return $output; } /** * Render the list of scheduled but not yet synchronized files. * * @param $files_scheduled_unsynced * Array of local files. * @return * The rendered HTML. */ function theme_cdn_scheduled_unsynced_files_list($files_scheduled_unsynced) { $output = ''; if (!count($files_scheduled_unsynced)) { $output .= '

'. t('All files are synchronized!') .'

'; } else { $header = array( array('data' => t('Local file')), array('data' => t('Size')), ); $rows = array(); foreach ($files_scheduled_unsynced as $file) { $rows[] = array('data' => array($file, number_format(filesize($file) / 1024, 2) .' KB')); } $output .= theme('table', $header, $rows); } return $output; } /** * Render the list of files that are queued for deletion. * * @param $files_unscheduled_synced * Array of local files. * @param $files_synced * Array of files that are already synchronized to the CDN. * @return * The rendered HTML. */ function theme_cdn_unscheduled_synced_files_list($files_unscheduled_synced, $files_synced) { $output = ''; if (!count($files_unscheduled_synced)) { $output .= '

'. t('No files are queued for deletion.') .'

'; } else { $header = array(array('data' => t('Local file (links to the remote file)'))); $rows = array(); foreach ($files_unscheduled_synced as $file) { $rows[] = array('data' => array(l($file, $files_synced[$file]))); } $output .= theme('table', $header, $rows); } return $output; } /** * Render the list of synchronized files. * * @param $files_synced * Array of files that are already synchronized to the CDN. * @return * The rendered HTML. */ function theme_cdn_synced_files_list($files_synced) { $output = ''; if (!count($files_synced)) { $output .= '

'. t('No files synchronized yet.') .'

'; } else { $header = array( array('data' => t('Local file (links to the remote file)')), array('data' => t('Size')), ); $rows = array(); foreach ($files_synced as $local_file => $remote_file) { $rows[] = array('data' => array(l($local_file, $remote_file), number_format(filesize($local_file) / 1024, 2) .' KB')); } $output .= theme('table', $header, $rows); } return $output; } /** * Render the CDN integration page statistics. * * @param $file_count * The number of files detected on this page. * @param $remote_file_count * The number of files on this page that are served from the CDN. * @param $local_files * Array of local files. * @param $remote_files * Array of remote files (i.e. on the CDN), keys are local files. * @param $synced_files * Array of synchronized files. * @param $unsynced_files * Array of unsynchronized files. * @return * The rendered HTML. */ function theme_cdn_page_stats($file_count, $remote_file_count, $local_files, $remote_files, $synced_files, $unsynced_files) { $output = ''; $items = array(); $output .= '
'; $items[] = 'Total number of files on this page: '. $file_count .''; $percentage = ($file_count == 0) ? '100' : number_format($remote_file_count / $file_count * 100); $items[] = 'Number of files available on the CDN: '. $remote_file_count .' ('. $percentage . '% coverage)'; // Nested list of unsynced files. if (count($unsynced_files)) { $unsynced_items = array(); foreach ($unsynced_files as $file) { $unsynced_items[] = array(l($file, $file)); } $items[] = 'The files that are not (yet?) synchronized to the CDN:' . theme('item_list', $unsynced_items, NULL, 'ol'); } // Nested list of synced files. if (count($synced_files)) { $synced_items = array(); foreach ($synced_files as $file) { $synced_items[] = array(l($file, $remote_files[$file])); } $items[] = 'The files that are synchronized to the CDN:' . theme('item_list', $synced_items, NULL, 'ol'); } $output .= theme('item_list', $items, ''. t('CDN integration statistics') .''); $output .= '
'; return $output; } /** * @} End of "ingroup themeable". */