diff options
-rw-r--r-- | CHANGELOG.txt | 2 | ||||
-rw-r--r-- | INSTALL.txt | 66 | ||||
-rw-r--r-- | database/database.mysql | 4 | ||||
-rw-r--r-- | database/database.pgsql | 4 | ||||
-rw-r--r-- | includes/bootstrap.inc | 42 | ||||
-rw-r--r-- | includes/common.inc | 94 | ||||
-rw-r--r-- | includes/file.inc | 54 | ||||
-rw-r--r-- | includes/module.inc | 78 | ||||
-rw-r--r-- | modules/system.module | 263 | ||||
-rw-r--r-- | modules/system/system.module | 263 | ||||
-rw-r--r-- | sites/default/settings.php (renamed from includes/conf.php) | 0 | ||||
-rw-r--r-- | themes/engines/xtemplate/xtemplate.engine | 6 |
12 files changed, 466 insertions, 410 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e2e94231c..bd00c8ae2 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -14,6 +14,8 @@ Drupal x.x.x, xxxx-xx-xx - usability: * refactored the throttle module configuration. * added a 'add child page' link to book pages. +- multi-site configuration: + * made it possible to run multiple sites from a single code base. - performance: * improved performance of the forum topics block. * improved performance of the tracker module. diff --git a/INSTALL.txt b/INSTALL.txt index 66da5ad45..837046d50 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -103,15 +103,8 @@ INSTALLATION 4. CONNECTING DRUPAL - Drupal server options are specified in includes/conf.php. - - Drupal allows for multiple virtual host installations; to configure - a virtual server host, you can create the configuration file - - includes/www.example.com.php - - where www.example.com is your website's URL. - + The default configuration can be found in the + 'sites/default/settings.php' file within your Drupal installation. Before you can run Drupal, you must set the database URL and the base URL to the web site. Open the configuration file and edit the $db_url line to match the database defined in the previous steps: @@ -122,6 +115,61 @@ INSTALLATION $base_url = "http://www.example.com"; + In addition, a single Drupal installation can host several + Drupal-powered sites, each with its own individual configuration. + If you don't need to run multiple Drupal sites, you can skip to the + next section. + + Additional site configurations are created in subdirectories within + the 'sites' directory. Each site subdirectory must have a + 'settings.php' file which specifies the configuration settings. The + easiest way to create additional sites is to copy the 'default' + directory and modify the 'settings.php' file as appropriate. The new + directory name is constructed from the site's URL. The + configuration for www.example.com could be in + 'sites/example.com/settings.php' (note that 'www.' should be omitted + if users can access your site at http://example.com/). + + Sites do not each have to have a different domain. You can use + subdomains and subdirectories for Drupal sites also. For example, + example.com, sub.example.com, and sub.example.com/site3 can all be + defined as independent Drupal sites. The setup for a configuration + such as this would look like the following: + + sites/default/settings.php + sites/example.com/settings.php + sites/sub.example.com/settings.php + sites/sub.example.com.site3/settings.php + + When searching for a site configuration (for example + www.sub.example.com/site3), Drupal will search for configuration + files in the following order, using the first configuration file it + finds: + + sites/www.sub.example.com.site3/settings.php + sites/sub.example.com.site3/settings.php + sites/example.com.site3/settings.php + sites/www.sub.example.com/settings.php + sites/sub.example.com/settings.php + sites/example.com/settings.php + sites/default/settings.php + + Each site configuration can have its own site-specific modules and + themes that will be made available in addition to those installed + in the standard 'modules' and 'themes' directories. To use + site-specific modules or themes, simply create a 'modules' or + 'themes' directory within the site configuration directory. For + example, if sub.example.dom has a custom theme and a custom module + that should not be accessible to other sites, the setup would look + like this: + + sites/sub.example.com/: + settings.php + themes/: + custom_theme + modules/: + custom_module + NOTE: for more information about multiple virtual hosts or the configuration settings, consult the Drupal handbook at drupal.org. diff --git a/database/database.mysql b/database/database.mysql index 767ea08e2..9f2ef285f 100644 --- a/database/database.mysql +++ b/database/database.mysql @@ -767,11 +767,15 @@ CREATE TABLE watchdog ( INSERT INTO system VALUES ('modules/admin.module','admin','module','',1,0,0); INSERT INTO system VALUES ('modules/block.module','block','module','',1,0,0); INSERT INTO system VALUES ('modules/comment.module','comment','module','',1,0,0); +INSERT INTO system VALUES ('modules/filter.module','filter','module','',1,0,0); INSERT INTO system VALUES ('modules/help.module','help','module','',1,0,0); INSERT INTO system VALUES ('modules/node.module','node','module','',1,0,0); INSERT INTO system VALUES ('modules/page.module','page','module','',1,0,0); INSERT INTO system VALUES ('modules/story.module','story','module','',1,0,0); +INSERT INTO system VALUES ('modules/system.module','system','module','',1,0,0); INSERT INTO system VALUES ('modules/taxonomy.module','taxonomy','module','',1,0,0); +INSERT INTO system VALUES ('modules/user.module','user','module','',1,0,0); +INSERT INTO system VALUES ('modules/watchdog.module','watchdog','module','',1,0,0); INSERT INTO system VALUES ('themes/bluemarine/xtemplate.xtmpl','bluemarine','theme','themes/engines/xtemplate/xtemplate.engine',1,0,0); INSERT INTO system VALUES ('themes/engines/xtemplate/xtemplate.engine','xtemplate','theme_engine','',1,0,0); INSERT INTO users (uid, name, mail) VALUES ('0', '', ''); diff --git a/database/database.pgsql b/database/database.pgsql index 1ebd958d5..92ba88c67 100644 --- a/database/database.pgsql +++ b/database/database.pgsql @@ -751,11 +751,15 @@ CREATE TABLE watchdog ( INSERT INTO system VALUES ('modules/admin.module','admin','module','',1,0,0); INSERT INTO system VALUES ('modules/block.module','block','module','',1,0,0); INSERT INTO system VALUES ('modules/comment.module','comment','module','',1,0,0); +INSERT INTO system VALUES ('modules/filter.module','filter','module','',1,0,0); INSERT INTO system VALUES ('modules/help.module','help','module','',1,0,0); INSERT INTO system VALUES ('modules/node.module','node','module','',1,0,0); INSERT INTO system VALUES ('modules/page.module','page','module','',1,0,0); INSERT INTO system VALUES ('modules/story.module','story','module','',1,0,0); +INSERT INTO system VALUES ('modules/system.module','system','module','',1,0,0); INSERT INTO system VALUES ('modules/taxonomy.module','taxonomy','module','',1,0,0); +INSERT INTO system VALUES ('modules/user.module','user','module','',1,0,0); +INSERT INTO system VALUES ('modules/watchdog.module','watchdog','module','',1,0,0); INSERT INTO system VALUES ('themes/bluemarine/xtemplate.xtmpl','bluemarine','theme','themes/engines/xtemplate/xtemplate.engine',1,0,0); INSERT INTO system VALUES ('themes/engines/xtemplate/xtemplate.engine','xtemplate','theme_engine','',1,0,0); diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index b1da3b337..a0d783910 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -12,25 +12,41 @@ define('CACHE_TEMPORARY', -1); /** * Locate the appropriate configuration file. * - * Try finding a matching configuration file by stripping the website's - * URI from left to right. If no configuration file is found, return the - * default value, "conf". + * Try finding a matching configuration directory by stripping the + * website's hostname from left to right and pathname from right to + * left. If no configuration file is found, return a default value + * '$confdir/default'. Example for a ficticious site installed at + * http://www.drupal.org/test: + * + * 1. www.drupal.org.test + * 2. drupal.org.test + * 3. www.drupal.org + * 4. drupal.org + * 5. default */ function conf_init() { - $uri = $_SERVER['PHP_SELF']; + static $conf = ''; - $file = strtolower(strtr($_SERVER['HTTP_HOST'] . substr($uri, 0, strrpos($uri, '/')), '/:', '..')); + if ($conf) { + return $conf; + } - while (strlen($file) > 4) { - if (file_exists('includes/'. $file .'.php')) { - return $file; - } - else { - $file = substr($file, strpos($file, '.') + 1); + $uri = explode('/', $_SERVER['PHP_SELF']); + $server = explode('.', $_SERVER['HTTP_HOST']); + $confdir = 'sites'; + 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")) { + $conf = "$confdir/$dir"; + return $conf; + } } } - return 'conf'; +print "$confdir/default/settings.php<br />"; + $conf = "$confdir/default"; + return $conf; } /** @@ -442,7 +458,7 @@ function drupal_get_messages() { unset($conf); $config = conf_init(); -include_once "includes/$config.php"; +include_once "$config/settings.php"; include_once 'includes/database.inc'; include_once 'includes/session.inc'; include_once 'includes/module.inc'; diff --git a/includes/common.inc b/includes/common.inc index d65ebe7a2..3da8bda85 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -1836,6 +1836,100 @@ function drupal_eval($code) { return $output; } +/** + * Returns and optionally sets the filename for a system item (module, + * theme, etc.). The filename, whether provided, cached, or retrieved + * from the database, is only returned if the file exists. + * + * @param $type + * The type of the item (i.e. theme, theme_engine, module). + * @param $name + * The name of the item for which the filename is requested. + * @param $filename + * The filename of the item if it is to be set explicitly rather + * than by consulting the database. + * + * @return + * The filename of the requested item. + */ +function drupal_get_filename($type, $name, $filename = NULL) { + static $files = array(); + + if (!$files[$type]) { + $files[$type] = array(); + } + + if ($filename && file_exists($filename)) { + $files[$type][$name] = $filename; + } + elseif ($files[$type][$name]) { + // nothing + } + elseif (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file)) { + $files[$type][$name] = $file; + } + else { + $config = conf_init(); + $dir = (($type == 'theme_engine') ? 'themes/engines' : "${type}s"); + $file = "$name.$type"; + + foreach (array("$config/$dir/$file", "$config/$dir/$name/$file", "$dir/$file", "$dir/$name/$file") as $file) { + if (file_exists($file)) { + $files[$type][$name] = $file; + break; + } + } + } + + return $files[$type][$name]; +} + +/** + * Returns the path to a system item (module, theme, etc.). + * + * @param $type + * The type of the item (i.e. theme, theme_engine, module). + * @param $name + * The name of the item for which the path is requested. + * + * @return + * The path to the requested item. + */ +function drupal_get_path($type, $name) { + return dirname(drupal_get_filename($type, $name)); +} + +/** + * Includes a file with the provided type and name. This prevents + * including a theme, engine, module, etc., more than once. + * + * @param $type + * The type of item to load (i.e. theme, theme_engine, module). + * @param $name + * The name of the item to load. + * + * @return + * TRUE if the item is loaded or has already been loaded. + */ +function drupal_load($type, $name) { + static $files = array(); + + if ($files[$type][$name]) { + return TRUE; + } + + $filename = drupal_get_filename($type, $name); + + if ($filename) { + include_once($filename); + $files[$type][$name] = TRUE; + + return TRUE; + } + + return FALSE; +} + include_once 'includes/theme.inc'; include_once 'includes/pager.inc'; include_once 'includes/menu.inc'; diff --git a/includes/file.inc b/includes/file.inc index 0eda14c6c..7c467ad17 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -469,39 +469,59 @@ function file_download() { } /** - * Finds all files that match a given mask in a given directory. + * Finds all files that match a given mask in a given + * directory. * - * @param $dir Directory to scan - * @param $mask Regular expression to filter out files. Only filenames that - * match the mask will be returned. - * @param $nomask Array of filenames which should never be returned regardless - * if they match the $mask - * @param $callback Function to call for qualifying file. - * Set to 0 or false if you do not want callbacks. - * @param $recurse When true directory scan will recurse the entire tree starting at $dir - * @return Array of qualifying files + * @param $dir + * The base directory for the scan. + * @param $mask + * The regular expression of the files to find. + * @param $nomask + * An array of files/directories to ignore. + * @param $callback + * The callback function to call for each match. + * @param $recurse + * When TRUE, the directory scan will recurse the entire tree + * starting at the provided directory. + * @param $key + * The key to be used for the returned array of files. Possible + * values are "filename", for the path starting with $dir, + * "basename", for the basename of the file, and "name" for the name + * of the file without an extension. + * + * @return + * An associative array (keyed on the provided key) of objects with + * "path", "basename", and "name" members corresponding to the + * matching files. */ -function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE) { +function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE, $key = 'filename') { + $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename'); $files = array(); + if (is_dir($dir) && $handle = opendir($dir)) { while ($file = readdir($handle)) { if (!in_array($file, $nomask)) { if (is_dir("$dir/$file") && $recurse) { - $files = array_merge($files, file_scan_directory("$dir/$file", $mask, $nomask, $callback)); + $files = array_merge($files, file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key)); } elseif (ereg($mask, $file)) { - $name = basename($file); - $files["$dir/$file"] = new stdClass(); - $files["$dir/$file"]->filename = "$dir/$file"; - $files["$dir/$file"]->name = substr($name, 0, strrpos($name, '.')); + $filename = "$dir/$file"; + $basename = basename($file); + $name = substr($basename, 0, strrpos($basename, '.')); + $files[$$key] = new stdClass(); + $files[$$key]->filename = $filename; + $files[$$key]->basename = $basename; + $files[$$key]->name = $name; if ($callback) { - $callback("$dir/$file"); + $callback($filename); } } } } + closedir($handle); } + return $files; } diff --git a/includes/module.inc b/includes/module.inc index e4ac60dda..e5a68d7f1 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -61,8 +61,8 @@ function module_list($refresh = FALSE, $bootstrap = FALSE) { // variables, since throttle.module may not be loaded yet. $throttle = ($module->throttle && variable_get('throttle_level', 0) > 0); if (!$throttle) { + drupal_get_filename('module', $module->name, $module->filename); $list[$module->name] = $module->name; - module_set_filename($module->name, $module->filename); } } } @@ -72,85 +72,19 @@ function module_list($refresh = FALSE, $bootstrap = FALSE) { } /** - * Set the filename of a module, for future loading through module_load() - * - * @param $module - * Name of the module which to specify the filename of. - * @param $pa - * Filename of the module named $module. - * @return - * Filename of module, if no $path has been specified. - */ -function module_set_filename($module, $path = null) { - static $list; - - if ($path) { - $list[$module] = $path; - } - else { - return $list[$module] ? $list[$module] : "modules/$module.module"; - } -} - -/** - * Retrieve the filename of a module - * - * @param $module - * Name of the module which to retrieve the filename of. - * @return - * Filename of module. - */ -function module_get_filename($module) { - return module_set_filename($module); -} - -/** - * Retrieve the path of a module - * - * @param $module - * Name of the module which to retrieve the path of. - * @return - * Path of module. - */ -function module_get_path($module) { - return dirname(module_get_filename($module)); -} - -/** - * Load a module into Drupal, but check first whether a module by the same name - * has been loaded, and that the filename being included exists. - * @param $module - * The name of the module to be loaded. - * @return - * TRUE if the load was successful. - */ -function module_load($module) { - static $loaded = array(); - - if (!$loaded[$module]) { - $filename = module_get_filename($module); - if (file_exists($filename)) { - include_once($filename); - $loaded[$module] = $filename; - return true; - } - } - return false; -} - - -/** * Load all the modules that have been enabled in the system table. * * @return - * TRUE if all modules were loaded successfully + * TRUE if all modules were loaded successfully. */ function module_load_all() { $list = module_list(); - $status = true; + $status = TRUE; + foreach ($list as $module) { - $status &= module_load($module); + $status = (drupal_load('module', $module) && $status); } + return $status; } diff --git a/modules/system.module b/modules/system.module index 3b07b9da3..5ecfe82dd 100644 --- a/modules/system.module +++ b/modules/system.module @@ -271,177 +271,148 @@ function system_view_general() { } /** - * Inventory theme engines and insert entries for them into the system table - */ -function system_theme_engine_inventory($directory) { - $engines = array(); - - // Remove all theme engines from the system table - db_query('DELETE FROM {system} WHERE type = \'%s\'', 'theme_engine'); - - // Find theme engines in the directory and insert into database - $files = file_scan_directory($directory. '/engines', '\.engine$'); - - foreach ($files as $filename => $file) { - module_set_filename($file->name, $filename); - module_load($file->name); - - $info = new StdClass(); - $info->name = $file->name; - $info->filename = $file->filename; - $engines[$info->name] = $info; - - db_query('INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, 'theme_engine', $filename, 1, 0, 0); - } - return $engines; -} - -/** - * Retrieves an array of a particular type of files (specified by $type) in a particular $directory - * and their current status in the system table. - */ -function system_get_files($search, $type, $directory) { - // Find files in the directory. - $files = file_scan_directory($directory, $search); - - return $files; -} - -/** * Retrieves the current status of an array of files in the system table. */ function system_get_files_database(&$files, $type) { // Extract current files from database. - $result = db_query('SELECT filename, type, status, throttle FROM {system} WHERE type = \'%s\'', $type); + $result = db_query("SELECT name, type, status, throttle FROM {system} WHERE type = '%s'", $type); while ($file = db_fetch_object($result)) { - if (is_object($files[$file->filename])) { + if (is_object($files[$file->name])) { foreach ($file as $key => $value) { - $files[$file->filename]->$key = $value; + if (!$files[$file->name]->$key) { + $files[$file->name]->$key = $value; + } } } } } /** - * Obtains information about each theme in the $files array - * Also updates the system table - */ -function system_obtain_theme_info($files, $directory) { - foreach ($files as $filename => $file) { - $info = new StdClass(); - if ($file->theme) { - // file is a style - $info->description = $file->theme; - $info->style = TRUE; - } - - if (strpos($filename, '.theme')) { - // file is a theme - module_set_filename($file->name, $filename); - module_load($file->name); - $info->description = ''; - $info->prefix = basename($filename, '.theme'); - } - elseif ($info->style && !$file->engine) { - $info->prefix = $info->description; - } - else { - // file is a template - $info->description = $info->style ? $info->description : $file->engine; - $info->template = TRUE; - $info->prefix = basename($file->engine, '.engine'); - } - - $info->filename = $filename; - $info->path = pathinfo($info->filename); - $info->name = str_replace(array($directory .'/'), '', $info->path['dirname']); - $info->shortname = basename($info->name); - $info->screenshot = dirname($info->filename) .'/screenshot.png'; - - $info->status = $file->status; - - $themes[$info->name] = $info; - - // Update the contents of the system table: - db_query('DELETE FROM {system} WHERE filename = \'%s\' AND type = \'%s\'', $info->filename, 'theme'); - db_query('INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, $info->description, 'theme', $info->filename, $info->status, 0, 0); - } - return $themes; -} - -/** * Collect data about all currently available themes */ -function system_theme_data($directory) { +function system_theme_data() { + // Find themes + $themes = system_listing('\.theme$', 'themes'); + // Find theme engines - $engines = system_theme_engine_inventory($directory); + $engines = system_listing('\.engine$', 'themes/engines'); + + // can't iterate over array itself as it uses a copy of the array items + foreach (array_keys($themes) as $key) { + drupal_get_filename('theme', $themes[$key]->name, $themes[$key]->filename); + drupal_load('theme', $themes[$key]->name); + $themes[$key]->description = dirname($themes[$key]->filename); + $themes[$key]->owner = $themes[$key]->filename; + $themes[$key]->prefix = $key; + } - // Get current list of themes and their present status in the system table. - $files = system_get_files('\.theme$', 'theme', $directory); + // Remove all theme engines from the system table + db_query("DELETE FROM {system} WHERE type = 'theme_engine'"); // Add templates to the site listing foreach ($engines as $engine) { - foreach (call_user_func($engine->name .'_templates', $directory) as $template) { - $template_files[$template->filename] = $template; - $template_files[$template->filename]->engine = $engine->filename; - foreach ($files as $file) { - // do not double-insert templates with theme files in their directory - if (dirname($template->filename) == dirname($file->filename)) { - unset($template_files[$template->filename]); - } - } + drupal_get_filename('theme_engine', $engine->name, $engine->filename); + drupal_load('theme_engine', $engine->name); + db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0); + + foreach (call_user_func($engine->name . '_templates') as $template) { + $template->template = TRUE; + $template->name = basename(dirname($template->filename)); + $template->basename = $template->name; + $template->description = dirname($template->filename); + $template->owner = $engine->filename; + $template->prefix = $engine->name; + $themes[$template->name] = $template; } } - $files = array_merge($files, $template_files); // Find styles in each theme's directory. - foreach ($files as $file) { - foreach (system_get_files("style.css$", 'theme', dirname($file->filename)) as $style) { + foreach ($themes as $theme) { + foreach (file_scan_directory(dirname($theme->filename), 'style.css$') as $style) { // do not double-insert themes with css files in their directory - if (dirname($style->filename) != dirname($file->filename)) { - $style_files[$style->filename] = $style; - $path = pathinfo($file->filename); - $style_files[$style->filename]->theme = str_replace(array($directory .'/'), '', $path['dirname']); - if ($file->engine) { - $style_files[$style->filename]->engine = $file->engine; - } + if (dirname($style->filename) != dirname($theme->filename)) { + $style->style = TRUE; + $style->name = basename(dirname($style->filename)); + $style->description = dirname($style->filename); + $style->owner = $theme->filename; + $style->prefix = $theme->name; + $themes[$style->name] = $style; } } } - $files = array_merge($files, $style_files); // Extract current files from database. - system_get_files_database($files, 'theme'); + system_get_files_database($themes, 'theme'); + + db_query("DELETE FROM {system} WHERE type = 'theme'"); - // Build an array of information about each theme for use in displaying the selection table. - return system_obtain_theme_info($files, $directory); + foreach ($themes as $theme) { + db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, 'theme', $theme->filename, $theme->status, 0, 0); + } + + return $themes; +} + +/** + * Returns an array of files objects of the given type from both the + * site-wide directory (i.e. modules/) and site-specific directory + * (i.e. sites/somesite/modules/). The returned array will be keyed + * using the key specified (name, basename, filename). Using name or + * basename will cause site-specific files to shadow files in the + * default directories. That is, if a file with the same name appears + * in both location, only the site-specific version will be included. + * + * @param $mask + * The regular expression of the files to find. + * @param $directory + * The subdirectory name in which the files are found. For example, + * 'modules' will search in both modules/ and + * sites/somesite/modules/. + * @param $key + * The key to be passed to file_scan_directory(). + * + * @return + * An array of file objects of the specified type. + */ +function system_listing($mask, $directory, $key = 'name') { + $config = conf_init(); + $searchdir = array($directory); + $files = array(); + + if (file_exists("$config/$directory")) { + $searchdir[] = "$config/$directory"; + } + + // Get current list of items + foreach ($searchdir as $dir) { + $files = array_merge($files, file_scan_directory($dir, $mask, array('.', '..', 'CVS'), 0, TRUE, $key)); + } + + return $files; } /** * Generate a list of all the available theme/style combinations. */ function system_theme_listing() { - $directory = 'themes'; - - $themes = system_theme_data($directory); + $themes = system_theme_data(); ksort($themes); - foreach ($themes as $key => $info) { + foreach ($themes as $name => $info) { + $info->screenshot = dirname($info->filename) . '/screenshot.png'; $row = array(); // Screenshot column. - $row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->shortname)), '', 'class="screenshot"', false) : t('no screenshot'); + $row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', 'class="screenshot"', false) : t('no screenshot'); // Information field. - $field = '<strong>'. $info->shortname .'</strong>'; - $field .= '<br /><em>themes/'. $key .'</em>'; - $row[] = $field; + $row[] = "<strong>$info->name</strong><br /><em>$info->description</em>"; // enabled, default, and operations columns - $row[] = array('data' => form_checkbox('', 'status]['. $info->filename, 1, $info->status), 'align' => 'center'); - $row[] = array('data' => form_radio('', 'theme_default', $info->filename, (variable_get('theme_default', 'bluemarine') == $key) ? 1 : 0), 'align' => 'center'); - if (function_exists($info->prefix .'_settings') || function_exists($info->prefix .'_features')) { - $row[] = array('data' => l(t('configure'), 'admin/themes/settings/'. str_replace('/', '.', $key)), 'align' => 'center'); + $row[] = array('data' => form_checkbox('', 'status]['. $info->name, 1, $info->status), 'align' => 'center'); + $row[] = array('data' => form_radio('', 'theme_default', $info->name, (variable_get('theme_default', 'bluemarine') == $name) ? 1 : 0), 'align' => 'center'); + if (function_exists($info->prefix . '_settings') || function_exists($info->prefix . '_features')) { + $row[] = array('data' => l(t('configure'), 'admin/themes/settings/' . str_replace('/', '.', preg_replace('<^.*themes/(.*)$>', '$1', $info->description))), 'align' => 'center'); } else { $row[] = ''; @@ -459,18 +430,16 @@ function system_theme_listing() { * Generate a list of all the available modules, as well as update the system list. */ function system_module_listing() { - $directory = 'modules'; - // Get current list of modules - $files = system_get_files('\.module$', 'module', $directory); + $files = system_listing('\.module$', 'modules'); // Extract current files from database. system_get_files_database($files, 'module'); ksort($files); - $required = array('modules/admin.module', 'modules/block.module', 'modules/filter.module', 'modules/system.module', 'modules/user.module', 'modules/watchdog.module'); - $throttle_required = array_merge($required, array('modules/throttle.module')); + $required = array('admin', 'block', 'filter', 'system', 'user', 'watchdog'); + $throttle_required = array_merge($required, array('throttle')); $header = array(t('Name'), t('Description'), t('Enabled')); if (module_exist('throttle')) { @@ -478,12 +447,11 @@ function system_module_listing() { } foreach ($files as $filename => $file) { - module_set_filename($file->name, $filename); - module_load($file->name); + drupal_get_filename('module', $file->name, $file->filename); + drupal_load('module', $file->name); + + $file->description = module_invoke($file->name, 'help', 'admin/modules#description'); - $info = new StdClass(); - $info->name = module_invoke($file->name, 'help', 'admin/modules#name') ? module_invoke($file->name, 'help', 'admin/modules#name') : $file->name; - $info->description = module_invoke($file->name, 'help', 'admin/modules#description'); // log the critical hooks implemented by this module $bootstrap = 0; foreach (bootstrap_hooks() as $hook) { @@ -494,12 +462,12 @@ function system_module_listing() { } // Update the contents of the system table: - db_query('DELETE FROM {system} WHERE filename = \'%s\' AND type = \'%s\'', $filename, 'module'); - db_query('INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, $info->description, 'module', $filename, $file->status, $file->throttle, $bootstrap); + db_query("DELETE FROM {system} WHERE name = '%s' AND type = '%s'", $file->name, 'module'); + db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, $file->description, 'module', $file->filename, $file->status, $file->throttle, $bootstrap); - $row = array($info->name, $info->description, array('data' => (in_array($filename, $required) ? form_hidden('status]['. $filename, 1) . t('required') : form_checkbox('', 'status]['. $filename, 1, $file->status)), 'align' => 'center')); + $row = array($file->name, $file->description, array('data' => (in_array($file->name, $required) ? form_hidden("status][$file->name", 1) . t('required') : form_checkbox('', "status][$file->name", 1, $file->status)), 'align' => 'center')); if (module_exist('throttle')) { - $row[] = array('data' => (in_array($filename, $throttle_required) ? form_hidden('throttle]['. $filename, 0) . t('required') : form_checkbox(NULL, 'throttle]['. $filename, 1, $file->throttle, NULL)), 'align' => 'center'); + $row[] = array('data' => (in_array($file->name, $throttle_required) ? form_hidden("throttle][$file->name", 0) . t('required') : form_checkbox(NULL, "throttle][$file->name", 1, $file->throttle, NULL)), 'align' => 'center'); } $rows[] = $row; } @@ -516,18 +484,17 @@ function system_listing_save($edit = array()) { if ($op == t('Save configuration')) { db_query("UPDATE {system} SET status = 0 WHERE type = '%s'", $edit['type']); - foreach ($edit['status'] as $filename => $status) { + foreach ($edit['status'] as $name => $status) { // Make certain that the default theme is enabled to avoid user error - if (($edit['type'] == 'theme') && ($edit['theme_default'] == $filename)) { + if (($edit['type'] == 'theme') && ($edit['theme_default'] == $name)) { $status = 1; } - db_query("UPDATE {system} SET status = %d, throttle = %d WHERE filename = '%s'", $status, $edit['throttle'][$filename], $filename); + db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", $status, $edit['throttle'][$name], $edit['type'], $name); } + if ($edit['type'] == 'theme') { - $path = pathinfo($edit['theme_default']); - $name = str_replace(array('themes/'), '', $path['dirname']); - variable_set('theme_default', $name); + variable_set('theme_default', $edit['theme_default']); } cache_clear_all(); @@ -620,8 +587,8 @@ function system_theme_settings() { if ($key) { $settings = theme_get_settings($key); $var = str_replace('/', '_', 'theme_'. $key .'_settings'); - $themes = system_theme_data('themes'); - $features = function_exists($themes[$key]->prefix .'_features') ? call_user_func($themes[$key]->prefix .'_features') : array(); + $themes = system_theme_data(); + $features = function_exists($themes[$key]->prefix . '_features') ? call_user_func($themes[$key]->prefix . '_features') : array(); } else { $settings = theme_get_settings(''); diff --git a/modules/system/system.module b/modules/system/system.module index 3b07b9da3..5ecfe82dd 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -271,177 +271,148 @@ function system_view_general() { } /** - * Inventory theme engines and insert entries for them into the system table - */ -function system_theme_engine_inventory($directory) { - $engines = array(); - - // Remove all theme engines from the system table - db_query('DELETE FROM {system} WHERE type = \'%s\'', 'theme_engine'); - - // Find theme engines in the directory and insert into database - $files = file_scan_directory($directory. '/engines', '\.engine$'); - - foreach ($files as $filename => $file) { - module_set_filename($file->name, $filename); - module_load($file->name); - - $info = new StdClass(); - $info->name = $file->name; - $info->filename = $file->filename; - $engines[$info->name] = $info; - - db_query('INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, 'theme_engine', $filename, 1, 0, 0); - } - return $engines; -} - -/** - * Retrieves an array of a particular type of files (specified by $type) in a particular $directory - * and their current status in the system table. - */ -function system_get_files($search, $type, $directory) { - // Find files in the directory. - $files = file_scan_directory($directory, $search); - - return $files; -} - -/** * Retrieves the current status of an array of files in the system table. */ function system_get_files_database(&$files, $type) { // Extract current files from database. - $result = db_query('SELECT filename, type, status, throttle FROM {system} WHERE type = \'%s\'', $type); + $result = db_query("SELECT name, type, status, throttle FROM {system} WHERE type = '%s'", $type); while ($file = db_fetch_object($result)) { - if (is_object($files[$file->filename])) { + if (is_object($files[$file->name])) { foreach ($file as $key => $value) { - $files[$file->filename]->$key = $value; + if (!$files[$file->name]->$key) { + $files[$file->name]->$key = $value; + } } } } } /** - * Obtains information about each theme in the $files array - * Also updates the system table - */ -function system_obtain_theme_info($files, $directory) { - foreach ($files as $filename => $file) { - $info = new StdClass(); - if ($file->theme) { - // file is a style - $info->description = $file->theme; - $info->style = TRUE; - } - - if (strpos($filename, '.theme')) { - // file is a theme - module_set_filename($file->name, $filename); - module_load($file->name); - $info->description = ''; - $info->prefix = basename($filename, '.theme'); - } - elseif ($info->style && !$file->engine) { - $info->prefix = $info->description; - } - else { - // file is a template - $info->description = $info->style ? $info->description : $file->engine; - $info->template = TRUE; - $info->prefix = basename($file->engine, '.engine'); - } - - $info->filename = $filename; - $info->path = pathinfo($info->filename); - $info->name = str_replace(array($directory .'/'), '', $info->path['dirname']); - $info->shortname = basename($info->name); - $info->screenshot = dirname($info->filename) .'/screenshot.png'; - - $info->status = $file->status; - - $themes[$info->name] = $info; - - // Update the contents of the system table: - db_query('DELETE FROM {system} WHERE filename = \'%s\' AND type = \'%s\'', $info->filename, 'theme'); - db_query('INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, $info->description, 'theme', $info->filename, $info->status, 0, 0); - } - return $themes; -} - -/** * Collect data about all currently available themes */ -function system_theme_data($directory) { +function system_theme_data() { + // Find themes + $themes = system_listing('\.theme$', 'themes'); + // Find theme engines - $engines = system_theme_engine_inventory($directory); + $engines = system_listing('\.engine$', 'themes/engines'); + + // can't iterate over array itself as it uses a copy of the array items + foreach (array_keys($themes) as $key) { + drupal_get_filename('theme', $themes[$key]->name, $themes[$key]->filename); + drupal_load('theme', $themes[$key]->name); + $themes[$key]->description = dirname($themes[$key]->filename); + $themes[$key]->owner = $themes[$key]->filename; + $themes[$key]->prefix = $key; + } - // Get current list of themes and their present status in the system table. - $files = system_get_files('\.theme$', 'theme', $directory); + // Remove all theme engines from the system table + db_query("DELETE FROM {system} WHERE type = 'theme_engine'"); // Add templates to the site listing foreach ($engines as $engine) { - foreach (call_user_func($engine->name .'_templates', $directory) as $template) { - $template_files[$template->filename] = $template; - $template_files[$template->filename]->engine = $engine->filename; - foreach ($files as $file) { - // do not double-insert templates with theme files in their directory - if (dirname($template->filename) == dirname($file->filename)) { - unset($template_files[$template->filename]); - } - } + drupal_get_filename('theme_engine', $engine->name, $engine->filename); + drupal_load('theme_engine', $engine->name); + db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0); + + foreach (call_user_func($engine->name . '_templates') as $template) { + $template->template = TRUE; + $template->name = basename(dirname($template->filename)); + $template->basename = $template->name; + $template->description = dirname($template->filename); + $template->owner = $engine->filename; + $template->prefix = $engine->name; + $themes[$template->name] = $template; } } - $files = array_merge($files, $template_files); // Find styles in each theme's directory. - foreach ($files as $file) { - foreach (system_get_files("style.css$", 'theme', dirname($file->filename)) as $style) { + foreach ($themes as $theme) { + foreach (file_scan_directory(dirname($theme->filename), 'style.css$') as $style) { // do not double-insert themes with css files in their directory - if (dirname($style->filename) != dirname($file->filename)) { - $style_files[$style->filename] = $style; - $path = pathinfo($file->filename); - $style_files[$style->filename]->theme = str_replace(array($directory .'/'), '', $path['dirname']); - if ($file->engine) { - $style_files[$style->filename]->engine = $file->engine; - } + if (dirname($style->filename) != dirname($theme->filename)) { + $style->style = TRUE; + $style->name = basename(dirname($style->filename)); + $style->description = dirname($style->filename); + $style->owner = $theme->filename; + $style->prefix = $theme->name; + $themes[$style->name] = $style; } } } - $files = array_merge($files, $style_files); // Extract current files from database. - system_get_files_database($files, 'theme'); + system_get_files_database($themes, 'theme'); + + db_query("DELETE FROM {system} WHERE type = 'theme'"); - // Build an array of information about each theme for use in displaying the selection table. - return system_obtain_theme_info($files, $directory); + foreach ($themes as $theme) { + db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, 'theme', $theme->filename, $theme->status, 0, 0); + } + + return $themes; +} + +/** + * Returns an array of files objects of the given type from both the + * site-wide directory (i.e. modules/) and site-specific directory + * (i.e. sites/somesite/modules/). The returned array will be keyed + * using the key specified (name, basename, filename). Using name or + * basename will cause site-specific files to shadow files in the + * default directories. That is, if a file with the same name appears + * in both location, only the site-specific version will be included. + * + * @param $mask + * The regular expression of the files to find. + * @param $directory + * The subdirectory name in which the files are found. For example, + * 'modules' will search in both modules/ and + * sites/somesite/modules/. + * @param $key + * The key to be passed to file_scan_directory(). + * + * @return + * An array of file objects of the specified type. + */ +function system_listing($mask, $directory, $key = 'name') { + $config = conf_init(); + $searchdir = array($directory); + $files = array(); + + if (file_exists("$config/$directory")) { + $searchdir[] = "$config/$directory"; + } + + // Get current list of items + foreach ($searchdir as $dir) { + $files = array_merge($files, file_scan_directory($dir, $mask, array('.', '..', 'CVS'), 0, TRUE, $key)); + } + + return $files; } /** * Generate a list of all the available theme/style combinations. */ function system_theme_listing() { - $directory = 'themes'; - - $themes = system_theme_data($directory); + $themes = system_theme_data(); ksort($themes); - foreach ($themes as $key => $info) { + foreach ($themes as $name => $info) { + $info->screenshot = dirname($info->filename) . '/screenshot.png'; $row = array(); // Screenshot column. - $row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->shortname)), '', 'class="screenshot"', false) : t('no screenshot'); + $row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', 'class="screenshot"', false) : t('no screenshot'); // Information field. - $field = '<strong>'. $info->shortname .'</strong>'; - $field .= '<br /><em>themes/'. $key .'</em>'; - $row[] = $field; + $row[] = "<strong>$info->name</strong><br /><em>$info->description</em>"; // enabled, default, and operations columns - $row[] = array('data' => form_checkbox('', 'status]['. $info->filename, 1, $info->status), 'align' => 'center'); - $row[] = array('data' => form_radio('', 'theme_default', $info->filename, (variable_get('theme_default', 'bluemarine') == $key) ? 1 : 0), 'align' => 'center'); - if (function_exists($info->prefix .'_settings') || function_exists($info->prefix .'_features')) { - $row[] = array('data' => l(t('configure'), 'admin/themes/settings/'. str_replace('/', '.', $key)), 'align' => 'center'); + $row[] = array('data' => form_checkbox('', 'status]['. $info->name, 1, $info->status), 'align' => 'center'); + $row[] = array('data' => form_radio('', 'theme_default', $info->name, (variable_get('theme_default', 'bluemarine') == $name) ? 1 : 0), 'align' => 'center'); + if (function_exists($info->prefix . '_settings') || function_exists($info->prefix . '_features')) { + $row[] = array('data' => l(t('configure'), 'admin/themes/settings/' . str_replace('/', '.', preg_replace('<^.*themes/(.*)$>', '$1', $info->description))), 'align' => 'center'); } else { $row[] = ''; @@ -459,18 +430,16 @@ function system_theme_listing() { * Generate a list of all the available modules, as well as update the system list. */ function system_module_listing() { - $directory = 'modules'; - // Get current list of modules - $files = system_get_files('\.module$', 'module', $directory); + $files = system_listing('\.module$', 'modules'); // Extract current files from database. system_get_files_database($files, 'module'); ksort($files); - $required = array('modules/admin.module', 'modules/block.module', 'modules/filter.module', 'modules/system.module', 'modules/user.module', 'modules/watchdog.module'); - $throttle_required = array_merge($required, array('modules/throttle.module')); + $required = array('admin', 'block', 'filter', 'system', 'user', 'watchdog'); + $throttle_required = array_merge($required, array('throttle')); $header = array(t('Name'), t('Description'), t('Enabled')); if (module_exist('throttle')) { @@ -478,12 +447,11 @@ function system_module_listing() { } foreach ($files as $filename => $file) { - module_set_filename($file->name, $filename); - module_load($file->name); + drupal_get_filename('module', $file->name, $file->filename); + drupal_load('module', $file->name); + + $file->description = module_invoke($file->name, 'help', 'admin/modules#description'); - $info = new StdClass(); - $info->name = module_invoke($file->name, 'help', 'admin/modules#name') ? module_invoke($file->name, 'help', 'admin/modules#name') : $file->name; - $info->description = module_invoke($file->name, 'help', 'admin/modules#description'); // log the critical hooks implemented by this module $bootstrap = 0; foreach (bootstrap_hooks() as $hook) { @@ -494,12 +462,12 @@ function system_module_listing() { } // Update the contents of the system table: - db_query('DELETE FROM {system} WHERE filename = \'%s\' AND type = \'%s\'', $filename, 'module'); - db_query('INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, $info->description, 'module', $filename, $file->status, $file->throttle, $bootstrap); + db_query("DELETE FROM {system} WHERE name = '%s' AND type = '%s'", $file->name, 'module'); + db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, $file->description, 'module', $file->filename, $file->status, $file->throttle, $bootstrap); - $row = array($info->name, $info->description, array('data' => (in_array($filename, $required) ? form_hidden('status]['. $filename, 1) . t('required') : form_checkbox('', 'status]['. $filename, 1, $file->status)), 'align' => 'center')); + $row = array($file->name, $file->description, array('data' => (in_array($file->name, $required) ? form_hidden("status][$file->name", 1) . t('required') : form_checkbox('', "status][$file->name", 1, $file->status)), 'align' => 'center')); if (module_exist('throttle')) { - $row[] = array('data' => (in_array($filename, $throttle_required) ? form_hidden('throttle]['. $filename, 0) . t('required') : form_checkbox(NULL, 'throttle]['. $filename, 1, $file->throttle, NULL)), 'align' => 'center'); + $row[] = array('data' => (in_array($file->name, $throttle_required) ? form_hidden("throttle][$file->name", 0) . t('required') : form_checkbox(NULL, "throttle][$file->name", 1, $file->throttle, NULL)), 'align' => 'center'); } $rows[] = $row; } @@ -516,18 +484,17 @@ function system_listing_save($edit = array()) { if ($op == t('Save configuration')) { db_query("UPDATE {system} SET status = 0 WHERE type = '%s'", $edit['type']); - foreach ($edit['status'] as $filename => $status) { + foreach ($edit['status'] as $name => $status) { // Make certain that the default theme is enabled to avoid user error - if (($edit['type'] == 'theme') && ($edit['theme_default'] == $filename)) { + if (($edit['type'] == 'theme') && ($edit['theme_default'] == $name)) { $status = 1; } - db_query("UPDATE {system} SET status = %d, throttle = %d WHERE filename = '%s'", $status, $edit['throttle'][$filename], $filename); + db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", $status, $edit['throttle'][$name], $edit['type'], $name); } + if ($edit['type'] == 'theme') { - $path = pathinfo($edit['theme_default']); - $name = str_replace(array('themes/'), '', $path['dirname']); - variable_set('theme_default', $name); + variable_set('theme_default', $edit['theme_default']); } cache_clear_all(); @@ -620,8 +587,8 @@ function system_theme_settings() { if ($key) { $settings = theme_get_settings($key); $var = str_replace('/', '_', 'theme_'. $key .'_settings'); - $themes = system_theme_data('themes'); - $features = function_exists($themes[$key]->prefix .'_features') ? call_user_func($themes[$key]->prefix .'_features') : array(); + $themes = system_theme_data(); + $features = function_exists($themes[$key]->prefix . '_features') ? call_user_func($themes[$key]->prefix . '_features') : array(); } else { $settings = theme_get_settings(''); diff --git a/includes/conf.php b/sites/default/settings.php index 365d4fd68..365d4fd68 100644 --- a/includes/conf.php +++ b/sites/default/settings.php diff --git a/themes/engines/xtemplate/xtemplate.engine b/themes/engines/xtemplate/xtemplate.engine index 253e3e85a..b92c2d959 100644 --- a/themes/engines/xtemplate/xtemplate.engine +++ b/themes/engines/xtemplate/xtemplate.engine @@ -10,15 +10,15 @@ function xtemplate_init($template) { // We cannot use the theme() or path_to_theme() functions here if (!class_exists('XTemplate')) { - include_once('themes/engines/xtemplate/xtemplate.inc'); + include_once(dirname(__FILE__) . '/xtemplate.inc'); } $GLOBALS["xtemplate"] = new StdClass(); $GLOBALS['xtemplate']->template = new XTemplate(basename($template->filename), dirname($template->filename)); $GLOBALS['xtemplate']->template->SetNullBlock(' '); // '' doesn't work! } -function xtemplate_templates($directory) { - return file_scan_directory($directory, 'xtemplate.xtmpl$'); +function xtemplate_templates() { + return system_listing('^xtemplate\.xtmpl$', 'themes', 'filename'); } function xtemplate_features() { |