5 * Functions used by drush to query the environment and
6 * setting the current configuration.
8 * Bootstrapping now occurs in bootstrap.inc.
10 * @see includes/bootstrap.inc
14 use Drush\Log\LogLevel;
15 use Webmozart\PathUtil\Path;
18 * Log PHP errors to the Drush log. This is in effect until Drupal's error
21 function drush_error_handler($errno, $message, $filename, $line, $context) {
22 // E_DEPRECATED was added in PHP 5.3. Drupal 6 will not fix all the
23 // deprecated errors, but suppresses them. So we suppress them as well.
24 if (defined('E_DEPRECATED')) {
25 $errno = $errno & ~E_DEPRECATED;
28 // "error_reporting" is usually set in php.ini, but may be changed by
29 // drush_errors_on() and drush_errors_off().
30 if ($errno & error_reporting()) {
31 // By default we log notices.
32 $type = Drush::config()->get('runtime.php.notices', LogLevel::INFO);
33 $halt_on_error = Drush::config()->get('runtime.php.halt-on-error', (drush_drupal_major_version() != 6));
35 // Bitmask value that constitutes an error needing to be logged.
36 $error = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
37 if ($errno & $error) {
41 // Bitmask value that constitutes a warning being logged.
42 $warning = E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING;
43 if ($errno & $warning) {
44 $type = LogLevel::WARNING;
47 drush_log($message . ' ' . basename($filename) . ':' . $line, $type);
49 if ($errno == E_RECOVERABLE_ERROR && $halt_on_error) {
50 drush_log(dt('E_RECOVERABLE_ERROR encountered; aborting. To ignore recoverable errors, run again with --no-halt-on-error'), 'error');
51 exit(DRUSH_APPLICATION_ERROR);
59 * Evalute the environment after an abnormal termination and
60 * see if we can determine any configuration settings that the user might
63 function _drush_postmortem() {
64 // Make sure that the memory limit has been bumped up from the minimum default value of 32M.
65 $php_memory_limit = drush_memory_limit();
66 if (($php_memory_limit > 0) && ($php_memory_limit <= 32*DRUSH_KILOBYTE*DRUSH_KILOBYTE)) {
67 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', ['!memory_limit' => $php_memory_limit / (DRUSH_KILOBYTE*DRUSH_KILOBYTE) . 'M', '!php_ini_msg' => _drush_php_ini_loaded_file_message()]));
72 * Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
73 * Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
74 * proper drive path, still with Unix slashes (c:/dir1).
76 function _drush_convert_path($path) {
77 $path = str_replace('\\','/', $path);
78 if (drush_is_windows() && !drush_is_cygwin()) {
79 $path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
86 * Build a drush command suitable for use for Drush to call itself.
87 * Used in backend_invoke.
89 function drush_build_drush_command($drush_path = NULL, $php = NULL, $os = NULL, $remote_command = FALSE, $environment_variables = []) {
90 $os = _drush_get_os($os);
91 $additional_options = '';
94 if (!$remote_command) {
95 $drush_path = DRUSH_COMMAND;
98 $drush_path = 'drush'; // drush_is_windows($os) ? 'drush.bat' : 'drush';
101 // If the path to drush points to drush.php, then we will need to
102 // run it via php rather than direct execution. By default, we
103 // will use 'php' unless something more specific was passed in
104 // via the --php flag.
105 if (substr($drush_path, -4) == ".php") {
107 $php = Drush::config()->get('php', 'php');
109 if (isset($php) && ($php != "php")) {
110 $additional_options .= ' --php=' . drush_escapeshellarg($php, $os);
112 // We will also add in the php options from --php-options
113 $prefix .= drush_escapeshellarg($php, $os);
114 $php_options = implode(' ', drush_get_context_options('php-options'));
115 if (!empty($php_options)) {
116 $prefix .= ' ' . $php_options;
117 $additional_options .= ' --php-options=' . drush_escapeshellarg($php_options, $os);
121 // Set environment variables to propogate config to redispatched calls.
122 if (drush_has_bash($os)) {
124 $environment_variables['DRUSH_PHP'] = $php;
126 if ($php_options_alias = drush_get_option('php-options', NULL, 'alias')) {
127 $environment_variables['PHP_OPTIONS'] = $php_options_alias;
129 $columns = drush_get_context('DRUSH_COLUMNS');
130 if (($columns) && ($columns != 80)) {
131 $environment_variables['COLUMNS'] = $columns;
136 // Add environmental variables, if present
137 if (!empty($environment_variables)) {
139 foreach ($environment_variables as $key=>$value) {
140 $prefix .= ' ' . drush_escapeshellarg($key, $os) . '=' . drush_escapeshellarg($value, $os);
144 return trim($prefix . ' ' . drush_escapeshellarg($drush_path, $os) . $additional_options);
148 * Check if the operating system is Winodws
149 * running some variant of cygwin -- either
150 * Cygwin or the MSYSGIT shell. If you care
151 * which is which, test mingw first.
153 function drush_is_cygwin($os = NULL) {
154 return _drush_test_os($os, ["CYGWIN","CWRSYNC","MINGW"]);
157 function drush_is_mingw($os = NULL) {
158 return _drush_test_os($os, ["MINGW"]);
162 * Check if the operating system is OS X.
163 * This will return TRUE for Mac OS X (Darwin).
165 function drush_is_osx($os = NULL) {
166 return _drush_test_os($os, ["DARWIN"]);
170 * Checks if the operating system has bash.
172 * MinGW has bash, but PHP isn't part of MinGW and hence doesn't run in bash.
174 function drush_has_bash($os = NULL) {
175 return (drush_is_cygwin($os) && !drush_is_mingw($os)) || !drush_is_windows($os);
179 * Checks operating system and returns supported bit bucket folder.
181 function drush_bit_bucket() {
182 return drush_has_bash() ? '/dev/null' : 'nul';
186 * Return the OS we are running under.
192 * MINGW* (e.g. MINGW32)
194 function _drush_get_os($os = NULL) {
195 // In most cases, $os will be NULL and PHP_OS will be returned. However, if an
196 // OS is specified in $os, return that instead.
197 return $os ?: PHP_OS;
200 function _drush_test_os($os, $os_list_to_check) {
201 $os = _drush_get_os($os);
202 foreach ($os_list_to_check as $test) {
203 if (strtoupper(substr($os, 0, strlen($test))) == strtoupper($test)) {
211 * Make a determination whether or not the given
212 * host is local or not.
215 * A hostname, 'localhost' or '127.0.0.1'.
217 * True if the host is local.
219 function drush_is_local_host($host) {
220 // Check to see if the provided host is "local".
221 // @see hook_drush_sitealias_alter() in drush.api.php.
222 return $host == 'localhost' || $host == '127.0.0.1';
226 * Determine whether current OS is a Windows variant.
228 function drush_is_windows($os = NULL) {
229 return strtoupper(substr(_drush_get_os($os), 0, 3)) === 'WIN';
232 function drush_escapeshellarg($arg, $os = NULL, $raw = FALSE) {
233 // Short-circuit escaping for simple params (keep stuff readable)
234 if (preg_match('|^[a-zA-Z0-9.:/_-]*$|', $arg)) {
237 elseif (drush_is_windows($os)) {
238 return _drush_escapeshellarg_windows($arg, $raw);
241 return _drush_escapeshellarg_linux($arg, $raw);
246 * Linux version of escapeshellarg().
248 * This is intended to work the same way that escapeshellarg() does on
249 * Linux. If we need to escape a string that will be used remotely on
250 * a Linux system, then we need our own implementation of escapeshellarg,
251 * because the Windows version behaves differently.
253 function _drush_escapeshellarg_linux($arg, $raw = FALSE) {
254 // For single quotes existing in the string, we will "exit"
255 // single-quote mode, add a \' and then "re-enter"
256 // single-quote mode. The result of this is that
257 // 'quote' becomes '\''quote'\''
258 $arg = preg_replace('/\'/', '\'\\\'\'', $arg);
260 // Replace "\t", "\n", "\r", "\0", "\x0B" with a whitespace.
261 // Note that this replacement makes Drush's escapeshellarg work differently
262 // than the built-in escapeshellarg in PHP on Linux, as these characters
263 // usually are NOT replaced. However, this was done deliberately to be more
264 // conservative when running _drush_escapeshellarg_linux on Windows
265 // (this can happen when generating a command to run on a remote Linux server.)
266 $arg = str_replace(["\t", "\n", "\r", "\0", "\x0B"], ' ', $arg);
268 // Only wrap with quotes when needed.
270 // Add surrounding quotes.
271 $arg = "'" . $arg . "'";
278 * Windows version of escapeshellarg().
280 function _drush_escapeshellarg_windows($arg, $raw = FALSE) {
281 // Double up existing backslashes
282 $arg = preg_replace('/\\\/', '\\\\\\\\', $arg);
284 // Double up double quotes
285 $arg = preg_replace('/"/', '""', $arg);
287 // Double up percents.
288 // $arg = preg_replace('/%/', '%%', $arg);
290 // Only wrap with quotes when needed.
292 // Add surrounding quotes.
293 $arg = '"' . $arg . '"';