User login

Set higher minimum server environment requirements for a Drupal installation profile

There's a hook for that! The logically named hook_requirements lets you set requirements for each module.

To make these requirements apply to an installation profile, simply put your implementation of hook_requirements in the .install file of a module that is required by that installation profile.

Skip down to the resolution for the code that worked– doing it this Drupal way.

Keep reading for the various wrong turns on the path to the right direction.

Wrong Way

Overriding defined constants is not possible in PHP.

Many will point out that redefining a constant defeats the meaning of constant. Nonetheless, I did try, and can confirm that defining the constants from system.module a second time in custom.profile does NOT work. The override doesn't happen. Unlike an issue of overriding some other variable, here the the profile is not loaded, if at all, until after system.module (where the below are defined) is somehow loaded later:

<?php
/**
 * Minimum supported version of PHP.
 */
define('DRUPAL_MINIMUM_PHP',    '4.3.5');

/**
 * Minimum recommended value of PHP memory_limit.
 */
define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT',    '16M');

/**
 * Minimum supported version of MySQL, if it is used.
 */
define('DRUPAL_MINIMUM_MYSQL''4.1.1');

/**
 * Minimum supported version of PostgreSQL, if it is used.
 */
define('DRUPAL_MINIMUM_PGSQL''7.4');
?>

We tried to take a shortcut and it didn't work to redefine minimum supported environment configuration.

<?php
/**
 * Minimum supported version of PHP.
 */
define('DRUPAL_MINIMUM_PHP',    '5.2.0');

/**
 * Minimum recommended value of PHP memory_limit.
 */
define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT',    '32M');

/**
 * Minimum supported version of MySQL, if it is used.
 */
define('DRUPAL_MINIMUM_MYSQL''5.0.0');

/**
 * Minimum supported version of PostgreSQL, if it is used.
 */
define('DRUPAL_MINIMUM_PGSQL''99.86');
?>

(We would actually like a way to declare PostgreSQL unsupported... just for now, sorry!)

Aha! Agaric finds how it really works:

<?php
drupal_check_profile
($profile)

// ...

  // Get a list of modules required by this profile.
 

$function = $profile .'_profile_modules';

 

$installs = drupal_get_install_files($module_list);

 

// Collect requirement testing results
 
$requirements = array();
  foreach (
$installs as $install) {
    require_once
$install->filename;
    if (
module_hook($install->name, 'requirements')) {
     
$requirements = array_merge($requirements, module_invoke($install->name, 'requirements', 'install'));
    }
  }
  return
$requirements;
?>

However, it appears that system.install's requirements hook is just run the same way as every other module's hook_requirements implementation– every required module in an installation profile has its .install file loaded.

