security update core+modules

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-26 18:38:56 +02:00
parent 2f45ea820a
commit 7c96373038
1022 changed files with 30319 additions and 11259 deletions

View File

@@ -0,0 +1,137 @@
<?php
/**
* @file
* Contains the administration pages for LESS.
*/
/**
* Form for LESS module settings.
*/
function less_settings_form($form, &$form_state) {
$form['less_flush'] = array(
'#type' => 'fieldset',
'#collapsible' => FALSE,
'#value' => t('Click this button to flag all LESS files for regeneration.'),
);
$form['less_flush']['flush'] = array(
'#type' => 'submit',
'#submit' => array('_flush_less'),
'#value' => t('Flush LESS files'),
);
$registered_engines = _less_get_engines();
$less_engines = array();
foreach ($registered_engines as $library => $engine) {
$less_engines[] = libraries_detect($library);
}
$less_engine_element = array(
'#type' => 'radios',
'#title' => t('LESS engine'),
'#options' => array(),
'#required' => TRUE,
'#default_value' => variable_get('less_engine', 'lessphp'),
);
foreach ($less_engines as $less_engine) {
$less_engine_element['#options'][$less_engine['machine name']] = $less_engine['name'];
$less_engine_element[$less_engine['machine name']] = array(
'#type' => 'radio',
'#title' => t('@engine_name - <a href="@vendor_url">@vendor_url</a>', array('@engine_name' => $less_engine['name'], '@vendor_url' => $less_engine['vendor url'])),
'#return_value' => $less_engine['machine name'],
'#description' => t('Missing - Click vendor link above to read installation instructions.'),
'#disabled' => empty($less_engine['installed']),
);
if ($less_engine['installed']) {
$less_engine_element[$less_engine['machine name']]['#description'] = t('v%version Installed', array('%version' => $less_engine['version']));
}
}
$form['less_engine'] = $less_engine_element;
$lessautoprefixer_library = libraries_detect('lessautoprefixer');
$form[LESS_AUTOPREFIXER] = array(
'#type' => 'checkbox',
'#title' => t('Use @name - <a href="@vendor_url">@vendor_url</a>', array('@name' => $lessautoprefixer_library['name'], '@vendor_url' => $lessautoprefixer_library['vendor url'])),
'#description' => t('Enable automatic prefixing of vendor CSS extensions.'),
'#default_value' => variable_get(LESS_AUTOPREFIXER, FALSE),
'#disabled' => empty($lessautoprefixer_library['installed']),
);
if ($lessautoprefixer_library['installed']) {
$form[LESS_AUTOPREFIXER]['#description'] .= '<br />'. t('v%version Installed', array('%version' => $lessautoprefixer_library['version']));
}
$form['developer_options'] = array(
'#type' => 'fieldset',
'#title' => t('Developer Options'),
'#collapsible' => TRUE,
'#collapsed' => !(variable_get(LESS_DEVEL, FALSE)),
);
$form['developer_options'][LESS_DEVEL] = array(
'#type' => 'checkbox',
'#title' => t('Developer Mode'),
'#description' => t('Enable developer mode to ensure LESS files are regenerated every page load.'),
'#default_value' => variable_get(LESS_DEVEL, FALSE),
);
$form['developer_options'][LESS_SOURCE_MAPS] = array(
'#type' => 'checkbox',
'#title' => t('Source Maps'),
'#description' => t('Enable source maps output while "Developer Mode" is enabled.'),
'#default_value' => variable_get(LESS_SOURCE_MAPS, FALSE),
'#states' => array(
'enabled' => array(
':input[name="' . LESS_DEVEL . '"]' => array('checked' => TRUE),
),
),
);
$form['developer_options'][LESS_WATCH] = array(
'#type' => 'checkbox',
'#title' => t('Watch Mode'),
'#description' => t('Enable watch mode while developer mode is active to automatically reload styles when changes are detected, including changes to @import-ed files. Does not cause a page reload.'),
'#default_value' => variable_get(LESS_WATCH, FALSE),
'#states' => array(
'enabled' => array(
':input[name="' . LESS_DEVEL . '"]' => array('checked' => TRUE),
),
),
);
$form['#submit'] = array('less_settings_form_submit');
return system_settings_form($form);
}
/**
* Form submission function.
*
* Trigger clear of LESS module cache data.
*/
function less_settings_form_submit($form, &$form_state) {
cache_clear_all('less:', 'cache', TRUE);
}
/**
* Submit handler for cache clear button.
*/
function _flush_less($form, &$form_state) {
less_flush_caches();
drupal_set_message(t('LESS files cache cleared.'), 'status');
}

