environment.inc

  1. 8.0.x includes/environment.inc
  2. 8.0.x commands/core/drupal/environment.inc
  3. 6.x includes/environment.inc
  4. 6.x commands/core/drupal/environment.inc
  5. 7.x includes/environment.inc
  6. 7.x commands/core/drupal/environment.inc
  7. 3.x includes/environment.inc
  8. 4.x commands/core/drupal/environment.inc
  9. 4.x includes/environment.inc
  10. 5.x commands/core/drupal/environment.inc
  11. 5.x includes/environment.inc
  12. master commands/core/drupal/environment.inc
  13. master includes/environment.inc

Functions used by drush to query the environment and setting the current configuration.

Bootstrapping now occurs in bootstrap.inc.

See also

includes/bootstrap.inc

Functions

Namesort descending Description
drush_bit_bucket Checks operating system and returns supported bit bucket folder.
drush_build_drush_command Build a drush command suitable for use for drush to call itself e.g. in backend_invoke.
drush_conf_path This is a copy of Drupal's conf_path function, taken from D7 and adjusted slightly to search from the selected Drupal Root.
drush_cwd Returns the current working directory.
drush_directory_cache The path to the global cache directory.
drush_drupal_required_modules
drush_drupal_sitewide_directory Returns the sitewide Drupal directory for extensions.
drush_environment_lib Check for the existence of the specified lib directory, and create if needed.
drush_environment_table_lib
drush_error_handler Log PHP errors to the Drush log. This is in effect until Drupal's error handler takes over.
drush_extension_check_incompatibility Test compatibility of a extension with version of drupal core and php.
drush_find_drush Determine a proper way to call drush again
drush_get_extensions Get complete information for all available extensions (modules and themes).
drush_get_tar_executable Return tar executable name specific for the current OS
drush_get_username Return the name of the user running drush.
drush_has_bash Checks if the operating system has bash.
drush_is_cygwin Check if the operating system is Winodws running some variant of cygwin -- either Cygwin or the MSYSGIT shell. If you care which is which, test mingw first.
drush_is_local_host Make a determination whether or not the given host is local or not.
drush_is_mingw
drush_is_osx Check if the operating system is OS X. This will return TRUE for Mac OS X (Darwin).
drush_is_windows Check if the operating system is Windows. This will return TRUE under DOS, Powershell Cygwin and MSYSGIT shells, so test for the Windows variant FIRST if you care.
drush_locate_root Exhaustive depth-first search to try and locate the Drupal root directory. This makes it possible to run drush from a subdirectory of the drupal root.
drush_read_drush_info Read the drush info file.
drush_server_home Return the user's home directory.
drush_site_dir_lookup_from_hostname Lookup a site's directory via the sites.php file given a hostname.
drush_site_path Like Drupal conf_path, but searching from beneath. Allows proper site uri detection in site sub-directories.
drush_theme_get_admin Return the administration theme.
drush_theme_get_default Return the default theme.
drush_valid_db_credentials Tests the currently loaded database credentials to ensure a database connection can be made.
drush_valid_drupal_root Checks whether given path qualifies as a Drupal root.
drush_verify_cli Verify that we are running PHP through the command line interface.
_drush_convert_path Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3). Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a proper drive path, still with Unix slashes (c:/dir1).
_drush_environment_check_php_ini Evaluate the environment before command bootstrapping begins. If the php environment is too restrictive, then notify the user that a setting change is needed and abort.
_drush_get_os Return the OS we are running under.
_drush_php_ini_loaded_file_message Returns a localizable message about php.ini that varies depending on whether the php_ini_loaded_file() is available or not.
_drush_postmortem Evalute the environment after an abnormal termination and see if we can determine any configuration settings that the user might want to adjust.
_drush_shift_path_up Returns parent directory.
_drush_test_os

Constants

Namesort descending Description
CONSOLE_TABLE_BASE_URL Base URL for automatic file download of PEAR packages.
DRUSH_TABLE_VERSION Supported version of Console Table. This is displayed in the manual install help.

File