(Honestly, I didn't see where the Drupal core required modules get added to the list of requirements, but somehow and somewhere it seems to do this.)

Note that there doesn't appear to be anything that reads the .info files for required modules, so requirements defined in these .ini style for each required module does not get applied to the installation profile requirements. That would be neat and simple though.

Agaric we will take for scf.install the parts of system.install that look interesting. Here's a version of system module's implementation of hook_requirements copied and slightly reduced to focus on areas of interest to Agaric on this project...

<?php
/**
 * Test and report Drupal installation requirements.
 *
 * @param $phase
 *   The current system installation phase.
 * @return
 *   An array of system requirements.
 */
function system_requirements($phase) {
 
$requirements = array();
 
// Ensure translations don't break at install time
 
$t = get_t();

 

// Test PHP version
 
$requirements['php'] = array(
   
'title' => $t('PHP'),
   
'value' => ($phase == 'runtime') ? l(phpversion(), 'admin/reports/status/php') : phpversion(),
  );
  if (
version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
   
$requirements['php']['description'] = $t('Your PHP installation is too old. Drupal requires at least PHP %version.', array('%version' => DRUPAL_MINIMUM_PHP));
   
$requirements['php']['severity'] = REQUIREMENT_ERROR;
  }

 

// Test PHP memory_limit
 
$memory_limit = ini_get('memory_limit');
 
$requirements['php_memory_limit'] = array(
   
'title' => $t('PHP memory limit'),
   
'value' => $memory_limit,
  );

  if (

$memory_limit && parse_size($memory_limit) < parse_size(DRUPAL_MINIMUM_PHP_MEMORY_LIMIT)) {
   
$description = '';
    if (
$phase == 'install') {
     
$description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the installation process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
    }
    elseif (
$phase == 'update') {
     
$description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the update process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
    }
    elseif (
$phase == 'runtime') {
     
$description = $t('Depending on your configuration, Drupal can run with a %memory_limit PHP memory limit. However, a %memory_minimum_limit PHP memory limit or above is recommended, especially if your site uses additional custom or contributed modules.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
    }

    if (!empty(

$description)) {
      if (
$php_ini_path = get_cfg_var('cfg_file_path')) {
       
$description .= ' '. $t('Increase the memory limit by editing the memory_limit parameter in the file %configuration-file and then restart your web server (or contact your system administrator or hosting provider for assistance).', array('%configuration-file' => $php_ini_path));
      }
      else {
       
$description .= ' '. $t('Contact your system administrator or hosting provider for assistance with increasing your PHP memory limit.');
      }

     

$requirements['php_memory_limit']['description'] = $description .' '. $t('See the <a href="@url">Drupal requirements</a> for more information.', array('@url' => 'http://drupal.org/requirements'));
     
$requirements['php_memory_limit']['severity'] = REQUIREMENT_WARNING;
    }
  }

 

// Test DB version
 
global $db_type;
  if (
function_exists('db_status_report')) {
   
$requirements += db_status_report($phase);
  }

 

// Test files directory
 
$directory = file_directory_path();
 
$requirements['file system'] = array(
   
'title' => $t('File system'),
  );

 

// For installer, create the directory if possible.
 
if ($phase == 'install' && !is_dir($directory) && @mkdir($directory)) {
    @
chmod($directory, 0775); // Necessary for non-webserver users.
 
}

 

$is_writable = is_writable($directory);
 
$is_directory = is_dir($directory);
  if (!
$is_writable || !$is_directory) {
   
$description = '';
   
$requirements['file system']['value'] = $t('Not writable');
    if (!
$is_directory) {
     
$error = $t('The directory %directory does not exist.', array('%directory' => $directory));
    }
    else {
     
$error = $t('The directory %directory is not writable.', array('%directory' => $directory));
    }
   
// The files directory requirement check is done only during install and runtime.
   
if ($phase == 'runtime') {
     
$description = $error .' '. $t('You may need to set the correct directory at the <a href="@admin-file-system">file system settings page</a> or change the current directory\'s permissions so that it is writable.', array('@admin-file-system' => url('admin/settings/file-system')));
    }
    elseif (
$phase == 'install') {
     
// For the installer UI, we need different wording. 'value' will
      // be treated as version, so provide none there.
     
$description = $error .' '. $t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually, or ensure that the installer has the permissions to create it automatically. For more information, please see INSTALL.txt or the <a href="@handbook_url">on-line handbook</a>.', array('@handbook_url' => 'http://drupal.org/server-permissions'));
     
$requirements['file system']['value'] = '';
    }
    if (!empty(
$description)) {
     
$requirements['file system']['description'] = $description;
     
$requirements['file system']['severity'] = REQUIREMENT_ERROR;
    }
  }
  else {
    if (
variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) {
     
$requirements['file system']['value'] = $t('Writable (<em>public</em> download method)');
    }
    else {
     
$requirements['file system']['value'] = $t('Writable (<em>private</em> download method)');
    }
  }
// ...
 
return $requirements;
}
?>

Note, however, that PHP does not cause an error on attempting to define a constant a second time, so that if we had been able to define the constant first (such as you would be able to do in settings.php) then, in this way, you can change a constant defined in Drupal code without hacking Drupal. (OK, in the metaphysical sense pre-defining a constant in settings.php feels like a hack.)

Database Requirements Reference

http://api.drupal.org/api/function/db_status_report/6
http://api.drupal.org/api/file/includes/database.mysqli.inc/6/source
http://api.drupal.org/api/function/drupal_detect_database_types/6

Resolution

Agaric added this to the top of scf.install, where scf is a required module in scf.profile.

<?php
/**
 * Minimum supported version of PHP.
 */
define('SCF_MINIMUM_PHP',    '5.2.0');

/**
 * Minimum recommended value of PHP memory_limit.
 */
define('SCF_MINIMUM_PHP_MEMORY_LIMIT',    '32');

/**
 * Minimum supported version of MySQL, if it is used.
 */
define('SCF_MINIMUM_MYSQL''5.0.0');

/**
 * Minimum supported version of PostgreSQL, if it is used.
 */
define('SCF_PGSQL'FALSE);

/**
 * Test and report SCF installation requirements.
 *
 * @param $phase
 *   The current system installation phase.
 * @return
 *   An array of system requirements.
 */
function scf_requirements($phase) {
 
$requirements = array();
 
// Ensure translations don't break at install time
 
$t = get_t();

 

// Test PHP version
 
$requirements['php'] = array(
   
'title' => $t('PHP'),
   
'value' => ($phase == 'runtime') ? l(phpversion(), 'admin/reports/status/php') : phpversion(),
  );
  if (
version_compare(phpversion(), SCF_MINIMUM_PHP) < 0) {
   
$requirements['php']['description'] = $t('Your PHP installation is too old. SCF Drupal requires at least PHP %version.', array('%version' => SCF_MINIMUM_PHP));
   
$requirements['php']['severity'] = REQUIREMENT_ERROR;
  }

 

// Test PHP memory_limit
 
$memory_limit = ini_get('memory_limit');
 
$requirements['php_memory_limit'] = array(
   
'title' => $t('PHP memory limit'),
   
'value' => $memory_limit,
  );

  if (

$memory_limit && parse_size($memory_limit) < parse_size(SCF_MINIMUM_PHP_MEMORY_LIMIT)) {
   
$description = '';
    if (
$phase == 'install') {
     
$description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the installation process.', array('%memory_minimum_limit' => SCF_MINIMUM_PHP_MEMORY_LIMIT));
    }
    elseif (
$phase == 'update') {
     
$description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the update process.', array('%memory_minimum_limit' => SCF_MINIMUM_PHP_MEMORY_LIMIT));
    }
    if (!empty(
$description)) {
      if (
$php_ini_path = get_cfg_var('cfg_file_path')) {
       
$description .= ' '. $t('Increase the memory limit by editing the memory_limit parameter in the file %configuration-file and then restart your web server (or contact your system administrator or hosting provider for assistance).', array('%configuration-file' => $php_ini_path));
      }
      else {
       
$description .= ' '. $t('Contact your system administrator or hosting provider for assistance with increasing your PHP memory limit.');
      }

     

$requirements['php_memory_limit']['description'] = $description .' '. $t('See the <a href="@url">Drupal requirements</a> for more information.', array('@url' => 'http://drupal.org/requirements'));
     
$requirements['php_memory_limit']['severity'] = REQUIREMENT_WARNING;
    }
  }
 
 
// Test DB version
 
global $db_type;
  if (!
SCF_PGSQL && $db_type == 'pgsql') {
   
$requirements['pgsql'] = array(
     
'title' => $t('PostgreSQL'),
     
'value' => $db_type,
     
'severity' => REQUIREMENT_WARNING,
     
'description' => $t('SCF Drupal has not been tested with PostgreSQL'),
    );
  }
  else { 
// if (function_exists('db_status_report')) {
    // this deviates from the simple function call in system.install
    // for some reason, no db files are loaded and nothing in $db_type variable
    // so no db_status_report() and no db_version().
    //    $requirements += db_status_report($phase);
 
    //  $version = db_version();
   
list($version) = explode('-', mysql_get_server_info());
   
$requirements['mysql'] = array(
     
'title' => $t('MySQL database'),
     
'value' => ($phase == 'runtime') ? l($version, 'admin/reports/status/sql') : $version,
    );
 
    if (
version_compare($version, SCF_MINIMUM_MYSQL) < 0) {
     
$requirements['mysql']['severity'] = REQUIREMENT_ERROR;
     
$requirements['mysql']['description'] = $t('Your MySQL Server is too old. SCF Drupal requires at least MySQL %version.', array('%version' => SCF_MINIMUM_MYSQL));
    }
  }
 
  return
$requirements;
}
?>
Searched words: 
drupal override minimum settings with installation profile Drupal add requirements to installation profile set higher php version and memory requirements for a Drupal distribution need to give stricter recommended values for Drupal running environment require more resources for D6 installation profiles redefine reqs constants

Comments

Detecting MySQL version

Thanks for the useful code! I have a concern about detecting the MySQL version.

Is scf.install supposed to be executed before the user enters his database access credentials?

If so, then mysql_get_server_info() is not the best choice, as it will rely on previous connections or just fail with a warning according to its specification. Calling mysql_get_client_info() would probably be more reliable if the user has not provided database access credentials yet.
http://agaricdesign.com/note/set-higher-minimum-server-environment-requirements-a-drupal-installation-profile

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.