View File

@@ -0,0 +1,209 @@
<?php
/**
* @file
* Contains Libraries API integration.
*/
/**
* Implements hook_libraries_info().
*/
function less_libraries_info() {
$libraries = array();
/**
* Legacy leafo/lessphp library.
*/
$libraries['lessphp'] = array(
'name' => 'lessphp (Not recommended)',
'vendor url' => 'http://leafo.net/lessphp/',
'download url' => 'http://leafo.net/lessphp/',
'version arguments' => array(
'file' => 'lessc.inc.php',
'pattern' => '/VERSION\s*=\s*["\']v?([\d\.]+)/',
'lines' => 50,
),
'files' => array(
'php' => array(
'lessc.inc.php',
),
),
);
_less_lessphp_locate($libraries['lessphp']);
/**
* Newer oyejorge/less.php library. Closer to canonical spec from lesscss.org.
*/
$libraries['less.php'] = array(
'name' => 'less.php',
'vendor url' => 'http://lessphp.gpeasy.com/',
'download url' => 'http://lessphp.gpeasy.com/#integration-with-other-projects',
'version arguments' => array(
'file' => 'Version.php',
'pattern' => '/version\s*=\s*["\']([\d\.]+)/',
'lines' => 20,
),
'files' => array(
'php' => array(
'Less.php',
),
),
'versions' => array(
'1.7.0' => array(),
),
);
_less_less_php_locate($libraries['less.php']);
/**
* Canonical version of LESS language.
*/
$libraries['less.js'] = array(
'name' => 'less.js',
'vendor url' => 'http://lesscss.org/',
'download url' => 'http://lesscss.org/usage/#using-less-environments',
'library path' => drupal_get_path('module', 'less') . '/classes',
'version callback' => array('Lessjs', 'version'),
/**
* Integer indexed 'version arguments' array causes 'version callback' to be
* run through call_user_func_array().
*
* @see call_user_func_array()
*/
'version arguments' => array(
0 => 'not used',
),
'files' => array(
'php' => array(
'class.lessjs.inc',
),
),
'versions' => array(
'1.5.0' => array(),
),
);
/**
* Autoprefixer
*/
$libraries['lessautoprefixer'] = array(
'name' => 'Autoprefixer',
'vendor url' => 'https://github.com/ai/autoprefixer',
'download url' => 'https://github.com/ai/autoprefixer/releases',
'library path' => drupal_get_path('module', 'less') . '/classes',
'version callback' => array('LessAutoprefixer', 'version'),
/**
* Integer indexed 'version arguments' array causes 'version callback' to be
* run through call_user_func_array().
*
* @see call_user_func_array()
*/
'version arguments' => array(
0 => 'not used',
),
'files' => array(
'php' => array(
'class.lessautoprefixer.inc',
),
),
'versions' => array(
'1.1' => array(),
),
);
return $libraries;
}
/**
* Locates oyejorge/less.php in the many possible places it could be.
*
* @param array $library
* Libraries definition array.
*/
function _less_less_php_locate(&$library) {
$locations = array();
// Primary libraries location
$locations[] = libraries_get_path('less.php');
// lessphp drop-in replacement location
$locations[] = libraries_get_path('lessphp');
// Composer location
$locations[] = drupal_get_path('module', 'less') . '/vendor/oyejorge/less.php';
$version_files = array(
'lib/Less/Version.php' => 'lessc.inc.php', // Source code
'Version.php' => 'Less.php', // Compiled
);
_less_libraries_determine_location($library, $locations, $version_files);
}
/**
* Locates leafo/lessphp in the many possible places it could be.
*
* @param array $library
* Libraries definition array.
*/
function _less_lessphp_locate(&$library) {
$locations = array();
// Primary libraries location
$locations[] = libraries_get_path('lessphp');
// Legacy bundled location
$locations[] = drupal_get_path('module', 'less') . '/lessphp';
// Composer location
$locations[] = drupal_get_path('module', 'less') . '/vendor/leafo/lessphp';
/*
* oyejorge/less.php does not have the actual version number in lessc.inc.php,
* so we don't have to worry about mistaken identity.
*/
$version_files = array(
'lessc.inc.php' => 'lessc.inc.php',
);
_less_libraries_determine_location($library, $locations, $version_files);
}
/**
* Helper function that checks locations for LESS libraries.
*
* @param array &$library
* Library in question. Paths to found libraries will be added here.
* @param array $locations
* Array of paths of potential library installs relative to DRUPAL_ROOT.
* @param array $version_files
* Array of key => value pairs, where key is location library version number,
* and value is the location of that file that to be included when this
* library is loaded with libraries_load().
*/
function _less_libraries_determine_location(array &$library, array $locations, array $version_files) {
foreach (array_filter($locations) as $location) {
foreach ($version_files as $version_file => $class_file) {
if (file_exists($location . DIRECTORY_SEPARATOR . $version_file)) {
$library['library path'] = $location;
$library['files'] = array(
'php' => array(
$class_file,
),
);
$library['version arguments']['file'] = $version_file;
return; // File has been found, skip remaining $locations and $version_files
}
}
}
}

