diff -Naur drupal-7.9/.editorconfig drupal-7.66/.editorconfig
--- drupal-7.9/.editorconfig 1970-01-01 01:00:00.000000000 +0100
+++ drupal-7.66/.editorconfig 2019-04-17 22:20:46.000000000 +0200
@@ -0,0 +1,14 @@
+# Drupal editor configuration normalization
+# @see http://editorconfig.org/
+
+# This is the top-most .editorconfig file; do not search in parent directories.
+root = true
+
+# All files.
+[*]
+end_of_line = LF
+indent_style = space
+indent_size = 2
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff -Naur drupal-7.9/.htaccess drupal-7.66/.htaccess
--- drupal-7.9/.htaccess 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/.htaccess 2019-04-17 22:20:46.000000000 +0200
@@ -3,8 +3,13 @@
#
# Protect files and directories from prying eyes.
-
, and
+ similar tags in a larger font size, so it is easier to read.
+- Fixed a bug in the Search module that caused exceptions to be thrown during
+ searches if the server was not configured to represent decimal points as a
+ period.
+- Fixed a regression in the Image module that made image_style_url() not work
+ when a relative path (rather than a complete file URI) was passed to it.
+- Added an optional feature to the Statistics module to allow node views to be
+ tracked by Ajax requests rather than during the server-side generation of the
+ page. This allows the node counter to work on sites that use external page
+ caches (string change and new administrative option:
+ https://drupal.org/node/2164069).
+- Added a link to the drupal.org documentation page for cron to the Cron
+ settings page (string change).
+- Added a 'drupal_anonymous_user_object' variable to allow the anonymous user
+ object returned by drupal_anonymous_user() to be overridden with a classed
+ object (API addition).
+- Changed the database API to allow inserts based on a SELECT * query to work
+ correctly.
+- Changed the database schema of the {file_managed} table to allow Drupal to
+ manage files larger than 4 GB.
+- Changed the File module's hook_field_load() implementation to prevent file
+ entity properties which have the same name as file or image field properties
+ from overwriting the field properties (minor API change).
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.24, 2013-11-20
+-----------------------
+- Fixed security issues (multiple vulnerabilities), see SA-CORE-2013-003.
+
+Drupal 7.23, 2013-08-07
+-----------------------
+- Fixed a fatal error on PostgreSQL databases when updating the Taxonomy module
+ from Drupal 6 to Drupal 7.
+- Fixed the default ordering of CSS files for sites using right-to-left
+ languages, to consistently place the right-to-left override file immediately
+ after the CSS it is overriding (API change: https://drupal.org/node/2058463).
+- Added a drupal_check_memory_limit() API function to allow the memory limit to
+ be checked consistently (API addition).
+- Changed the default web.config file for IIS servers to allow favicon.ico
+ files which are present in the filesystem to be accessed.
+- Fixed inconsistent support for the 'tel' protocol in Drupal's URL filtering
+ functions.
+- Performance improvement: Allowed all hooks to be included in the
+ module_implements() cache, even those that are only invoked on HTTP POST
+ requests.
+- Made the database system replace truncate queries with delete queries when
+ inside a transaction, to fix issues with PostgreSQL and other databases.
+- Fixed a bug which caused nested contextual links to display improperly.
+- Fixed a bug which prevented cached image derivatives from being flushed for
+ private files and other non-default file schemes.
+- Fixed drupal_render() to always return an empty string when there is no
+ output, rather than sometimes returning NULL (minor API change).
+- Added protection to cache_clear_all() to ensure that non-cache tables cannot
+ be truncated (API addition: a new isValidBin() method has been added to the
+ default database cache implementation).
+- Changed the default .htaccess file to support HTTP authorization in CGI
+ environments.
+- Changed the password reset form to pre-fill the username when requested via a
+ URL query parameter, and used this in the error message that appears after a
+ failed login attempt (minor data structure and behavior change).
+- Fixed broken support for foreign keys in the field API.
+- Fixed "No active batch" error when a user cancels their own account.
+- Added a description to the "access content overview" permission on the
+ permissions page (string change).
+- Added a drupal_array_diff_assoc_recursive() function to allow associative
+ arrays to be compared recursively (API addition).
+- Added human-readable labels to image styles, in addition to the existing
+ machine-readable name (API change: https://drupal.org/node/2058503).
+- Moved the drupal_get_hash_salt() function to bootstrap.inc and used it in
+ additional places in the code, for added security in the case where there is
+ no hash salt in settings.php.
+- Fixed a regression in Drupal 7.22 that caused internal server errors for
+ sites running on very old Apache 1.x web servers.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.22, 2013-04-03
+-----------------------
+- Allowed the drupal_http_request() function to be overridden so that
+ additional HTTP request capabilities can be added by contributed modules.
+- Changed the Simpletest module to allow PSR-0 test classes to be used in
+ Drupal 7.
+- Removed an unnecessary "Content-Disposition" header from private file
+ downloads; it prevented many private files from being viewed inline in a web
+ browser.
+- Changed various field API functions to allow them to optionally act on a
+ single field within an entity (API addition: http://drupal.org/node/1825844).
+- Fixed a bug which prevented Drupal's file transfer functionality from working
+ on some PHP 5.4 systems.
+- Fixed incorrect log message when theme() is called for a theme hook that does
+ not exist (minor string change).
+- Fixed Drupal's token-replacement system to allow spaces in the token value.
+- Changed the default behavior after a user creates a node they do not have
+ access to view. The user will now be redirected to the front page rather than
+ an access denied page.
+- Fixed a bug which prevented empty HTTP headers (such as "0") from being set.
+ (Minor behavior change: Callers of drupal_add_http_header() must now set
+ FALSE explicitly to prevent a header from being sent at all; this was already
+ indicated in the function's documentation.)
+- Fixed OpenID errors when more than one module implements hook_openid(). The
+ behavior is now changed so that if more than one module tries to set the same
+ parameter, the last module's change takes effect.
+- Fixed a serious documentation bug: The $name variable in the
+ taxonomy-term.tpl.php theme template was incorrectly documented as being
+ sanitized when in fact it is not.
+- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
+ duplicate permission names in the User module's database tables.
+- Added an empty "datatype" attribute to taxonomy term and username links to
+ make the RDFa markup upward compatible with RDFa 1.1 (minor markup addition).
+- Fixed a bug which caused the denial-of-service protection added in Drupal
+ 7.20 to break certain valid image URLs that had an extra slash in them.
+- Fixed a bug with update queries in the SQLite database driver that prevented
+ Drupal from being installed with SQLite on PHP 5.4.
+- Fixed enforced dependencies errors updating to recent versions of Drupal 7 on
+ certain non-MySQL databases.
+- Refactored the Field module's caching behavior to obtain large improvements
+ in memory usage for sites with many fields and instances (API addition:
+ http://drupal.org/node/1915646).
+- Fixed entity argument not being passed to implementations of
+ hook_file_download_access_alter(). The fix adds an additional context
+ parameter that can be passed when calling drupal_alter() for any hook (API
+ change: http://drupal.org/node/1882722).
+- Fixed broken support for translatable comment fields (API change:
+ http://drupal.org/node/1874724).
+- Added an assertThemeOutput() method to Simpletest to allow tests to check
+ that themed output matches an expected HTML string (API addition).
+- Added a link to "Install another module" after a module has been successfully
+ downloaded via the Update Manager (UI change).
+- Added an optional "exclusive" flag to installation profile .info files which
+ allows Drupal distributions to force a profile to be selected during
+ installation (API addition: http://drupal.org/node/1961012).
+- Fixed a bug which caused the database API to not properly close database
+ connections.
+- Added a link to the URL for running cron from outside the site to the Cron
+ settings page (UI change).
+- Fixed a bug which prevented image styles from being reverted on PHP 5.4.
+- Made the default .htaccess rules protocol sensitive to improve security for
+ sites which use HTTPS and redirect between "www" and non-"www" versions of
+ the page.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.21, 2013-03-06
+-----------------------
+- Allowed sites using the 'image_allow_insecure_derivatives' variable to still
+ have partial protection from the security issues fixed in Drupal 7.20.
+
+Drupal 7.20, 2013-02-20
+-----------------------
+- Fixed security issues (denial of service). See SA-CORE-2013-002.
+
+Drupal 7.19, 2013-01-16
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2013-001.
+
+Drupal 7.18, 2012-12-19
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2012-004.
+
+Drupal 7.17, 2012-11-07
+-----------------------
+- Changed the default value of the '404_fast_html' variable to have a DOCTYPE
+ declaration.
+- Made it possible to use associative arrays for the 'items' variable in
+ theme_item_list().
+- Fixed a bug which prevented required form elements without a title from being
+ given an "error" class when the form fails validation.
+- Prevented duplicate HTML IDs from appearing when two forms are displayed on
+ the same page and one of them is submitted with invalid data (minor markup
+ change).
+- Fixed a bug which prevented Drupal 6 to Drupal 7 upgrades on sites which had
+ stale data in the Upload module's database tables.
+- Fixed a bug in the States API which prevented certain types of form elements
+ from being disabled when requested.
+- Allowed aggregator feed items with author names longer than 255 characters to
+ have a truncated version saved to the database (rather than causing a fatal
+ error).
+- Allowed aggregator feed items to have URLs longer than 255 characters
+ (schema change which results in several columns in the Aggregator module's
+ database tables changing from VARCHAR to TEXT fields).
+- Added hook_taxonomy_term_view() and standardized the process for rendering
+ taxonomy terms to invoke hook_entity_view() and otherwise make it consistent
+ with other entities (API change: http://drupal.org/node/1808870).
+- Added hook_entity_view_mode_alter() to allow modules to change entity view
+ modes on display (API addition: http://drupal.org/node/1833086).
+- Fixed a bug which made database queries running a "LIKE" query on blob fields
+ fail on PostgreSQL databases. This caused errors during the Drupal 6 to
+ Drupal 7 upgrade.
+- Changed the hook_menu() entry for Drupal's rss.xml page to prevent extra path
+ components from being accidentally passed to the page callback function (data
+ structure change).
+- Removed a non-standard "name" attribute from Drupal's default Content-Type
+ header for file downloads.
+- Fixed the theme settings form to properly clean up submitted values in
+ $form_state['values'] when the form is submitted (data structure change).
+- Fixed an inconsistency by removing the colon from the end of the label on
+ multi-valued form fields (minor string change).
+- Added support for 'weight' in hook_field_widget_info() to allow modules to
+ control the order in which widgets are displayed in the Field UI.
+- Updated various tables in the OpenID and Book modules to use the default
+ "empty table" text pattern (string change).
+- Added proxy server support to drupal_http_request().
+- Added "lang" attributes to language links, to better support screen readers.
+- Fixed double occurrence of a "ul" HTML tag on secondary local tasks in the
+ Seven theme (markup change).
+- Fixed bugs which caused taxonomy vocabulary and shortcut set titles to be
+ double-escaped. The fix replaces the taxonomy vocabulary overview page and
+ "Edit shortcuts" menu items' title callback entries in hook_menu() with new
+ functions that do not escape HTML characters (data structure change).
+- Modified the Update manager module to allow drupal.org to collect usage
+ statistics for individual modules and themes, rather than only for entire
+ projects.
+- Modified the node listing database query on Drupal's default front page to
+ add table aliases for better query altering (this is a data structure change
+ affecting code which implements hook_query_alter() on this query).
+- Improved the translatability of the "Field type(s) in use" message on the
+ modules page (admin-facing string change).
+- Fixed a regression which caused a "call to undefined function
+ drupal_find_base_themes()" fatal error under rare circumstances.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.16, 2012-10-17
+-----------------------
+- Fixed security issues (Arbitrary PHP code execution and information
+ disclosure). See SA-CORE-2012-003.
+
+Drupal 7.15, 2012-08-01
+-----------------------
+- Introduced a 'user_password_reset_timeout' variable to allow the 24-hour
+ expiration for user password reset links to be adjusted (API addition).
+- Fixed database errors due to ambiguous column names that occurred when
+ EntityFieldQuery was used in certain situations.
+- Changed the drupal_array_get_nested_value() function to return a reference
+ (API addition).
+- Changed the System module's hook_block_info() implementation to assign the
+ "Main page content" and "System help" blocks to appropriate regions by
+ default and prevent error messages on the block administration page (data
+ structure change).
+- Fixed regression: Non-node entities couldn't be accessed with
+ EntityFieldQuery.
+- Fixed regression: Optional radio buttons with an empty, non-NULL default
+ value led to an illegal choice error when none were selected.
+- Reorganized the testing framework to split setUp() into specific sub-methods
+ and fix several regressions in the process.
+- Fixed bug which made it impossible to search for strings that have not been
+ translated into a particular language.
+- Renamed the "Field" column on the Manage Fields screen to "Field type", since
+ the former was confusing and inaccurate (UI change).
+- Performance improvement: Removed needless call to system_rebuild_module_data()
+ in field_sync_field_status(), greatly speeding up bulk module enable/disable.
+- Fixed bug which prevented notifications from being sent when core, module, and
+ theme updates are available.
+- Fixed bug which prevented sub-themes from inheriting the default values of
+ theme settings defined by the base theme.
+- Fixed bug which prevented the jQuery UI Datepicker from being localized.
+- Made Ajax alert dialogs respect error reporting settings.
+- Fixed bug which prevented image styles from being deleted on PHP 5.4.
+- Fixed bug: Language detection by domain only worked on port 80.
+- Fixed regression: The first plural index on a page was not calculated
+ correctly.
+- Introduced generic entity language support. Entities may now declare their
+ language property in hook_entity_info(), and modules working with entities
+ may access the language using entity_language() (API change:
+ http://drupal.org/node/1626346).
+- Added EntityFieldQuery support for taxonomy bundles.
+- Fixed issue where field form structure was incomplete if field_access()
+ returned FALSE. Instead of being incomplete, the form structure now has
+ #access set to FALSE and field form validation is skipped (data structure
+ change: http://drupal.org/node/1663020).
+- Fixed data loss issue due to field_has_data() returning inconsistent results.
+ The fix adds an optional DANGEROUS_ACCESS_CHECK_OPT_OUT tag to entity field
+ queries which field storage engines can respond to (API addition:
+ http://drupal.org/node/1597378).
+- Fixed notice: Undefined index: default_image in image_field_prepare_view()
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.14, 2012-05-02
+-----------------------
+- Fixed "integrity constraint" fatal errors when rebuilding registry.
+- Fixed custom logo and favicon functionality referencing incorrect paths.
+- Fixed DB Case Sensitivity: Allow BINARY attribute in MySQL.
+- Split field_bundle_settings out per bundle.
+- Improve UX for machine names for fields (UI change).
+- Fixed User pictures are not removed properly.
+- Fixed HTTPS sessions not working in all cases.
+- Fixed Regression: Required radios throw illegal choice error when none
+ selected.
+- Fixed allow autocompletion requests to include slashes.
+- Eliminate $user->cache and {session}.cache in favor of
+ $_SESSION['cache_expiration'][$bin] (Performance).
+- Fixed focus jumps to tab when pressing enter on a form element within tab.
+- Fixed race condition in locale() - duplicates in {locales_source}.
+- Fixed Missing "Default image" per field instance.
+- Quit clobbering people's work when they click the filter tips link
+- Form API #states: Fix conditionals to allow OR and XOR constructions.
+- Fixed Focus jumps to tab when pressing enter on a form element within tab.
+ (Accessibility)
+- Improved performance of node_access queries.
+- Fixed Fieldsets inside vertical tabs have no title and can't be collapsed.
+- Reduce size of cache_menu table (Performance).
+- Fixed unnecessary aggregation of CSS/JS (Performance).
+- Fixed taxonomy_autocomplete() produces SQL error for nonexistent field.
+- Fixed HTML filter is not run first by default, despite default weight.
+- Fixed Overlay does not work with prefixed URL paths.
+- Better debug info for field errors (string change).
+- Fixed Data corruption in comment IDs (results in broken threading on
+ PostgreSQL).
+- Fixed machine name not editable if every character is replaced.
+- Fixed user picture not appearing in comment preview (Markup change).
+- Added optional vid argument for taxonomy_get_term_by_name().
+- Fixed Invalid Unicode code range in PREG_CLASS_UNICODE_WORD_BOUNDARY fails
+ with PCRE 8.30.
+- Fixed {trigger_assignments()}.hook has only 32 characters, is too short.
+- Numerous fixes to run-tests.sh.
+- Fixed Tests in profiles/[name]/modules cannot be run and cannot use a
+ different profile for running tests.
+- Numerous JavaScript performance fixes.
+- Numerous documentation fixes.
+- Fixed All pager links have an 'active' CSS class.
+- Numerous upgrade path fixes; notably:
+ - system_update_7061() fails on inserting files with same name but different
+ case.
+ - system_update_7061() converts filepaths too aggressively.
+ - Trigger upgrade path: Node triggers removed when upgrading to 7-x from 6.25.
+
+Drupal 7.13, 2012-05-02
+-----------------------
+- Fixed security issues (Multiple vulnerabilities), see SA-CORE-2012-002.
+
+Drupal 7.12, 2012-02-01
+-----------------------
+- Fixed bug preventing custom menus from receiving an active trail.
+- Fixed hook_field_delete() no longer invoked during field_purge_data().
+- Fixed bug causing entity info cache to not be cleared with the rest of caches.
+- Fixed file_unmanaged_copy() fails with Drupal 7.7+ and safe_mode() or
+ open_basedir().
+- Fixed Nested transactions throw exceptions when they got out of scope.
+- Fixed bugs with the Return-Path when sending mail on both Windows and
+ non-Windows systems.
+- Fixed bug with DrupalCacheArray property visibility preventing others from
+ extending it (API change: http://drupal.org/node/1422264).
+- Fixed bug with handling of non-ASCII characters in file names (API change:
+ http://drupal.org/node/1424840).
+- Reconciled field maximum length with database column size in image and
+ aggregator modules.
+- Fixes to various core JavaScript files to allow for minification and
+ aggregation.
+- Fixed Prevent tests from deleting main installation's tables when
+ parent::setUp() is not called.
+- Fixed several Poll module bugs.
+- Fixed several Shortcut module bugs.
+- Added new hook_system_theme_info() to provide ability for contributed modules
+ to test theme functionality.
+- Added ability to cancel mail sending from hook_mail_alter().
+- Added support for configurable PDO connection options, enabling master-master
+ database replication.
+- Numerous improvements to tests and test runner to pave the way for faster test
+ runs.
+- Expanded test coverage.
+- Numerous API documentation improvements.
+- Numerous performance improvements, including token replacement and render
+ cache.
+
+Drupal 7.11, 2012-02-01
+-----------------------
+- Fixed security issues (Multiple vulnerabilities), see SA-CORE-2012-001.
+
+Drupal 7.10, 2011-12-05
+-----------------------
+- Fixed Content-Language HTTP header to not cause issues with Drush 5.x.
+- Reduce memory usage of theme registry (performance).
+- Fixed PECL upload progress bar for FileField
+- Fixed running update.php doesn't always clear the cache.
+- Fixed PDO exceptions on long titles.
+- Fixed Overlay redirect does not include query string.
+- Fixed D6 modules satisfy D7 module dependencies.
+- Fixed the ordering of module hooks when using module_implements_alter().
+- Fixed "floating" submit buttons during AJAX requests.
+- Fixed timezone selected on install not propogating to admin account.
+- Added msgctx context to JS translation functions, for feature parity with t().
+- Profiles' .install files now available during hook_install_tasks().
+- Added test coverage of 7.0 -> 7.x upgrade path.
+- Numerous notice fixes.
+- Numerous documentation improvements.
+- Additional automated test coverage.
Drupal 7.9, 2011-10-26
----------------------
@@ -149,8 +1114,8 @@
order can now be customized using the Views module.
* Removed the 'related terms' feature from taxonomy module since this can
now be achieved with Field API.
- * Added additional features to the default install profile, and implemented
- a "slimmed down" install profile designed for developers.
+ * Added additional features to the default installation profile, and
+ implemented a "slimmed down" profile designed for developers.
* Added a built-in, automated cron run feature, which is triggered by site
visitors.
* Added an administrator role which is assigned all permissions for
@@ -334,7 +1299,7 @@
requests.
Drupal 6.23-dev, xxxx-xx-xx (development release)
------------------------
+---------------------------
Drupal 6.22, 2011-05-25
-----------------------
@@ -344,25 +1309,25 @@
- Fixed a variety of other bugs.
Drupal 6.21, 2011-05-25
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting), see SA-CORE-2011-001.
Drupal 6.20, 2010-12-15
-----------------------
+-----------------------
- Fixed a variety of small bugs, improved code documentation.
Drupal 6.19, 2010-08-11
-----------------------
+-----------------------
- Fixed a variety of small bugs, improved code documentation.
Drupal 6.18, 2010-08-11
-----------------------
+-----------------------
- Fixed security issues (OpenID authentication bypass, File download access
bypass, Comment unpublishing bypass, Actions cross site scripting),
see SA-CORE-2010-002.
Drupal 6.17, 2010-06-02
-----------------------
+-----------------------
- Improved PostgreSQL compatibility
- Better PHP 5.3 and PHP 4 compatibility
- Better browser compatibility of CSS and JS aggregation
@@ -371,24 +1336,24 @@
- Fixed a variety of other bugs.
Drupal 6.16, 2010-03-03
-----------------------
+-----------------------
- Fixed security issues (Installation cross site scripting, Open redirection,
Locale module cross site scripting, Blocked user session regeneration),
see SA-CORE-2010-001.
- Better support for updated jQuery versions.
- Reduced resource usage of update.module.
-- Fixed several issues relating to support of install profiles and
+- Fixed several issues relating to support of installation profiles and
distributions.
- Added a locking framework to avoid data corruption on long operations.
- Fixed a variety of other bugs.
Drupal 6.15, 2009-12-16
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting), see SA-CORE-2009-009.
- Fixed a variety of other bugs.
Drupal 6.14, 2009-09-16
-----------------------
+-----------------------
- Fixed security issues (OpenID association cross site request forgeries,
OpenID impersonation and File upload), see SA-CORE-2009-008.
- Changed the system modules page to not run all cache rebuilds; use the
@@ -397,18 +1362,18 @@
- Fixed a variety of small bugs.
Drupal 6.13, 2009-07-01
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting, Input format access bypass and
Password leakage in URL), see SA-CORE-2009-007.
- Fixed a variety of small bugs.
Drupal 6.12, 2009-05-13
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting), see SA-CORE-2009-006.
- Fixed a variety of small bugs.
Drupal 6.11, 2009-04-29
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting and limited information
disclosure), see SA-CORE-2009-005
- Fixed performance issues with the menu router cache, the update
@@ -416,7 +1381,7 @@
- Fixed a variety of small bugs.
Drupal 6.10, 2009-02-25
-----------------------
+-----------------------
- Fixed a security issue, (Local file inclusion on Windows),
see SA-CORE-2009-003
- Fixed node_feed() so custom fields can show up in RSS feeds.
@@ -495,7 +1460,7 @@
* Expands the severity levels from 3 (Error, Warning, Notice) to the 8
levels defined in RFC 3164.
* The watchdog module is now called dblog, and is optional, but enabled by
- default in the default install profile.
+ default in the default installation profile.
* Extended the database log module so log messages can be filtered.
* Added syslog module: useful for monitoring large Drupal installations.
- Added optional e-mail notifications when users are approved, blocked, or
@@ -550,7 +1515,7 @@
* Themed the installer with the Garland theme.
* Added form to provide initial site information during installation.
* Added ability to provide extra installation steps programmatically.
- * Made it possible to import interface translations at install time.
+ * Made it possible to import interface translations during installation.
- Added the HTML corrector filter:
* Fixes faulty and chopped off HTML in postings.
* Tags are now automatically closed at the end of the teaser.
@@ -729,7 +1694,7 @@
- Added web-based installer which can:
* Check installation and run-time requirements
* Automatically generate the database configuration file
- * Install pre-made 'install profiles' or distributions
+ * Install pre-made installation profiles or distributions
* Import the database structure with automatic table prefixing
* Be localized
- Added new default Garland theme
@@ -789,7 +1754,7 @@
- Removed the archive module.
- Upgrade system:
* Created space for update branches.
-- Forms API:
+- Form API:
* Made it possible to programmatically submit forms.
* Improved api for multistep forms.
- Theme system:
@@ -812,7 +1777,7 @@
- fixed a security issue (SQL injection), see SA-2007-031
Drupal 4.7.8, 2007-10-17
-----------------------
+------------------------
- fixed a security issue (HTTP response splitting), see SA-2007-024
- fixed a security issue (Cross site scripting via uploads), see SA-2007-026
- fixed a security issue (API handling of unpublished comment), see SA-2007-030
@@ -925,7 +1890,7 @@
- Fixed security issue (DoS), see SA-2007-002
Drupal 4.6.10, 2006-10-18
-------------------------
+-------------------------
- Fixed security issue (XSS), see SA-2006-024
- Fixed security issue (CSRF), see SA-2006-025
- Fixed security issue (Form action attribute injection), see SA-2006-026
diff -Naur drupal-7.9/COPYRIGHT.txt drupal-7.66/COPYRIGHT.txt
--- drupal-7.9/COPYRIGHT.txt 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/COPYRIGHT.txt 2019-04-17 22:20:46.000000000 +0200
@@ -1,5 +1,4 @@
-
-All Drupal code is Copyright 2001 - 2010 by the original authors.
+All Drupal code is Copyright 2001 - 2013 by the original authors.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,5 +20,25 @@
according to the terms of the GNU General Public License or a compatible
license, including:
- jQuery - Copyright (c) 2008 - 2009 John Resig
+Javascript
+
+ Farbtastic - Copyright (c) 2010 Matt Farina
+
+ jQuery - Copyright (c) 2010 John Resig
+
+ jQuery BBQ - Copyright (c) 2010 "Cowboy" Ben Alman
+
+ jQuery Cookie - Copyright (c) 2006 Klaus Hartl
+
+ jQuery Form - Copyright (c) 2010 Mike Alsup
+
+ jQuery Once - Copyright (c) 2009 Konstantin K�fer
+
+ jQuery UI - Copyright (c) 2010 by the original authors
+ (http://jqueryui.com/about)
+
+ Sizzle.js - Copyright (c) 2010 The Dojo Foundation (http://sizzlejs.com/)
+
+PHP
+ ArchiveTar - Copyright (c) 1997 - 2008 Vincent Blavet
diff -Naur drupal-7.9/INSTALL.mysql.txt drupal-7.66/INSTALL.mysql.txt
--- drupal-7.9/INSTALL.mysql.txt 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/INSTALL.mysql.txt 2019-04-17 22:20:46.000000000 +0200
@@ -18,20 +18,23 @@
mysql -u username -p
Again, you will be asked for the 'username' database password. At the MySQL
-prompt, enter following command:
+prompt, enter the following command:
- GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
- ON databasename.*
+ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
+ CREATE TEMPORARY TABLES ON databasename.*
TO 'username'@'localhost' IDENTIFIED BY 'password';
-where
+where:
'databasename' is the name of your database
- 'username@localhost' is the username of your MySQL account
+ 'username' is the username of your MySQL account
+ 'localhost' is the web server host where Drupal is installed
'password' is the password required for that username
-Note: Unless your database user has all of the privileges listed above, you will
-not be able to run Drupal.
+Note: Unless the database user/host combination for your Drupal installation
+has all of the privileges listed above (except possibly CREATE TEMPORARY TABLES,
+which is currently only used by Drupal core automated tests and some
+contributed modules), you will not be able to install or run Drupal.
If successful, MySQL will reply with:
diff -Naur drupal-7.9/INSTALL.txt drupal-7.66/INSTALL.txt
--- drupal-7.9/INSTALL.txt 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/INSTALL.txt 2019-04-17 22:20:46.000000000 +0200
@@ -20,8 +20,10 @@
- MySQL 5.0.15 (or greater) (http://www.mysql.com/).
- MariaDB 5.1.44 (or greater) (http://mariadb.org/). MariaDB is a fully
compatible drop-in replacement for MySQL.
+ - Percona Server 5.1.70 (or greater) (http://www.percona.com/). Percona
+ Server is a backwards-compatible replacement for MySQL.
- PostgreSQL 8.3 (or greater) (http://www.postgresql.org/).
- - SQLite 3.4.2 (or greater) (http://www.sqlite.org/).
+ - SQLite 3.3.7 (or greater) (http://www.sqlite.org/).
For more detailed information about Drupal requirements, including a list of
PHP extensions and configurations that are required, see "System requirements"
@@ -89,8 +91,8 @@
- Download a translation file for the correct Drupal version and language
from the translation server: http://localize.drupal.org/translate/downloads
- - Place the file into your installation profile's translations
- directory. For instance, if you are using the Standard install profile,
+ - Place the file into your installation profile's translations directory.
+ For instance, if you are using the Standard installation profile,
move the .po file into the directory:
profiles/standard/translations/
diff -Naur drupal-7.9/MAINTAINERS.txt drupal-7.66/MAINTAINERS.txt
--- drupal-7.9/MAINTAINERS.txt 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/MAINTAINERS.txt 2019-04-17 22:20:46.000000000 +0200
@@ -1,147 +1,163 @@
-Drupal core is maintained by the community. To participate, go to
-
- http://drupal.org/contribute
-
-The people listed here have agreed to do more quality assurance work for
-particular areas of Drupal. All of them are subject to change.
-
+Drupal core is built and maintained by the Drupal project community. Everyone is
+encouraged to submit issues and changes (patches) to improve Drupal, and to
+contribute in other ways -- see https://www.drupal.org/contribute to find out
+how.
Branch maintainers
------------------
-Drupal 7
-- Dries Buytaert 'dries'
-- Angela Byron 'webchick'
+The Drupal Core branch maintainers oversee the development of Drupal as a whole.
+The branch maintainers for Drupal 7 are:
+
+- Dries Buytaert 'dries' https://www.drupal.org/u/dries
+- Angela Byron 'webchick' https://www.drupal.org/u/webchick
+- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
+- Stefan Ruijsenaars 'stefan.r' https://www.drupal.org/u/stefanr-0
+- (provisional) Pol Dellaiera 'Pol' https://www.drupal.org/u/pol
Component maintainers
---------------------
+The Drupal Core component maintainers oversee the development of Drupal
+subsystems. See https://www.drupal.org/contribute/core-maintainers for more
+information on their responsibilities, and to find out how to become a component
+maintainer. Current component maintainers for Drupal 7:
+
Ajax system
-- Alex Bronstein 'effulgentsia'
-- Randy Fay 'rfay'
-- Earl Miles 'merlinofchaos'
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Earl Miles 'merlinofchaos' https://www.drupal.org/u/merlinofchaos
Base system
-- Károly Négyesi 'chx'
-- Damien Tournoud 'DamZ'
-- Moshe Weitzman 'moshe weitzman'
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
Batch system
-- Yves Chedemois 'yched'
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
Cache system
-- Damien Tournoud 'DamZ'
-- Nathaniel Catchpole 'catch'
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
Cron system
-- Károly Négyesi 'chx'
-- Derek Wright 'dww'
+- Derek Wright 'dww' https://www.drupal.org/u/dww
Database system
-- Larry Garfield 'Crell'
+- ?
- MySQL driver
- - Larry Garfield 'Crell'
- - David Strauss 'David Strauss'
+ - David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
- PostgreSQL driver
- - Damien Tournoud 'DamZ'
- - Josh Waihi 'fiasco'
+ - Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+ - Josh Waihi 'fiasco' https://www.drupal.org/u/josh-waihi
- Sqlite driver
- - Damien Tournoud 'DamZ'
- - Károly Négyesi 'chx'
+ - Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
Database update system
-- Károly Négyesi 'chx'
+- Ashok Modi 'BTMash' https://www.drupal.org/u/btmash
Entity system
-- Nathaniel Catchpole 'catch'
-- Franz Heinzmann 'Frando'
+- Wolfgang Ziegler 'fago' https://www.drupal.org/u/fago
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
File system
-- Andrew Morton 'drewish'
-- Aaron Winborn 'aaron'
+- Andrew Morton 'drewish' https://www.drupal.org/u/drewish
+- Aaron Winborn 'aaron' https://www.drupal.org/u/aaron
Form system
-- Károly Négyesi 'chx'
-- Alex Bronstein 'effulgentsia'
-- Wolfgang Ziegler 'fago'
-- Daniel F. Kudwien 'sun'
-- Franz Heinzmann 'Frando'
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Wolfgang Ziegler 'fago' https://www.drupal.org/u/fago
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
Image system
-- Andrew Morton 'drewish'
-- Nathan Haug 'quicksketch'
+- Andrew Morton 'drewish' https://www.drupal.org/u/drewish
+- Nathan Haug 'quicksketch' https://www.drupal.org/u/quicksketch
Install system
-- David Rothstein 'David_Rothstein'
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
JavaScript
-- ?
+- Théodore Biadala 'nod_' https://www.drupal.org/u/nod_
+- Steve De Jonghe 'seutje' https://www.drupal.org/u/seutje
Language system
-- Francesco Placella 'plach'
-- Daniel F. Kudwien 'sun'
+- Francesco Placella 'plach' https://www.drupal.org/u/plach
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Lock system
-- Damien Tournoud 'DamZ'
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
Mail system
- ?
Markup
-- Jacine Luisi 'Jacine'
-- Daniel F. Kudwien 'sun'
+- Jacine Luisi 'Jacine' https://www.drupal.org/u/jacine
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Menu system
-- Peter Wolanin 'pwolanin'
-- Károly Négyesi 'chx'
+- Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin
Path system
-- Dave Reid 'davereid'
-- Nathaniel Catchpole 'catch'
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
Render system
-- Moshe Weitzman 'moshe weitzman'
-- Alex Bronstein 'effulgentsia'
-- Franz Heinzmann 'Frando'
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
Theme system
-- Earl Miles 'merlinofchaos'
-- Alex Bronstein 'effulgentsia'
-- Joon Park 'dvessel'
-- John Albin Wilkins 'JohnAlbin'
+- Earl Miles 'merlinofchaos' https://www.drupal.org/u/merlinofchaos
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Joon Park 'dvessel' https://www.drupal.org/u/dvessel
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
Token system
-- Dave Reid 'davereid'
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
XML-RPC system
-- Frederic G. Marand 'fgm'
+- Frederic G. Marand 'fgm' https://www.drupal.org/u/fgm
Topic coordinators
------------------
Accessibility
-- Everett Zufelt 'Everett Zufelt'
-- Brandon Bowersox 'brandonojc'
+- Everett Zufelt 'Everett Zufelt' https://www.drupal.org/u/everett-zufelt
+- Brandon Bowersox-Johnson 'bowersox' https://www.drupal.org/u/bowersox
Documentation
-- Ariane Khachatourians 'arianek'
-- Jennifer Hodgdon 'jhodgdon'
-
-Security
-- Heine Deelstra 'Heine'
+- Jennifer Hodgdon 'jhodgdon' https://www.drupal.org/u/jhodgdon
Translations
-- Gerhard Killesreiter 'killes'
+- Gerhard Killesreiter 'killes' https://www.drupal.org/u/gerhard-killesreiter
User experience and usability
-- Roy Scholten 'yoroy'
-- Bojhan Somers 'Bojhan'
+- Roy Scholten 'yoroy' https://www.drupal.org/u/yoroy
+- Bojhan Somers 'Bojhan' https://www.drupal.org/u/bojhan
+
+Node Access
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- Ken Rickard 'agentrickard' https://www.drupal.org/u/agentrickard
+
+
+Security team
+-----------------
+
+To report a security issue, see: https://www.drupal.org/security-team/report-issue
+
+The Drupal security team provides Security Advisories for vulnerabilities,
+assists developers in resolving security issues, and provides security
+documentation. See https://www.drupal.org/security-team for more information.
+The security team lead is:
+
+- Michael Hess 'mlhess' https://www.drupal.org/u/mlhess
Module maintainers
@@ -151,144 +167,141 @@
- ?
Block module
-- John Albin Wilkins 'JohnAlbin'
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
Blog module
- ?
Book module
-- Peter Wolanin 'pwolanin'
+- Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin
Color module
- ?
Comment module
-- Nathaniel Catchpole 'catch'
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
Contact module
-- Dave Reid 'davereid'
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
Contextual module
-- Daniel F. Kudwien 'sun'
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Dashboard module
- ?
Database logging module
-- Khalid Baheyeldin 'kbahey'
+- Khalid Baheyeldin 'kbahey' https://www.drupal.org/u/kbahey
Field module
-- Yves Chedemois 'yched'
-- Barry Jaspan 'bjaspan'
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
+- Barry Jaspan 'bjaspan' https://www.drupal.org/u/bjaspan
Field UI module
-- Yves Chedemois 'yched'
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
File module
-- Aaron Winborn 'aaron'
+- Aaron Winborn 'aaron' https://www.drupal.org/u/aaron
Filter module
-- Daniel F. Kudwien 'sun'
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Forum module
-- Lee Rowlands 'larowlan'
+- Lee Rowlands 'larowlan' https://www.drupal.org/u/larowlan
Help module
- ?
Image module
-- Nathan Haug 'quicksketch'
+- Nathan Haug 'quicksketch' https://www.drupal.org/u/quicksketch
Locale module
-- Gábor Hojtsy 'Gábor Hojtsy'
+- Gábor Hojtsy 'Gábor Hojtsy' https://www.drupal.org/u/gábor-hojtsy
Menu module
- ?
Node module
-- Moshe Weitzman 'moshe weitzman'
-- David Strauss 'David Strauss'
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
OpenID module
-- Vojtech Kusy 'wojtha'
-- Heine Deelstra 'Heine'
-- Christian Schmidt 'c960657'
-- Damien Tournoud 'DamZ'
+- Vojtech Kusy 'wojtha' https://www.drupal.org/u/wojtha
+- Christian Schmidt 'c960657' https://www.drupal.org/u/c960657
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
Overlay module
-- Katherine Senzee 'ksenzee'
+- Katherine Senzee 'ksenzee' https://www.drupal.org/u/ksenzee
Path module
-- Dave Reid 'davereid'
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
PHP module
- ?
Poll module
-- ?
+- Andrei Mateescu 'amateescu' https://www.drupal.org/u/amateescu
Profile module
- ?
RDF module
-- Stéphane Corlosquet 'scor'
+- Stéphane Corlosquet 'scor' https://www.drupal.org/u/scor
Search module
-- Doug Green 'douggreen'
+- Doug Green 'douggreen' https://www.drupal.org/u/douggreen
Shortcut module
-- David Rothstein 'David_Rothstein'
-- Kristof De Jaeger 'swentel'
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
Simpletest module
-- Jimmy Berry 'boombatower'
-- Károly Négyesi 'chx'
+- Jimmy Berry 'boombatower' https://www.drupal.org/u/boombatower
Statistics module
-- Dave Reid 'davereid'
+- Tim Millwood 'timmillwood' https://www.drupal.org/u/timmillwood
Syslog module
-- Khalid Baheyeldin 'kbahey'
+- Khalid Baheyeldin 'kbahey' https://www.drupal.org/u/kbahey
System module
- ?
Taxonomy module
-- Nathaniel Catchpole 'catch'
-- Benjamin Doherty 'bangpound'
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
+- Benjamin Doherty 'bangpound' https://www.drupal.org/u/bangpound
Toolbar module
- ?
Tracker module
-- David Strauss 'David Strauss'
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
Translation module
-- Francesco Placella 'plach'
+- Francesco Placella 'plach' https://www.drupal.org/u/plach
Trigger module
- ?
Update module
-- Derek Wright 'dww'
+- Derek Wright 'dww' https://www.drupal.org/u/dww
User module
-- Moshe Weitzman 'moshe weitzman'
-- David Strauss 'David Strauss'
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
Theme maintainers
-----------------
Bartik theme
-- Jen Simmons 'jensimmons'
-- Jeff Burns 'Jeff Burnz'
+- Jen Simmons 'jensimmons' https://www.drupal.org/u/jensimmons
+- Jeff Burns 'Jeff Burnz' https://www.drupal.org/u/jeff-burnz
Garland theme
-- John Albin Wilkins 'JohnAlbin'
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
Seven theme
-- Jeff Burns 'Jeff Burnz'
+- Jeff Burns 'Jeff Burnz' https://www.drupal.org/u/jeff-burnz
Stark theme
-- John Albin Wilkins 'JohnAlbin'
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
diff -Naur drupal-7.9/README.txt drupal-7.66/README.txt
--- drupal-7.9/README.txt 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/README.txt 2019-04-17 22:20:46.000000000 +0200
@@ -4,6 +4,7 @@
* About Drupal
* Configuration and features
+ * Installation profiles
* Appearance
* Developing for Drupal
@@ -43,6 +44,40 @@
http://drupal.org/project/modules
* See also: "Developing for Drupal" for writing your own modules, below.
+INSTALLATION PROFILES
+---------------------
+
+Installation profiles define additional steps (such as enabling modules,
+defining content types, etc.) that run after the base installation provided
+by core when Drupal is first installed. There are two basic installation
+profiles provided with Drupal core.
+
+Installation profiles from the Drupal community modify the installation process
+to provide a website for a specific use case, such as a CMS for media
+publishers, a web-based project tracking tool, or a full-fledged CRM for
+non-profit organizations raising money and accepting donations. They can be
+distributed as bare installation profiles or as "distributions". Distributions
+include Drupal core, the installation profile, and all other required
+extensions, such as contributed and custom modules, themes, and third-party
+libraries. Bare installation profiles require you to download Drupal Core and
+the required extensions separately; place the downloaded profile in the
+/profiles directory before you start the installation process. Note that the
+contents of this directory may be overwritten during updates of Drupal core;
+it is advised to keep code backups or use a version control system.
+
+Additionally, modules and themes may be placed inside subdirectories in a
+specific installation profile such as profiles/your_site_profile/modules and
+profiles/your_site_profile/themes respectively to restrict their usage to only
+sites that were installed with that specific profile.
+
+More about installation profiles and distributions:
+ * Read about the difference between installation profiles and distributions:
+ http://drupal.org/node/1089736
+ * Download contributed installation profiles and distributions:
+ http://drupal.org/project/distributions
+ * Develop your own installation profile or distribution:
+ http://drupal.org/developing/distributions
+
APPEARANCE
----------
diff -Naur drupal-7.9/UPGRADE.txt drupal-7.66/UPGRADE.txt
--- drupal-7.9/UPGRADE.txt 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/UPGRADE.txt 2019-04-17 22:20:46.000000000 +0200
@@ -64,6 +64,9 @@
Sometimes an update includes changes to default.settings.php (this will be
noted in the release notes). If that's the case, follow these steps:
+ - Locate your settings.php file in the /sites/* directory. (Typically
+ sites/default.)
+
- Make a backup copy of your settings.php file, with a different file name.
- Make a copy of the new default.settings.php file, and name the copy
@@ -74,6 +77,13 @@
database information, and you will also want to copy in any other
customizations you have added.
+ You can find the release notes for your version at
+ https://www.drupal.org/project/drupal. At bottom of the project page under
+ "Downloads" use the link for your version of Drupal to view the release
+ notes. If your version is not listed, use the 'View all releases' link. From
+ this page you can scroll down or use the filter to find your version and its
+ release notes.
+
4. Download the latest Drupal 7.x release from http://drupal.org to a
directory outside of your web root. Extract the archive and copy the files
into your Drupal directory.
@@ -141,15 +151,19 @@
download Drupal 6.x and follow the instructions in its UPGRADE.txt. This
document only applies for upgrades from 6.x to 7.x.
-3. Log in as user ID 1 (the site maintenance user).
+3. In addition to updating to the latest available version of Drupal 6.x core,
+ you must also upgrade all of your contributed modules for Drupal to their
+ latest Drupal 6.x versions.
+
+4. Log in as user ID 1 (the site maintenance user).
-4. Go to Administer > Site configuration > Site maintenance. Select
+5. Go to Administer > Site configuration > Site maintenance. Select
"Off-line" and save the configuration.
-5. Go to Administer > Site building > Themes. Enable "Garland" and select it as
+6. Go to Administer > Site building > Themes. Enable "Garland" and select it as
the default theme.
-6. Go to Administer > Site building > Modules. Disable all modules that are not
+7. Go to Administer > Site building > Modules. Disable all modules that are not
listed under "Core - required" or "Core - optional". It is possible that some
modules cannot be disabled, because others depend on them. Repeat this step
until all non-core modules are disabled.
@@ -158,21 +172,21 @@
no longer need their data, then you can uninstall them under the Uninstall
tab after disabling them.
-7. On the command line or in your FTP client, remove the file
+8. On the command line or in your FTP client, remove the file
sites/default/default.settings.php
-8. Remove all old core files and directories, except for the 'sites' directory
+9. Remove all old core files and directories, except for the 'sites' directory
and any custom files you added elsewhere.
If you made modifications to files like .htaccess or robots.txt, you will
need to re-apply them from your backup, after the new files are in place.
-9. If you uninstalled any modules, remove them from the sites/all/modules and
+10. If you uninstalled any modules, remove them from the sites/all/modules and
other sites/*/modules directories. Leave other modules in place, even though
they are incompatible with Drupal 7.x.
-10. Download the latest Drupal 7.x release from http://drupal.org to a
+11. Download the latest Drupal 7.x release from http://drupal.org to a
directory outside of your web root. Extract the archive and copy the files
into your Drupal directory.
@@ -191,14 +205,14 @@
from http://drupal.org using your web browser, extract it, and then use an
FTP client to upload the files to your web root.
-11. Re-apply any modifications to files such as .htaccess or robots.txt.
+12. Re-apply any modifications to files such as .htaccess or robots.txt.
-12. Make your settings.php file writeable, so that the update process can
+13. Make your settings.php file writeable, so that the update process can
convert it to the format of Drupal 7.x. settings.php is usually located in
sites/default/settings.php
-13. Run update.php by visiting http://www.example.com/update.php (replace
+14. Run update.php by visiting http://www.example.com/update.php (replace
www.example.com with your domain name). This will update the core database
tables.
@@ -214,17 +228,17 @@
- Once the upgrade is done, $update_free_access must be reverted to FALSE.
-14. Backup your database after the core upgrade has run.
+15. Backup your database after the core upgrade has run.
-15. Replace and update your non-core modules and themes, following the
+16. Replace and update your non-core modules and themes, following the
procedures at http://drupal.org/node/948216
-16. Go to Administration > Reports > Status report. Verify that everything is
+17. Go to Administration > Reports > Status report. Verify that everything is
working as expected.
-17. Ensure that $update_free_access is FALSE in settings.php.
+18. Ensure that $update_free_access is FALSE in settings.php.
-18. Go to Administration > Configuration > Development > Maintenance mode.
+19. Go to Administration > Configuration > Development > Maintenance mode.
Disable the "Put site into maintenance mode" checkbox and save the
configuration.
diff -Naur drupal-7.9/authorize.php drupal-7.66/authorize.php
--- drupal-7.9/authorize.php 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/authorize.php 2019-04-17 22:20:46.000000000 +0200
@@ -4,16 +4,16 @@
* @file
* Administrative script for running authorized file operations.
*
- * Using this script, the site owner (the user actually owning the files on
- * the webserver) can authorize certain file-related operations to proceed
- * with elevated privileges, for example to deploy and upgrade modules or
- * themes. Users should not visit this page directly, but instead use an
- * administrative user interface which knows how to redirect the user to this
- * script as part of a multistep process. This script actually performs the
- * selected operations without loading all of Drupal, to be able to more
- * gracefully recover from errors. Access to the script is controlled by a
- * global killswitch in settings.php ('allow_authorize_operations') and via
- * the 'administer software updates' permission.
+ * Using this script, the site owner (the user actually owning the files on the
+ * webserver) can authorize certain file-related operations to proceed with
+ * elevated privileges, for example to deploy and upgrade modules or themes.
+ * Users should not visit this page directly, but instead use an administrative
+ * user interface which knows how to redirect the user to this script as part of
+ * a multistep process. This script actually performs the selected operations
+ * without loading all of Drupal, to be able to more gracefully recover from
+ * errors. Access to the script is controlled by a global killswitch in
+ * settings.php ('allow_authorize_operations') and via the 'administer software
+ * updates' permission.
*
* There are helper functions for setting up an operation to run via this
* system in modules/system/system.module. For more information, see:
@@ -21,16 +21,17 @@
*/
/**
- * Root directory of Drupal installation.
+ * Defines the root directory of the Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
- * Global flag to identify update.php and authorize.php runs, and so
- * avoid various unwanted operations, such as hook_init() and
- * hook_exit() invokes, css/js preprocessing and translation, and
- * solve some theming issues. This flag is checked on several places
- * in Drupal code (not just authorize.php).
+ * Global flag to identify update.php and authorize.php runs.
+ *
+ * Identifies update.php and authorize.php runs, avoiding unwanted operations
+ * such as hook_init() and hook_exit() invokes, css/js preprocessing and
+ * translation, and solves some theming issues. The flag is checked in other
+ * places in Drupal code (not just authorize.php).
*/
define('MAINTENANCE_MODE', 'update');
@@ -51,7 +52,7 @@
* have access to the 'administer software updates' permission.
*
* @return
- * TRUE if the current user can run authorize.php, otherwise FALSE.
+ * TRUE if the current user can run authorize.php, and FALSE if not.
*/
function authorize_access_allowed() {
return variable_get('allow_authorize_operations', TRUE) && user_access('administer software updates');
@@ -60,7 +61,6 @@
// *** Real work of the script begins here. ***
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
-require_once DRUPAL_ROOT . '/includes/session.inc';
require_once DRUPAL_ROOT . '/includes/common.inc';
require_once DRUPAL_ROOT . '/includes/file.inc';
require_once DRUPAL_ROOT . '/includes/module.inc';
diff -Naur drupal-7.9/includes/actions.inc drupal-7.66/includes/actions.inc
--- drupal-7.9/includes/actions.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/actions.inc 2019-04-17 22:20:46.000000000 +0200
@@ -22,7 +22,7 @@
* - $a1, $a2: Optional additional information, which can be passed into
* actions_do() and will be passed along to the action function.
*
- * @} End of "defgroup actions".
+ * @}
*/
/**
@@ -48,6 +48,7 @@
* Passed along to the callback.
* @param $a2
* Passed along to the callback.
+ *
* @return
* An associative array containing the results of the functions that
* perform the actions, keyed on action ID.
@@ -149,6 +150,7 @@
*
* @param $reset
* Reset the action info static cache.
+ *
* @return
* An associative array keyed on action function name, with the same format
* as the return value of hook_action_info(), containing all
@@ -176,9 +178,9 @@
* function and the actions returned by actions_list() are partially
* synchronized. Non-configurable actions from hook_action_info()
* implementations are put into the database when actions_synchronize() is
- * called, which happens when admin/config/system/actions is visited. Configurable
- * actions are not added to the database until they are configured in the
- * user interface, in which case a database row is created for each
+ * called, which happens when admin/config/system/actions is visited.
+ * Configurable actions are not added to the database until they are configured
+ * in the user interface, in which case a database row is created for each
* configuration of each action.
*
* @return
@@ -205,6 +207,7 @@
* An associative array with function names or action IDs as keys
* and associative arrays with keys 'label', 'type', etc. as values.
* This is usually the output of actions_list() or actions_get_all_actions().
+ *
* @return
* An associative array whose keys are hashes of the input array keys, and
* whose corresponding values are associative arrays with components
@@ -223,7 +226,7 @@
}
/**
- * Given a hash of an action array key, returns the key (function or ID).
+ * Returns an action array key (function or ID), given its hash.
*
* Faster than actions_actions_map() when you only need the function name or ID.
*
@@ -231,6 +234,7 @@
* Hash of a function name or action ID array key. The array key
* is a key into the return value of actions_list() (array key is the action
* function name) or actions_get_all_actions() (array key is the action ID).
+ *
* @return
* The corresponding array key, or FALSE if no match is found.
*/
@@ -332,6 +336,7 @@
* to Jim'.
* @param $aid
* The ID of this action. If omitted, a new action is created.
+ *
* @return
* The ID of the action.
*/
@@ -361,6 +366,7 @@
*
* @param $aid
* The ID of the action to retrieve.
+ *
* @return
* The appropriate action row from the database as an object.
*/
@@ -380,4 +386,3 @@
->execute();
module_invoke_all('actions_delete', $aid);
}
-
diff -Naur drupal-7.9/includes/ajax.inc drupal-7.66/includes/ajax.inc
--- drupal-7.9/includes/ajax.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/ajax.inc 2019-04-17 22:20:46.000000000 +0200
@@ -24,7 +24,8 @@
* ajax_form_callback() and a defined #ajax['callback'] function.
* However, you may optionally specify a different path to request or a
* different callback function to invoke, which can return updated HTML or can
- * also return a richer set of @link ajax_commands Ajax framework commands @endlink.
+ * also return a richer set of
+ * @link ajax_commands Ajax framework commands @endlink.
*
* Standard form handling is as follows:
* - A form element has a #ajax property that includes #ajax['callback'] and
@@ -101,7 +102,7 @@
* In the above example, the 'changethis' element is Ajax-enabled. The default
* #ajax['event'] is 'change', so when the 'changethis' element changes,
* an Ajax call is made. The form is submitted and reprocessed, and then the
- * callback is called. In this case, the form has been automatically
+ * callback is called. In this case, the form has been automatically
* built changing $form['replace_textfield']['#description'], so the callback
* just returns that part of the form.
*
@@ -167,7 +168,7 @@
* displayed while awaiting a response from the callback, and add an optional
* message. Possible keys: 'type', 'message', 'url', 'interval'.
* More information is available in the
- * @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7 Form API Reference @endlink
+ * @link forms_api_reference.html Form API Reference @endlink
*
* In addition to using Form API for doing in-form modification, Ajax may be
* enabled by adding classes to buttons and links. By adding the 'use-ajax'
@@ -188,11 +189,11 @@
* be converted to a JSON object and returned to the client, which will then
* iterate over the array and process it like a macro language.
*
- * Each command item is an associative array which will be converted to a command
- * object on the JavaScript side. $command_item['command'] is the type of
- * command, e.g. 'alert' or 'replace', and will correspond to a method in the
- * Drupal.ajax[command] space. The command array may contain any other data
- * that the command needs to process, e.g. 'method', 'selector', 'settings', etc.
+ * Each command item is an associative array which will be converted to a
+ * command object on the JavaScript side. $command_item['command'] is the type
+ * of command, e.g. 'alert' or 'replace', and will correspond to a method in the
+ * Drupal.ajax[command] space. The command array may contain any other data that
+ * the command needs to process, e.g. 'method', 'selector', 'settings', etc.
*
* Commands are usually created with a couple of helper functions, so they
* look like this:
@@ -210,7 +211,7 @@
*
* When returning an Ajax command array, it is often useful to have
* status messages rendered along with other tasks in the command array.
- * In that case the the Ajax commands array may be constructed like this:
+ * In that case the Ajax commands array may be constructed like this:
* @code
* $commands = array();
* $commands[] = ajax_command_replace(NULL, $output);
@@ -222,13 +223,17 @@
*/
/**
- * Render a commands array into JSON.
+ * Renders a commands array into JSON.
*
* @param $commands
* A list of macro commands generated by the use of ajax_command_*()
* functions.
*/
function ajax_render($commands = array()) {
+ // Although ajax_deliver() does this, some contributed and custom modules
+ // render Ajax responses without using that delivery callback.
+ ajax_set_verification_header();
+
// Ajax responses aren't rendered with html.tpl.php, so we have to call
// drupal_get_css() and drupal_get_js() here, in order to have new files added
// during this request to be loaded by the page. We only want to send back
@@ -250,8 +255,8 @@
// reliably diffed with array_diff_key(), since the number can change
// due to factors unrelated to the inline content, so for now, we strip
// the inline items from Ajax responses, and can add support for them
- // when drupal_add_css() and drupal_add_js() are changed to using md5()
- // or some other hash of the inline content.
+ // when drupal_add_css() and drupal_add_js() are changed to use a hash
+ // of the inline content as the array key.
foreach ($items[$type] as $key => $item) {
if (is_numeric($key)) {
unset($items[$type][$key]);
@@ -262,26 +267,20 @@
}
}
- // Settings are handled separately, later in this function, so that changes to
- // the ajaxPageState setting that occur during drupal_get_css() and
- // drupal_get_js() get included, and because the jQuery.extend() code produced
- // by drupal_get_js() for adding settings isn't appropriate during an Ajax
- // response, because it does not pass TRUE for the "deep" parameter, and
- // therefore, can clobber existing settings on the page.
+ // Render the HTML to load these files, and add AJAX commands to insert this
+ // HTML in the page. We pass TRUE as the $skip_alter argument to prevent the
+ // data from being altered again, as we already altered it above. Settings are
+ // handled separately, afterwards.
if (isset($items['js']['settings'])) {
unset($items['js']['settings']);
}
-
- // Render the HTML to load these files, and add Ajax commands to insert this
- // HTML in the page. We pass TRUE as the $skip_alter argument to prevent the
- // data from being altered again, as we already altered it above.
$styles = drupal_get_css($items['css'], TRUE);
$scripts_footer = drupal_get_js('footer', $items['js'], TRUE);
$scripts_header = drupal_get_js('header', $items['js'], TRUE);
$extra_commands = array();
if (!empty($styles)) {
- $extra_commands[] = ajax_command_prepend('head', $styles);
+ $extra_commands[] = ajax_command_add_css($styles);
}
if (!empty($scripts_header)) {
$extra_commands[] = ajax_command_prepend('head', $scripts_header);
@@ -293,12 +292,11 @@
$commands = array_merge($extra_commands, $commands);
}
+ // Now add a command to merge changes and additions to Drupal.settings.
$scripts = drupal_add_js();
if (!empty($scripts['settings'])) {
$settings = $scripts['settings'];
- // Automatically extract any settings added via drupal_add_js() and make
- // them the first command.
- array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));
+ array_unshift($commands, ajax_command_settings(drupal_array_merge_deep_array($settings['data']), TRUE));
}
// Allow modules to alter any Ajax response.
@@ -308,16 +306,17 @@
}
/**
- * Get a form submitted via #ajax during an Ajax callback.
+ * Gets a form submitted via #ajax during an Ajax callback.
*
* This will load a form from the form cache used during Ajax operations. It
* pulls the form info from $_POST.
*
* @return
- * An array containing the $form and $form_state. Use the list() function
- * to break these apart:
+ * An array containing the $form, $form_state, $form_id, $form_build_id and an
+ * initial list of Ajax $commands. Use the list() function to break these
+ * apart:
* @code
- * list($form, $form_state, $form_id, $form_build_id) = ajax_get_form();
+ * list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();
* @endcode
*/
function ajax_get_form() {
@@ -337,6 +336,17 @@
drupal_exit();
}
+ // When a page level cache is enabled, the form-build id might have been
+ // replaced from within form_get_cache. If this is the case, it is also
+ // necessary to update it in the browser by issuing an appropriate Ajax
+ // command.
+ $commands = array();
+ if (isset($form['#build_id_old']) && $form['#build_id_old'] != $form['#build_id']) {
+ // If the form build ID has changed, issue an Ajax command to update it.
+ $commands[] = ajax_command_update_build_id($form);
+ $form_build_id = $form['#build_id'];
+ }
+
// Since some of the submit handlers are run, redirects need to be disabled.
$form_state['no_redirect'] = TRUE;
@@ -351,7 +361,7 @@
$form_state['input'] = $_POST;
$form_id = $form['#form_id'];
- return array($form, $form_state, $form_id, $form_build_id);
+ return array($form, $form_state, $form_id, $form_build_id, $commands);
}
/**
@@ -368,9 +378,11 @@
* #ajax['path']. If processing is required that cannot be accomplished with
* a callback, re-implement this function and set #ajax['path'] to the
* enhanced function.
+ *
+ * @see system_menu()
*/
function ajax_form_callback() {
- list($form, $form_state) = ajax_get_form();
+ list($form, $form_state, $form_id, $form_build_id, $commands) = ajax_get_form();
drupal_process_form($form['#form_id'], $form, $form_state);
// We need to return the part of the form (or some other content) that needs
@@ -382,8 +394,20 @@
if (!empty($form_state['triggering_element'])) {
$callback = $form_state['triggering_element']['#ajax']['callback'];
}
- if (!empty($callback) && function_exists($callback)) {
- return $callback($form, $form_state);
+ if (!empty($callback) && is_callable($callback)) {
+ $result = $callback($form, $form_state);
+
+ if (!(is_array($result) && isset($result['#type']) && $result['#type'] == 'ajax')) {
+ // Turn the response into a #type=ajax array if it isn't one already.
+ $result = array(
+ '#type' => 'ajax',
+ '#commands' => ajax_prepare_response($result),
+ );
+ }
+
+ $result['#commands'] = array_merge($commands, $result['#commands']);
+
+ return $result;
}
}
@@ -403,6 +427,9 @@
* of the page. Therefore, system_menu() sets the 'theme callback' for
* 'system/ajax' to this function, and it is recommended that modules
* implementing other generic Ajax paths do the same.
+ *
+ * @see system_menu()
+ * @see file_menu()
*/
function ajax_base_page_theme() {
if (!empty($_POST['ajax_page_state']['theme']) && !empty($_POST['ajax_page_state']['theme_token'])) {
@@ -421,7 +448,7 @@
}
/**
- * Package and send the result of a page callback to the browser as an Ajax response.
+ * Packages and sends the result of a page callback as an Ajax response.
*
* This function is the equivalent of drupal_deliver_html_page(), but for Ajax
* requests. Like that function, it:
@@ -464,6 +491,9 @@
}
}
+ // Let ajax.js know that this response is safe to process.
+ ajax_set_verification_header();
+
// Print the response.
$commands = ajax_prepare_response($page_callback_result);
$json = ajax_render($commands);
@@ -554,7 +584,30 @@
}
/**
- * Perform end-of-Ajax-request tasks.
+ * Sets a response header for ajax.js to trust the response body.
+ *
+ * It is not safe to invoke Ajax commands within user-uploaded files, so this
+ * header protects against those being invoked.
+ *
+ * @see Drupal.ajax.options.success()
+ */
+function ajax_set_verification_header() {
+ $added = &drupal_static(__FUNCTION__);
+
+ // User-uploaded files cannot set any response headers, so a custom header is
+ // used to indicate to ajax.js that this response is safe. Note that most
+ // Ajax requests bound using the Form API will be protected by having the URL
+ // flagged as trusted in Drupal.settings, so this header is used only for
+ // things like custom markup that gets Ajax behaviors attached.
+ if (empty($added)) {
+ drupal_add_http_header('X-Drupal-Ajax-Token', '1');
+ // Avoid sending the header twice.
+ $added = TRUE;
+ }
+}
+
+/**
+ * Performs end-of-Ajax-request tasks.
*
* This function is the equivalent of drupal_page_footer(), but for Ajax
* requests.
@@ -577,7 +630,7 @@
}
/**
- * Form element process callback to handle #ajax.
+ * Form element processing handler for the #ajax form property.
*
* @param $element
* An associative array containing the properties of the element.
@@ -596,7 +649,7 @@
}
/**
- * Add Ajax information about an element to the page to communicate with JavaScript.
+ * Adds Ajax information about an element to communicate with JavaScript.
*
* If #ajax['path'] is set on an element, this additional JavaScript is added
* to the page header to attach the Ajax behaviors. See ajax.js for more
@@ -741,7 +794,12 @@
$element['#attached']['js'][] = array(
'type' => 'setting',
- 'data' => array('ajax' => array($element['#id'] => $settings)),
+ 'data' => array(
+ 'ajax' => array($element['#id'] => $settings),
+ 'urlIsAjaxTrusted' => array(
+ $settings['url'] => TRUE,
+ ),
+ ),
);
// Indicate that Ajax processing was successful.
@@ -837,7 +895,8 @@
* @return
* An array suitable for use with the ajax_render() function.
*
- * See @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
+ * See
+ * @link http://docs.jquery.com/Manipulation/replaceWith#content jQuery replaceWith command @endlink
*/
function ajax_command_replace($selector, $html, $settings = NULL) {
return array(
@@ -1211,3 +1270,48 @@
);
}
+/**
+ * Creates a Drupal Ajax 'update_build_id' command.
+ *
+ * This command updates the value of a hidden form_build_id input element on a
+ * form. It requires the form passed in to have keys for both the old build ID
+ * in #build_id_old and the new build ID in #build_id.
+ *
+ * The primary use case for this Ajax command is to serve a new build ID to a
+ * form served from the cache to an anonymous user, preventing one anonymous
+ * user from accessing the form state of another anonymous users on Ajax enabled
+ * forms.
+ *
+ * @param $form
+ * The form array representing the form whose build ID should be updated.
+ */
+function ajax_command_update_build_id($form) {
+ return array(
+ 'command' => 'updateBuildId',
+ 'old' => $form['#build_id_old'],
+ 'new' => $form['#build_id'],
+ );
+}
+
+/**
+ * Creates a Drupal Ajax 'add_css' command.
+ *
+ * This method will add css via ajax in a cross-browser compatible way.
+ *
+ * This command is implemented by Drupal.ajax.prototype.commands.add_css()
+ * defined in misc/ajax.js.
+ *
+ * @param $styles
+ * A string that contains the styles to be added.
+ *
+ * @return
+ * An array suitable for use with the ajax_render() function.
+ *
+ * @see misc/ajax.js
+ */
+function ajax_command_add_css($styles) {
+ return array(
+ 'command' => 'add_css',
+ 'data' => $styles,
+ );
+}
diff -Naur drupal-7.9/includes/archiver.inc drupal-7.66/includes/archiver.inc
--- drupal-7.9/includes/archiver.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/archiver.inc 2019-04-17 22:20:46.000000000 +0200
@@ -6,61 +6,63 @@
*/
/**
- * Common interface for all Archiver classes.
+ * Defines the common interface for all Archiver classes.
*/
interface ArchiverInterface {
/**
- * Constructor for a new archiver instance.
+ * Constructs a new archiver instance.
*
* @param $file_path
- * The full system path of the archive to manipulate. Only local files
- * are supported. If the file does not yet exist, it will be created if
+ * The full system path of the archive to manipulate. Only local files
+ * are supported. If the file does not yet exist, it will be created if
* appropriate.
*/
public function __construct($file_path);
/**
- * Add the specified file or directory to the archive.
+ * Adds the specified file or directory to the archive.
*
* @param $file_path
* The full system path of the file or directory to add. Only local files
* and directories are supported.
+ *
* @return ArchiverInterface
* The called object.
*/
public function add($file_path);
/**
- * Remove the specified file from the archive.
+ * Removes the specified file from the archive.
*
* @param $path
* The file name relative to the root of the archive to remove.
+ *
* @return ArchiverInterface
* The called object.
*/
public function remove($path);
/**
- * Extract multiple files in the archive to the specified path.
+ * Extracts multiple files in the archive to the specified path.
*
* @param $path
* A full system path of the directory to which to extract files.
* @param $files
* Optionally specify a list of files to be extracted. Files are
* relative to the root of the archive. If not specified, all files
- * in the archive will be extracted
+ * in the archive will be extracted.
+ *
* @return ArchiverInterface
* The called object.
*/
- public function extract($path, Array $files = array());
+ public function extract($path, array $files = array());
/**
- * List all files in the archive.
+ * Lists all files in the archive.
*
* @return
* An array of file names relative to the root of the archive.
*/
public function listContents();
}
-
diff -Naur drupal-7.9/includes/authorize.inc drupal-7.66/includes/authorize.inc
--- drupal-7.9/includes/authorize.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/authorize.inc 2019-04-17 22:20:46.000000000 +0200
@@ -6,13 +6,19 @@
*/
/**
- * Build the form for choosing a FileTransfer type and supplying credentials.
+ * Form constructor for the file transfer authorization form.
+ *
+ * Allows the user to choose a FileTransfer type and supply credentials.
+ *
+ * @see authorize_filetransfer_form_validate()
+ * @see authorize_filetransfer_form_submit()
+ * @ingroup forms
*/
function authorize_filetransfer_form($form, &$form_state) {
global $base_url, $is_https;
$form = array();
- // If possible, we want to post this form securely via https.
+ // If possible, we want to post this form securely via HTTPS.
$form['#https'] = TRUE;
// CSS we depend on lives in modules/system/maintenance.css, which is loaded
@@ -127,10 +133,11 @@
}
/**
- * Generate the Form API array for the settings for a given connection backend.
+ * Generates the Form API array for a given connection backend's settings.
*
* @param $backend
* The name of the backend (e.g. 'ftp', 'ssh', etc).
+ *
* @return
* Form API array of connection settings for the given backend.
*
@@ -151,7 +158,7 @@
}
/**
- * Recursively fill in the default settings on a file transfer connection form.
+ * Sets the default settings on a file transfer connection form recursively.
*
* The default settings for the file transfer connection forms are saved in
* the database. The settings are stored as a nested array in the case of a
@@ -165,8 +172,6 @@
* The key for our current form element, if any.
* @param array $defaults
* The default settings for the file transfer backend we're operating on.
- * @return
- * Nothing, this function just sets $element['#default_value'] if needed.
*/
function _authorize_filetransfer_connection_settings_set_defaults(&$element, $key, array $defaults) {
// If we're operating on a form element which isn't a fieldset, and we have
@@ -186,9 +191,10 @@
}
/**
- * Validate callback for the filetransfer authorization form.
+ * Form validation handler for authorize_filetransfer_form().
*
* @see authorize_filetransfer_form()
+ * @see authorize_filetransfer_submit()
*/
function authorize_filetransfer_form_validate($form, &$form_state) {
// Only validate the form if we have collected all of the user input and are
@@ -218,9 +224,10 @@
}
/**
- * Submit callback when a file transfer is being authorized.
+ * Form submission handler for authorize_filetransfer_form().
*
* @see authorize_filetransfer_form()
+ * @see authorize_filetransfer_validate()
*/
function authorize_filetransfer_form_submit($form, &$form_state) {
global $base_url;
@@ -280,7 +287,7 @@
}
/**
- * Run the operation specified in $_SESSION['authorize_operation']
+ * Runs the operation specified in $_SESSION['authorize_operation'].
*
* @param $filetransfer
* The FileTransfer object to use for running the operation.
@@ -298,12 +305,13 @@
}
/**
- * Get a FileTransfer class for a specific transfer method and settings.
+ * Gets a FileTransfer class for a specific transfer method and settings.
*
* @param $backend
* The FileTransfer backend to get the class for.
* @param $settings
* Array of settings for the FileTransfer.
+ *
* @return
* An instantiated FileTransfer object for the requested method and settings,
* or FALSE if there was an error finding or instantiating it.
diff -Naur drupal-7.9/includes/batch.inc drupal-7.66/includes/batch.inc
--- drupal-7.9/includes/batch.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/batch.inc 2019-04-17 22:20:46.000000000 +0200
@@ -1,6 +1,5 @@
getAllItems();
- $batch_set['finished']($batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
+ call_user_func($batch_set['finished'], $batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
}
}
}
@@ -521,7 +524,10 @@
}
/**
- * Shutdown function; store the current batch data for the next request.
+ * Shutdown function: Stores the current batch data for the next request.
+ *
+ * @see _batch_page()
+ * @see drupal_register_shutdown_function()
*/
function _batch_shutdown() {
if ($batch = batch_get()) {
@@ -531,4 +537,3 @@
->execute();
}
}
-
diff -Naur drupal-7.9/includes/batch.queue.inc drupal-7.66/includes/batch.queue.inc
--- drupal-7.9/includes/batch.queue.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/batch.queue.inc 2019-04-17 22:20:46.000000000 +0200
@@ -1,24 +1,30 @@
$this->name))->fetchObject();
if ($item) {
@@ -29,9 +35,9 @@
}
/**
- * Retrieve all remaining items in the queue.
+ * Retrieves all remaining items in the queue.
*
- * This is specific to Batch API and is not part of the DrupalQueueInterface,
+ * This is specific to Batch API and is not part of the DrupalQueueInterface.
*/
public function getAllItems() {
$result = array();
@@ -44,10 +50,17 @@
}
/**
- * Batch queue implementation used for non-progressive batches.
+ * Defines a batch queue for non-progressive batches.
*/
class BatchMemoryQueue extends MemoryQueue {
+ /**
+ * Overrides MemoryQueue::claimItem().
+ *
+ * Unlike MemoryQueue::claimItem(), this method provides a default lease
+ * time of 0 (no expiration) instead of 30. This allows the item to be
+ * claimed repeatedly until it is deleted.
+ */
public function claimItem($lease_time = 0) {
if (!empty($this->queue)) {
reset($this->queue);
@@ -57,9 +70,9 @@
}
/**
- * Retrieve all remaining items in the queue.
+ * Retrieves all remaining items in the queue.
*
- * This is specific to Batch API and is not part of the DrupalQueueInterface,
+ * This is specific to Batch API and is not part of the DrupalQueueInterface.
*/
public function getAllItems() {
$result = array();
diff -Naur drupal-7.9/includes/bootstrap.inc drupal-7.66/includes/bootstrap.inc
--- drupal-7.9/includes/bootstrap.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/bootstrap.inc 2019-04-17 22:20:46.000000000 +0200
@@ -8,7 +8,7 @@
/**
* The current system version.
*/
-define('VERSION', '7.9');
+define('VERSION', '7.66');
/**
* Core API compatibility.
@@ -26,6 +26,21 @@
define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '32M');
/**
+ * Error reporting level: display no errors.
+ */
+define('ERROR_REPORTING_HIDE', 0);
+
+/**
+ * Error reporting level: display errors and warnings.
+ */
+define('ERROR_REPORTING_DISPLAY_SOME', 1);
+
+/**
+ * Error reporting level: display all messages.
+ */
+define('ERROR_REPORTING_DISPLAY_ALL', 2);
+
+/**
* Indicates that the item should never be removed unless explicitly selected.
*
* The item may be removed using cache_clear_all() with a cache ID.
@@ -43,9 +58,9 @@
* Logging severity levels as defined in RFC 3164.
*
* The WATCHDOG_* constant definitions correspond to the logging severity levels
- * defined in RFC 3164, section 4.1.1. PHP supplies predefined LOG_* constants
+ * defined in RFC 3164, section 4.1.1. PHP supplies predefined LOG_* constants
* for use in the syslog() function, but their values on Windows builds do not
- * correspond to RFC 3164. The associated PHP bug report was closed with the
+ * correspond to RFC 3164. The associated PHP bug report was closed with the
* comment, "And it's also not a bug, as Windows just have less log levels,"
* and "So the behavior you're seeing is perfectly normal."
*
@@ -68,32 +83,32 @@
define('WATCHDOG_ALERT', 1);
/**
- * Log message severity -- Critical: critical conditions.
+ * Log message severity -- Critical conditions.
*/
define('WATCHDOG_CRITICAL', 2);
/**
- * Log message severity -- Error: error conditions.
+ * Log message severity -- Error conditions.
*/
define('WATCHDOG_ERROR', 3);
/**
- * Log message severity -- Warning: warning conditions.
+ * Log message severity -- Warning conditions.
*/
define('WATCHDOG_WARNING', 4);
/**
- * Log message severity -- Notice: normal but significant condition.
+ * Log message severity -- Normal but significant conditions.
*/
define('WATCHDOG_NOTICE', 5);
/**
- * Log message severity -- Informational: informational messages.
+ * Log message severity -- Informational messages.
*/
define('WATCHDOG_INFO', 6);
/**
- * Log message severity -- Debug: debug-level messages.
+ * Log message severity -- Debug-level messages.
*/
define('WATCHDOG_DEBUG', 7);
@@ -137,8 +152,7 @@
define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
/**
- * Final bootstrap phase: Drupal is fully loaded; validate and fix
- * input data.
+ * Final bootstrap phase: Drupal is fully loaded; validate and fix input data.
*/
define('DRUPAL_BOOTSTRAP_FULL', 7);
@@ -153,8 +167,9 @@
define('DRUPAL_AUTHENTICATED_RID', 2);
/**
- * The number of bytes in a kilobyte. For more information, visit
- * http://en.wikipedia.org/wiki/Kilobyte.
+ * The number of bytes in a kilobyte.
+ *
+ * For more information, visit http://en.wikipedia.org/wiki/Kilobyte.
*/
define('DRUPAL_KILOBYTE', 1024);
@@ -191,20 +206,28 @@
define('LANGUAGE_RTL', 1);
/**
- * For convenience, define a short form of the request time global.
+ * Time of the current request in seconds elapsed since the Unix Epoch.
+ *
+ * This differs from $_SERVER['REQUEST_TIME'], which is stored as a float
+ * since PHP 5.4.0. Float timestamps confuse most PHP functions
+ * (including date_create()).
*
- * REQUEST_TIME is a float with microseconds since PHP 5.4.0, but float
- * timestamps confuses most of the PHP functions (including date_create()).
+ * @see http://php.net/manual/reserved.variables.server.php
+ * @see http://php.net/manual/function.time.php
*/
define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
/**
- * Flag for drupal_set_title(); text is not sanitized, so run check_plain().
+ * Flag used to indicate that text is not sanitized, so run check_plain().
+ *
+ * @see drupal_set_title()
*/
define('CHECK_PLAIN', 0);
/**
- * Flag for drupal_set_title(); text has already been sanitized.
+ * Flag used to indicate that text has already been sanitized.
+ *
+ * @see drupal_set_title()
*/
define('PASS_THROUGH', -1);
@@ -221,11 +244,25 @@
/**
* Regular expression to match PHP function names.
*
- * @see http://php.net/manual/en/language.functions.php
+ * @see http://php.net/manual/language.functions.php
*/
define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*');
/**
+ * A RFC7231 Compliant date.
+ *
+ * http://tools.ietf.org/html/rfc7231#section-7.1.1.1
+ *
+ * Example: Sun, 06 Nov 1994 08:49:37 GMT
+ *
+ * This constant was introduced in PHP 7.0.19 and PHP 7.1.5 but needs to be
+ * defined by Drupal for earlier PHP versions.
+ */
+if (!defined('DATE_RFC7231')) {
+ define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T');
+}
+
+/**
* Provides a caching wrapper to be used in place of large array structures.
*
* This class should be extended by systems that need to cache large amounts
@@ -255,7 +292,7 @@
* error, and $var will be populated with the contents of $object['foo'], but
* that data will be passed by value, not reference. For more information on
* the PHP limitation, see the note in the official PHP documentation at·
- * http://php.net/manual/en/arrayaccess.offsetget.php on
+ * http://php.net/manual/arrayaccess.offsetget.php on
* ArrayAccess::offsetGet().
*
* By default, the class accounts for caches where calling functions might
@@ -275,7 +312,7 @@
* means that assigning an offset via arrayAccess will only apply while the
* object is in scope and will not be written back to the persistent cache.
* This follows a similar pattern to static vs. persistent caching in
- * procedural code. Extending classes may wish to alter this behaviour, for
+ * procedural code. Extending classes may wish to alter this behavior, for
* example by overriding offsetSet() and adding an automatic call to persist().
*
* @see SchemaCache
@@ -285,12 +322,12 @@
/**
* A cid to pass to cache_set() and cache_get().
*/
- private $cid;
+ protected $cid;
/**
* A bin to pass to cache_set() and cache_get().
*/
- private $bin;
+ protected $bin;
/**
* An array of keys to add to the cache at the end of the request.
@@ -303,7 +340,7 @@
protected $storage = array();
/**
- * Constructor.
+ * Constructs a DrupalCacheArray object.
*
* @param $cid
* The cid for the array being cached.
@@ -319,10 +356,16 @@
}
}
+ /**
+ * Implements ArrayAccess::offsetExists().
+ */
public function offsetExists($offset) {
return $this->offsetGet($offset) !== NULL;
}
+ /**
+ * Implements ArrayAccess::offsetGet().
+ */
public function offsetGet($offset) {
if (isset($this->storage[$offset]) || array_key_exists($offset, $this->storage)) {
return $this->storage[$offset];
@@ -332,10 +375,16 @@
}
}
+ /**
+ * Implements ArrayAccess::offsetSet().
+ */
public function offsetSet($offset, $value) {
$this->storage[$offset] = $value;
}
+ /**
+ * Implements ArrayAccess::offsetUnset().
+ */
public function offsetUnset($offset) {
unset($this->storage[$offset]);
}
@@ -349,11 +398,11 @@
* without necessarily writing back to the persistent cache at the end.
*
* @param $offset
- * The array offset that was request.
+ * The array offset that was requested.
* @param $persist
* Optional boolean to specify whether the offset should be persisted or
* not, defaults to TRUE. When called with $persist = FALSE the offset will
- * be unflagged so that it will not written at the end of the request.
+ * be unflagged so that it will not be written at the end of the request.
*/
protected function persist($offset, $persist = TRUE) {
$this->keysToPersist[$offset] = $persist;
@@ -375,32 +424,31 @@
abstract protected function resolveCacheMiss($offset);
/**
- * Immediately write a value to the persistent cache.
+ * Writes a value to the persistent cache immediately.
*
- * @param $cid
- * The cache ID.
- * @param $bin
- * The cache bin.
* @param $data
* The data to write to the persistent cache.
* @param $lock
* Whether to acquire a lock before writing to cache.
*/
- protected function set($cid, $data, $bin, $lock = TRUE) {
+ protected function set($data, $lock = TRUE) {
// Lock cache writes to help avoid stampedes.
// To implement locking for cache misses, override __construct().
- $lock_name = $cid . ':' . $bin;
+ $lock_name = $this->cid . ':' . $this->bin;
if (!$lock || lock_acquire($lock_name)) {
- if ($cached = cache_get($cid, $bin)) {
+ if ($cached = cache_get($this->cid, $this->bin)) {
$data = $cached->data + $data;
}
- cache_set($cid, $data, $bin);
+ cache_set($this->cid, $data, $this->bin);
if ($lock) {
lock_release($lock_name);
}
}
}
+ /**
+ * Destructs the DrupalCacheArray object.
+ */
public function __destruct() {
$data = array();
foreach ($this->keysToPersist as $offset => $persist) {
@@ -409,14 +457,16 @@
}
}
if (!empty($data)) {
- $this->set($this->cid, $data, $this->bin);
+ $this->set($data);
}
}
}
/**
- * Start the timer with the specified name. If you start and stop the same
- * timer multiple times, the measured intervals will be accumulated.
+ * Starts the timer with the specified name.
+ *
+ * If you start and stop the same timer multiple times, the measured intervals
+ * will be accumulated.
*
* @param $name
* The name of the timer.
@@ -429,7 +479,7 @@
}
/**
- * Read the current timer value without stopping the timer.
+ * Reads the current timer value without stopping the timer.
*
* @param $name
* The name of the timer.
@@ -453,7 +503,7 @@
}
/**
- * Stop the timer with the specified name.
+ * Stops the timer with the specified name.
*
* @param $name
* The name of the timer.
@@ -481,56 +531,11 @@
}
/**
- * Finds the appropriate configuration directory.
+ * Returns the appropriate configuration directory.
*
- * Finds a matching configuration directory by stripping the website's
- * hostname from left to right and pathname from right to left. The first
- * configuration file found will be used and the remaining ones will be ignored.
- * If no configuration file is found, return a default value '$confdir/default'.
- *
- * With a site located at http://www.example.com:8080/mysite/test/, the file,
- * settings.php, is searched for in the following directories:
- *
- * - $confdir/8080.www.example.com.mysite.test
- * - $confdir/www.example.com.mysite.test
- * - $confdir/example.com.mysite.test
- * - $confdir/com.mysite.test
- *
- * - $confdir/8080.www.example.com.mysite
- * - $confdir/www.example.com.mysite
- * - $confdir/example.com.mysite
- * - $confdir/com.mysite
- *
- * - $confdir/8080.www.example.com
- * - $confdir/www.example.com
- * - $confdir/example.com
- * - $confdir/com
- *
- * - $confdir/default
- *
- * If a file named sites.php is present in the $confdir, it will be loaded
- * prior to scanning for directories. It should define an associative array
- * named $sites, which maps domains to directories. It should be in the form
- * of:
- * @code
- * $sites = array(
- * 'The url to alias' => 'A directory within the sites directory'
- * );
- * @endcode
- * For example:
- * @code
- * $sites = array(
- * 'devexample.com' => 'example.com',
- * 'localhost.example' => 'example.com',
- * );
- * @endcode
- * The above array will cause Drupal to look for a directory named
- * "example.com" in the sites directory whenever a request comes from
- * "example.com", "devexample.com", or "localhost/example". That is useful
- * on development servers, where the domain name may not be the same as the
- * domain of the live server. Since Drupal stores file paths into the database
- * (files, system table, etc.) this will ensure the paths are correct while
- * accessed on development servers.
+ * Returns the configuration path based on the site's hostname, port, and
+ * pathname. See default.settings.php for examples on how the URL is converted
+ * to a directory.
*
* @param bool $require_settings
* Only configuration directories with an existing settings.php file
@@ -543,6 +548,8 @@
*
* @return
* The path of the matching directory.
+ *
+ * @see default.settings.php
*/
function conf_path($require_settings = TRUE, $reset = FALSE) {
$conf = &drupal_static(__FUNCTION__, '');
@@ -578,7 +585,7 @@
}
/**
- * Set appropriate server variables needed for command line scripts to work.
+ * Sets appropriate server variables needed for command line scripts to work.
*
* This function can be called by command line scripts before bootstrapping
* Drupal, to ensure that the page loads with the desired server parameters.
@@ -640,7 +647,7 @@
}
/**
- * Initialize PHP environment.
+ * Initializes the PHP environment.
*/
function drupal_environment_initialize() {
if (!isset($_SERVER['HTTP_REFERER'])) {
@@ -689,45 +696,74 @@
ini_set('session.use_only_cookies', '1');
ini_set('session.use_trans_sid', '0');
// Don't send HTTP headers using PHP's session handler.
- ini_set('session.cache_limiter', 'none');
+ // An empty string is used here to disable the cache limiter.
+ ini_set('session.cache_limiter', '');
// Use httponly session cookies.
ini_set('session.cookie_httponly', '1');
// Set sane locale settings, to ensure consistent string, dates, times and
// numbers handling.
setlocale(LC_ALL, 'C');
+
+ // PHP's built-in phar:// stream wrapper is not sufficiently secure. Override
+ // it with a more secure one, which requires PHP 5.3.3. For lower versions,
+ // unregister the built-in one without replacing it. Sites needing phar
+ // support for lower PHP versions must implement hook_stream_wrappers() to
+ // register their desired implementation.
+ if (in_array('phar', stream_get_wrappers(), TRUE)) {
+ stream_wrapper_unregister('phar');
+ if (version_compare(PHP_VERSION, '5.3.3', '>=')) {
+ include_once DRUPAL_ROOT . '/includes/file.phar.inc';
+ file_register_phar_wrapper();
+ }
+ }
}
/**
- * Validate that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
+ * Validates that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
*
* @return
* TRUE if only containing valid characters, or FALSE otherwise.
*/
function drupal_valid_http_host($host) {
- return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
+ // Limit the length of the host name to 1000 bytes to prevent DoS attacks with
+ // long host names.
+ return strlen($host) <= 1000
+ // Limit the number of subdomains and port separators to prevent DoS attacks
+ // in conf_path().
+ && substr_count($host, '.') <= 100
+ && substr_count($host, ':') <= 100
+ && preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
+}
+
+/**
+ * Checks whether an HTTPS request is being served.
+ *
+ * @return bool
+ * TRUE if the request is HTTPS, FALSE otherwise.
+ */
+function drupal_is_https() {
+ return isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
}
/**
- * Loads the configuration and sets the base URL, cookie domain, and
- * session name correctly.
+ * Sets the base URL, cookie domain, and session name from configuration.
*/
function drupal_settings_initialize() {
global $base_url, $base_path, $base_root;
- // Export the following settings.php variables to the global namespace
+ // Export these settings.php variables to the global namespace.
global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;
$conf = array();
if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
include_once DRUPAL_ROOT . '/' . conf_path() . '/settings.php';
}
- $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
+ $is_https = drupal_is_https();
if (isset($base_url)) {
// Parse fixed base URL from settings.php.
$parts = parse_url($base_url);
- $http_protocol = $parts['scheme'];
if (!isset($parts['path'])) {
$parts['path'] = '';
}
@@ -736,7 +772,7 @@
$base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
}
else {
- // Create base URL
+ // Create base URL.
$http_protocol = $is_https ? 'https' : 'http';
$base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST'];
@@ -762,7 +798,7 @@
}
else {
// Otherwise use $base_url as session name, without the protocol
- // to use the same session identifiers across http and https.
+ // to use the same session identifiers across HTTP and HTTPS.
list( , $session_name) = explode('://', $base_url, 2);
// HTTP_HOST can be modified by a visitor, but we already sanitized it
// in drupal_settings_initialize().
@@ -796,13 +832,14 @@
}
/**
- * Returns and optionally sets the filename for a system item (module,
- * theme, etc.). The filename, whether provided, cached, or retrieved
- * from the database, is only returned if the file exists.
+ * Returns and optionally sets the filename for a system resource.
+ *
+ * The filename, whether provided, cached, or retrieved from the database, is
+ * only returned if the file exists.
*
* This function plays a key role in allowing Drupal's resources (modules
* and themes) to be located in different places depending on a site's
- * configuration. For example, a module 'foo' may legally be be located
+ * configuration. For example, a module 'foo' may legally be located
* in any of these three places:
*
* modules/foo/foo.module
@@ -813,93 +850,337 @@
* the above, depending on where the module is located.
*
* @param $type
- * The type of the item (i.e. theme, theme_engine, module, profile).
+ * The type of the item (theme, theme_engine, module, profile).
* @param $name
* The name of the item for which the filename is requested.
* @param $filename
* The filename of the item if it is to be set explicitly rather
* than by consulting the database.
+ * @param bool $trigger_error
+ * Whether to trigger an error when a file is missing or has unexpectedly
+ * moved. This defaults to TRUE, but can be set to FALSE by calling code that
+ * merely wants to check whether an item exists in the filesystem.
*
* @return
- * The filename of the requested item.
- */
-function drupal_get_filename($type, $name, $filename = NULL) {
+ * The filename of the requested item or NULL if the item is not found.
+ */
+function drupal_get_filename($type, $name, $filename = NULL, $trigger_error = TRUE) {
+ // The $files static variable will hold the locations of all requested files.
+ // We can be sure that any file listed in this static variable actually
+ // exists as all additions have gone through a file_exists() check.
// The location of files will not change during the request, so do not use
// drupal_static().
- static $files = array(), $dirs = array();
+ static $files = array();
+ // Profiles are a special case: they have a fixed location and naming.
+ if ($type == 'profile') {
+ $profile_filename = "profiles/$name/$name.profile";
+ $files[$type][$name] = file_exists($profile_filename) ? $profile_filename : FALSE;
+ }
if (!isset($files[$type])) {
$files[$type] = array();
}
if (!empty($filename) && file_exists($filename)) {
+ // Prime the static cache with the provided filename.
$files[$type][$name] = $filename;
}
elseif (isset($files[$type][$name])) {
- // nothing
+ // This item had already been found earlier in the request, either through
+ // priming of the static cache (for example, in system_list()), through a
+ // lookup in the {system} table, or through a file scan (cached or not). Do
+ // nothing.
}
- // Verify that we have an active database connection, before querying
- // the database. This is required because this function is called both
- // before we have a database connection (i.e. during installation) and
- // when a database connection fails.
else {
+ // Look for the filename listed in the {system} table. Verify that we have
+ // an active database connection before doing so, since this function is
+ // called both before we have a database connection (i.e. during
+ // installation) and when a database connection fails.
+ $database_unavailable = TRUE;
try {
if (function_exists('db_query')) {
$file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField();
- if (file_exists(DRUPAL_ROOT . '/' . $file)) {
+ if ($file !== FALSE && file_exists(DRUPAL_ROOT . '/' . $file)) {
$files[$type][$name] = $file;
}
+ $database_unavailable = FALSE;
}
}
catch (Exception $e) {
// The database table may not exist because Drupal is not yet installed,
- // or the database might be down. We have a fallback for this case so we
- // hide the error completely.
+ // the database might be down, or we may have done a non-database cache
+ // flush while $conf['page_cache_without_database'] = TRUE and
+ // $conf['page_cache_invoke_hooks'] = TRUE. We have a fallback for these
+ // cases so we hide the error completely.
}
- // Fallback to searching the filesystem if the database could not find the
- // file or the file returned by the database is not found.
+ // Fall back to searching the filesystem if the database could not find the
+ // file or the file does not exist at the path returned by the database.
if (!isset($files[$type][$name])) {
- // We have a consistent directory naming: modules, themes...
- $dir = $type . 's';
- if ($type == 'theme_engine') {
- $dir = 'themes/engines';
- $extension = 'engine';
- }
- elseif ($type == 'theme') {
- $extension = 'info';
- }
- else {
- $extension = $type;
- }
+ $files[$type][$name] = _drupal_get_filename_fallback($type, $name, $trigger_error, $database_unavailable);
+ }
+ }
- if (!isset($dirs[$dir][$extension])) {
- $dirs[$dir][$extension] = TRUE;
- if (!function_exists('drupal_system_listing')) {
- require_once DRUPAL_ROOT . '/includes/common.inc';
- }
- // Scan the appropriate directories for all files with the requested
- // extension, not just the file we are currently looking for. This
- // prevents unnecessary scans from being repeated when this function is
- // called more than once in the same page request.
- $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
- foreach ($matches as $matched_name => $file) {
- $files[$type][$matched_name] = $file->uri;
+ if (isset($files[$type][$name])) {
+ return $files[$type][$name];
+ }
+}
+
+/**
+ * Performs a cached file system scan as a fallback when searching for a file.
+ *
+ * This function looks for the requested file by triggering a file scan,
+ * caching the new location if the file has moved and caching the miss
+ * if the file is missing. If a file had been marked as missing in a previous
+ * file scan, or if it has been marked as moved and is still in the last known
+ * location, no new file scan will be performed.
+ *
+ * @param string $type
+ * The type of the item (theme, theme_engine, module, profile).
+ * @param string $name
+ * The name of the item for which the filename is requested.
+ * @param bool $trigger_error
+ * Whether to trigger an error when a file is missing or has unexpectedly
+ * moved.
+ * @param bool $database_unavailable
+ * Whether this function is being called because the Drupal database could
+ * not be queried for the file's location.
+ *
+ * @return
+ * The filename of the requested item or NULL if the item is not found.
+ *
+ * @see drupal_get_filename()
+ */
+function _drupal_get_filename_fallback($type, $name, $trigger_error, $database_unavailable) {
+ $file_scans = &_drupal_file_scan_cache();
+ $filename = NULL;
+
+ // If the cache indicates that the item is missing, or we can verify that the
+ // item exists in the location the cache says it exists in, use that.
+ if (isset($file_scans[$type][$name]) && ($file_scans[$type][$name] === FALSE || file_exists($file_scans[$type][$name]))) {
+ $filename = $file_scans[$type][$name];
+ }
+ // Otherwise, perform a new file scan to find the item.
+ else {
+ $filename = _drupal_get_filename_perform_file_scan($type, $name);
+ // Update the static cache, and mark the persistent cache for updating at
+ // the end of the page request. See drupal_file_scan_write_cache().
+ $file_scans[$type][$name] = $filename;
+ $file_scans['#write_cache'] = TRUE;
+ }
+
+ // If requested, trigger a user-level warning about the missing or
+ // unexpectedly moved file. If the database was unavailable, do not trigger a
+ // warning in the latter case, though, since if the {system} table could not
+ // be queried there is no way to know if the location found here was
+ // "unexpected" or not.
+ if ($trigger_error) {
+ $error_type = $filename === FALSE ? 'missing' : 'moved';
+ if ($error_type == 'missing' || !$database_unavailable) {
+ _drupal_get_filename_fallback_trigger_error($type, $name, $error_type);
+ }
+ }
+
+ // The cache stores FALSE for files that aren't found (to be able to
+ // distinguish them from files that have not yet been searched for), but
+ // drupal_get_filename() expects NULL for these instead, so convert to NULL
+ // before returning.
+ if ($filename === FALSE) {
+ $filename = NULL;
+ }
+ return $filename;
+}
+
+/**
+ * Returns the current list of cached file system scan results.
+ *
+ * @return
+ * An associative array tracking the most recent file scan results for all
+ * files that have had scans performed. The keys are the type and name of the
+ * item that was searched for, and the values can be either:
+ * - Boolean FALSE if the item was not found in the file system.
+ * - A string pointing to the location where the item was found.
+ */
+function &_drupal_file_scan_cache() {
+ $file_scans = &drupal_static(__FUNCTION__, array());
+
+ // The file scan results are stored in a persistent cache (in addition to the
+ // static cache) but because this function can be called before the
+ // persistent cache is available, we must merge any items that were found
+ // earlier in the page request into the results from the persistent cache.
+ if (!isset($file_scans['#cache_merge_done'])) {
+ try {
+ if (function_exists('cache_get')) {
+ $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
+ if (!empty($cache->data)) {
+ // File scan results from the current request should take precedence
+ // over the results from the persistent cache, since they are newer.
+ $file_scans = drupal_array_merge_deep($cache->data, $file_scans);
}
+ // Set a flag to indicate that the persistent cache does not need to be
+ // merged again.
+ $file_scans['#cache_merge_done'] = TRUE;
}
}
+ catch (Exception $e) {
+ // Hide the error.
+ }
}
- if (isset($files[$type][$name])) {
- return $files[$type][$name];
+ return $file_scans;
+}
+
+/**
+ * Performs a file system scan to search for a system resource.
+ *
+ * @param $type
+ * The type of the item (theme, theme_engine, module, profile).
+ * @param $name
+ * The name of the item for which the filename is requested.
+ *
+ * @return
+ * The filename of the requested item or FALSE if the item is not found.
+ *
+ * @see drupal_get_filename()
+ * @see _drupal_get_filename_fallback()
+ */
+function _drupal_get_filename_perform_file_scan($type, $name) {
+ // The location of files will not change during the request, so do not use
+ // drupal_static().
+ static $dirs = array(), $files = array();
+
+ // We have a consistent directory naming: modules, themes...
+ $dir = $type . 's';
+ if ($type == 'theme_engine') {
+ $dir = 'themes/engines';
+ $extension = 'engine';
+ }
+ elseif ($type == 'theme') {
+ $extension = 'info';
+ }
+ else {
+ $extension = $type;
+ }
+
+ // Check if we had already scanned this directory/extension combination.
+ if (!isset($dirs[$dir][$extension])) {
+ // Log that we have now scanned this directory/extension combination
+ // into a static variable so as to prevent unnecessary file scans.
+ $dirs[$dir][$extension] = TRUE;
+ if (!function_exists('drupal_system_listing')) {
+ require_once DRUPAL_ROOT . '/includes/common.inc';
+ }
+ // Scan the appropriate directories for all files with the requested
+ // extension, not just the file we are currently looking for. This
+ // prevents unnecessary scans from being repeated when this function is
+ // called more than once in the same page request.
+ $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
+ foreach ($matches as $matched_name => $file) {
+ // Log the locations found in the file scan into a static variable.
+ $files[$type][$matched_name] = $file->uri;
+ }
+ }
+
+ // Return the results of the file system scan, or FALSE to indicate the file
+ // was not found.
+ return isset($files[$type][$name]) ? $files[$type][$name] : FALSE;
+}
+
+/**
+ * Triggers a user-level warning for missing or unexpectedly moved files.
+ *
+ * @param $type
+ * The type of the item (theme, theme_engine, module, profile).
+ * @param $name
+ * The name of the item for which the filename is requested.
+ * @param $error_type
+ * The type of the error ('missing' or 'moved').
+ *
+ * @see drupal_get_filename()
+ * @see _drupal_get_filename_fallback()
+ */
+function _drupal_get_filename_fallback_trigger_error($type, $name, $error_type) {
+ // Hide messages due to known bugs that will appear on a lot of sites.
+ // @todo Remove this in https://www.drupal.org/node/2383823
+ if (empty($name)) {
+ return;
+ }
+
+ // Make sure we only show any missing or moved file errors only once per
+ // request.
+ static $errors_triggered = array();
+ if (empty($errors_triggered[$type][$name][$error_type])) {
+ // Use _drupal_trigger_error_with_delayed_logging() here since these are
+ // triggered during low-level operations that cannot necessarily be
+ // interrupted by a watchdog() call.
+ if ($error_type == 'missing') {
+ _drupal_trigger_error_with_delayed_logging(format_string('The following @type is missing from the file system: %name. For information about how to fix this, see the documentation page.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+ }
+ elseif ($error_type == 'moved') {
+ _drupal_trigger_error_with_delayed_logging(format_string('The following @type has moved within the file system: %name. In order to fix this, clear caches or put the @type back in its original location. For more information, see the documentation page.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+ }
+ $errors_triggered[$type][$name][$error_type] = TRUE;
+ }
+}
+
+/**
+ * Invokes trigger_error() with logging delayed until the end of the request.
+ *
+ * This is an alternative to PHP's trigger_error() function which can be used
+ * during low-level Drupal core operations that need to avoid being interrupted
+ * by a watchdog() call.
+ *
+ * Normally, Drupal's error handler calls watchdog() in response to a
+ * trigger_error() call. However, this invokes hook_watchdog() which can run
+ * arbitrary code. If the trigger_error() happens in the middle of an
+ * operation such as a rebuild operation which should not be interrupted by
+ * arbitrary code, that could potentially break or trigger the rebuild again.
+ * This function protects against that by delaying the watchdog() call until
+ * the end of the current page request.
+ *
+ * This is an internal function which should only be called by low-level Drupal
+ * core functions. It may be removed in a future Drupal 7 release.
+ *
+ * @param string $error_msg
+ * The error message to trigger. As with trigger_error() itself, this is
+ * limited to 1024 bytes; additional characters beyond that will be removed.
+ * @param int $error_type
+ * (optional) The type of error. This should be one of the E_USER family of
+ * constants. As with trigger_error() itself, this defaults to E_USER_NOTICE
+ * if not provided.
+ *
+ * @see _drupal_log_error()
+ */
+function _drupal_trigger_error_with_delayed_logging($error_msg, $error_type = E_USER_NOTICE) {
+ $delay_logging = &drupal_static(__FUNCTION__, FALSE);
+ $delay_logging = TRUE;
+ trigger_error($error_msg, $error_type);
+ $delay_logging = FALSE;
+}
+
+/**
+ * Writes the file scan cache to the persistent cache.
+ *
+ * This cache stores all files marked as missing or moved after a file scan
+ * to prevent unnecessary file scans in subsequent requests. This cache is
+ * cleared in system_list_reset() (i.e. after a module/theme rebuild).
+ */
+function drupal_file_scan_write_cache() {
+ // Only write to the persistent cache if requested, and if we know that any
+ // data previously in the cache was successfully loaded and merged in by
+ // _drupal_file_scan_cache().
+ $file_scans = &_drupal_file_scan_cache();
+ if (isset($file_scans['#write_cache']) && isset($file_scans['#cache_merge_done'])) {
+ unset($file_scans['#write_cache']);
+ cache_set('_drupal_file_scan_cache', $file_scans, 'cache_bootstrap');
}
}
/**
- * Load the persistent variable table.
+ * Loads the persistent variable table.
*
* The variable table is composed of values that have been saved in the table
- * with variable_set() as well as those explicitly specified in the configuration
- * file.
+ * with variable_set() as well as those explicitly specified in the
+ * configuration file.
*/
function variable_initialize($conf = array()) {
// NOTE: caching the variables improves performance by 20% when serving
@@ -944,7 +1225,7 @@
* The default value to use if this variable has never been set.
*
* @return
- * The value of the variable.
+ * The value of the variable. Unserialization is taken care of as necessary.
*
* @see variable_del()
* @see variable_set()
@@ -1006,7 +1287,7 @@
}
/**
- * Retrieve the current page from the cache.
+ * Retrieves the current page from the cache.
*
* Note: we do not serve cached pages to authenticated users, or to anonymous
* users when $_SESSION is non-empty. $_SESSION may contain status messages
@@ -1038,10 +1319,10 @@
}
/**
- * Determine the cacheability of the current page.
+ * Determines the cacheability of the current page.
*
* @param $allow_caching
- * Set to FALSE if you want to prevent this page to get cached.
+ * Set to FALSE if you want to prevent this page from being cached.
*
* @return
* TRUE if the current page can be cached, FALSE otherwise.
@@ -1057,7 +1338,7 @@
}
/**
- * Invoke a bootstrap hook in all bootstrap modules that implement it.
+ * Invokes a bootstrap hook in all bootstrap modules that implement it.
*
* @param $hook
* The name of the bootstrap hook to invoke.
@@ -1079,8 +1360,9 @@
}
/**
- * Includes a file with the provided type and name. This prevents
- * including a theme, engine, module, etc., more than once.
+ * Includes a file with the provided type and name.
+ *
+ * This prevents including a theme, engine, module, etc., more than once.
*
* @param $type
* The type of item to load (i.e. theme, theme_engine, module).
@@ -1112,7 +1394,7 @@
}
/**
- * Set an HTTP response header for the current page.
+ * Sets an HTTP response header for the current page.
*
* Note: When sending a Content-Type header, always include a 'charset' type,
* too. This is necessary to avoid security bugs (e.g. UTF-7 XSS).
@@ -1148,11 +1430,12 @@
}
/**
- * Get the HTTP response headers for the current page.
+ * Gets the HTTP response headers for the current page.
*
* @param $name
* An HTTP header name. If omitted, all headers are returned as name/value
* pairs. If an array value is FALSE, the header has been unset.
+ *
* @return
* A string containing the header value, or FALSE if the header has been set,
* or NULL if the header has not been set.
@@ -1169,6 +1452,8 @@
}
/**
+ * Sets the preferred name for the HTTP header.
+ *
* Header names are case-insensitive, but for maximum compatibility they should
* follow "common form" (see RFC 2617, section 4.2).
*/
@@ -1182,14 +1467,16 @@
}
/**
- * Send the HTTP response headers previously set using drupal_add_http_header().
- * Add default headers, unless they have been replaced or unset using
- * drupal_add_http_header().
- *
- * @param $default_headers
- * An array of headers as name/value pairs.
- * @param $single
- * If TRUE and headers have already be sent, send only the specified header.
+ * Sends the HTTP response headers that were previously set, adding defaults.
+ *
+ * Headers are set in drupal_add_http_header(). Default headers are not set
+ * if they have been replaced or unset using drupal_add_http_header().
+ *
+ * @param array $default_headers
+ * (optional) An array of headers as name/value pairs.
+ * @param bool $only_default
+ * (optional) If TRUE and headers have already been sent, send only the
+ * specified headers.
*/
function drupal_send_headers($default_headers = array(), $only_default = FALSE) {
$headers_sent = &drupal_static(__FUNCTION__, FALSE);
@@ -1212,36 +1499,23 @@
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value);
}
// Skip headers that have been unset.
- elseif ($value) {
+ elseif ($value !== FALSE) {
header($header_names[$name_lower] . ': ' . $value);
}
}
}
/**
- * Set HTTP headers in preparation for a page response.
+ * Sets HTTP headers in preparation for a page response.
*
* Authenticated users are always given a 'no-cache' header, and will fetch a
* fresh page on every request. This prevents authenticated users from seeing
* locally cached pages.
*
- * Also give each page a unique ETag. This will force clients to include both
- * an If-Modified-Since header and an If-None-Match header when doing
- * conditional requests for the page (required by RFC 2616, section 13.3.4),
- * making the validation more robust. This is a workaround for a bug in Mozilla
- * Firefox that is triggered when Drupal's caching is enabled and the user
- * accesses Drupal via an HTTP proxy (see
- * https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an authenticated
- * user requests a page, and then logs out and requests the same page again,
- * Firefox may send a conditional request based on the page that was cached
- * locally when the user was logged in. If this page did not have an ETag
- * header, the request only contains an If-Modified-Since header. The date will
- * be recent, because with authenticated users the Last-Modified header always
- * refers to the time of the request. If the user accesses Drupal via a proxy
- * server, and the proxy already has a cached copy of the anonymous page with an
- * older Last-Modified date, the proxy may respond with 304 Not Modified, making
- * the client think that the anonymous and authenticated pageviews are
- * identical.
+ * ETag and Last-Modified headers are not set per default for authenticated
+ * users so that browsers do not send If-Modified-Since headers from
+ * authenticated user pages. drupal_serve_page_from_cache() will set appropriate
+ * ETag and Last-Modified headers for cached pages.
*
* @see drupal_page_set_cache()
*/
@@ -1254,15 +1528,17 @@
$default_headers = array(
'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT',
- 'Last-Modified' => gmdate(DATE_RFC1123, REQUEST_TIME),
- 'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
- 'ETag' => '"' . REQUEST_TIME . '"',
+ 'Cache-Control' => 'no-cache, must-revalidate',
+ // Prevent browsers from sniffing a response and picking a MIME type
+ // different from the declared content-type, since that can lead to
+ // XSS and other vulnerabilities.
+ 'X-Content-Type-Options' => 'nosniff',
);
drupal_send_headers($default_headers);
}
/**
- * Set HTTP headers in preparation for a cached page response.
+ * Sets HTTP headers in preparation for a cached page response.
*
* The headers allow as much as possible in proxies and browsers without any
* particular knowledge about the pages. Modules can override these headers
@@ -1274,7 +1550,7 @@
*/
function drupal_serve_page_from_cache(stdClass $cache) {
// Negotiate whether to use compression.
- $page_compression = variable_get('page_compression', TRUE) && extension_loaded('zlib');
+ $page_compression = !empty($cache->data['page_compressed']);
$return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE;
// Get headers set in hook_boot(). Keys are lower-case.
@@ -1324,7 +1600,7 @@
drupal_add_http_header($name, $value);
}
- $default_headers['Last-Modified'] = gmdate(DATE_RFC1123, $cache->created);
+ $default_headers['Last-Modified'] = gmdate(DATE_RFC7231, $cache->created);
// HTTP/1.0 proxies does not support the Vary header, so prevent any caching
// by sending an Expires date in the past. HTTP/1.1 clients ignores the
@@ -1365,7 +1641,7 @@
}
/**
- * Define the critical hooks that force modules to always be loaded.
+ * Defines the critical hooks that force modules to always be loaded.
*/
function bootstrap_hooks() {
return array('boot', 'exit', 'watchdog', 'language_init');
@@ -1405,6 +1681,7 @@
* more information, including recommendations on how to break up or not
* break up strings for translation.
*
+ * @section sec_translating_vars Translating Variables
* You should never use t() to translate variables, such as calling
* @code t($text); @endcode, unless the text that the variable holds has been
* passed through t() elsewhere (e.g., $text is one of several translated
@@ -1418,32 +1695,54 @@
* $text = t("@name's blog", array('@name' => format_username($account)));
* @endcode
* Basically, you can put variables like @name into your string, and t() will
- * substitute their sanitized values at translation time (see $args below or
- * the Localization API pages referenced above for details). Translators can
- * then rearrange the string as necessary for the language (e.g., in Spanish,
- * it might be "blog de @name").
+ * substitute their sanitized values at translation time. (See the
+ * Localization API pages referenced above and the documentation of
+ * format_string() for details about how to define variables in your string.)
+ * Translators can then rearrange the string as necessary for the language
+ * (e.g., in Spanish, it might be "blog de @name").
*
+ * @section sec_alt_funcs_install Use During Installation Phase
* During the Drupal installation phase, some resources used by t() wil not be
* available to code that needs localization. See st() and get_t() for
* alternatives.
*
+ * @section sec_context String context
+ * Matching source strings are normally only translated once, and the same
+ * translation is used everywhere that has a matching string. However, in some
+ * cases, a certain English source string needs to have multiple translations.
+ * One example of this is the string "May", which could be used as either a
+ * full month name or a 3-letter abbreviated month. In other languages where
+ * the month name for May has more than 3 letters, you would need to provide
+ * two different translations (one for the full name and one abbreviated), and
+ * the correct form would need to be chosen, depending on how "May" is being
+ * used. To facilitate this, the "May" string should be provided with two
+ * different contexts in the $options parameter when calling t(). For example:
+ * @code
+ * t('May', array(), array('context' => 'Long month name')
+ * t('May', array(), array('context' => 'Abbreviated month name')
+ * @endcode
+ * See https://localize.drupal.org/node/2109 for more information.
+ *
* @param $string
* A string containing the English string to translate.
* @param $args
- * An associative array of replacements to make after translation.
- * See format_string().
+ * An associative array of replacements to make after translation. Based
+ * on the first character of the key, the value is escaped and/or themed.
+ * See format_string() for details.
* @param $options
* An associative array of additional options, with the following elements:
* - 'langcode' (defaults to the current language): The language code to
* translate to a language other than what is used to display the page.
- * - 'context' (defaults to the empty context): The context the source string
- * belongs to.
+ * - 'context' (defaults to the empty context): A string giving the context
+ * that the source string belongs to. See @ref sec_context above for more
+ * information.
*
* @return
* The translated string.
*
* @see st()
* @see get_t()
+ * @see format_string()
* @ingroup sanitization
*/
function t($string, array $args = array(), array $options = array()) {
@@ -1482,21 +1781,34 @@
}
/**
- * Replace placeholders with sanitized values in a string.
+ * Formats a string for HTML display by replacing variable placeholders.
+ *
+ * This function replaces variable placeholders in a string with the requested
+ * values and escapes the values so they can be safely displayed as HTML. It
+ * should be used on any unknown text that is intended to be printed to an HTML
+ * page (especially text that may have come from untrusted users, since in that
+ * case it prevents cross-site scripting and other security problems).
+ *
+ * In most cases, you should use t() rather than calling this function
+ * directly, since it will translate the text (on non-English-only sites) in
+ * addition to formatting it.
*
* @param $string
* A string containing placeholders.
* @param $args
* An associative array of replacements to make. Occurrences in $string of
- * any key in $args are replaced with the corresponding value, after
- * sanitization. The sanitization function depends on the first character of
- * the key:
- * - !variable: Inserted as is. Use this for text that has already been
- * sanitized.
- * - @variable: Escaped to HTML using check_plain(). Use this for anything
- * displayed on a page on the site.
- * - %variable: Escaped as a placeholder for user-submitted content using
- * drupal_placeholder(), which shows up as emphasized text.
+ * any key in $args are replaced with the corresponding value, after optional
+ * sanitization and formatting. The type of sanitization and formatting
+ * depends on the first character of the key:
+ * - @variable: Escaped to HTML using check_plain(). Use this as the default
+ * choice for anything displayed on a page on the site.
+ * - %variable: Escaped to HTML and formatted using drupal_placeholder(),
+ * which makes it display as emphasized text.
+ * - !variable: Inserted as is, with no sanitization or formatting. Only use
+ * this for text that has already been prepared for HTML display (for
+ * example, user-supplied text that has already been run through
+ * check_plain() previously, or is expected to contain some limited HTML
+ * tags and has already been run through filter_xss() previously).
*
* @see t()
* @ingroup sanitization
@@ -1524,17 +1836,18 @@
}
/**
- * Encode special characters in a plain-text string for display as HTML.
+ * Encodes special characters in a plain-text string for display as HTML.
*
* Also validates strings as UTF-8 to prevent cross site scripting attacks on
* Internet Explorer 6.
*
- * @param $text
+ * @param string $text
* The text to be checked or processed.
*
- * @return
- * An HTML safe version of $text, or an empty string if $text is not
- * valid UTF-8.
+ * @return string
+ * An HTML safe version of $text. If $text is not valid UTF-8, an empty string
+ * is returned and, on PHP < 5.4, a warning may be issued depending on server
+ * configuration (see @link https://bugs.php.net/bug.php?id=47494 @endlink).
*
* @see drupal_validate_utf8()
* @ingroup sanitization
@@ -1563,6 +1876,7 @@
*
* @param $text
* The text to check.
+ *
* @return
* TRUE if the text is valid UTF-8, FALSE if not.
*/
@@ -1604,7 +1918,7 @@
}
/**
- * Log an exception.
+ * Logs an exception.
*
* This is a wrapper function for watchdog() which automatically decodes an
* exception.
@@ -1618,14 +1932,14 @@
* information about the passed-in exception is used.
* @param $variables
* Array of variables to replace in the message on display. Defaults to the
- * return value of drupal_decode_exception().
+ * return value of _drupal_decode_exception().
* @param $severity
* The severity of the message, as per RFC 3164.
* @param $link
* A link to associate with the message.
*
* @see watchdog()
- * @see drupal_decode_exception()
+ * @see _drupal_decode_exception()
*/
function watchdog_exception($type, Exception $exception, $message = NULL, $variables = array(), $severity = WATCHDOG_ERROR, $link = NULL) {
@@ -1645,7 +1959,7 @@
}
/**
- * Log a system message.
+ * Logs a system message.
*
* @param $type
* The category to which this message belongs. Can be any string, but the
@@ -1661,8 +1975,16 @@
* NULL if message is already translated or not possible to
* translate.
* @param $severity
- * The severity of the message, as per RFC 3164. Possible values are
- * WATCHDOG_ERROR, WATCHDOG_WARNING, etc.
+ * The severity of the message; one of the following values as defined in
+ * @link http://www.faqs.org/rfcs/rfc3164.html RFC 3164: @endlink
+ * - WATCHDOG_EMERGENCY: Emergency, system is unusable.
+ * - WATCHDOG_ALERT: Alert, action must be taken immediately.
+ * - WATCHDOG_CRITICAL: Critical conditions.
+ * - WATCHDOG_ERROR: Error conditions.
+ * - WATCHDOG_WARNING: Warning conditions.
+ * - WATCHDOG_NOTICE: (default) Normal but significant conditions.
+ * - WATCHDOG_INFO: Informational messages.
+ * - WATCHDOG_DEBUG: Debug-level messages.
* @param $link
* A link to associate with the message.
*
@@ -1679,6 +2001,9 @@
if (!$in_error_state && function_exists('module_implements')) {
$in_error_state = TRUE;
+ // The user object may not exist in all conditions, so 0 is substituted if needed.
+ $user_uid = isset($user->uid) ? $user->uid : 0;
+
// Prepare the fields to be logged
$log_entry = array(
'type' => $type,
@@ -1687,10 +2012,12 @@
'severity' => $severity,
'link' => $link,
'user' => $user,
+ 'uid' => $user_uid,
'request_uri' => $base_root . request_uri(),
'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
'ip' => ip_address(),
- 'timestamp' => REQUEST_TIME,
+ // Request time isn't accurate for long processes, use time() instead.
+ 'timestamp' => time(),
);
// Call the logging hooks to log/process the message
@@ -1705,25 +2032,40 @@
}
/**
- * Set a message which reflects the status of the performed operation.
+ * Sets a message to display to the user.
*
- * If the function is called with no arguments, this function returns all set
- * messages without clearing them.
+ * Messages are stored in a session variable and displayed in page.tpl.php via
+ * the $messages theme variable.
*
- * @param $message
- * The message to be displayed to the user. For consistency with other
- * messages, it should begin with a capital letter and end with a period.
- * @param $type
- * The type of the message. One of the following values are possible:
+ * Example usage:
+ * @code
+ * drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
+ * @endcode
+ *
+ * @param string $message
+ * (optional) The translated message to be displayed to the user. For
+ * consistency with other messages, it should begin with a capital letter and
+ * end with a period.
+ * @param string $type
+ * (optional) The message's type. Defaults to 'status'. These values are
+ * supported:
* - 'status'
* - 'warning'
* - 'error'
- * @param $repeat
- * If this is FALSE and the message is already set, then the message won't
- * be repeated.
+ * @param bool $repeat
+ * (optional) If this is FALSE and the message is already set, then the
+ * message won't be repeated. Defaults to TRUE.
+ *
+ * @return array|null
+ * A multidimensional array with keys corresponding to the set message types.
+ * The indexed array values of each contain the set messages for that type.
+ * Or, if there are no messages set, the function returns NULL.
+ *
+ * @see drupal_get_messages()
+ * @see theme_status_messages()
*/
function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) {
- if ($message) {
+ if ($message || $message === '0' || $message === 0) {
if (!isset($_SESSION['messages'][$type])) {
$_SESSION['messages'][$type] = array();
}
@@ -1741,17 +2083,29 @@
}
/**
- * Return all messages that have been set.
+ * Returns all messages that have been set with drupal_set_message().
*
- * @param $type
- * (optional) Only return messages of this type.
- * @param $clear_queue
- * (optional) Set to FALSE if you do not want to clear the messages queue
- * @return
- * An associative array, the key is the message type, the value an array
- * of messages. If the $type parameter is passed, you get only that type,
- * or an empty array if there are no such messages. If $type is not passed,
- * all message types are returned, or an empty array if none exist.
+ * @param string $type
+ * (optional) Limit the messages returned by type. Defaults to NULL, meaning
+ * all types. These values are supported:
+ * - NULL
+ * - 'status'
+ * - 'warning'
+ * - 'error'
+ * @param bool $clear_queue
+ * (optional) If this is TRUE, the queue will be cleared of messages of the
+ * type specified in the $type parameter. Otherwise the queue will be left
+ * intact. Defaults to TRUE.
+ *
+ * @return array
+ * A multidimensional array with keys corresponding to the set message types.
+ * The indexed array values of each contain the set messages for that type.
+ * The messages returned are limited to the type specified in the $type
+ * parameter. If there are no messages of the specified type, an empty array
+ * is returned.
+ *
+ * @see drupal_set_message()
+ * @see theme_status_messages()
*/
function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
if ($messages = drupal_set_message()) {
@@ -1774,7 +2128,9 @@
}
/**
- * Get the title of the current page, for display on the page and in the title bar.
+ * Gets the title of the current page.
+ *
+ * The title is displayed on the page and in the title bar.
*
* @return
* The current page's title.
@@ -1791,7 +2147,9 @@
}
/**
- * Set the title of the current page, for display on the page and in the title bar.
+ * Sets the title of the current page.
+ *
+ * The title is displayed on the page and in the title bar.
*
* @param $title
* Optional string value to assign to the page title; or if set to NULL
@@ -1816,7 +2174,7 @@
}
/**
- * Check to see if an IP address has been blocked.
+ * Checks to see if an IP address has been blocked.
*
* Blocked IP addresses are stored in the database by default. However for
* performance reasons we allow an override in settings.php. This allows us
@@ -1825,6 +2183,7 @@
*
* @param $ip
* IP address to check.
+ *
* @return bool
* TRUE if access is denied, FALSE if access is allowed.
*/
@@ -1850,7 +2209,7 @@
}
/**
- * Handle denied users.
+ * Handles denied users.
*
* @param $ip
* IP address to check. Prints a message and exits if access is denied.
@@ -1865,39 +2224,73 @@
}
/**
+ * Returns a URL-safe, base64 encoded string of highly randomized bytes (over the full 8-bit range).
+ *
+ * @param $byte_count
+ * The number of random bytes to fetch and base64 encode.
+ *
+ * @return string
+ * The base64 encoded result will have a length of up to 4 * $byte_count.
+ */
+function drupal_random_key($byte_count = 32) {
+ return drupal_base64_encode(drupal_random_bytes($byte_count));
+}
+
+/**
+ * Returns a URL-safe, base64 encoded version of the supplied string.
+ *
+ * @param $string
+ * The string to convert to base64.
+ *
+ * @return string
+ */
+function drupal_base64_encode($string) {
+ $data = base64_encode($string);
+ // Modify the output so it's safe to use in URLs.
+ return strtr($data, array('+' => '-', '/' => '_', '=' => ''));
+}
+
+/**
* Returns a string of highly randomized bytes (over the full 8-bit range).
*
* This function is better than simply calling mt_rand() or any other built-in
* PHP function because it can return a long string of bytes (compared to < 4
- * bytes normally from mt_rand()) and uses the best available pseudo-random source.
+ * bytes normally from mt_rand()) and uses the best available pseudo-random
+ * source.
*
* @param $count
* The number of characters (bytes) to return in the string.
*/
function drupal_random_bytes($count) {
// $random_state does not use drupal_static as it stores random bytes.
- static $random_state, $bytes;
- // Initialize on the first call. The contents of $_SERVER includes a mix of
- // user-specific and system information that varies a little with each page.
- if (!isset($random_state)) {
- $random_state = print_r($_SERVER, TRUE);
- if (function_exists('getmypid')) {
- // Further initialize with the somewhat random PHP process ID.
- $random_state .= getmypid();
- }
- $bytes = '';
- }
- if (strlen($bytes) < $count) {
- // /dev/urandom is available on many *nix systems and is considered the
- // best commonly available pseudo-random source.
- if ($fh = @fopen('/dev/urandom', 'rb')) {
+ static $random_state, $bytes, $has_openssl;
+
+ $missing_bytes = $count - strlen($bytes);
+
+ if ($missing_bytes > 0) {
+ // PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
+ // locking on Windows and rendered it unusable.
+ if (!isset($has_openssl)) {
+ $has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=') && function_exists('openssl_random_pseudo_bytes');
+ }
+
+ // openssl_random_pseudo_bytes() will find entropy in a system-dependent
+ // way.
+ if ($has_openssl) {
+ $bytes .= openssl_random_pseudo_bytes($missing_bytes);
+ }
+
+ // Else, read directly from /dev/urandom, which is available on many *nix
+ // systems and is considered cryptographically secure.
+ elseif ($fh = @fopen('/dev/urandom', 'rb')) {
// PHP only performs buffered reads, so in reality it will always read
// at least 4096 bytes. Thus, it costs nothing extra to read and store
// that much so as to speed any additional invocations.
- $bytes .= fread($fh, max(4096, $count));
+ $bytes .= fread($fh, max(4096, $missing_bytes));
fclose($fh);
}
- // If /dev/urandom is not available or returns no bytes, this loop will
+
+ // If we couldn't get enough entropy, this simple hash-based PRNG will
// generate a good set of pseudo-random bytes on any system.
// Note that it may be important that our $random_state is passed
// through hash() prior to being rolled into $output, that the two hash()
@@ -1905,9 +2298,23 @@
// the microtime() - is prepended rather than appended. This is to avoid
// directly leaking $random_state via the $output stream, which could
// allow for trivial prediction of further "random" numbers.
- while (strlen($bytes) < $count) {
- $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
- $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+ if (strlen($bytes) < $count) {
+ // Initialize on the first call. The contents of $_SERVER includes a mix of
+ // user-specific and system information that varies a little with each page.
+ if (!isset($random_state)) {
+ $random_state = print_r($_SERVER, TRUE);
+ if (function_exists('getmypid')) {
+ // Further initialize with the somewhat random PHP process ID.
+ $random_state .= getmypid();
+ }
+ $bytes = '';
+ }
+
+ do {
+ $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
+ $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+ }
+ while (strlen($bytes) < $count);
}
}
$output = substr($bytes, 0, $count);
@@ -1916,25 +2323,29 @@
}
/**
- * Calculate a base-64 encoded, URL-safe sha-256 hmac.
+ * Calculates a base-64 encoded, URL-safe sha-256 hmac.
*
- * @param $data
+ * @param string $data
* String to be validated with the hmac.
- * @param $key
+ * @param string $key
* A secret string key.
*
- * @return
+ * @return string
* A base-64 encoded sha-256 hmac, with + replaced with -, / with _ and
* any = padding characters removed.
*/
function drupal_hmac_base64($data, $key) {
- $hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
+ // Casting $data and $key to strings here is necessary to avoid empty string
+ // results of the hash function if they are not scalar values. As this
+ // function is used in security-critical contexts like token validation it is
+ // important that it never returns an empty string.
+ $hmac = base64_encode(hash_hmac('sha256', (string) $data, (string) $key, TRUE));
// Modify the hmac so it's safe to use in URLs.
return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
}
/**
- * Calculate a base-64 encoded, URL-safe sha-256 hash.
+ * Calculates a base-64 encoded, URL-safe sha-256 hash.
*
* @param $data
* String to be hashed.
@@ -1977,7 +2388,8 @@
* @see drupal_array_merge_deep_array()
*/
function drupal_array_merge_deep() {
- return drupal_array_merge_deep_array(func_get_args());
+ $args = func_get_args();
+ return drupal_array_merge_deep_array($args);
}
/**
@@ -2028,7 +2440,7 @@
* @return Object - the user object.
*/
function drupal_anonymous_user() {
- $user = new stdClass();
+ $user = variable_get('drupal_anonymous_user_object', new stdClass);
$user->uid = 0;
$user->hostname = ip_address();
$user->roles = array();
@@ -2038,20 +2450,34 @@
}
/**
- * A string describing a phase of Drupal to load. Each phase adds to the
- * previous one, so invoking a later phase automatically runs the earlier
- * phases too. The most important usage is that if you want to access the
- * Drupal database from a script without loading anything else, you can
- * include bootstrap.inc, and call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE).
- *
- * @param $phase
- * A constant. Allowed values are the DRUPAL_BOOTSTRAP_* constants.
- * @param $new_phase
+ * Ensures Drupal is bootstrapped to the specified phase.
+ *
+ * In order to bootstrap Drupal from another PHP script, you can use this code:
+ * @code
+ * define('DRUPAL_ROOT', '/path/to/drupal');
+ * require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+ * drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ * @endcode
+ *
+ * @param int $phase
+ * A constant telling which phase to bootstrap to. When you bootstrap to a
+ * particular phase, all earlier phases are run automatically. Possible
+ * values:
+ * - DRUPAL_BOOTSTRAP_CONFIGURATION: Initializes configuration.
+ * - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
+ * - DRUPAL_BOOTSTRAP_DATABASE: Initializes the database layer.
+ * - DRUPAL_BOOTSTRAP_VARIABLES: Initializes the variable system.
+ * - DRUPAL_BOOTSTRAP_SESSION: Initializes session handling.
+ * - DRUPAL_BOOTSTRAP_PAGE_HEADER: Sets up the page header.
+ * - DRUPAL_BOOTSTRAP_LANGUAGE: Finds out the language of the page.
+ * - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
+ * data.
+ * @param boolean $new_phase
* A boolean, set to FALSE if calling drupal_bootstrap from inside a
* function called from drupal_bootstrap (recursion).
- * @return
- * The most recently completed phase.
*
+ * @return int
+ * The most recently completed phase.
*/
function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
// Not drupal_static(), because does not depend on any run-time information.
@@ -2072,12 +2498,13 @@
// bootstrap state.
static $stored_phase = -1;
- // When not recursing, store the phase name so it's not forgotten while
- // recursing.
- if ($new_phase) {
- $final_phase = $phase;
- }
if (isset($phase)) {
+ // When not recursing, store the phase name so it's not forgotten while
+ // recursing but take care of not going backwards.
+ if ($new_phase && $phase >= $stored_phase) {
+ $final_phase = $phase;
+ }
+
// Call a phase if it has not been called before and is below the requested
// phase.
while ($phases && $phase > $stored_phase && $final_phase > $stored_phase) {
@@ -2130,7 +2557,7 @@
}
/**
- * Return the time zone of the current user.
+ * Returns the time zone of the current user.
*/
function drupal_get_user_timezone() {
global $user;
@@ -2145,7 +2572,20 @@
}
/**
- * Custom PHP error handler.
+ * Gets a salt useful for hardening against SQL injection.
+ *
+ * @return
+ * A salt based on information in settings.php, not in the database.
+ */
+function drupal_get_hash_salt() {
+ global $drupal_hash_salt, $databases;
+ // If the $drupal_hash_salt variable is empty, a hash of the serialized
+ // database credentials is used as a fallback salt.
+ return empty($drupal_hash_salt) ? hash('sha256', serialize($databases)) : $drupal_hash_salt;
+}
+
+/**
+ * Provides custom PHP error handling.
*
* @param $error_level
* The level of the error raised.
@@ -2156,7 +2596,8 @@
* @param $line
* The line number the error was raised at.
* @param $context
- * An array that points to the active symbol table at the point the error occurred.
+ * An array that points to the active symbol table at the point the error
+ * occurred.
*/
function _drupal_error_handler($error_level, $message, $filename, $line, $context) {
require_once DRUPAL_ROOT . '/includes/errors.inc';
@@ -2164,7 +2605,7 @@
}
/**
- * Custom PHP exception handler.
+ * Provides custom PHP exception handling.
*
* Uncaught exceptions are those not enclosed in a try/catch block. They are
* always fatal: the execution of the script will stop as soon as the exception
@@ -2192,7 +2633,7 @@
}
/**
- * Bootstrap configuration: Setup script environment and load settings.php.
+ * Sets up the script environment and loads settings.php.
*/
function _drupal_bootstrap_configuration() {
// Set the Drupal custom error handler.
@@ -2204,10 +2645,14 @@
timer_start('page');
// Initialize the configuration, including variables from settings.php.
drupal_settings_initialize();
+
+ // Sanitize unsafe keys from the request.
+ require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc';
+ DrupalRequestSanitizer::sanitize();
}
/**
- * Bootstrap page cache: Try to serve a page from cache.
+ * Attempts to serve a page from the cache.
*/
function _drupal_bootstrap_page_cache() {
global $user;
@@ -2263,7 +2708,7 @@
}
/**
- * Bootstrap database: Initialize database system and register autoload functions.
+ * Initializes the database system and registers autoload functions.
*/
function _drupal_bootstrap_database() {
// Redirect the user to the installation script if Drupal has not been
@@ -2312,10 +2757,13 @@
// the install or upgrade process.
spl_autoload_register('drupal_autoload_class');
spl_autoload_register('drupal_autoload_interface');
+ if (version_compare(PHP_VERSION, '5.4') >= 0) {
+ spl_autoload_register('drupal_autoload_trait');
+ }
}
/**
- * Bootstrap variables: Load system variables and all enabled bootstrap modules.
+ * Loads system variables and all enabled bootstrap modules.
*/
function _drupal_bootstrap_variables() {
global $conf;
@@ -2329,10 +2777,35 @@
// Load bootstrap modules.
require_once DRUPAL_ROOT . '/includes/module.inc';
module_load_all(TRUE);
+
+ // Sanitize the destination parameter (which is often used for redirects) to
+ // prevent open redirect attacks leading to other domains. Sanitize both
+ // $_GET['destination'] and $_REQUEST['destination'] to protect code that
+ // relies on either, but do not sanitize $_POST to avoid interfering with
+ // unrelated form submissions. The sanitization happens here because
+ // url_is_external() requires the variable system to be available.
+ if (isset($_GET['destination']) || isset($_REQUEST['destination'])) {
+ require_once DRUPAL_ROOT . '/includes/common.inc';
+ // If the destination is an external URL, remove it.
+ if (isset($_GET['destination']) && url_is_external($_GET['destination'])) {
+ unset($_GET['destination']);
+ unset($_REQUEST['destination']);
+ }
+ // Use the DrupalRequestSanitizer to ensure that the destination's query
+ // parameters are not dangerous.
+ if (isset($_GET['destination'])) {
+ DrupalRequestSanitizer::cleanDestination();
+ }
+ // If there's still something in $_REQUEST['destination'] that didn't come
+ // from $_GET, check it too.
+ if (isset($_REQUEST['destination']) && (!isset($_GET['destination']) || $_REQUEST['destination'] != $_GET['destination']) && url_is_external($_REQUEST['destination'])) {
+ unset($_REQUEST['destination']);
+ }
+ }
}
/**
- * Bootstrap page header: Invoke hook_boot(), initialize locking system, and send default HTTP headers.
+ * Invokes hook_boot(), initializes locking system, and sends HTTP headers.
*/
function _drupal_bootstrap_page_header() {
bootstrap_invoke_all('boot');
@@ -2351,12 +2824,11 @@
* @see drupal_bootstrap()
*/
function drupal_get_bootstrap_phase() {
- return drupal_bootstrap();
+ return drupal_bootstrap(NULL, FALSE);
}
/**
- * Checks the current User-Agent string to see if this is an internal request
- * from SimpleTest. If so, returns the test prefix for this test.
+ * Returns the test prefix if this is an internal request from SimpleTest.
*
* @return
* Either the simpletest prefix (the string "simpletest" followed by any
@@ -2364,7 +2836,6 @@
* HMAC and timestamp.
*/
function drupal_valid_test_ua() {
- global $drupal_hash_salt;
// No reason to reset this.
static $test_prefix;
@@ -2378,7 +2849,7 @@
// We use the salt from settings.php to make the HMAC key, since
// the database is not yet initialized and we can't access any Drupal variables.
// The file properties add more entropy not easily accessible to others.
- $key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__);
+ $key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
$time_diff = REQUEST_TIME - $time;
// Since we are making a local request a 5 second time window is allowed,
// and the HMAC must match.
@@ -2388,21 +2859,21 @@
}
}
- return FALSE;
+ $test_prefix = FALSE;
+ return $test_prefix;
}
/**
- * Generate a user agent string with a HMAC and timestamp for simpletest.
+ * Generates a user agent string with a HMAC and timestamp for simpletest.
*/
function drupal_generate_test_ua($prefix) {
- global $drupal_hash_salt;
static $key;
if (!isset($key)) {
// We use the salt from settings.php to make the HMAC key, since
// the database is not yet initialized and we can't access any Drupal variables.
// The file properties add more entropy not easily accessible to others.
- $key = $drupal_hash_salt . filectime(__FILE__) . fileinode(__FILE__);
+ $key = drupal_get_hash_salt() . filectime(__FILE__) . fileinode(__FILE__);
}
// Generate a moderately secure HMAC based on the database credentials.
$salt = uniqid('', TRUE);
@@ -2443,7 +2914,7 @@
$fast_paths = variable_get('404_fast_paths', FALSE);
if ($fast_paths && preg_match($fast_paths, $_GET['q'])) {
drupal_add_http_header('Status', '404 Not Found');
- $fast_404_html = variable_get('404_fast_html', '404 Not Found Not Found
The requested URL "@path" was not found on this server.
');
+ $fast_404_html = variable_get('404_fast_html', '404 Not Found Not Found
The requested URL "@path" was not found on this server.
');
// Replace @path in the variable with the page path.
print strtr($fast_404_html, array('@path' => check_plain(request_uri())));
exit;
@@ -2452,7 +2923,7 @@
}
/**
- * Return TRUE if a Drupal installation is currently being attempted.
+ * Returns TRUE if a Drupal installation is currently being attempted.
*/
function drupal_installation_attempted() {
return defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'install';
@@ -2467,7 +2938,7 @@
*
* This would include implementations of hook_install(), which could run
* during the Drupal installation phase, and might also be run during
- * non-installation time, such as while installing the module from the the
+ * non-installation time, such as while installing the module from the
* module administration page.
*
* Example usage:
@@ -2495,10 +2966,9 @@
}
/**
- * Initialize all the defined language types.
+ * Initializes all the defined language types.
*/
function drupal_language_initialize() {
- global $language;
$types = language_types();
// Ensure the language is correctly returned, even without multilanguage
@@ -2518,13 +2988,10 @@
// environments.
bootstrap_invoke_all('language_init');
}
-
- // Send appropriate HTTP-Header for browsers and search engines.
- header('Content-Language: ' . $language->language);
}
/**
- * The built-in language types.
+ * Returns a list of the built-in language types.
*
* @return
* An array of key-values pairs where the key is the language type and the
@@ -2539,7 +3006,10 @@
}
/**
- * Return true if there is more than one language enabled.
+ * Returns TRUE if there is more than one language enabled.
+ *
+ * @return
+ * TRUE if more than one language is enabled.
*/
function drupal_multilingual() {
// The "language_count" variable stores the number of enabled languages to
@@ -2549,7 +3019,11 @@
}
/**
- * Return an array of the available language types.
+ * Returns an array of the available language types.
+ *
+ * @return
+ * An array of all language types where the keys of each are the language type
+ * name and its value is its configurability (TRUE/FALSE).
*/
function language_types() {
return array_keys(variable_get('language_types', drupal_language_types()));
@@ -2606,10 +3080,14 @@
}
/**
- * Default language used on the site
+ * Returns the default language, as an object, or one of its properties.
*
* @param $property
- * Optional property of the language object to return
+ * (optional) The property of the language object to return.
+ *
+ * @return
+ * Either the language object for the default language used on the site,
+ * or the property of that object named in the $property parameter.
*/
function language_default($property = NULL) {
$language = variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => ''));
@@ -2640,7 +3118,7 @@
return $path;
}
- if (isset($_GET['q'])) {
+ if (isset($_GET['q']) && is_string($_GET['q'])) {
// This is a request with a ?q=foo/bar query string. $_GET['q'] is
// overwritten in drupal_path_initialize(), but request_path() is called
// very early in the bootstrap process, so the original value is saved in
@@ -2676,16 +3154,16 @@
}
/**
- * Return a component of the current Drupal path.
+ * Returns a component of the current Drupal path.
*
* When viewing a page at the path "admin/structure/types", for example, arg(0)
* returns "admin", arg(1) returns "structure", and arg(2) returns "types".
*
- * Avoid use of this function where possible, as resulting code is hard to read.
- * In menu callback functions, attempt to use named arguments. See the explanation
- * in menu.inc for how to construct callbacks that take arguments. When attempting
- * to use this function to load an element from the current path, e.g. loading the
- * node on a node page, please use menu_get_object() instead.
+ * Avoid use of this function where possible, as resulting code is hard to
+ * read. In menu callback functions, attempt to use named arguments. See the
+ * explanation in menu.inc for how to construct callbacks that take arguments.
+ * When attempting to use this function to load an element from the current
+ * path, e.g. loading the node on a node page, use menu_get_object() instead.
*
* @param $index
* The index of the component, where each component is separated by a '/'
@@ -2725,6 +3203,8 @@
}
/**
+ * Returns the IP address of the client machine.
+ *
* If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
* instead of $_SERVER['REMOTE_ADDR'], which would be the IP address of
* the proxy server, and not the client's. The actual header name can be
@@ -2759,8 +3239,15 @@
// Eliminate all trusted IPs.
$untrusted = array_diff($forwarded, $reverse_proxy_addresses);
- // The right-most IP is the most specific we can trust.
- $ip_address = array_pop($untrusted);
+ if (!empty($untrusted)) {
+ // The right-most IP is the most specific we can trust.
+ $ip_address = array_pop($untrusted);
+ }
+ else {
+ // All IP addresses in the forwarded array are configured proxy IPs
+ // (and thus trusted). We take the leftmost IP.
+ $ip_address = array_shift($forwarded);
+ }
}
}
}
@@ -2769,15 +3256,17 @@
}
/**
- * @ingroup schemaapi
+ * @addtogroup schemaapi
* @{
*/
/**
- * Get the schema definition of a table, or the whole database schema.
+ * Gets the schema definition of a table, or the whole database schema.
*
* The returned schema will include any modifications made by any
- * module that implements hook_schema_alter().
+ * module that implements hook_schema_alter(). To get the schema without
+ * modifications, use drupal_get_schema_unprocessed().
+ *
*
* @param $table
* The name of the table. If not given, the schema of all tables is returned.
@@ -2810,11 +3299,17 @@
*/
class SchemaCache extends DrupalCacheArray {
+ /**
+ * Constructs a SchemaCache object.
+ */
public function __construct() {
// Cache by request method.
parent::__construct('schema:runtime:' . ($_SERVER['REQUEST_METHOD'] == 'GET'), 'cache');
}
+ /**
+ * Overrides DrupalCacheArray::resolveCacheMiss().
+ */
protected function resolveCacheMiss($offset) {
$complete_schema = drupal_get_complete_schema();
$value = isset($complete_schema[$offset]) ? $complete_schema[$offset] : NULL;
@@ -2825,7 +3320,7 @@
}
/**
- * Get the whole database schema.
+ * Gets the whole database schema.
*
* The returned schema will include any modifications made by any
* module that implements hook_schema_alter().
@@ -2885,23 +3380,24 @@
}
/**
- * @} End of "ingroup schemaapi".
+ * @} End of "addtogroup schemaapi".
*/
/**
- * @ingroup registry
+ * @addtogroup registry
* @{
*/
/**
- * Confirm that an interface is available.
+ * Confirms that an interface is available.
*
* This function is rarely called directly. Instead, it is registered as an
* spl_autoload() handler, and PHP calls it for us when necessary.
*
* @param $interface
* The name of the interface to check or load.
+ *
* @return
* TRUE if the interface is currently available, FALSE otherwise.
*/
@@ -2910,13 +3406,14 @@
}
/**
- * Confirm that a class is available.
+ * Confirms that a class is available.
*
* This function is rarely called directly. Instead, it is registered as an
* spl_autoload() handler, and PHP calls it for us when necessary.
*
* @param $class
* The name of the class to check or load.
+ *
* @return
* TRUE if the class is currently available, FALSE otherwise.
*/
@@ -2925,7 +3422,23 @@
}
/**
- * Helper to check for a resource in the registry.
+ * Confirms that a trait is available.
+ *
+ * This function is rarely called directly. Instead, it is registered as an
+ * spl_autoload() handler, and PHP calls it for us when necessary.
+ *
+ * @param string $trait
+ * The name of the trait to check or load.
+ *
+ * @return bool
+ * TRUE if the trait is currently available, FALSE otherwise.
+ */
+function drupal_autoload_trait($trait) {
+ return _registry_check_code('trait', $trait);
+}
+
+/**
+ * Checks for a resource in the registry.
*
* @param $type
* The type of resource we are looking up, or one of the constants
@@ -2934,6 +3447,7 @@
* @param $name
* The name of the resource, or NULL if either of the REGISTRY_* constants
* is passed in.
+ *
* @return
* TRUE if the resource was found, FALSE if not.
* NULL if either of the REGISTRY_* constants is passed in as $type.
@@ -2941,7 +3455,7 @@
function _registry_check_code($type, $name = NULL) {
static $lookup_cache, $cache_update_needed;
- if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name)) {
+ if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name) || $type == 'trait' && trait_exists($name)) {
return TRUE;
}
@@ -2974,7 +3488,7 @@
$cache_key = $type[0] . $name;
if (isset($lookup_cache[$cache_key])) {
if ($lookup_cache[$cache_key]) {
- require_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
+ include_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
}
return (bool) $lookup_cache[$cache_key];
}
@@ -2982,10 +3496,13 @@
// This function may get called when the default database is not active, but
// there is no reason we'd ever want to not use the default database for
// this query.
- $file = Database::getConnection('default', 'default')->query("SELECT filename FROM {registry} WHERE name = :name AND type = :type", array(
- ':name' => $name,
- ':type' => $type,
- ))
+ $file = Database::getConnection('default', 'default')
+ ->select('registry', 'r', array('target' => 'default'))
+ ->fields('r', array('filename'))
+ // Use LIKE here to make the query case-insensitive.
+ ->condition('r.name', db_like($name), 'LIKE')
+ ->condition('r.type', $type)
+ ->execute()
->fetchField();
// Flag that we've run a lookup query and need to update the cache.
@@ -2996,7 +3513,7 @@
$lookup_cache[$cache_key] = $file;
if ($file) {
- require_once DRUPAL_ROOT . '/' . $file;
+ include_once DRUPAL_ROOT . '/' . $file;
return TRUE;
}
else {
@@ -3005,7 +3522,7 @@
}
/**
- * Rescan all enabled modules and rebuild the registry.
+ * Rescans all enabled modules and rebuilds the registry.
*
* Rescans all code in modules or includes directories, storing the location of
* each interface or class in the database.
@@ -3016,25 +3533,44 @@
}
/**
- * Update the registry based on the latest files listed in the database.
+ * Updates the registry based on the latest files listed in the database.
*
* This function should be used when system_rebuild_module_data() does not need
* to be called, because it is already known that the list of files in the
* {system} table matches those in the file system.
*
+ * @return
+ * TRUE if the registry was rebuilt, FALSE if another thread was rebuilding
+ * in parallel and the current thread just waited for completion.
+ *
* @see registry_rebuild()
*/
function registry_update() {
+ // install_system_module() calls module_enable() which calls into this
+ // function during initial system installation, so the lock system is neither
+ // loaded nor does its storage exist yet.
+ $in_installer = drupal_installation_attempted();
+ if (!$in_installer && !lock_acquire(__FUNCTION__)) {
+ // Another request got the lock, wait for it to finish.
+ lock_wait(__FUNCTION__);
+ return FALSE;
+ }
+
require_once DRUPAL_ROOT . '/includes/registry.inc';
_registry_update();
+
+ if (!$in_installer) {
+ lock_release(__FUNCTION__);
+ }
+ return TRUE;
}
/**
- * @} End of "ingroup registry".
+ * @} End of "addtogroup registry".
*/
/**
- * Central static variable storage.
+ * Provides central static variable storage.
*
* All functions requiring a static variable to persist or cache data within
* a single page request are encouraged to use this function unless it is
@@ -3114,8 +3650,8 @@
* However, the above line of code does not work, because PHP only allows static
* variables to be initializied by literal values, and does not allow static
* variables to be assigned to references.
- * - http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static
- * - http://php.net/manual/en/language.variables.scope.php#language.variables.scope.references
+ * - http://php.net/manual/language.variables.scope.php#language.variables.scope.static
+ * - http://php.net/manual/language.variables.scope.php#language.variables.scope.references
* The example below shows the syntax needed to work around both limitations.
* For benchmarks and more information, see http://drupal.org/node/619666.
*
@@ -3140,11 +3676,9 @@
* @param $default_value
* Optional default value.
* @param $reset
- * TRUE to reset a specific named variable, or all variables if $name is NULL.
- * Resetting every variable should only be used, for example, for running
- * unit tests with a clean environment. Should be used only though via
- * function drupal_static_reset() and the return value should not be used in
- * this case.
+ * TRUE to reset one or all variables(s). This parameter is only used
+ * internally and should not be passed in; use drupal_static_reset() instead.
+ * (This function's return value should not be used when TRUE is passed in.)
*
* @return
* Returns a variable by reference.
@@ -3185,17 +3719,19 @@
}
/**
- * Reset one or all centrally stored static variable(s).
+ * Resets one or all centrally stored static variable(s).
*
* @param $name
* Name of the static variable to reset. Omit to reset all variables.
+ * Resetting all variables should only be used, for example, for running unit
+ * tests with a clean environment.
*/
function drupal_static_reset($name = NULL) {
drupal_static($name, NULL, TRUE);
}
/**
- * Detect whether the current script is running in a command-line environment.
+ * Detects whether the current script is running in a command-line environment.
*/
function drupal_is_cli() {
return (!isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
@@ -3203,7 +3739,8 @@
/**
* Formats text for emphasized display in a placeholder inside a sentence.
- * Used automatically by t().
+ *
+ * Used automatically by format_string().
*
* @param $text
* The text to format (plain-text).
@@ -3216,7 +3753,7 @@
}
/**
- * Register a function for execution on shutdown.
+ * Registers a function for execution on shutdown.
*
* Wrapper for register_shutdown_function() that catches thrown exceptions to
* avoid "Exception thrown without a stack frame in Unknown".
@@ -3251,7 +3788,7 @@
}
/**
- * Internal function used to execute registered shutdown functions.
+ * Executes registered shutdown functions.
*/
function _drupal_shutdown_function() {
$callbacks = &drupal_register_shutdown_function();
@@ -3261,8 +3798,12 @@
chdir(DRUPAL_ROOT);
try {
- while (list($key, $callback) = each($callbacks)) {
+ // Manually iterate over the array instead of using a foreach loop.
+ // A foreach operates on a copy of the array, so any shutdown functions that
+ // were added from other shutdown functions would never be called.
+ while ($callback = current($callbacks)) {
call_user_func_array($callback['callback'], $callback['arguments']);
+ next($callbacks);
}
}
catch (Exception $exception) {
@@ -3274,3 +3815,63 @@
}
}
}
+
+/**
+ * Compares the memory required for an operation to the available memory.
+ *
+ * @param $required
+ * The memory required for the operation, expressed as a number of bytes with
+ * optional SI or IEC binary unit prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8bytes,
+ * 9mbytes).
+ * @param $memory_limit
+ * (optional) The memory limit for the operation, expressed as a number of
+ * bytes with optional SI or IEC binary unit prefix (e.g. 2, 3K, 5MB, 10G,
+ * 6GiB, 8bytes, 9mbytes). If no value is passed, the current PHP
+ * memory_limit will be used. Defaults to NULL.
+ *
+ * @return
+ * TRUE if there is sufficient memory to allow the operation, or FALSE
+ * otherwise.
+ */
+function drupal_check_memory_limit($required, $memory_limit = NULL) {
+ if (!isset($memory_limit)) {
+ $memory_limit = ini_get('memory_limit');
+ }
+
+ // There is sufficient memory if:
+ // - No memory limit is set.
+ // - The memory limit is set to unlimited (-1).
+ // - The memory limit is greater than the memory required for the operation.
+ return ((!$memory_limit) || ($memory_limit == -1) || (parse_size($memory_limit) >= parse_size($required)));
+}
+
+/**
+ * Invalidates a PHP file from any active opcode caches.
+ *
+ * If the opcode cache does not support the invalidation of individual files,
+ * the entire cache will be flushed.
+ *
+ * @param string $filepath
+ * The absolute path of the PHP file to invalidate.
+ */
+function drupal_clear_opcode_cache($filepath) {
+ if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) {
+ // Below PHP 5.3, clearstatcache does not accept any function parameters.
+ clearstatcache();
+ }
+ else {
+ clearstatcache(TRUE, $filepath);
+ }
+
+ // Zend OPcache.
+ if (function_exists('opcache_invalidate')) {
+ opcache_invalidate($filepath, TRUE);
+ }
+ // APC.
+ if (function_exists('apc_delete_file')) {
+ // apc_delete_file() throws a PHP warning in case the specified file was
+ // not compiled yet.
+ // @see http://php.net/apc-delete-file
+ @apc_delete_file($filepath);
+ }
+}
diff -Naur drupal-7.9/includes/cache-install.inc drupal-7.66/includes/cache-install.inc
--- drupal-7.9/includes/cache-install.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/cache-install.inc 2019-04-17 22:20:46.000000000 +0200
@@ -6,7 +6,7 @@
*/
/**
- * A stub cache implementation to be used during the installation process.
+ * Defines a stub cache implementation to be used during installation.
*
* The stub implementation is needed when database access is not yet available.
* Because Drupal's caching system never requires that cached data be present,
@@ -15,17 +15,30 @@
* normal operations would have a negative impact on performance.
*/
class DrupalFakeCache extends DrupalDatabaseCache implements DrupalCacheInterface {
+
+ /**
+ * Overrides DrupalDatabaseCache::get().
+ */
function get($cid) {
return FALSE;
}
+ /**
+ * Overrides DrupalDatabaseCache::getMultiple().
+ */
function getMultiple(&$cids) {
return array();
}
+ /**
+ * Overrides DrupalDatabaseCache::set().
+ */
function set($cid, $data, $expire = CACHE_PERMANENT) {
}
+ /**
+ * Overrides DrupalDatabaseCache::clear().
+ */
function clear($cid = NULL, $wildcard = FALSE) {
// If there is a database cache, attempt to clear it whenever possible. The
// reason for doing this is that the database cache can accumulate data
@@ -52,6 +65,9 @@
}
}
+ /**
+ * Overrides DrupalDatabaseCache::isEmpty().
+ */
function isEmpty() {
return TRUE;
}
diff -Naur drupal-7.9/includes/cache.inc drupal-7.66/includes/cache.inc
--- drupal-7.9/includes/cache.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/cache.inc 2019-04-17 22:20:46.000000000 +0200
@@ -1,18 +1,24 @@
get($cid);
}
/**
- * Return data from the persistent cache when given an array of cache IDs.
+ * Returns data from the persistent cache when given an array of cache IDs.
*
* @param $cids
* An array of cache IDs for the data to retrieve. This is passed by
* reference, and will have the IDs successfully returned from cache removed.
* @param $bin
* The cache bin where the data is stored.
+ *
* @return
* An array of the items successfully returned from cache indexed by cid.
*/
@@ -65,50 +74,22 @@
}
/**
- * Store data in the persistent cache.
+ * Stores data in the persistent cache.
*
* The persistent cache is split up into several cache bins. In the default
* cache implementation, each cache bin corresponds to a database table by the
* same name. Other implementations might want to store several bins in data
* structures that get flushed together. While it is not a problem for most
* cache bins if the entries in them are flushed before their expire time, some
- * might break functionality or are extremely expensive to recalculate. These
- * will be marked with a (*). The other bins expired automatically by core.
- * Contributed modules can add additional bins and get them expired
- * automatically by implementing hook_flush_caches().
- *
- * - cache: Generic cache storage bin (used for variables, theme registry,
- * locale date, list of simpletest tests etc).
- *
- * - cache_block: Stores the content of various blocks.
- *
- * - cache field: Stores the field data belonging to a given object.
- *
- * - cache_filter: Stores filtered pieces of content.
- *
- * - cache_form(*): Stores multistep forms. Flushing this bin means that some
- * forms displayed to users lose their state and the data already submitted
- * to them.
- *
- * - cache_menu: Stores the structure of visible navigation menus per page.
- *
- * - cache_page: Stores generated pages for anonymous users. It is flushed
- * very often, whenever a page changes, at least for every ode and comment
- * submission. This is the only bin affected by the page cache setting on
- * the administrator panel.
- *
- * - cache path: Stores the system paths that have an alias.
- *
- * - cache update(*): Stores available releases. The update server (for
- * example, drupal.org) needs to produce the relevant XML for every project
- * installed on the current site. As this is different for (almost) every
- * site, it's very expensive to recalculate for the update server.
+ * might break functionality or are extremely expensive to recalculate. The
+ * other bins are expired automatically by core. Contributed modules can add
+ * additional bins and get them expired automatically by implementing
+ * hook_flush_caches().
*
* The reasons for having several bins are as follows:
- *
- * - smaller bins mean smaller database tables and allow for faster selects and
- * inserts
- * - we try to put fast changing cache items and rather static ones into
+ * - Smaller bins mean smaller database tables and allow for faster selects and
+ * inserts.
+ * - We try to put fast changing cache items and rather static ones into
* different bins. The effect is that only the fast changing bins will need a
* lot of writes to disk. The more static bins will also be better cacheable
* with MySQL's query cache.
@@ -117,44 +98,67 @@
* The cache ID of the data to store.
* @param $data
* The data to store in the cache. Complex data types will be automatically
- * serialized before insertion.
- * Strings will be stored as plain text and not serialized.
+ * serialized before insertion. Strings will be stored as plain text and are
+ * not serialized. Some storage engines only allow objects up to a maximum of
+ * 1MB in size to be stored by default. When caching large arrays or similar,
+ * take care to ensure $data does not exceed this size.
* @param $bin
- * The cache bin to store the data in. Valid core values are 'cache_block',
- * 'cache_bootstrap', 'cache_field', 'cache_filter', 'cache_form',
- * 'cache_menu', 'cache_page', 'cache_update' or 'cache' for the default
- * cache.
+ * (optional) The cache bin to store the data in. Valid core values are:
+ * - cache: (default) Generic cache storage bin (used for theme registry,
+ * locale date, list of simpletest tests, etc.).
+ * - cache_block: Stores the content of various blocks.
+ * - cache_bootstrap: Stores the class registry, the system list of modules,
+ * the list of which modules implement which hooks, and the Drupal variable
+ * list.
+ * - cache_field: Stores the field data belonging to a given object.
+ * - cache_filter: Stores filtered pieces of content.
+ * - cache_form: Stores multistep forms. Flushing this bin means that some
+ * forms displayed to users lose their state and the data already submitted
+ * to them. This bin should not be flushed before its expired time.
+ * - cache_menu: Stores the structure of visible navigation menus per page.
+ * - cache_page: Stores generated pages for anonymous users. It is flushed
+ * very often, whenever a page changes, at least for every node and comment
+ * submission. This is the only bin affected by the page cache setting on
+ * the administrator panel.
+ * - cache_path: Stores the system paths that have an alias.
* @param $expire
- * One of the following values:
+ * (optional) Controls the maximum lifetime of this cache entry. Note that
+ * caches might be subject to clearing at any time, so this setting does not
+ * guarantee a minimum lifetime. With this in mind, the cache should not be
+ * used for data that must be kept during a cache clear, like sessions.
+ *
+ * Use one of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
* explicitly told to using cache_clear_all() with a cache ID.
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
* general cache wipe.
* - A Unix timestamp: Indicates that the item should be kept at least until
* the given time, after which it behaves like CACHE_TEMPORARY.
+ *
+ * @see _update_cache_set()
+ * @see cache_get()
*/
function cache_set($cid, $data, $bin = 'cache', $expire = CACHE_PERMANENT) {
return _cache_get_object($bin)->set($cid, $data, $expire);
}
/**
- * Expire data from the cache.
+ * Expires data from the cache.
*
- * If called without arguments, expirable entries will be cleared from the
- * cache_page and cache_block bins.
+ * If called with the arguments $cid and $bin set to NULL or omitted, then
+ * expirable entries will be cleared from the cache_page and cache_block bins,
+ * and the $wildcard argument is ignored.
*
* @param $cid
- * If set, the cache ID to delete. Otherwise, all cache entries that can
- * expire are deleted.
- *
+ * If set, the cache ID or an array of cache IDs. Otherwise, all cache entries
+ * that can expire are deleted. The $wildcard argument will be ignored if set
+ * to NULL.
* @param $bin
- * If set, the bin $bin to delete from. Mandatory
- * argument if $cid is set.
- *
+ * If set, the cache bin to delete from. Mandatory argument if $cid is set.
* @param $wildcard
- * If $wildcard is TRUE, cache IDs starting with $cid are deleted in
- * addition to the exact cache ID specified by $cid. If $wildcard is
- * TRUE and $cid is '*' then the entire bin $bin is emptied.
+ * If TRUE, the $cid argument must contain a string value and cache IDs
+ * starting with $cid are deleted in addition to the exact cache ID specified
+ * by $cid. If $wildcard is TRUE and $cid is '*', the entire cache is emptied.
*/
function cache_clear_all($cid = NULL, $bin = NULL, $wildcard = FALSE) {
if (!isset($cid) && !isset($bin)) {
@@ -170,13 +174,14 @@
}
/**
- * Check if a cache bin is empty.
+ * Checks if a cache bin is empty.
*
* A cache bin is considered empty if it does not contain any valid data for any
* cache ID.
*
* @param $bin
* The cache bin to check.
+ *
* @return
* TRUE if the cache bin specified is empty.
*/
@@ -185,7 +190,7 @@
}
/**
- * Interface for cache implementations.
+ * Defines an interface for cache implementations.
*
* All cache implementations have to implement this interface.
* DrupalDatabaseCache provides the default implementation, which can be
@@ -222,49 +227,52 @@
* @see DrupalDatabaseCache
*/
interface DrupalCacheInterface {
- /**
- * Constructor.
- *
- * @param $bin
- * The cache bin for which the object is created.
- */
- function __construct($bin);
/**
- * Return data from the persistent cache. Data may be stored as either plain
- * text or as serialized data. cache_get will automatically return
- * unserialized objects and arrays.
+ * Returns data from the persistent cache.
+ *
+ * Data may be stored as either plain text or as serialized data. cache_get()
+ * will automatically return unserialized objects and arrays.
*
* @param $cid
* The cache ID of the data to retrieve.
+ *
* @return
* The cache or FALSE on failure.
*/
function get($cid);
/**
- * Return data from the persistent cache when given an array of cache IDs.
+ * Returns data from the persistent cache when given an array of cache IDs.
*
* @param $cids
* An array of cache IDs for the data to retrieve. This is passed by
* reference, and will have the IDs successfully returned from cache
* removed.
+ *
* @return
* An array of the items successfully returned from cache indexed by cid.
*/
function getMultiple(&$cids);
/**
- * Store data in the persistent cache.
+ * Stores data in the persistent cache.
*
* @param $cid
* The cache ID of the data to store.
* @param $data
* The data to store in the cache. Complex data types will be automatically
- * serialized before insertion.
- * Strings will be stored as plain text and not serialized.
+ * serialized before insertion. Strings will be stored as plain text and not
+ * serialized. Some storage engines only allow objects up to a maximum of
+ * 1MB in size to be stored by default. When caching large arrays or
+ * similar, take care to ensure $data does not exceed this size.
* @param $expire
- * One of the following values:
+ * (optional) Controls the maximum lifetime of this cache entry. Note that
+ * caches might be subject to clearing at any time, so this setting does not
+ * guarantee a minimum lifetime. With this in mind, the cache should not be
+ * used for data that must be kept during a cache clear, like sessions.
+ *
+ * Use one of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
* explicitly told to using cache_clear_all() with a cache ID.
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
@@ -276,21 +284,25 @@
/**
- * Expire data from the cache. If called without arguments, expirable
- * entries will be cleared from the cache_page and cache_block bins.
+ * Expires data from the cache.
+ *
+ * If called without arguments, expirable entries will be cleared from the
+ * cache_page and cache_block bins.
*
* @param $cid
- * If set, the cache ID to delete. Otherwise, all cache entries that can
- * expire are deleted.
+ * If set, the cache ID or an array of cache IDs. Otherwise, all cache
+ * entries that can expire are deleted. The $wildcard argument will be
+ * ignored if set to NULL.
* @param $wildcard
- * If set to TRUE, the $cid is treated as a substring
- * to match rather than a complete ID. The match is a right hand
- * match. If '*' is given as $cid, the bin $bin will be emptied.
+ * If TRUE, the $cid argument must contain a string value and cache IDs
+ * starting with $cid are deleted in addition to the exact cache ID
+ * specified by $cid. If $wildcard is TRUE and $cid is '*', the entire
+ * cache is emptied.
*/
function clear($cid = NULL, $wildcard = FALSE);
/**
- * Check if a cache bin is empty.
+ * Checks if a cache bin is empty.
*
* A cache bin is considered empty if it does not contain any valid data for
* any cache ID.
@@ -302,7 +314,7 @@
}
/**
- * Default cache implementation.
+ * Defines a default cache implementation.
*
* This is Drupal's default cache implementation. It uses the database to store
* cached data. Each cache bin corresponds to a database table by the same name.
@@ -310,16 +322,28 @@
class DrupalDatabaseCache implements DrupalCacheInterface {
protected $bin;
+ /**
+ * Constructs a DrupalDatabaseCache object.
+ *
+ * @param $bin
+ * The cache bin for which the object is created.
+ */
function __construct($bin) {
$this->bin = $bin;
}
+ /**
+ * Implements DrupalCacheInterface::get().
+ */
function get($cid) {
$cids = array($cid);
$cache = $this->getMultiple($cids);
return reset($cache);
}
+ /**
+ * Implements DrupalCacheInterface::getMultiple().
+ */
function getMultiple(&$cids) {
try {
// Garbage collection necessary when enforcing a minimum cache lifetime.
@@ -357,11 +381,31 @@
* The bin being requested.
*/
protected function garbageCollection() {
- global $user;
+ $cache_lifetime = variable_get('cache_lifetime', 0);
- // Garbage collection necessary when enforcing a minimum cache lifetime.
+ // Clean-up the per-user cache expiration session data, so that the session
+ // handler can properly clean-up the session data for anonymous users.
+ if (isset($_SESSION['cache_expiration'])) {
+ $expire = REQUEST_TIME - $cache_lifetime;
+ foreach ($_SESSION['cache_expiration'] as $bin => $timestamp) {
+ if ($timestamp < $expire) {
+ unset($_SESSION['cache_expiration'][$bin]);
+ }
+ }
+ if (!$_SESSION['cache_expiration']) {
+ unset($_SESSION['cache_expiration']);
+ }
+ }
+
+ // Garbage collection of temporary items is only necessary when enforcing
+ // a minimum cache lifetime.
+ if (!$cache_lifetime) {
+ return;
+ }
+ // When cache lifetime is in force, avoid running garbage collection too
+ // often since this will remove temporary cache items indiscriminately.
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
- if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
+ if ($cache_flush && ($cache_flush + $cache_lifetime <= REQUEST_TIME)) {
// Reset the variable immediately to prevent a meltdown in heavy load situations.
variable_set('cache_flush_' . $this->bin, 0);
// Time to flush old cache data
@@ -373,13 +417,14 @@
}
/**
- * Prepare a cached item.
+ * Prepares a cached item.
*
* Checks that items are either permanent or did not expire, and unserializes
* data as appropriate.
*
* @param $cache
* An item loaded from cache_get() or cache_get_multiple().
+ *
* @return
* The item with data unserialized as appropriate or FALSE if there is no
* valid item to load.
@@ -390,17 +435,16 @@
if (!isset($cache->data)) {
return FALSE;
}
- // If enforcing a minimum cache lifetime, validate that the data is
- // currently valid for this user before we return it by making sure the cache
- // entry was created before the timestamp in the current session's cache
- // timer. The cache variable is loaded into the $user object by _drupal_session_read()
- // in session.inc. If the data is permanent or we're not enforcing a minimum
- // cache lifetime always return the cached data.
- if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && $user->cache > $cache->created) {
- // This cache data is too old and thus not valid for us, ignore it.
+ // If the cached data is temporary and subject to a per-user minimum
+ // lifetime, compare the cache entry timestamp with the user session
+ // cache_expiration timestamp. If the cache entry is too old, ignore it.
+ if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && isset($_SESSION['cache_expiration'][$this->bin]) && $_SESSION['cache_expiration'][$this->bin] > $cache->created) {
+ // Ignore cache data that is too old and thus not valid for this user.
return FALSE;
}
+ // If the data is permanent or not subject to a minimum cache lifetime,
+ // unserialize and return the cached data.
if ($cache->serialized) {
$cache->data = unserialize($cache->data);
}
@@ -408,6 +452,9 @@
return $cache;
}
+ /**
+ * Implements DrupalCacheInterface::set().
+ */
function set($cid, $data, $expire = CACHE_PERMANENT) {
$fields = array(
'serialized' => 0,
@@ -434,16 +481,18 @@
}
}
+ /**
+ * Implements DrupalCacheInterface::clear().
+ */
function clear($cid = NULL, $wildcard = FALSE) {
global $user;
if (empty($cid)) {
if (variable_get('cache_lifetime', 0)) {
- // We store the time in the current user's $user->cache variable which
- // will be saved into the sessions bin by _drupal_session_write(). We then
- // simulate that the cache was flushed for this user by not returning
- // cached data that was cached before the timestamp.
- $user->cache = REQUEST_TIME;
+ // We store the time in the current user's session. We then simulate
+ // that the cache was flushed for this user by not returning cached
+ // data that was cached before the timestamp.
+ $_SESSION['cache_expiration'][$this->bin] = REQUEST_TIME;
$cache_flush = variable_get('cache_flush_' . $this->bin, 0);
if ($cache_flush == 0) {
@@ -471,7 +520,16 @@
else {
if ($wildcard) {
if ($cid == '*') {
- db_truncate($this->bin)->execute();
+ // Check if $this->bin is a cache table before truncating. Other
+ // cache_clear_all() operations throw a PDO error in this situation,
+ // so we don't need to verify them first. This ensures that non-cache
+ // tables cannot be truncated accidentally.
+ if ($this->isValidBin()) {
+ db_truncate($this->bin)->execute();
+ }
+ else {
+ throw new Exception(t('Invalid or missing cache bin specified: %bin', array('%bin' => $this->bin)));
+ }
}
else {
db_delete($this->bin)
@@ -496,6 +554,9 @@
}
}
+ /**
+ * Implements DrupalCacheInterface::isEmpty().
+ */
function isEmpty() {
$this->garbageCollection();
$query = db_select($this->bin);
@@ -505,4 +566,25 @@
->fetchField();
return empty($result);
}
+
+ /**
+ * Checks if $this->bin represents a valid cache table.
+ *
+ * This check is required to ensure that non-cache tables are not truncated
+ * accidentally when calling cache_clear_all().
+ *
+ * @return boolean
+ */
+ function isValidBin() {
+ if ($this->bin == 'cache' || substr($this->bin, 0, 6) == 'cache_') {
+ // Skip schema check for bins with standard table names.
+ return TRUE;
+ }
+ // These fields are required for any cache table.
+ $fields = array('cid', 'data', 'expire', 'created', 'serialized');
+ // Load the table schema.
+ $schema = drupal_get_schema($this->bin);
+ // Confirm that all fields are present.
+ return isset($schema['fields']) && !array_diff($fields, array_keys($schema['fields']));
+ }
}
diff -Naur drupal-7.9/includes/common.inc drupal-7.66/includes/common.inc
--- drupal-7.9/includes/common.inc 2011-10-26 21:53:40.000000000 +0200
+++ drupal-7.66/includes/common.inc 2019-04-17 22:20:46.000000000 +0200
@@ -70,8 +70,7 @@
define('CSS_THEME', 100);
/**
- * The default group for JavaScript libraries, settings or jQuery plugins added
- * to the page.
+ * The default group for JavaScript and jQuery libraries added to the page.
*/
define('JS_LIBRARY', -100);
@@ -86,20 +85,27 @@
define('JS_THEME', 100);
/**
- * Error code indicating that the request made by drupal_http_request() exceeded
- * the specified timeout.
+ * Error code indicating that the request exceeded the specified timeout.
+ *
+ * @see drupal_http_request()
*/
define('HTTP_REQUEST_TIMEOUT', -1);
/**
- * Constants defining cache granularity for blocks and renderable arrays.
+ * @defgroup block_caching Block Caching
+ * @{
+ * Constants that define each block's caching state.
*
- * Modules specify the caching patterns for their blocks using binary
- * combinations of these constants in their hook_block_info():
- * $block[delta]['cache'] = DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE;
- * DRUPAL_CACHE_PER_ROLE is used as a default when no caching pattern is
- * specified. Use DRUPAL_CACHE_CUSTOM to disable standard block cache and
- * implement
+ * Modules specify how their blocks can be cached in their hook_block_info()
+ * implementations. Caching can be turned off (DRUPAL_NO_CACHE), managed by the
+ * module declaring the block (DRUPAL_CACHE_CUSTOM), or managed by the core
+ * Block module. If the Block module is managing the cache, you can specify that
+ * the block is the same for every page and user (DRUPAL_CACHE_GLOBAL), or that
+ * it can change depending on the page (DRUPAL_CACHE_PER_PAGE) or by user
+ * (DRUPAL_CACHE_PER_ROLE or DRUPAL_CACHE_PER_USER). Page and user settings can
+ * be combined with a bitwise-binary or operator; for example,
+ * DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE means that the block can change
+ * depending on the user role or page it is on.
*
* The block cache is cleared in cache_clear_all(), and uses the same clearing
* policy than page cache (node, comment, user, taxonomy added or updated...).
@@ -110,31 +116,35 @@
*/
/**
- * The block should not get cached. This setting should be used:
- * - for simple blocks (notably those that do not perform any db query),
- * where querying the db cache would be more expensive than directly generating
- * the content.
- * - for blocks that change too frequently.
+ * The block should not get cached.
+ *
+ * This setting should be used:
+ * - For simple blocks (notably those that do not perform any db query), where
+ * querying the db cache would be more expensive than directly generating the
+ * content.
+ * - For blocks that change too frequently.
*/
define('DRUPAL_NO_CACHE', -1);
/**
- * The block is handling its own caching in its hook_block_view(). From the
- * perspective of the block cache system, this is equivalent to DRUPAL_NO_CACHE.
- * Useful when time based expiration is needed or a site uses a node access
- * which invalidates standard block cache.
+ * The block is handling its own caching in its hook_block_view().
+ *
+ * This setting is useful when time based expiration is needed or a site uses a
+ * node access which invalidates standard block cache.
*/
define('DRUPAL_CACHE_CUSTOM', -2);
/**
- * The block or element can change depending on the roles the user viewing the
- * page belongs to. This is the default setting for blocks, used when the block
- * does not specify anything.
+ * The block or element can change depending on the user's roles.
+ *
+ * This is the default setting for blocks, used when the block does not specify
+ * anything.
*/
define('DRUPAL_CACHE_PER_ROLE', 0x0001);
/**
- * The block or element can change depending on the user viewing the page.
+ * The block or element can change depending on the user.
+ *
* This setting can be resource-consuming for sites with large number of users,
* and thus should only be used when DRUPAL_CACHE_PER_ROLE is not sufficient.
*/
@@ -146,12 +156,16 @@
define('DRUPAL_CACHE_PER_PAGE', 0x0004);
/**
- * The block or element is the same for every user on every page where it is visible.
+ * The block or element is the same for every user and page that it is visible.
*/
define('DRUPAL_CACHE_GLOBAL', 0x0008);
/**
- * Add content to a specified region.
+ * @} End of "defgroup block_caching".
+ */
+
+/**
+ * Adds content to a specified region.
*
* @param $region
* Page region the content is added to.
@@ -168,7 +182,7 @@
}
/**
- * Get assigned content for a given region.
+ * Gets assigned content for a given region.
*
* @param $region
* A specified region to fetch content for. If NULL, all regions will be
@@ -194,16 +208,16 @@
}
/**
- * Get the name of the currently active install profile.
+ * Gets the name of the currently active installation profile.
*
* When this function is called during Drupal's initial installation process,
* the name of the profile that's about to be installed is stored in the global
* installation state. At all other times, the standard Drupal systems variable
- * table contains the name of the current profile, and we can call variable_get()
- * to determine what one is active.
+ * table contains the name of the current profile, and we can call
+ * variable_get() to determine what one is active.
*
* @return $profile
- * The name of the install profile.
+ * The name of the installation profile.
*/
function drupal_get_profile() {
global $install_state;
@@ -220,7 +234,7 @@
/**
- * Set the breadcrumb trail for the current page.
+ * Sets the breadcrumb trail for the current page.
*
* @param $breadcrumb
* Array of links, starting with "home" and proceeding up to but not including
@@ -236,7 +250,7 @@
}
/**
- * Get the breadcrumb trail for the current page.
+ * Gets the breadcrumb trail for the current page.
*/
function drupal_get_breadcrumb() {
$breadcrumb = drupal_set_breadcrumb();
@@ -265,9 +279,9 @@
}
/**
- * Add output to the head tag of the HTML page.
+ * Adds output to the HEAD tag of the HTML page.
*
- * This function can be called as long the headers aren't sent. Pass no
+ * This function can be called as long as the headers aren't sent. Pass no
* arguments (or NULL for both) to retrieve the currently stored elements.
*
* @param $data
@@ -333,7 +347,7 @@
}
/**
- * Retrieve output to be displayed in the HEAD tag of the HTML page.
+ * Retrieves output to be displayed in the HEAD tag of the HTML page.
*/
function drupal_get_html_head() {
$elements = drupal_add_html_head();
@@ -342,7 +356,7 @@
}
/**
- * Add a feed URL for the current page.
+ * Adds a feed URL for the current page.
*
* This function can be called as long the HTML header hasn't been sent.
*
@@ -370,7 +384,7 @@
}
/**
- * Get the feed URLs for the current page.
+ * Gets the feed URLs for the current page.
*
* @param $delimiter
* A delimiter to split feeds by.
@@ -387,7 +401,7 @@
*/
/**
- * Process a URL query parameter array to remove unwanted elements.
+ * Processes a URL query parameter array to remove unwanted elements.
*
* @param $query
* (optional) An array to be processed. Defaults to $_GET.
@@ -432,19 +446,19 @@
}
/**
- * Split an URL-encoded query string into an array.
+ * Splits a URL-encoded query string into an array.
*
* @param $query
* The query string to split.
*
* @return
- * An array of url decoded couples $param_name => $value.
+ * An array of URL decoded couples $param_name => $value.
*/
function drupal_get_query_array($query) {
$result = array();
if (!empty($query)) {
foreach (explode('&', $query) as $param) {
- $param = explode('=', $param);
+ $param = explode('=', $param, 2);
$result[$param[0]] = isset($param[1]) ? rawurldecode($param[1]) : '';
}
}
@@ -452,7 +466,7 @@
}
/**
- * Parse an array into a valid, rawurlencoded query string.
+ * Parses an array into a valid, rawurlencoded query string.
*
* This differs from http_build_query() as we need to rawurlencode() (instead of
* urlencode()) all query parameters.
@@ -473,7 +487,7 @@
$params = array();
foreach ($query as $key => $value) {
- $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
+ $key = $parent ? $parent . rawurlencode('[' . $key . ']') : rawurlencode($key);
// Recurse into children.
if (is_array($value)) {
@@ -493,13 +507,19 @@
}
/**
- * Prepare a 'destination' URL query parameter for use in combination with drupal_goto().
+ * Prepares a 'destination' URL query parameter for use with drupal_goto().
*
* Used to direct the user back to the referring page after completing a form.
* By default the current URL is returned. If a destination exists in the
* previous request, that destination is returned. As such, a destination can
* persist across multiple pages.
*
+ * @return
+ * An associative array containing the key:
+ * - destination: The path provided via the destination query string or, if
+ * not available, the current path.
+ *
+ * @see current_path()
* @see drupal_goto()
*/
function drupal_get_destination() {
@@ -524,37 +544,32 @@
}
/**
- * Wrapper around parse_url() to parse a system URL string into an associative array, suitable for url().
+ * Parses a URL string into its path, query, and fragment components.
*
- * This function should only be used for URLs that have been generated by the
- * system, resp. url(). It should not be used for URLs that come from external
- * sources, or URLs that link to external resources.
+ * This function splits both internal paths like @code node?b=c#d @endcode and
+ * external URLs like @code https://example.com/a?b=c#d @endcode into their
+ * component parts. See
+ * @link http://tools.ietf.org/html/rfc3986#section-3 RFC 3986 @endlink for an
+ * explanation of what the component parts are.
*
- * The returned array contains a 'path' that may be passed separately to url().
- * For example:
- * @code
- * $options = drupal_parse_url($_GET['destination']);
- * $my_url = url($options['path'], $options);
- * $my_link = l('Example link', $options['path'], $options);
- * @endcode
+ * Note that, unlike the RFC, when passed an external URL, this function
+ * groups the scheme, authority, and path together into the path component.
*
- * This is required, because url() does not support relative URLs containing a
- * query string or fragment in its $path argument. Instead, any query string
- * needs to be parsed into an associative query parameter array in
- * $options['query'] and the fragment into $options['fragment'].
- *
- * @param $url
- * The URL string to parse, f.e. $_GET['destination'].
+ * @param string $url
+ * The internal path or external URL string to parse.
*
- * @return
- * An associative array containing the keys:
- * - 'path': The path of the URL. If the given $url is external, this includes
- * the scheme and host.
- * - 'query': An array of query parameters of $url, if existent.
- * - 'fragment': The fragment of $url, if existent.
+ * @return array
+ * An associative array containing:
+ * - path: The path component of $url. If $url is an external URL, this
+ * includes the scheme, authority, and path.
+ * - query: An array of query parameters from $url, if they exist.
+ * - fragment: The fragment component from $url, if it exists.
*
- * @see url()
* @see drupal_goto()
+ * @see l()
+ * @see url()
+ * @see http://tools.ietf.org/html/rfc3986
+ *
* @ingroup php_wrappers
*/
function drupal_parse_url($url) {
@@ -596,8 +611,9 @@
}
// The 'q' parameter contains the path of the current page if clean URLs are
// disabled. It overrides the 'path' of the URL when present, even if clean
- // URLs are enabled, due to how Apache rewriting rules work.
- if (isset($options['query']['q'])) {
+ // URLs are enabled, due to how Apache rewriting rules work. The path
+ // parameter must be a string.
+ if (isset($options['query']['q']) && is_string($options['query']['q'])) {
$options['path'] = $options['query']['q'];
unset($options['query']['q']);
}
@@ -621,7 +637,7 @@
}
/**
- * Send the user to a different Drupal page.
+ * Sends the user to a different page.
*
* This issues an on-site HTTP redirect. The function makes sure the redirected
* URL is formatted correctly.
@@ -642,20 +658,23 @@
* callback.
*
* @param $path
- * A Drupal path or a full URL.
+ * (optional) A Drupal path or a full URL, which will be passed to url() to
+ * compute the redirect for the URL.
* @param $options
- * An associative array of additional URL options to pass to url().
+ * (optional) An associative array of additional URL options to pass to url().
* @param $http_response_code
- * Valid values for an actual "goto" as per RFC 2616 section 10.3 are:
- * - 301 Moved Permanently (the recommended value for most redirects)
- * - 302 Found (default in Drupal and PHP, sometimes used for spamming search
- * engines)
- * - 303 See Other
- * - 304 Not Modified
- * - 305 Use Proxy
- * - 307 Temporary Redirect (alternative to "503 Site Down for Maintenance")
- * Note: Other values are defined by RFC 2616, but are rarely used and poorly
- * supported.
+ * (optional) The HTTP status code to use for the redirection, defaults to
+ * 302. The valid values for 3xx redirection status codes are defined in
+ * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 RFC 2616 @endlink
+ * and the
+ * @link http://tools.ietf.org/html/draft-reschke-http-status-308-07 draft for the new HTTP status codes: @endlink
+ * - 301: Moved Permanently (the recommended value for most redirects).
+ * - 302: Found (default in Drupal and PHP, sometimes used for spamming search
+ * engines).
+ * - 303: See Other.
+ * - 304: Not Modified.
+ * - 305: Use Proxy.
+ * - 307: Temporary Redirect.
*
* @see drupal_get_destination()
* @see url()
@@ -670,6 +689,13 @@
$options['fragment'] = $destination['fragment'];
}
+ // In some cases modules call drupal_goto(current_path()). We need to ensure
+ // that such a redirect is not to an external URL.
+ if ($path === current_path() && empty($options['external']) && url_is_external($path)) {
+ // Force url() to generate a non-external URL.
+ $options['external'] = FALSE;
+ }
+
drupal_alter('drupal_goto', $path, $options, $http_response_code);
// The 'Location' HTTP header must be absolute.
@@ -686,7 +712,7 @@
}
/**
- * Deliver a "site is under maintenance" message to the browser.
+ * Delivers a "site is under maintenance" message to the browser.
*
* Page callback functions wanting to report a "site offline" message should
* return MENU_SITE_OFFLINE instead of calling drupal_site_offline(). However,
@@ -698,7 +724,7 @@
}
/**
- * Deliver a "page not found" error to the browser.
+ * Delivers a "page not found" error to the browser.
*
* Page callback functions wanting to report a "page not found" message should
* return MENU_NOT_FOUND instead of calling drupal_not_found(). However,
@@ -710,19 +736,20 @@
}
/**
- * Deliver a "access denied" error to the browser.
+ * Delivers an "access denied" error to the browser.
*
* Page callback functions wanting to report an "access denied" message should
* return MENU_ACCESS_DENIED instead of calling drupal_access_denied(). However,
* functions that are invoked in contexts where that return value might not
- * bubble up to menu_execute_active_handler() should call drupal_access_denied().
+ * bubble up to menu_execute_active_handler() should call
+ * drupal_access_denied().
*/
function drupal_access_denied() {
drupal_deliver_page(MENU_ACCESS_DENIED);
}
/**
- * Perform an HTTP request.
+ * Performs an HTTP request.
*
* This is a flexible and powerful HTTP client implementation. Correctly
* handles GET, POST, PUT or any other HTTP requests. Handles redirects.
@@ -734,7 +761,8 @@
* - headers: An array containing request headers to send as name/value pairs.
* - method: A string containing the request method. Defaults to 'GET'.
* - data: A string containing the request body, formatted as
- * 'param=value¶m=value&...'. Defaults to NULL.
+ * 'param=value¶m=value&...'; to generate this, use http_build_query().
+ * Defaults to NULL.
* - max_redirects: An integer representing how many times a redirect
* may be followed. Defaults to 3.
* - timeout: A float representing the maximum number of seconds the function
@@ -759,8 +787,17 @@
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
* easy access the array keys are returned in lower case.
* - data: A string containing the response body that was received.
+ *
+ * @see http_build_query()
*/
function drupal_http_request($url, array $options = array()) {
+ // Allow an alternate HTTP client library to replace Drupal's default
+ // implementation.
+ $override_function = variable_get('drupal_http_request_function', FALSE);
+ if (!empty($override_function) && function_exists($override_function)) {
+ return $override_function($url, $options);
+ }
+
$result = new stdClass();
// Parse the URL and make sure we can handle the schema.
@@ -789,10 +826,53 @@
'timeout' => 30.0,
'context' => NULL,
);
+
+ // Merge the default headers.
+ $options['headers'] += array(
+ 'User-Agent' => 'Drupal (+http://drupal.org/)',
+ );
+
// stream_socket_client() requires timeout to be a float.
$options['timeout'] = (float) $options['timeout'];
+ // Use a proxy if one is defined and the host is not on the excluded list.
+ $proxy_server = variable_get('proxy_server', '');
+ if ($proxy_server && _drupal_http_use_proxy($uri['host'])) {
+ // Set the scheme so we open a socket to the proxy server.
+ $uri['scheme'] = 'proxy';
+ // Set the path to be the full URL.
+ $uri['path'] = $url;
+ // Since the URL is passed as the path, we won't use the parsed query.
+ unset($uri['query']);
+
+ // Add in username and password to Proxy-Authorization header if needed.
+ if ($proxy_username = variable_get('proxy_username', '')) {
+ $proxy_password = variable_get('proxy_password', '');
+ $options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . (!empty($proxy_password) ? ":" . $proxy_password : ''));
+ }
+ // Some proxies reject requests with any User-Agent headers, while others
+ // require a specific one.
+ $proxy_user_agent = variable_get('proxy_user_agent', '');
+ // The default value matches neither condition.
+ if ($proxy_user_agent === NULL) {
+ unset($options['headers']['User-Agent']);
+ }
+ elseif ($proxy_user_agent) {
+ $options['headers']['User-Agent'] = $proxy_user_agent;
+ }
+ }
+
switch ($uri['scheme']) {
+ case 'proxy':
+ // Make the socket connection to a proxy server.
+ $socket = 'tcp://' . $proxy_server . ':' . variable_get('proxy_port', 8080);
+ // The Host header still needs to match the real request.
+ if (!isset($options['headers']['Host'])) {
+ $options['headers']['Host'] = $uri['host'];
+ $options['headers']['Host'] .= isset($uri['port']) && $uri['port'] != 80 ? ':' . $uri['port'] : '';
+ }
+ break;
+
case 'http':
case 'feed':
$port = isset($uri['port']) ? $uri['port'] : 80;
@@ -800,14 +880,20 @@
// RFC 2616: "non-standard ports MUST, default ports MAY be included".
// We don't add the standard port to prevent from breaking rewrite rules
// checking the host that do not take into account the port number.
- $options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : '');
+ if (!isset($options['headers']['Host'])) {
+ $options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : '');
+ }
break;
+
case 'https':
// Note: Only works when PHP is compiled with OpenSSL support.
$port = isset($uri['port']) ? $uri['port'] : 443;
$socket = 'ssl://' . $uri['host'] . ':' . $port;
- $options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : '');
+ if (!isset($options['headers']['Host'])) {
+ $options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : '');
+ }
break;
+
default:
$result->error = 'invalid schema ' . $uri['scheme'];
$result->code = -1003;
@@ -832,7 +918,7 @@
// Mark that this request failed. This will trigger a check of the web
// server's ability to make outgoing HTTP requests the next time that
// requirements checking is performed.
- // See system_requirements()
+ // See system_requirements().
variable_set('drupal_http_request_fails', TRUE);
return $result;
@@ -844,11 +930,6 @@
$path .= '?' . $uri['query'];
}
- // Merge the default headers.
- $options['headers'] += array(
- 'User-Agent' => 'Drupal (+http://drupal.org/)',
- );
-
// Only add Content-Length if we actually have any content or if it is a POST
// or PUT request. Some non-standard servers get confused by Content-Length in
// at least HEAD/GET requests, and Squid always requires Content-Length in
@@ -860,7 +941,7 @@
// If the server URL has a user then attempt to use basic authentication.
if (isset($uri['user'])) {
- $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ''));
+ $options['headers']['Authorization'] = 'Basic ' . base64_encode($uri['user'] . (isset($uri['pass']) ? ':' . $uri['pass'] : ':'));
}
// If the database prefix is being used by SimpleTest to run the tests in a copied
@@ -921,9 +1002,10 @@
$response = preg_split("/\r\n|\n|\r/", $response);
// Parse the response status line.
- list($protocol, $code, $status_message) = explode(' ', trim(array_shift($response)), 3);
- $result->protocol = $protocol;
- $result->status_message = $status_message;
+ $response_status_array = _drupal_parse_response_status(trim(array_shift($response)));
+ $result->protocol = $response_status_array['http_version'];
+ $result->status_message = $response_status_array['reason_phrase'];
+ $code = $response_status_array['response_code'];
$result->headers = array();
@@ -992,6 +1074,12 @@
switch ($code) {
case 200: // OK
+ case 201: // Created
+ case 202: // Accepted
+ case 203: // Non-Authoritative Information
+ case 204: // No Content
+ case 205: // Reset Content
+ case 206: // Partial Content
case 304: // Not modified
break;
case 301: // Moved permanently
@@ -1006,6 +1094,11 @@
elseif ($options['max_redirects']) {
// Redirect to the new location.
$options['max_redirects']--;
+
+ // We need to unset the 'Host' header
+ // as we are redirecting to a new location.
+ unset($options['headers']['Host']);
+
$result = drupal_http_request($location, $options);
$result->redirect_code = $code;
}
@@ -1014,15 +1107,66 @@
}
break;
default:
- $result->error = $status_message;
+ $result->error = $result->status_message;
}
return $result;
}
+
+/**
+ * Splits an HTTP response status line into components.
+ *
+ * See the @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html status line definition @endlink
+ * in RFC 2616.
+ *
+ * @param string $respone
+ * The response status line, for example 'HTTP/1.1 500 Internal Server Error'.
+ *
+ * @return array
+ * Keyed array containing the component parts. If the response is malformed,
+ * all possible parts will be extracted. 'reason_phrase' could be empty.
+ * Possible keys:
+ * - 'http_version'
+ * - 'response_code'
+ * - 'reason_phrase'
+ */
+function _drupal_parse_response_status($response) {
+ $response_array = explode(' ', trim($response), 3);
+ // Set up empty values.
+ $result = array(
+ 'reason_phrase' => '',
+ );
+ $result['http_version'] = $response_array[0];
+ $result['response_code'] = $response_array[1];
+ if (isset($response_array[2])) {
+ $result['reason_phrase'] = $response_array[2];
+ }
+ return $result;
+}
+
+/**
+ * Helper function for determining hosts excluded from needing a proxy.
+ *
+ * @return
+ * TRUE if a proxy should be used for this host.
+ */
+function _drupal_http_use_proxy($host) {
+ $proxy_exceptions = variable_get('proxy_exceptions', array('localhost', '127.0.0.1'));
+ return !in_array(strtolower($host), $proxy_exceptions, TRUE);
+}
+
/**
* @} End of "HTTP handling".
*/
+/**
+ * Strips slashes from a string or array of strings.
+ *
+ * Callback for array_walk() within fix_gpx_magic().
+ *
+ * @param $item
+ * An individual string or array of strings from superglobals.
+ */
function _fix_gpc_magic(&$item) {
if (is_array($item)) {
array_walk($item, '_fix_gpc_magic');
@@ -1033,11 +1177,19 @@
}
/**
- * Helper function to strip slashes from $_FILES skipping over the tmp_name keys
- * since PHP generates single backslashes for file paths on Windows systems.
+ * Strips slashes from $_FILES items.
+ *
+ * Callback for array_walk() within fix_gpc_magic().
*
- * tmp_name does not have backslashes added see
- * http://php.net/manual/en/features.file-upload.php#42280
+ * The tmp_name key is skipped keys since PHP generates single backslashes for
+ * file paths on Windows systems.
+ *
+ * @param $item
+ * An item from $_FILES.
+ * @param $key
+ * The key for the item within $_FILES.
+ *
+ * @see http://php.net/manual/features.file-upload.php#42280
*/
function _fix_gpc_magic_files(&$item, $key) {
if ($key != 'tmp_name') {
@@ -1051,7 +1203,10 @@
}
/**
- * Fix double-escaping problems caused by "magic quotes" in some PHP installations.
+ * Fixes double-escaping caused by "magic quotes" in some PHP installations.
+ *
+ * @see _fix_gpc_magic()
+ * @see _fix_gpc_magic_files()
*/
function fix_gpc_magic() {
static $fixed = FALSE;
@@ -1072,12 +1227,14 @@
*/
/**
- * Verify the syntax of the given e-mail address.
+ * Verifies the syntax of the given e-mail address.
*
- * Empty e-mail addresses are allowed. See RFC 2822 for details.
+ * This uses the
+ * @link http://php.net/manual/filter.filters.validate.php PHP e-mail validation filter. @endlink
*
* @param $mail
* A string containing an e-mail address.
+ *
* @return
* TRUE if the address is in a valid format.
*/
@@ -1086,7 +1243,7 @@
}
/**
- * Verify the syntax of the given URL.
+ * Verifies the syntax of the given URL.
*
* This function should only be used on actual URLs. It should not be used for
* Drupal menu paths, which can contain arbitrary characters.
@@ -1095,6 +1252,7 @@
* The URL to verify.
* @param $absolute
* Whether the URL is absolute (beginning with a scheme such as "http:").
+ *
* @return
* TRUE if the URL is in a valid format.
*/
@@ -1127,7 +1285,7 @@
*/
/**
- * Register an event for the current visitor to the flood control mechanism.
+ * Registers an event for the current visitor to the flood control mechanism.
*
* @param $name
* The name of an event.
@@ -1154,7 +1312,7 @@
}
/**
- * Make the flood control mechanism forget about an event for the current visitor.
+ * Makes the flood control mechanism forget an event for the current visitor.
*
* @param $name
* The name of an event.
@@ -1172,7 +1330,7 @@
}
/**
- * Checks whether user is allowed to proceed with the specified event.
+ * Checks whether a user is allowed to proceed with the specified event.
*
* Events can have thresholds saying that each user can only do that event
* a certain number of times in a time window. This function verifies that the
@@ -1266,7 +1424,7 @@
}
/**
- * Strips dangerous protocols (e.g. 'javascript:') from a URI and encodes it for output to an HTML attribute value.
+ * Strips dangerous protocols from a URI and encodes it for output to HTML.
*
* @param $uri
* A plain-text URI that might contain dangerous protocols.
@@ -1286,7 +1444,7 @@
}
/**
- * Very permissive XSS/HTML filter for admin-only use.
+ * Applies a very permissive XSS/HTML filter for admin-only use.
*
* Use only for fields where it is impractical to use the
* whole filter system, but where some (mainly inline) mark-up
@@ -1300,7 +1458,7 @@
}
/**
- * Filters an HTML string to prevent cross-site-scripting (XSS) vulnerabilities.
+ * Filters HTML to prevent cross-site-scripting (XSS) vulnerabilities.
*
* Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
* For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
@@ -1323,7 +1481,6 @@
* valid UTF-8.
*
* @see drupal_validate_utf8()
- * @ingroup sanitization
*/
function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
// Only operate on valid UTF-8 strings. This is necessary to prevent cross
@@ -1331,21 +1488,21 @@
if (!drupal_validate_utf8($string)) {
return '';
}
- // Store the text format
+ // Store the text format.
_filter_xss_split($allowed_tags, TRUE);
- // Remove NULL characters (ignored by some browsers)
+ // Remove NULL characters (ignored by some browsers).
$string = str_replace(chr(0), '', $string);
- // Remove Netscape 4 JS entities
+ // Remove Netscape 4 JS entities.
$string = preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
- // Defuse all HTML entities
+ // Defuse all HTML entities.
$string = str_replace('&', '&', $string);
- // Change back only well-formed entities in our whitelist
- // Decimal numeric entities
+ // Change back only well-formed entities in our whitelist:
+ // Decimal numeric entities.
$string = preg_replace('/&#([0-9]+;)/', '\1', $string);
- // Hexadecimal numeric entities
+ // Hexadecimal numeric entities.
$string = preg_replace('/&#[Xx]0*((?:[0-9A-Fa-f]{2})+;)/', '\1', $string);
- // Named entities
+ // Named entities.
$string = preg_replace('/&([A-Za-z][A-Za-z0-9]*;)/', '&\1', $string);
return preg_replace_callback('%
@@ -1369,6 +1526,7 @@
* If $store is FALSE then the array has one element, the HTML tag to process.
* @param $store
* Whether to store $m.
+ *
* @return
* If the element isn't allowed, an empty string. Otherwise, the cleaned up
* version of the HTML element.
@@ -1384,16 +1542,16 @@
$string = $m[1];
if (substr($string, 0, 1) != '<') {
- // We matched a lone ">" character
+ // We matched a lone ">" character.
return '>';
}
elseif (strlen($string) == 1) {
- // We matched a lone "<" character
+ // We matched a lone "<" character.
return '<';
}
- if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|()$%', $string, $matches)) {
- // Seriously malformed
+ if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|()$%', $string, $matches)) {
+ // Seriously malformed.
return '';
}
@@ -1407,7 +1565,7 @@
}
if (!isset($allowed_html[strtolower($elem)])) {
- // Disallowed HTML element
+ // Disallowed HTML element.
return '';
}
@@ -1423,7 +1581,7 @@
$attrlist = preg_replace('%(\s?)/\s*$%', '\1', $attrlist, -1, $count);
$xhtml_slash = $count ? ' /' : '';
- // Clean up attributes
+ // Clean up attributes.
$attr2 = implode(' ', _filter_xss_attributes($attrlist));
$attr2 = preg_replace('/[<>]/', '', $attr2);
$attr2 = strlen($attr2) ? ' ' . $attr2 : '';
@@ -1448,7 +1606,7 @@
switch ($mode) {
case 0:
- // Attribute name, href for instance
+ // Attribute name, href for instance.
if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
$attrname = strtolower($match[1]);
$skip = ($attrname == 'style' || substr($attrname, 0, 2) == 'on');
@@ -1458,7 +1616,7 @@
break;
case 1:
- // Equals sign or valueless ("selected")
+ // Equals sign or valueless ("selected").
if (preg_match('/^\s*=\s*/', $attr)) {
$working = 1; $mode = 2;
$attr = preg_replace('/^\s*=\s*/', '', $attr);
@@ -1475,7 +1633,7 @@
break;
case 2:
- // Attribute value, a URL after href= for instance
+ // Attribute value, a URL after href= for instance.
if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) {
$thisval = filter_xss_bad_protocol($match[1]);
@@ -1512,7 +1670,7 @@
}
if ($working == 0) {
- // not well formed, remove and try again
+ // Not well formed; remove and try again.
$attr = preg_replace('/
^
(
@@ -1536,15 +1694,16 @@
}
/**
- * Processes an HTML attribute value and ensures it does not contain an URL with a disallowed protocol (e.g. javascript:).
+ * Processes an HTML attribute value and strips dangerous protocols from URLs.
*
* @param $string
* The string with the attribute value.
* @param $decode
- * (Deprecated) Whether to decode entities in the $string. Set to FALSE if the
+ * (deprecated) Whether to decode entities in the $string. Set to FALSE if the
* $string is in plain text, TRUE otherwise. Defaults to TRUE. This parameter
* is deprecated and will be removed in Drupal 8. To process a plain-text URI,
* call drupal_strip_dangerous_protocols() or check_url() instead.
+ *
* @return
* Cleaned up and HTML-escaped version of $string.
*/
@@ -1598,7 +1757,7 @@
}
/**
- * Format a single RSS item.
+ * Formats a single RSS item.
*
* Arbitrary elements may be added using the $args associative array.
*/
@@ -1614,7 +1773,7 @@
}
/**
- * Format XML elements.
+ * Formats XML elements.
*
* @param $array
* An array where each item represents an element and is either a:
@@ -1623,9 +1782,15 @@
* - 'key': element name
* - 'value': element contents
* - 'attributes': associative array of element attributes
+ * - 'encoded': TRUE if 'value' is already encoded
*
* In both cases, 'value' can be a simple string, or it can be another array
* with the same format as $array itself for nesting.
+ *
+ * If 'encoded' is TRUE it is up to the caller to ensure that 'value' is either
+ * entity-encoded or CDATA-escaped. Using this option is not recommended when
+ * working with untrusted user input, since failing to escape the data
+ * correctly has security implications.
*/
function format_xml_elements($array) {
$output = '';
@@ -1638,7 +1803,7 @@
}
if (isset($value['value']) && $value['value'] != '') {
- $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : check_plain($value['value'])) . '' . $value['key'] . ">\n";
+ $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : (!empty($value['encoded']) ? $value['value'] : check_plain($value['value']))) . '' . $value['key'] . ">\n";
}
else {
$output .= " />\n";
@@ -1653,7 +1818,7 @@
}
/**
- * Format a string containing a count of items.
+ * Formats a string containing a count of items.
*
* This function ensures that the string is pluralized correctly. Since t() is
* called by this function, make sure not to pass already-localized strings to
@@ -1669,37 +1834,33 @@
* $output = format_plural($update_count,
* 'Changed the content type of 1 post from %old-type to %new-type.',
* 'Changed the content type of @count posts from %old-type to %new-type.',
- * array('%old-type' => $info->old_type, '%new-type' => $info->new_type)));
+ * array('%old-type' => $info->old_type, '%new-type' => $info->new_type));
* @endcode
*
* @param $count
* The item count to display.
* @param $singular
- * The string for the singular case. Please make sure it is clear this is
- * singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
- * Do not use @count in the singular string.
+ * The string for the singular case. Make sure it is clear this is singular,
+ * to ease translation (e.g. use "1 new comment" instead of "1 new"). Do not
+ * use @count in the singular string.
* @param $plural
- * The string for the plural case. Please make sure it is clear this is plural,
- * to ease translation. Use @count in place of the item count, as in "@count
- * new comments".
+ * The string for the plural case. Make sure it is clear this is plural, to
+ * ease translation. Use @count in place of the item count, as in
+ * "@count new comments".
* @param $args
- * An associative array of replacements to make after translation. Incidences
+ * An associative array of replacements to make after translation. Instances
* of any key in this array are replaced with the corresponding value.
- * Based on the first character of the key, the value is escaped and/or themed:
- * - !variable: inserted as is
- * - @variable: escape plain text to HTML (check_plain)
- * - %variable: escape text and theme as a placeholder for user-submitted
- * content (check_plain + drupal_placeholder)
- * Note that you do not need to include @count in this array.
- * This replacement is done automatically for the plural case.
+ * Based on the first character of the key, the value is escaped and/or
+ * themed. See format_string(). Note that you do not need to include @count
+ * in this array; this replacement is done automatically for the plural case.
* @param $options
- * An associative array of additional options, with the following keys:
- * - 'langcode' (default to the current language) The language code to
- * translate to a language other than what is used to display the page.
- * - 'context' (default to the empty context) The context the source string
- * belongs to.
+ * An associative array of additional options. See t() for allowed keys.
+ *
* @return
* A translated string.
+ *
+ * @see t()
+ * @see format_string()
*/
function format_plural($count, $singular, $plural, array $args = array(), array $options = array()) {
$args['@count'] = $count;
@@ -1709,7 +1870,8 @@
// Get the plural index through the gettext formula.
$index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1;
- // Backwards compatibility.
+ // If the index cannot be computed, use the plural as a fallback (which
+ // allows for most flexiblity with the replaceable @count value).
if ($index < 0) {
return t($plural, $args, $options);
}
@@ -1728,11 +1890,12 @@
}
/**
- * Parse a given byte count.
+ * Parses a given byte count.
*
* @param $size
* A size expressed as a number of bytes with optional SI or IEC binary unit
* prefix (e.g. 2, 3K, 5MB, 10G, 6GiB, 8 bytes, 9mbytes).
+ *
* @return
* An integer representation of the size in bytes.
*/
@@ -1749,13 +1912,14 @@
}
/**
- * Generate a string representation for the given byte count.
+ * Generates a string representation for the given byte count.
*
* @param $size
* A size in bytes.
* @param $langcode
* Optional language code to translate to a language other than what is used
* to display the page.
+ *
* @return
* A translated string representation of the size.
*/
@@ -1788,19 +1952,20 @@
}
/**
- * Format a time interval with the requested granularity.
+ * Formats a time interval with the requested granularity.
*
- * @param $timestamp
+ * @param $interval
* The length of the interval in seconds.
* @param $granularity
* How many different units to display in the string.
* @param $langcode
* Optional language code to translate to a language other than
* what is used to display the page.
+ *
* @return
* A translated string representation of the interval.
*/
-function format_interval($timestamp, $granularity = 2, $langcode = NULL) {
+function format_interval($interval, $granularity = 2, $langcode = NULL) {
$units = array(
'1 year|@count years' => 31536000,
'1 month|@count months' => 2592000,
@@ -1813,9 +1978,9 @@
$output = '';
foreach ($units as $key => $value) {
$key = explode('|', $key);
- if ($timestamp >= $value) {
- $output .= ($output ? ' ' : '') . format_plural(floor($timestamp / $value), $key[0], $key[1], array(), array('langcode' => $langcode));
- $timestamp %= $value;
+ if ($interval >= $value) {
+ $output .= ($output ? ' ' : '') . format_plural(floor($interval / $value), $key[0], $key[1], array(), array('langcode' => $langcode));
+ $interval %= $value;
$granularity--;
}
@@ -1845,7 +2010,7 @@
* get interpreted as date format characters.
* @param $timezone
* (optional) Time zone identifier, as described at
- * http://php.net/manual/en/timezones.php Defaults to the time zone used to
+ * http://php.net/manual/timezones.php Defaults to the time zone used to
* display the page.
* @param $langcode
* (optional) Language code to translate to. Defaults to the language used to
@@ -1928,10 +2093,11 @@
/**
* Returns an ISO8601 formatted date based on the given date.
*
- * Can be used as a callback for RDF mappings.
+ * Callback for use within hook_rdf_mapping() implementations.
*
* @param $date
* A UNIX timestamp.
+ *
* @return string
* An ISO8601 formatted date.
*/
@@ -1942,7 +2108,9 @@
}
/**
- * Callback function for preg_replace_callback().
+ * Translates a formatted date string.
+ *
+ * Callback for preg_replace_callback() within format_date().
*/
function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
// We cache translations to avoid redundant and rather costly calls to t().
@@ -1978,6 +2146,9 @@
/**
* Format a username.
*
+ * This is also the label callback implementation of
+ * callback_entity_info_label() for user_entity_info().
+ *
* By default, the passed-in object's 'name' property is used if it exists, or
* else, the site-defined value for the 'anonymous' variable. However, a module
* may override this by implementing hook_username_alter(&$name, $account).
@@ -2009,8 +2180,9 @@
* alternative than url().
*
* @param $path
- * The internal path or external URL being linked to, such as "node/34" or
- * "http://example.com/foo". A few notes:
+ * (optional) The internal path or external URL being linked to, such as
+ * "node/34" or "http://example.com/foo". The default value is equivalent to
+ * passing in ''. A few notes:
* - If you provide a full URL, it will be considered an external URL.
* - If you provide only the path (e.g. "node/34"), it will be
* considered an internal link. In this case, it should be a system URL,
@@ -2026,7 +2198,8 @@
* include them in $path, or use $options['query'] to let this function
* URL encode them.
* @param $options
- * An associative array of additional options, with the following elements:
+ * (optional) An associative array of additional options, with the following
+ * elements:
* - 'query': An array of query key/value-pairs (without any URL-encoding) to
* append to the URL.
* - 'fragment': A fragment identifier (named anchor) to append to the URL.
@@ -2042,7 +2215,7 @@
* for the URL. If $options['language'] is omitted, the global $language_url
* will be used.
* - 'https': Whether this URL should point to a secure location. If not
- * defined, the current scheme is used, so the user stays on http or https
+ * defined, the current scheme is used, so the user stays on HTTP or HTTPS
* respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
* only be enforced when the variable 'https' is set to TRUE.
* - 'base_url': Only used internally, to modify the base URL when a language
@@ -2057,8 +2230,8 @@
* Drupal on a web server that cannot be configured to automatically find
* index.php, then hook_url_outbound_alter() can be implemented to force
* this value to 'index.php'.
- * - 'entity_type': The entity type of the object that called url(). Only set if
- * url() is invoked by entity_uri().
+ * - 'entity_type': The entity type of the object that called url(). Only
+ * set if url() is invoked by entity_uri().
* - 'entity': The entity object (such as a node) for which the URL is being
* generated. Only set if url() is invoked by entity_uri().
*
@@ -2075,14 +2248,11 @@
'prefix' => ''
);
+ // Determine whether this is an external link, but ensure that the current
+ // path is always treated as internal by default (to prevent external link
+ // injection vulnerabilities).
if (!isset($options['external'])) {
- // Return an external link if $path contains an allowed absolute URL. Only
- // call the slow drupal_strip_dangerous_protocols() if $path contains a ':'
- // before any / ? or #. Note: we could use url_is_external($path) here, but
- // that would require another function call, and performance inside url() is
- // critical.
- $colonpos = strpos($path, ':');
- $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path);
+ $options['external'] = $path === $_GET['q'] ? FALSE : url_is_external($path);
}
// Preserve the original path before altering or aliasing.
@@ -2120,6 +2290,11 @@
return $path . $options['fragment'];
}
+ // Strip leading slashes from internal paths to prevent them becoming external
+ // URLs without protocol. /example.com should not be turned into
+ // //example.com.
+ $path = ltrim($path, '/');
+
global $base_url, $base_secure_url, $base_insecure_url;
// The base_url might be rewritten from the language rewrite in domain mode.
@@ -2147,7 +2322,10 @@
$language = isset($options['language']) && isset($options['language']->language) ? $options['language']->language : '';
$alias = drupal_get_path_alias($original_path, $language);
if ($alias != $original_path) {
- $path = $alias;
+ // Strip leading slashes from internal path aliases to prevent them
+ // becoming external URLs without protocol. /example.com should not be
+ // turned into //example.com.
+ $path = ltrim($alias, '/');
}
}
@@ -2183,7 +2361,7 @@
}
/**
- * Return TRUE if a path is external to Drupal (e.g. http://example.com).
+ * Returns TRUE if a path is external to Drupal (e.g. http://example.com).
*
* If a path cannot be assessed by Drupal's menu handler, then we must
* treat it as potentially insecure.
@@ -2191,19 +2369,31 @@
* @param $path
* The internal path or external URL being linked to, such as "node/34" or
* "http://example.com/foo".
+ *
* @return
* Boolean TRUE or FALSE, where TRUE indicates an external path.
*/
function url_is_external($path) {
$colonpos = strpos($path, ':');
- // Avoid calling drupal_strip_dangerous_protocols() if there is any
- // slash (/), hash (#) or question_mark (?) before the colon (:)
- // occurrence - if any - as this would clearly mean it is not a URL.
- return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path;
+ // Some browsers treat \ as / so normalize to forward slashes.
+ $path = str_replace('\\', '/', $path);
+ // If the path starts with 2 slashes then it is always considered an external
+ // URL without an explicit protocol part.
+ return (strpos($path, '//') === 0)
+ // Leading control characters may be ignored or mishandled by browsers, so
+ // assume such a path may lead to an external location. The \p{C} character
+ // class matches all UTF-8 control, unassigned, and private characters.
+ || (preg_match('/^\p{C}/u', $path) !== 0)
+ // Avoid calling drupal_strip_dangerous_protocols() if there is any slash
+ // (/), hash (#) or question_mark (?) before the colon (:) occurrence - if
+ // any - as this would clearly mean it is not a URL.
+ || ($colonpos !== FALSE
+ && !preg_match('![/?#]!', substr($path, 0, $colonpos))
+ && drupal_strip_dangerous_protocols($path) == $path);
}
/**
- * Format an attribute string for a HTTP header.
+ * Formats an attribute string for an HTTP header.
*
* @param $attributes
* An associative array of attributes such as 'rel'.
@@ -2225,7 +2415,7 @@
}
/**
- * Converts an associative array to an attribute string for use in XML/HTML tags.
+ * Converts an associative array to an XML/HTML tag attribute string.
*
* Each array key and its value will be formatted into an attribute string.
* If a value is itself an array, then its elements are concatenated to a single
@@ -2271,21 +2461,30 @@
/**
* Formats an internal or external URL link as an HTML anchor tag.
*
- * This function correctly handles aliased paths, and adds an 'active' class
+ * This function correctly handles aliased paths and adds an 'active' class
* attribute to links that point to the current page (for theming), so all
* internal links output by modules should be generated by this function if
* possible.
*
- * @param $text
- * The link text for the anchor tag.
- * @param $path
+ * However, for links enclosed in translatable text you should use t() and
+ * embed the HTML anchor tag directly in the translated string. For example:
+ * @code
+ * t('Visit the settings page', array('@url' => url('admin')));
+ * @endcode
+ * This keeps the context of the link title ('settings' in the example) for
+ * translators.
+ *
+ * @param string $text
+ * The translated link text for the anchor tag.
+ * @param string $path
* The internal path or external URL being linked to, such as "node/34" or
* "http://example.com/foo". After the url() function is called to construct
* the URL from $path and $options, the resulting URL is passed through
* check_plain() before it is inserted into the HTML anchor tag, to ensure
* well-formed HTML. See url() for more information and notes.
* @param array $options
- * An associative array of additional options, with the following elements:
+ * An associative array of additional options. Defaults to an empty array. It
+ * may contain the following elements.
* - 'attributes': An associative array of HTML attributes to apply to the
* anchor tag. If element 'class' is included, it must be an array; 'title'
* must be a string; other elements are more flexible, as they just need
@@ -2301,8 +2500,10 @@
* well as the path must match). This element is also used by url().
* - Additional $options elements used by the url() function.
*
- * @return
+ * @return string
* An HTML string containing a link to the given path.
+ *
+ * @see url()
*/
function l($text, $path, array $options = array()) {
global $language_url;
@@ -2338,7 +2539,7 @@
// rendering.
if (variable_get('theme_link', TRUE)) {
drupal_theme_initialize();
- $registry = theme_get_registry();
+ $registry = theme_get_registry(FALSE);
// We don't want to duplicate functionality that's in theme(), so any
// hint of a module or theme doing anything at all special with the 'link'
// theme hook should simply result in theme() being called. This includes
@@ -2446,7 +2647,7 @@
}
/**
- * Package and send the result of a page callback to the browser as HTML.
+ * Packages and sends the result of a page callback to the browser as HTML.
*
* @param $page_callback_result
* The result of a page callback. Can be one of:
@@ -2466,6 +2667,19 @@
drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
}
+ // Send appropriate HTTP-Header for browsers and search engines.
+ global $language;
+ drupal_add_http_header('Content-Language', $language->language);
+
+ // By default, do not allow the site to be rendered in an iframe on another
+ // domain, but provide a variable to override this. If the code running for
+ // this page request already set the X-Frame-Options header earlier, don't
+ // overwrite it here.
+ $frame_options = variable_get('x_frame_options', 'SAMEORIGIN');
+ if ($frame_options && is_null(drupal_get_http_header('X-Frame-Options'))) {
+ drupal_add_http_header('X-Frame-Options', $frame_options);
+ }
+
// Menu status constants are integers; page content is a string or array.
if (is_int($page_callback_result)) {
// @todo: Break these up into separate functions?
@@ -2481,7 +2695,10 @@
// Keep old path for reference, and to allow forms to redirect to it.
if (!isset($_GET['destination'])) {
- $_GET['destination'] = $_GET['q'];
+ // Make sure that the current path is not interpreted as external URL.
+ if (!url_is_external($_GET['q'])) {
+ $_GET['destination'] = $_GET['q'];
+ }
}
$path = drupal_get_normal_path(variable_get('site_404', ''));
@@ -2510,7 +2727,10 @@
// Keep old path for reference, and to allow forms to redirect to it.
if (!isset($_GET['destination'])) {
- $_GET['destination'] = $_GET['q'];
+ // Make sure that the current path is not interpreted as external URL.
+ if (!url_is_external($_GET['q'])) {
+ $_GET['destination'] = $_GET['q'];
+ }
}
$path = drupal_get_normal_path(variable_get('site_403', ''));
@@ -2551,7 +2771,7 @@
}
/**
- * Perform end-of-request tasks.
+ * Performs end-of-request tasks.
*
* This function sets the page cache if appropriate, and allows modules to
* react to the closing of the page by calling hook_exit().
@@ -2574,11 +2794,12 @@
_registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
drupal_cache_system_paths();
module_implements_write_cache();
+ drupal_file_scan_write_cache();
system_run_automated_cron();
}
/**
- * Perform end-of-request tasks.
+ * Performs end-of-request tasks.
*
* In some cases page requests need to end without calling drupal_page_footer().
* In these cases, call drupal_exit() instead. There should rarely be a reason
@@ -2600,7 +2821,7 @@
}
/**
- * Form an associative array from a linear array.
+ * Forms an associative array from a linear array.
*
* This function walks through the provided array and constructs an associative
* array out of it. The keys of the resulting array will be the values of the
@@ -2635,11 +2856,11 @@
* into script execution a call such as set_time_limit(20) is made, the
* script will run for a total of 45 seconds before timing out.
*
- * It also means that it is possible to decrease the total time limit if
- * the sum of the new time limit and the current time spent running the
- * script is inferior to the original time limit. It is inherent to the way
- * set_time_limit() works, it should rather be called with an appropriate
- * value every time you need to allocate a certain amount of time
+ * If the current time limit is not unlimited it is possible to decrease the
+ * total time limit if the sum of the new time limit and the current time spent
+ * running the script is inferior to the original time limit. It is inherent to
+ * the way set_time_limit() works, it should rather be called with an
+ * appropriate value every time you need to allocate a certain amount of time
* to execute a task than only once at the beginning of the script.
*
* Before calling set_time_limit(), we check if this function is available
@@ -2656,7 +2877,11 @@
*/
function drupal_set_time_limit($time_limit) {
if (function_exists('set_time_limit')) {
- @set_time_limit($time_limit);
+ $current = ini_get('max_execution_time');
+ // Do not set time limit if it is currently unlimited.
+ if ($current != 0) {
+ @set_time_limit($time_limit);
+ }
}
}
@@ -2669,17 +2894,17 @@
* The name of the item for which the path is requested.
*
* @return
- * The path to the requested item.
+ * The path to the requested item or an empty string if the item is not found.
*/
function drupal_get_path($type, $name) {
return dirname(drupal_get_filename($type, $name));
}
/**
- * Return the base URL path (i.e., directory) of the Drupal installation.
+ * Returns the base URL path (i.e., directory) of the Drupal installation.
*
- * base_path() prefixes and suffixes a "/" onto the returned path if the path is
- * not empty. At the very least, this will return "/".
+ * base_path() adds a "/" to the beginning and end of the returned path if the
+ * path is not empty. At the very least, this will return "/".
*
* Examples:
* - http://example.com returns "/" because the path is empty.
@@ -2690,12 +2915,12 @@
}
/**
- * Add a LINK tag with a distinct 'rel' attribute to the page's HEAD.
+ * Adds a LINK tag with a distinct 'rel' attribute to the page's HEAD.
*
- * This function can be called as long the HTML header hasn't been sent,
- * which on normal pages is up through the preprocess step of theme('html').
- * Adding a link will overwrite a prior link with the exact same 'rel' and
- * 'href' attributes.
+ * This function can be called as long the HTML header hasn't been sent, which
+ * on normal pages is up through the preprocess step of theme('html'). Adding
+ * a link will overwrite a prior link with the exact same 'rel' and 'href'
+ * attributes.
*
* @param $attributes
* Associative array of element attributes including 'href' and 'rel'.
@@ -2759,8 +2984,8 @@
* See drupal_get_css() where the overrides are performed. Also, if the
* direction of the current language is right-to-left (Hebrew, Arabic,
* etc.), the function will also look for an RTL CSS file and append it to
- * the list. The name of this file should have an '-rtl.css' suffix. For
- * example a CSS file called 'mymodule-name.css' will have a
+ * the list. The name of this file should have an '-rtl.css' suffix. For
+ * example, a CSS file called 'mymodule-name.css' will have a
* 'mymodule-name-rtl.css' file added to the list, if exists in the same
* directory. This CSS file should contain overrides for properties which
* should be reversed or otherwise different in a right-to-left display.
@@ -2785,7 +3010,7 @@
* - 'group': A number identifying the group in which to add the stylesheet.
* Available constants are:
* - CSS_SYSTEM: Any system-layer CSS.
- * - CSS_DEFAULT: Any module-layer CSS.
+ * - CSS_DEFAULT: (default) Any module-layer CSS.
* - CSS_THEME: Any theme-layer CSS.
* The group number serves as a weight: the markup for loading a stylesheet
* within a lower weight group is output to the page before the markup for
@@ -2837,6 +3062,13 @@
*/
function drupal_add_css($data = NULL, $options = NULL) {
$css = &drupal_static(__FUNCTION__, array());
+ $count = &drupal_static(__FUNCTION__ . '_count', 0);
+
+ // If the $css variable has been reset with drupal_static_reset(), there is
+ // no longer any CSS being tracked, so set the counter back to 0 also.
+ if (count($css) === 0) {
+ $count = 0;
+ }
// Construct the options, taking the defaults into consideration.
if (isset($options)) {
@@ -2872,7 +3104,8 @@
}
// Always add a tiny value to the weight, to conserve the insertion order.
- $options['weight'] += count($css) / 1000;
+ $options['weight'] += $count / 1000;
+ $count++;
// Add the data to the CSS array depending on the type.
switch ($options['type']) {
@@ -2892,7 +3125,7 @@
}
/**
- * Returns a themed representation of all stylesheets that should be attached to the page.
+ * Returns a themed representation of all stylesheets to attach to the page.
*
* It loads the CSS in order, with 'module' first, then 'theme' afterwards.
* This ensures proper cascading of styles so themes can easily override
@@ -2933,12 +3166,24 @@
// Sort CSS items, so that they appear in the correct order.
uasort($css, 'drupal_sort_css_js');
+ // Provide the page with information about the individual CSS files used,
+ // information not otherwise available when CSS aggregation is enabled. The
+ // setting is attached later in this function, but is set here, so that CSS
+ // files removed below are still considered "used" and prevented from being
+ // added in a later AJAX request.
+ // Skip if no files were added to the page or jQuery.extend() will overwrite
+ // the Drupal.settings.ajaxPageState.css object with an empty array.
+ if (!empty($css)) {
+ // Cast the array to an object to be on the safe side even if not empty.
+ $setting['ajaxPageState']['css'] = (object) array_fill_keys(array_keys($css), 1);
+ }
+
// Remove the overridden CSS files. Later CSS files override former ones.
$previous_item = array();
foreach ($css as $key => $item) {
if ($item['type'] == 'file') {
// If defined, force a unique basename for this file.
- $basename = isset($item['basename']) ? $item['basename'] : basename($item['data']);
+ $basename = isset($item['basename']) ? $item['basename'] : drupal_basename($item['data']);
if (isset($previous_item[$basename])) {
// Remove the previous item that shared the same base name.
unset($css[$previous_item[$basename]]);
@@ -2953,20 +3198,32 @@
'#items' => $css,
);
- // Provide the page with information about the individual CSS files used,
- // information not otherwise available when CSS aggregation is enabled.
- $setting['ajaxPageState']['css'] = array_fill_keys(array_keys($css), 1);
- $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+ if (!empty($setting)) {
+ $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+ }
return drupal_render($styles);
}
/**
- * Function used by uasort to sort the array structures returned by drupal_add_css() and drupal_add_js().
+ * Sorts CSS and JavaScript resources.
+ *
+ * Callback for uasort() within:
+ * - drupal_get_css()
+ * - drupal_get_js()
*
* This sort order helps optimize front-end performance while providing modules
* and themes with the necessary control for ordering the CSS and JavaScript
* appearing on a page.
+ *
+ * @param $a
+ * First item for comparison. The compared items should be associative arrays
+ * of member items from drupal_add_css() or drupal_add_js().
+ * @param $b
+ * Second item for comparison.
+ *
+ * @see drupal_add_css()
+ * @see drupal_add_js()
*/
function drupal_sort_css_js($a, $b) {
// First order by group, so that, for example, all items in the CSS_SYSTEM
@@ -3033,6 +3290,7 @@
* 'items' key, which is the subset of items from $css that are in the group.
*
* @see drupal_pre_render_styles()
+ * @see system_element_info()
*/
function drupal_group_css($css) {
$groups = array();
@@ -3115,6 +3373,7 @@
*
* @see drupal_group_css()
* @see drupal_pre_render_styles()
+ * @see system_element_info()
*/
function drupal_aggregate_css(&$css_groups) {
$preprocess_css = (variable_get('preprocess_css', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
@@ -3293,7 +3552,11 @@
$import_batch = array_slice($import, 0, 31);
$import = array_slice($import, 31);
$element = $style_element_defaults;
- $element['#value'] = implode("\n", $import_batch);
+ // This simplifies the JavaScript regex, allowing each line
+ // (separated by \n) to be treated as a completely different string.
+ // This means that we can use ^ and $ on one line at a time, and not
+ // worry about style tags since they'll never match the regex.
+ $element['#value'] = "\n" . implode("\n", $import_batch) . "\n";
$element['#attributes']['media'] = $group['media'];
$element['#browsers'] = $group['browsers'];
$elements[] = $element;
@@ -3376,8 +3639,8 @@
* in $css while the value is the cache file name. The cache file is generated
* in two cases. First, if there is no file name value for the key, which will
* happen if a new file name has been added to $css or after the lookup
- * variable is emptied to force a rebuild of the cache. Second, the cache
- * file is generated if it is missing on disk. Old cache files are not deleted
+ * variable is emptied to force a rebuild of the cache. Second, the cache file
+ * is generated if it is missing on disk. Old cache files are not deleted
* immediately when the lookup variable is emptied, but are deleted after a set
* period by drupal_delete_file_if_stale(). This ensures that files referenced
* by a cached page will still be available.
@@ -3392,7 +3655,13 @@
$data = '';
$uri = '';
$map = variable_get('drupal_css_cache_files', array());
- $key = hash('sha256', serialize($css));
+ // Create a new array so that only the file names are used to create the hash.
+ // This prevents new aggregates from being created unnecessarily.
+ $css_data = array();
+ foreach ($css as $css_file) {
+ $css_data[] = $css_file['data'];
+ }
+ $key = hash('sha256', serialize($css_data));
if (isset($map[$key])) {
$uri = $map[$key];
}
@@ -3455,9 +3724,7 @@
}
/**
- * Helper function for drupal_build_css_cache().
- *
- * This function will prefix all paths within a CSS file.
+ * Prefixes all paths within a CSS file for drupal_build_css_cache().
*/
function _drupal_build_css_path($matches, $base = NULL) {
$_base = &drupal_static(__FUNCTION__);
@@ -3514,33 +3781,40 @@
if ($basepath && !file_uri_scheme($file)) {
$file = $basepath . '/' . $file;
}
+ // Store the parent base path to restore it later.
+ $parent_base_path = $basepath;
+ // Set the current base path to process possible child imports.
$basepath = dirname($file);
// Load the CSS stylesheet. We suppress errors because themes may specify
// stylesheets in their .info file that don't exist in the theme's path,
// but are merely there to disable certain module CSS files.
+ $content = '';
if ($contents = @file_get_contents($file)) {
// Return the processed stylesheet.
- return drupal_load_stylesheet_content($contents, $_optimize);
+ $content = drupal_load_stylesheet_content($contents, $_optimize);
}
- return '';
+ // Restore the parent base path as the file and its childen are processed.
+ $basepath = $parent_base_path;
+ return $content;
}
/**
- * Process the contents of a stylesheet for aggregation.
+ * Processes the contents of a stylesheet for aggregation.
*
* @param $contents
* The contents of the stylesheet.
* @param $optimize
* (optional) Boolean whether CSS contents should be minified. Defaults to
* FALSE.
+ *
* @return
* Contents of the stylesheet including the imported stylesheets.
*/
function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
// Remove multiple charset declarations for standards compliance (and fixing Safari problems).
- $contents = preg_replace('/^@charset\s+[\'"](\S*)\b[\'"];/i', '', $contents);
+ $contents = preg_replace('/^@charset\s+[\'"](\S*?)\b[\'"];/i', '', $contents);
if ($optimize) {
// Perform some safe CSS optimizations.
@@ -3559,7 +3833,7 @@
// Remove certain whitespace.
// There are different conditions for removing leading and trailing
// whitespace.
- // @see http://php.net/manual/en/regexp.reference.subpatterns.php
+ // @see http://php.net/manual/regexp.reference.subpatterns.php
$contents = preg_replace('<
# Strip leading and trailing whitespace.
\s*([@{};,])\s*
@@ -3584,7 +3858,7 @@
// Replaces @import commands with the actual stylesheet content.
// This happens recursively but omits external files.
- $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
+ $contents = preg_replace_callback('/@import\s*(?:url\(\s*)?[\'"]?(?![a-z]+:)(?!\/\/)([^\'"\()]+)[\'"]?\s*\)?\s*;/', '_drupal_load_stylesheet', $contents);
return $contents;
}
@@ -3608,7 +3882,7 @@
// Alter all internal url() paths. Leave external paths alone. We don't need
// to normalize absolute paths here (i.e. remove folder/... segments) because
// that will be done later.
- return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)/i', 'url(\1'. $directory, $file);
+ return preg_replace('/url\(\s*([\'"]?)(?![a-z]+:|\/+)([^\'")]+)([\'"]?)\s*\)/i', 'url(\1' . $directory . '\2\3)', $file);
}
/**
@@ -3630,7 +3904,7 @@
}
/**
- * Prepare a string for use as a valid CSS identifier (element, class or ID name).
+ * Prepares a string for use as a CSS identifier (element, class, or ID name).
*
* http://www.w3.org/TR/CSS21/syndata.html#characters shows the syntax for valid
* CSS identifiers (including element names, classes, and IDs in selectors.)
@@ -3639,10 +3913,26 @@
* The identifier to clean.
* @param $filter
* An array of string replacements to use on the identifier.
+ *
* @return
* The cleaned identifier.
*/
function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
+ // Use the advanced drupal_static() pattern, since this is called very often.
+ static $drupal_static_fast;
+ if (!isset($drupal_static_fast)) {
+ $drupal_static_fast['allow_css_double_underscores'] = &drupal_static(__FUNCTION__ . ':allow_css_double_underscores');
+ }
+ $allow_css_double_underscores = &$drupal_static_fast['allow_css_double_underscores'];
+ if (!isset($allow_css_double_underscores)) {
+ $allow_css_double_underscores = variable_get('allow_css_double_underscores', FALSE);
+ }
+
+ // Preserve BEM-style double-underscores depending on custom setting.
+ if ($allow_css_double_underscores) {
+ $filter['__'] = '__';
+ }
+
// By default, we filter using Drupal's coding standards.
$identifier = strtr($identifier, $filter);
@@ -3660,22 +3950,30 @@
}
/**
- * Prepare a string for use as a valid class name.
+ * Prepares a string for use as a valid class name.
*
* Do not pass one string containing multiple classes as they will be
* incorrectly concatenated with dashes, i.e. "one two" will become "one-two".
*
* @param $class
* The class name to clean.
+ *
* @return
* The cleaned class name.
*/
function drupal_html_class($class) {
- return drupal_clean_css_identifier(drupal_strtolower($class));
+ // The output of this function will never change, so this uses a normal
+ // static instead of drupal_static().
+ static $classes = array();
+
+ if (!isset($classes[$class])) {
+ $classes[$class] = drupal_clean_css_identifier(drupal_strtolower($class));
+ }
+ return $classes[$class];
}
/**
- * Prepare a string for use as a valid HTML ID and guarantee uniqueness.
+ * Prepares a string for use as a valid HTML ID and guarantees uniqueness.
*
* This function ensures that each passed HTML ID value only exists once on the
* page. By tracking the already returned ids, this function enables forms,
@@ -3706,7 +4004,11 @@
// be merged with content already on the base page. The HTML IDs must be
// unique for the fully merged content. Therefore, initialize $seen_ids to
// take into account IDs that are already in use on the base page.
- $seen_ids_init = &drupal_static(__FUNCTION__ . ':init');
+ static $drupal_static_fast;
+ if (!isset($drupal_static_fast['seen_ids_init'])) {
+ $drupal_static_fast['seen_ids_init'] = &drupal_static(__FUNCTION__ . ':init');
+ }
+ $seen_ids_init = &$drupal_static_fast['seen_ids_init'];
if (!isset($seen_ids_init)) {
// Ideally, Drupal would provide an API to persist state information about
// prior page requests in the database, and we'd be able to add this
@@ -3726,7 +4028,16 @@
// requested id. $_POST['ajax_html_ids'] contains the ids as they were
// returned by this function, potentially with the appended counter, so
// we parse that to reconstruct the $seen_ids array.
- foreach ($_POST['ajax_html_ids'] as $seen_id) {
+ if (isset($_POST['ajax_html_ids'][0]) && strpos($_POST['ajax_html_ids'][0], ',') === FALSE) {
+ $ajax_html_ids = $_POST['ajax_html_ids'];
+ }
+ else {
+ // jquery.form.js may send the server a comma-separated string as the
+ // first element of an array (see http://drupal.org/node/1575060), so
+ // we need to convert it to an array in that case.
+ $ajax_html_ids = explode(',', $_POST['ajax_html_ids'][0]);
+ }
+ foreach ($ajax_html_ids as $seen_id) {
// We rely on '--' being used solely for separating a base id from the
// counter, which this function ensures when returning an id.
$parts = explode('--', $seen_id, 2);
@@ -3742,7 +4053,10 @@
}
}
}
- $seen_ids = &drupal_static(__FUNCTION__, $seen_ids_init);
+ if (!isset($drupal_static_fast['seen_ids'])) {
+ $drupal_static_fast['seen_ids'] = &drupal_static(__FUNCTION__, $seen_ids_init);
+ }
+ $seen_ids = &$drupal_static_fast['seen_ids'];
$id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
@@ -3806,7 +4120,7 @@
* to tell the user that a new message arrived, by opening a pop up, alert
* box, etc.). This should only be used for JavaScript that cannot be executed
* from a file. When adding inline code, make sure that you are not relying on
- * $() being the jQuery function. Wrap your code in
+ * $() being the jQuery function. Wrap your code in
* @code (function ($) {... })(jQuery); @endcode
* or use jQuery() instead of $().
* - Add external JavaScript ('external'): Allows the inclusion of external
@@ -3852,7 +4166,8 @@
* actually needed.
*
* @param $data
- * (optional) If given, the value depends on the $options parameter:
+ * (optional) If given, the value depends on the $options parameter, or
+ * $options['type'] if $options is passed as an associative array:
* - 'file': Path to the file relative to base_path().
* - 'inline': The JavaScript code that should be placed in the given scope.
* - 'external': The absolute path to an external JavaScript file that is not
@@ -3925,8 +4240,15 @@
* else being the same, JavaScript added by a call to drupal_add_js() that
* happened later in the page request gets added to the page after one for
* which drupal_add_js() happened earlier in the page request.
- * - defer: If set to TRUE, the defer attribute is set on the <script>
- * tag. Defaults to FALSE.
+ * - requires_jquery: Set this to FALSE if the JavaScript you are adding does
+ * not have a dependency on jQuery. Defaults to TRUE, except for JavaScript
+ * settings where it defaults to FALSE. This is used on sites that have the
+ * 'javascript_always_use_jquery' variable set to FALSE; on those sites, if
+ * all the JavaScript added to the page by drupal_add_js() does not have a
+ * dependency on jQuery, then for improved front-end performance Drupal
+ * will not add jQuery and related libraries and settings to the page.
+ * - defer: If set to TRUE, the defer attribute is set on the