includes/environment.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Functions used by drush to query the environment and
  5. * setting the current configuration.
  6. *
  7. * Bootstrapping now occurs in bootstrap.inc.
  8. *
  9. * @see includes/bootstrap.inc
  10. */
  11. /**
  12. * Supported version of Console Table. This is displayed in the manual install help.
  13. */
  14. define('DRUSH_TABLE_VERSION', '1.1.5');
  15. /**
  16. * Base URL for automatic file download of PEAR packages.
  17. */
  18. define('CONSOLE_TABLE_BASE_URL', 'https://github.com/RobLoach/Console_Table/archive/');
  19. /**
  20. * Log PHP errors to the Drush log. This is in effect until Drupal's error
  21. * handler takes over.
  22. */
  23. function drush_error_handler($errno, $message, $filename, $line, $context) {
  24. // E_DEPRECATED was added in PHP 5.3. Drupal 6 will not fix all the
  25. // deprecated errors, but suppresses them. So we suppress them as well.
  26. if (defined('E_DEPRECATED')) {
  27. $errno = $errno & ~E_DEPRECATED;
  28. }
  29. // "error_reporting" is usually set in php.ini, but may be changed by
  30. // drush_errors_on() and drush_errors_off().
  31. if ($errno & error_reporting()) {
  32. // By default we log notices.
  33. $type = drush_get_option('php-notices', 'notice');
  34. // Bitmask value that constitutes an error needing to be logged.
  35. $error = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR;
  36. if ($errno & $error) {
  37. $type = 'error';
  38. }
  39. // Bitmask value that constitutes a warning being logged.
  40. $warning = E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING;
  41. if ($errno & $warning) {
  42. $type = 'warning';
  43. }
  44. drush_log($message . ' ' . basename($filename) . ':' . $line, $type);
  45. return TRUE;
  46. }
  47. }
  48. /**
  49. * Returns a localizable message about php.ini that
  50. * varies depending on whether the php_ini_loaded_file()
  51. * is available or not.
  52. */
  53. function _drush_php_ini_loaded_file_message() {
  54. if (function_exists('php_ini_loaded_file')) {
  55. return dt('Please check your configuration settings in !phpini or in your drush.ini file; see examples/example.drush.ini for details.', array('!phpini' => php_ini_loaded_file()));
  56. }
  57. else {
  58. return dt('Please check your configuration settings in your php.ini file or in your drush.ini file; see examples/example.drush.ini for details.');
  59. }
  60. }
  61. /**
  62. * Evalute the environment after an abnormal termination and
  63. * see if we can determine any configuration settings that the user might
  64. * want to adjust.
  65. */
  66. function _drush_postmortem() {
  67. // Make sure that the memory limit has been bumped up from the minimum default value of 32M.
  68. $php_memory_limit = drush_memory_limit();
  69. if (($php_memory_limit > 0) && ($php_memory_limit <= 32*DRUSH_DRUPAL_KILOBYTE*DRUSH_DRUPAL_KILOBYTE)) {
  70. drush_set_error('DRUSH_MEMORY_LIMIT', dt('Your memory limit is set to !memory_limit; drush needs as much memory to run as Drupal. !php_ini_msg', array('!memory_limit' => $php_memory_limit / (DRUSH_DRUPAL_KILOBYTE*DRUSH_DRUPAL_KILOBYTE) . 'M', '!php_ini_msg' => _drush_php_ini_loaded_file_message())));
  71. }
  72. }
  73. /**
  74. * Evaluate the environment before command bootstrapping
  75. * begins. If the php environment is too restrictive, then
  76. * notify the user that a setting change is needed and abort.
  77. */
  78. function _drush_environment_check_php_ini() {
  79. $ini_checks = array('safe_mode' => '', 'open_basedir' => '', 'disable_functions' => array('exec', 'system'), 'disable_classes' => '');
  80. // Test to insure that certain php ini restrictions have not been enabled
  81. $prohibited_list = array();
  82. foreach ($ini_checks as $prohibited_mode => $disallowed_value) {
  83. $ini_value = ini_get($prohibited_mode);
  84. $invalid_value = FALSE;
  85. if (empty($disallowed_value)) {
  86. $invalid_value = !empty($ini_value) && (strcasecmp($ini_value, 'off') != 0);
  87. }
  88. else {
  89. foreach ($disallowed_value as $test_value) {
  90. if (preg_match('/(^|,)' . $test_value . '(,|$)/', $ini_value)) {
  91. $invalid_value = TRUE;
  92. }
  93. }
  94. }
  95. if ($invalid_value) {
  96. $prohibited_list[] = $prohibited_mode;
  97. }
  98. }
  99. if (!empty($prohibited_list)) {
  100. drush_log(dt('The following restricted PHP modes have non-empty values: !prohibited_list. This configuration is incompatible with drush. !php_ini_msg', array('!prohibited_list' => implode(' and ', $prohibited_list), '!php_ini_msg' => _drush_php_ini_loaded_file_message())), 'error');
  101. }
  102. return TRUE;
  103. }
  104. /**
  105. * Check for the existence of the specified lib directory, and create if needed.
  106. */
  107. function drush_environment_lib() {
  108. $lib = drush_get_option('lib', DRUSH_BASE_PATH . '/lib');
  109. // We tell drush_mkdir that $lib is not required, because otherwise it
  110. // will throw an error if the folder exists but is not writable. It
  111. // is okay with us if the $lib dir is not writable by the current
  112. // user, as it may have already been set up by the user who installed Drush.
  113. drush_mkdir($lib, FALSE);
  114. if (!is_dir($lib)) {
  115. return FALSE;
  116. }
  117. }
  118. function drush_environment_table_lib() {
  119. // Try using the PEAR installed version of Console_Table.
  120. $tablefile = 'Console/Table.php';
  121. if (@file_get_contents($tablefile, FILE_USE_INCLUDE_PATH) === FALSE) {
  122. $lib = drush_get_option('lib', DRUSH_BASE_PATH . '/lib');
  123. $tablefile = $lib . '/Console_Table-' . DRUSH_TABLE_VERSION . '/Table.php';
  124. // If it is not already present, download Console Table.
  125. if (!drush_file_not_empty($tablefile)) {
  126. // Attempt to remove the old Console Table file, from the legacy location.
  127. // TODO: Remove this (and associated .git.ignore) in Drush 6.x.
  128. $tablefile_legacy = DRUSH_BASE_PATH . '/includes/table.inc';
  129. if (drush_file_not_empty($tablefile_legacy)) {
  130. drush_op('unlink', $tablefile_legacy);
  131. }
  132. // Download and extract Console_Table, and confirm success.
  133. if (drush_lib_fetch(CONSOLE_TABLE_BASE_URL . DRUSH_TABLE_VERSION . '.tar.gz')) {
  134. // Remove unneccessary package.xml file which ends up in /lib.
  135. drush_op('unlink', $lib . '/package.xml');
  136. }
  137. if (!drush_file_not_empty($tablefile)) {
  138. return drush_bootstrap_error('DRUSH_TABLES_LIB_NOT_FOUND', dt("Drush needs a copy of the PEAR Console_Table library in order to function, and the attempt to download this file automatically failed. To continue you will need to download the !version package from http://pear.php.net/package/Console_Table, extract it into !lib directory, such that Table.php exists at !tablefile.", array('!version' => DRUSH_TABLE_VERSION, '!tablefile' => $tablefile, '!lib' => $lib)));
  139. }
  140. }
  141. }
  142. require_once $tablefile;
  143. }
  144. /**
  145. * Returns the current working directory.
  146. *
  147. * This is the directory as it was when drush was started, not the
  148. * directory we are currently in. For that, use getcwd() directly.
  149. */
  150. function drush_cwd() {
  151. if ($path = drush_get_context('DRUSH_OLDCWD')) {
  152. return $path;
  153. }
  154. // We use PWD if available because getcwd() resolves symlinks, which
  155. // could take us outside of the Drupal root, making it impossible to find.
  156. // $_SERVER['PWD'] isn't set on windows and generates a Notice.
  157. $path = isset($_SERVER['PWD']) ? $_SERVER['PWD'] : '';
  158. if (empty($path)) {
  159. $path = getcwd();
  160. }
  161. // Convert windows paths.
  162. $path = _drush_convert_path($path);
  163. // Save original working dir case some command wants it.
  164. drush_set_context('DRUSH_OLDCWD', $path);
  165. return $path;
  166. }
  167. /**
  168. * Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
  169. * Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
  170. * proper drive path, still with Unix slashes (c:/dir1).
  171. */
  172. function _drush_convert_path($path) {
  173. $path = str_replace('\\','/', $path);
  174. $path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
  175. return $path;
  176. }
  177. /**
  178. * Returns parent directory.
  179. *
  180. * @param string
  181. * Path to start from.
  182. *
  183. * @return string
  184. * Parent path of given path.
  185. */
  186. function _drush_shift_path_up($path) {
  187. if (empty($path)) {
  188. return FALSE;
  189. }
  190. $path = explode('/', $path);
  191. // Move one directory up.
  192. array_pop($path);
  193. return implode('/', $path);
  194. }
  195. /**
  196. * Like Drupal conf_path, but searching from beneath.
  197. * Allows proper site uri detection in site sub-directories.
  198. *
  199. * Essentially looks for a settings.php file. Drush uses this
  200. * function to find a usable site based on the user's current
  201. * working directory.
  202. *
  203. * @param string
  204. * Search starting path. Defaults to current working directory.
  205. *
  206. * @return
  207. * Current site path (folder containing settings.php) or FALSE if not found.
  208. */
  209. function drush_site_path($path = NULL) {
  210. $site_path = FALSE;
  211. $path = empty($path) ? drush_cwd() : $path;
  212. // Check the current path.
  213. if (file_exists($path . '/settings.php')) {
  214. $site_path = $path;
  215. }
  216. else {
  217. // Move up dir by dir and check each.
  218. while ($path = _drush_shift_path_up($path)) {
  219. if (file_exists($path . '/settings.php')) {
  220. $site_path = $path;
  221. break;
  222. }
  223. }
  224. }
  225. $site_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
  226. if (file_exists($site_root . '/sites/sites.php')) {
  227. $sites = array();
  228. // This will overwrite $sites with the desired mappings.
  229. include($site_root . '/sites/sites.php');
  230. // We do a reverse lookup here to determine the URL given the site key.
  231. if ($match = array_search($site_path, $sites)) {
  232. $site_path = $match;
  233. }
  234. }
  235. // Last resort: try from site root
  236. if (!$site_path) {
  237. if ($site_root) {
  238. if (file_exists($site_root . '/sites/default/settings.php')) {
  239. $site_path = $site_root . '/sites/default';
  240. }
  241. }
  242. }
  243. return $site_path;
  244. }
  245. /**
  246. * Lookup a site's directory via the sites.php file given a hostname.
  247. *
  248. * @param $hostname
  249. * The hostname of a site. May be converted from URI.
  250. *
  251. * @return $dir
  252. * The directory associated with that hostname or FALSE if not found.
  253. */
  254. function drush_site_dir_lookup_from_hostname($hostname) {
  255. $site_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
  256. if (file_exists($site_root . '/sites/sites.php')) {
  257. $sites = array();
  258. // This will overwrite $sites with the desired mappings.
  259. include($site_root . '/sites/sites.php');
  260. return isset($sites[$hostname]) ? $sites[$hostname] : FALSE;
  261. }
  262. else {
  263. return FALSE;
  264. }
  265. }
  266. /**
  267. * This is a copy of Drupal's conf_path function, taken from D7 and
  268. * adjusted slightly to search from the selected Drupal Root.
  269. *
  270. * Drush uses this routine to find a usable site based on a URI
  271. * passed in via a site alias record or the --uri commandline option.
  272. *
  273. * Drush uses Drupal itself (specifically, the Drupal conf_path function)
  274. * to bootstrap the site itself. If the implementation of conf_path
  275. * changes, the site should still bootstrap correctly; the only consequence
  276. * of this routine not working is that drush configuration files
  277. * (drushrc.php) stored with the site's settimight not be found.
  278. */
  279. function drush_conf_path($server_uri, $require_settings = TRUE) {
  280. $drupal_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
  281. if(empty($drupal_root) || empty($server_uri)) {
  282. return NULL;
  283. }
  284. $parsed_uri = parse_url($server_uri);
  285. if (is_array($parsed_uri) && !array_key_exists('scheme', $parsed_uri)) {
  286. $parsed_uri = parse_url('http://' . $server_uri);
  287. }
  288. if (!is_array($parsed_uri)) {
  289. return NULL;
  290. }
  291. $server_host = $parsed_uri['host'];
  292. if (array_key_exists('path', $parsed_uri)) {
  293. $server_uri = $parsed_uri['path'] . '/index.php';
  294. }
  295. else {
  296. $server_uri = "/index.php";
  297. }
  298. $confdir = 'sites';
  299. $sites = array();
  300. if (file_exists($drupal_root . '/' . $confdir . '/sites.php')) {
  301. // This will overwrite $sites with the desired mappings.
  302. include($drupal_root . '/' . $confdir . '/sites.php');
  303. }
  304. $uri = explode('/', $server_uri);
  305. $server = explode('.', implode('.', array_reverse(explode(':', rtrim($server_host, '.')))));
  306. for ($i = count($uri) - 1; $i > 0; $i--) {
  307. for ($j = count($server); $j > 0; $j--) {
  308. $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
  309. if (isset($sites[$dir]) && file_exists($drupal_root . '/' . $confdir . '/' . $sites[$dir])) {
  310. $dir = $sites[$dir];
  311. }
  312. if (file_exists($drupal_root . '/' . $confdir . '/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/' . $confdir . '/' . $dir))) {
  313. $conf = "$confdir/$dir";
  314. return $conf;
  315. }
  316. }
  317. }
  318. $conf = "$confdir/default";
  319. return $conf;
  320. }
  321. /**
  322. * Exhaustive depth-first search to try and locate the Drupal root directory.
  323. * This makes it possible to run drush from a subdirectory of the drupal root.
  324. *
  325. * @param
  326. * Search start path. Defaults to current working directory.
  327. * @return
  328. * A path to drupal root, or FALSE if not found.
  329. */
  330. function drush_locate_root($start_path = NULL) {
  331. $drupal_root = FALSE;
  332. $start_path = empty($start_path) ? drush_cwd() : $start_path;
  333. foreach (array(TRUE, FALSE) as $follow_symlinks) {
  334. $path = $start_path;
  335. if ($follow_symlinks && is_link($path)) {
  336. $path = realpath($path);
  337. }
  338. // Check the start path.
  339. if (drush_valid_drupal_root($path)) {
  340. $drupal_root = $path;
  341. break;
  342. }
  343. else {
  344. // Move up dir by dir and check each.
  345. while ($path = _drush_shift_path_up($path)) {
  346. if ($follow_symlinks && is_link($path)) {
  347. $path = realpath($path);
  348. }
  349. if (drush_valid_drupal_root($path)) {
  350. $drupal_root = $path;
  351. break 2;
  352. }
  353. }
  354. }
  355. }
  356. return $drupal_root;
  357. }
  358. /**
  359. * Checks whether given path qualifies as a Drupal root.
  360. *
  361. * @param string
  362. * Path to check.
  363. *
  364. * @return string
  365. * The relative path to common.inc (varies by Drupal version), or FALSE if not
  366. * a Drupal root.
  367. */
  368. function drush_valid_drupal_root($path) {
  369. if (!empty($path) && is_dir($path) && file_exists($path . '/index.php')) {
  370. // Drupal 8 root. Additional check for the presence of core/composer.json to
  371. // grant it is not a Drupal 7 site with a base folder named "core".
  372. $candidate = 'core/includes/common.inc';
  373. if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/misc/drupal.js') && file_exists($path . '/composer.json')) {
  374. return $candidate;
  375. }
  376. // Drupal 7 root. Additional check for the absence of core/composer.json to
  377. // grant $path is not core/ of a Drupal 8 root.
  378. $candidate = 'includes/common.inc';
  379. if (file_exists($path . '/' . $candidate) && file_exists($path . '/misc/drupal.js') && ((basename($path) != 'core') || !file_exists($path . '/../composer.json'))) {
  380. return $candidate;
  381. }
  382. }
  383. return FALSE;
  384. }
  385. /**
  386. * Tests the currently loaded database credentials to ensure a database connection can be made.
  387. */
  388. function drush_valid_db_credentials() {
  389. $creds = drush_get_context('DRUSH_DB_CREDENTIALS');
  390. // Do minimal checking that we have the necessary information.
  391. if (count($creds) == 0) {
  392. return FALSE;
  393. }
  394. $type = $creds['driver'];
  395. switch (drush_drupal_major_version()) {
  396. case 6:
  397. // Check availability of db extension in PHP and also Drupal support.
  398. if (file_exists('./includes/install.'. $type .'.inc')) {
  399. require_once './includes/install.'. $type .'.inc';
  400. $function = $type .'_is_available';
  401. if (!$function()) {
  402. drush_log(dt('!type extension for PHP is not installed. Check your php.ini to see how you can enable it.', array('!type' => $type)), 'bootstrap');
  403. return FALSE;
  404. }
  405. }
  406. else {
  407. drush_log(dt('!type database type is unsupported.', array('!type' => $type)), 'bootstrap');
  408. return FALSE;
  409. }
  410. // Verify connection settings.
  411. switch ($type) {
  412. case 'mysql':
  413. $hostspec = $creds['port'] ? $creds['host'] . ':' . $creds['port'] : $creds['host'];
  414. $connection = @mysql_connect($hostspec, $creds['user'], $creds['pass']);
  415. if (!$connection || !mysql_select_db($creds['name'])) {
  416. drush_log(mysql_error(), 'bootstrap');
  417. return FALSE;
  418. }
  419. break;
  420. case 'mysqli':
  421. $connection = mysqli_init();
  422. @mysqli_real_connect($connection, $creds['host'], $creds['user'], $creds['pass'], $creds['name'], (int)$creds['port']);
  423. if (mysqli_connect_errno() > 0) {
  424. drush_log(mysqli_connect_error(), 'bootstrap');
  425. return FALSE;
  426. }
  427. break;
  428. case 'pgsql':
  429. $conn_string = sprintf("host=%s user=%s password=%s dbname=%s", $creds['host'], $creds['user'], $creds['pass'], $creds['name']);
  430. if (isset($creds['port'])) {
  431. $conn_string .= ' port=' . $creds['port'];
  432. }
  433. // Copied from d6's database.pgsql.inc:
  434. // pg_last_error() does not return a useful error message for database
  435. // connection errors. We must turn on error tracking to get at a good error
  436. // message, which will be stored in $php_errormsg.
  437. $php_errormsg = '';
  438. $track_errors_previous = ini_get('track_errors');
  439. ini_set('track_errors', 1);
  440. $connection = @pg_connect($conn_string);
  441. // Restore error tracking setting
  442. ini_set('track_errors', $track_errors_previous);
  443. if (!$connection) {
  444. if (empty($php_errormsg)) {
  445. drush_log(dt("Unknown error connecting to pgsql database via !constr", array('!constr' => $conn_string)), 'bootstrap');
  446. }
  447. else {
  448. require_once './includes/unicode.inc';
  449. drush_log(decode_entities($php_errormsg), 'bootstrap');
  450. }
  451. return FALSE;
  452. }
  453. break;
  454. }
  455. break;
  456. case 7:
  457. default:
  458. $type = ( $type=='oracle' ? 'oci' : $type); // fix PDO driver name, should go away in Drupal 8
  459. // Drupal >=7 requires PDO and drush requires php 5.3 which ships with PDO
  460. // but it may be compiled with --disable-pdo.
  461. if (!class_exists('PDO')) {
  462. drush_log(dt('PDO support is required.'), 'bootstrap');
  463. return FALSE;
  464. }
  465. // Warn if the database specific driver is available. We don't return FALSE since
  466. // Drush6 supports DB drivers that extend mysql.
  467. if (!in_array($type, PDO::getAvailableDrivers())) {
  468. drush_log(dt('!type extension for PHP PDO is not installed. Check your php.ini to see how you can enable it. Proceeding with the mysql PDO extension.', array('!type' => $type)), 'bootstrap');
  469. $type = 'mysql';
  470. }
  471. // Build the connection string.
  472. if ($type === 'sqlite') {
  473. $constr = 'sqlite:' . $creds['name'];
  474. }
  475. elseif ($type === 'sqlsrv') {
  476. $server = $creds['host'];
  477. if (!empty($creds['port'])) {
  478. $server .= ", " . $creds['port'];
  479. }
  480. $constr = sprintf("%s:database=%s;server=%s", $type, $creds['name'], $server);
  481. }
  482. elseif ($type === 'oci') {
  483. if (empty($creds['port']))
  484. $creds['port'] = 1521;
  485. if ($creds['host'] == 'USETNS')
  486. $constr = 'oci:dbname=' . $creds['database'] . ';charset=AL32UTF8';
  487. else
  488. $constr = 'oci:dbname=//' . $creds['host'] . ':' . $creds['port'] . '/' . $creds['database'] . ';charset=AL32UTF8';
  489. }
  490. else {
  491. $constr = sprintf("%s:dbname=%s", $type, $creds['name']);
  492. // Use unix_socket if set instead of host:port.
  493. if (!empty($creds['unix_socket'])) {
  494. $constr .= sprintf(";unix_socket=%s", $creds['unix_socket']);
  495. }
  496. else {
  497. $constr .= sprintf(";host=%s", $creds['host']);
  498. if (!empty($creds['port'])) {
  499. $constr .= sprintf(";port=%d", $creds['port']);
  500. }
  501. }
  502. }
  503. try {
  504. $db = new PDO($constr, $creds['user'], $creds['pass'], $creds['pdo']);
  505. $db = null;
  506. }
  507. catch (PDOException $e) {
  508. drush_log($e->getMessage(), 'bootstrap');
  509. return FALSE;
  510. }
  511. break;
  512. }
  513. return TRUE;
  514. }
  515. /**
  516. * Determine a proper way to call drush again
  517. *
  518. * This check if we were called directly or as an argument to some
  519. * wrapper command (php and sudo are checked now).
  520. *
  521. * Calling ./drush.php directly yields the following environment:
  522. *
  523. * _SERVER["argv"][0] => ./drush.php
  524. *
  525. * Calling php ./drush.php also yields the following:
  526. *
  527. * _SERVER["argv"][0] => ./drush.php
  528. *
  529. * Note that the $_ global is defined only in bash and therefore cannot
  530. * be relied upon.
  531. *
  532. * The DRUSH_COMMAND constant is initialised to the value of this
  533. * function when environment.inc is loaded.
  534. *
  535. * @see DRUSH_COMMAND
  536. */
  537. function drush_find_drush() {
  538. $drush = realpath($_SERVER['argv']['0']);
  539. // TODO: On Windows, if we leave $drush as-is, then callbacks will
  540. // be done just as we were called by the batch file: php.exe C:\path\drush.php
  541. // We could also convert drush.php to drush.bat to run the batch file again,
  542. // but this works just as well.
  543. return $drush;
  544. }
  545. /**
  546. * Verify that we are running PHP through the command line interface.
  547. *
  548. * This function is useful for making sure that code cannot be run via the web server,
  549. * such as a function that needs to write files to which the web server should not have
  550. * access to.
  551. *
  552. * @return
  553. * A boolean value that is true when PHP is being run through the command line,
  554. * and false if being run through cgi or mod_php.
  555. */
  556. function drush_verify_cli() {
  557. return (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0));
  558. }
  559. /**
  560. * Build a drush command suitable for use for drush to call itself
  561. * e.g. in backend_invoke.
  562. */
  563. function drush_build_drush_command($drush_path = NULL, $php = NULL, $os = NULL, $remote_command = FALSE) {
  564. $environment_variables = array();
  565. $os = _drush_get_os($os);
  566. $additional_options = '';
  567. if (!isset($drush_path)) {
  568. if (!$remote_command) {
  569. $drush_path = DRUSH_COMMAND;
  570. }
  571. else {
  572. $drush_path = drush_is_windows($os) ? 'drush.bat' : 'drush';
  573. }
  574. }
  575. // If the path to drush points to drush.php, then we will need to
  576. // run it via php rather than direct execution. By default, we
  577. // will use 'php' unless something more specific was passed in
  578. // via the --php flag.
  579. if (substr($drush_path, -4) == ".php") {
  580. if (!isset($php)) {
  581. $php = drush_get_option('php');
  582. if (!isset($php)) {
  583. $php = 'php';
  584. }
  585. }
  586. if (isset($php) && ($php != "php")) {
  587. $additional_options .= ' --php=' . drush_escapeshellarg($php, $os);
  588. }
  589. // We will also add in the php options from --php-options
  590. $prefix = drush_escapeshellarg($php, $os);
  591. $php_options = implode(' ', drush_get_context_options('php-options'));
  592. if (!empty($php_options)) {
  593. $prefix .= ' ' . $php_options;
  594. $additional_options .= ' --php-options=' . drush_escapeshellarg($php_options, $os);
  595. }
  596. }
  597. else {
  598. // Set environment variables to propogate config to redispatched calls.
  599. if (drush_has_bash($os)) {
  600. if ($php) {
  601. $environment_variables[] = 'DRUSH_PHP=' . drush_escapeshellarg($php, $os);
  602. }
  603. if ($php_options_alias = drush_get_option('php-options', NULL, 'alias')) {
  604. $environment_variables[] = 'PHP_OPTIONS=' . drush_escapeshellarg($php_options_alias, $os);
  605. }
  606. $columns = drush_get_context('DRUSH_COLUMNS');
  607. if (($columns) && ($columns != 80)) {
  608. $environment_variables[] = 'COLUMNS=' . $columns;
  609. }
  610. $prefix = implode(' ', $environment_variables);
  611. }
  612. }
  613. return trim($prefix . ' ' . drush_escapeshellarg($drush_path, $os) . $additional_options);
  614. }
  615. /**
  616. * Check if the operating system is Windows.
  617. * This will return TRUE under DOS, Powershell
  618. * Cygwin and MSYSGIT shells, so test for the
  619. * Windows variant FIRST if you care.
  620. */
  621. function drush_is_windows($os = NULL) {
  622. return _drush_test_os($os, array("WIN","CYGWIN","CWRSYNC","MINGW"));
  623. }
  624. /**
  625. * Check if the operating system is Winodws
  626. * running some variant of cygwin -- either
  627. * Cygwin or the MSYSGIT shell. If you care
  628. * which is which, test mingw first.
  629. */
  630. function drush_is_cygwin($os = NULL) {
  631. return _drush_test_os($os, array("CYGWIN","CWRSYNC","MINGW"));
  632. }
  633. function drush_is_mingw($os = NULL) {
  634. return _drush_test_os($os, array("MINGW"));
  635. }
  636. /**
  637. * Return tar executable name specific for the current OS
  638. */
  639. function drush_get_tar_executable() {
  640. return drush_is_windows() ? (drush_is_mingw() ? "tar.exe" : "bsdtar.exe") : "tar";
  641. }
  642. /**
  643. * Check if the operating system is OS X.
  644. * This will return TRUE for Mac OS X (Darwin).
  645. */
  646. function drush_is_osx($os = NULL) {
  647. return _drush_test_os($os, array("DARWIN"));
  648. }
  649. /**
  650. * Checks if the operating system has bash.
  651. *
  652. * MinGW has bash, but PHP isn't part of MinGW and hence doesn't run in bash.
  653. */
  654. function drush_has_bash($os = NULL) {
  655. return (drush_is_cygwin($os) && !drush_is_mingw($os)) || !drush_is_windows($os);
  656. }
  657. /**
  658. * Checks operating system and returns
  659. * supported bit bucket folder.
  660. */
  661. function drush_bit_bucket() {
  662. if (drush_has_bash()) {
  663. return '/dev/null';
  664. }
  665. else {
  666. return 'nul';
  667. }
  668. }
  669. /**
  670. * Return the OS we are running under.
  671. *
  672. * @return string
  673. * Linux
  674. * WIN* (e.g. WINNT)
  675. * CYGWIN
  676. * MINGW* (e.g. MINGW32)
  677. */
  678. function _drush_get_os($os = NULL) {
  679. // The special os "CWRSYNC" can be used to indicate that we are testing
  680. // a path that will be passed as an argument to cwRsync, which requires
  681. // that the path be converted to /cygdrive/c/path, even on DOS or Powershell.
  682. // The special os "RSYNC" can be used to indicate that we want to assume
  683. // "CWRSYNC" when cwrsync is installed, or default to the local OS otherwise.
  684. if (strtoupper($os) == "RSYNC") {
  685. $os = _drush_get_os("LOCAL");
  686. // For now we assume that cwrsync is always installed on Windows, and never installed son any other platform.
  687. return drush_is_windows($os) ? "CWRSYNC" : $os;
  688. }
  689. // We allow "LOCAL" to document, in instances where some parameters are being escaped
  690. // for use on a remote machine, that one particular parameter will always be used on
  691. // the local machine (c.f. drush_backend_invoke).
  692. if (isset($os) && ($os != "LOCAL")) {
  693. return $os;
  694. }
  695. if (_drush_test_os(getenv("MSYSTEM"), array("MINGW"))) {
  696. return getenv("MSYSTEM");
  697. }
  698. // QUESTION: Can we differentiate between DOS and POWERSHELL? They appear to have the same environment.
  699. // At the moment, it does not seem to matter; they behave the same from PHP.
  700. // At this point we will just return PHP_OS.
  701. return PHP_OS;
  702. }
  703. function _drush_test_os($os, $os_list_to_check) {
  704. $os = _drush_get_os($os);
  705. foreach ($os_list_to_check as $test) {
  706. if (strtoupper(substr($os, 0, strlen($test))) == strtoupper($test)) {
  707. return TRUE;
  708. }
  709. }
  710. return FALSE;
  711. }
  712. /**
  713. * Read the drush info file.
  714. */
  715. function drush_read_drush_info() {
  716. $drush_info_file = dirname(__FILE__) . '/../drush.info';
  717. return parse_ini_file($drush_info_file);
  718. }
  719. /**
  720. * Make a determination whether or not the given
  721. * host is local or not.
  722. *
  723. * @param host
  724. * A hostname, 'localhost' or '127.0.0.1'.
  725. * @return
  726. * True if the host is local.
  727. */
  728. function drush_is_local_host($host) {
  729. // In order for this to work right, you must use 'localhost' or '127.0.0.1'
  730. // or the machine returned by 'uname -n' for your 'remote-host' entry in
  731. // your site alias.
  732. if (($host == 'localhost') || ($host == '127.0.0.1')) {
  733. return TRUE;
  734. }
  735. // We'll start out by asking for uname -n via php_uname, since
  736. // that is most portable. On Linux, uname -n returns the contents of
  737. // /etc/hostname, which, according to `man hostname`, should never
  738. // contain the fqdn. We will therefore also try `hostname -f`, and
  739. // see if we can get the fqdn from that.
  740. $uname = php_uname('n');
  741. if ((strpos($uname,'.') === FALSE) && (!drush_is_windows())) {
  742. $hostname = exec('hostname -f');
  743. if (!empty($hostname)) {
  744. $uname = $hostname;
  745. }
  746. }
  747. // We will require an exact match if we have the fqdn for this
  748. // host; if we only have the short name, then we will consider it
  749. // to be a match if it matches the first part of the remote-host
  750. // item (up to the first dot).
  751. return (strpos($uname,'.') !== FALSE) ? ($host == $uname) : substr($host . '.',0,strlen($uname)+1) == $uname . '.';
  752. }
  753. /**
  754. * Return the user's home directory.
  755. */
  756. function drush_server_home() {
  757. // Cannot use $_SERVER superglobal since that's empty during Drush_UnitTestCase
  758. // getenv('HOME') isn't set on windows and generates a Notice.
  759. $home = getenv('HOME');
  760. if (empty($home)) {
  761. if (!empty($_SERVER['HOMEDRIVE']) && !empty($_SERVER['HOMEPATH'])) {
  762. // home on windows
  763. $home = $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
  764. }
  765. }
  766. return empty($home) ? NULL : $home;
  767. }
  768. /**
  769. * Return the name of the user running drush.
  770. */
  771. function drush_get_username() {
  772. $name = NULL;
  773. if (!$name = getenv("username")) { // Windows
  774. if (!$name = getenv("USER")) {
  775. // If USER not defined, use posix
  776. if (function_exists('posix_getpwuid')) {
  777. $processUser = posix_getpwuid(posix_geteuid());
  778. $name = $processUser['name'];
  779. }
  780. }
  781. }
  782. return $name;
  783. }
  784. /**
  785. * The path to the global cache directory.
  786. *
  787. * @param subdir
  788. * Return the specified subdirectory inside the global
  789. * cache directory instead. The subdirectory is created.
  790. */
  791. function drush_directory_cache($subdir = '') {
  792. $cache_locations = array();
  793. if (getenv('CACHE_PREFIX')) {
  794. $cache_locations[getenv('CACHE_PREFIX')] = 'cache';
  795. }
  796. $home = drush_server_home();
  797. if ($home) {
  798. $cache_locations[$home] = '.drush/cache';
  799. }
  800. $cache_locations[drush_find_tmp()] = 'drush-' . drush_get_username() . '/cache';
  801. foreach ($cache_locations as $base => $dir) {
  802. if (!empty($base) && is_writable($base)) {
  803. $cache_dir = $base . '/' . $dir;
  804. if (!empty($subdir)) {
  805. $cache_dir .= '/' . $subdir;
  806. }
  807. if (drush_mkdir($cache_dir)) {
  808. return $cache_dir;
  809. }
  810. else {
  811. // If the base directory is writable, but the cache directory
  812. // is not, then we will get an error. The error will be displayed,
  813. // but we will still call drush_clear_error so that we can go
  814. // on and try the next location to see if we can find a cache
  815. // directory somewhere.
  816. drush_clear_error();
  817. }
  818. }
  819. }
  820. return drush_set_error('DRUSH_NO_WRITABLE_CACHE', dt('Drush must have a writable cache directory; please insure that one of the following locations is writable: @locations',
  821. array('@locations' => implode(',', array_keys($cache_locations)))));
  822. }
  823. /**
  824. * Get complete information for all available extensions (modules and themes).
  825. *
  826. * @return
  827. * An array containing info for all available extensions.
  828. */
  829. function drush_get_extensions($include_hidden = TRUE) {
  830. drush_include_engine('drupal', 'environment');
  831. $extensions = array_merge(drush_get_modules($include_hidden), drush_get_themes($include_hidden));
  832. foreach ($extensions as $name => $extension) {
  833. if (isset($extension->info['name'])) {
  834. $extensions[$name]->label = $extension->info['name'].' ('.$extension->name.')';
  835. }
  836. else {
  837. drush_log(dt("Extension !name provides no human-readable name in .info file.", array('!name' => $name), 'debug'));
  838. $extensions[$name]->label = $name.' ('.$extension->name.')';
  839. }
  840. if (empty($extension->info['package'])) {
  841. $extensions[$name]->info['package'] = dt('Other');
  842. }
  843. }
  844. return $extensions;
  845. }
  846. /**
  847. * Test compatibility of a extension with version of drupal core and php.
  848. *
  849. * @param $file Extension object as returned by system_rebuild_module_data().
  850. * @return FALSE if the extension is compatible.
  851. */
  852. function drush_extension_check_incompatibility($file) {
  853. if (!isset($file->info['core']) || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY) {
  854. return 'Drupal';
  855. }
  856. if (version_compare(phpversion(), $file->info['php']) < 0) {
  857. return 'PHP';
  858. }
  859. return FALSE;
  860. }
  861. /**
  862. *
  863. */
  864. function drush_drupal_required_modules($modules) {
  865. drush_include_engine('drupal', 'environment');
  866. return _drush_drupal_required_modules($modules);
  867. }
  868. /**
  869. * Return the default theme.
  870. *
  871. * @return
  872. * Machine name of the default theme.
  873. */
  874. function drush_theme_get_default() {
  875. return variable_get('theme_default', 'garland');
  876. }
  877. /**
  878. * Return the administration theme.
  879. *
  880. * @return
  881. * Machine name of the administration theme.
  882. */
  883. function drush_theme_get_admin() {
  884. return variable_get('admin_theme', drush_theme_get_default());
  885. }
  886. /**
  887. * Returns the sitewide Drupal directory for extensions.
  888. */
  889. function drush_drupal_sitewide_directory($major_version = NULL) {
  890. if (!$major_version) {
  891. $major_version = drush_drupal_major_version();
  892. }
  893. return ($major_version < 8) ? 'sites/all' : '';
  894. }