View File

@@ -0,0 +1,281 @@
<?php
/**
* @file
* Contains functions related to compiling .less files.
*/
/**
* Attach LESS settings to each file as appropriate.
*
* @param array[] $item
* @param string $key
*/
function _less_attach_settings(&$item, $key) {
$defaults = array(
'less' => less_get_settings(), // Bare defaults for LESS.
);
// These items must be reset for consistent operation.
$nullify = array(
'less' => array(
'output_file' => NULL,
'build_required' => NULL,
),
);
// Merge in any info from $item.
$item = array_replace_recursive($defaults, $item, $nullify);
$item['less']['input_file'] = $item['data'];
$less_settings = less_get_settings(_less_file_owner($item['less']['input_file']));
// array_replace_recursive() works on keys, flip to not use numeric keys.
$less_settings['paths'] = array_flip($less_settings['paths']);
$item['less']['paths'] = array_flip($item['less']['paths']);
// Merge defaults with any per file settings.
$item['less'] = array_replace_recursive($less_settings, $item['less']);
// First array_flips before merge removed duplicates, so just flip back.
$item['less']['paths'] = array_flip($item['less']['paths']);
}
/**
* Determine output filename and add it to the settings array.
*
* @param array[] $item
* @param string $key
*/
function _less_output_path(&$item, $key) {
$input_file = $item['less']['input_file'];
$less_settings = $item['less'];
// array_multisort() the data so that the hash returns the same hash regardless order of data.
array_multisort($less_settings);
$output_path_array = array(
'!less_output_dir' => LESS_DIRECTORY,
// Strip '.css' extension of filenames following the RTL extension pattern.
'!input_file_basename' => basename(basename($input_file, '.less'), '.css'),
// drupal_json_encode() is used because serialize() throws an error with lambda functions.
'!settings_hash' => drupal_hash_base64(drupal_json_encode($less_settings)),
);
$output_path = format_string('!less_output_dir/!input_file_basename.!settings_hash.css', $output_path_array);
$item['less']['output_file'] = $output_path;
}
/**
* Check if the file needs to be rebuilt based on changes to @import'ed files.
*
* @param array[] $item
* @param string $key
*/
function _less_check_build(&$item, $key) {
$input_file = $item['less']['input_file'];
$build_required = FALSE;
// Set $rebuild if this file or its children have been modified.
if ($less_file_cache = cache_get('less:devel:' . drupal_hash_base64($input_file))) {
// Iterate over each file and check if there are any changes.
foreach ($less_file_cache->data as $filepath => $filemtime) {
// Only rebuild if there has been a change to a file.
if (is_file($filepath) && filemtime($filepath) > $filemtime) {
$build_required = TRUE;
break;
}
}
}
else {
// No cache data, force a rebuild for later comparison.
$build_required = TRUE;
}
$item['less']['build_required'] = $build_required;
}
/**
* Process a .less file and save the compiled styles.
*
* @param array[] $item
* @param string $key
*
* @see \LessEngineInterface
*/
function _less_process_file(&$item, $key) {
$less_settings = $item['less'];
// $output_file doesn't exist or is flagged for build.
if (!is_file($item['less']['output_file']) || !empty($item['less']['build_required'])) {
$output_data = NULL;
try {
$engine = less_get_engine($less_settings['input_file']);
$engine->setImportDirectories($less_settings['paths']);
if ($less_settings[LESS_DEVEL]) {
$engine->setSourceMaps($less_settings[LESS_SOURCE_MAPS], DRUPAL_ROOT, base_path());
}
$engine->modifyVariables($less_settings['variables']);
$output_data = $engine->compile();
if ($less_settings[LESS_DEVEL]) {
_less_cache_dependencies($less_settings['input_file'], $engine->getDependencies());
}
}
catch (Exception $e) {
$message_vars = array(
'@message' => $e->getMessage(),
'%input_file' => $item['less']['input_file'],
);
watchdog('LESS', 'LESS error: @message, %input_file', $message_vars, WATCHDOG_ERROR);
if (user_access(LESS_PERMISSION)) {
drupal_set_message(t('LESS error: @message, %input_file', $message_vars), 'error');
}
}
if (isset($output_data)) {
// Fix paths for images as .css is in different location.
$output_data = _less_rewrite_paths($item['less']['input_file'], $output_data);
// Ensure the destination directory exists.
if (_less_ensure_directory(dirname($item['less']['output_file']))) {
file_unmanaged_save_data($output_data, $item['less']['output_file'], FILE_EXISTS_REPLACE);
}
}
if (is_file($item['less']['output_file']) && $item['less'][LESS_AUTOPREFIXER]) {
if (($lessautoprefixer_library = libraries_load('lessautoprefixer')) && $lessautoprefixer_library['installed']) {
try {
LessAutoprefixer::create(drupal_realpath($item['less']['output_file']))->compile();
}
catch (Exception $e) {
$message_vars = array(
'@message' => $e->getMessage(),
'%input_file' => $item['less']['output_file'],
);
watchdog('LESS', 'Autoprefixer error: @message, %input_file', $message_vars, WATCHDOG_ERROR);
if (user_access(LESS_PERMISSION)) {
drupal_set_message(t('Autoprefixer error: @message, %input_file', $message_vars), 'error');
}
}
}
}
}
if (is_file($item['less']['output_file'])) {
// Set render path of the stylesheet to the compiled output.
$item['data'] = $item['less']['output_file'];
}
}
/**
* @param array[] $item
* @param string $key
*/
function _less_store_cache_info(&$item, $key) {
// Only match when output_file exists.
if ($item['data'] === $item['less']['output_file']) {
$less_watch_cache = $item;
$less_watch_cache['data'] = $item['less']['input_file'];
cache_set('less:watch:' . drupal_hash_base64(file_create_url($item['less']['output_file'])), $less_watch_cache);
// 'preprocess' being FALSE generates a discreet <link /> rather than an @import.
$item['preprocess'] = FALSE;
}
}
/**
* Normalize keeping track of changed files.
*
* @param string $input_file
* Path of source file.
* @param string[] $dependencies
* Array of files that are @import'ed in $input_file, recursively.
*/
function _less_cache_dependencies($input_file, $dependencies = array()) {
// Add $input_file to $dependencies as it is not in return from some engines.
$dependencies = array_merge(array($input_file), (array) $dependencies);
$watched_files = array();
foreach ($dependencies as $dependency) {
// Full path on file should enforce uniqueness in associative array.
$watched_files[drupal_realpath($dependency)] = filemtime($dependency);
}
cache_set('less:devel:' . drupal_hash_base64($input_file), $watched_files);
}
/**
* Copied functionality from drupal_build_css_cache() for our own purposes.
*
* This function processes $contents and rewrites relative paths to be absolute
* from web root. This is mainly used to ensure that compiled .less files still
* reference images at their original paths.
*
* @param string $input_filepath
* @param string $contents
*
* @return string
* Processed styles with replaced paths.
*
* @see drupal_build_css_cache()
*/
function _less_rewrite_paths($input_filepath, $contents) {
$output = '';
// Build the base URL of this CSS file: start with the full URL.
$css_base_url = file_create_url($input_filepath);
// Move to the parent.
$css_base_url = substr($css_base_url, 0, strrpos($css_base_url, '/'));
// Simplify to a relative URL if the stylesheet URL starts with the
// base URL of the website.
if (substr($css_base_url, 0, strlen($GLOBALS['base_root'])) == $GLOBALS['base_root']) {
$css_base_url = substr($css_base_url, strlen($GLOBALS['base_root']));
}
_drupal_build_css_path(NULL, $css_base_url . '/');
// Anchor all paths in the CSS with its base URL, ignoring external and absolute paths.
$output .= preg_replace_callback('/url\(\s*[\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\s*\)/i', '_drupal_build_css_path', $contents);
return $output;
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* @file
* Contains alterations to theme settings forms.
*/
/**
* Implements hook_form_alter().
*/
function less_form_alter(&$form, &$form_state, $form_id) {
if ($form_id === 'system_theme_settings') {
preg_match('/^theme_(?P<current_theme_key>\w+)_settings$/', $form['var']['#value'], $matches);
// only show settings on forms for themes, not "Global settings"
if (!empty($matches['current_theme_key'])) {
$current_theme_key = $matches['current_theme_key'];
$saved_settings = theme_get_setting('less', $current_theme_key);
$less_settings_form = array();
$theme_items = system_list('theme');
if (isset($theme_items[$current_theme_key]) && !empty($theme_items[$current_theme_key]->info['less']['vars'])) {
$less_settings_form[$current_theme_key] = _less_setting_form_element($current_theme_key, $theme_items[$current_theme_key]->info['less']['vars'], $saved_settings[$current_theme_key]);
}
// showing settings form for modules
$system_items = system_list('module_enabled');
$less_module_settings = array();
foreach ($system_items as $system_item_name => $system_item) {
if (!empty($system_item->info['less']['vars'])) {
$item_saved_settings = isset($saved_settings[$system_item_name]) ? $saved_settings[$system_item_name] : array();
$less_module_settings[$system_item_name] = _less_setting_form_element($system_item_name, $system_item->info['less']['vars'], $item_saved_settings, $system_item->info['name']);
$less_module_settings[$system_item_name]['#group'] = 'less][modules_list';
}
}
if (!empty($less_module_settings)) {
$less_settings_form['modules'] = array(
'#type' => 'fieldset',
'#title' => t('Modules'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#parents' => array('less'),
// make sure all settings are stored under the system name immediately inside the themes less settings array
);
$less_settings_form['modules']['modules_list'] = array(
'#type' => 'vertical_tabs',
);
$less_settings_form['modules'] += $less_module_settings;
}
if (!empty($less_settings_form)) {
$form['less'] = array(
'#type' => 'vertical_tabs',
'#prefix' => t('<h3>LESS settings</h3>'),
'#tree' => TRUE,
'#description' => t('These settings are per theme. Delete a value to use the default.'),
'#attached' => array(
'css' => array(
drupal_get_path('module', 'less') . '/styles/less.theme.css',
),
),
);
$form['less'] += $less_settings_form;
}
}
}
}
function _less_setting_form_element($system_name, $less_settings, $saved_settings, $title = NULL) {
$form = array(
'#type' => 'fieldset',
'#title' => isset($title) ? $title : $system_name,
'#attributes' => array(
'class' => array(
'less-theme-settings',
),
),
);
if (module_exists($system_name)) {
$less_settings = array_replace($less_settings, (array) module_invoke($system_name, 'less_variables'));
}
foreach ($less_settings as $var_name => $var_value) {
$form[$var_name] = array(
'#type' => 'textfield',
'#title' => $var_name,
'#default_value' => !empty($saved_settings[$var_name]) ? $saved_settings[$var_name] : NULL,
'#description' => t('Default value: %variable_value', array('%variable_value' => $var_value)),
'#attributes' => array('placeholder' => $var_value),
);
}
return $form;
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* @file
* Contains page callback for LESS watch functionality.
*/
/**
* Page callback for 'ajax/less/watch'.
*
* Handles AJAX requests to check for changes to files while in developer mode.
*/
function _less_watch() {
global $theme;
drupal_page_is_cacheable(FALSE);
$changed_files = array();
if (variable_get(LESS_WATCH, FALSE)) {
$files = (isset($_POST['less_files']) && is_array($_POST['less_files'])) ? $_POST['less_files'] : array();
foreach ($files as $file) {
$file_url_parts = drupal_parse_url($file);
if ($cache = cache_get('less:watch:' . drupal_hash_base64($file_url_parts['path']))) {
$cached_data = $cache->data;
$input_file = $cached_data['less']['input_file'];
$output_file = $cached_data['less']['output_file'];
$current_mtime = filemtime($output_file);
$theme = $cached_data['less']['theme'];
$styles = array(
'#items' => array(
$input_file => $cached_data,
),
);
$styles = _less_pre_render($styles);
if (filemtime($styles['#items'][$input_file]['data']) > $current_mtime) {
$changed_files[] = array(
'old_file' => $file_url_parts['path'],
'new_file' => file_create_url($styles['#items'][$input_file]['data']),
);
}
}
}
}
return $changed_files;
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* @file
* Contains functions that handle WYSIWYG module integration.
*/
/**
* Implements hook_wysiwyg_editor_settings_alter().
*
* Check the CSS WYSIWYG setting for LESS files and replace with
* generated CSS files where necessary.
*/
function less_wysiwyg_editor_settings_alter(&$settings, $context) {
$wysiwyg = $context['editor']['name'];
// Each editor has a different $settings array key for CSS files.
$editors = array(
'tinymce' => 'content_css',
'fckeditor' => 'EditorAreaCSS',
'ckeditor' => 'contentsCss',
);
if (!empty($editors[$wysiwyg]) && !empty($settings[$editors[$wysiwyg]])) {
$stylesheets = $settings[$editors[$wysiwyg]];
// Keep track if comma separated paths, or array of paths.
$is_array = is_array($stylesheets);
if ($is_array === FALSE) {
// $stylesheets is a list of comma separated file paths.
$stylesheets = explode(',', $stylesheets);
}
// Prepare an array that can be handled by normal LESS module processing.
$styles = array(
'#items' => array(),
);
foreach ($stylesheets as $stylesheet) {
// Might contain ?query portion, separate parts.
$parts = drupal_parse_url($stylesheet);
// Paths are expected to be relative to DRUPAL_ROOT, trim leading '/'.
$path = trim($parts['path'], '/');
$styles['#items'][$path] = array(
'data' => $path,
);
}
$styles = _less_pre_render($styles);
$processed_stylesheets = array();
foreach ($styles['#items'] as $file) {
$processed_stylesheets[] = file_create_url($file['data']);
}
// Recombine file paths into comma separated list.
if ($is_array === FALSE) {
$processed_stylesheets = implode(',', $processed_stylesheets);
}
$settings[$editors[$wysiwyg]] = $processed_stylesheets;
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* form_id = 'wysiwyg_profile'
*/
function less_form_wysiwyg_profile_form_alter(&$form, $form_state, $form_id) {
$form['css']['css_path']['#description'] .= '<br />' . t('You may enter a path to a LESS file and it will be parsed automatically.');
}
/**
* Implements hook_ckeditor_settings_alter().
*/
function less_ckeditor_settings_alter(&$settings) {
$context = array(
'editor' => array(
'name' => 'ckeditor',
),
);
less_wysiwyg_editor_settings_alter($settings, $context);
}