From c2f92a3fb86e2b70e943fee5f1c17debc1b264d3 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Thu, 29 Mar 2012 15:48:14 -0700 Subject: [PATCH 01/29] Issue by mikeytown2: prevent variable_init from returning a blank array. --- includes/bootstrap.inc | 62 ++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index d857f651597..6db36634625 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -561,13 +561,21 @@ function drupal_get_filename($type, $name, $filename = NULL) { * file. */ function variable_init($conf = array(), $regenerate = FALSE, $recursion_depth = 0) { - // NOTE: caching the variables improves performance by 20% when serving cached pages. + // NOTE: caching the variables improves performance by 20% when serving + // cached pages. if (!$regenerate && $cached = cache_get('variables', 'cache')) { $variables = $cached->data; } else { if (defined('MAINTENANCE_MODE') || lock_acquire('variable_cache_regenerate')) { $result = db_query('SELECT * FROM {variable}'); + // Exit here if the database went away. Do not want to pollute the cache + // with bad data. This request isn't going to end well anyway; end it + // eairly. + if ($result === FALSE) { + // This function calls exit. + _db_error_page(); + } while ($variable = db_fetch_object($result)) { $variables[$variable->name] = unserialize($variable->value); } @@ -580,15 +588,27 @@ function variable_init($conf = array(), $regenerate = FALSE, $recursion_depth = // Wait for another request that is already doing this work. lock_wait('variable_cache_regenerate'); - // Run the function again. Try a limited number of times to avoid - // infinite recursion if the database connection is invalid for + // Run the function again. Try a limited number of times to avoid + // infinite recursion if the database connection is invalid for // some reason, e.g., mysqld restart, loss of network, etc. $recursion_depth++; if ($recursion_depth < 50) { return variable_init($conf, $regenerate, $recursion_depth); } - $variables = array(); + // If the recursion_depth hit the limit, assume we aren't going to get it + // from the cache or the lock will be released any time soon. Give up and + // get variables from the database. + $result = db_query('SELECT * FROM {variable}'); + // Exit here if the database went away. Do not want to pollute the cache + // with bad data. This request isn't going to end well. + if ($result === FALSE) { + // This function calls exit. + _db_error_page(); + } + while ($variable = db_fetch_object($result)) { + $variables[$variable->name] = unserialize($variable->value); + } } } @@ -653,7 +673,7 @@ function variable_set($name, $value) { if (is_string($db_prefix) && strpos($db_prefix, 'simpletest') === 0) { cache_clear_all('variables', 'cache'); } - + variable_cache_rebuild(); } @@ -682,7 +702,7 @@ function variable_del($name) { if (is_string($db_prefix) && strpos($db_prefix, 'simpletest') === 0) { cache_clear_all('variables', 'cache'); } - + variable_cache_rebuild(); } @@ -805,7 +825,7 @@ function drupal_set_header($name = NULL, $value = NULL, $append = FALSE) { if (!isset($name)) { return $headers; } - + // Support the Drupal 6 header API if (!isset($value)) { if (strpos($name, ':') !== FALSE) { @@ -1423,7 +1443,7 @@ function drupal_bootstrap($phase = NULL) { _drupal_bootstrap($current_phase); } } - + return $phase_index; } @@ -1483,7 +1503,7 @@ function _drupal_bootstrap($phase) { // those using APC or memcached. require_once variable_get('lock_inc', './includes/lock.inc'); lock_init(); - + // Detect if an installation is present. detect_installation_or_run_installer(); @@ -1534,11 +1554,11 @@ function _drupal_bootstrap($phase) { // We are done. exit; } - + if (!$cache && drupal_page_is_cacheable() && $cache_mode != CACHE_EXTERNAL) { header('X-Drupal-Cache: MISS'); } - + // If using an external cache and the page is cacheable, set headers. if ($cache_mode == CACHE_EXTERNAL && drupal_page_is_cacheable()) { drupal_page_cache_header_external(); @@ -1679,17 +1699,17 @@ function ip_address() { if (!isset($ip_address)) { $ip_address = $_SERVER['REMOTE_ADDR']; - + // Only use parts of the X-Forwarded-For (XFF) header that have followed a trusted route. // Specifically, identify the leftmost IP address in the XFF header that is not one of ours. // An XFF header is: X-Forwarded-For: client1, proxy1, proxy2 if (isset($_SERVER['HTTP_' . variable_get('x_forwarded_for_header', 'X_FORWARDED_FOR')]) && variable_get('reverse_proxy', 0)) { // Load trusted reverse proxy server IPs. $reverse_proxy_addresses = variable_get('reverse_proxy_addresses', array()); - + // Turn XFF header into an array. $forwarded = explode(',', $_SERVER['HTTP_' . variable_get('x_forwarded_for_header', 'X_FORWARDED_FOR')]); - + // Trim the forwarded IPs; they may have been delimited by commas and spaces. $forwarded = array_map('trim', $forwarded); @@ -1698,7 +1718,7 @@ function ip_address() { // Eliminate all trusted IPs. $untrusted = array_diff($forwarded, $reverse_proxy_addresses); - + // The right-most IP is the most specific we can trust. $ip_address = array_pop($untrusted); } @@ -1712,9 +1732,9 @@ function ip_address() { */ function drupal_session_initialize() { global $user; - + session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc'); - + if (isset($_COOKIE[session_name()])) { // If a session cookie exists, initialize the session. Otherwise the // session is only started on demand in drupal_session_commit(), making @@ -1776,7 +1796,7 @@ function drupal_session_commit() { /** * Return whether a session has been started. - */ + */ function drupal_session_started($set = NULL) { static $session_started = FALSE; if (isset($set)) { @@ -1841,7 +1861,7 @@ function drupal_save_session($status = NULL) { } return $save_session; } - + /** * Returns the current bootstrap phase for this Drupal process. * @@ -1886,7 +1906,7 @@ function drupal_generate_test_ua($prefix) { // check the HMAC before the database is initialized. filectime() // and fileinode() are not easily determined from remote. // $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $filepath = './includes/bootstrap.inc'; + $filepath = './includes/bootstrap.inc'; // $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE); $key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); } @@ -1914,7 +1934,7 @@ function drupal_is_cli() { */ function drupal_session_destroy() { session_destroy(); - + // Workaround PHP 5.2 fatal error "Failed to initialize storage module". // @see http://bugs.php.net/bug.php?id=32330 session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc'); From 855b22040cada75101f15cfac802f30717561f0b Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 14:47:18 -0400 Subject: [PATCH 02/29] Issue #939810 by mikeytown2: Notice: Undefined index: key in format_xml_elements() --- includes/common.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/common.inc b/includes/common.inc index 7ef1e51b1ba..5c0908ce06a 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1148,7 +1148,7 @@ function format_xml_elements($array) { $output = ''; foreach ($array as $key => $value) { if (is_numeric($key)) { - if ($value['key']) { + if (!empty($value['key'])) { $output .= ' <'. $value['key']; if (isset($value['attributes']) && is_array($value['attributes'])) { $output .= drupal_attributes($value['attributes']); From 0fb357773c547962de65b117d9abc247e422820c Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 14:52:44 -0400 Subject: [PATCH 03/29] Issue #557542 by mikeytown2, c960657, catch, & glennpratt: Cache module_implements() --- includes/common.inc | 3 ++ includes/module.inc | 72 ++++++++++++++++++++++++++++++++++++++++----- install.php | 36 ++++++++++------------- update.php | 4 ++- 4 files changed, 86 insertions(+), 29 deletions(-) diff --git a/includes/common.inc b/includes/common.inc index 5c0908ce06a..739ae17b456 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1668,6 +1668,9 @@ function drupal_page_footer() { } module_invoke_all('exit'); + + // Update the hook implementation cache. + module_implements('', FALSE, FALSE, TRUE); } /** diff --git a/includes/module.inc b/includes/module.inc index 79583675bd5..6fa7448e836 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -257,15 +257,15 @@ function module_load_install($module) { /** * Load a module include file. - * + * * Examples: * @code * // Load node.admin.inc from the node module. * module_load_include('inc', 'node', 'node.admin'); * // Load content_types.inc from the node module. - * module_load_include('inc', 'node', 'content_types'); + * module_load_include('inc', 'node', 'content_types'); * @endcode - * + * * Do not use this function to load an install file. Use module_load_install() * instead. * @@ -274,7 +274,7 @@ function module_load_install($module) { * @param $module * The module to which the include file belongs. * @param $name - * Optionally, specify the base file name (without the $type extension). + * Optionally, specify the base file name (without the $type extension). * If not set, $module is used. */ function module_load_include($type, $module, $name = NULL) { @@ -420,22 +420,64 @@ function module_hook($module, $hook) { * @param $sort * By default, modules are ordered by weight and filename, settings this option * to TRUE, module list will be ordered by module name. - * @param $refresh + * @param $reset * For internal use only: Whether to force the stored list of hook * implementations to be regenerated (such as after enabling a new module, * before processing hook_enable). + * @param $write_cache + * For internal use only: Update the persistent cache of hook implementations. * @return * An array with the names of the modules which are implementing this hook. */ -function module_implements($hook, $sort = FALSE, $refresh = FALSE) { +function module_implements($hook, $sort = FALSE, $reset = FALSE, $write_cache = FALSE) { static $implementations; - - if ($refresh) { + static $verified; + + // We maintain a persistent cache of hook implementations in addition to the + // static cache to avoid looping through every module and every hook on each + // request. Benchmarks show that the benefit of this caching outweighs the + // additional database hit even when using the default database caching + // backend and only a small number of modules are enabled. The cost of the + // cache_get() is more or less constant and reduced further when non-database + // caching backends are used, so there will be more significant gains when a + // large number of modules are installed or hooks invoked, since this can + // quickly lead to module_hook() being called several thousand times + // per request. + if ($reset) { $implementations = array(); + $verified = array(); + cache_set('module_implements', array()); return; } + if ($write_cache) { + // Check whether we should write the cache. We do not want to cache hooks + // which are only invoked on HTTP POST requests since these do not need to + // be optimized as tightly, and not doing so keeps the cache entry smaller. + if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) { + unset($implementations['#write_cache']); + cache_set('module_implements', $implementations); + } + return; + } + + // Fetch implementations from cache. + if (empty($implementations)) { + if (function_exists('cache_get')) { + $cache = cache_get('module_implements'); + } + if (empty($cache)) { + $implementations = array(); + } + else { + $implementations = $cache->data; + } + } + if (!isset($implementations[$hook])) { + // The hook is not cached, so ensure that whether or not it has + // implementations, that the cache is updated at the end of the request. + $implementations['#write_cache'] = TRUE; $implementations[$hook] = array(); $list = module_list(FALSE, TRUE, $sort); foreach ($list as $module) { @@ -444,6 +486,20 @@ function module_implements($hook, $sort = FALSE, $refresh = FALSE) { } } } + elseif (empty($verified[$hook])) { + foreach ($implementations[$hook] as $key => $module) { + // It is possible that a module removed a hook implementation without the + // implementations cache being rebuilt yet, so we check module_hook() on + // each request to avoid undefined function errors. + if (!module_hook($module, $hook)) { + // Clear out the stale implementation from the cache and force a cache + // refresh to forget about no longer existing hook implementations. + unset($implementations[$hook][$key]); + $implementations['#write_cache'] = TRUE; + } + } + $verified[$hook] = TRUE; + } // The explicit cast forces a copy to be made. This is needed because // $implementations[$hook] is only a reference to an element of diff --git a/install.php b/install.php index beb3fcb4f18..b02bb41febf 100644 --- a/install.php +++ b/install.php @@ -47,6 +47,18 @@ function install_main() { drupal_load('module', 'system'); drupal_load('module', 'filter'); + // Load the cache infrastructure using a "fake" cache implementation that + // does not attempt to write to the database. We need this during the initial + // part of the installer because the database is not available yet. We + // continue to use it even when the database does become available, in order + // to preserve consistency between interactive and command-line installations + // (the latter complete in one page request and therefore are forced to + // continue using the cache implementation they started with) and also + // because any data put in the cache during the installer is inherently + // suspect, due to the fact that Drupal is not fully set up yet. + require_once './includes/cache-install.inc'; + $conf['cache_inc'] = './includes/cache-install.inc'; + // Install profile chosen, set the global immediately. // This needs to be done before the theme cache gets // initialized in drupal_maintenance_theme(). @@ -61,12 +73,6 @@ function install_main() { $verify = install_verify_settings(); if ($verify) { - // Since we have a database connection, we use the normal cache system. - // This is important, as the installer calls into the Drupal system for - // the clean URL checks, so we should maintain the cache properly. - require_once './includes/cache.inc'; - $conf['cache_inc'] = './includes/cache.inc'; - // Establish a connection to the database. require_once './includes/database.inc'; db_set_active(); @@ -78,13 +84,6 @@ function install_main() { } } else { - // Since no persistent storage is available yet, and functions that check - // for cached data will fail, we temporarily replace the normal cache - // system with a stubbed-out version that short-circuits the actual - // caching process and avoids any errors. - require_once './includes/cache-install.inc'; - $conf['cache_inc'] = './includes/cache-install.inc'; - $task = NULL; } @@ -821,17 +820,14 @@ function install_tasks($profile, $task) { // The end of the install process. Remember profile used. if ($task == 'done') { - // Rebuild menu to get content type links registered by the profile, - // and possibly any other menu items created through the tasks. - menu_rebuild(); + // Flush all caches to ensure that any full bootstraps during the installer + // do not leave stale cached data, and that any content types or other items + // registered by the install profile are registered correctly. + drupal_flush_all_caches(); // Register actions declared by any modules. actions_synchronize(); - // Randomize query-strings on css/js files, to hide the fact that - // this is a new install, not upgraded yet. - _drupal_flush_css_js(); - variable_set('install_profile', $profile); } diff --git a/update.php b/update.php index e32547369da..44e06987717 100644 --- a/update.php +++ b/update.php @@ -597,7 +597,7 @@ function update_check_requirements() { $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; if (empty($op)) { // Minimum load of components. - drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); + drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE); require_once './includes/install.inc'; require_once './includes/file.inc'; @@ -608,6 +608,8 @@ function update_check_requirements() { $module_list['system']['filename'] = 'modules/system/system.module'; $module_list['filter']['filename'] = 'modules/filter/filter.module'; module_list(TRUE, FALSE, FALSE, $module_list); + module_implements('', FALSE, TRUE); + drupal_load('module', 'system'); drupal_load('module', 'filter'); From 707636f5139262de775d734a4f36825e81527f49 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 14:56:36 -0400 Subject: [PATCH 04/29] Issue #1317236 by mikeytown2: Race condition in file_delete: Warning: unlink() No such file or directory in file_delete() --- includes/file.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/file.inc b/includes/file.inc index 4a3e3fc16c5..c8058a0b108 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -520,7 +520,7 @@ function file_create_filename($basename, $directory) { */ function file_delete($path) { if (is_file($path)) { - return unlink($path); + return @unlink($path); } } From cdbd30096cf477180bbe1f8dc11fc640c6c9ce52 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 14:59:40 -0400 Subject: [PATCH 05/29] Issue #1004820 by mikeytown2: Notice: Undefined index: type in dblog_build_filter_query() --- modules/dblog/dblog.admin.inc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/dblog/dblog.admin.inc b/modules/dblog/dblog.admin.inc index 853a2ce14c8..3448bd00026 100644 --- a/modules/dblog/dblog.admin.inc +++ b/modules/dblog/dblog.admin.inc @@ -191,8 +191,10 @@ function dblog_build_filter_query() { foreach ($_SESSION['dblog_overview_filter'] as $key => $filter) { $filter_where = array(); foreach ($filter as $value) { - $filter_where[] = $filters[$key]['where']; - $args[] = $value; + if (isset($filters[$key]['where'])) { + $filter_where[] = $filters[$key]['where']; + $args[] = $value; + } } if (!empty($filter_where)) { $where[] = '('. implode(' OR ', $filter_where) .')'; From 71e7146d5d1aa2e66a3b2027247d1dee00b17d79 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 15:00:58 -0400 Subject: [PATCH 06/29] Issue #134204 by mikeytown2: Optimize element_children() --- includes/common.inc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/includes/common.inc b/includes/common.inc index 739ae17b456..a0550f6949a 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -3091,10 +3091,18 @@ function element_child($key) { } /** - * Get keys of a structured array tree element that are not properties (i.e., do not begin with '#'). + * Get keys of a structured array tree element that are not properties + * (i.e., do not begin with '#'). */ function element_children($element) { - return array_filter(array_keys((array) $element), 'element_child'); + $results = array(); + foreach ((array) $element as $key => $value) { + // Inlined call to element_child() for performance reasons. + if (!isset($key[0]) || $key[0] != '#') { + $results[] = $key; + } + } + return $results; } /** From e909d96e85aa029796f222adb3252c86eec93a96 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 15:02:36 -0400 Subject: [PATCH 07/29] Issue #753064 by mikeytown2: _menu_link_translate() might avoid calling _menu_load_objects() --- includes/menu.inc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/includes/menu.inc b/includes/menu.inc index 0d377d0d387..9b813d436aa 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -581,7 +581,7 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) { $router_item['href'] = implode('/', $link_map); $router_item['options'] = array(); _menu_check_access($router_item, $map); - + // For performance, don't localize an item the user can't access. if ($router_item['access']) { _menu_item_localize($router_item, $map); @@ -656,7 +656,11 @@ function _menu_link_translate(&$item) { } // menu_tree_check_access() may set this ahead of time for links to nodes. if (!isset($item['access'])) { - if (!_menu_load_objects($item, $map)) { + // Loading a views object is expensive so we have a special case for it. + if (isset($item['access_callback']) && $item['access_callback'] == 'views_access' && $item['access_arguments'] == 'a:1:{i:0;b:1;}' && $item['title_callback'] == 't' && empty($item['title_arguments'])) { + $item['access'] = TRUE; + } + elseif (!_menu_load_objects($item, $map)) { // An error occurred loading an object. $item['access'] = FALSE; return FALSE; @@ -1695,7 +1699,7 @@ function menu_cache_clear_all() { function menu_rebuild() { if (!lock_acquire('menu_rebuild')) { // Wait for another request that is already doing this work. - // We choose to block here since otherwise the router item may not + // We choose to block here since otherwise the router item may not // be avaiable in menu_execute_active_handler() resulting in a 404. lock_wait('menu_rebuild'); return FALSE; @@ -1709,7 +1713,7 @@ function menu_rebuild() { // Clear the menu, page and block caches. menu_cache_clear_all(); _menu_clear_page_cache(); - + if (defined('MAINTENANCE_MODE')) { variable_set('menu_rebuild_needed', TRUE); } @@ -1904,7 +1908,7 @@ function _menu_delete_item($item, $force = FALSE) { * - router_path: The path of the relevant router item. * * @return - * The mlid of the saved menu link, or FALSE if the menu link could not be + * The mlid of the saved menu link, or FALSE if the menu link could not be * saved. */ function menu_link_save(&$item) { From 471dea89de2175f6d5256751cf0b90cd389a797f Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 15:56:03 -0400 Subject: [PATCH 08/29] Issue #261148 by mikeytown2, catch, chx: menu_masks variable is empty (race condition) --- includes/menu.inc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/includes/menu.inc b/includes/menu.inc index 9b813d436aa..79d8843127a 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -206,7 +206,16 @@ function menu_get_ancestors($parts) { $ancestors = array(); $length = $number_parts - 1; $end = (1 << $number_parts) - 1; - $masks = variable_get('menu_masks', array()); + $masks = variable_get('menu_masks', NULL); + // If the optimized menu_masks array is not available, try every character + // position to see if that matches up with a wildcard, slash, or the original + // value in order to get the correct $ancestors and $placeholders returned. + // Do not use this as the default value of the menu_masks variable to avoid + // building such a big array. Currently the maximum value for $end is 511 + // (2^9) - 1. 9 comes from the MENU_MAX_PARTS constant. + if (!$masks) { + $masks = range($end, 1); + } // Only examine patterns that actually exist as router items (the masks). foreach ($masks as $i) { if ($i > $end) { From 9c92a1a5804418214696ec393f97ca09b452aa5e Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 15:58:25 -0400 Subject: [PATCH 09/29] Issue #1688282 by mikeytown2: Unknown error: Function split() is deprecated in _filter_autop() --- modules/filter/filter.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/filter/filter.module b/modules/filter/filter.module index b95517914ee..2ed560d26da 100644 --- a/modules/filter/filter.module +++ b/modules/filter/filter.module @@ -911,7 +911,7 @@ function _filter_autop($text) { else { // Opening or closing tag? $open = ($chunk[1] != '/'); - list($tag) = split('[ >]', substr($chunk, 2 - $open), 2); + list($tag) = preg_split('/[ >]/', substr($chunk, 2 - $open), 2); if (!$ignore) { if ($open) { $ignore = TRUE; From 9325a3749f632ee73656cf35cce589a3658d79e2 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:00:34 -0400 Subject: [PATCH 10/29] Issue #521838 by mikeytown2: Speedup/Clean up drupal_get_schema_versions() --- includes/install.inc | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/includes/install.inc b/includes/install.inc index e70f87ccbaa..80e83265d0b 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -34,25 +34,41 @@ function drupal_load_updates() { * @param $module * A module name. * @return - * If the module has updates, an array of available updates sorted by version. + * If the module has updates, an array of available updates sorted by version. * Otherwise, FALSE. */ function drupal_get_schema_versions($module) { - $updates = array(); - $functions = get_defined_functions(); - foreach ($functions['user'] as $function) { - if (strpos($function, $module .'_update_') === 0) { - $version = substr($function, strlen($module .'_update_')); - if (is_numeric($version)) { - $updates[] = $version; + static $updates; + if (!isset($updates[$module])) { + $updates = array(); + + foreach (module_list() as $loaded_module) { + $updates[$loaded_module] = array(); + } + + // Prepare regular expression to match all possible defined hook_update_N(). + $regexp = '/^(?P.+)_update_(?P\d+)$/'; + $functions = get_defined_functions(); + // Narrow this down to functions ending with an integer, since all + // hook_update_N() functions end this way, and there are other + // possible functions which match '_update_'. We use preg_grep() here + // instead of foreaching through all defined functions, since the loop + // through all PHP functions can take significant page execution time + // and this function is called on every administrative page via + // system_requirements(). + foreach (preg_grep('/_\d+$/', $functions['user']) as $function) { + // If this function is a module update function, add it to the list of + // module updates. + if (preg_match($regexp, $function, $matches)) { + $updates[$matches['module']][] = $matches['version']; } } + // Ensure that updates are applied in numerical order. + foreach ($updates as &$module_updates) { + sort($module_updates, SORT_NUMERIC); + } } - if (count($updates) == 0) { - return FALSE; - } - sort($updates, SORT_NUMERIC); - return $updates; + return empty($updates[$module]) ? FALSE : $updates[$module]; } /** From a506b7d662c810d2a9c89445453df7ca3b69c9ad Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:08:40 -0400 Subject: [PATCH 11/29] Issue #1710656 by mikeytown2: If item is hidden in _menu_tree_check_access() skip it right away. --- includes/menu.inc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/includes/menu.inc b/includes/menu.inc index 79d8843127a..a316048e41e 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -1038,6 +1038,11 @@ function _menu_tree_check_access(&$tree) { $new_tree = array(); foreach ($tree as $key => $v) { $item = &$tree[$key]['link']; + // Do not load hidden menu items if not in active breadcrumb trail and + // user can't administer the menu. + if (!empty($item['hidden']) && empty($item['in_active_trail']) && !user_access('administer menu')) { + continue; + } _menu_link_translate($item); if ($item['access']) { if ($tree[$key]['below']) { @@ -1730,9 +1735,9 @@ function menu_rebuild() { variable_del('menu_rebuild_needed'); } lock_release('menu_rebuild'); - + db_query('COMMIT'); - + return TRUE; } From 280a9300fe17478ce707d3ea854aa5fc41498e1d Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:33:55 -0400 Subject: [PATCH 12/29] Issue #352180 by scor: Better, multi-site friendly www. addition/removal in .htaccess --- .htaccess | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.htaccess b/.htaccess index 4733ffa4a86..718c3bf51d4 100644 --- a/.htaccess +++ b/.htaccess @@ -86,15 +86,15 @@ DirectoryIndex index.php # # To redirect all users to access the site WITH the 'www.' prefix, # (http://example.com/... will be redirected to http://www.example.com/...) - # adapt and uncomment the following: - # RewriteCond %{HTTP_HOST} ^example\.com$ [NC] - # RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301] + # uncomment the following: + # RewriteCond %{HTTP_HOST} !^www\. [NC] + # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # # To redirect all users to access the site WITHOUT the 'www.' prefix, # (http://www.example.com/... will be redirected to http://example.com/...) - # uncomment and adapt the following: - # RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC] - # RewriteRule ^(.*)$ http://example.com/$1 [L,R=301] + # uncomment the following: + # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] + # RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301] # Modify the RewriteBase if you are using Drupal in a subdirectory or in a # VirtualDocumentRoot and the rewrite rules are not working properly. From 1bfe877013bf18d6c2115c9669b840ec3ff5ec10 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:38:38 -0400 Subject: [PATCH 13/29] Issue #764726 by mikeytown2: hook_taxonomy_term_presave() is missing --- modules/taxonomy/taxonomy.module | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module index 38b74e19f35..ae0208ae884 100644 --- a/modules/taxonomy/taxonomy.module +++ b/modules/taxonomy/taxonomy.module @@ -200,6 +200,19 @@ function taxonomy_save_vocabulary(&$edit) { $edit['module'] = 'taxonomy'; } + $return = module_invoke_all('taxonomy_vocabulary_presave', $edit); + if (is_array($return) && !empty($return)) { + $update = TRUE; + foreach ($return as $key => $value) { + if (is_numeric($key) && $value == FALSE) { + $update = FALSE; + } + } + if ($update) { + $edit = $return; + } + } + if (!empty($edit['vid']) && !empty($edit['name'])) { drupal_write_record('vocabulary', $edit, 'vid'); db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']); @@ -309,6 +322,19 @@ function taxonomy_save_term(&$form_values) { 'weight' => 0 ); + $return = module_invoke_all('taxonomy_term_presave', $form_values); + if (is_array($return) && !empty($return)) { + $update = TRUE; + foreach ($return as $key => $value) { + if (is_numeric($key) && $value == FALSE) { + $update = FALSE; + } + } + if ($update) { + $form_values = $return; + } + } + if (!empty($form_values['tid']) && $form_values['name']) { drupal_write_record('term_data', $form_values, 'tid'); $hook = 'update'; From 4b90144507dc3e66de563ebc3cde2d6e0d0cd481 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:40:39 -0400 Subject: [PATCH 14/29] Issue #496184 by mikeytown2: db_set_active errors out if db_connect fails. Add in the ability to handle this gracefully (don't always call _db_error_page). --- includes/database.inc | 52 +++++++++++++++++++++++++++++++----- includes/database.mysql.inc | 4 +-- includes/database.mysqli.inc | 4 +-- includes/database.pgsql.inc | 4 +-- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/includes/database.inc b/includes/database.inc index efb4a90fa25..79862da6a1d 100644 --- a/includes/database.inc +++ b/includes/database.inc @@ -117,11 +117,13 @@ function db_prefix_tables($sql) { * @param $name * The key in the $db_url global variable from settings.php. If omitted, the * default connection will be made active. + * @param $abort + * If database connection could not be made, should we abort here or continue. * * @return * The name of the previously active database, or FALSE if none was found. */ -function db_set_active($name = 'default') { +function db_set_active($name = 'default', $abort = TRUE) { global $db_url, $db_slave_url, $db_type, $active_db, $active_slave_db; static $db_conns, $db_slave_conns, $active_name = FALSE; @@ -139,7 +141,7 @@ function db_set_active($name = 'default') { $slave_connect_url = $db_slave_url[$name][$slave_index]; } else { - $slave_connect_url = $db_slave_url[$name]; + $slave_connect_url = $db_slave_url[$name]; } } else { @@ -149,7 +151,7 @@ function db_set_active($name = 'default') { $slave_connect_url = $db_slave_url[$slave_index]; } else { - $slave_connect_url = $db_slave_url; + $slave_connect_url = $db_slave_url; } } @@ -163,9 +165,45 @@ function db_set_active($name = 'default') { _db_error_page("The database type '". $db_type ."' is unsupported. Please use either 'mysql' or 'mysqli' for MySQL, or 'pgsql' for PostgreSQL databases."); } - $db_conns[$name] = db_connect($connect_url); + $connection = db_connect($connect_url); + // db_connect is using array return notation. + if (is_array($connection)) { + list($success, $result) = $connection; + // Connection worked + if ($success) { + $db_conns[$name] = $result; + } + // Connection failed and abort page load. + elseif ($abort) { + _db_error_page($result); + } + // Connection failed but return false. Calling function will handle error. + else { + return FALSE; + } + } + // db_connect is not using array return notation; revert to old code style. + else { + $db_conns[$name] = $connection; + } if (!empty($slave_connect_url)) { - $db_slave_conns[$name] = db_connect($slave_connect_url); + $connection = db_connect($slave_connect_url); + // db_connect is using array return notation. + if (is_array($connection)) { + list($success, $result) = $connection; + // Connection worked + if ($success) { + $db_slave_conns[$name] = $result; + } + // Connection failed, set to false. + else { + $db_slave_conns[$name] = FALSE; + } + } + // db_connect is not using array return notation; revert to old code style. + else { + $db_slave_conns[$name] = $connection; + } } } @@ -173,7 +211,7 @@ function db_set_active($name = 'default') { // Set the active connection. $active_name = $name; $active_db = $db_conns[$name]; - if (isset($db_slave_conns[$name])) { + if (!empty($db_slave_conns[$name])) { $active_slave_db = $db_slave_conns[$name]; } else { @@ -696,7 +734,7 @@ function db_ignore_slave() { // the old data. $duration = variable_get('maximum_replication_lag', 300); // Set session variable with amount of time to delay before using slave. - // This will stick around for 5 minutes by default. + // This will stick around for 5 minutes by default. // There is another $_Session variable 'not_slavesafe' for single queries. $_SESSION['ignore_slave_server'] = $_SERVER['REQUEST_TIME'] + $duration; } diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index 4ff53e1fa77..73c5a7aaa9a 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -76,7 +76,7 @@ function db_connect($url) { $connection = @mysql_connect($url['host'], $url['user'], $url['pass'], TRUE, 2); if (!$connection || !mysql_select_db(substr($url['path'], 1))) { // Show error screen otherwise - _db_error_page(mysql_error()); + return array(FALSE, mysql_error()); } // Force MySQL to use the UTF-8 character set. Also set the collation, if a @@ -89,7 +89,7 @@ function db_connect($url) { mysql_query('SET NAMES utf8', $connection); } - return $connection; + return array(TRUE, $connection); } /** diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index 2ee710bdb75..f0ce35d4ec2 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -75,7 +75,7 @@ function db_connect($url) { @mysqli_real_connect($connection, $url['host'], $url['user'], $url['pass'], substr($url['path'], 1), $url['port'], NULL, MYSQLI_CLIENT_FOUND_ROWS); if (mysqli_connect_errno() > 0) { - _db_error_page(mysqli_connect_error()); + return array(FALSE, mysqli_connect_error()); } // Force MySQL to use the UTF-8 character set. Also set the collation, if a @@ -88,7 +88,7 @@ function db_connect($url) { mysqli_query($connection, 'SET NAMES utf8'); } - return $connection; + return array(TRUE, $connection); } /** diff --git a/includes/database.pgsql.inc b/includes/database.pgsql.inc index 161de08f513..e44bc00d7f8 100644 --- a/includes/database.pgsql.inc +++ b/includes/database.pgsql.inc @@ -78,14 +78,14 @@ function db_connect($url) { $connection = @pg_connect($conn_string); if (!$connection) { require_once './includes/unicode.inc'; - _db_error_page(decode_entities($php_errormsg)); + return array(FALSE, decode_entities($php_errormsg)); } // Restore error tracking setting ini_set('track_errors', $track_errors_previous); pg_query($connection, "set client_encoding=\"UTF8\""); - return $connection; + return array(TRUE, $connection); } /** From 91e2070b741a18bfc4069703ae142c6d537e76b2 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:44:12 -0400 Subject: [PATCH 15/29] Issue #961908 by mikeytown2: Make drupal_attributes() faster --- includes/common.inc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/includes/common.inc b/includes/common.inc index a0550f6949a..36b69945215 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1572,13 +1572,11 @@ function url($path = NULL, $options = array()) { * An HTML string ready for insertion in a tag. */ function drupal_attributes($attributes = array()) { - if (is_array($attributes)) { - $t = ''; - foreach ($attributes as $key => $value) { - $t .= " $key=".'"'. check_plain($value) .'"'; - } - return $t; + $t = ''; + foreach ((array) $attributes as $attribute => $data) { + $t .= " $attribute=".'"'. check_plain($data) .'"'; } + return $t; } /** From c2da748fcffae16195aeaa5c74bed79fbcfe28ca Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 16:49:57 -0400 Subject: [PATCH 16/29] Issue #1103910 by mikeytown2, catch: bootstrap_invoke_all() queries bootstrap modules twice --- includes/bootstrap.inc | 6 +++++- modules/system/system.module | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 72cd178e819..3a6030e4e3d 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -767,7 +767,11 @@ function drupal_page_is_cacheable($force = NULL) { * The name of the bootstrap hook we wish to invoke. */ function bootstrap_invoke_all($hook) { - foreach (module_list(TRUE, TRUE) as $module) { + static $bootstrap_modules; + if (!isset($bootstrap_modules)) { + $bootstrap_modules = module_list(TRUE, TRUE); + } + foreach ($bootstrap_modules as $module) { drupal_load('module', $module); module_invoke($module, $hook); } diff --git a/modules/system/system.module b/modules/system/system.module index 1df0a9160c5..ec30bdd0f9f 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -1044,9 +1044,16 @@ function system_find_base_theme($themes, $key, $used_keys = array()) { */ function system_region_list($theme_key) { static $list = array(); + global $theme, $theme_info; if (!array_key_exists($theme_key, $list)) { - $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key))); + if ($theme == $theme_key) { + $info = $theme_info->info; + } + else { + $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key))); + } + $list[$theme_key] = array_map('t', $info['regions']); } From 9a5b2d426d54d5cf5aef501b3487f8ae38728e78 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 17:40:07 -0400 Subject: [PATCH 17/29] Issue #1345402 by mikeytown2, catch: Backport DRUPAL_ROOT to 6.x --- cron.php | 7 +- includes/batch.inc | 4 +- includes/bootstrap.inc | 32 ++++---- includes/common.inc | 22 +++--- includes/database.inc | 4 +- includes/database.mysql.inc | 2 +- includes/database.mysqli.inc | 2 +- includes/database.pgsql.inc | 2 +- includes/form.inc | 2 +- includes/image.inc | 4 +- includes/install.inc | 28 +++---- includes/mail.inc | 2 +- includes/menu.inc | 4 +- includes/module.inc | 4 +- includes/theme.inc | 44 +++++------ includes/theme.maintenance.inc | 14 ++-- includes/unicode.inc | 2 +- index.php | 7 +- install.php | 75 ++++++++++--------- modules/color/color.module | 2 +- modules/locale/locale.module | 4 +- modules/poll/poll.module | 2 +- modules/system/system.admin.inc | 12 +-- modules/system/system.install | 2 +- modules/system/system.module | 4 +- modules/update/update.fetch.inc | 2 +- modules/update/update.module | 4 +- themes/engines/phptemplate/phptemplate.engine | 2 +- update.php | 19 +++-- xmlrpc.php | 11 ++- 30 files changed, 175 insertions(+), 150 deletions(-) diff --git a/cron.php b/cron.php index 79fd2381b1f..7917fad2f06 100644 --- a/cron.php +++ b/cron.php @@ -5,6 +5,11 @@ * Handles incoming requests to fire off regularly-scheduled tasks (cron jobs). */ -include_once './includes/bootstrap.inc'; +/** + * Root directory of Drupal installation. + */ +define('DRUPAL_ROOT', getcwd()); + +include_once DRUPAL_ROOT . '/includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); drupal_cron_run(); diff --git a/includes/batch.inc b/includes/batch.inc index 63629875817..b7d0ce1495f 100644 --- a/includes/batch.inc +++ b/includes/batch.inc @@ -176,7 +176,7 @@ function _batch_process() { // request, we check if it requires an additional file for functions // definitions. if ($set_changed && isset($current_set['file']) && is_file($current_set['file'])) { - include_once($current_set['file']); + include_once DRUPAL_ROOT . '/' . $current_set['file']; } $finished = 1; @@ -295,7 +295,7 @@ function _batch_finished() { if (isset($batch_set['finished'])) { // Check if the set requires an additional file for functions definitions. if (isset($batch_set['file']) && is_file($batch_set['file'])) { - include_once($batch_set['file']); + include_once DRUPAL_ROOT . '/' . $batch_set['file']; } if (function_exists($batch_set['finished'])) { $batch_set['finished']($batch_set['success'], $batch_set['results'], $batch_set['operations']); diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 3a6030e4e3d..cb93bc51027 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -337,7 +337,7 @@ function conf_path($require_settings = TRUE, $reset = FALSE) { for ($i = count($uri) - 1; $i > 0; $i--) { for ($j = count($server); $j > 0; $j--) { $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i)); - if (file_exists("$confdir/$dir/settings.php") || (!$require_settings && file_exists("$confdir/$dir"))) { + if (file_exists(DRUPAL_ROOT . "/$confdir/$dir/settings.php") || (!$require_settings && file_exists(DRUPAL_ROOT . "/$confdir/$dir"))) { $conf = "$confdir/$dir"; return $conf; } @@ -407,8 +407,8 @@ function conf_init() { $_SERVER['HTTP_HOST'] = ''; } - if (file_exists('./'. conf_path() .'/settings.php')) { - include_once './'. conf_path() .'/settings.php'; + if (file_exists(DRUPAL_ROOT . '/'. conf_path() .'/settings.php')) { + include_once DRUPAL_ROOT . '/'. conf_path() .'/settings.php'; } // Ignore the placeholder URL from default.settings.php. @@ -520,7 +520,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { $files[$type] = array(); } - if (!empty($filename) && file_exists($filename)) { + if (!empty($filename) && file_exists(DRUPAL_ROOT . '/'. $filename)) { $files[$type][$name] = $filename; } elseif (isset($files[$type][$name])) { @@ -530,7 +530,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { // the database. This is required because this function is called both // before we have a database connection (i.e. during installation) and // when a database connection fails. - elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { + elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists(DRUPAL_ROOT . '/'. $file))) { $files[$type][$name] = $file; } else { @@ -541,7 +541,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { $file = (($type == 'theme_engine') ? "$name.engine" : "$name.$type"); foreach (array("$config/$dir/$file", "$config/$dir/$name/$file", "$dir/$file", "$dir/$name/$file") as $file) { - if (file_exists($file)) { + if (file_exists(DRUPAL_ROOT . '/'. $file)) { $files[$type][$name] = $file; break; } @@ -799,7 +799,7 @@ function drupal_load($type, $name) { $filename = drupal_get_filename($type, $name); if ($filename) { - include_once "./$filename"; + include_once DRUPAL_ROOT . "/$filename"; $files[$type][$name] = TRUE; return TRUE; @@ -1477,7 +1477,7 @@ function _drupal_bootstrap($phase) { case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: // Allow specifying special cache handlers in settings.php, like // using memcached or files for storing cache information. - require_once variable_get('cache_inc', './includes/cache.inc'); + require_once DRUPAL_ROOT . '/' . variable_get('cache_inc', 'includes/cache.inc'); // If the page_cache_fastpath is set to TRUE in settings.php and // page_cache_fastpath (implemented in the special implementation of // cache.inc) printed the page and indicated this with a returned TRUE @@ -1501,11 +1501,11 @@ function _drupal_bootstrap($phase) { } // Initialize the default database. - require_once './includes/database.inc'; + require_once DRUPAL_ROOT . '/includes/database.inc'; db_set_active(); // Allow specifying alternate lock implementations in settings.php, like // those using APC or memcached. - require_once variable_get('lock_inc', './includes/lock.inc'); + require_once DRUPAL_ROOT . '/' . variable_get('lock_inc', 'includes/lock.inc'); lock_init(); // Detect if an installation is present. @@ -1523,7 +1523,7 @@ function _drupal_bootstrap($phase) { break; case DRUPAL_BOOTSTRAP_SESSION: - require_once variable_get('session_inc', './includes/session.inc'); + require_once DRUPAL_ROOT . '/' . variable_get('session_inc', 'includes/session.inc'); drupal_session_initialize(); break; @@ -1543,7 +1543,7 @@ function _drupal_bootstrap($phase) { // If the skipping of the bootstrap hooks is not enforced, call hook_init. if (!is_object($cache) || $cache_mode != CACHE_AGGRESSIVE) { // Load module handling. - require_once './includes/module.inc'; + require_once DRUPAL_ROOT . '/includes/module.inc'; bootstrap_invoke_all('boot'); } @@ -1580,13 +1580,13 @@ function _drupal_bootstrap($phase) { break; case DRUPAL_BOOTSTRAP_PATH: - require_once './includes/path.inc'; + require_once DRUPAL_ROOT . '/includes/path.inc'; // Initialize $_GET['q'] prior to loading modules and invoking hook_init(). drupal_init_path(); break; case DRUPAL_BOOTSTRAP_FULL: - require_once './includes/common.inc'; + require_once DRUPAL_ROOT . '/includes/common.inc'; _drupal_bootstrap_full(); break; } @@ -1601,7 +1601,7 @@ function _drupal_bootstrap($phase) { * @see _drupal_maintenance_theme() */ function drupal_maintenance_theme() { - require_once './includes/theme.maintenance.inc'; + require_once DRUPAL_ROOT . '/includes/theme.maintenance.inc'; _drupal_maintenance_theme(); } @@ -1629,7 +1629,7 @@ function drupal_init_language() { $language = language_default(); } else { - include_once './includes/language.inc'; + include_once DRUPAL_ROOT . '/includes/language.inc'; $language = language_initialize(); } } diff --git a/includes/common.inc b/includes/common.inc index 36b69945215..3ec4aefd0c4 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2661,7 +2661,7 @@ function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) { * failed. See xmlrpc_error(). */ function xmlrpc($url) { - require_once './includes/xmlrpc.inc'; + require_once DRUPAL_ROOT . '/includes/xmlrpc.inc'; $args = func_get_args(); return call_user_func_array('_xmlrpc', $args); } @@ -2673,16 +2673,16 @@ function _drupal_bootstrap_full() { return; } $called = 1; - require_once './includes/theme.inc'; - require_once './includes/pager.inc'; - require_once './includes/menu.inc'; - require_once './includes/tablesort.inc'; - require_once './includes/file.inc'; - require_once './includes/unicode.inc'; - require_once './includes/image.inc'; - require_once './includes/form.inc'; - require_once './includes/mail.inc'; - require_once './includes/actions.inc'; + require_once DRUPAL_ROOT . '/includes/theme.inc'; + require_once DRUPAL_ROOT . '/includes/pager.inc'; + require_once DRUPAL_ROOT . '/includes/menu.inc'; + require_once DRUPAL_ROOT . '/includes/tablesort.inc'; + require_once DRUPAL_ROOT . '/includes/file.inc'; + require_once DRUPAL_ROOT . '/includes/unicode.inc'; + require_once DRUPAL_ROOT . '/includes/image.inc'; + require_once DRUPAL_ROOT . '/includes/form.inc'; + require_once DRUPAL_ROOT . '/includes/mail.inc'; + require_once DRUPAL_ROOT . '/includes/actions.inc'; // Set the Drupal custom error handler. set_error_handler('_drupal_error_handler'); set_exception_handler('_drupal_exception_handler'); diff --git a/includes/database.inc b/includes/database.inc index 79862da6a1d..dbb86e1bc55 100644 --- a/includes/database.inc +++ b/includes/database.inc @@ -128,7 +128,7 @@ function db_set_active($name = 'default', $abort = TRUE) { static $db_conns, $db_slave_conns, $active_name = FALSE; if (empty($db_url)) { - include_once 'includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; install_goto('install.php'); } @@ -156,7 +156,7 @@ function db_set_active($name = 'default', $abort = TRUE) { } $db_type = substr($connect_url, 0, strpos($connect_url, '://')); - $handler = "./includes/database.$db_type.inc"; + $handler = DRUPAL_ROOT . "/includes/database.$db_type.inc"; if (is_file($handler)) { include_once $handler; diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index 73c5a7aaa9a..7ff85471360 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -11,7 +11,7 @@ */ // Include functions shared between mysql and mysqli. -require_once './includes/database.mysql-common.inc'; +require_once DRUPAL_ROOT . '/includes/database.mysql-common.inc'; /** * Report database status. diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index f0ce35d4ec2..21083900716 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -14,7 +14,7 @@ */ // Include functions shared between mysql and mysqli. -require_once './includes/database.mysql-common.inc'; +require_once DRUPAL_ROOT . '/includes/database.mysql-common.inc'; /** * Report database status. diff --git a/includes/database.pgsql.inc b/includes/database.pgsql.inc index e44bc00d7f8..33166601063 100644 --- a/includes/database.pgsql.inc +++ b/includes/database.pgsql.inc @@ -77,7 +77,7 @@ function db_connect($url) { $connection = @pg_connect($conn_string); if (!$connection) { - require_once './includes/unicode.inc'; + require_once DRUPAL_ROOT . '/includes/unicode.inc'; return array(FALSE, decode_entities($php_errormsg)); } diff --git a/includes/form.inc b/includes/form.inc index 11445b457bd..5f273fdfa4e 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -2551,7 +2551,7 @@ function batch_process($redirect = NULL, $url = NULL) { else { // Non-progressive execution: bypass the whole progressbar workflow // and execute the batch in one pass. - require_once './includes/batch.inc'; + require_once DRUPAL_ROOT . '/includes/batch.inc'; _batch_process(); } } diff --git a/includes/image.inc b/includes/image.inc index 1580d317a96..808982666fc 100644 --- a/includes/image.inc +++ b/includes/image.inc @@ -40,7 +40,7 @@ function image_get_available_toolkits() { $output = array(); foreach ($toolkits as $file => $toolkit) { - include_once "./$file"; + include_once DRUPAL_ROOT . "/$file"; $function = str_replace('.', '_', $toolkit->name) .'_info'; if (function_exists($function)) { $info = $function(); @@ -62,7 +62,7 @@ function image_get_toolkit() { if (!$toolkit) { $toolkit = variable_get('image_toolkit', 'gd'); - $toolkit_file = './includes/image.'. $toolkit .'.inc'; + $toolkit_file = DRUPAL_ROOT . '/includes/image.'. $toolkit .'.inc'; if (isset($toolkit) && file_exists($toolkit_file)) { include_once $toolkit_file; } diff --git a/includes/install.inc b/includes/install.inc index 80e83265d0b..4ceae8cd839 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -168,8 +168,8 @@ function drupal_detect_database_types() { $databases = array(); foreach (array('mysql', 'mysqli', 'pgsql') as $type) { - if (file_exists('./includes/install.'. $type .'.inc')) { - include_once './includes/install.'. $type .'.inc'; + if (file_exists(DRUPAL_ROOT . '/includes/install.'. $type .'.inc')) { + include_once DRUPAL_ROOT . '/includes/install.'. $type .'.inc'; $function = $type .'_is_available'; if ($function()) { $databases[$type] = $type; @@ -188,8 +188,8 @@ function drupal_detect_database_types() { * An array of settings that need to be updated. */ function drupal_rewrite_settings($settings = array(), $prefix = '') { - $default_settings = './sites/default/default.settings.php'; - $settings_file = './'. conf_path(FALSE, TRUE) .'/'. $prefix .'settings.php'; + $default_settings = DRUPAL_ROOT . '/sites/default/default.settings.php'; + $settings_file = DRUPAL_ROOT . '/' . conf_path(FALSE, TRUE) .'/'. $prefix .'settings.php'; // Build list of setting names and insert the values into the global namespace. $keys = array(); @@ -283,10 +283,10 @@ function drupal_get_install_files($module_list = array()) { * The list of modules to install. */ function drupal_verify_profile($profile, $locale) { - include_once './includes/file.inc'; - include_once './includes/common.inc'; + include_once DRUPAL_ROOT . '/includes/file.inc'; + include_once DRUPAL_ROOT . '/includes/common.inc'; - $profile_file = "./profiles/$profile/$profile.profile"; + $profile_file = DRUPAL_ROOT . "/profiles/$profile/$profile.profile"; if (!isset($profile) || !file_exists($profile_file)) { install_no_profile_error(); @@ -371,7 +371,7 @@ function _drupal_install_module($module) { */ function drupal_install_system() { $system_path = dirname(drupal_get_filename('module', 'system', NULL)); - require_once './'. $system_path .'/system.install'; + require_once DRUPAL_ROOT . '/' . $system_path . '/system.install'; module_invoke('system', 'install'); $system_versions = drupal_get_schema_versions('system'); $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; @@ -646,16 +646,16 @@ function st($string, $args = array()) { if (!isset($locale_strings)) { $locale_strings = array(); - $filename = './profiles/'. $profile .'/translations/'. $install_locale .'.po'; + $filename = DRUPAL_ROOT . '/profiles/'. $profile .'/translations/'. $install_locale .'.po'; if (file_exists($filename)) { - require_once './includes/locale.inc'; + require_once DRUPAL_ROOT . '/includes/locale.inc'; $file = (object) array('filepath' => $filename); _locale_import_read_po('mem-store', $file); $locale_strings = _locale_import_one_string('mem-report'); } } - require_once './includes/theme.inc'; + require_once DRUPAL_ROOT . '/includes/theme.inc'; // Transform arguments before inserting them foreach ($args as $key => $value) { switch ($key[0]) { @@ -682,9 +682,9 @@ function st($string, $args = array()) { * Name of profile to check. */ function drupal_check_profile($profile) { - include_once './includes/file.inc'; + include_once DRUPAL_ROOT . '/includes/file.inc'; - $profile_file = "./profiles/$profile/$profile.profile"; + $profile_file = DRUPAL_ROOT . "/profiles/$profile/$profile.profile"; if (!isset($profile) || !file_exists($profile_file)) { install_no_profile_error(); @@ -730,7 +730,7 @@ function drupal_check_module($module) { // Include install file $install = drupal_get_install_files(array($module)); if (isset($install[$module])) { - require_once $install[$module]->filename; + require_once DRUPAL_ROOT . '/' . $install->filename; // Check requirements $requirements = module_invoke($module, 'requirements', 'install'); diff --git a/includes/mail.inc b/includes/mail.inc index 92540e2ea5f..9a9f7596fdf 100644 --- a/includes/mail.inc +++ b/includes/mail.inc @@ -172,7 +172,7 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N function drupal_mail_send($message) { // Allow for a custom mail backend. if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) { - include_once './'. variable_get('smtp_library', ''); + include_once DRUPAL_ROOT . '/'. variable_get('smtp_library', ''); return drupal_mail_wrapper($message); } else { diff --git a/includes/menu.inc b/includes/menu.inc index a316048e41e..e11de864856 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -354,7 +354,7 @@ function menu_execute_active_handler($path = NULL) { if ($router_item = menu_get_item($path)) { if ($router_item['access']) { if ($router_item['file']) { - require_once($router_item['file']); + require_once DRUPAL_ROOT . '/' . $router_item['file']; } return call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); } @@ -2537,7 +2537,7 @@ function _menu_site_is_offline() { return $_GET['q'] != 'user' && $_GET['q'] != 'user/login'; } // Logged in users are unprivileged here, so they are logged out. - require_once drupal_get_path('module', 'user') .'/user.pages.inc'; + require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'user') .'/user.pages.inc'; user_logout(); } } diff --git a/includes/module.inc b/includes/module.inc index 6fa7448e836..402da24bc7c 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -250,7 +250,7 @@ function module_exists($module) { */ function module_load_install($module) { // Make sure the installation API is available - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; module_load_include('install', $module); } @@ -282,7 +282,7 @@ function module_load_include($type, $module, $name = NULL) { $name = $module; } - $file = './'. drupal_get_path('module', $module) ."/$name.$type"; + $file = DRUPAL_ROOT . '/'. drupal_get_path('module', $module) ."/$name.$type"; if (is_file($file)) { require_once $file; diff --git a/includes/theme.inc b/includes/theme.inc index 0b25f710e54..fb6ff58907d 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -164,7 +164,7 @@ function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme // Initialize the theme. if (isset($theme->engine)) { // Include the engine. - include_once './'. $theme->owner; + include_once DRUPAL_ROOT . '/'. $theme->owner; $theme_engine = $theme->engine; if (function_exists($theme_engine .'_init')) { @@ -179,12 +179,12 @@ function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme foreach ($base_theme as $base) { // Include the theme file or the engine. if (!empty($base->owner)) { - include_once './'. $base->owner; + include_once DRUPAL_ROOT . '/'. $base->owner; } } // and our theme gets one too. if (!empty($theme->owner)) { - include_once './'. $theme->owner; + include_once DRUPAL_ROOT . '/'. $theme->owner; } } @@ -298,23 +298,23 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) { // files can prevent them from getting registered. if (isset($info['file']) && !isset($info['path'])) { // First, check to see if the fully qualified file exists. - $filename = './'. $path .'/'. $info['file']; - if (file_exists($filename)) { - require_once $filename; + $filename = $path .'/'. $info['file']; + if (file_exists(DRUPAL_ROOT . '/' . $filename)) { + require_once DRUPAL_ROOT . '/' . $filename; $result[$hook]['include files'][] = $filename; } else { - $filename = './'. $info['file']; - if (file_exists($filename)) { - require_once $filename; + $filename = $info['file']; + if (file_exists(DRUPAL_ROOT . '/' . $filename)) { + require_once DRUPAL_ROOT . '/' . $filename; $result[$hook]['include files'][] = $filename; } } } elseif (isset($info['file']) && isset($info['path'])) { - $filename = './'. $info['path'] .'/'. $info['file']; - if (file_exists($filename)) { - require_once $filename; + $filename = $info['path'] .'/'. $info['file']; + if (file_exists(DRUPAL_ROOT . '/' . $filename)) { + require_once DRUPAL_ROOT . '/' . $filename; $result[$hook]['include files'][] = $filename; } } @@ -482,7 +482,7 @@ function list_themes($refresh = FALSE) { if (db_is_active() && !defined('MAINTENANCE_MODE')) { $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme'); while ($theme = db_fetch_object($result)) { - if (file_exists($theme->filename)) { + if (file_exists(DRUPAL_ROOT . '/' . $theme->filename)) { $theme->info = unserialize($theme->info); $themes[] = $theme; } @@ -500,7 +500,7 @@ function list_themes($refresh = FALSE) { } } foreach ($theme->info['scripts'] as $script => $path) { - if (file_exists($path)) { + if (file_exists(DRUPAL_ROOT . '/' . $path)) { $theme->scripts[$script] = $path; } } @@ -606,7 +606,7 @@ function list_themes($refresh = FALSE) { * implementations for named objects. * @param ... * Additional arguments to pass along to the theme function. - * + * * @return * An HTML string that generates the themed output. */ @@ -642,7 +642,7 @@ function theme() { // Include a file if the theme function or preprocess function is held elsewhere. if (!empty($info['include files'])) { foreach ($info['include files'] as $include_file) { - include_once($include_file); + include_once DRUPAL_ROOT . '/' . $include_file; } } @@ -658,8 +658,8 @@ function theme() { // Statically cache files we've already tried to include so we don't // run unnecessary file_exists calls. $included_files[$include_file] = TRUE; - if (file_exists('./'. $include_file)) { - include_once('./'. $include_file); + if (file_exists(DRUPAL_ROOT . '/' . $include_file)) { + include_once DRUPAL_ROOT . '/' . $include_file; } } } @@ -765,8 +765,8 @@ function drupal_discover_template($paths, $suggestions, $extension = '.tpl.php') if (!empty($suggestion)) { $suggestion = str_replace(array("/", "\\", "\0"), '', $suggestion); foreach ($paths as $path) { - if (file_exists($file = $path .'/'. $suggestion . $extension)) { - return $file; + if (file_exists(DRUPAL_ROOT . '/' . $path .'/'. $suggestion . $extension)) { + return $path .'/'. $suggestion . $extension; } } } @@ -1076,7 +1076,7 @@ function theme_get_setting($setting_name, $refresh = FALSE) { function theme_render_template($template_file, $variables) { extract($variables, EXTR_SKIP); // Extract the variables to a local namespace ob_start(); // Start output buffering - include "./$template_file"; // Include the template file + include DRUPAL_ROOT . '/' . "$template_file"; // Include the template file $contents = ob_get_contents(); // Get the contents of the buffer ob_end_clean(); // End buffering and discard return $contents; // Return the contents @@ -1279,7 +1279,7 @@ function theme_links($links, $attributes = array('class' => 'links')) { * @param $getsize * If set to TRUE, the image's dimension are fetched and added as width/height attributes. * Defaults to TRUE. Must be set to FALSE if $path is a full URL. - * + * * @return * A string containing the image tag. */ diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc index 2725057d8b2..60c54daa36c 100644 --- a/includes/theme.maintenance.inc +++ b/includes/theme.maintenance.inc @@ -21,13 +21,13 @@ function _drupal_maintenance_theme() { return; } - require_once './includes/path.inc'; - require_once './includes/theme.inc'; - require_once './includes/common.inc'; - require_once './includes/unicode.inc'; - require_once './includes/file.inc'; - require_once './includes/module.inc'; - require_once './includes/database.inc'; + require_once DRUPAL_ROOT . '/includes/path.inc'; + require_once DRUPAL_ROOT . '/includes/theme.inc'; + require_once DRUPAL_ROOT . '/includes/common.inc'; + require_once DRUPAL_ROOT . '/includes/unicode.inc'; + require_once DRUPAL_ROOT . '/includes/file.inc'; + require_once DRUPAL_ROOT . '/includes/module.inc'; + require_once DRUPAL_ROOT . '/includes/database.inc'; unicode_check(); // Install and update pages are treated differently to prevent theming overrides. diff --git a/includes/unicode.inc b/includes/unicode.inc index b1ce75760b9..9a1ba799c6b 100644 --- a/includes/unicode.inc +++ b/includes/unicode.inc @@ -336,7 +336,7 @@ function _mime_header_decode($matches) { function decode_entities($text, $exclude = array()) { static $html_entities; if (!isset($html_entities)) { - include_once './includes/unicode.entities.inc'; + include_once DRUPAL_ROOT . '/includes/unicode.entities.inc'; } // Flip the exclude list so that we can do quick lookups later. diff --git a/index.php b/index.php index cc504603123..58af9149327 100644 --- a/index.php +++ b/index.php @@ -11,7 +11,12 @@ * See COPYRIGHT.txt and LICENSE.txt. */ -require_once './includes/bootstrap.inc'; +/** + * Root directory of Drupal installation. + */ +define('DRUPAL_ROOT', getcwd()); + +require_once DRUPAL_ROOT . '/includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); $return = menu_execute_active_handler(); diff --git a/install.php b/install.php index b02bb41febf..a44bbbe0d9e 100644 --- a/install.php +++ b/install.php @@ -1,6 +1,11 @@ filename; + require_once DRUPAL_ROOT . '/' . $profile->filename; return $profile->name; } elseif (sizeof($profiles) > 1) { @@ -475,7 +480,7 @@ function install_select_profile_form(&$form_state, $profile_files) { $names = array(); foreach ($profile_files as $profile) { - include_once($profile->filename); + include_once DRUPAL_ROOT . '/' . $profile->filename; // Load profile details and store them for later retrieval. $function = $profile->name .'_profile_details'; @@ -490,7 +495,7 @@ function install_select_profile_form(&$form_state, $profile_files) { $names[$profile->name] = $name; } - // Display radio buttons alphabetically by human-readable name. + // Display radio buttons alphabetically by human-readable name. natcasesort($names); foreach ($names as $profile => $name) { $form['profile'][$name] = array( @@ -513,7 +518,7 @@ function install_select_profile_form(&$form_state, $profile_files) { * Find all .po files for the current profile. */ function install_find_locales($profilename) { - $locales = file_scan_directory('./profiles/'. $profilename .'/translations', '\.po$', array('.', '..', 'CVS'), 0, FALSE); + $locales = file_scan_directory(DRUPAL_ROOT . '/profiles/'. $profilename .'/translations', '\.po$', array('.', '..', 'CVS'), 0, FALSE); array_unshift($locales, (object) array('name' => 'en')); return $locales; } @@ -525,8 +530,8 @@ function install_find_locales($profilename) { * The selected language. */ function install_select_locale($profilename) { - include_once './includes/file.inc'; - include_once './includes/form.inc'; + include_once DRUPAL_ROOT . '/includes/file.inc'; + include_once DRUPAL_ROOT . '/includes/form.inc'; // Find all available locales. $locales = install_find_locales($profilename); @@ -592,7 +597,7 @@ function install_select_locale($profilename) { * Form API array definition for language selection. */ function install_select_locale_form(&$form_state, $locales) { - include_once './includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; $languages = _locale_get_predefined_list(); foreach ($locales as $locale) { // Try to use verbose locale name @@ -686,14 +691,14 @@ function install_tasks($profile, $task) { // to the same address, until the batch finished callback is invoked // and the task advances to 'locale-initial-import'. if ($task == 'profile-install-batch') { - include_once 'includes/batch.inc'; + include_once DRUPAL_ROOT . '/includes/batch.inc'; $output = _batch_page(); } // Import interface translations for the enabled modules. if ($task == 'locale-initial-import') { if (!empty($install_locale) && ($install_locale != 'en')) { - include_once 'includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; // Enable installation language as default site language. locale_add_language($install_locale, NULL, NULL, NULL, NULL, NULL, 1, TRUE); // Collect files to import for this language. @@ -712,8 +717,8 @@ function install_tasks($profile, $task) { $task = 'configure'; } if ($task == 'locale-initial-batch') { - include_once 'includes/batch.inc'; - include_once 'includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/batch.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; $output = _batch_page(); } @@ -732,7 +737,7 @@ function install_tasks($profile, $task) { drupal_set_title(st('Configure site')); // Warn about settings.php permissions risk - $settings_dir = './'. conf_path(); + $settings_dir = DRUPAL_ROOT . '/'. conf_path(); $settings_file = $settings_dir .'/settings.php'; if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file($settings_dir, FILE_NOT_WRITABLE, 'dir')) { drupal_set_message(st('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, please consult the on-line handbook.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/getting-started')), 'error'); @@ -786,7 +791,7 @@ function install_tasks($profile, $task) { // control and proceed with importing the remaining translations. if ($task == 'profile-finished') { if (!empty($install_locale) && ($install_locale != 'en')) { - include_once 'includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; // Collect files to import for this language. Skip components // already covered in the initial batch set. $batch = locale_batch_by_language($install_locale, '_install_locale_remaining_batch_finished', variable_get('install_locale_batch_components', array())); @@ -804,8 +809,8 @@ function install_tasks($profile, $task) { $task = 'finished'; } if ($task == 'locale-remaining-batch') { - include_once 'includes/batch.inc'; - include_once 'includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/batch.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; $output = _batch_page(); } @@ -898,7 +903,7 @@ function install_check_requirements($profile, $verify) { // If Drupal is not set up already, we need to create a settings file. if (!$verify) { $writable = FALSE; - $conf_path = './'. conf_path(FALSE, TRUE); + $conf_path = DRUPAL_ROOT . '/'. conf_path(FALSE, TRUE); $settings_file = $conf_path .'/settings.php'; $file = $conf_path; $exists = FALSE; @@ -953,7 +958,7 @@ function install_check_requirements($profile, $verify) { drupal_set_message($message, 'warning'); } } - } + } } /** diff --git a/modules/color/color.module b/modules/color/color.module index 63fad7af91f..a8f620f3fd6 100644 --- a/modules/color/color.module +++ b/modules/color/color.module @@ -121,7 +121,7 @@ function _color_page_alter(&$vars) { */ function color_get_info($theme) { $path = drupal_get_path('theme', $theme); - $file = $path .'/color/color.inc'; + $file = DRUPAL_ROOT . '/' . $path .'/color/color.inc'; if ($path && file_exists($file)) { include $file; return $info; diff --git a/modules/locale/locale.module b/modules/locale/locale.module index 092eb4842ab..3a25fd62f70 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -175,7 +175,7 @@ function locale_menu() { function locale_inc_callback() { $args = func_get_args(); $function = array_shift($args); - include_once './includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; return call_user_func_array($function, $args); } @@ -479,7 +479,7 @@ function locale_language_list($field = 'name', $all = FALSE) { * translations for. */ function locale_system_update($components) { - include_once 'includes/locale.inc'; + include_once DRUPAL_ROOT . '/includes/locale.inc'; if ($batch = locale_batch_by_component($components)) { batch_set($batch); } diff --git a/modules/poll/poll.module b/modules/poll/poll.module index 7bc5587d399..edf0246165b 100644 --- a/modules/poll/poll.module +++ b/modules/poll/poll.module @@ -320,7 +320,7 @@ function _poll_choice_form($delta, $value = '', $votes = 0) { * Menu callback for AHAH additions. */ function poll_choice_js() { - include_once 'modules/node/node.pages.inc'; + include_once DRUPAL_ROOT . '/modules/node/node.pages.inc'; $form_state = array('storage' => NULL, 'submitted' => FALSE); $form_build_id = $_POST['form_build_id']; // Get the form from the cache. diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index 3086139bdf7..44ea1b87fe1 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -525,7 +525,7 @@ function system_theme_settings(&$form_state, $key = '') { // Process the theme and all its base themes. foreach ($theme_keys as $theme) { // Include the theme-settings.php file. - $filename = './'. str_replace("/$theme.info", '', $themes[$theme]->filename) .'/theme-settings.php'; + $filename = DRUPAL_ROOT . '/'. str_replace("/$theme.info", '', $themes[$theme]->filename) .'/theme-settings.php'; if (file_exists($filename)) { require_once $filename; } @@ -875,7 +875,7 @@ function system_modules_confirm_form($modules, $storage) { * Submit callback; handles modules form submission. */ function system_modules_submit($form, &$form_state) { - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; $new_modules = array(); // If we are coming from the confirm form... @@ -1027,7 +1027,7 @@ function system_module_build_dependencies($modules, $form_values) { */ function system_modules_uninstall($form_state = NULL) { // Make sure the install API is available. - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; // Display the confirm form if any modules have been submitted. if (isset($form_state) && $confirm_form = system_modules_uninstall_confirm_form($form_state['storage'])) { @@ -1128,7 +1128,7 @@ function system_modules_uninstall_validate($form, &$form_state) { */ function system_modules_uninstall_submit($form, &$form_state) { // Make sure the install API is available. - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; if (!empty($form['#confirmed'])) { // Call the uninstall routine for each selected module. @@ -1729,7 +1729,7 @@ function system_clean_url_settings() { */ function system_status($check = FALSE) { // Load .install files - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; drupal_load_updates(); // Check run-time requirements and status information. @@ -1837,7 +1837,7 @@ function system_sql() { * Default page callback for batches. */ function system_batch_page() { - require_once './includes/batch.inc'; + require_once DRUPAL_ROOT . '/includes/batch.inc'; $output = _batch_page(); if ($output === FALSE) { drupal_access_denied(); diff --git a/modules/system/system.install b/modules/system/system.install index 4dc6a2b6113..d0e84fb4436 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -274,7 +274,7 @@ function system_requirements($phase) { } // Test Unicode library - include_once './includes/unicode.inc'; + include_once DRUPAL_ROOT . '/includes/unicode.inc'; $requirements = array_merge($requirements, unicode_requirements()); if ($phase == 'runtime') { diff --git a/modules/system/system.module b/modules/system/system.module index ec30bdd0f9f..a12d9e7d12c 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -702,7 +702,7 @@ function system_theme_select_form($description = '', $default_value = '', $weigh $screenshot = NULL; $theme_key = $info->name; while ($theme_key) { - if (file_exists($themes[$theme_key]->info['screenshot'])) { + if (file_exists(DRUPAL_ROOT . '/' . $themes[$theme_key]->info['screenshot'])) { $screenshot = $themes[$theme_key]->info['screenshot']; break; } @@ -885,7 +885,7 @@ function _system_theme_data() { } if (empty($themes[$key]->info['engine'])) { $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme'; - if (file_exists($filename)) { + if (file_exists(DRUPAL_ROOT . '/' . $filename)) { $themes[$key]->owner = $filename; $themes[$key]->prefix = $key; } diff --git a/modules/update/update.fetch.inc b/modules/update/update.fetch.inc index d1e381277ac..e25a504c4cd 100644 --- a/modules/update/update.fetch.inc +++ b/modules/update/update.fetch.inc @@ -148,7 +148,7 @@ function _update_get_fetch_url_base($project) { * @see update_requirements() */ function _update_cron_notify() { - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; $status = update_requirements('runtime'); $params = array(); $notify_all = (variable_get('update_notification_threshold', 'all') == 'all'); diff --git a/modules/update/update.module b/modules/update/update.module index fd45ed5df79..b4129a5adaf 100644 --- a/modules/update/update.module +++ b/modules/update/update.module @@ -71,7 +71,7 @@ function update_help($path, $arg) { return $output; case 'admin/build/themes': case 'admin/build/modules': - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; $status = update_requirements('runtime'); foreach (array('core', 'contrib') as $report_type) { $type = 'update_'. $report_type; @@ -103,7 +103,7 @@ function update_help($path, $arg) { // update missing, print an error message about it. if (arg(0) == 'admin' && strpos($path, '#') === FALSE && user_access('administer site configuration')) { - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; $status = update_requirements('runtime'); foreach (array('core', 'contrib') as $report_type) { $type = 'update_'. $report_type; diff --git a/themes/engines/phptemplate/phptemplate.engine b/themes/engines/phptemplate/phptemplate.engine index 214e1a41e5f..f9b36490ada 100644 --- a/themes/engines/phptemplate/phptemplate.engine +++ b/themes/engines/phptemplate/phptemplate.engine @@ -11,7 +11,7 @@ function phptemplate_init($template) { $file = dirname($template->filename) .'/template.php'; if (file_exists($file)) { - include_once "./$file"; + include_once DRUPAL_ROOT . "/$file"; } } diff --git a/update.php b/update.php index 44e06987717..e4ef7cdff31 100644 --- a/update.php +++ b/update.php @@ -12,6 +12,11 @@ * be sure to open settings.php again, and change it back to its original state! */ +/** + * Root directory of Drupal installation. + */ +define('DRUPAL_ROOT', getcwd()); + /** * Global flag to identify update.php run, and so avoid various unwanted * operations, such as hook_init() and hook_exit() invokes, css/js preprocessing @@ -590,7 +595,7 @@ function update_check_requirements() { // Our custom error handler is not yet installed, so we just suppress them. ini_set('display_errors', FALSE); -require_once './includes/bootstrap.inc'; +require_once DRUPAL_ROOT . '/includes/bootstrap.inc'; // We only load DRUPAL_BOOTSTRAP_CONFIGURATION for the update requirements // check to avoid reaching the PHP memory limit. @@ -599,12 +604,12 @@ function update_check_requirements() { // Minimum load of components. drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE); - require_once './includes/install.inc'; - require_once './includes/file.inc'; - require_once './modules/system/system.install'; + require_once DRUPAL_ROOT . '/includes/install.inc'; + require_once DRUPAL_ROOT . '/includes/file.inc'; + require_once DRUPAL_ROOT . '/modules/system/system.install'; // Load module basics. - include_once './includes/module.inc'; + include_once DRUPAL_ROOT . '/includes/module.inc'; $module_list['system']['filename'] = 'modules/system/system.module'; $module_list['filter']['filename'] = 'modules/filter/filter.module'; module_list(TRUE, FALSE, FALSE, $module_list); @@ -648,8 +653,8 @@ function update_check_requirements() { if (!empty($update_free_access) || $user->uid == 1) { drupal_session_start(); - include_once './includes/install.inc'; - include_once './includes/batch.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/batch.inc'; drupal_load_updates(); update_fix_d6_requirements(); diff --git a/xmlrpc.php b/xmlrpc.php index 0f0300b184b..e50f276f8ce 100644 --- a/xmlrpc.php +++ b/xmlrpc.php @@ -1,13 +1,18 @@ Date: Tue, 19 Mar 2013 17:41:57 -0400 Subject: [PATCH 18/29] Issue #1080964 by catch: Be more sparing with locale cache clears --- includes/bootstrap.inc | 7 +- includes/locale.inc | 2 +- modules/locale/locale.module | 93 +++++++++++---------- modules/simpletest/drupal_web_test_case.php | 3 +- 4 files changed, 55 insertions(+), 50 deletions(-) diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index cb93bc51027..dd20e18e53c 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -1889,8 +1889,7 @@ function drupal_valid_test_ua($user_agent) { // We use the database credentials from settings.php to make the HMAC key, since // the database is not yet initialized and we can't access any Drupal variables. // The file properties add more entropy not easily accessible to others. -// $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $filepath = './includes/bootstrap.inc'; + $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; // $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE); $key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); // The HMAC must match. @@ -1909,9 +1908,7 @@ function drupal_generate_test_ua($prefix) { // We use the database credentials to make the HMAC key, since we // check the HMAC before the database is initialized. filectime() // and fileinode() are not easily determined from remote. -// $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; - $filepath = './includes/bootstrap.inc'; -// $key = sha1(serialize($databases) . filectime($filepath) . fileinode($filepath), TRUE); + $filepath = DRUPAL_ROOT . '/includes/bootstrap.inc'; $key = sha1(serialize($db_url) . filectime($filepath) . fileinode($filepath), TRUE); } // Generate a moderately secure HMAC based on the database credentials. diff --git a/includes/locale.inc b/includes/locale.inc index 82723701197..affc91893fa 100644 --- a/includes/locale.inc +++ b/includes/locale.inc @@ -2602,7 +2602,7 @@ function _locale_batch_build($files, $finished = NULL, $components = array()) { 'title' => $t('Importing interface translations'), 'init_message' => $t('Starting import'), 'error_message' => $t('Error importing interface translations'), - 'file' => './includes/locale.inc', + 'file' => DRUPAL_ROOT . '/includes/locale.inc', // This is not a batch API construct, but data passed along to the // installer, so we know what did we import already. '#components' => $components, diff --git a/modules/locale/locale.module b/modules/locale/locale.module index 3a25fd62f70..776525372be 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -342,59 +342,68 @@ function locale($string = NULL, $langcode = NULL, $reset = FALSE) { $langcode = isset($langcode) ? $langcode : $language->language; - // Store database cached translations in a static var. - if (!isset($locale_t[$langcode])) { - $locale_t[$langcode] = array(); - // Disabling the usage of string caching allows a module to watch for - // the exact list of strings used on a page. From a performance - // perspective that is a really bad idea, so we have no user - // interface for this. Be careful when turning this option off! - if (variable_get('locale_cache_strings', 1) == 1) { - if ($cache = cache_get('locale:'. $langcode, 'cache')) { - $locale_t[$langcode] = $cache->data; - } - elseif (lock_acquire('locale_cache_' . $langcode)) { - // Refresh database stored cache of translations for given language. - // We only store short strings used in current version, to improve - // performance and consume less memory. - $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION); - while ($data = db_fetch_object($result)) { - $locale_t[$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation); - } - cache_set('locale:'. $langcode, $locale_t[$langcode]); - lock_release('locale_cache_' . $langcode); - } - } - } + // Strings are cached by langcode and user roles, using instances of the + // LocaleLookup class to handle string lookup and caching. + if (!isset($locale_t[$langcode]) && isset($language)) { + $locale_t[$langcode] = new LocaleLookup($langcode); + } - // If we have the translation cached, skip checking the database - if (!isset($locale_t[$langcode][$string])) { + return ($locale_t[$langcode][$string] === TRUE ? $string : $locale_t[$langcode][$string]); +} - // We do not have this translation cached, so get it from the DB. - $translation = db_fetch_object(db_query("SELECT s.lid, t.translation, s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.source = '%s' AND s.textgroup = 'default'", $langcode, $string)); - if ($translation) { - // We have the source string at least. - // Cache translation string or TRUE if no translation exists. - $locale_t[$langcode][$string] = (empty($translation->translation) ? TRUE : $translation->translation); +/** + * Extends CacheArray to allow for dynamic building of the locale cache. + */ +class LocaleLookup extends DrupalCacheArray { + + /** + * A language code. + * @var string + */ + protected $langcode; + + /** + * Constructs a LocaleCache object. + */ + public function __construct($langcode) { + $this->langcode = $langcode; + + // Add the current user's role IDs to the cache key, this ensures that, for + // example, strings for admin menu items and settings forms are not cached + // for anonymous users. + $rids = implode(':', array_keys($GLOBALS['user']->roles)); + parent::__construct("locale:$langcode:$rids", 'cache'); + } + /** + * Overrides DrupalCacheArray::resolveCacheMiss(). + */ + protected function resolveCacheMiss($offset) { + $translation = db_fetch_object(db_query("SELECT s.lid, t.translation, s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.source = '%s' AND s.textgroup = 'default'", $this->langcode, $offset)); + if ($translation) { if ($translation->version != VERSION) { - // This is the first use of this string under current Drupal version. Save version - // and clear cache, to include the string into caching next time. Saved version is - // also a string-history information for later pruning of the tables. + // This is the first use of this string under current Drupal version. + // Update the {locales_source} table to indicate the string is current. db_query("UPDATE {locales_source} SET version = '%s' WHERE lid = %d", VERSION, $translation->lid); - cache_clear_all('locale:', 'cache', TRUE); } + $value = !empty($translation->translation) ? $translation->translation : TRUE; } else { - // We don't have the source string, cache this as untranslated. + // We don't have the source string, update the {locales_source} table to + // indicate the string is not translated. db_query("INSERT INTO {locales_source} (location, source, textgroup, version) VALUES ('%s', '%s', 'default', '%s')", request_uri(), $string, VERSION); - $locale_t[$langcode][$string] = TRUE; - // Clear locale cache so this string can be added in a later request. - cache_clear_all('locale:', 'cache', TRUE); + $value = TRUE; } + $this->storage[$offset] = $value; + // Disabling the usage of string caching allows a module to watch for + // the exact list of strings used on a page. From a performance + // perspective that is a really bad idea, so we have no user + // interface for this. Be careful when turning this option off! + if (variable_get('locale_cache_strings', 1)) { + $this->persist($offset); + } + return $value; } - - return ($locale_t[$langcode][$string] === TRUE ? $string : $locale_t[$langcode][$string]); } /** diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index 6789a8d3e7d..aadf73220b6 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -1109,8 +1109,7 @@ protected function setUp() { ini_set('log_errors', 1); ini_set('error_log', $directory . '/error.log'); -// include_once DRUPAL_ROOT . '/includes/install.inc'; - include_once './includes/install.inc'; + include_once DRUPAL_ROOT . '/includes/install.inc'; drupal_install_system(); // $this->preloadRegistry(); From e08f3da0722b8a16ae55b6b0ea8945cbf5937e97 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 17:44:09 -0400 Subject: [PATCH 19/29] Issue #960056 by cedarm: trigger_get_assigned_actions() has no static cache. --- modules/trigger/trigger.module | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module index 263a2a125ba..70762799a25 100644 --- a/modules/trigger/trigger.module +++ b/modules/trigger/trigger.module @@ -142,12 +142,16 @@ function trigger_access_check($module) { * An array of action IDs. */ function _trigger_get_hook_aids($hook, $op = '') { - $aids = array(); - $result = db_query("SELECT aa.aid, a.type FROM {trigger_assignments} aa LEFT JOIN {actions} a ON aa.aid = a.aid WHERE aa.hook = '%s' AND aa.op = '%s' ORDER BY weight", $hook, $op); - while ($action = db_fetch_object($result)) { - $aids[$action->aid]['type'] = $action->type; + static $hooks; + if (!isset($hooks[$hook][$op])) { + $aids = array(); + $result = db_query("SELECT aa.aid, a.type FROM {trigger_assignments} aa LEFT JOIN {actions} a ON aa.aid = a.aid WHERE aa.hook = '%s' AND aa.op = '%s' ORDER BY weight", $hook, $op); + while ($action = db_fetch_object($result)) { + $aids[$action->aid]['type'] = $action->type; + } + $hooks[$hook][$op] = $aids; } - return $aids; + return $hooks[$hook][$op]; } /** From 470a314738e0f384044016892e7775b61fa86ef0 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 17:45:43 -0400 Subject: [PATCH 20/29] Issue #353595 by hefox: node_access issues four queries on default install node/1 and has no static cache. --- modules/node/node.module | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/modules/node/node.module b/modules/node/node.module index d0ca2142fa4..0ea58d8645f 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -2021,30 +2021,47 @@ function node_search_validate($form, &$form_state) { */ function node_access($op, $node, $account = NULL) { global $user; + static $rights; if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) { // If there was no node to check against, or the $op was not one of the // supported ones, we return access denied. return FALSE; } + // If no user object is supplied, the access check is for the current user. + if (empty($account)) { + $account = $user; + } + + // Cache ID contains user account, op, and NID or node type if op is create. + $cid = $account->uid . $op; // Convert the node to an object if necessary: if ($op != 'create') { $node = (object)$node; + $cid .= $node->nid; } - // If no user object is supplied, the access check is for the current user. - if (empty($account)) { - $account = $user; + // Checking create condition; $node is a string referencing a node type. + else { + $cid .= is_object($node) ? $node->type : $node; + } + + // Return cached value if it exists. + if (isset($rights[$cid])) { + return $rights[$cid]; } // If the node is in a restricted format, disallow editing. if ($op == 'update' && !filter_access($node->format)) { + $rights[$cid] = FALSE; return FALSE; } if (user_access('administer nodes', $account)) { + $rights[$cid] = TRUE; return TRUE; } if (!user_access('access content', $account)) { + $rights[$cid] = FALSE; return FALSE; } @@ -2056,6 +2073,7 @@ function node_access($op, $node, $account = NULL) { } $access = module_invoke($module, 'access', $op, $node, $account); if (!is_null($access)) { + $rights[$cid] = $access; return $access; } @@ -2076,11 +2094,13 @@ function node_access($op, $node, $account = NULL) { $sql = "SELECT 1 FROM {node_access} WHERE (nid = 0 OR nid = %d) $grants_sql AND grant_$op >= 1"; $result = db_query_range($sql, $node->nid, 0, 1); - return (bool) db_result($result); + $rights[$cid] = (bool) db_result($result); + return $rights[$cid]; } // Let authors view their own nodes. if ($op == 'view' && $account->uid == $node->uid && $account->uid != 0) { + $rights[$cid] = TRUE; return TRUE; } From ba7c5b56f81293776726398fb20ebedf00366e81 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 17:46:57 -0400 Subject: [PATCH 21/29] Issue #163018 by catch: taxonomy_get_vocabularies needs static caching. --- modules/taxonomy/taxonomy.module | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module index ae0208ae884..b34b57601a2 100644 --- a/modules/taxonomy/taxonomy.module +++ b/modules/taxonomy/taxonomy.module @@ -497,10 +497,19 @@ function taxonomy_form_all($free_tags = 0) { * If set, return only those vocabularies associated with this node type. */ function taxonomy_get_vocabularies($type = NULL) { + static $vocabularies_cache = array(); + static $vocabularies_null; + if ($type) { + if (isset($vocabularies_cache[$type])) { + return $vocabularies_cache[$type]; + } $result = db_query(db_rewrite_sql("SELECT v.vid, v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $type); } else { + if (is_array($vocabularies_null)) { + return $vocabularies_null; + } $result = db_query(db_rewrite_sql('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid ORDER BY v.weight, v.name', 'v', 'vid')); } @@ -520,7 +529,15 @@ function taxonomy_get_vocabularies($type = NULL) { $vocabularies[$voc->vid] = $voc; } + if ($type) { + $vocabularies_cache[$type] = $vocabularies; + } + else { + $vocabularies_null = $vocabularies; + } + return $vocabularies; + } /** @@ -1075,20 +1092,7 @@ function taxonomy_vocabulary_load($vid, $reset = FALSE) { } if (!isset($vocabularies[$vid])) { - // Initialize so if this vocabulary does not exist, we have - // that cached, and we will not try to load this later. - $vocabularies[$vid] = FALSE; - // Try to load the data and fill up the object. - $result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE v.vid = %d', $vid); - $node_types = array(); - while ($voc = db_fetch_object($result)) { - if (!empty($voc->type)) { - $node_types[$voc->type] = $voc->type; - } - unset($voc->type); - $voc->nodes = $node_types; - $vocabularies[$vid] = $voc; - } + $vocabularies = taxonomy_get_vocabularies(); } // Return FALSE if this vocabulary does not exist. From 932f1322bb0c5dd5137bf24b500ff9704b96d7bf Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 17:47:54 -0400 Subject: [PATCH 22/29] Issue #196862 by mikeytown2: COUNT(*) is an expensive query in InnoDB. --- includes/locale.inc | 2 +- modules/book/book.install | 2 +- modules/menu/menu.admin.inc | 2 +- modules/node/node.admin.inc | 2 +- modules/node/node.module | 8 +++----- modules/path/path.admin.inc | 4 ++-- modules/path/path.module | 2 +- modules/ping/ping.module | 2 +- modules/profile/profile.module | 2 +- modules/profile/profile.pages.inc | 2 +- modules/system/system.module | 4 ++-- modules/user/user.admin.inc | 4 ++-- modules/user/user.module | 4 ++-- 13 files changed, 19 insertions(+), 21 deletions(-) diff --git a/includes/locale.inc b/includes/locale.inc index affc91893fa..3412ecb92b4 100644 --- a/includes/locale.inc +++ b/includes/locale.inc @@ -289,7 +289,7 @@ function _locale_languages_common_controls(&$form, $language = NULL) { function locale_languages_predefined_form_validate($form, &$form_state) { $langcode = $form_state['values']['langcode']; - if ($duplicate = db_result(db_query("SELECT COUNT(*) FROM {languages} WHERE language = '%s'", $langcode)) != 0) { + if ($duplicate = db_result(db_query_range("SELECT 1 FROM {languages} WHERE language = '%s'", $langcode, 0, 1)) != 0) { form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $form_state['values']['name'], '%code' => $langcode))); } diff --git a/modules/book/book.install b/modules/book/book.install index e3172f8b725..94d24bc1b00 100644 --- a/modules/book/book.install +++ b/modules/book/book.install @@ -106,7 +106,7 @@ function book_update_6000() { } // Determine whether there are any existing nodes in the book hierarchy. - if (db_result(db_query("SELECT COUNT(*) FROM {book}"))) { + if (db_result(db_query_range("SELECT 1 FROM {book}", 0, 1))) { // Temporary table for the old book hierarchy; we'll discard revision info. $schema['book_temp'] = array( 'fields' => array( diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc index a62f246e196..84b1b1da21f 100644 --- a/modules/menu/menu.admin.inc +++ b/modules/menu/menu.admin.inc @@ -475,7 +475,7 @@ function menu_delete_menu_confirm_submit($form, &$form_state) { $menu = $form['#menu']; $form_state['redirect'] = 'admin/build/menu'; // System-defined menus may not be deleted - only menus defined by this module. - if (in_array($menu['menu_name'], menu_list_system_menus()) || !db_result(db_query("SELECT COUNT(*) FROM {menu_custom} WHERE menu_name = '%s'", $menu['menu_name']))) { + if (in_array($menu['menu_name'], menu_list_system_menus()) || !db_result(db_query_range("SELECT 1 FROM {menu_custom} WHERE menu_name = '%s'", $menu['menu_name'], 0, 1))) { return; } // Reset all the menu links defined by the system via hook_menu. diff --git a/modules/node/node.admin.inc b/modules/node/node.admin.inc index 41f473032ce..74e0607f83d 100644 --- a/modules/node/node.admin.inc +++ b/modules/node/node.admin.inc @@ -455,7 +455,7 @@ function node_admin_nodes() { $result = pager_query(db_rewrite_sql('SELECT n.*, u.name FROM {node} n '. $filter['join'] .' INNER JOIN {users} u ON n.uid = u.uid '. $filter['where'] .' ORDER BY n.changed DESC'), 50, 0, NULL, $filter['args']); // Enable language column if locale is enabled or if we have any node with language - $count = db_result(db_query("SELECT COUNT(*) FROM {node} n WHERE language != ''")); + $count = db_result(db_query_range("SELECT 1 FROM {node} n WHERE language != ''", 0, 1)); $multilanguage = (module_exists('locale') || $count); $form['options'] = array( diff --git a/modules/node/node.module b/modules/node/node.module index 0ea58d8645f..8e53e1b7a4f 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -490,7 +490,7 @@ function node_types_rebuild() { function node_type_save($info) { $is_existing = FALSE; $existing_type = !empty($info->old_type) ? $info->old_type : $info->type; - $is_existing = db_result(db_query("SELECT COUNT(*) FROM {node_type} WHERE type = '%s'", $existing_type)); + $is_existing = db_result(db_query_range("SELECT 1 FROM {node_type} WHERE type = '%s'", $existing_type, 0, 1)); if (!isset($info->help)) { $info->help = ''; } @@ -2206,9 +2206,7 @@ function node_access_view_all_nodes() { $grants_sql = 'AND ('. implode(' OR ', $grants) .')'; } - $sql = "SELECT COUNT(*) FROM {node_access} WHERE nid = 0 $grants_sql AND grant_view >= 1"; - $result = db_query($sql); - $access = db_result($result); + $access = db_result(db_query_range("SELECT 1 FROM {node_access} WHERE nid = 0 $grants_sql AND grant_view >= 1", 0, 1)); } return $access; @@ -2766,7 +2764,7 @@ function node_assign_owner_action_form($context) { } function node_assign_owner_action_validate($form, $form_state) { - $count = db_result(db_query("SELECT COUNT(*) FROM {users} WHERE name = '%s'", $form_state['values']['owner_name'])); + $count = db_result(db_query_range("SELECT 1 FROM {users} WHERE name = '%s'", $form_state['values']['owner_name'], 0, 1)); if (intval($count) != 1) { form_set_error('owner_name', t('Please enter a valid username.')); } diff --git a/modules/path/path.admin.inc b/modules/path/path.admin.inc index dba0d030037..9c3f7b87936 100644 --- a/modules/path/path.admin.inc +++ b/modules/path/path.admin.inc @@ -14,7 +14,7 @@ function path_admin_overview($keys = NULL) { // Add the filter form above the overview table. $output = drupal_get_form('path_admin_filter_form', $keys); // Enable language column if locale is enabled or if we have any alias with language - $count = db_result(db_query("SELECT COUNT(*) FROM {url_alias} WHERE language != ''")); + $count = db_result(db_query_range("SELECT 1 FROM {url_alias} WHERE language != ''", 0, 1)); $multilanguage = (module_exists('locale') || $count); if ($keys) { @@ -134,7 +134,7 @@ function path_admin_form_validate($form, &$form_state) { // Language is only set if locale module is enabled, otherwise save for all languages. $language = isset($form_state['values']['language']) ? $form_state['values']['language'] : ''; - if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s' AND language = '%s'", $pid, $dst, $language))) { + if (db_result(db_query_range("SELECT 1 FROM {url_alias} WHERE pid != %d AND dst = '%s' AND language = '%s'", $pid, $dst, $language, 0, 1))) { form_set_error('dst', t('The alias %alias is already in use in this language.', array('%alias' => $dst))); } $item = menu_get_item($src); diff --git a/modules/path/path.module b/modules/path/path.module index 953feb25337..5790c12c138 100644 --- a/modules/path/path.module +++ b/modules/path/path.module @@ -180,7 +180,7 @@ function path_nodeapi(&$node, $op, $arg = NULL) { case 'validate': if (isset($node->path)) { $node->path = trim($node->path); - if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE dst = '%s' AND src != '%s' AND language = '%s'", $node->path, "node/$node->nid", $language))) { + if (db_result(db_query_range("SELECT 1 FROM {url_alias} WHERE dst = '%s' AND src != '%s' AND language = '%s'", $node->path, "node/$node->nid", $language, 0, 1))) { form_set_error('path', t('The path is already in use.')); } } diff --git a/modules/ping/ping.module b/modules/ping/ping.module index 6553960d204..12b137028ed 100644 --- a/modules/ping/ping.module +++ b/modules/ping/ping.module @@ -29,7 +29,7 @@ function ping_cron() { if (variable_get('site_name', 0)) { $cron_last = variable_get('cron_last', time()); // Query changed first since usually changed >= created. - if (db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1 AND changed > %d', $cron_last)) || db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1 AND created > %d', $cron_last))) { + if (db_result(db_query_range('SELECT 1 FROM {node} WHERE status = 1 AND changed > %d', $cron_last, 0, 1)) || db_result(db_query_range('SELECT 1 FROM {node} WHERE status = 1 AND created > %d', $cron_last, 0, 1))) { _ping_notify(variable_get('site_name', ''), $base_url); } } diff --git a/modules/profile/profile.module b/modules/profile/profile.module index e8c053904b5..61d4b303bd3 100644 --- a/modules/profile/profile.module +++ b/modules/profile/profile.module @@ -470,7 +470,7 @@ function profile_category_access($account, $category) { return TRUE; } else { - return user_edit_access($account) && db_result(db_query("SELECT COUNT(*) FROM {profile_fields} WHERE category = '%s' AND visibility <> %d", $category, PROFILE_HIDDEN)); + return user_edit_access($account) && db_result(db_query_range("SELECT 1 FROM {profile_fields} WHERE category = '%s' AND visibility <> %d", $category, PROFILE_HIDDEN, 0, 1)); } } diff --git a/modules/profile/profile.pages.inc b/modules/profile/profile.pages.inc index da1b8c5834d..b3c23db3a30 100644 --- a/modules/profile/profile.pages.inc +++ b/modules/profile/profile.pages.inc @@ -108,7 +108,7 @@ function profile_browse() { */ function profile_autocomplete($field, $string) { $matches = array(); - if (db_result(db_query("SELECT COUNT(*) FROM {profile_fields} WHERE fid = %d AND autocomplete = 1", $field))) { + if (db_result(db_query_range("SELECT 1 FROM {profile_fields} WHERE fid = %d AND autocomplete = 1", $field, 0, 1))) { $result = db_query_range("SELECT value FROM {profile_values} WHERE fid = %d AND value LIKE '%s%%' GROUP BY value ORDER BY value ASC", $field, $string, 0, 10); while ($data = db_fetch_object($result)) { $matches[$data->value] = check_plain($data->value); diff --git a/modules/system/system.module b/modules/system/system.module index a12d9e7d12c..9fa852eac75 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -654,7 +654,7 @@ function system_admin_menu_block($item) { function system_admin_theme_submit($form, &$form_state) { // If we're changing themes, make sure the theme has its blocks initialized. if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) { - $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme'])); + $result = db_result(db_query_range("SELECT 1 FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme'], 0, 1)); if (!$result) { system_initialize_theme_blocks($form_state['values']['admin_theme']); } @@ -1086,7 +1086,7 @@ function system_default_region($theme) { */ function system_initialize_theme_blocks($theme) { // Initialize theme's blocks if none already registered. - if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $theme)))) { + if (!(db_result(db_query_range("SELECT 1 FROM {blocks} WHERE theme = '%s'", $theme, 0, 1)))) { $default_theme = variable_get('theme_default', 'garland'); $regions = system_region_list($theme); $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme); diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc index c84fdbcf66f..6ad978487bf 100644 --- a/modules/user/user.admin.inc +++ b/modules/user/user.admin.inc @@ -683,12 +683,12 @@ function user_admin_role() { function user_admin_role_validate($form, &$form_state) { if ($form_state['values']['name']) { if ($form_state['values']['op'] == t('Save role')) { - if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s' AND rid != %d", $form_state['values']['name'], $form_state['values']['rid']))) { + if (db_result(db_query_range("SELECT 1 FROM {role} WHERE name = '%s' AND rid != %d", $form_state['values']['name'], $form_state['values']['rid'], 0, 1))) { form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_state['values']['name']))); } } else if ($form_state['values']['op'] == t('Add role')) { - if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s'", $form_state['values']['name']))) { + if (db_result(db_query_range("SELECT 1 FROM {role} WHERE name = '%s'", $form_state['values']['name'], 0, 1))) { form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_state['values']['name']))); } } diff --git a/modules/user/user.module b/modules/user/user.module index 4e6364722f8..cafc94b3252 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -1616,7 +1616,7 @@ function _user_edit_validate($uid, &$edit) { if ($error = user_validate_name($edit['name'])) { form_set_error('name', $error); } - else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND name = '%s'", $uid, $edit['name'])) > 0) { + else if (db_result(db_query_range("SELECT 1 FROM {users} WHERE uid != %d AND name = '%s'", $uid, $edit['name'], 0, 1)) > 0) { form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name']))); } else if (drupal_is_denied('user', $edit['name'])) { @@ -1628,7 +1628,7 @@ function _user_edit_validate($uid, &$edit) { if ($error = user_validate_mail($edit['mail'])) { form_set_error('mail', $error); } - else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND mail = '%s'", $uid, $edit['mail'])) > 0) { + else if (db_result(db_query_range("SELECT 1 FROM {users} WHERE uid != %d AND mail = '%s'", $uid, $edit['mail'], 0, 1)) > 0) { form_set_error('mail', t('The e-mail address %email is already registered. Have you forgotten your password?', array('%email' => $edit['mail'], '@password' => url('user/password')))); } else if (drupal_is_denied('mail', $edit['mail'])) { From 907a84c6026adf458ea5ea6e88fb01112cd68e64 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 17:49:39 -0400 Subject: [PATCH 23/29] Issue #818818 by mikeytown2: Race Condition when using file_save_data FILE_EXISTS_REPLACE --- includes/file.inc | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/includes/file.inc b/includes/file.inc index c8058a0b108..ced6adcfea0 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -311,7 +311,34 @@ function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) { return FALSE; } - if (!@copy($source, $dest)) { + // Perform the replace operation. Since there could be multiple processes + // writing to the same file, the best option is to create a temporary file in + // the same directory and then rename it to the destination. A temporary file + // is needed if the directory is mounted on a separate machine; thus ensuring + // the rename command stays local. + $result = FALSE; + if ($replace == FILE_EXISTS_REPLACE) { + // Get a temporary filename in the destination directory. + $temporary_file = tempnam(dirname($dest), 'file'); + // Place contents in the temporary file. + if ($temporary_file && @copy($source, $temporary_file)) { + if (!$result = @rename($temporary_file, $dest)) { + // Unlink and try again for windows. Rename on windows does not replace + // the file if it already exists. + @unlink($dest); + $result = @rename($temporary_file, $dest); + } + // Remove temporary_file if rename failed. + if (!$result) { + @unlink($temporary_file); + } + } + } + // Perform the copy operation. + else { + $result = @copy($source, $dest); + } + if ($result === FALSE) { drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error'); return 0; } From 895f06d78e7dbca37d034afb7919041cc1815ee3 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 18:15:11 -0400 Subject: [PATCH 24/29] Issue #667714 by mikeytown2, tinker: Impossible to insert serialized data with update_sql() --- includes/database.inc | 19 ++++++-- includes/database.mysql-common.inc | 35 ++++++++++++++ includes/database.mysql.inc | 71 +++++++++++++++++++--------- includes/database.mysqli.inc | 74 +++++++++++++++++++++--------- includes/database.pgsql.inc | 35 ++++++++++++++ 5 files changed, 188 insertions(+), 46 deletions(-) diff --git a/includes/database.inc b/includes/database.inc index dbb86e1bc55..ff0c422da0d 100644 --- a/includes/database.inc +++ b/includes/database.inc @@ -53,15 +53,28 @@ define('DB_ERROR', 'a515ac9c2796ca0e23adbe92c68fc9fc'); * Perform an SQL query and return success or failure. * * @param $sql - * A string containing a complete SQL query. %-substitution - * parameters are not supported. + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose + * in '') and %%. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * * @return * An array containing the keys: * success: a boolean indicating whether the query succeeded * query: the SQL query executed, passed through check_plain() */ function update_sql($sql) { - $result = db_query($sql, true); + $args = func_get_args(); + array_shift($args); + $result = db_query($sql, $args); + $sql = db_query_get_string($sql, $args); return array('success' => $result !== FALSE, 'query' => check_plain($sql)); } diff --git a/includes/database.mysql-common.inc b/includes/database.mysql-common.inc index ead7f367c94..f10f8766e2a 100644 --- a/includes/database.mysql-common.inc +++ b/includes/database.mysql-common.inc @@ -42,6 +42,41 @@ function db_query($query) { return _db_query($query); } +/** + * Builds a query, returns string. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose + * in '') and %%. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * String of the query fully escaped and ready to run. + */ +function db_query_get_string($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback($args, TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + return $query; +} + /** * @ingroup schemaapi * @{ diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index 7ff85471360..87a6f5d1e40 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -134,34 +134,63 @@ function _db_query($query, $debug = 0, $slave = FALSE) { $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; } - $sent_to_slave = FALSE; - if (isset($active_slave_db) && $slave) { - $result = mysql_query($query, $active_slave_db); - $sent_to_slave = TRUE; - } - else { - $result = mysql_query($query, $active_db); - } + $retry = 0; + do { + $sent_to_slave = FALSE; + if (isset($active_slave_db) && $slave) { + $result = mysql_query($query, $active_slave_db); + $errno = mysql_errno($active_slave_db); + $sent_to_slave = TRUE; + } + else { + $result = mysql_query($query, $active_db); + $errno = mysql_errno($active_db); + } - if (variable_get('dev_query', 0)) { - $query = $bt[2]['function'] ."\n". $query; - list($usec, $sec) = explode(' ', microtime()); - $stop = (float)$usec + (float)$sec; - $diff = $stop - $timer; - $queries[] = array($query, $diff, $sent_to_slave); - } + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff, $sent_to_slave); + } - if (!$sent_to_slave) { - $active_last_db = $active_db; - } else { - $active_last_db = $active_slave_db; - } + // Handle transient errors. + // If we can handle this error, then increment the counter, so we run again. Otherwise + // use the default case to exit the while loop and return an error as per normal. + switch($errno) { + case 1205: // Lock wait timeout exceeded; try restarting transaction + case 1213: // Deadlock found when trying to get lock; try restarting transaction + $retry++; // Increment counter. + break; + + case 1614: // Transaction branch was rolled back: deadlock was detected + case 2013: // Lost connection to MySQL server during query + $retry++; // Increment counter. + if ($sent_to_slave) { + $slave = FALSE; // Retry on master. + } + break; + + // If not an error we can handle (or not an error!) exit the loop. + // We cal deal with fall-out later, as errno is set. + default: + $retry = 2; + break; + } + + if (!$sent_to_slave) { + $active_last_db = $active_db; + } else { + $active_last_db = $active_slave_db; + } + } while ($retry < 2); if ($debug) { print '

query: '. $query .'
error:'. mysql_error($active_db) .'

'; } - if (!mysql_errno($active_last_db)) { + if (!$errno) { return $result; } else { diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index 21083900716..6e48c70335a 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -133,34 +133,64 @@ function _db_query($query, $debug = 0, $slave = FALSE) { $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; } - $sent_to_slave = FALSE; - if (isset($active_slave_db) && $slave) { - $result = mysqli_query($active_slave_db, $query); - $sent_to_slave = TRUE; - } - else { - $result = mysqli_query($active_db, $query); - } + $retry = 0; + do { + $sent_to_slave = FALSE; + if (isset($active_slave_db) && $slave) { + $result = mysqli_query($query, $active_slave_db); + $errno = mysqli_errno($active_slave_db); + $sent_to_slave = TRUE; + } + else { + $result = mysql_query($query, $active_db); + $errno = mysql_errno($active_db); + } - if (variable_get('dev_query', 0)) { - $query = $bt[2]['function'] ."\n". $query; - list($usec, $sec) = explode(' ', microtime()); - $stop = (float)$usec + (float)$sec; - $diff = $stop - $timer; - $queries[] = array($query, $diff, $sent_to_slave); - } + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff, $sent_to_slave); + } + + // Handle transient errors. + // If we can handle this error, then increment the counter, so we run again. Otherwise + // use the default case to exit the while loop and return an error as per normal. + switch($errno) { + case 1205: // Lock wait timeout exceeded; try restarting transaction + case 1213: // Deadlock found when trying to get lock; try restarting transaction + $retry++; // Increment counter. + break; + + case 1614: // Transaction branch was rolled back: deadlock was detected + case 2013: // Lost connection to MySQL server during query + $retry++; // Increment counter. + if ($sent_to_slave) { + $slave = FALSE; // Retry on master. + } + break; + + // If not an error we can handle (or not an error!) exit the loop. + // We cal deal with fall-out later, as errno is set. + default: + $retry = 2; + break; + } + + if (!$sent_to_slave) { + $active_last_db = $active_db; + } else { + $active_last_db = $active_slave_db; + } + } while ($retry < 2); - if (!$sent_to_slave) { - $active_last_db = $active_db; - } else { - $active_last_db = $active_slave_db; - } if ($debug) { print '

query: '. $query .'
error:'. mysqli_error($active_db) .'

'; } - if (!mysqli_errno($active_last_db)) { + if (!$errno) { return $result; } else { @@ -336,7 +366,7 @@ function db_query_range_slave($query) { * * Use this as a substitute for db_query() when the results need to be stored * in a temporary table. - * + * * User-supplied arguments to the query should be passed in as separate parameters * so that they can be properly escaped to avoid SQL injection attacks. * diff --git a/includes/database.pgsql.inc b/includes/database.pgsql.inc index 33166601063..085015486df 100644 --- a/includes/database.pgsql.inc +++ b/includes/database.pgsql.inc @@ -124,6 +124,41 @@ function db_query($query) { return _db_query($query); } +/** + * Builds a query, returns string. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose + * in '') and %%. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * String of the query fully escaped and ready to run. + */ +function db_query_get_string($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback($args, TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + return $query; +} + /** * Helper function for db_query(). */ From a1ef2cdab76c4edd56d267125ccd2d8580f4e987 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 18:26:59 -0400 Subject: [PATCH 25/29] Issue #972528 by mikeytown2, mkalkbrenner: dblog fails to log MAX_ALLOWED_PACKET errors because they're longer than MAX_ALLOWED_PACKET --- includes/database.mysql.inc | 8 ++++++++ includes/database.mysqli.inc | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/includes/database.mysql.inc b/includes/database.mysql.inc index 87a6f5d1e40..1b5ca295528 100644 --- a/includes/database.mysql.inc +++ b/includes/database.mysql.inc @@ -159,6 +159,14 @@ function _db_query($query, $debug = 0, $slave = FALSE) { // If we can handle this error, then increment the counter, so we run again. Otherwise // use the default case to exit the while loop and return an error as per normal. switch($errno) { + case 1153: // Got a packet bigger than "max_allowed_packet" bytes + // If the MySQL Server rejected the query because it's too big, + // writing the query to database watchdog will fail as well + // Truncate the query ... + $retry = 2; + $query = substr($query, 0, 100); + break; + case 1205: // Lock wait timeout exceeded; try restarting transaction case 1213: // Deadlock found when trying to get lock; try restarting transaction $retry++; // Increment counter. diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index 6e48c70335a..2166793aa9d 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -158,6 +158,14 @@ function _db_query($query, $debug = 0, $slave = FALSE) { // If we can handle this error, then increment the counter, so we run again. Otherwise // use the default case to exit the while loop and return an error as per normal. switch($errno) { + case 1153: // Got a packet bigger than "max_allowed_packet" bytes + // If the MySQL Server rejected the query because it's too big, + // writing the query to database watchdog will fail as well + // Truncate the query ... + $retry = 2; + $query = substr($query, 0, 100); + break; + case 1205: // Lock wait timeout exceeded; try restarting transaction case 1213: // Deadlock found when trying to get lock; try restarting transaction $retry++; // Increment counter. From 0dcfca3d949492f28020e94e14546bae230e017b Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 18:29:05 -0400 Subject: [PATCH 26/29] Issue #360377 by janusman: book_get_books() cache becomes stale when batch-inserting book pages --- modules/book/book.module | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/book/book.module b/modules/book/book.module index 56f839a33c6..65f17784cff 100644 --- a/modules/book/book.module +++ b/modules/book/book.module @@ -251,11 +251,14 @@ function theme_book_title_link($link) { * * This list may be used for generating a list of all the books, or for building * the options for a form select. + * + * @param $reset + * Reset the cache of stored books. */ -function book_get_books() { +function book_get_books($reset = FALSE) { static $all_books; - if (!isset($all_books)) { + if ($reset || !isset($all_books)) { $all_books = array(); $result = db_query("SELECT DISTINCT(bid) FROM {book}"); $nids = array(); @@ -463,12 +466,16 @@ function _book_update_outline(&$node) { if ($new) { // Insert new. db_query("INSERT INTO {book} (nid, mlid, bid) VALUES (%d, %d, %d)", $node->nid, $node->book['mlid'], $node->book['bid']); + // Reset the cache of stored books. + book_get_books(TRUE); } else { if ($node->book['bid'] != db_result(db_query("SELECT bid FROM {book} WHERE nid = %d", $node->nid))) { // Update the bid for this page and all children. book_update_bid($node->book); } + // Reset the cache of stored books. + book_get_books(TRUE); } return TRUE; } @@ -712,6 +719,8 @@ function book_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { } menu_link_delete($node->book['mlid']); db_query('DELETE FROM {book} WHERE mlid = %d', $node->book['mlid']); + // Reset the cache of stored books. + book_get_books(TRUE); } break; case 'prepare': From 7d8cdc5582d0c25efc0a0d036f375a597b8f3311 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Tue, 19 Mar 2013 19:35:41 -0400 Subject: [PATCH 27/29] Issue #476048 by mikeytown2: MySQL transient error handling --- includes/database.mysqli.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/database.mysqli.inc b/includes/database.mysqli.inc index 2166793aa9d..0bfddf51ab2 100644 --- a/includes/database.mysqli.inc +++ b/includes/database.mysqli.inc @@ -137,13 +137,13 @@ function _db_query($query, $debug = 0, $slave = FALSE) { do { $sent_to_slave = FALSE; if (isset($active_slave_db) && $slave) { - $result = mysqli_query($query, $active_slave_db); + $result = mysqli_query($active_slave_db, $query); $errno = mysqli_errno($active_slave_db); $sent_to_slave = TRUE; } else { - $result = mysql_query($query, $active_db); - $errno = mysql_errno($active_db); + $result = mysqli_query($active_db, $query); + $errno = mysqli_errno($active_db); } if (variable_get('dev_query', 0)) { From cb7df7a282fd43976ebfa88c2be79214bde208fc Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Fri, 22 Mar 2013 17:30:28 -0400 Subject: [PATCH 28/29] php 5.4 fixes --- includes/form.inc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/includes/form.inc b/includes/form.inc index 5f273fdfa4e..25baf686f98 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -302,7 +302,7 @@ function drupal_execute($form_id, &$form_state) { // Make sure $form_state is passed around by reference. $args[1] = &$form_state; - + $form = call_user_func_array('drupal_retrieve_form', $args); $form['#post'] = $form_state['values']; @@ -773,8 +773,8 @@ function form_execute_handlers($type, &$form, &$form_state) { foreach ($handlers as $function) { if (function_exists($function)) { - // Check to see if a previous _submit handler has set a batch, but - // make sure we do not react to a batch that is already being processed + // Check to see if a previous _submit handler has set a batch, but + // make sure we do not react to a batch that is already being processed // (for instance if a batch operation performs a drupal_execute()). if ($type == 'submit' && ($batch =& batch_get()) && !isset($batch['current_set'])) { // Some previous _submit handler has set a batch. We store the call @@ -900,7 +900,7 @@ function form_builder($form_id, $form, &$form_state) { // Recurse through all child elements. $count = 0; foreach (element_children($form) as $key) { - $form[$key]['#post'] = $form['#post']; + $form[$key]['#post'] = isset($form['#post']) ? $form['#post'] : NULL; $form[$key]['#programmed'] = $form['#programmed']; // Don't squash an existing tree value. if (!isset($form[$key]['#tree'])) { @@ -1342,6 +1342,9 @@ function form_set_value($form_item, $value, &$form_state) { function _form_set_value(&$form_values, $form_item, $parents, $value) { $parent = array_shift($parents); if (empty($parents)) { + if (!is_array($form_values)) { + $form_values = array(); + } $form_values[$parent] = $value; } else { @@ -2127,7 +2130,6 @@ function theme_textarea($element) { * * @ingroup themeable */ - function theme_markup($element) { return (isset($element['#value']) ? $element['#value'] : '') . (isset($element['#children']) ? $element['#children'] : ''); } From f9498387cf7593b8b07714af6b937d27bb545f43 Mon Sep 17 00:00:00 2001 From: mikeytown2 Date: Fri, 22 Mar 2013 17:32:01 -0400 Subject: [PATCH 29/29] Fix file mode --- modules/simpletest/run-tests.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 modules/simpletest/run-tests.sh diff --git a/modules/simpletest/run-tests.sh b/modules/simpletest/run-tests.sh old mode 100755 new mode 100644