| Line # | Frequency | Source Line | | 1 | | <?php |
| 2 | | // $Id: install.inc,v 1.58 2008/02/12 13:45:16 dries Exp $ |
| 3 | | |
| 4 | 1 | define('SCHEMA_UNINSTALLED', -1); |
| 5 | 1 | define('SCHEMA_INSTALLED', 0); |
| 6 | | |
| 7 | 1 | define('REQUIREMENT_INFO', -1); |
| 8 | 1 | define('REQUIREMENT_OK', 0); |
| 9 | 1 | define('REQUIREMENT_WARNING', 1); |
| 10 | 1 | define('REQUIREMENT_ERROR', 2); |
| 11 | | |
| 12 | 1 | define('FILE_EXIST', 1); |
| 13 | 1 | define('FILE_READABLE', 2); |
| 14 | 1 | define('FILE_WRITABLE', 4); |
| 15 | 1 | define('FILE_EXECUTABLE', 8); |
| 16 | 1 | define('FILE_NOT_EXIST', 16); |
| 17 | 1 | define('FILE_NOT_READABLE', 32); |
| 18 | 1 | define('FILE_NOT_WRITABLE', 64); |
| 19 | 1 | define('FILE_NOT_EXECUTABLE', 128); |
| 20 | | |
| 21 | | /** |
| 22 | | * Initialize the update system by loading all installed module's .install files. |
| 23 | | */ |
| 24 | | function drupal_load_updates() { |
| 25 | | foreach (drupal_get_installed_schema_version(NULL, FALSE, TRUE) as $module => $schema_version) { |
| 26 | | if ($schema_version > -1) { |
| 27 | | module_load_install($module); |
| 28 | | } |
| 29 | | } |
| 30 | | } |
| 31 | | |
| 32 | | /** |
| 33 | | * Returns an array of available schema versions for a module. |
| 34 | | * |
| 35 | | * @param $module |
| 36 | | * A module name. |
| 37 | | * @return |
| 38 | | * If the module has updates, an array of available updates. Otherwise, |
| 39 | | * FALSE. |
| 40 | | */ |
| 41 | | function drupal_get_schema_versions($module) { |
| 42 | | $updates = array(); |
| 43 | 1 | $functions = get_defined_functions(); |
| 44 | 1 | foreach ($functions['user'] as $function) { |
| 45 | 1 | if (strpos($function, $module .'_update_') === 0) { |
| 46 | 1 | $version = substr($function, strlen($module .'_update_')); |
| 47 | 1 | if (is_numeric($version)) { |
| 48 | 1 | $updates[] = $version; |
| 49 | | } |
| 50 | | } |
| 51 | | } |
| 52 | 1 | if (count($updates) == 0) { |
| 53 | 1 | return FALSE; |
| 54 | | } |
| 55 | 1 | return $updates; |
| 56 | | } |
| 57 | | |
| 58 | | /** |
| 59 | | * Returns the currently installed schema version for a module. |
| 60 | | * |
| 61 | | * @param $module |
| 62 | | * A module name. |
| 63 | | * @param $reset |
| 64 | | * Set to TRUE after modifying the system table. |
| 65 | | * @param $array |
| 66 | | * Set to TRUE if you want to get information about all modules in the |
| 67 | | * system. |
| 68 | | * @return |
| 69 | | * The currently installed schema version. |
| 70 | | */ |
| 71 | | function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) { |
| 72 | | static $versions = array(); |
| 73 | | |
| 74 | 1 | if ($reset) { |
| 75 | | $versions = array(); |
| 76 | | } |
| 77 | | |
| 78 | 1 | if (!$versions) { |
| 79 | | $versions = array(); |
| 80 | 1 | $result = db_query("SELECT name, schema_version FROM {system} WHERE type = '%s'", 'module'); |
| 81 | 1 | while ($row = db_fetch_object($result)) { |
| 82 | 1 | $versions[$row->name] = $row->schema_version; |
| 83 | | } |
| 84 | | } |
| 85 | | |
| 86 | 1 | return $array ? $versions : $versions[$module]; |
| 87 | | } |
| 88 | | |
| 89 | | /** |
| 90 | | * Update the installed version information for a module. |
| 91 | | * |
| 92 | | * @param $module |
| 93 | | * A module name. |
| 94 | | * @param $version |
| 95 | | * The new schema version. |
| 96 | | */ |
| 97 | | function drupal_set_installed_schema_version($module, $version) { |
| 98 | 1 | db_query("UPDATE {system} SET schema_version = %d WHERE name = '%s'", $version, $module); |
| 99 | | } |
| 100 | | |
| 101 | | /** |
| 102 | | * Loads the profile definition, extracting the profile's defined name. |
| 103 | | * |
| 104 | | * @return |
| 105 | | * The name defined in the profile's _profile_details() hook. |
| 106 | | */ |
| 107 | | function drupal_install_profile_name() { |
| 108 | | global $profile; |
| 109 | | static $name = NULL; |
| 110 | | |
| 111 | | if (!isset($name)) { |
| 112 | | // Load profile details. |
| 113 | | $function = $profile .'_profile_details'; |
| 114 | | if (function_exists($function)) { |
| 115 | | $details = $function(); |
| 116 | | } |
| 117 | | $name = isset($details['name']) ? $details['name'] : 'Drupal'; |
| 118 | | } |
| 119 | | |
| 120 | | return $name; |
| 121 | | } |
| 122 | | |
| 123 | | /** |
| 124 | | * Auto detect the base_url with PHP predefined variables. |
| 125 | | * |
| 126 | | * @param $file |
| 127 | | * The name of the file calling this function so we can strip it out of |
| 128 | | * the URI when generating the base_url. |
| 129 | | * |
| 130 | | * @return |
| 131 | | * The auto-detected $base_url that should be configured in settings.php |
| 132 | | */ |
| 133 | | function drupal_detect_baseurl($file = 'install.php') { |
| 134 | | global $profile; |
| 135 | | $proto = $_SERVER['HTTPS'] ? 'https://' : 'http://'; |
| 136 | | $host = $_SERVER['SERVER_NAME']; |
| 137 | | $port = ($_SERVER['SERVER_PORT'] == 80 ? '' : ':'. $_SERVER['SERVER_PORT']); |
| 138 | | $uri = preg_replace("/\?.*/", '', $_SERVER['REQUEST_URI']); |
| 139 | | $dir = str_replace("/$file", '', $uri); |
| 140 | | |
| 141 | | return "$proto$host$port$dir"; |
| 142 | | } |
| 143 | | |
| 144 | | /** |
| 145 | | * Detect all databases supported by Drupal that are compiled into the current |
| 146 | | * PHP installation. |
| 147 | | * |
| 148 | | * @return |
| 149 | | * An array of database types compiled into PHP. |
| 150 | | */ |
| 151 | | function drupal_detect_database_types() { |
| 152 | | $databases = array(); |
| 153 | | |
| 154 | | foreach (array('mysql', 'mysqli', 'pgsql') as $type) { |
| 155 | | if (file_exists('./includes/install.'. $type .'.inc')) { |
| 156 | | include_once './includes/install.'. $type .'.inc'; |
| 157 | | $function = $type .'_is_available'; |
| 158 | | if ($function()) { |
| 159 | | $databases[$type] = $type; |
| 160 | | } |
| 161 | | } |
| 162 | | } |
| 163 | | |
| 164 | | return $databases; |
| 165 | | } |
| 166 | | |
| 167 | | /** |
| 168 | | * Read settings.php into a buffer line by line, changing values specified in |
| 169 | | * $settings array, then over-writing the old settings.php file. |
| 170 | | * |
| 171 | | * @param $settings |
| 172 | | * An array of settings that need to be updated. |
| 173 | | */ |
| 174 | | function drupal_rewrite_settings($settings = array(), $prefix = '') { |
| 175 | | $default_settings = './sites/default/default.settings.php'; |
| 176 | | $settings_file = './'. conf_path(FALSE, TRUE) .'/'. $prefix .'settings.php'; |
| 177 | | |
| 178 | | // Build list of setting names and insert the values into the global namespace. |
| 179 | | $keys = array(); |
| 180 | | foreach ($settings as $setting => $data) { |
| 181 | | $GLOBALS[$setting] = $data['value']; |
| 182 | | $keys[] = $setting; |
| 183 | | } |
| 184 | | |
| 185 | | $buffer = NULL; |
| 186 | | $first = TRUE; |
| 187 | | if ($fp = fopen($default_settings, 'r')) { |
| 188 | | // Step line by line through settings.php. |
| 189 | | while (!feof($fp)) { |
| 190 | | $line = fgets($fp); |
| 191 | | if ($first && substr($line, 0, 5) != '<?php') { |
| 192 | | $buffer = "<?php\n\n"; |
| 193 | | } |
| 194 | | $first = FALSE; |
| 195 | | // Check for constants. |
| 196 | | if (substr($line, 0, 7) == 'define(') { |
| 197 | | preg_match('/define\(\s*[\'"]([A-Z_-]+)[\'"]\s*,(.*?)\);/', $line, $variable); |
| 198 | | if (in_array($variable[1], $keys)) { |
| 199 | | $setting = $settings[$variable[1]]; |
| 200 | | $buffer .= str_replace($variable[2], " '". $setting['value'] ."'", $line); |
| 201 | | unset($settings[$variable[1]]); |
| 202 | | unset($settings[$variable[2]]); |
| 203 | | } |
| 204 | | else { |
| 205 | | $buffer .= $line; |
| 206 | | } |
| 207 | | } |
| 208 | | // Check for variables. |
| 209 | | elseif (substr($line, 0, 1) == '$') { |
| 210 | | preg_match('/\$([^ ]*) /', $line, $variable); |
| 211 | | if (in_array($variable[1], $keys)) { |
| 212 | | // Write new value to settings.php in the following format: |
| 213 | | // $'setting' = 'value'; // 'comment' |
| 214 | | $setting = $settings[$variable[1]]; |
| 215 | | $buffer .= '$'. $variable[1] ." = '". $setting['value'] ."';". (!empty($setting['comment']) ? ' // '. $setting['comment'] ."\n" : "\n"); |
| 216 | | unset($settings[$variable[1]]); |
| 217 | | } |
| 218 | | else { |
| 219 | | $buffer .= $line; |
| 220 | | } |
| 221 | | } |
| 222 | | else { |
| 223 | | $buffer .= $line; |
| 224 | | } |
| 225 | | } |
| 226 | | fclose($fp); |
| 227 | | |
| 228 | | // Add required settings that were missing from settings.php. |
| 229 | | foreach ($settings as $setting => $data) { |
| 230 | | if ($data['required']) { |
| 231 | | $buffer .= "\$$setting = '". $data['value'] ."';\n"; |
| 232 | | } |
| 233 | | } |
| 234 | | |
| 235 | | $fp = fopen($settings_file, 'w'); |
| 236 | | if ($fp && fwrite($fp, $buffer) === FALSE) { |
| 237 | | drupal_set_message(st('Failed to modify %settings, please verify the file permissions.', array('%settings' => $settings_file)), 'error'); |
| 238 | | } |
| 239 | | } |
| 240 | | else { |
| 241 | | drupal_set_message(st('Failed to open %settings, please verify the file permissions.', array('%settings' => $default_settings)), 'error'); |
| 242 | | } |
| 243 | | } |
| 244 | | |
| 245 | | /** |
| 246 | | * Get list of all .install files. |
| 247 | | * |
| 248 | | * @param $module_list |
| 249 | | * An array of modules to search for their .install files. |
| 250 | | */ |
| 251 | | function drupal_get_install_files($module_list = array()) { |
| 252 | | $installs = array(); |
| 253 | | foreach ($module_list as $module) { |
| 254 | | $installs = array_merge($installs, drupal_system_listing($module .'.install$', 'modules')); |
| 255 | | } |
| 256 | | return $installs; |
| 257 | | } |
| 258 | | |
| 259 | | /** |
| 260 | | * Verify a profile for installation. |
| 261 | | * |
| 262 | | * @param profile |
| 263 | | * Name of profile to verify. |
| 264 | | * @param locale |
| 265 | | * Name of locale used (if any). |
| 266 | | * @return |
| 267 | | * The list of modules to install. |
| 268 | | */ |
| 269 | | function drupal_verify_profile($profile, $locale) { |
| 270 | | include_once './includes/file.inc'; |
| 271 | | include_once './includes/common.inc'; |
| 272 | | |
| 273 | 1 | $profile_file = "./profiles/$profile/$profile.profile"; |
| 274 | | |
| 275 | 1 | if (!isset($profile) || !file_exists($profile_file)) { |
| 276 | | install_no_profile_error(); |
| 277 | | } |
| 278 | | |
| 279 | | require_once($profile_file); |
| 280 | | |
| 281 | | // Get a list of modules required by this profile. |
| 282 | 1 | $function = $profile .'_profile_modules'; |
| 283 | 1 | $module_list = array_merge(drupal_required_modules(), $function(), ($locale != 'en' ? array('locale') : array())); |
| 284 | | |
| 285 | | // Get a list of modules that exist in Drupal's assorted subdirectories. |
| 286 | | $present_modules = array(); |
| 287 | 1 | foreach (drupal_system_listing('\.module$', 'modules', 'name', 0) as $present_module) { |
| 288 | 1 | $present_modules[] = $present_module->name; |
| 289 | | } |
| 290 | | |
| 291 | | // Verify that all of the profile's required modules are present. |
| 292 | 1 | $missing_modules = array_diff($module_list, $present_modules); |
| 293 | 1 | if (count($missing_modules)) { |
| 294 | | foreach ($missing_modules as $module) { |
| 295 | | drupal_set_message(st('The %module module is required but was not found. Please move it into the <em>modules</em> subdirectory.', array('%module' => $module)), 'error'); |
| 296 | | } |
| 297 | | } |
| 298 | | else { |
| 299 | 1 | return $module_list; |
| 300 | | } |
| 301 | | } |
| 302 | | |
| 303 | | /** |
| 304 | | * Calls the install function and updates the system table for a given list of |
| 305 | | * modules. |
| 306 | | * |
| 307 | | * @param module_list |
| 308 | | * The modules to install. |
| 309 | | */ |
| 310 | | function drupal_install_modules($module_list = array()) { |
| 311 | 1 | $files = module_rebuild_cache(); |
| 312 | 1 | $module_list = array_flip(array_values($module_list)); |
| 313 | | do { |
| 314 | 1 | $moved = FALSE; |
| 315 | 1 | foreach ($module_list as $module => $weight) { |
| 316 | 1 | $file = $files[$module]; |
| 317 | 1 | if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) { |
| 318 | 1 | foreach ($file->info['dependencies'] as $dependency) { |
| 319 | | if (isset($module_list[$dependency]) && $module_list[$module] < $module_list[$dependency] +1) { |
| 320 | | $module_list[$module] = $module_list[$dependency] +1; |
| 321 | | $moved = TRUE; |
| 322 | | } |
| 323 | | } |
| 324 | | } |
| 325 | | } |
| 326 | | } while ($moved); |
| 327 | 1 | asort($module_list); |
| 328 | 1 | $module_list = array_keys($module_list); |
| 329 | 1 | array_filter($module_list, '_drupal_install_module'); |
| 330 | 1 | module_enable($module_list); |
| 331 | | } |
| 332 | | |
| 333 | | /** |
| 334 | | * Callback to install an individual profile module. |
| 335 | | * |
| 336 | | * Used during installation to install modules one at a time and then |
| 337 | | * enable them, or to install a number of modules at one time |
| 338 | | * from admin/build/modules. |
| 339 | | */ |
| 340 | | function _drupal_install_module($module) { |
| 341 | 1 | if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) { |
| 342 | 1 | module_load_install($module); |
| 343 | 1 | module_invoke($module, 'install'); |
| 344 | 1 | $versions = drupal_get_schema_versions($module); |
| 345 | 1 | drupal_set_installed_schema_version($module, $versions ? max($versions) : SCHEMA_INSTALLED); |
| 346 | 1 | return TRUE; |
| 347 | | } |
| 348 | | } |
| 349 | | |
| 350 | | /** |
| 351 | | * Callback to install the system module. |
| 352 | | * |
| 353 | | * Separated from the installation of other modules so core system |
| 354 | | * functions can be made available while other modules are installed. |
| 355 | | */ |
| 356 | | function drupal_install_system() { |
| 357 | 1 | $system_path = dirname(drupal_get_filename('module', 'system', NULL)); |
| 358 | | require_once './'. $system_path .'/system.install'; |
| 359 | 1 | module_invoke('system', 'install'); |
| 360 | 1 | $system_versions = drupal_get_schema_versions('system'); |
| 361 | 1 | $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; |
| 362 | 1 | db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', '%s', '%s', %d, %d, %d, %d)", $system_path .'/system.module', 'system', 'module', '', 1, 0, 0, $system_version); |
| 363 | | // Now that we've installed things properly, bootstrap the full Drupal environment |
| 364 | 1 | drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); |
| 365 | 1 | module_rebuild_cache(); |
| 366 | | } |
| 367 | | |
| 368 | | |
| 369 | | /** |
| 370 | | * Calls the uninstall function and updates the system table for a given module. |
| 371 | | * |
| 372 | | * @param $module |
| 373 | | * The module to uninstall. |
| 374 | | */ |
| 375 | | function drupal_uninstall_module($module) { |
| 376 | | // First, retrieve all the module's menu paths from db. |
| 377 | | drupal_load('module', $module); |
| 378 | | $paths = module_invoke($module, 'menu'); |
| 379 | | |
| 380 | | // Uninstall the module(s). |
| 381 | | module_load_install($module); |
| 382 | | module_invoke($module, 'uninstall'); |
| 383 | | |
| 384 | | // Now remove the menu links for all paths declared by this module. |
| 385 | | if (!empty($paths)) { |
| 386 | | $paths = array_keys($paths); |
| 387 | | // Clean out the names of load functions. |
| 388 | | foreach ($paths as $index => $path) { |
| 389 | | $parts = explode('/', $path, MENU_MAX_PARTS); |
| 390 | | foreach ($parts as $k => $part) { |
| 391 | | if (preg_match('/^%[a-z_]*$/', $part)) { |
| 392 | | $parts[$k] = '%'; |
| 393 | | } |
| 394 | | } |
| 395 | | $paths[$index] = implode('/', $parts); |
| 396 | | } |
| 397 | | $placeholders = implode(', ', array_fill(0, count($paths), "'%s'")); |
| 398 | | |
| 399 | | $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN ('. $placeholders .') AND external = 0 ORDER BY depth DESC', $paths); |
| 400 | | // Remove all such items. Starting from those with the greatest depth will |
| 401 | | // minimize the amount of re-parenting done by menu_link_delete(). |
| 402 | | while ($item = db_fetch_array($result)) { |
| 403 | | _menu_delete_item($item, TRUE); |
| 404 | | } |
| 405 | | } |
| 406 | | |
| 407 | | drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED); |
| 408 | | } |
| 409 | | |
| 410 | | /** |
| 411 | | * Verify the state of the specified file. |
| 412 | | * |
| 413 | | * @param $file |
| 414 | | * The file to check for. |
| 415 | | * @param $mask |
| 416 | | * An optional bitmask created from various FILE_* constants. |
| 417 | | * @param $type |
| 418 | | * The type of file. Can be file (default), dir, or link. |
| 419 | | * @return |
| 420 | | * TRUE on success or FALSE on failure. A message is set for the latter. |
| 421 | | */ |
| 422 | | function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { |
| 423 | | $return = TRUE; |
| 424 | | // Check for files that shouldn't be there. |
| 425 | | if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) { |
| 426 | | return FALSE; |
| 427 | | } |
| 428 | | // Verify that the file is the type of file it is supposed to be. |
| 429 | | if (isset($type) && file_exists($file)) { |
| 430 | | $check = 'is_'. $type; |
| 431 | | if (!function_exists($check) || !$check($file)) { |
| 432 | | $return = FALSE; |
| 433 | | } |
| 434 | | } |
| 435 | | |
| 436 | | // Verify file permissions. |
| 437 | | if (isset($mask)) { |
| 438 | | $masks = array(FILE_EXIST, FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); |
| 439 | | foreach ($masks as $current_mask) { |
| 440 | | if ($mask & $current_mask) { |
| 441 | | switch ($current_mask) { |
| 442 | | case FILE_EXIST: |
| 443 | | if (!file_exists($file)) { |
| 444 | | if ($type == 'dir') { |
| 445 | | drupal_install_mkdir($file, $mask); |
| 446 | | } |
| 447 | | if (!file_exists($file)) { |
| 448 | | $return = FALSE; |
| 449 | | } |
| 450 | | } |
| 451 | | break; |
| 452 | | case FILE_READABLE: |
| 453 | | if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) { |
| 454 | | $return = FALSE; |
| 455 | | } |
| 456 | | break; |
| 457 | | case FILE_WRITABLE: |
| 458 | | if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) { |
| 459 | | $return = FALSE; |
| 460 | | } |
| 461 | | break; |
| 462 | | case FILE_EXECUTABLE: |
| 463 | | if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) { |
| 464 | | $return = FALSE; |
| 465 | | } |
| 466 | | break; |
| 467 | | case FILE_NOT_READABLE: |
| 468 | | if (is_readable($file) && !drupal_install_fix_file($file, $mask)) { |
| 469 | | $return = FALSE; |
| 470 | | } |
| 471 | | break; |
| 472 | | case FILE_NOT_WRITABLE: |
| 473 | | if (is_writable($file) && !drupal_install_fix_file($file, $mask)) { |
| 474 | | $return = FALSE; |
| 475 | | } |
| 476 | | break; |
| 477 | | case FILE_NOT_EXECUTABLE: |
| 478 | | if (is_executable($file) && !drupal_install_fix_file($file, $mask)) { |
| 479 | | $return = FALSE; |
| 480 | | } |
| 481 | | break; |
| 482 | | } |
| 483 | | } |
| 484 | | } |
| 485 | | } |
| 486 | | return $return; |
| 487 | | } |
| 488 | | |
| 489 | | /** |
| 490 | | * Create a directory with specified permissions. |
| 491 | | * |
| 492 | | * @param file |
| 493 | | * The name of the directory to create; |
| 494 | | * @param mask |
| 495 | | * The permissions of the directory to create. |
| 496 | | * @param $message |
| 497 | | * (optional) Whether to output messages. Defaults to TRUE. |
| 498 | | * |
| 499 | | * @return |
| 500 | | * TRUE/FALSE whether or not the directory was successfully created. |
| 501 | | */ |
| 502 | | function drupal_install_mkdir($file, $mask, $message = TRUE) { |
| 503 | | $mod = 0; |
| 504 | | $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); |
| 505 | | foreach ($masks as $m) { |
| 506 | | if ($mask & $m) { |
| 507 | | switch ($m) { |
| 508 | | case FILE_READABLE: |
| 509 | | $mod += 444; |
| 510 | | break; |
| 511 | | case FILE_WRITABLE: |
| 512 | | $mod += 222; |
| 513 | | break; |
| 514 | | case FILE_EXECUTABLE: |
| 515 | | $mod += 111; |
| 516 | | break; |
| 517 | | } |
| 518 | | } |
| 519 | | } |
| 520 | | |
| 521 | | if (@mkdir($file, intval("0$mod", 8))) { |
| 522 | | return TRUE; |
| 523 | | } |
| 524 | | else { |
| 525 | | return FALSE; |
| 526 | | } |
| 527 | | } |
| 528 | | |
| 529 | | /** |
| 530 | | * Attempt to fix file permissions. |
| 531 | | * |
| 532 | | * The general approach here is that, because we do not know the security |
| 533 | | * setup of the webserver, we apply our permission changes to all three |
| 534 | | * digits of the file permission (i.e. user, group and all). |
| 535 | | * |
| 536 | | * To ensure that the values behave as expected (and numbers don't carry |
| 537 | | * from one digit to the next) we do the calculation on the octal value |
| 538 | | * using bitwise operations. This lets us remove, for example, 0222 from |
| 539 | | * 0700 and get the correct value of 0500. |
| 540 | | * |
| 541 | | * @param $file |
| 542 | | * The name of the file with permissions to fix. |
| 543 | | * @param $mask |
| 544 | | * The desired permissions for the file. |
| 545 | | * @param $message |
| 546 | | * (optional) Whether to output messages. Defaults to TRUE. |
| 547 | | * |
| 548 | | * @return |
| 549 | | * TRUE/FALSE whether or not we were able to fix the file's permissions. |
| 550 | | */ |
| 551 | | function drupal_install_fix_file($file, $mask, $message = TRUE) { |
| 552 | | $mod = fileperms($file) & 0777; |
| 553 | | $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); |
| 554 | | |
| 555 | | // FILE_READABLE, FILE_WRITABLE, and FILE_EXECUTABLE permission strings |
| 556 | | // can theoretically be 0400, 0200, and 0100 respectively, but to be safe |
| 557 | | // we set all three access types in case the administrator intends to |
| 558 | | // change the owner of settings.php after installation. |
| 559 | | foreach ($masks as $m) { |
| 560 | | if ($mask & $m) { |
| 561 | | switch ($m) { |
| 562 | | case FILE_READABLE: |
| 563 | | if (!is_readable($file)) { |
| 564 | | $mod |= 0444; |
| 565 | | } |
| 566 | | break; |
| 567 | | case FILE_WRITABLE: |
| 568 | | if (!is_writable($file)) { |
| 569 | | $mod |= 0222; |
| 570 | | } |
| 571 | | break; |
| 572 | | case FILE_EXECUTABLE: |
| 573 | | if (!is_executable($file)) { |
| 574 | | $mod |= 0111; |
| 575 | | } |
| 576 | | break; |
| 577 | | case FILE_NOT_READABLE: |
| 578 | | if (is_readable($file)) { |
| 579 | | $mod &= ~0444; |
| 580 | | } |
| 581 | | break; |
| 582 | | case FILE_NOT_WRITABLE: |
| 583 | | if (is_writable($file)) { |
| 584 | | $mod &= ~0222; |
| 585 | | } |
| 586 | | break; |
| 587 | | case FILE_NOT_EXECUTABLE: |
| 588 | | if (is_executable($file)) { |
| 589 | | $mod &= ~0111; |
| 590 | | } |
| 591 | | break; |
| 592 | | } |
| 593 | | } |
| 594 | | } |
| 595 | | |
| 596 | | // chmod() will work if the web server is running as owner of the file. |
| 597 | | // If PHP safe_mode is enabled the currently executing script must also |
| 598 | | // have the same owner. |
| 599 | | if (@chmod($file, $mod)) { |
| 600 | | return TRUE; |
| 601 | | } |
| 602 | | else { |
| 603 | | return FALSE; |
| 604 | | } |
| 605 | | } |
| 606 | | |
| 607 | | |
| 608 | | /** |
| 609 | | * Send the user to a different installer page. This issues an on-site HTTP |
| 610 | | * redirect. Messages (and errors) are erased. |
| 611 | | * |
| 612 | | * @param $path |
| 613 | | * An installer path. |
| 614 | | */ |
| 615 | | function install_goto($path) { |
| 616 | | global $base_url; |
| 617 | | header('Location: '. $base_url .'/'. $path); |
| 618 | | header('Cache-Control: no-cache'); // Not a permanent redirect. |
| 619 | | exit(); |
| 620 | | } |
| 621 | | |
| 622 | | /** |
| 623 | | * Hardcoded function for doing the equivalent of t() during |
| 624 | | * the install process, when database, theme, and localization |
| 625 | | * system is possibly not yet available. |
| 626 | | */ |
| 627 | | function st($string, $args = array()) { |
| 628 | 1 | static $locale_strings = NULL; |
| 629 | 1 | global $profile, $install_locale; |
| 630 | | |
| 631 | 1 | if (!isset($locale_strings)) { |
| 632 | | $locale_strings = array(); |
| 633 | 1 | $filename = './profiles/'. $profile .'/translations/'. $install_locale .'.po'; |
| 634 | 1 | if (file_exists($filename)) { |
| 635 | | require_once './includes/locale.inc'; |
| 636 | | $file = (object) array('filepath' => $filename); |
| 637 | | _locale_import_read_po('mem-store', $file); |
| 638 | | $locale_strings = _locale_import_one_string('mem-report'); |
| 639 | | } |
| 640 | | } |
| 641 | | |
| 642 | | require_once './includes/theme.inc'; |
| 643 | | // Transform arguments before inserting them |
| 644 | 1 | foreach ($args as $key => $value) { |
| 645 | | switch ($key[0]) { |
| 646 | | // Escaped only |
| 647 | | case '@': |
| 648 | | $args[$key] = check_plain($value); |
| 649 | | break; |
| 650 | | // Escaped and placeholder |
| 651 | | case '%': |
| 652 | | default: |
| 653 | | $args[$key] = '<em>'. check_plain($value) .'</em>'; |
| 654 | | break; |
| 655 | | // Pass-through |
| 656 | | case '!': |
| 657 | | } |
| 658 | | } |
| 659 | 1 | return strtr((!empty($locale_strings[$string]) ? $locale_strings[$string] : $string), $args); |
| 660 | | } |
| 661 | | |
| 662 | | /** |
| 663 | | * Check a profile's requirements. |
| 664 | | * |
| 665 | | * @param profile |
| 666 | | * Name of profile to check. |
| 667 | | */ |
| 668 | | function drupal_check_profile($profile) { |
| 669 | | include_once './includes/file.inc'; |
| 670 | | |
| 671 | | $profile_file = "./profiles/$profile/$profile.profile"; |
| 672 | | |
| 673 | | if (!isset($profile) || !file_exists($profile_file)) { |
| 674 | | install_no_profile_error(); |
| 675 | | } |
| 676 | | |
| 677 | | require_once($profile_file); |
| 678 | | |
| 679 | | // Get a list of modules required by this profile. |
| 680 | | $function = $profile .'_profile_modules'; |
| 681 | | $module_list = array_unique(array_merge(drupal_required_modules(), $function())); |
| 682 | | |
| 683 | | // Get a list of all .install files. |
| 684 | | $installs = drupal_get_install_files($module_list); |
| 685 | | |
| 686 | | // Collect requirement testing results |
| 687 | | $requirements = array(); |
| 688 | | foreach ($installs as $install) { |
| 689 | | require_once $install->filename; |
| 690 | | if (module_hook($install->name, 'requirements')) { |
| 691 | | $requirements = array_merge($requirements, module_invoke($install->name, 'requirements', 'install')); |
| 692 | | } |
| 693 | | } |
| 694 | | return $requirements; |
| 695 | | } |
| 696 | | |
| 697 | | /** |
| 698 | | * Extract highest severity from requirements array. |
| 699 | | */ |
| 700 | | function drupal_requirements_severity(&$requirements) { |
| 701 | | $severity = REQUIREMENT_OK; |
| 702 | | foreach ($requirements as $requirement) { |
| 703 | | if (isset($requirement['severity'])) { |
| 704 | | $severity = max($severity, $requirement['severity']); |
| 705 | | } |
| 706 | | } |
| 707 | | return $severity; |
| 708 | | } |
| 709 | | |
| 710 | | /** |
| 711 | | * Check a module's requirements. |
| 712 | | */ |
| 713 | | function drupal_check_module($module) { |
| 714 | | // Include install file |
| 715 | | $install = drupal_get_install_files(array($module)); |
| 716 | | if (isset($install[$module])) { |
| 717 | | require_once $install[$module]->filename; |
| 718 | | |
| 719 | | // Check requirements |
| 720 | | $requirements = module_invoke($module, 'requirements', 'install'); |
| 721 | | if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) { |
| 722 | | // Print any error messages |
| 723 | | foreach ($requirements as $requirement) { |
| 724 | | if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) { |
| 725 | | $message = $requirement['description']; |
| 726 | | if (isset($requirement['value']) && $requirement['value']) { |
| 727 | | $message .= ' ('. t('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) .')'; |
| 728 | | } |
| 729 | | drupal_set_message($message, 'error'); |
| 730 | | } |
| 731 | | } |
| 732 | | return FALSE; |
| 733 | | } |
| 734 | | } |
| 735 | | return TRUE; |
| 736 | | } |