$contents). // * @param array $aggregate_settings // * Array of settings. // * @param array $other_parameters // * Array of containing $files and $type. $file_types = array(); // Handle gzip. if (!empty($aggregate_settings['variables']['advagg_gzip'])) { // Use zopfli_encode if it exists. // See https://github.com/kjdev/php-ext-zopfli if (function_exists('zopfli_encode') && defined('ZOPFLI_GZIP') && empty($aggregate_settings['variables']['advagg_no_zopfli']) ) { $file_types['.gz'] = array('zopfli_encode', 15, constant('ZOPFLI_GZIP')); } else { $file_types['.gz'] = array('gzencode', 9, FORCE_GZIP); } } // Handle brotli. // See https://github.com/kjdev/php-ext-brotli if (!empty($aggregate_settings['variables']['advagg_brotli']) && defined('BROTLI_TEXT') && function_exists('brotli_compress') ) { $file_types['.br'] = array('brotli_compress', 11, constant('BROTLI_TEXT')); } if (empty($file_types)) { return; } // Special S3 handling. $s3fs = FALSE; $files_to_save_keys = array_keys($files_to_save); foreach ($files_to_save_keys as $uri) { $wrapper = file_stream_wrapper_get_instance_by_uri($uri); if ($wrapper && get_class($wrapper) === 'S3fsStreamWrapper') { $s3fs = TRUE; break; } } foreach ($file_types as $ext => $settings) { // See if a file already exists with this extension. $ext_exists = FALSE; foreach ($files_to_save as $uri => $contents) { // See if this uri contains $ext near the end of it. if (strlen($uri) > 91 + strlen(ADVAGG_SPACE) * 3) { $pos = strripos($uri, $ext, 91 + strlen(ADVAGG_SPACE) * 3); } else { $pos = strripos($uri, $ext); } if (!empty($pos)) { $len = strlen($uri); // $ext file exists, exit loop. if ($pos == $len - 3) { $ext_exists = TRUE; break; } } } // If a $ext file does not exist, create one. if (!$ext_exists) { // Use the first file in the array. $data = reset($files_to_save); $uri = key($files_to_save); // Compress it and add it to the $files_to_save array. $callback = $settings[0]; $settings[0] = $data; $compressed = call_user_func_array($callback, $settings); if (!empty($compressed)) { if ($s3fs && $ext === '.gz') { // Only serve gzip files from S3. $files_to_save[$uri] = $compressed; } elseif ($s3fs && $ext === '.br' && !isset($file_types['.gz'])) { // Only serve br files from S3. $files_to_save[$uri] = $compressed; } else { $files_to_save[$uri . $ext] = $compressed; } } } } } /** * Implements hook_advagg_build_aggregate_plans_alter(). * * Used to alter the plan so it has the same grouping as cores. */ function advagg_advagg_build_aggregate_plans_alter(array &$files, &$modified, $type) { // * @param array $files // * List of files in the aggregate as well as the aggregate name. // * @param bool $modified // * Change this to TRUE if $files has been changed. // * @param string $type // * String containing css or js. // // Do nothing if core grouping is disabled. if (!variable_get('advagg_core_groups', ADVAGG_CORE_GROUPS)) { return; } $temp_new_files = array(); $counter = 0; foreach ($files as $data) { $group = NULL; $every_page = NULL; foreach ($data['files'] as $fileinfo) { // Grouped by group and every_page variables. if (is_null($group)) { $group = $fileinfo['group']; } if (is_null($every_page)) { $every_page = $fileinfo['every_page']; } // Bump Counter if group/every_page has changed from the last one. if ($group != $fileinfo['group'] || $every_page != $fileinfo['every_page']) { ++$counter; $group = $fileinfo['group']; $every_page = $fileinfo['every_page']; $modified = TRUE; } $temp_new_files[$counter][] = $fileinfo; } ++$counter; } // Replace $files array with new aggregate filenames. $files = advagg_generate_filenames(array($temp_new_files), $type); } /** * Implements hook_advagg_context_alter(). */ function advagg_advagg_context_alter(&$original, $aggregate_settings, $mode) { if ($mode == 0) { // Change context. $original['base_root'] = $GLOBALS['base_root']; $original['base_url'] = $GLOBALS['base_url']; $original['base_path'] = $GLOBALS['base_path']; $original['is_https'] = $GLOBALS['is_https']; $original['language'] = isset($GLOBALS['language']) ? $GLOBALS['language'] : NULL; $GLOBALS['is_https'] = $aggregate_settings['variables']['is_https']; if ($aggregate_settings['variables']['is_https']) { $GLOBALS['base_root'] = str_replace('http://', 'https://', $GLOBALS['base_root']); } else { $GLOBALS['base_root'] = str_replace('https://', 'http://', $GLOBALS['base_root']); } $GLOBALS['base_path'] = $aggregate_settings['variables']['base_path']; $GLOBALS['base_url'] = rtrim($GLOBALS['base_root'] . $GLOBALS['base_path'], '/'); if (isset($aggregate_settings['variables']['language'])) { $languages = language_list(); if (isset($languages[$aggregate_settings['variables']['language']])) { $GLOBALS['language'] = $languages[$aggregate_settings['variables']['language']]; } } } elseif ($mode == 1) { // Change context back. if (isset($original['base_root'])) { $GLOBALS['base_root'] = $original['base_root']; } if (isset($original['base_url'])) { $GLOBALS['base_url'] = $original['base_url']; } if (isset($original['base_path'])) { $GLOBALS['base_path'] = $original['base_path']; } if (isset($original['is_https'])) { $GLOBALS['is_https'] = $original['is_https']; } if (isset($original['language'])) { $GLOBALS['language'] = $original['language']; } } // Moved this in here due to incomplete bug reports from // https://www.drupal.org/node/1942230. I can not reproduce the reported // issues with the patch for the CDN module so I've moved the code into // advagg. if (!function_exists('cdn_advagg_context_alter') && module_exists('cdn')) { if ($mode == 0) { // Save original context. $original[CDN_MODE_VARIABLE] = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC); $original[CDN_BASIC_FARFUTURE_VARIABLE] = variable_get(CDN_BASIC_FARFUTURE_VARIABLE, CDN_BASIC_FARFUTURE_DEFAULT); $original[CDN_HTTPS_SUPPORT_VARIABLE] = variable_get(CDN_HTTPS_SUPPORT_VARIABLE, FALSE); $original[CDN_STATUS_VARIABLE] = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED); // Set context for file_create_url()/cdn_file_url_alter(). $GLOBALS['conf'][CDN_MODE_VARIABLE] = isset($aggregate_settings['variables'][CDN_MODE_VARIABLE]) ? $aggregate_settings['variables'][CDN_MODE_VARIABLE] : variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC); $GLOBALS['conf'][CDN_BASIC_FARFUTURE_VARIABLE] = isset($aggregate_settings['variables'][CDN_BASIC_FARFUTURE_VARIABLE]) ? $aggregate_settings['variables'][CDN_BASIC_FARFUTURE_VARIABLE] : variable_get(CDN_BASIC_FARFUTURE_VARIABLE, CDN_BASIC_FARFUTURE_DEFAULT); $GLOBALS['conf'][CDN_HTTPS_SUPPORT_VARIABLE] = isset($aggregate_settings['variables'][CDN_HTTPS_SUPPORT_VARIABLE]) ? $aggregate_settings['variables'][CDN_HTTPS_SUPPORT_VARIABLE] : variable_get(CDN_HTTPS_SUPPORT_VARIABLE, FALSE); $GLOBALS['conf'][CDN_STATUS_VARIABLE] = isset($aggregate_settings['variables'][CDN_STATUS_VARIABLE]) ? $aggregate_settings['variables'][CDN_STATUS_VARIABLE] : variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED); // Disable CDN if cdn_check_drupal_path is FALSE. if (empty($aggregate_settings['variables']['cdn_check_drupal_path'])) { $original[CDN_STATUS_VARIABLE] = CDN_DISABLED; } // Handle HTTPS. if (!empty($aggregate_settings['variables']['cdn_request_is_https']) && !cdn_request_is_https()) { if (isset($_SERVER['HTTPS'])) { $original['HTTPS'] = $_SERVER['HTTPS']; } else { $original['HTTPS'] = FALSE; } $_SERVER['HTTPS'] = 'on'; } } elseif ($mode == 1) { // Set context back. $GLOBALS['conf'][CDN_MODE_VARIABLE] = $original[CDN_MODE_VARIABLE]; $GLOBALS['conf'][CDN_BASIC_FARFUTURE_VARIABLE] = $original[CDN_BASIC_FARFUTURE_VARIABLE]; $GLOBALS['conf'][CDN_HTTPS_SUPPORT_VARIABLE] = $original[CDN_HTTPS_SUPPORT_VARIABLE]; $GLOBALS['conf'][CDN_STATUS_VARIABLE] = $original[CDN_STATUS_VARIABLE]; // Handle HTTPS. if (isset($original['HTTPS']) && !is_null($original['HTTPS'])) { $_SERVER['HTTPS'] = $original['HTTPS']; } } } } /** * Implements hook_advagg_get_info_on_files_alter(). * * Used to make sure the info is up to date in the cache. */ function advagg_advagg_get_info_on_files_alter(&$return, $cached_data, $bypass_cache) { // Check for the ie_css_selector_limiter. if (variable_get('advagg_ie_css_selector_limiter', ADVAGG_IE_CSS_SELECTOR_LIMITER)) { $limit_value = variable_get('advagg_ie_css_selector_limiter_value', ADVAGG_IE_CSS_SELECTOR_LIMITER_VALUE); // Get the css path. list($css_path) = advagg_get_root_files_dir(); $css_parts_path = (advagg_s3fs_evaluate_no_rewrite_cssjs(FALSE)) ? $css_path[0] : $css_path[1]; $parts_path = $css_parts_path . '/parts/'; foreach ($return as &$info) { // Skip if not a css file. if (empty($info['fileext']) || $info['fileext'] !== 'css') { continue; } // Check if this is a split css file. if (strpos($info['data'], $parts_path) !== FALSE) { $info['split'] = TRUE; } // Break large file into multiple small files if needed. elseif ($info['linecount'] > $limit_value) { advagg_split_css_file($info); } } unset($info); } // Capture resource_hints. if (variable_get('advagg_resource_hints_dns_prefetch', ADVAGG_RESOURCE_HINTS_DNS_PREFETCH) || variable_get('advagg_resource_hints_preconnect', ADVAGG_RESOURCE_HINTS_PRECONNECT) || variable_get('advagg_resource_hints_preload', ADVAGG_RESOURCE_HINTS_PRELOAD) ) { $aggregate_settings = advagg_current_hooks_hash_array(); foreach ($return as &$info) { // Skip if not a css file. if (empty($info['fileext']) || $info['fileext'] !== 'css') { continue; } // Get the file contents. $file_contents = (string) @advagg_file_get_contents($info['data']); $file_contents = advagg_load_css_stylesheet($info['data'], FALSE, $aggregate_settings, $file_contents); // Get domain names and external assets in this css file. $hosts = array(); $urls = array(); $matches = array(); $pattern = '%url\(\s*+[\'"]?+(http:\/\/|https:\/\/|\/\/)([^\'"()\s]++)[\'"]?+\s*+\)%i'; preg_match_all($pattern, $file_contents, $matches); if (!empty($matches[1])) { foreach ($matches[1] as $key => $match) { $url = $match . $matches[2][$key]; $parse = @parse_url($url); if (!empty($parse['host'])) { $extra = ''; $ext = strtolower(pathinfo($url, PATHINFO_EXTENSION)); $supported = array( 'eot', 'woff2', 'woff', 'ttf', 'otf', ); if (in_array($ext, $supported)) { $extra .= '#crossorigin'; } $hosts[$parse['host'] . $extra] = $match . $parse['host'] . '/' . $extra; $urls[$url] = $url; } } } if (!empty($hosts) && (variable_get('advagg_resource_hints_dns_prefetch', ADVAGG_RESOURCE_HINTS_DNS_PREFETCH) || variable_get('advagg_resource_hints_preconnect', ADVAGG_RESOURCE_HINTS_PRECONNECT) )) { $info['dns_prefetch'] = array_values($hosts); } // Get local files to preload in this css file. if (variable_get('advagg_resource_hints_preload', ADVAGG_RESOURCE_HINTS_PRELOAD)) { $matches = array(); $pattern = '/url\(\s*+[\'"]?(.*?)[\'"\s]?+\)/i'; preg_match_all($pattern, $file_contents, $matches); if (!empty($matches[1])) { foreach ($matches[1] as $key => $match) { $url = advagg_convert_abs_to_rel($match); $parse = @parse_url($url); if (empty($parse['host'])) { $urls[$url] = $url; } } } if (!empty($urls)) { $info['preload'] = array_values($urls); } } } unset($info); } } /** * Implements hook_advagg_changed_files(). * * If the color module is enabled regenerate color module css when it changes. * If a responsive file inside an adaptive theme has changed, regenerate it. */ function advagg_advagg_changed_files(array $files, array $types) { // * @param array $files // * List of files that have changed. // * @param array $types // * Array with the css and or the js key. if (module_exists('locale')) { _advagg_locale_changed_files($files, $types); } // Keep track of what themes have been done. static $themes_done; if (!isset($themes_done)) { $themes_done = array(); } // Skip if no css changed. if (empty($types['css'])) { return; } foreach ($files as $filename => $meta_data) { // Only care about css files. $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if ($ext !== 'css') { continue; } advagg_advagg_scan_for_changes($filename, TRUE); } // Save error states and clear them. $errors_before = drupal_static('form_set_error', array()); form_clear_error(); // See if the css file is used the theme. $themes = list_themes(); $changed_files = array_keys($files); $submit_ran = FALSE; foreach ($themes as $theme_name => $theme_values) { $files_in_theme = array(); foreach ($changed_files as $css_file) { // Skip if we already did a form submit for this theme. if (!empty($themes_done[$theme_name])) { continue; } // Skip if the file that was changed is not in this themes directory. $theme_path = drupal_get_path('theme', $theme_name); if ((!empty($theme_path)) && strpos($css_file, $theme_path) !== 0) { continue; } $files_in_theme[] = $css_file; } // Skip the theme if none of the changed files live in here. if (empty($files_in_theme)) { continue; } // Get the form for this theme. $router_item = menu_get_item('admin/appearance/settings/' . $theme_name); if ($router_item['include_file']) { require_once DRUPAL_ROOT . '/' . $router_item['include_file']; } $form = drupal_get_form('system_theme_settings', $theme_name); // Get the form defaults. $defaults = array(); advagg_get_defaults_from_form($defaults, $form); $rebuild = FALSE; if (isset($defaults['atcore_version_test'])) { // Rebuild if the theme is an adaptive theme. $rebuild = TRUE; } if (!$rebuild && module_exists('color')) { foreach ($files_in_theme as $css_file) { if (isset($form['color'])) { // Rebuild if the file that was changed is a color module file. foreach ($defaults['info']['css'] as $theme_file) { if ($theme_path . '/' . $theme_file === $css_file) { $rebuild = TRUE; break 2; } } } } } // Skip if themes css does not need to be generated dynamically. if (empty($rebuild)) { continue; } // Build the palette value. $palette = array(); if (isset($form['color'])) { foreach (element_children($form['color']['palette']) as $key) { $palette[$key] = $form['color']['palette'][$key]['#value']; } } // Build the form state array. $form_state = array( 'values' => array('palette' => $palette), 'build_info' => array('args' => array(0 => $theme_name)), ); $form_state['values'] += $defaults; if (isset($defaults['atcore_version_test'])) { // Validate form. at_core_settings_validate($form, $form_state); $errors = form_set_error(); if (empty($errors)) { // Only submit if no errors. at_core_settings_submit($form, $form_state); $themes_done[$theme_name] = TRUE; $submit_ran = TRUE; } } elseif (isset($form['color'])) { // Validate form. color_scheme_form_validate($form, $form_state); $errors = form_set_error(); if (empty($errors)) { // Only submit if no errors. color_scheme_form_submit($form, $form_state); $themes_done[$theme_name] = TRUE; $submit_ran = TRUE; } } // Reset form errors. form_clear_error(); } // Save error states back. $form_set_error = &drupal_static('form_set_error', array()); $form_set_error = $errors_before; // Rescan again as the submit will generate new files in the css dir. if ($submit_ran) { advagg_push_new_changes(); } } /** * Implements hook_advagg_scan_for_changes(). * * Used to see if the responsive files inside an adaptive theme has changed. */ function advagg_advagg_scan_for_changes($filename, $save_changes = FALSE) { // Skip if this file is not a css file. $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if ($ext !== 'css') { return FALSE; } // Skip if the file is not in an adaptive theme. $adaptivethemes = array(); $themes = list_themes(); foreach ($themes as $theme_name => $theme_values) { $path = variable_get('theme_' . $theme_name . '_files_directory', ''); if (!empty($path) && strpos($filename, $path) !== FALSE) { $adaptivethemes[$theme_name] = $path; } } if (empty($adaptivethemes)) { return; } $file_changed = array(); foreach ($adaptivethemes as $theme_name => $path) { // Set up some paths we use to get and save files. $path_to_responsive_css = drupal_get_path('theme', $theme_name) . '/css/'; $path_to_panels_css = drupal_get_path('theme', 'adaptivetheme') . '/layouts/css/'; // Map files to generated file names. $file_map = array( "$path/$theme_name.responsive.styles.css" => array( $path_to_responsive_css . 'responsive.custom.css', $path_to_responsive_css . 'responsive.smalltouch.portrait.css', $path_to_responsive_css . 'responsive.smartphone.portrait.css', $path_to_responsive_css . 'responsive.smalltouch.landscape.css', $path_to_responsive_css . 'responsive.smartphone.landscape.css', $path_to_responsive_css . 'responsive.tablet.portrait.css', $path_to_responsive_css . 'responsive.tablet.landscape.css', $path_to_responsive_css . 'responsive.desktop.css', ), "$path/$theme_name.lt-ie8.layout.css" => array( $path_to_panels_css . 'ie_defaults.css', ), ); if (!isset($file_map[$filename])) { continue; } // See if anything has changed. $changes = advagg_detect_subfile_changes($filename, $file_map[$filename], 'adaptivetheme', $save_changes); if (!empty($changes)) { $file_changed[$path] = $changes; } } return $file_changed; } /** * @} End of "addtogroup advagg_hooks". */ /** * If the locale module is enabled regenerate locale translations. * * @param array $files * List of files that have changed. * @param array $types * Array with the css and or the js key. */ function _advagg_locale_changed_files(array $files, array $types) { // Skip if no js changed. if (empty($types['js'])) { return; } $javascript = array(); foreach ($files as $filename => $meta_data) { // Only care about js files. $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if ($ext !== 'js') { continue; } $javascript[] = array( 'type' => 'file', 'data' => $filename, ); } if (!empty($javascript)) { $javascript_before = $javascript; $language_before = $GLOBALS['language']; $language_list = language_list(); foreach ($language_list as $lang) { if ($lang->enabled) { $GLOBALS['language'] = $lang; $javascript = $javascript_before; _advagg_locale_js_alter($javascript); } } $GLOBALS['language'] = $language_before; } } /** * Given a form get the default values from it. * * @param array $defaults * An empty array used to populate the default values. * @param array $form * The form returned from drupal_get_form(). * @param string $parent_key * The key name of the parent. */ function advagg_get_defaults_from_form(array &$defaults, array $form, $parent_key = '') { foreach (element_children($form) as $key) { $values = $form[$key]; if (isset($values['#value'])) { // Grab defaults at this level. if (!isset($defaults[$key])) { $defaults[$key] = $values['#value']; } else { $defaults[$parent_key . '-' . $key] = $values['#value']; } } elseif (isset($values['#default_value'])) { // Grab defaults at this level. if (!isset($defaults[$key])) { $defaults[$key] = $values['#default_value']; } else { $defaults[$parent_key . '-' . $key] = $values['#default_value']; } } elseif (is_array($values)) { // Go deeper if needed. advagg_get_defaults_from_form($defaults, $values, $key); } } }