summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
Diffstat (limited to 'includes')
-rw-r--r--includes/actions.inc1
-rw-r--r--includes/ajax.inc238
-rw-r--r--includes/archiver.inc1
-rw-r--r--includes/authorize.inc3
-rw-r--r--includes/batch.inc1
-rw-r--r--includes/batch.queue.inc1
-rw-r--r--includes/bootstrap.inc263
-rw-r--r--includes/cache-install.inc3
-rw-r--r--includes/cache.inc14
-rw-r--r--includes/common.inc272
-rw-r--r--includes/database/database.inc60
-rw-r--r--includes/database/log.inc1
-rw-r--r--includes/database/mysql/database.inc1
-rw-r--r--includes/database/mysql/install.inc1
-rw-r--r--includes/database/mysql/query.inc9
-rw-r--r--includes/database/mysql/schema.inc1
-rw-r--r--includes/database/pgsql/database.inc10
-rw-r--r--includes/database/pgsql/install.inc1
-rw-r--r--includes/database/pgsql/query.inc5
-rw-r--r--includes/database/pgsql/schema.inc9
-rw-r--r--includes/database/pgsql/select.inc1
-rw-r--r--includes/database/prefetch.inc1
-rw-r--r--includes/database/query.inc23
-rw-r--r--includes/database/schema.inc1
-rw-r--r--includes/database/select.inc6
-rw-r--r--includes/database/sqlite/database.inc1
-rw-r--r--includes/database/sqlite/install.inc1
-rw-r--r--includes/database/sqlite/query.inc11
-rw-r--r--includes/database/sqlite/schema.inc1
-rw-r--r--includes/database/sqlite/select.inc1
-rw-r--r--includes/date.inc1
-rw-r--r--includes/entity.inc3
-rw-r--r--includes/errors.inc1
-rw-r--r--includes/file.inc8
-rw-r--r--includes/file.mimetypes.inc1
-rw-r--r--includes/filetransfer/filetransfer.inc1
-rw-r--r--includes/filetransfer/ftp.inc1
-rw-r--r--includes/filetransfer/local.inc1
-rw-r--r--includes/filetransfer/ssh.inc1
-rw-r--r--includes/form.inc61
-rw-r--r--includes/graph.inc9
-rw-r--r--includes/image.inc1
-rw-r--r--includes/install.core.inc1
-rw-r--r--includes/install.inc46
-rw-r--r--includes/iso.inc1
-rw-r--r--includes/language.inc66
-rw-r--r--includes/locale.inc194
-rw-r--r--includes/lock.inc29
-rw-r--r--includes/mail.inc5
-rw-r--r--includes/menu.inc53
-rw-r--r--includes/module.inc14
-rw-r--r--includes/pager.inc3
-rw-r--r--includes/password.inc1
-rw-r--r--includes/path.inc1
-rw-r--r--includes/registry.inc4
-rw-r--r--includes/session.inc1
-rw-r--r--includes/stream_wrappers.inc3
-rw-r--r--includes/tablesort.inc82
-rw-r--r--includes/theme.inc82
-rw-r--r--includes/theme.maintenance.inc1
-rw-r--r--includes/token.inc82
-rw-r--r--includes/unicode.entities.inc1
-rw-r--r--includes/unicode.inc5
-rw-r--r--includes/update.inc1
-rw-r--r--includes/updater.inc1
-rw-r--r--includes/utility.inc1
-rw-r--r--includes/xmlrpc.inc1
-rw-r--r--includes/xmlrpcs.inc9
68 files changed, 960 insertions, 759 deletions
diff --git a/includes/actions.inc b/includes/actions.inc
index 0daf8e86d..c2fd4d96c 100644
--- a/includes/actions.inc
+++ b/includes/actions.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 0f652eff8..41c69832a 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -1,17 +1,16 @@
<?php
-// $Id$
/**
* @file
- * Functions for use with Drupal's AJAX framework.
+ * Functions for use with Drupal's Ajax framework.
*/
/**
- * @defgroup ajax AJAX framework
+ * @defgroup ajax Ajax framework
* @{
- * Functions for Drupal's AJAX framework.
+ * Functions for Drupal's Ajax framework.
*
- * Drupal's AJAX framework is used to dynamically update parts of a page's HTML
+ * Drupal's Ajax framework is used to dynamically update parts of a page's HTML
* based on data from the server. Upon a specified event, such as a button
* click, a callback function is triggered which performs server-side logic and
* may return updated markup, which is then replaced on-the-fly with no page
@@ -20,33 +19,33 @@
* This framework creates a PHP macro language that allows the server to
* instruct JavaScript to perform actions on the client browser. When using
* forms, it can be used with the #ajax property.
- * The #ajax property can be used to bind events to the AJAX framework. By
+ * The #ajax property can be used to bind events to the Ajax framework. By
* default, #ajax uses 'system/ajax' as its path for submission and thus calls
* 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
* omits #ajax['path']. See below about using #ajax['path'] to implement
* advanced use-cases that require something other than standard form
* handling.
- * - On the specified element, AJAX processing is triggered by a change to
+ * - On the specified element, Ajax processing is triggered by a change to
* that element.
* - The browser submits an HTTP POST request to the 'system/ajax' Drupal
* path.
* - The menu page callback for 'system/ajax', ajax_form_callback(), calls
* drupal_process_form() to process the form submission and rebuild the
* form if necessary. The form is processed in much the same way as if it
- * were submitted without AJAX, with the same #process functions and
+ * were submitted without Ajax, with the same #process functions and
* validation and submission handlers called in either case, making it easy
- * to create AJAX-enabled forms that degrade gracefully when JavaScript is
+ * to create Ajax-enabled forms that degrade gracefully when JavaScript is
* disabled.
* - After form processing is complete, ajax_form_callback() calls the
* function named by #ajax['callback'], which returns the form element that
* has been updated and needs to be returned to the browser, or
- * alternatively, an array of custom AJAX commands.
+ * alternatively, an array of custom Ajax commands.
* - The page delivery callback for 'system/ajax', ajax_deliver(), renders the
* element returned by #ajax['callback'], and returns the JSON string
* created by ajax_render() to the browser.
@@ -57,7 +56,7 @@
* #ajax['callback'], using a JavaScript animation effect specified by
* #ajax['effect'].
*
- * A simple example of basic AJAX use from the
+ * A simple example of basic Ajax use from the
* @link http://drupal.org/project/examples Examples module @endlink follows:
* @code
* function main_page() {
@@ -99,28 +98,28 @@
* }
* @endcode
*
- * In the above example, the 'changethis' element is AJAX-enabled. The default
+ * 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
+ * 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
* built changing $form['replace_textfield']['#description'], so the callback
* just returns that part of the form.
*
- * To implement AJAX handling in a form, add '#ajax' to the form
- * definition of a field. That field will trigger an AJAX event when it is
+ * To implement Ajax handling in a form, add '#ajax' to the form
+ * definition of a field. That field will trigger an Ajax event when it is
* clicked (or changed, depending on the kind of field). #ajax supports
* the following parameters (either 'path' or 'callback' is required at least):
* - #ajax['callback']: The callback to invoke to handle the server side of the
- * AJAX event, which will receive a $form and $form_state as arguments, and
+ * Ajax event, which will receive a $form and $form_state as arguments, and
* returns a renderable array (most often a form or form fragment), an HTML
- * string, or an array of AJAX commands. If returning a renderable array or
+ * string, or an array of Ajax commands. If returning a renderable array or
* a string, the value will replace the original element named in
* #ajax['wrapper'], and
* theme_status_messages()
* will be prepended to that
* element. (If the status messages are not wanted, return an array
- * of AJAX commands instead.)
- * #ajax['wrapper']. If an array of AJAX commands is returned, it will be
+ * of Ajax commands instead.)
+ * #ajax['wrapper']. If an array of Ajax commands is returned, it will be
* executed by the calling code.
* - #ajax['path']: The menu path to use for the request. This is often omitted
* and the default is used. This path should map
@@ -155,21 +154,21 @@
* More information is available in the
* @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7 Form API Reference @endlink
*
- * In addition to using Form API for doing in-form modification, AJAX may be
+ * 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'
- * class to a link, the link will be loaded via an AJAX call. When using this
+ * class to a link, the link will be loaded via an Ajax call. When using this
* method, the href of the link can contain '/nojs/' as part of the path. When
- * the AJAX framework makes the request, it will convert this to '/ajax/'.
+ * the Ajax framework makes the request, it will convert this to '/ajax/'.
* The server is then able to easily tell if this request was made through an
- * actual AJAX request or in a degraded state, and respond appropriately.
+ * actual Ajax request or in a degraded state, and respond appropriately.
*
* Similarly, submit buttons can be given the class 'use-ajax-submit'. The
- * form will then be submitted via AJAX to the path specified in the #action.
+ * form will then be submitted via Ajax to the path specified in the #action.
* Like the ajax-submit class above, this path will have '/nojs/' replaced with
* '/ajax/' so that the submit handler can tell if the form was submitted
* in a degraded state or not.
*
- * When responding to AJAX requests, the server should do what it needs to do
+ * When responding to Ajax requests, the server should do what it needs to do
* for that request, then create a commands array. This commands array will
* 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.
@@ -189,14 +188,14 @@
* // Add a visual "changed" marker to the '#object-1' element.
* $commands[] = ajax_command_changed('#object-1');
* // Menu 'page callback' and #ajax['callback'] functions are supposed to
- * // return render arrays. If returning an AJAX commands array, it must be
+ * // return render arrays. If returning an Ajax commands array, it must be
* // encapsulated in a render array structure.
* return array('#type' => 'ajax', '#commands' => $commands);
* @endcode
*
- * When returning an AJAX command array, it is often useful to have
+ * 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 the Ajax commands array may be constructed like this:
* @code
* $commands = array();
* $commands[] = ajax_command_replace(NULL, $output);
@@ -204,7 +203,7 @@
* return array('#type' => 'ajax', '#commands' => $commands);
* @endcode
*
- * See @link ajax_commands AJAX framework commands @endlink
+ * See @link ajax_commands Ajax framework commands @endlink
*/
/**
@@ -215,7 +214,7 @@
* functions.
*/
function ajax_render($commands = array()) {
- // AJAX responses aren't rendered with html.tpl.php, so we have to call
+ // 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
// files that the page hasn't already loaded, so we implement simple diffing
@@ -235,7 +234,7 @@ function ajax_render($commands = array()) {
// @todo Inline CSS and JS items are indexed numerically. These can't be
// 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
+ // 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.
foreach ($items[$type] as $key => $item) {
@@ -251,14 +250,14 @@ function ajax_render($commands = array()) {
// 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
+ // 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.
if (isset($items['js']['settings'])) {
unset($items['js']['settings']);
}
- // Render the HTML to load these files, and add AJAX commands to insert this
+ // 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);
@@ -287,16 +286,16 @@ function ajax_render($commands = array()) {
array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));
}
- // Allow modules to alter any AJAX response.
+ // Allow modules to alter any Ajax response.
drupal_alter('ajax_render', $commands);
return drupal_json_encode($commands);
}
/**
- * Get a form submitted via #ajax during an AJAX callback.
+ * Get a form submitted via #ajax during an Ajax callback.
*
- * This will load a form from the form cache used during AJAX operations. It
+ * This will load a form from the form cache used during Ajax operations. It
* pulls the form info from $_POST.
*
* @return
@@ -326,7 +325,7 @@ function ajax_get_form() {
// Since some of the submit handlers are run, redirects need to be disabled.
$form_state['no_redirect'] = TRUE;
- // When a form is rebuilt after AJAX processing, its #build_id and #action
+ // When a form is rebuilt after Ajax processing, its #build_id and #action
// should not change.
// @see drupal_rebuild_form()
$form_state['rebuild_info']['copy']['#build_id'] = TRUE;
@@ -341,10 +340,10 @@ function ajax_get_form() {
}
/**
- * Menu callback; handles AJAX requests for the #ajax Form API property.
+ * Menu callback; handles Ajax requests for the #ajax Form API property.
*
* This rebuilds the form from cache and invokes the defined #ajax['callback']
- * to return an AJAX command structure for JavaScript. In case no 'callback' has
+ * to return an Ajax command structure for JavaScript. In case no 'callback' has
* been defined, nothing will happen.
*
* The Form API #ajax property can be set both for buttons and other input
@@ -361,9 +360,9 @@ function ajax_form_callback() {
// We need to return the part of the form (or some other content) that needs
// to be re-rendered so the browser can update the page with changed content.
- // Since this is the generic menu callback used by many AJAX elements, it is
+ // Since this is the generic menu callback used by many Ajax elements, it is
// up to the #ajax['callback'] function of the element (may or may not be a
- // button) that triggered the AJAX request to determine what needs to be
+ // button) that triggered the Ajax request to determine what needs to be
// rendered.
if (!empty($form_state['triggering_element'])) {
$callback = $form_state['triggering_element']['#ajax']['callback'];
@@ -374,21 +373,21 @@ function ajax_form_callback() {
}
/**
- * Theme callback for AJAX requests.
+ * Theme callback for Ajax requests.
*
- * Many different pages can invoke an AJAX request to system/ajax or another
- * generic AJAX path. It is almost always desired for an AJAX response to be
+ * Many different pages can invoke an Ajax request to system/ajax or another
+ * generic Ajax path. It is almost always desired for an Ajax response to be
* rendered using the same theme as the base page, because most themes are built
* with the assumption that they control the entire page, so if the CSS for two
* themes are both loaded for a given page, they may conflict with each other.
* For example, Bartik is Drupal's default theme, and Seven is Drupal's default
* administration theme. Depending on whether the "Use the administration theme
* when editing or creating content" checkbox is checked, the node edit form may
- * be displayed in either theme, but the AJAX response to the Field module's
+ * be displayed in either theme, but the Ajax response to the Field module's
* "Add another item" button should be rendered using the same theme as the rest
* 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.
+ * implementing other generic Ajax paths do the same.
*/
function ajax_base_page_theme() {
if (!empty($_POST['ajax_page_state']['theme']) && !empty($_POST['ajax_page_state']['theme_token'])) {
@@ -407,9 +406,9 @@ function ajax_base_page_theme() {
}
/**
- * Package and send the result of a page callback to the browser as an AJAX response.
+ * Package and send the result of a page callback to the browser as an Ajax response.
*
- * This function is the equivalent of drupal_deliver_html_page(), but for AJAX
+ * This function is the equivalent of drupal_deliver_html_page(), but for Ajax
* requests. Like that function, it:
* - Adds needed HTTP headers.
* - Prints rendered output.
@@ -425,36 +424,71 @@ function ajax_base_page_theme() {
* @see drupal_deliver_html_page()
*/
function ajax_deliver($page_callback_result) {
+ // Browsers do not allow JavaScript to read the contents of a user's local
+ // files. To work around that, the jQuery Form plugin submits forms containing
+ // a file input element to an IFRAME, instead of using XHR. Browsers do not
+ // normally expect JSON strings as content within an IFRAME, so the response
+ // must be customized accordingly.
+ // @see http://malsup.com/jquery/form/#file-upload
+ // @see Drupal.ajax.prototype.beforeSend()
+ $iframe_upload = !empty($_POST['ajax_iframe_upload']);
+
// Emit a Content-Type HTTP header if none has been added by the page callback
// or by a wrapping delivery callback.
if (is_null(drupal_get_http_header('Content-Type'))) {
- // The standard header for JSON is application/json.
- // @see http://www.ietf.org/rfc/rfc4627.txt?number=4627
- // However, browsers do not allow JavaScript to read the contents of a
- // user's local files. To work around that, jQuery submits forms containing
- // a file input element to an IFRAME, instead of using XHR.
- // @see http://malsup.com/jquery/form/#file-upload
- // When Internet Explorer receives application/json content in an IFRAME, it
- // treats it as a file download and prompts the user to save it. To prevent
- // that, we return the content as text/plain. But only for POST requests,
- // since jQuery should always use XHR for GET requests and the incorrect
- // mime type should not end up in page or proxy server caches.
- // @see http://drupal.org/node/995854
- $iframe_upload = !isset($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest';
- if ($iframe_upload && $_SERVER['REQUEST_METHOD'] == 'POST') {
- drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+ if (!$iframe_upload) {
+ // Standard JSON can be returned to a browser's XHR object, and to
+ // non-browser user agents.
+ // @see http://www.ietf.org/rfc/rfc4627.txt?number=4627
+ drupal_add_http_header('Content-Type', 'application/json; charset=utf-8');
}
else {
- drupal_add_http_header('Content-Type', 'application/json; charset=utf-8');
+ // Browser IFRAMEs expect HTML. With most other content types, Internet
+ // Explorer presents the user with a download prompt.
+ drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
}
}
- // Normalize whatever was returned by the page callback to an AJAX commands
- // array.
+ // Print the response.
+ $commands = ajax_prepare_response($page_callback_result);
+ $json = ajax_render($commands);
+ if (!$iframe_upload) {
+ // Standard JSON can be returned to a browser's XHR object, and to
+ // non-browser user agents.
+ print $json;
+ }
+ else {
+ // Browser IFRAMEs expect HTML. Browser extensions, such as Linkification
+ // and Skype's Browser Highlighter, convert URLs, phone numbers, etc. into
+ // links. This corrupts the JSON response. Protect the integrity of the
+ // JSON data by making it the value of a textarea.
+ // @see http://malsup.com/jquery/form/#file-upload
+ // @see http://drupal.org/node/1009382
+ print '<textarea>' . $json . '</textarea>';
+ }
+
+ // Perform end-of-request tasks.
+ ajax_footer();
+}
+
+/**
+ * Converts the return value of a page callback into an Ajax commands array.
+ *
+ * @param $page_callback_result
+ * The result of a page callback. Can be one of:
+ * - NULL: to indicate no content.
+ * - An integer menu status constant: to indicate an error condition.
+ * - A string of HTML content.
+ * - A renderable array of content.
+ *
+ * @return
+ * An Ajax commands array that can be passed to ajax_render().
+ */
+function ajax_prepare_response($page_callback_result) {
$commands = array();
if (!isset($page_callback_result)) {
// Simply delivering an empty commands array is sufficient. This results
- // in the AJAX request being completed, but nothing being done to the page.
+ // in the Ajax request being completed, but nothing being done to the page.
}
elseif (is_int($page_callback_result)) {
switch ($page_callback_result) {
@@ -473,7 +507,7 @@ function ajax_deliver($page_callback_result) {
}
}
elseif (is_array($page_callback_result) && isset($page_callback_result['#type']) && ($page_callback_result['#type'] == 'ajax')) {
- // Complex AJAX callbacks can return a result that contains an error message
+ // Complex Ajax callbacks can return a result that contains an error message
// or a specific set of commands to send to the browser.
$page_callback_result += element_info('ajax');
$error = $page_callback_result['#error'];
@@ -488,7 +522,7 @@ function ajax_deliver($page_callback_result) {
}
}
else {
- // Like normal page callbacks, simple AJAX callbacks can return HTML
+ // Like normal page callbacks, simple Ajax callbacks can return HTML
// content, as a string or render array. This HTML is inserted in some
// relationship to #ajax['wrapper'], as determined by which jQuery DOM
// manipulation method is used. The method used is specified by
@@ -497,28 +531,24 @@ function ajax_deliver($page_callback_result) {
$html = is_string($page_callback_result) ? $page_callback_result : drupal_render($page_callback_result);
$commands[] = ajax_command_insert(NULL, $html);
// Add the status messages inside the new content's wrapper element, so that
- // on subsequent AJAX requests, it is treated as old content.
+ // on subsequent Ajax requests, it is treated as old content.
$commands[] = ajax_command_prepend(NULL, theme('status_messages'));
}
- // Unlike the recommendation in http://malsup.com/jquery/form/#file-upload,
- // we do not have to wrap the JSON string in a TEXTAREA, because
- // drupal_json_encode() returns an HTML-safe JSON string.
- print ajax_render($commands);
- ajax_footer();
+ return $commands;
}
/**
- * Perform end-of-AJAX-request tasks.
+ * Perform end-of-Ajax-request tasks.
*
- * This function is the equivalent of drupal_page_footer(), but for AJAX
+ * This function is the equivalent of drupal_page_footer(), but for Ajax
* requests.
*
* @see drupal_page_footer()
*/
function ajax_footer() {
- // Even for AJAX requests, invoke hook_exit() implementations. There may be
- // modules that need very fast AJAX responses, and therefore, run AJAX
+ // Even for Ajax requests, invoke hook_exit() implementations. There may be
+ // modules that need very fast Ajax responses, and therefore, run Ajax
// requests with an early bootstrap.
if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update')) {
module_invoke_all('exit');
@@ -551,10 +581,10 @@ function ajax_process_form($element, &$form_state) {
}
/**
- * Add AJAX information about an element to the page to communicate with JavaScript.
+ * Add Ajax information about an element to the page 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
+ * to the page header to attach the Ajax behaviors. See ajax.js for more
* information.
*
* @param $element
@@ -591,9 +621,9 @@ function ajax_pre_render_element($element) {
case 'image_button':
// Use the mousedown instead of the click event because form
// submission via pressing the enter key triggers a click event on
- // submit inputs, inappropriately triggering AJAX behaviors.
+ // submit inputs, inappropriately triggering Ajax behaviors.
$element['#ajax']['event'] = 'mousedown';
- // Attach an additional event handler so that AJAX behaviors
+ // Attach an additional event handler so that Ajax behaviors
// can be triggered still via keyboard input.
$element['#ajax']['keypress'] = TRUE;
break;
@@ -642,7 +672,7 @@ function ajax_pre_render_element($element) {
unset($settings['path'], $settings['options']);
// Add special data to $settings['submit'] so that when this element
- // triggers an AJAX submission, Drupal's form processing can determine which
+ // triggers an Ajax submission, Drupal's form processing can determine which
// element triggered it.
// @see _form_element_triggered_scripted_submission()
if (isset($settings['trigger_as'])) {
@@ -685,7 +715,7 @@ function ajax_pre_render_element($element) {
'data' => array('ajax' => array($element['#id'] => $settings)),
);
- // Indicate that AJAX processing was successful.
+ // Indicate that Ajax processing was successful.
$element['#ajax_processed'] = TRUE;
}
return $element;
@@ -696,16 +726,16 @@ function ajax_pre_render_element($element) {
*/
/**
- * @defgroup ajax_commands AJAX framework commands
+ * @defgroup ajax_commands Ajax framework commands
* @{
- * Functions to create various AJAX commands.
+ * Functions to create various Ajax commands.
*
* These functions can be used to create arrays for use with the
* ajax_render() function.
*/
/**
- * Creates a Drupal AJAX 'alert' command.
+ * Creates a Drupal Ajax 'alert' command.
*
* The 'alert' command instructs the client to display a JavaScript alert
* dialog box.
@@ -727,7 +757,7 @@ function ajax_command_alert($text) {
}
/**
- * Creates a Drupal AJAX 'insert' command using the method in #ajax['method'].
+ * Creates a Drupal Ajax 'insert' command using the method in #ajax['method'].
*
* This command instructs the client to insert the given HTML using whichever
* jQuery DOM manipulation method has been specified in the #ajax['method']
@@ -758,7 +788,7 @@ function ajax_command_insert($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'insert/replaceWith' command.
+ * Creates a Drupal Ajax 'insert/replaceWith' command.
*
* The 'insert/replaceWith' command instructs the client to use jQuery's
* replaceWith() method to replace each element matched matched by the given
@@ -791,7 +821,7 @@ function ajax_command_replace($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'insert/html' command.
+ * Creates a Drupal Ajax 'insert/html' command.
*
* The 'insert/html' command instructs the client to use jQuery's html()
* method to set the HTML content of each element matched by the given
@@ -824,7 +854,7 @@ function ajax_command_html($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'insert/prepend' command.
+ * Creates a Drupal Ajax 'insert/prepend' command.
*
* The 'insert/prepend' command instructs the client to use jQuery's prepend()
* method to prepend the given HTML content to the inside each element matched
@@ -857,10 +887,10 @@ function ajax_command_prepend($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'insert/append' command.
+ * Creates a Drupal Ajax 'insert/append' command.
*
* The 'insert/append' command instructs the client to use jQuery's append()
- * method to append the given HTML content to the inside each element matched
+ * method to append the given HTML content to the inside of each element matched
* by the given selector.
*
* This command is implemented by Drupal.ajax.prototype.commands.insert()
@@ -890,7 +920,7 @@ function ajax_command_append($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'insert/after' command.
+ * Creates a Drupal Ajax 'insert/after' command.
*
* The 'insert/after' command instructs the client to use jQuery's after()
* method to insert the given HTML content after each element matched by
@@ -923,7 +953,7 @@ function ajax_command_after($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'insert/before' command.
+ * Creates a Drupal Ajax 'insert/before' command.
*
* The 'insert/before' command instructs the client to use jQuery's before()
* method to insert the given HTML content before each of elements matched by
@@ -956,7 +986,7 @@ function ajax_command_before($selector, $html, $settings = NULL) {
}
/**
- * Creates a Drupal AJAX 'remove' command.
+ * Creates a Drupal Ajax 'remove' command.
*
* The 'remove' command instructs the client to use jQuery's remove() method
* to remove each of elements matched by the given selector, and everything
@@ -982,7 +1012,7 @@ function ajax_command_remove($selector) {
}
/**
- * Creates a Drupal AJAX 'changed' command.
+ * Creates a Drupal Ajax 'changed' command.
*
* This command instructs the client to mark each of the elements matched by the
* given selector as 'ajax-changed'.
@@ -1009,7 +1039,7 @@ function ajax_command_changed($selector, $asterisk = '') {
}
/**
- * Creates a Drupal AJAX 'css' command.
+ * Creates a Drupal Ajax 'css' command.
*
* The 'css' command will instruct the client to use the jQuery css() method
* to apply the CSS arguments to elements matched by the given selector.
@@ -1037,7 +1067,7 @@ function ajax_command_css($selector, $argument) {
}
/**
- * Creates a Drupal AJAX 'settings' command.
+ * Creates a Drupal Ajax 'settings' command.
*
* The 'settings' command instructs the client either to use the given array as
* the settings for ajax-loaded content or to extend Drupal.settings with the
@@ -1068,7 +1098,7 @@ function ajax_command_settings($argument, $merge = FALSE) {
}
/**
- * Creates a Drupal AJAX 'data' command.
+ * Creates a Drupal Ajax 'data' command.
*
* The 'data' command instructs the client to attach the name=value pair of
* data to the selector via jQuery's data cache.
@@ -1100,7 +1130,7 @@ function ajax_command_data($selector, $name, $value) {
}
/**
- * Creates a Drupal AJAX 'invoke' command.
+ * Creates a Drupal Ajax 'invoke' command.
*
* The 'invoke' command will instruct the client to invoke the given jQuery
* method with the supplied arguments on the elements matched by the given
@@ -1131,7 +1161,7 @@ function ajax_command_invoke($selector, $method, array $arguments = array()) {
}
/**
- * Creates a Drupal AJAX 'restripe' command.
+ * Creates a Drupal Ajax 'restripe' command.
*
* The 'restripe' command instructs the client to restripe a table. This is
* usually used after a table has been modified by a replace or append command.
diff --git a/includes/archiver.inc b/includes/archiver.inc
index 5e6ef323f..fec053be6 100644
--- a/includes/archiver.inc
+++ b/includes/archiver.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/authorize.inc b/includes/authorize.inc
index a1e8a7bdb..3617d7d03 100644
--- a/includes/authorize.inc
+++ b/includes/authorize.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -160,7 +159,7 @@ function _authorize_filetransfer_connection_settings($backend) {
* Therefore, to properly add defaults, we need to walk through all the
* children form elements and process those defaults recursively.
*
- * @param &$element
+ * @param $element
* Reference to the Form API form element we're operating on.
* @param $key
* The key for our current form element, if any.
diff --git a/includes/batch.inc b/includes/batch.inc
index 1510a62e8..7011abfbd 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
diff --git a/includes/batch.queue.inc b/includes/batch.queue.inc
index ee721463f..846483698 100644
--- a/includes/batch.queue.inc
+++ b/includes/batch.queue.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index fb73528ff..b70149cd3 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -9,7 +8,7 @@
/**
* The current system version.
*/
-define('VERSION', '7.1');
+define('VERSION', '7.2');
/**
* Core API compatibility.
@@ -1222,185 +1221,64 @@ function drupal_unpack($obj, $field = 'data') {
/**
* Translates a string to the current language or to a given language.
*
- * All human-readable text that will be displayed on the site or sent to a user
- * should be passed through the t() function. This ensures that sites can be
- * fully translated into other languages.
- *
- * Here are some examples of translating static text using t():
- * @code
- * if (!$info || !$info['extension']) {
- * form_set_error('picture_upload', t('The uploaded file was not an image.'));
- * }
- *
- * $form['submit'] = array(
- * '#type' => 'submit',
- * '#value' => t('Log in'),
- * );
- * @endcode
- *
- * In addition to translating static text, t() can handle text that should not
- * be translated or that might change from time to time (such as link paths)
- * and dynamic text from variables, using special "placeholders". There are
- * three styles of placeholders:
- * - !variable: Indicates that the text should be inserted as-is. This is
- * useful for inserting variables into things like e-mail. Example:
- * @code
- * $message[] = t("If you don't want to receive such e-mails, you can change your settings at !url.", array('!url' => url("user/$account->uid", array('absolute' => TRUE))));
- * @endcode
- * - @variable: Indicates that the text should be run through check_plain(), to
- * escape HTML characters. Use this for any output that is displayed within a
- * Drupal page. Example:
- * @code
- * drupal_set_title($title = t("@name's blog", array('@name' => format_username($account))), PASS_THROUGH);
- * @endcode
- * - %variable: Indicates that the string should be HTML-escaped and highlighted
- * with drupal_placeholder(), which shows up as <em>emphasized</em>.
- * @code
- * $message = t('%name-from sent %name-to an e-mail.', array('%name-from' => format_username($user), '%name-to' => format_username($account)));
- * @endcode
- *
- * When using t(), try to put entire paragraphs in one t() call. This makes it
- * easier for translators, as it provides context as to what each word refers
- * to (and also allows translators to adjust word order, which may not be the
- * same in all languages). HTML markup within translation strings is allowed,
- * but should be avoided if possible. The exception is embedded links: link
- * titles add context for translators and need to be translated, so they should
- * be kept in the main string, while link URLs should be generated using
- * placeholders.
- * - Incorrect HTML in t():
- * @code
- * $output .= t('<p>Go to the @contact-page.</p>', array('@contact-page' => l(t('contact page'), 'contact')));
- * @endcode
- * - Correct HTML in t():
- * @code
- * $output .= '<p>' . t('Go to the <a href="@contact-page">contact page</a>.', array('@contact-page' => url('contact'))) . '</p>';
- * @endcode
- *
- * Another thing that is helpful is to avoid escaping quotation marks wherever
- * possible, because it can be confusing to translation teams.
- * - Less desirable quotation mark escaping:
- * @code
- * $output .= t('Don\'t click me.');
- * @endcode
- * - Better way to use quotation marks:
- * @code
- * $output .= t("Don't click me.");
- * @endcode
- *
- * It is important that all translation uses the t() mechanism, because in
- * addition to actually translating the text at run-time, the t() function is
- * also used by text-extraction routines to find text that needs to be
- * translated, and build databases of text to be translated for translation
- * teams. For that reason, you must put the actual string into the t() function,
- * in most cases, and not a variable.
- * - Incorrect use of a variable in t():
- * @code
- * $message = 'An error occurred.';
- * drupal_set_message(t($message), 'error');
- * $output .= t($message);
- * @endcode
- * - Correct translation of a variable with t():
- * @code
- * $message = t('An error occurred.');
- * drupal_set_message($message, 'error');
- * $output .= $message;
- * @endcode
- *
- * The only case in which variables can be passed safely through t() is when
- * code-based versions of the same strings will be passed through t() (or
- * otherwise extracted) elsewhere.
- *
- * Also, you cannot use t() early in the bootstrap process, prior to the
- * DRUPAL_BOOTSTRAP_LANGUAGE phase. The language variables will not be
- * initialized yet, so the string will not be translated into the correct
- * language. Examples of places where t() cannot be used include:
- * - In a PHP define() statement.
- * - In a hook_boot() implementation.
- *
- * In some cases, modules may include strings in code that can't use t()
- * calls. For example, a module may use an external PHP application that
- * produces strings that are loaded into variables in Drupal for output.
- * In these cases, module authors may include a dummy file that passes the
- * relevant strings through t(). This approach will allow the strings to be
- * extracted.
- *
- * Sample external (non-Drupal) code:
- * @code
- * class Time {
- * public $yesterday = 'Yesterday';
- * public $today = 'Today';
- * public $tomorrow = 'Tomorrow';
- * }
- * @endcode
- *
- * Sample dummy file:
- * @code
- * // Dummy function included in example.potx.inc.
- * function example_potx() {
- * $strings = array(
- * t('Yesterday'),
- * t('Today'),
- * t('Tomorrow'),
- * );
- * // No return value needed, since this is a dummy function.
- * }
- * @endcode
- *
- * Having passed strings through t() in a dummy function, it is then
- * possible to pass variables through t():
- * @code
- * $time = new Time();
- * $output .= t($time->today);
- * @endcode
- *
- * However tempting it is, custom data from user input or other non-code
- * sources should not be passed through t(). Doing so leads to the following
- * problems and errors:
- * - The t() system doesn't support updates to existing strings. When user
- * data is updated, the next time it's passed through t(), a new record is
- * created instead of an update. The database bloats over time and any
- * existing translations are orphaned with each update.
- * - The t() system assumes any data it receives is in English. User data may
- * be in another language, producing translation errors.
- * - The "Built-in interface" text group in the locale system is used to
- * produce translations for storage in .po files. When non-code strings are
- * passed through t(), they are added to this text group, which is rendered
- * inaccurate since it is a mix of actual interface strings and various user
- * input strings of uncertain origin.
- * Instead, translation of these data can be done through the locale system,
- * either directly through hook_local() or through helper functions provided by
- * contributed modules.
- *
- * Incorrect:
+ * The t() function serves two purposes. First, at run-time it translates
+ * user-visible text into the appropriate language. Second, various mechanisms
+ * that figure out what text needs to be translated work off t() -- the text
+ * inside t() calls is added to the database of strings to be translated. So,
+ * to enable a fully-translatable site, it is important that all human-readable
+ * text that will be displayed on the site or sent to a user is passed through
+ * the t() function, or a related function. See the
+ * @link http://drupal.org/node/322729 Localization API @endlink pages for
+ * more information, including recommendations on how to break up or not
+ * break up strings for translation.
+ *
+ * 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
+ * literal strings in an array). It is especially important never to call
+ * @code t($user_text); @endcode, where $user_text is some text that a user
+ * entered - doing that can lead to cross-site scripting and other security
+ * problems. However, you can use variable substitution in your string, to put
+ * variable text such as user names or link URLs into translated text. Variable
+ * substitution looks like this:
* @code
- * $item = item_load();
- * $output .= check_plain(t($item['title']));
+ * $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").
*
- * During installation, st() is used in place of t(). Code that may be called
- * during installation or during normal operation should use the get_t()
- * helper function.
+ * 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.
*
* @param $string
* A string containing the English string to translate.
* @param $args
- * An associative array of replacements to make after translation. Incidences
- * 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 (using check_plain())
- * - %variable: escape text and theme as a placeholder for user-submitted
- * content (using check_plain() + drupal_placeholder())
+ * An associative array of replacements to make after translation.
+ * 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 <em>emphasized</em> text.
* @param $options
- * An associative array of additional options, with the following keys:
- * - '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.
+ * 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.
*
* @return
* The translated string.
*
+ * @see st()
+ * @see get_t()
* @ingroup sanitization
*/
function t($string, array $args = array(), array $options = array()) {
@@ -1547,7 +1425,7 @@ function request_uri() {
* The exception that is going to be logged.
* @param $message
* The message to store in the log. If empty, a text that contains all useful
- * information about the passed in exception is used.
+ * 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().
@@ -1643,8 +1521,8 @@ function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NO
* messages without clearing them.
*
* @param $message
- * The message should begin with a capital letter and always ends with a
- * period '.'.
+ * 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:
* - 'status'
@@ -2363,8 +2241,30 @@ function drupal_installation_attempted() {
}
/**
- * Return the name of the localization function. Use in code that needs to
- * run both during installation and normal operation.
+ * Returns the name of the proper localization function.
+ *
+ * get_t() exists to support localization for code that might run during
+ * the installation phase, when some elements of the system might not have
+ * loaded.
+ *
+ * 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
+ * module administration page.
+ *
+ * Example useage:
+ * @code
+ * $t = get_t();
+ * $translated = $t('translate this');
+ * @endcode
+ *
+ * Use t() if your code will never run during the Drupal installation phase.
+ * Use st() if your code will only run during installation and never any other
+ * time. Use get_t() if your code could run in either circumstance.
+ *
+ * @see t()
+ * @see st()
+ * @ingroup sanitization
*/
function get_t() {
static $t;
@@ -2420,6 +2320,9 @@ function drupal_language_types() {
* Return true if there is more than one language enabled.
*/
function drupal_multilingual() {
+ // The "language_count" variable stores the number of enabled languages to
+ // avoid unnecessarily querying the database when building the list of
+ // enabled languages on monolingual sites.
return variable_get('language_count', 1) > 1;
}
@@ -2491,6 +2394,8 @@ function language_default($property = NULL) {
* base_path() returns "/drupalfolder/".
* - http://example.com/path/alias (which is a path alias for node/306) returns
* "path/alias" as opposed to the internal path.
+ * - http://example.com/index.php returns an empty string (meaning: front page).
+ * - http://example.com/index.php?page=1 returns an empty string.
*
* @return
* The requested Drupal URL path.
@@ -2512,11 +2417,19 @@ function request_path() {
$path = $_GET['q'];
}
elseif (isset($_SERVER['REQUEST_URI'])) {
- // This is a request using a clean URL. Extract the path from REQUEST_URI.
+ // This request is either a clean URL, or 'index.php', or nonsense.
+ // Extract the path from REQUEST_URI.
$request_path = strtok($_SERVER['REQUEST_URI'], '?');
$base_path_len = strlen(rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/'));
// Unescape and strip $base_path prefix, leaving q without a leading slash.
$path = substr(urldecode($request_path), $base_path_len + 1);
+ // If the path equals the script filename, either because 'index.php' was
+ // explicitly provided in the URL, or because the server added it to
+ // $_SERVER['REQUEST_URI'] even when it wasn't provided in the URL (some
+ // versions of Microsoft IIS do this), the front page should be served.
+ if ($path == basename($_SERVER['PHP_SELF'])) {
+ $path = '';
+ }
}
else {
// This is the front page.
diff --git a/includes/cache-install.inc b/includes/cache-install.inc
index 545f1a2a2..d9bb0f92e 100644
--- a/includes/cache-install.inc
+++ b/includes/cache-install.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -31,7 +30,7 @@ class DrupalFakeCache extends DrupalDatabaseCache implements DrupalCacheInterfac
// 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
// during installation due to any full bootstraps that may occur at the
- // same time (for example, AJAX requests triggered by the installer). If we
+ // same time (for example, Ajax requests triggered by the installer). If we
// didn't try to clear it whenever this function is called, the data in the
// cache would become stale; for example, the installer sometimes calls
// variable_set(), which updates the {variable} table and then clears the
diff --git a/includes/cache.inc b/includes/cache.inc
index 21630617d..8666874ac 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* Get the cache object for a cache bin.
@@ -325,10 +324,15 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
try {
// Garbage collection necessary when enforcing a minimum cache lifetime.
$this->garbageCollection($this->bin);
- $query = db_select($this->bin);
- $query->fields($this->bin, array('cid', 'data', 'created', 'expire', 'serialized'));
- $query->condition($this->bin . '.cid', $cids, 'IN');
- $result = $query->execute();
+
+ // When serving cached pages, the overhead of using db_select() was found
+ // to add around 30% overhead to the request. Since $this->bin is a
+ // variable, this means the call to db_query() here uses a concatenated
+ // string. This is highly discouraged under any other circumstances, and
+ // is used here only due to the performance overhead we would incur
+ // otherwise. When serving an uncached page, the overhead of using
+ // db_select() is a much smaller proportion of the request.
+ $result = db_query('SELECT cid, data, created, expire, serialized FROM {' . db_escape_table($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids));
$cache = array();
foreach ($result as $item) {
$item = $this->prepareItem($item);
diff --git a/includes/common.inc b/includes/common.inc
index 03b0de485..5dadb4d16 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -915,7 +914,9 @@ function drupal_http_request($url, array $options = array()) {
return $result;
}
// Parse response headers from the response body.
- list($response, $result->data) = explode("\r\n\r\n", $response, 2);
+ // Be tolerant of malformed HTTP responses that separate header and body with
+ // \n\n or \r\r instead of \r\n\r\n.
+ list($response, $result->data) = preg_split("/\r\n\r\n|\n\n|\r\r/", $response, 2);
$response = preg_split("/\r\n|\n|\r/", $response);
// Parse the response status line.
@@ -1050,15 +1051,15 @@ function _fix_gpc_magic_files(&$item, $key) {
* Fix double-escaping problems caused by "magic quotes" in some PHP installations.
*/
function fix_gpc_magic() {
- $fixed = &drupal_static(__FUNCTION__, FALSE);
+ static $fixed = FALSE;
if (!$fixed && ini_get('magic_quotes_gpc')) {
array_walk($_GET, '_fix_gpc_magic');
array_walk($_POST, '_fix_gpc_magic');
array_walk($_COOKIE, '_fix_gpc_magic');
array_walk($_REQUEST, '_fix_gpc_magic');
array_walk($_FILES, '_fix_gpc_magic_files');
- $fixed = TRUE;
}
+ $fixed = TRUE;
}
/**
@@ -1974,7 +1975,7 @@ function _format_date_callback(array $matches = NULL, $new_langcode = NULL) {
/**
* Format a username.
*
- * By default, the passed in object's 'name' property is used if it exists, or
+ * 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).
*
@@ -2238,7 +2239,7 @@ function drupal_http_header_attributes(array $attributes = array()) {
* drupal_attributes(array('title' => t('<script>steal_cookie();</script>')));
*
* // The statement below demonstrates dangerous use of drupal_attributes, and
- * // will return an onmouseout attribute with javascript code that, when used
+ * // will return an onmouseout attribute with JavaScript code that, when used
* // as attribute in a tag, will cause users to be redirected to another site.
* //
* // In this case, the 'onmouseout' attribute should not be whitelisted --
@@ -2383,9 +2384,9 @@ function l($text, $path, array $options = array()) {
* basis in hook_page_delivery_callback_alter().
*
* For example, the same page callback function can be used for an HTML
- * version of the page and an AJAX version of the page. The page callback
+ * version of the page and an Ajax version of the page. The page callback
* function just needs to decide what content is to be returned and the
- * delivery callback function will send it as an HTML page or an AJAX
+ * delivery callback function will send it as an HTML page or an Ajax
* response, as appropriate.
*
* In order for page callbacks to be reusable in different delivery formats,
@@ -2602,7 +2603,8 @@ function drupal_exit($destination = NULL) {
* A linear array.
* @param $function
* A name of a function to apply to all values before output.
- * @result
+ *
+ * @return
* An associative array.
*/
function drupal_map_assoc($array, $function = NULL) {
@@ -3543,7 +3545,7 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
// There are different conditions for removing leading and trailing
// whitespace.
// @see http://php.net/manual/en/regexp.reference.subpatterns.php
- $contents = preg_replace_callback('<
+ $contents = preg_replace('<
# Strip leading and trailing whitespace.
\s*([@{};,])\s*
# Strip only leading whitespace from:
@@ -3554,7 +3556,10 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
# - Colon: Retain :pseudo-selectors.
| ([\(:])\s+
>xS',
- '_drupal_load_stylesheet_content',
+ // Only one of the three capturing groups will match, so its reference
+ // will contain the wanted value and the references for the
+ // two non-matching groups will be replaced with empty strings.
+ '$1$2$3',
$contents
);
// End the file with a new line.
@@ -3569,16 +3574,6 @@ function drupal_load_stylesheet_content($contents, $optimize = FALSE) {
}
/**
- * Helper for drupal_load_stylesheet_content().
- */
-function _drupal_load_stylesheet_content($matches) {
- // Discard the full match.
- unset($matches[0]);
- // Use the non-empty match.
- return current(array_filter($matches));
-}
-
-/**
* Loads stylesheets recursively and returns contents with corrected paths.
*
* This function is used for recursive loading of stylesheets and
@@ -3672,17 +3667,17 @@ function drupal_html_class($class) {
* blocks, and other content to be output multiple times on the same page,
* without breaking (X)HTML validation.
*
- * For already existing ids, a counter is appended to the id string. Therefore,
+ * For already existing IDs, a counter is appended to the ID string. Therefore,
* JavaScript and CSS code should not rely on any value that was generated by
* this function and instead should rely on manually added CSS classes or
* similarly reliable constructs.
*
- * Two consecutive hyphens separate the counter from the original id. To manage
- * uniqueness across multiple AJAX requests on the same page, AJAX requests
+ * Two consecutive hyphens separate the counter from the original ID. To manage
+ * uniqueness across multiple Ajax requests on the same page, Ajax requests
* POST an array of all IDs currently present on the page, which are used to
* prime this function's cache upon first invocation.
*
- * To allow reverse-parsing of ids submitted via AJAX, any multiple consecutive
+ * To allow reverse-parsing of IDs submitted via Ajax, any multiple consecutive
* hyphens in the originally passed $id are replaced with a single hyphen.
*
* @param $id
@@ -3692,10 +3687,10 @@ function drupal_html_class($class) {
* The cleaned ID.
*/
function drupal_html_id($id) {
- // If this is an AJAX request, then content returned by this page request will
- // be merged with content already on the base page. The HTML ids must be
+ // If this is an Ajax request, then content returned by this page request will
+ // 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.
+ // take into account IDs that are already in use on the base page.
$seen_ids_init = &drupal_static(__FUNCTION__ . ':init');
if (!isset($seen_ids_init)) {
// Ideally, Drupal would provide an API to persist state information about
@@ -3703,7 +3698,7 @@ function drupal_html_id($id) {
// function's $seen_ids static variable to that state information in order
// to have it properly initialized for this page request. However, no such
// page state API exists, so instead, ajax.js adds all of the in-use HTML
- // ids to the POST data of AJAX submissions. Direct use of $_POST is
+ // IDs to the POST data of Ajax submissions. Direct use of $_POST is
// normally not recommended as it could open up security risks, but because
// the raw POST data is cast to a number before being returned by this
// function, this usage is safe.
@@ -3750,7 +3745,7 @@ function drupal_html_id($id) {
// The counter needs to be appended with a delimiter that does not exist in
// the base ID. Requiring a unique delimiter helps ensure that we really do
// return unique IDs and also helps us re-create the $seen_ids array during
- // AJAX requests.
+ // Ajax requests.
if (isset($seen_ids[$id])) {
$id = $id . '--' . ++$seen_ids[$id];
}
@@ -3768,7 +3763,7 @@ function drupal_html_id($id) {
* page region that is output by the theme (Drupal core already handles this in
* the standard template preprocess implementation). Standardizing the class
* names in this way allows modules to implement certain features, such as
- * drag-and-drop or dynamic AJAX loading, in a theme-independent way.
+ * drag-and-drop or dynamic Ajax loading, in a theme-independent way.
*
* @param $region
* The name of the page region (for example, 'page_top' or 'content').
@@ -3953,12 +3948,17 @@ function drupal_add_js($data = NULL, $options = NULL) {
if (isset($data)) {
// Add jquery.js and drupal.js, as well as the basePath setting, the
- // first time a Javascript file is added.
+ // first time a JavaScript file is added.
if (empty($javascript)) {
+ // url() generates the prefix using hook_url_outbound_alter(). Instead of
+ // running the hook_url_outbound_alter() again here, extract the prefix
+ // from url().
+ url('', array('prefix' => &$prefix));
$javascript = array(
'settings' => array(
'data' => array(
array('basePath' => base_path()),
+ array('pathPrefix' => empty($prefix) ? '' : $prefix),
),
'type' => 'setting',
'scope' => 'header',
@@ -3996,7 +3996,7 @@ function drupal_add_js($data = NULL, $options = NULL) {
default: // 'file' and 'external'
// Local and external files must keep their name as the associative key
- // so the same JavaScript file is not be added twice.
+ // so the same JavaScript file is not added twice.
$javascript[$options['data']] = $options;
}
}
@@ -4094,13 +4094,13 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
// page request.
$default_query_string = variable_get('css_js_query_string', '0');
- // For inline Javascript to validate as XHTML, all Javascript containing
+ // For inline JavaScript to validate as XHTML, all JavaScript containing
// XHTML needs to be wrapped in CDATA. To make that backwards compatible
// with HTML 4, we need to comment out the CDATA-tag.
$embed_prefix = "\n<!--//--><![CDATA[//><!--\n";
$embed_suffix = "\n//--><!]]>\n";
- // Since Javascript may look for arguments in the url and act on them, some
+ // Since JavaScript may look for arguments in the URL and act on them, some
// third-party code might require the use of a different query string.
$js_version_string = variable_get('drupal_js_version_query_string', 'v=');
@@ -4318,7 +4318,7 @@ function drupal_process_attached($elements, $group = JS_DEFAULT, $dependency_che
}
// Add additional types of attachments specified in the render() structure.
- // Libraries, Javascript and CSS have been added already, as they require
+ // Libraries, JavaScript and CSS have been added already, as they require
// special handling.
foreach ($elements['#attached'] as $callback => $options) {
if (function_exists($callback)) {
@@ -4785,7 +4785,7 @@ function drupal_clear_js_cache() {
}
/**
- * Converts a PHP variable into its Javascript equivalent.
+ * Converts a PHP variable into its JavaScript equivalent.
*
* We use HTML-safe strings, i.e. with <, > and & escaped.
*
@@ -4881,12 +4881,12 @@ function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
}
function _drupal_bootstrap_full() {
- $called = &drupal_static(__FUNCTION__);
+ static $called = FALSE;
if ($called) {
return;
}
- $called = 1;
+ $called = TRUE;
require_once DRUPAL_ROOT . '/' . variable_get('path_inc', 'includes/path.inc');
require_once DRUPAL_ROOT . '/includes/theme.inc';
require_once DRUPAL_ROOT . '/includes/pager.inc';
@@ -5235,7 +5235,7 @@ function drupal_set_page_content($content = NULL) {
* browsers, '#browsers' can be set to array('IE' => 'gte IE 8').
*
* @return
- * The passed in element with markup for conditional comments potentially
+ * The passed-in element with markup for conditional comments potentially
* added to '#prefix' and '#suffix'.
*/
function drupal_pre_render_conditional_comments($elements) {
@@ -5297,7 +5297,7 @@ function drupal_pre_render_conditional_comments($elements) {
* - #options: (optional) An array of options to pass to l().
*
* @return
- * The passed in elements containing a rendered link in '#markup'.
+ * The passed-in elements containing a rendered link in '#markup'.
*/
function drupal_pre_render_link($element) {
// By default, link options to pass to l() are normally set in #options.
@@ -5327,7 +5327,7 @@ function drupal_pre_render_link($element) {
if (!isset($element['#id'])) {
$element['#id'] = $element['#options']['attributes']['id'] = drupal_html_id('ajax-link');
}
- // If #ajax['path] was not specified, use the href as AJAX request URL.
+ // If #ajax['path] was not specified, use the href as Ajax request URL.
if (!isset($element['#ajax']['path'])) {
$element['#ajax']['path'] = $element['#href'];
$element['#ajax']['options'] = $element['#options'];
@@ -5444,7 +5444,7 @@ function drupal_pre_render_links($element) {
* A structured array using the #markup key.
*
* @return
- * The passed in elements, but #markup appended to #children.
+ * The passed-in elements, but #markup appended to #children.
*/
function drupal_pre_render_markup($elements) {
$elements['#children'] = $elements['#markup'];
@@ -5575,9 +5575,9 @@ function drupal_render(&$elements) {
return $cached_output;
}
- // If #markup is not empty, set #type. This allows to specify just #markup on
- // an element without setting #type.
- if (!empty($elements['#markup']) && !isset($elements['#type'])) {
+ // If #markup is set, ensure #type is set. This allows to specify just #markup
+ // on an element without setting #type.
+ if (isset($elements['#markup']) && !isset($elements['#type'])) {
$elements['#type'] = 'markup';
}
@@ -5694,13 +5694,17 @@ function drupal_render_children(&$element, $children_keys = NULL) {
}
/**
- * Render and print an element.
+ * Render an element.
*
* This function renders an element using drupal_render(). The top level
- * element is always rendered even if hide() had been previously used on it.
+ * element is shown with show() before rendering, so it will always be rendered
+ * even if hide() had been previously used on it.
*
- * Any nested elements are only rendered if they haven't been rendered before
- * or if they have been re-enabled with show().
+ * @param $element
+ * The element to be rendered.
+ *
+ * @return
+ * The rendered element.
*
* @see drupal_render()
* @see show()
@@ -5721,6 +5725,21 @@ function render(&$element) {
/**
* Hide an element from later rendering.
*
+ * The first time render() or drupal_render() is called on an element tree,
+ * as each element in the tree is rendered, it is marked with a #printed flag
+ * and the rendered children of the element are cached. Subsequent calls to
+ * render() or drupal_render() will not traverse the child tree of this element
+ * again: they will just use the cached children. So if you want to hide an
+ * element, be sure to call hide() on the element before its parent tree is
+ * rendered for the first time, as it will have no effect on subsequent
+ * renderings of the parent tree.
+ *
+ * @param $element
+ * The element to be hidden.
+ *
+ * @return
+ * The element.
+ *
* @see render()
* @see show()
*/
@@ -5730,10 +5749,25 @@ function hide(&$element) {
}
/**
- * Show a hidden or already printed element from later rendering.
+ * Show a hidden element for later rendering.
+ *
+ * You can also use render($element), which shows the element while rendering
+ * it.
+ *
+ * The first time render() or drupal_render() is called on an element tree,
+ * as each element in the tree is rendered, it is marked with a #printed flag
+ * and the rendered children of the element are cached. Subsequent calls to
+ * render() or drupal_render() will not traverse the child tree of this element
+ * again: they will just use the cached children. So if you want to show an
+ * element, be sure to call show() on the element before its parent tree is
+ * rendered for the first time, as it will have no effect on subsequent
+ * renderings of the parent tree.
+ *
+ * @param $element
+ * The element to be shown.
*
- * Alternatively, render($element) could be used which automatically shows the
- * element while rendering it.
+ * @return
+ * The element.
*
* @see render()
* @see hide()
@@ -5800,8 +5834,9 @@ function drupal_render_cache_set(&$markup, $elements) {
// be retrieved and used.
$data['#markup'] = &$markup;
// Persist attached data associated with this element.
- if (isset($elements['#attached'])) {
- $data['#attached'] = $elements['#attached'];
+ $attached = drupal_render_collect_attached($elements, TRUE);
+ if ($attached) {
+ $data['#attached'] = $attached;
}
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : CACHE_PERMANENT;
@@ -5809,6 +5844,49 @@ function drupal_render_cache_set(&$markup, $elements) {
}
/**
+ * Collect #attached for an element and all child elements into a single array.
+ *
+ * When caching elements, it is necessary to collect all libraries, JavaScript
+ * and CSS into a single array, from both the element itself and all child
+ * elements. This allows drupal_render() to add these back to the page when the
+ * element is returned from cache.
+ *
+ * @param $elements
+ * The element to collect #attached from.
+ * @param $return
+ * Whether to return the attached elements and reset the internal static.
+ *
+ * @return
+ * The #attached array for this element and its descendants.
+ */
+function drupal_render_collect_attached($elements, $return = FALSE) {
+ $attached = &drupal_static(__FUNCTION__, array());
+
+ // Collect all #attached for this element.
+ if (isset($elements['#attached'])) {
+ foreach ($elements['#attached'] as $key => $value) {
+ if (!isset($attached[$key])) {
+ $attached[$key] = array();
+ }
+ $attached[$key] = array_merge($attached[$key], $value);
+ }
+ }
+ if ($children = element_children($elements)) {
+ foreach ($children as $child) {
+ drupal_render_collect_attached($elements[$child]);
+ }
+ }
+
+ // If this was the first call to the function, return all attached elements
+ // and reset the static cache.
+ if ($return) {
+ $return = $attached;
+ $attached = array();
+ return $return;
+ }
+}
+
+/**
* Prepare an element for caching based on a query. This smart caching strategy
* saves Drupal from querying and rendering to HTML when the underlying query is
* unchanged.
@@ -5830,7 +5908,7 @@ function drupal_render_cache_set(&$markup, $elements) {
*
* @return
* A renderable array with the following keys and values:
- * - #query: The passed in $query.
+ * - #query: The passed-in $query.
* - #pre_render: $function with a _pre_render suffix.
* - #cache: An associative array prepared for drupal_render_cache_set().
*/
@@ -6237,7 +6315,7 @@ function drupal_array_set_nested_value(array &$array, array $parents, $value, $f
* The array from which to get the value.
* @param $parents
* An array of parent keys of the value, starting with the outermost key.
- * @param &$key_exists
+ * @param $key_exists
* (optional) If given, an already defined variable that is altered by
* reference.
*
@@ -6651,30 +6729,27 @@ function drupal_schema_fields_sql($table, $prefix = NULL) {
}
/**
- * Saves a record to the database based upon the schema.
- *
- * Default values are filled in for missing items, and 'serial' (auto increment)
- * types are filled in with IDs.
+ * Saves (inserts or updates) a record to the database based upon the schema.
*
* @param $table
* The name of the table; this must be defined by a hook_schema()
* implementation.
* @param $record
* An object or array representing the record to write, passed in by
- * reference. The function will fill in defaults from the schema and add an
- * ID value to serial fields.
+ * reference. If inserting a new record, values not provided in $record will
+ * be populated in $record and in the database with the default values from
+ * the schema, as well as a single serial (auto-increment) field (if present).
+ * If updating an existing record, only provided values are updated in the
+ * database, and $record is not modified.
* @param $primary_keys
- * If this is an update, specify the primary keys' field names. If this is a
- * new record, you must not provide this value. If there is only 1 field in
- * the key, you may pass in a string; if there are multiple fields in the key,
- * pass in an array.
+ * To indicate that this is a new record to be inserted, omit this argument.
+ * If this is an update, this argument specifies the primary keys' field
+ * names. If there is only 1 field in the key, you may pass in a string; if
+ * there are multiple fields in the key, pass in an array.
*
* @return
- * Failure to write a record will return FALSE. Otherwise SAVED_NEW or
- * SAVED_UPDATED is returned depending on the operation performed. The $object
- * parameter will contain values for any serial fields defined by the $table.
- * For example, $record->nid or $record['nid'] will be populated after
- * inserting a new a new node.
+ * If the record insert or update failed, returns FALSE. If it succeeded,
+ * returns SAVED_NEW or SAVED_UPDATED, depending on the operation performed.
*/
function drupal_write_record($table, &$record, $primary_keys = array()) {
// Standardize $primary_keys to an array.
@@ -6815,7 +6890,7 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
*/
/**
- * Parse Drupal module and theme info file format.
+ * Parses Drupal module and theme .info files.
*
* Info files are NOT for placing arbitrary theme and module-specific settings.
* Use variable_get() and variable_set() for that.
@@ -6826,35 +6901,42 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
* - dependencies: An array of shortnames of other modules this module requires.
* - package: The name of the package of modules this module belongs to.
*
- * @see forum.info
+ * See forum.info for an example of a module .info file.
*
* Information stored in a theme .info file:
- * - name: The real name of the theme for display purposes
- * - description: Brief description
+ * - name: The real name of the theme for display purposes.
+ * - description: Brief description.
* - screenshot: Path to screenshot relative to the theme's .info file.
* - engine: Theme engine; typically phptemplate.
- * - base: Name of a base theme, if applicable, eg: base = zen
- * - regions: Listed regions eg: region[left] = Left sidebar
- * - features: Features available eg: features[] = logo
- * - stylesheets: Theme stylesheets eg: stylesheets[all][] = my-style.css
- * - scripts: Theme scripts eg: scripts[] = my-script.css
+ * - base: Name of a base theme, if applicable; e.g., base = zen.
+ * - regions: Listed regions; e.g., region[left] = Left sidebar.
+ * - features: Features available; e.g., features[] = logo.
+ * - stylesheets: Theme stylesheets; e.g., stylesheets[all][] = my-style.css.
+ * - scripts: Theme scripts; e.g., scripts[] = my-script.js.
*
- * @see bartik.info
+ * See bartik.info for an example of a theme .info file.
*
* @param $filename
* The file we are parsing. Accepts file with relative or absolute path.
+ *
* @return
* The info array.
*
* @see drupal_parse_info_format()
*/
function drupal_parse_info_file($filename) {
- if (!file_exists($filename)) {
- return array();
- }
+ $info = &drupal_static(__FUNCTION__, array());
- $data = file_get_contents($filename);
- return drupal_parse_info_format($data);
+ if (!isset($info[$filename])) {
+ if (!file_exists($filename)) {
+ $info[$filename] = array();
+ }
+ else {
+ $data = file_get_contents($filename);
+ $info[$filename] = drupal_parse_info_format($data);
+ }
+ }
+ return $info[$filename];
}
/**
@@ -7319,8 +7401,7 @@ function entity_create_stub_entity($entity_type, $ids) {
/**
* Load entities from the database.
*
- * This function should be used whenever you need to load more than one entity
- * from the database. The entities are loaded into memory and will not require
+ * The entities are stored in a static memory cache, and will not require
* database access if loaded again during the same page request.
*
* The actual loading is done through a class that has to implement the
@@ -7415,8 +7496,15 @@ function entity_get_controller($entity_type) {
* The type of entity, i.e. 'node', 'user'.
* @param $entities
* The entity objects which are being prepared for view, keyed by object ID.
+ * @param $langcode
+ * (optional) A language code to be used for rendering. Defaults to the global
+ * content language of the current request.
*/
-function entity_prepare_view($entity_type, $entities) {
+function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
+ if (!isset($langcode)) {
+ $langcode = $GLOBALS['language_content']->language;
+ }
+
// To ensure hooks are only run once per entity, check for an
// entity_view_prepared flag and only process items without it.
// @todo: resolve this more generally for both entity and field level hooks.
@@ -7432,7 +7520,7 @@ function entity_prepare_view($entity_type, $entities) {
}
if (!empty($prepare)) {
- module_invoke_all('entity_prepare_view', $prepare, $entity_type);
+ module_invoke_all('entity_prepare_view', $prepare, $entity_type, $langcode);
}
}
@@ -7507,7 +7595,7 @@ function entity_label($entity_type, $entity) {
$label = FALSE;
$info = entity_get_info($entity_type);
if (isset($info['label callback']) && function_exists($info['label callback'])) {
- $label = $info['label callback']($entity);
+ $label = $info['label callback']($entity, $entity_type);
}
elseif (!empty($info['entity keys']['label']) && isset($entity->{$info['entity keys']['label']})) {
$label = $entity->{$info['entity keys']['label']};
diff --git a/includes/database/database.inc b/includes/database/database.inc
index b384afe3a..4cc1a33d7 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -321,7 +320,7 @@ abstract class DatabaseConnection extends PDO {
* PDO::FETCH_OBJ, PDO::FETCH_NUM, or a string representing the name of a
* class. If a string is specified, each record will be fetched into a new
* object of that class. The behavior of all other values is defined by PDO.
- * See http://www.php.net/PDOStatement-fetch
+ * See http://php.net/manual/pdostatement.fetch.php
* - return: Depending on the type of query, different return values may be
* meaningful. This directive instructs the system which type of return
* value is desired. The system will generally set the correct value
@@ -542,6 +541,63 @@ abstract class DatabaseConnection extends PDO {
}
/**
+ * Flatten an array of query comments into a single comment string.
+ *
+ * The comment string will be sanitized to avoid SQL injection attacks.
+ *
+ * @param $comments
+ * An array of query comment strings.
+ *
+ * @return
+ * A sanitized comment string.
+ */
+ public function makeComment($comments) {
+ if (empty($comments))
+ return '';
+
+ // Flatten the array of comments.
+ $comment = implode('; ', $comments);
+
+ // Sanitize the comment string so as to avoid SQL injection attacks.
+ return '/* ' . $this->filterComment($comment) . ' */ ';
+ }
+
+ /**
+ * Sanitize a query comment string.
+ *
+ * Ensure a query comment does not include strings such as "* /" that might
+ * terminate the comment early. This avoids SQL injection attacks via the
+ * query comment. The comment strings in this example are separated by a
+ * space to avoid PHP parse errors.
+ *
+ * For example, the comment:
+ * @code
+ * db_update('example')
+ * ->condition('id', $id)
+ * ->fields(array('field2' => 10))
+ * ->comment('Exploit * / DROP TABLE node; --')
+ * ->execute()
+ * @endcode
+ *
+ * Would result in the following SQL statement being generated:
+ * @code
+ * "/ * Exploit * / DROP TABLE node; -- * / UPDATE example SET field2=..."
+ * @endcode
+ *
+ * Unless the comment is sanitised first, the SQL server would drop the
+ * node table and ignore the rest of the SQL statement.
+ *
+ * @param $comment
+ * A query comment string.
+ *
+ * @return
+ * A sanitized version of the query comment string.
+ */
+ protected function filterComment($comment = '') {
+ return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment);
+ }
+
+ /**
* Executes a query string against the database.
*
* This method provides a central handler for the actual execution of every
diff --git a/includes/database/log.inc b/includes/database/log.inc
index f28aadb2c..ec27ef8e6 100644
--- a/includes/database/log.inc
+++ b/includes/database/log.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc
index a3d711840..262cc6051 100644
--- a/includes/database/mysql/database.inc
+++ b/includes/database/mysql/database.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/mysql/install.inc b/includes/database/mysql/install.inc
index 2f83b2664..75f2ae390 100644
--- a/includes/database/mysql/install.inc
+++ b/includes/database/mysql/install.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/mysql/query.inc b/includes/database/mysql/query.inc
index 584a4a473..888b6a5a4 100644
--- a/includes/database/mysql/query.inc
+++ b/includes/database/mysql/query.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @ingroup database
@@ -43,8 +42,8 @@ class InsertQuery_mysql extends InsertQuery {
}
public function __toString() {
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
// Default fields are always placed first for consistency.
$insert_fields = array_merge($this->defaultFields, $this->insertFields);
@@ -93,8 +92,8 @@ class TruncateQuery_mysql extends TruncateQuery {
// not transactional, and result in an implicit COMMIT. When we are in a
// transaction, fallback to the slower, but transactional, DELETE.
if ($this->connection->inTransaction()) {
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
}
else {
diff --git a/includes/database/mysql/schema.inc b/includes/database/mysql/schema.inc
index 01933da09..4e88fa169 100644
--- a/includes/database/mysql/schema.inc
+++ b/includes/database/mysql/schema.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc
index d38b64afe..98b954ffd 100644
--- a/includes/database/pgsql/database.inc
+++ b/includes/database/pgsql/database.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -35,6 +34,15 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
if (empty($connection_options['password'])) {
$connection_options['password'] = NULL;
}
+ // If the password contains a backslash it is treated as an escape character
+ // http://bugs.php.net/bug.php?id=53217
+ // so backslashes in the password need to be doubled up.
+ // The bug was reported against pdo_pgsql 1.0.2, backslashes in passwords
+ // will break on this doubling up when the bug is fixed, so check the version
+ //elseif (phpversion('pdo_pgsql') < 'version_this_was_fixed_in') {
+ else {
+ $connection_options['password'] = str_replace('\\', '\\\\', $connection_options['password']);
+ }
$this->connectionOptions = $connection_options;
diff --git a/includes/database/pgsql/install.inc b/includes/database/pgsql/install.inc
index 0d446af58..c77f4ea78 100644
--- a/includes/database/pgsql/install.inc
+++ b/includes/database/pgsql/install.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc
index c475a0011..f3783a9ca 100644
--- a/includes/database/pgsql/query.inc
+++ b/includes/database/pgsql/query.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @ingroup database
@@ -104,8 +103,8 @@ class InsertQuery_pgsql extends InsertQuery {
}
public function __toString() {
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
// Default fields are always placed first for consistency.
$insert_fields = array_merge($this->defaultFields, $this->insertFields);
diff --git a/includes/database/pgsql/schema.inc b/includes/database/pgsql/schema.inc
index 30f12ef78..9ed8a2620 100644
--- a/includes/database/pgsql/schema.inc
+++ b/includes/database/pgsql/schema.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -528,6 +527,9 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
$this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $check . '"');
}
+ // Remove old default.
+ $this->fieldSetNoDefault($table, $field);
+
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast);
if (isset($spec['not null'])) {
@@ -562,6 +564,11 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
$this->connection->query('ALTER TABLE {' . $table . '} ADD CHECK ("' . $field_new . '" >= 0)');
}
+ // Add default if necessary.
+ if (isset($spec['default'])) {
+ $this->fieldSetDefault($table, $field_new, $spec['default']);
+ }
+
// Change description if necessary.
if (!empty($spec['description'])) {
$this->connection->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description']));
diff --git a/includes/database/pgsql/select.inc b/includes/database/pgsql/select.inc
index 98061c90a..d1d838281 100644
--- a/includes/database/pgsql/select.inc
+++ b/includes/database/pgsql/select.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/prefetch.inc b/includes/database/prefetch.inc
index a81ea10f1..f378d3555 100644
--- a/includes/database/prefetch.inc
+++ b/includes/database/prefetch.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/query.inc b/includes/database/query.inc
index de421b30c..23b652f9b 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @ingroup database
@@ -362,6 +361,9 @@ abstract class Query implements QueryPlaceholderInterface {
* for easier debugging and allows you to more easily find where a query
* with a performance problem is being generated.
*
+ * The comment string will be sanitized to remove * / and other characters
+ * that may terminate the string early so as to avoid SQL injection attacks.
+ *
* @param $comment
* The comment string to be inserted into the query.
*
@@ -624,9 +626,8 @@ class InsertQuery extends Query {
* The prepared statement.
*/
public function __toString() {
-
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
// Default fields are always placed first for consistency.
$insert_fields = array_merge($this->defaultFields, $this->insertFields);
@@ -816,9 +817,8 @@ class DeleteQuery extends Query implements QueryConditionInterface {
* The prepared statement.
*/
public function __toString() {
-
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
$query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
@@ -885,8 +885,8 @@ class TruncateQuery extends Query {
* The prepared statement.
*/
public function __toString() {
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
}
@@ -1112,9 +1112,8 @@ class UpdateQuery extends Query implements QueryConditionInterface {
* The prepared statement.
*/
public function __toString() {
-
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
// Expressions take priority over literal fields, so we process those first
// and remove any literal fields that conflict.
diff --git a/includes/database/schema.inc b/includes/database/schema.inc
index e57c94bfb..de1b2f5b9 100644
--- a/includes/database/schema.inc
+++ b/includes/database/schema.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/select.inc b/includes/database/select.inc
index 43f92671e..716c2fc3d 100644
--- a/includes/database/select.inc
+++ b/includes/database/select.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @ingroup database
@@ -1440,9 +1439,8 @@ class SelectQuery extends Query implements SelectQueryInterface {
}
public function __toString() {
-
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
// SELECT
$query = $comments . 'SELECT ';
diff --git a/includes/database/sqlite/database.inc b/includes/database/sqlite/database.inc
index 651efa26f..cf3b9551f 100644
--- a/includes/database/sqlite/database.inc
+++ b/includes/database/sqlite/database.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/sqlite/install.inc b/includes/database/sqlite/install.inc
index a8a12410d..62cbac381 100644
--- a/includes/database/sqlite/install.inc
+++ b/includes/database/sqlite/install.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index 7b1af8114..6b8a72f2a 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -33,8 +32,8 @@ class InsertQuery_sqlite extends InsertQuery {
}
public function __toString() {
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
// Produce as many generic placeholders as necessary.
$placeholders = array_fill(0, count($this->insertFields), '?');
@@ -102,7 +101,7 @@ class UpdateQuery_sqlite extends UpdateQuery {
}
elseif (!isset($data)) {
// The field will be set to NULL.
- $condition->isNull($field);
+ $condition->isNotNull($field);
}
else {
$condition->condition($field, $data, '<>');
@@ -149,8 +148,8 @@ class DeleteQuery_sqlite extends DeleteQuery {
*/
class TruncateQuery_sqlite extends TruncateQuery {
public function __toString() {
- // Create a comments string to prepend to the query.
- $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+ // Create a sanitized comment string to prepend to the query.
+ $comments = $this->connection->makeComment($this->comments);
return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
}
diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc
index 11ecd881a..840ba6b5d 100644
--- a/includes/database/sqlite/schema.inc
+++ b/includes/database/sqlite/schema.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/database/sqlite/select.inc b/includes/database/sqlite/select.inc
index ee3d84dff..fb926ef04 100644
--- a/includes/database/sqlite/select.inc
+++ b/includes/database/sqlite/select.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/date.inc b/includes/date.inc
index 75d666bc9..27634f9e3 100644
--- a/includes/date.inc
+++ b/includes/date.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/entity.inc b/includes/entity.inc
index 5fb36e2dd..a3cdf7417 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* Interface for entity controller classes.
@@ -409,7 +408,7 @@ class EntityFieldQueryException extends Exception {}
* direct access to the collected properties in order to handle alternate
* execution routines. We therefore use public properties for simplicity. Note
* that code that is simply creating and running a field query should still use
- * the appropriate methods add conditions on the query.
+ * the appropriate methods to add conditions on the query.
*
* Storage engines are not required to support every type of query. By default,
* an EntityFieldQueryException will be raised if an unsupported condition is
diff --git a/includes/errors.inc b/includes/errors.inc
index 235c16141..3a97b6daa 100644
--- a/includes/errors.inc
+++ b/includes/errors.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/file.inc b/includes/file.inc
index 4f7a4c3be..6dc7f88b3 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -202,9 +201,8 @@ function file_stream_wrapper_get_class($scheme) {
* @see file_uri_target()
*/
function file_uri_scheme($uri) {
- $data = explode('://', $uri, 2);
-
- return count($data) == 2 ? $data[0] : FALSE;
+ $position = strpos($uri, '://');
+ return $position ? substr($uri, 0, $position) : FALSE;
}
/**
@@ -424,7 +422,7 @@ function file_create_url($uri) {
* Directories need to have execute permissions to be considered a directory by
* FTP servers, etc.
*
- * @param &$directory
+ * @param $directory
* A string reference containing the name of a directory path or URI. A
* trailing slash will be trimmed from a path.
* @param $options
diff --git a/includes/file.mimetypes.inc b/includes/file.mimetypes.inc
index fe23ba48b..cda03fb92 100644
--- a/includes/file.mimetypes.inc
+++ b/includes/file.mimetypes.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/filetransfer/filetransfer.inc b/includes/filetransfer/filetransfer.inc
index cd62f1d51..2083da9d3 100644
--- a/includes/filetransfer/filetransfer.inc
+++ b/includes/filetransfer/filetransfer.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/*
* Base FileTransfer class.
diff --git a/includes/filetransfer/ftp.inc b/includes/filetransfer/ftp.inc
index ddb0d3eae..838dc7c1e 100644
--- a/includes/filetransfer/ftp.inc
+++ b/includes/filetransfer/ftp.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* Base class for FTP implementations.
diff --git a/includes/filetransfer/local.inc b/includes/filetransfer/local.inc
index d5744c191..b12598973 100644
--- a/includes/filetransfer/local.inc
+++ b/includes/filetransfer/local.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* The local connection class for copying files as the httpd user.
diff --git a/includes/filetransfer/ssh.inc b/includes/filetransfer/ssh.inc
index 56b944ca4..43ec3249e 100644
--- a/includes/filetransfer/ssh.inc
+++ b/includes/filetransfer/ssh.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* The SSH connection class for the update module.
diff --git a/includes/form.inc b/includes/form.inc
index 2ff93e61c..a337b03d1 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @defgroup forms Form builder functions
@@ -128,9 +127,9 @@
* - 'triggering_element': (read-only) The form element that triggered
* submission. This is the same as the deprecated
* $form_state['clicked_button']. It is the element that caused submission,
- * which may or may not be a button (in the case of AJAX forms.) This is
+ * which may or may not be a button (in the case of Ajax forms.) This is
* often used to distinguish between various buttons in a submit handler,
- * and is also used in AJAX handlers.
+ * and is also used in Ajax handlers.
* - 'cache': The typical form workflow involves two page requests. During the
* first page request, a form is built and returned for the user to fill in.
* Then the user fills the form in and submits it, triggering a second page
@@ -139,9 +138,9 @@
* In some special use-cases, it is necessary or desired to persist the $form
* and $form_state variables from the initial page request to the one that
* processes the submission. A form builder function can set 'cache' to TRUE
- * to do this. One example where this is needed is to handle AJAX submissions,
+ * to do this. One example where this is needed is to handle Ajax submissions,
* so ajax_process_form() sets this for all forms that include an element with
- * a #ajax property. (In AJAX, the handler has no way to build the form
+ * a #ajax property. (In Ajax, the handler has no way to build the form
* itself, so must rely on the cached version created on each page load, so
* it's a classic example of this use case.) Note that the persistence of
* $form and $form_state across successive submissions of a multi-step form
@@ -202,7 +201,7 @@ function drupal_get_form($form_id) {
* can implement hook_forms(), which maps different $form_id values to the
* proper form constructor function. Examples may be found in node_forms(),
* search_forms(), and user_forms().
- * @param &$form_state
+ * @param $form_state
* An array which stores information about the form. This is passed as a
* reference so that the caller can use it to examine what in the form changed
* when the form submission process is complete. Furthermore, it may be used
@@ -254,7 +253,7 @@ function drupal_get_form($form_id) {
* - must_validate: Ordinarily, a form is only validated once but there are
* times when a form is resubmitted internally and should be validated
* again. Setting this to TRUE will force that to happen. This is most
- * likely to occur during AHAH or AJAX operations.
+ * likely to occur during AHAH or Ajax operations.
* - temporary: An array holding temporary data accessible during the current
* page request only. It may be used to temporary save any data that doesn't
* need to or shouldn't be cached during the whole form workflow, e.g. data
@@ -396,9 +395,9 @@ function form_state_defaults() {
* function is called to generate a new $form, the next step in the form
* workflow, to be returned for rendering.
*
- * AJAX form submissions are almost always multi-step workflows, so that is one
+ * Ajax form submissions are almost always multi-step workflows, so that is one
* common use-case during which form rebuilding occurs. See ajax_form_callback()
- * for more information about creating AJAX-enabled forms.
+ * for more information about creating Ajax-enabled forms.
*
* @param $form_id
* The unique string identifying the desired form. If a function
@@ -411,7 +410,7 @@ function form_state_defaults() {
* A keyed array containing the current state of the form.
* @param $old_form
* (optional) A previously built $form. Used to retain the #build_id and
- * #action properties in AJAX callbacks and similar partial form rebuilds. The
+ * #action properties in Ajax callbacks and similar partial form rebuilds. The
* only properties copied from $old_form are the ones which both exist in
* $old_form and for which $form_state['rebuild_info']['copy'][PROPERTY] is
* TRUE. If $old_form is not passed, the entire $form is rebuilt freshly.
@@ -427,7 +426,7 @@ function form_state_defaults() {
function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
$form = drupal_retrieve_form($form_id, $form_state);
- // If only parts of the form will be returned to the browser (e.g. AJAX or
+ // If only parts of the form will be returned to the browser (e.g., Ajax or
// RIA clients), re-use the old #build_id to not require client-side code to
// manually update the hidden 'build_id' input element.
// Otherwise, a new #build_id is generated, to not clobber the previous
@@ -441,7 +440,7 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
$form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
}
- // #action defaults to request_uri(), but in case of AJAX and other partial
+ // #action defaults to request_uri(), but in case of Ajax and other partial
// rebuilds, the form is submitted to an alternate URL, and the original
// #action needs to be retained.
if (isset($old_form['#action']) && !empty($form_state['rebuild_info']['copy']['#action'])) {
@@ -882,13 +881,13 @@ function drupal_process_form($form_id, &$form, &$form_state) {
// yet complete. A new $form needs to be constructed based on the changes
// made to $form_state during this request. Normally, a submit handler sets
// $form_state['rebuild'] if a fully executed form requires another step.
- // However, for forms that have not been fully executed (e.g., AJAX
+ // However, for forms that have not been fully executed (e.g., Ajax
// submissions triggered by non-buttons), there is no submit handler to set
// $form_state['rebuild']. It would not make sense to redisplay the
// identical form without an error for the user to correct, so we also
// rebuild error-free non-executed forms, regardless of
// $form_state['rebuild'].
- // @todo D8: Simplify this logic; considering AJAX and non-HTML front-ends,
+ // @todo D8: Simplify this logic; considering Ajax and non-HTML front-ends,
// along with element-level #submit properties, it makes no sense to have
// divergent form execution based on whether the triggering element has
// #executes_submit_callback set to TRUE.
@@ -1146,7 +1145,7 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
* - If $form_state['no_redirect'] is TRUE, then the callback that originally
* built the form explicitly disallows any redirection, regardless of the
* redirection value in $form_state['redirect']. For example, ajax_get_form()
- * defines $form_state['no_redirect'] when building a form in an AJAX
+ * defines $form_state['no_redirect'] when building a form in an Ajax
* callback to prevent any redirection. $form_state['no_redirect'] should NOT
* be altered by form builder functions or form validation/submit handlers.
* - If $form_state['programmed'] is TRUE, the form submission was usually
@@ -1286,7 +1285,7 @@ function _form_validate(&$elements, &$form_state, $form_id = NULL) {
// If submit handlers won't run (due to the submission having been triggered
// by an element whose #executes_submit_callback property isn't TRUE), then
// it's safe to suppress all validation errors, and we do so by default,
- // which is particularly useful during an AJAX submission triggered by a
+ // which is particularly useful during an Ajax submission triggered by a
// non-button. An element can override this default by setting the
// #limit_validation_errors property. For button element types,
// #limit_validation_errors defaults to FALSE (via system_element_info()),
@@ -1962,12 +1961,12 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) {
// form_state_values_clean(). Enforce the same input processing restrictions
// as above.
if ($process_input) {
- // Detect if the element triggered the submission via AJAX.
+ // Detect if the element triggered the submission via Ajax.
if (_form_element_triggered_scripted_submission($element, $form_state)) {
$form_state['triggering_element'] = $element;
}
- // If the form was submitted by the browser rather than via AJAX, then it
+ // If the form was submitted by the browser rather than via Ajax, then it
// can only have been triggered by a button, and we need to determine which
// button within the constraints of how browsers provide this information.
if (isset($element['#button_type'])) {
@@ -1992,7 +1991,7 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) {
* Helper function to handle the convoluted logic of button click detection.
*
* This detects button or non-button controls that trigger a form submission via
- * AJAX or some other scriptable environment. These environments can set the
+ * Ajax or some other scriptable environment. These environments can set the
* special input key '_triggering_element_name' to identify the triggering
* element. If the name alone doesn't identify the element uniquely, the input
* key '_triggering_element_value' may also be set to require a match on element
@@ -2017,7 +2016,7 @@ function _form_element_triggered_scripted_submission($element, &$form_state) {
* of the POST data, but with extra code to deal with the convoluted way in
* which browsers submit data for image button clicks.
*
- * This does not detect button clicks processed by AJAX (that is done in
+ * This does not detect button clicks processed by Ajax (that is done in
* _form_element_triggered_scripted_submission()) and it does not detect form
* submissions from Internet Explorer in response to an ENTER key pressed in a
* textfield (form_builder() has extra code for that).
@@ -2062,7 +2061,7 @@ function _form_button_was_clicked($element, &$form_state) {
* - form_build_id
* - op
*
- * @param &$form_state
+ * @param $form_state
* A keyed array containing the current state of the form, including
* submitted form values; altered by reference.
*/
@@ -2492,7 +2491,7 @@ function form_process_select($element) {
if (($required && !isset($element['#default_value'])) || isset($element['#empty_value']) || isset($element['#empty_option'])) {
$element += array(
'#empty_value' => '',
- '#empty_option' => $required ? t('- Select - ') : t('- None -'),
+ '#empty_option' => $required ? t('- Select -') : t('- None -'),
);
// The empty option is prepended to #options and purposively not merged
// to prevent another option in #options mistakenly using the same value
@@ -3378,7 +3377,7 @@ function form_validate_machine_name(&$element, &$form_state) {
* Adds fieldsets to the specified group or adds group members to this
* fieldset.
*
- * @param &$element
+ * @param $element
* An associative array containing the properties and children of the
* fieldset. Note that $element must be taken by reference here, so processed
* child elements are taken over into $form_state.
@@ -3724,7 +3723,7 @@ function theme_textarea($variables) {
function theme_password($variables) {
$element = $variables['element'];
$element['#attributes']['type'] = 'password';
- element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength'));
+ element_set_attributes($element, array('id', 'name', 'size', 'maxlength'));
_form_set_class($element, array('form-text'));
return '<input' . drupal_attributes($element['#attributes']) . ' />';
@@ -3956,7 +3955,7 @@ function theme_form_element_label($variables) {
*
* Adds 'required' and 'error' classes as needed.
*
- * @param &$element
+ * @param $element
* The form element.
* @param $name
* Array of new class names to be added.
@@ -4016,7 +4015,9 @@ function _form_set_class(&$element, $class = array()) {
* Note: if the batch 'title', 'init_message', 'progress_message', or
* 'error_message' could contain any user input, it is the responsibility of
* the code calling batch_set() to sanitize them first with a function like
- * check_plain() or filter_xss().
+ * check_plain() or filter_xss(). Furthermore, if the batch operation
+ * returns any user input in the 'results' or 'message' keys of $context,
+ * it must also sanitize them first.
*
* Sample batch operations:
* @code
@@ -4039,8 +4040,8 @@ function _form_set_class(&$element, $class = array()) {
* // and the batch processing can continue to the next operation.
*
* $node = node_load(array('uid' => $uid, 'type' => $type));
- * $context['results'][] = $node->nid . ' : ' . $node->title;
- * $context['message'] = $node->title;
+ * $context['results'][] = $node->nid . ' : ' . check_plain($node->title);
+ * $context['message'] = check_plain($node->title);
* }
*
* // More advanced example: multi-step operation - load all nodes, five by five
@@ -4059,10 +4060,10 @@ function _form_set_class(&$element, $class = array()) {
* ->execute();
* foreach ($result as $row) {
* $node = node_load($row->nid, NULL, TRUE);
- * $context['results'][] = $node->nid . ' : ' . $node->title;
+ * $context['results'][] = $node->nid . ' : ' . check_plain($node->title);
* $context['sandbox']['progress']++;
* $context['sandbox']['current_node'] = $node->nid;
- * $context['message'] = $node->title;
+ * $context['message'] = check_plain($node->title);
* }
* if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
* $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
diff --git a/includes/graph.inc b/includes/graph.inc
index 38ed6fc3a..416fad6df 100644
--- a/includes/graph.inc
+++ b/includes/graph.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -33,7 +32,7 @@
* @endcode
*
* @return
- * The passed in $graph with more secondary keys filled in:
+ * The passed-in $graph with more secondary keys filled in:
* - 'paths': Contains a list of vertices than can be reached on a path from
* this vertex.
* - 'reverse_paths': Contains a list of vertices that has a path from them
@@ -75,15 +74,15 @@ function drupal_depth_first_search(&$graph) {
/**
* Helper function to perform a depth first sort.
*
- * @param &$graph
+ * @param $graph
* A three dimensional associated graph array.
- * @param &$state
+ * @param $state
* An associative array. The key 'last_visit_order' stores a list of the
* vertices visited. The key components stores list of vertices belonging
* to the same the component.
* @param $start
* An arbitrary vertex where we started traversing the graph.
- * @param &$component
+ * @param $component
* The component of the last vertex.
*
* @see drupal_depth_first_search()
diff --git a/includes/image.inc b/includes/image.inc
index 28d63be77..b04943b5e 100644
--- a/includes/image.inc
+++ b/includes/image.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/install.core.inc b/includes/install.core.inc
index c7b4053d9..a74dfdf0f 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/install.inc b/includes/install.inc
index 68a67bcd6..d22f4f9cb 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* Indicates that a module has not been installed yet.
@@ -199,7 +198,7 @@ function drupal_install_profile_distribution_name() {
// At all other times, we load the profile via standard methods.
else {
$profile = drupal_get_profile();
- $info = install_profile_info($profile);
+ $info = system_get_info('module', $profile);
return $info['distribution_name'];
}
}
@@ -548,7 +547,7 @@ abstract class DatabaseTasks {
*
* @param $database
* An array of driver specific configuration options.
- *
+ *
* @return
* An array of driver configuration errors, keyed by form element name.
*/
@@ -783,44 +782,12 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents
}
foreach ($module_list as $module) {
- // First, retrieve all the module's menu paths from db.
- drupal_load('module', $module);
- $paths = module_invoke($module, 'menu');
-
// Uninstall the module.
module_load_install($module);
module_invoke($module, 'uninstall');
drupal_uninstall_schema($module);
watchdog('system', '%module module uninstalled.', array('%module' => $module), WATCHDOG_INFO);
-
- // Now remove the menu links for all paths declared by this module.
- if (!empty($paths)) {
- $paths = array_keys($paths);
- // Clean out the names of load functions.
- foreach ($paths as $index => $path) {
- $parts = explode('/', $path, MENU_MAX_PARTS);
- foreach ($parts as $k => $part) {
- if (preg_match('/^%[a-z_]*$/', $part)) {
- $parts[$k] = '%';
- }
- }
- $paths[$index] = implode('/', $parts);
- }
-
- $result = db_select('menu_links')
- ->fields('menu_links')
- ->condition('router_path', $paths, 'IN')
- ->condition('external', 0)
- ->orderBy('depth')
- ->execute();
- // Remove all such items. Starting from those with the greatest depth will
- // minimize the amount of re-parenting done by menu_link_delete().
- foreach ($result as $item) {
- _menu_delete_item($item, TRUE);
- }
- }
-
drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED);
}
@@ -1055,7 +1022,12 @@ function install_goto($path) {
* Used during the install process, when database, theme, and localization
* system is possibly not yet available.
*
+ * Use t() if your code will never run during the Drupal installation phase.
+ * Use st() if your code will only run during installation and never any other
+ * time. Use get_t() if your code could run in either circumstance.
+ *
* @see t()
+ * @see get_t()
* @ingroup sanitization
*/
function st($string, array $args = array(), array $options = array()) {
@@ -1199,6 +1171,10 @@ function drupal_check_module($module) {
* installed, to be shown throughout the installation process. Defaults to
* 'Drupal'.
*
+ * Note that this function does an expensive file system scan to get info file
+ * information for dependencies. If you only need information from the info
+ * file itself, use system_get_info().
+ *
* Example of .info file:
* @code
* name = Minimal
diff --git a/includes/iso.inc b/includes/iso.inc
index ed2bfdd79..dabbefdd5 100644
--- a/includes/iso.inc
+++ b/includes/iso.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/language.inc b/includes/language.inc
index 908f013fd..b7057f2a1 100644
--- a/includes/language.inc
+++ b/includes/language.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -85,6 +84,44 @@ function language_types_disable($types) {
}
/**
+ * Updates the language type configuration.
+ */
+function language_types_set() {
+ // Ensure that we are getting the defined language negotiation information. An
+ // invocation of module_enable() or module_disable() could outdate the cached
+ // information.
+ drupal_static_reset('language_types_info');
+ drupal_static_reset('language_negotiation_info');
+
+ // Determine which language types are configurable and which not by checking
+ // whether the 'fixed' key is defined. Non-configurable (fixed) language types
+ // have their language negotiation settings stored there.
+ $defined_providers = language_negotiation_info();
+ foreach (language_types_info() as $type => $info) {
+ if (isset($info['fixed'])) {
+ $language_types[$type] = FALSE;
+ $negotiation = array();
+ foreach ($info['fixed'] as $weight => $id) {
+ if (isset($defined_providers[$id])) {
+ $negotiation[$id] = $weight;
+ }
+ }
+ language_negotiation_set($type, $negotiation);
+ }
+ else {
+ $language_types[$type] = TRUE;
+ }
+ }
+
+ // Save language types.
+ variable_set('language_types', $language_types);
+
+ // Ensure that subsequent calls of language_types_configurable() return the
+ // updated language type information.
+ drupal_static_reset('language_types_configurable');
+}
+
+/**
* Check if a language provider is enabled.
*
* This has two possible behaviors:
@@ -174,6 +211,28 @@ function language_negotiation_get_switch_links($type, $path) {
return $links;
}
+/**
+ * Updates language configuration to remove any language provider that is no longer defined.
+ */
+function language_negotiation_purge() {
+ // Ensure that we are getting the defined language negotiation information. An
+ // invocation of module_enable() or module_disable() could outdate the cached
+ // information.
+ drupal_static_reset('language_negotiation_info');
+ drupal_static_reset('language_types_info');
+
+ $defined_providers = language_negotiation_info();
+ foreach (language_types_info() as $type => $type_info) {
+ $weight = 0;
+ $negotiation = array();
+ foreach (variable_get("language_negotiation_$type", array()) as $id => $provider) {
+ if (isset($defined_providers[$id])) {
+ $negotiation[$id] = $weight++;
+ }
+ }
+ language_negotiation_set($type, $negotiation);
+ }
+}
/**
* Save a list of language providers.
@@ -181,7 +240,8 @@ function language_negotiation_get_switch_links($type, $path) {
* @param $type
* The language negotiation type.
* @param $language_providers
- * An array of language provider ids.
+ * An array of language provider weights keyed by id.
+ * @see language_provider_weight()
*/
function language_negotiation_set($type, $language_providers) {
// Save only the necessary fields.
@@ -190,7 +250,7 @@ function language_negotiation_set($type, $language_providers) {
$negotiation = array();
$providers_weight = array();
$defined_providers = language_negotiation_info();
- $default_types = language_types_configurable();
+ $default_types = language_types_configurable(FALSE);
// Initialize the providers weight list.
foreach ($language_providers as $id => $provider) {
diff --git a/includes/locale.inc b/includes/locale.inc
index d6db7c17c..578b1b3c6 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -586,159 +585,250 @@ function _locale_import_po($file, $langcode, $mode, $group = NULL) {
*/
function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group = 'default') {
- $fd = fopen($file->uri, "rb"); // File will get closed by PHP on return
+ // The file will get closed by PHP on returning from this function.
+ $fd = fopen($file->uri, 'rb');
if (!$fd) {
_locale_import_message('The translation import failed, because the file %filename could not be read.', $file);
return FALSE;
}
- $context = "COMMENT"; // Parser context: COMMENT, MSGID, MSGID_PLURAL, MSGSTR and MSGSTR_ARR
- $current = array(); // Current entry being read
- $plural = 0; // Current plural form
- $lineno = 0; // Current line
+ /*
+ * The parser context. Can be:
+ * - 'COMMENT' (#)
+ * - 'MSGID' (msgid)
+ * - 'MSGID_PLURAL' (msgid_plural)
+ * - 'MSGCTXT' (msgctxt)
+ * - 'MSGSTR' (msgstr or msgstr[])
+ * - 'MSGSTR_ARR' (msgstr_arg)
+ */
+ $context = 'COMMENT';
+
+ // Current entry being read.
+ $current = array();
+
+ // Current plurality for 'msgstr[]'.
+ $plural = 0;
+
+ // Current line.
+ $lineno = 0;
while (!feof($fd)) {
- $line = fgets($fd, 10*1024); // A line should not be this long
+ // A line should not be longer than 10 * 1024.
+ $line = fgets($fd, 10 * 1024);
+
if ($lineno == 0) {
// The first line might come with a UTF-8 BOM, which should be removed.
$line = str_replace("\xEF\xBB\xBF", '', $line);
}
+
$lineno++;
+
+ // Trim away the linefeed.
$line = trim(strtr($line, array("\\\n" => "")));
- if (!strncmp("#", $line, 1)) { // A comment
- if ($context == "COMMENT") { // Already in comment context: add
- $current["#"][] = substr($line, 1);
+ if (!strncmp('#', $line, 1)) {
+ // Lines starting with '#' are comments.
+
+ if ($context == 'COMMENT') {
+ // Already in comment token, insert the comment.
+ $current['#'][] = substr($line, 1);
}
- elseif (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one
+ elseif (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
+ // We are currently in string token, close it out.
_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
- $current = array();
- $current["#"][] = substr($line, 1);
- $context = "COMMENT";
+
+ // Start a new entry for the comment.
+ $current = array();
+ $current['#'][] = substr($line, 1);
+
+ $context = 'COMMENT';
}
- else { // Parse error
+ else {
+ // A comment following any other token is a syntax error.
_locale_import_message('The translation file %filename contains an error: "msgstr" was expected but not found on line %line.', $file, $lineno);
return FALSE;
}
}
- elseif (!strncmp("msgid_plural", $line, 12)) {
- if ($context != "MSGID") { // Must be plural form for current entry
+ elseif (!strncmp('msgid_plural', $line, 12)) {
+ // A plural form for the current message.
+
+ if ($context != 'MSGID') {
+ // A plural form cannot be added to anything else but the id directly.
_locale_import_message('The translation file %filename contains an error: "msgid_plural" was expected but not found on line %line.', $file, $lineno);
return FALSE;
}
+
+ // Remove 'msgid_plural' and trim away whitespace.
$line = trim(substr($line, 12));
+ // At this point, $line should now contain only the plural form.
+
$quoted = _locale_import_parse_quoted($line);
if ($quoted === FALSE) {
+ // The plural form must be wrapped in quotes.
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- $current["msgid"] = $current["msgid"] . "\0" . $quoted;
- $context = "MSGID_PLURAL";
+
+ // Append the plural form to the current entry.
+ $current['msgid'] .= "\0" . $quoted;
+
+ $context = 'MSGID_PLURAL';
}
- elseif (!strncmp("msgid", $line, 5)) {
- if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one
+ elseif (!strncmp('msgid', $line, 5)) {
+ // Starting a new message.
+
+ if (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
+ // We are currently in a message string, close it out.
_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
+
+ // Start a new context for the id.
$current = array();
}
- elseif ($context == "MSGID") { // Already in this context? Parse error
+ elseif ($context == 'MSGID') {
+ // We are currently already in the context, meaning we passed an id with no data.
_locale_import_message('The translation file %filename contains an error: "msgid" is unexpected on line %line.', $file, $lineno);
return FALSE;
}
+
+ // Remove 'msgid' and trim away whitespace.
$line = trim(substr($line, 5));
+ // At this point, $line should now contain only the message id.
+
$quoted = _locale_import_parse_quoted($line);
if ($quoted === FALSE) {
+ // The message id must be wrapped in quotes.
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- $current["msgid"] = $quoted;
- $context = "MSGID";
+
+ $current['msgid'] = $quoted;
+ $context = 'MSGID';
}
- elseif (!strncmp("msgctxt", $line, 7)) {
- if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one
+ elseif (!strncmp('msgctxt', $line, 7)) {
+ // Starting a new context.
+
+ if (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
+ // We are currently in a message, start a new one.
_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
$current = array();
}
- elseif (!empty($current["msgctxt"])) { // Already in this context? Parse error
+ elseif (!empty($current['msgctxt'])) {
+ // A context cannot apply to another context.
_locale_import_message('The translation file %filename contains an error: "msgctxt" is unexpected on line %line.', $file, $lineno);
return FALSE;
}
+
+ // Remove 'msgctxt' and trim away whitespaces.
$line = trim(substr($line, 7));
+ // At this point, $line should now contain the context.
+
$quoted = _locale_import_parse_quoted($line);
if ($quoted === FALSE) {
+ // The context string must be quoted.
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- $current["msgctxt"] = $quoted;
- $context = "MSGCTXT";
+
+ $current['msgctxt'] = $quoted;
+
+ $context = 'MSGCTXT';
}
- elseif (!strncmp("msgstr[", $line, 7)) {
- if (($context != "MSGID") && ($context != "MSGCTXT") && ($context != "MSGID_PLURAL") && ($context != "MSGSTR_ARR")) { // Must come after msgid, msgxtxt, msgid_plural, or msgstr[]
+ elseif (!strncmp('msgstr[', $line, 7)) {
+ // A message string for a specific plurality.
+
+ if (($context != 'MSGID') && ($context != 'MSGCTXT') && ($context != 'MSGID_PLURAL') && ($context != 'MSGSTR_ARR')) {
+ // Message strings must come after msgid, msgxtxt, msgid_plural, or other msgstr[] entries.
_locale_import_message('The translation file %filename contains an error: "msgstr[]" is unexpected on line %line.', $file, $lineno);
return FALSE;
}
- if (strpos($line, "]") === FALSE) {
+
+ // Ensure the plurality is terminated.
+ if (strpos($line, ']') === FALSE) {
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- $frombracket = strstr($line, "[");
- $plural = substr($frombracket, 1, strpos($frombracket, "]") - 1);
+
+ // Extract the plurality.
+ $frombracket = strstr($line, '[');
+ $plural = substr($frombracket, 1, strpos($frombracket, ']') - 1);
+
+ // Skip to the next whitespace and trim away any further whitespace, bringing $line to the message data.
$line = trim(strstr($line, " "));
+
$quoted = _locale_import_parse_quoted($line);
if ($quoted === FALSE) {
+ // The string must be quoted.
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- $current["msgstr"][$plural] = $quoted;
- $context = "MSGSTR_ARR";
+
+ $current['msgstr'][$plural] = $quoted;
+
+ $context = 'MSGSTR_ARR';
}
elseif (!strncmp("msgstr", $line, 6)) {
- if (($context != "MSGID") && ($context != "MSGCTXT")) { // Should come just after a msgid or msgctxt block
+ // A string for the an id or context.
+
+ if (($context != 'MSGID') && ($context != 'MSGCTXT')) {
+ // Strings are only valid within an id or context scope.
_locale_import_message('The translation file %filename contains an error: "msgstr" is unexpected on line %line.', $file, $lineno);
return FALSE;
}
+
+ // Remove 'msgstr' and trim away away whitespaces.
$line = trim(substr($line, 6));
+ // At this point, $line should now contain the message.
+
$quoted = _locale_import_parse_quoted($line);
if ($quoted === FALSE) {
+ // The string must be quoted.
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- $current["msgstr"] = $quoted;
- $context = "MSGSTR";
+
+ $current['msgstr'] = $quoted;
+
+ $context = 'MSGSTR';
}
- elseif ($line != "") {
+ elseif ($line != '') {
+ // Anything that is not a token may be a continuation of a previous token.
+
$quoted = _locale_import_parse_quoted($line);
if ($quoted === FALSE) {
+ // The string must be quoted.
_locale_import_message('The translation file %filename contains a syntax error on line %line.', $file, $lineno);
return FALSE;
}
- if (($context == "MSGID") || ($context == "MSGID_PLURAL")) {
- $current["msgid"] .= $quoted;
+
+ // Append the string to the current context.
+ if (($context == 'MSGID') || ($context == 'MSGID_PLURAL')) {
+ $current['msgid'] .= $quoted;
}
- elseif ($context == "MSGCTXT") {
- $current["msgctxt"] .= $quoted;
+ elseif ($context == 'MSGCTXT') {
+ $current['msgctxt'] .= $quoted;
}
- elseif ($context == "MSGSTR") {
- $current["msgstr"] .= $quoted;
+ elseif ($context == 'MSGSTR') {
+ $current['msgstr'] .= $quoted;
}
- elseif ($context == "MSGSTR_ARR") {
- $current["msgstr"][$plural] .= $quoted;
+ elseif ($context == 'MSGSTR_ARR') {
+ $current['msgstr'][$plural] .= $quoted;
}
else {
+ // No valid context to append to.
_locale_import_message('The translation file %filename contains an error: there is an unexpected string on line %line.', $file, $lineno);
return FALSE;
}
}
}
- // End of PO file, flush last entry.
- if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) {
+ // End of PO file, closed out the last entry.
+ if (($context == 'MSGSTR') || ($context == 'MSGSTR_ARR')) {
_locale_import_one_string($op, $current, $mode, $lang, $file, $group);
}
- elseif ($context != "COMMENT") {
+ elseif ($context != 'COMMENT') {
_locale_import_message('The translation file %filename ended unexpectedly at line %line.', $file, $lineno);
return FALSE;
}
-
}
/**
diff --git a/includes/lock.inc b/includes/lock.inc
index 6dd4b9352..42f1906f2 100644
--- a/includes/lock.inc
+++ b/includes/lock.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -188,7 +187,7 @@ function lock_may_be_available($name) {
* lock. This will block further execution until the lock is available or the
* specified delay in seconds is reached. This should not be used with locks
* that are acquired very frequently, since the lock is likely to be acquired
- * again by a different request during the sleep().
+ * again by a different request while waiting.
*
* @param $name
* The name of the lock.
@@ -199,12 +198,32 @@ function lock_may_be_available($name) {
* TRUE if the lock holds, FALSE if it is available.
*/
function lock_wait($name, $delay = 30) {
- $delay = (int) $delay;
- while ($delay--) {
+ // Pause the process for short periods between calling
+ // lock_may_be_available(). This prevents hitting the database with constant
+ // database queries while waiting, which could lead to performance issues.
+ // However, if the wait period is too long, there is the potential for a
+ // large number of processes to be blocked waiting for a lock, especially
+ // if the item being rebuilt is commonly requested. To address both of these
+ // concerns, begin waiting for 25ms, then add 25ms to the wait period each
+ // time until it reaches 500ms. After this point polling will continue every
+ // 500ms until $delay is reached.
+
+ // $delay is passed in seconds, but we will be using usleep(), which takes
+ // microseconds as a parameter. Multiply it by 1 million so that all
+ // further numbers are equivalent.
+ $delay = (int) $delay * 1000000;
+
+ // Begin sleeping at 25ms.
+ $sleep = 25000;
+ while ($delay > 0) {
// This function should only be called by a request that failed to get a
// lock, so we sleep first to give the parallel request a chance to finish
// and release the lock.
- sleep(1);
+ usleep($sleep);
+ // After each sleep, increase the value of $sleep until it reaches
+ // 500ms, to reduce the potential for a lock stampede.
+ $delay = $delay - $sleep;
+ $sleep = min(500000, $sleep + 25000, $delay);
if (lock_may_be_available($name)) {
// No longer need to wait.
return FALSE;
diff --git a/includes/mail.inc b/includes/mail.inc
index 2628175ed..d2febed39 100644
--- a/includes/mail.inc
+++ b/includes/mail.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -123,8 +122,8 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N
if ($default_from) {
// To prevent e-mail from looking like spam, the addresses in the Sender and
// Return-Path headers should have a domain authorized to use the originating
- // SMTP server. Errors-To is redundant, but shouldn't hurt.
- $headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $headers['Errors-To'] = $default_from;
+ // SMTP server.
+ $headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $default_from;
}
if ($from) {
$headers['From'] = $from;
diff --git a/includes/menu.inc b/includes/menu.inc
index 0806a31cf..cfd35c794 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -14,7 +13,10 @@
* The Drupal menu system drives both the navigation system from a user
* perspective and the callback system that Drupal uses to respond to URLs
* passed from the browser. For this reason, a good understanding of the
- * menu system is fundamental to the creation of complex modules.
+ * menu system is fundamental to the creation of complex modules. As a note,
+ * this is related to, but separate from menu.module, which allows menus
+ * (which in this context are hierarchical lists of links) to be customized from
+ * the Drupal administrative interface.
*
* Drupal's menu system follows a simple hierarchy defined by paths.
* Implementations of hook_menu() define menu items and assign them to
@@ -125,7 +127,7 @@ define('MENU_IS_LOCAL_ACTION', 0x0100);
/**
* @defgroup menu_item_types Menu item types
* @{
- * Definitions for various menu types.
+ * Definitions for various menu item types.
*
* Menu item definitions provide one of these constants, which are shortcuts for
* combinations of @link menu_flags Menu flags @endlink.
@@ -1042,7 +1044,7 @@ function menu_tree_output($tree) {
}
// Allow menu-specific theme overrides.
- $element['#theme'] = 'menu_link__' . $data['link']['menu_name'];
+ $element['#theme'] = 'menu_link__' . strtr($data['link']['menu_name'], '-', '_');
$element['#attributes']['class'] = $class;
$element['#title'] = $data['link']['title'];
$element['#href'] = $data['link']['href'];
@@ -2064,7 +2066,7 @@ function menu_local_tasks($level = 0) {
* node or array('system', 'navigation') for a certain block.
*
* @return
- * A list of menu router items that are local tasks for the passed in path.
+ * A list of menu router items that are local tasks for the passed-in path.
*
* @see contextual_links_preprocess()
*/
@@ -2319,11 +2321,11 @@ function menu_set_active_trail($new_trail = NULL) {
}
list($key, $curr) = each($tree);
}
- // Make sure the current page is in the trail (needed for the page title),
- // if the link's type allows it to be shown in the breadcrumb. Also exclude
- // it if we are on the front page.
+ // Make sure the current page is in the trail to build the page title, by
+ // appending either the preferred link or the menu router item for the
+ // current page. Exclude it if we are on the front page.
$last = end($trail);
- if ($last['href'] != $preferred_link['href'] && ($preferred_link['type'] & MENU_VISIBLE_IN_BREADCRUMB) == MENU_VISIBLE_IN_BREADCRUMB && !drupal_is_front_page()) {
+ if ($last['href'] != $preferred_link['href'] && !drupal_is_front_page()) {
$trail[] = $preferred_link;
}
}
@@ -2891,11 +2893,12 @@ function _menu_delete_item($item, $force = FALSE) {
menu_link_save($child);
}
}
- db_delete('menu_links')->condition('mlid', $item['mlid'])->execute();
- // Notify modules we have deleted the item.
+ // Notify modules we are deleting the item.
module_invoke_all('menu_link_delete', $item);
+ db_delete('menu_links')->condition('mlid', $item['mlid'])->execute();
+
// Update the has_children status of the parent.
_menu_update_parental_status($item);
menu_cache_clear($item['menu_name']);
@@ -2904,18 +2907,26 @@ function _menu_delete_item($item, $force = FALSE) {
}
/**
- * Save a menu link.
+ * Saves a menu link.
+ *
+ * After calling this function, rebuild the menu cache using
+ * menu_cache_clear_all().
*
* @param $item
- * An array representing a menu link item. The only mandatory keys are
- * link_path and link_title. Possible keys are:
- * - menu_name: Default is navigation
- * - weight: Default is 0
- * - expanded: Whether the item is expanded.
- * - options: An array of options, see l() for more.
- * - mlid: Set to an existing value, or 0 or NULL to insert a new link.
- * - plid: The mlid of the parent.
- * - router_path: The path of the relevant router item.
+ * An associative array representing a menu link item, with elements:
+ * - link_path: (required) The path of the menu item, which should be
+ * normalized first by calling drupal_get_normal_path() on it.
+ * - link_title: (required) Title to appear in menu for the link.
+ * - menu_name: (optional) The machine name of the menu for the link.
+ * Defaults to 'navigation'.
+ * - weight: (optional) Integer to determine position in menu. Default is 0.
+ * - expanded: (optional) Boolean that determines if the item is expanded.
+ * - options: (optional) An array of options, see l() for more.
+ * - mlid: (optional) Menu link identifier, the primary integer key for each
+ * menu link. Can be set to an existing value, or to 0 or NULL
+ * to insert a new link.
+ * - plid: (optional) The mlid of the parent.
+ * - router_path: (optional) The path of the relevant router item.
*
* @return
* The mlid of the saved menu link, or FALSE if the menu link could not be
diff --git a/includes/module.inc b/includes/module.inc
index aa061e195..779b66826 100644
--- a/includes/module.inc
+++ b/includes/module.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -127,6 +126,9 @@ function system_list($type) {
// if not fetch only the required information to fire bootstrap hooks
// in case we are going to serve the page from cache.
if ($type == 'bootstrap') {
+ if (isset($lists['bootstrap'])) {
+ return $lists['bootstrap'];
+ }
if ($cached = cache_get('bootstrap_modules', 'cache_bootstrap')) {
$bootstrap_list = $cached->data;
}
@@ -372,7 +374,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
// Add dependencies to the list, with a placeholder weight.
// The new modules will be processed as the while loop continues.
- foreach ($module_data[$module]->info['dependencies'] as $dependency) {
+ foreach (array_keys($module_data[$module]->requires) as $dependency) {
if (!isset($module_list[$dependency])) {
$module_list[$dependency] = 0;
}
@@ -854,7 +856,7 @@ function drupal_required_modules() {
/**
* Hands off alterable variables to type-specific *_alter implementations.
*
- * This dispatch function hands off the passed in variables to type-specific
+ * This dispatch function hands off the passed-in variables to type-specific
* hook_TYPE_alter() implementations in modules. It ensures a consistent
* interface for all altering operations.
*
@@ -888,14 +890,14 @@ function drupal_required_modules() {
* values in $type. For example, when Form API is using drupal_alter() to
* execute both hook_form_alter() and hook_form_FORM_ID_alter()
* implementations, it passes array('form', 'form_' . $form_id) for $type.
- * @param &$data
+ * @param $data
* The variable that will be passed to hook_TYPE_alter() implementations to be
* altered. The type of this variable depends on the value of the $type
* argument. For example, when altering a 'form', $data will be a structured
* array. When altering a 'profile', $data will be an object.
- * @param &$context1
+ * @param $context1
* (optional) An additional variable that is passed by reference.
- * @param &$context2
+ * @param $context2
* (optional) An additional variable that is passed by reference. If more
* context needs to be provided to implementations, then this should be an
* associative array as described above.
diff --git a/includes/pager.inc b/includes/pager.inc
index 553e279c3..146033f1b 100644
--- a/includes/pager.inc
+++ b/includes/pager.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -431,7 +430,7 @@ function theme_pager($variables) {
/**
* @defgroup pagerpieces Pager pieces
* @{
- * Use these pieces to construct your own custom pagers in your theme.
+ * Theme functions for customizing pager elements.
*
* Note that you should NOT modify this file to customize your pager.
*/
diff --git a/includes/password.inc b/includes/password.inc
index 1c6672af1..93d34f81f 100644
--- a/includes/password.inc
+++ b/includes/password.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/path.inc b/includes/path.inc
index 83ebcb0c9..db605370c 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/registry.inc b/includes/registry.inc
index 99fbfef63..3fb14fb31 100644
--- a/includes/registry.inc
+++ b/includes/registry.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -98,7 +97,8 @@ function _registry_update() {
_registry_check_code(REGISTRY_RESET_LOOKUP_CACHE);
}
catch (Exception $e) {
- $transaction->rollback('registry', $e->getMessage(), array(), WATCHDOG_ERROR);
+ $transaction->rollback();
+ watchdog_exception('registry', $e);
throw $e;
}
diff --git a/includes/session.inc b/includes/session.inc
index 23af6bd64..2ede2ff89 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc
index 1f837783d..7df1f9dc6 100644
--- a/includes/stream_wrappers.inc
+++ b/includes/stream_wrappers.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -384,7 +383,7 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
* The file mode ("r", "wb" etc.).
* @param $options
* A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
- * @param &$opened_path
+ * @param $opened_path
* A string containing the path actually opened.
*
* @return
diff --git a/includes/tablesort.inc b/includes/tablesort.inc
index b2b122f90..121a1b909 100644
--- a/includes/tablesort.inc
+++ b/includes/tablesort.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -74,18 +73,7 @@ class TableSort extends SelectQueryExtender {
* The current sort direction ("asc" or "desc").
*/
protected function getSort() {
- if (isset($_GET['sort'])) {
- return ($_GET['sort'] == 'desc') ? 'desc' : 'asc';
- }
- // User has not specified a sort. Use default if specified; otherwise use "asc".
- else {
- foreach ($this->header as $header) {
- if (is_array($header) && isset($header['sort'])) {
- return $header['sort'];
- }
- }
- }
- return 'asc';
+ return tablesort_get_sort($this->header);
}
/**
@@ -112,32 +100,7 @@ class TableSort extends SelectQueryExtender {
* - "sql": The name of the database field to sort on.
*/
protected function order() {
- $order = isset($_GET['order']) ? $_GET['order'] : '';
- foreach ($this->header as $header) {
- if (isset($header['data']) && $order == $header['data']) {
- return array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : '');
- }
-
- if (isset($header['sort']) && ($header['sort'] == 'asc' || $header['sort'] == 'desc')) {
- $default = array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : '');
- }
- }
-
- if (isset($default)) {
- return $default;
- }
- else {
- // The first column specified is initial 'order by' field unless otherwise specified
- $headers = array_values($this->header);
- $header = $headers[0];
- if (is_array($header)) {
- $header += array('data' => NULL, 'field' => NULL);
- return array('name' => $header['data'], 'sql' => $header['field']);
- }
- else {
- return array('name' => $header);
- }
- }
+ return tablesort_get_order($this->header);
}
}
@@ -239,29 +202,27 @@ function tablesort_get_query_parameters() {
function tablesort_get_order($headers) {
$order = isset($_GET['order']) ? $_GET['order'] : '';
foreach ($headers as $header) {
- if (isset($header['data']) && $order == $header['data']) {
- return array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : '');
- }
+ if (is_array($header)) {
+ if (isset($header['data']) && $order == $header['data']) {
+ $default = $header;
+ break;
+ }
- if (isset($header['sort']) && ($header['sort'] == 'asc' || $header['sort'] == 'desc')) {
- $default = array('name' => $header['data'], 'sql' => isset($header['field']) ? $header['field'] : '');
+ if (empty($default) && isset($header['sort']) && ($header['sort'] == 'asc' || $header['sort'] == 'desc')) {
+ $default = $header;
+ }
}
}
- if (isset($default)) {
- return $default;
- }
- else {
- // The first column specified is the initial 'order by' field unless otherwise specified.
- $first = current($headers);
- if (is_array($first)) {
- $first += array('data' => NULL, 'field' => NULL);
- return array('name' => $first['data'], 'sql' => $first['field']);
- }
- else {
- return array('name' => $first, 'sql' => '');
+ if (!isset($default)) {
+ $default = reset($headers);
+ if (!is_array($default)) {
+ $default = array('data' => $default);
}
}
+
+ $default += array('data' => NULL, 'field' => NULL);
+ return array('name' => $default['data'], 'sql' => $default['field']);
}
/**
@@ -274,12 +235,15 @@ function tablesort_get_order($headers) {
*/
function tablesort_get_sort($headers) {
if (isset($_GET['sort'])) {
- return ($_GET['sort'] == 'desc') ? 'desc' : 'asc';
+ return (strtolower($_GET['sort']) == 'desc') ? 'desc' : 'asc';
}
- // User has not specified a sort. Use default if specified; otherwise use "asc".
+ // The user has not specified a sort. Use the default for the currently sorted
+ // header if specified; otherwise use "asc".
else {
+ // Find out which header is currently being sorted.
+ $ts = tablesort_get_order($headers);
foreach ($headers as $header) {
- if (isset($header['sort'])) {
+ if (is_array($header) && isset($header['data']) && $header['data'] == $ts['name'] && isset($header['sort'])) {
return $header['sort'];
}
}
diff --git a/includes/theme.inc b/includes/theme.inc
index c5015865d..3ae50006a 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -104,7 +103,7 @@ function drupal_theme_initialize() {
drupal_static_reset('drupal_alter');
// Provide the page with information about the theme that's used, so that a
- // later AJAX request can be rendered using the same theme.
+ // later Ajax request can be rendered using the same theme.
// @see ajax_base_page_theme()
$setting['ajaxPageState'] = array(
'theme' => $theme_key,
@@ -320,8 +319,8 @@ function drupal_theme_rebuild() {
* The theme registry that will eventually be cached; It is an associative
* array keyed by theme hooks, whose values are associative arrays describing
* the hook:
- * - 'type': The passed in $type.
- * - 'theme path': The passed in $path.
+ * - 'type': The passed-in $type.
+ * - 'theme path': The passed-in $path.
* - 'function': The name of the function generating output for this theme
* hook. Either defined explicitly in hook_theme() or, if neither 'function'
* nor 'template' is defined, then the default theme function name is used.
@@ -363,7 +362,6 @@ function drupal_theme_rebuild() {
*/
function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
$result = array();
- $function = $name . '_theme';
// Processor functions work in two distinct phases with the process
// functions always being executed after the preprocess functions.
@@ -372,24 +370,43 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
'process functions' => 'process',
);
+ $hook_defaults = array(
+ 'variables' => TRUE,
+ 'render element' => TRUE,
+ 'pattern' => TRUE,
+ 'base hook' => TRUE,
+ );
+
+ // Invoke the hook_theme() implementation, process what is returned, and
+ // merge it into $cache.
+ $function = $name . '_theme';
if (function_exists($function)) {
$result = $function($cache, $type, $theme, $path);
foreach ($result as $hook => $info) {
+ // When a theme or engine overrides a module's theme function
+ // $result[$hook] will only contain key/value pairs for information being
+ // overridden. Pull the rest of the information from what was defined by
+ // an earlier hook.
+
+ // Fill in the type and path of the module, theme, or engine that
+ // implements this theme function.
$result[$hook]['type'] = $type;
$result[$hook]['theme path'] = $path;
- // if function and file are left out, default to standard naming
+
+ // If function and file are omitted, default to standard naming
// conventions.
if (!isset($info['template']) && !isset($info['function'])) {
$result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name . '_') . $hook;
}
- // If a path is set in the info, use what was set. Otherwise use the
- // default path. This is mostly so system.module can declare theme
- // functions on behalf of core .include files.
- // All files are included to be safe. Conditionally included
- // files can prevent them from getting registered.
+
if (isset($cache[$hook]['includes'])) {
$result[$hook]['includes'] = $cache[$hook]['includes'];
}
+
+ // If the theme implementation defines a file, then also use the path
+ // that it defined. Otherwise use the default path. This allows
+ // system.module to declare theme functions on behalf of core .include
+ // files.
if (isset($info['file'])) {
$include_file = isset($info['path']) ? $info['path'] : $path;
$include_file .= '/' . $info['file'];
@@ -397,14 +414,10 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
$result[$hook]['includes'][] = $include_file;
}
- // If these keys are left unspecified within overridden entries returned
- // by hook_theme(), carry them forward from the prior entry. This is so
- // that themes don't need to specify this information, since the module
- // that registered the theme hook already has.
- foreach (array('variables', 'render element', 'pattern', 'base hook') as $key) {
- if (!isset($info[$key]) && isset($cache[$hook][$key])) {
- $result[$hook][$key] = $cache[$hook][$key];
- }
+ // If the default keys are not set, use the default values registered
+ // by the module.
+ if (isset($cache[$hook])) {
+ $result[$hook] += array_intersect_key($cache[$hook], $hook_defaults);
}
// The following apply only to theming hooks implemented as templates.
@@ -469,7 +482,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
}
// Merge the newly created theme hooks into the existing cache.
- $cache = array_merge($cache, $result);
+ $cache = $result + $cache;
}
// Let themes have variable processors even if they didn't register a template.
@@ -972,7 +985,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
// start with. The default is the name of the hook followed by '__'. An
// 'base hook' key is added to each entry made for a found suggestion,
// so that common functionality can be implemented for all suggestions of
- // the same base hook. To keep things simple, deep heirarchy of
+ // the same base hook. To keep things simple, deep hierarchy of
// suggestions is not supported: each suggestion's 'base hook' key
// refers to a base hook, not to another suggestion, and all suggestions
// are found using the base hook's pattern, not a pattern from an
@@ -982,7 +995,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
$matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']);
if ($matches) {
foreach ($matches as $match) {
- $new_hook = str_replace($prefix . '_', '', $match);
+ $new_hook = substr($match, strlen($prefix) + 1);
$arg_name = isset($info['variables']) ? 'variables' : 'render element';
$implementations[$new_hook] = array(
'function' => $match,
@@ -1256,15 +1269,8 @@ function theme_enable($theme_list) {
menu_rebuild();
drupal_theme_rebuild();
- // Notify locale module about new themes being enabled, so translations can
- // be imported. This might start a batch, and only return to the redirect
- // path after that.
- module_invoke('locale', 'system_update', $theme_list);
-
- // Invoke hook_themes_enabled after the themes have been enabled.
+ // Invoke hook_themes_enabled() after the themes have been enabled.
module_invoke_all('themes_enabled', $theme_list);
-
- return;
}
/**
@@ -1296,10 +1302,8 @@ function theme_disable($theme_list) {
menu_rebuild();
drupal_theme_rebuild();
- // Invoke hook_themes_enabled after the themes have been enabled.
+ // Invoke hook_themes_disabled after the themes have been disabled.
module_invoke_all('themes_disabled', $theme_list);
-
- return;
}
/**
@@ -1756,10 +1760,10 @@ function theme_table($variables) {
*/
function theme_tablesort_indicator($variables) {
if ($variables['style'] == "asc") {
- return theme('image', array('path' => 'misc/arrow-asc.png', 'alt' => t('sort ascending'), 'title' => t('sort ascending')));
+ return theme('image', array('path' => 'misc/arrow-asc.png', 'width' => 13, 'height' => 13, 'alt' => t('sort ascending'), 'title' => t('sort ascending')));
}
else {
- return theme('image', array('path' => 'misc/arrow-desc.png', 'alt' => t('sort descending'), 'title' => t('sort descending')));
+ return theme('image', array('path' => 'misc/arrow-desc.png', 'width' => 13, 'height' => 13, 'alt' => t('sort descending'), 'title' => t('sort descending')));
}
}
@@ -1872,7 +1876,7 @@ function theme_more_help_link($variables) {
*/
function theme_feed_icon($variables) {
$text = t('Subscribe to @feed-title', array('@feed-title' => $variables['title']));
- if ($image = theme('image', array('path' => 'misc/feed.png', 'alt' => $text))) {
+ if ($image = theme('image', array('path' => 'misc/feed.png', 'width' => 16, 'height' => 16, 'alt' => $text))) {
return l($image, $variables['url'], array('html' => TRUE, 'attributes' => array('class' => array('feed-icon'), 'title' => $text)));
}
}
@@ -2042,6 +2046,9 @@ function _theme_table_cell($cell, $header = FALSE) {
* Adds a default set of helper variables for variable processors and templates.
* This comes in before any other preprocess function which makes it possible to
* be used in default theme implementations (non-overridden theme functions).
+ *
+ * For more detailed information, see theme().
+ *
*/
function template_preprocess(&$variables, $hook) {
global $user;
@@ -2119,6 +2126,9 @@ function _template_preprocess_default_variables() {
/**
* A default process function used to alter variables as late as possible.
+ *
+ * For more detailed information, see theme().
+ *
*/
function template_process(&$variables, $hook) {
// Flatten out classes.
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index 4950d8278..218a8adaa 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/token.inc b/includes/token.inc
index 57c15ea4f..edc8a962f 100644
--- a/includes/token.inc
+++ b/includes/token.inc
@@ -1,24 +1,23 @@
<?php
-// $Id$
/**
* @file
* Drupal placeholder/token replacement system.
*
- * Provides a set of extensible API functions for replacing placeholders in text
- * with meaningful values.
+ * API functions for replacing placeholders in text with meaningful values.
*
- * For example: When configuring automated emails, an administrator enters standard
- * text for the email. Variables like the title of a node and the date the email
- * was sent can be entered as placeholders like [node:title] and [date:short].
- * When a Drupal module prepares to send the email, it can call the token_replace()
- * function, passing in the text. The token system will scan the text for placeholder
- * tokens, give other modules an opportunity to replace them with meaningful text,
- * then return the final product to the original module.
+ * For example: When configuring automated emails, an administrator enters
+ * standard text for the email. Variables like the title of a node and the date
+ * the email was sent can be entered as placeholders like [node:title] and
+ * [date:short]. When a Drupal module prepares to send the email, it can call
+ * the token_replace() function, passing in the text. The token system will
+ * scan the text for placeholder tokens, give other modules an opportunity to
+ * replace them with meaningful text, then return the final product to the
+ * original module.
*
* Tokens follow the form: [$type:$name], where $type is a general class of
* tokens like 'node', 'user', or 'comment' and $name is the name of a given
- * placeholder. For example, [node:title].
+ * placeholder. For example, [node:title] or [node:created:since].
*
* In addition to raw text containing placeholders, modules may pass in an array
* of objects to be used when performing the replacement. The objects should be
@@ -38,8 +37,8 @@
* Some tokens may be chained in the form of [$type:$pointer:$name], where $type
* is a normal token type, $pointer is a reference to another token type, and
* $name is the name of a given placeholder. For example, [node:author:mail]. In
- * that example, 'author' is a pointer to the 'user' account that created the node,
- * and 'mail' is a placeholder available for any 'user'.
+ * that example, 'author' is a pointer to the 'user' account that created the
+ * node, and 'mail' is a placeholder available for any 'user'.
*
* @see token_replace()
* @see hook_tokens()
@@ -47,7 +46,7 @@
*/
/**
- * Replace all tokens in a given string with appropriate values.
+ * Replaces all tokens in a given string with appropriate values.
*
* @param $text
* A string potentially containing replaceable tokens.
@@ -55,22 +54,25 @@
* (optional) An array of keyed objects. For simple replacement scenarios
* 'node', 'user', and others are common keys, with an accompanying node or
* user object being the value. Some token types, like 'site', do not require
- * any explicit information from $data and can be replaced even if it is empty.
+ * any explicit information from $data and can be replaced even if it is
+ * empty.
* @param $options
* (optional) A keyed array of settings and flags to control the token
* replacement process. Supported options are:
* - language: A language object to be used when generating locale-sensitive
* tokens.
* - callback: A callback function that will be used to post-process the array
- * of token replacements after they are generated. For example, a module using
- * tokens in a text-only email might provide a callback to strip HTML
+ * of token replacements after they are generated. For example, a module
+ * using tokens in a text-only email might provide a callback to strip HTML
* entities from token values before they are inserted into the final text.
* - clear: A boolean flag indicating that tokens should be removed from the
* final text if no replacement value can be generated.
* - sanitize: A boolean flag indicating that tokens should be sanitized for
- * display to a web browser. Defaults to TRUE. Developers who set this option
- * to FALSE assume responsibility for running filter_xss(), check_plain() or
- * other appropriate scrubbing functions before displaying data to users.
+ * display to a web browser. Defaults to TRUE. Developers who set this
+ * option to FALSE assume responsibility for running filter_xss(),
+ * check_plain() or other appropriate scrubbing functions before displaying
+ * data to users.
+ *
* @return
* Text with tokens replaced.
*/
@@ -96,17 +98,25 @@ function token_replace($text, array $data = array(), array $options = array()) {
}
/**
- * Build a list of all token-like patterns that appear in the text.
+ * Builds a list of all token-like patterns that appear in the text.
*
* @param $text
* The text to be scanned for possible tokens.
+ *
* @return
* An associative array of discovered tokens, grouped by type.
*/
function token_scan($text) {
- // Matches tokens with the following pattern: [$type:$token]
- // $type and $token may not contain white spaces.
- preg_match_all('/\[([^\s\]:]*):([^\s\]]*)\]/', $text, $matches);
+ // Matches tokens with the following pattern: [$type:$name]
+ // $type and $name may not contain [ ] or whitespace characters.
+ // $type may not contain : characters, but $name may.
+ preg_match_all('/
+ \[ # [ - pattern start
+ ([^\s\[\]:]*) # match $type not containing whitespace : [ or ]
+ : # : - separator
+ ([^\s\[\]]*) # match $name not containing whitespace [ or ]
+ \] # ] - pattern end
+ /x', $text, $matches);
$types = $matches[1];
$tokens = $matches[2];
@@ -123,7 +133,7 @@ function token_scan($text) {
}
/**
- * Generate replacement values for a list of tokens.
+ * Generates replacement values for a list of tokens.
*
* @param $type
* The type of token being replaced. 'node', 'user', and 'date' are common.
@@ -134,20 +144,22 @@ function token_scan($text) {
* (optional) An array of keyed objects. For simple replacement scenarios
* 'node', 'user', and others are common keys, with an accompanying node or
* user object being the value. Some token types, like 'site', do not require
- * any explicit information from $data and can be replaced even if it is empty.
+ * any explicit information from $data and can be replaced even if it is
+ * empty.
* @param $options
* (optional) A keyed array of settings and flags to control the token
* replacement process. Supported options are:
- * - 'language' A language object to be used when generating locale-sensitive
+ * - language: A language object to be used when generating locale-sensitive
* tokens.
- * - 'callback' A callback function that will be used to post-process the array
- * of token replacements after they are generated. Can be used when modules
- * require special formatting of token text, for example URL encoding or
- * truncation to a specific length.
- * - 'sanitize' A boolean flag indicating that tokens should be sanitized for
+ * - callback: A callback function that will be used to post-process the
+ * array of token replacements after they are generated. Can be used when
+ * modules require special formatting of token text, for example URL
+ * encoding or truncation to a specific length.
+ * - sanitize: A boolean flag indicating that tokens should be sanitized for
* display to a web browser. Developers who set this option to FALSE assume
* responsibility for running filter_xss(), check_plain() or other
* appropriate scrubbing functions before displaying data to users.
+ *
* @return
* An associative array of replacement values, keyed by the original 'raw'
* tokens that were found in the source text. For example:
@@ -173,7 +185,7 @@ function token_generate($type, array $tokens, array $data = array(), array $opti
}
/**
- * Given a list of tokens, return those that begin with a specific prefix.
+ * Given a list of tokens, returns those that begin with a specific prefix.
*
* Used to extract a group of 'chained' tokens (such as [node:author:name]) from
* the full list of tokens found in text. For example:
@@ -181,7 +193,7 @@ function token_generate($type, array $tokens, array $data = array(), array $opti
* $data = array(
* 'author:name' => '[node:author:name]',
* 'title' => '[node:title]',
- * 'created' => '[node:author:name]',
+ * 'created' => '[node:created]',
* );
* $results = token_find_with_prefix($data, 'author');
* $results == array('name' => '[node:author:name]');
@@ -194,6 +206,7 @@ function token_generate($type, array $tokens, array $data = array(), array $opti
* @param $delimiter
* An optional string containing the character that separates the prefix from
* the rest of the token. Defaults to ':'.
+ *
* @return
* An associative array of discovered tokens, with the prefix and delimiter
* stripped from the key.
@@ -230,6 +243,7 @@ function token_find_with_prefix(array $tokens, $prefix, $delimiter = ':') {
* 'type' => 'user',
* );
* @endcode
+ *
* @return
* An associative array of token information, grouped by token type.
*/
diff --git a/includes/unicode.entities.inc b/includes/unicode.entities.inc
index 1ef3d4799..3b1fbb691 100644
--- a/includes/unicode.entities.inc
+++ b/includes/unicode.entities.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/unicode.inc b/includes/unicode.inc
index 812a2f174..9dde2ca70 100644
--- a/includes/unicode.inc
+++ b/includes/unicode.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* Indicates an error during check for PHP unicode support.
@@ -170,7 +169,7 @@ function unicode_requirements() {
* This is also where unsupported encodings will be converted. Callers should
* take this into account: $data might have been changed after the call.
*
- * @param &$data
+ * @param $data
* The XML data which will be parsed later.
*
* @return
@@ -221,7 +220,7 @@ function drupal_xml_parser_create(&$data) {
* @param $data
* The data to be converted.
* @param $encoding
- * The encoding that the data is in
+ * The encoding that the data is in.
*
* @return
* Converted data or FALSE.
diff --git a/includes/update.inc b/includes/update.inc
index 0019df671..1eb7a1d9c 100644
--- a/includes/update.inc
+++ b/includes/update.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/updater.inc b/includes/updater.inc
index b49d5d21f..363c6ebff 100644
--- a/includes/updater.inc
+++ b/includes/updater.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/utility.inc b/includes/utility.inc
index 8bd78904f..254313f73 100644
--- a/includes/utility.inc
+++ b/includes/utility.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/xmlrpc.inc b/includes/xmlrpc.inc
index 40b0d9d03..92e5d14f0 100644
--- a/includes/xmlrpc.inc
+++ b/includes/xmlrpc.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc
index fd5a40733..70c7cdac3 100644
--- a/includes/xmlrpcs.inc
+++ b/includes/xmlrpcs.inc
@@ -1,5 +1,4 @@
<?php
-// $Id$
/**
* @file
@@ -337,7 +336,7 @@ function xmlrpc_server_get_capabilities() {
}
/**
- * Returns the method signature of a function.
+ * Returns one method signature for a function.
*
* This is the function mapped to the XML-RPC method system.methodSignature.
*
@@ -349,8 +348,8 @@ function xmlrpc_server_get_capabilities() {
* Name of method to return a method signature for.
*
* @return array
- * An array of types representing the method signature of the function that
- * $methodname maps to.
+ * An array of arrays of types, each of the arrays representing one method
+ * signature of the function that $methodname maps to.
*/
function xmlrpc_server_method_signature($methodname) {
$xmlrpc_server = xmlrpc_server_get();
@@ -365,7 +364,7 @@ function xmlrpc_server_method_signature($methodname) {
foreach ($xmlrpc_server->signatures[$methodname] as $type) {
$return[] = $type;
}
- return $return;
+ return array($return);
}
/**