@@ -383,15 +383,11 @@ function launch_editor_for_input( $input, $filename = 'WP-CLI' ) {
383383
384384 $ editor = getenv ( 'EDITOR ' );
385385 if ( ! $ editor ) {
386- $ editor = 'vi ' ;
387-
388- if ( isset ( $ _SERVER ['OS ' ] ) && false !== strpos ( $ _SERVER ['OS ' ], 'indows ' ) ) {
389- $ editor = 'notepad ' ;
390- }
386+ $ editor = is_windows () ? 'notepad ' : 'vi ' ;
391387 }
392388
393389 $ descriptorspec = array ( STDIN , STDOUT , STDERR );
394- $ process = proc_open ( "$ editor " . escapeshellarg ( $ tmpfile ), $ descriptorspec , $ pipes );
390+ $ process = proc_open_compat ( "$ editor " . escapeshellarg ( $ tmpfile ), $ descriptorspec , $ pipes );
395391 $ r = proc_close ( $ process );
396392 if ( $ r ) {
397393 exit ( $ r );
@@ -453,7 +449,7 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) {
453449
454450 $ final_cmd = force_env_on_nix_systems ( $ cmd ) . assoc_args_to_str ( $ assoc_args );
455451
456- $ proc = proc_open ( $ final_cmd , $ descriptors , $ pipes );
452+ $ proc = proc_open_compat ( $ final_cmd , $ descriptors , $ pipes );
457453 if ( ! $ proc ) {
458454 exit ( 1 );
459455 }
@@ -515,14 +511,15 @@ function mustache_render( $template_name, $data = array() ) {
515511 *
516512 * @param string $message Text to display before the progress bar.
517513 * @param integer $count Total number of ticks to be performed.
514+ * @param int $interval Optional. The interval in milliseconds between updates. Default 100.
518515 * @return cli\progress\Bar|WP_CLI\NoOp
519516 */
520- function make_progress_bar ( $ message , $ count ) {
517+ function make_progress_bar ( $ message , $ count, $ interval = 100 ) {
521518 if ( \cli \Shell::isPiped () ) {
522519 return new \WP_CLI \NoOp ;
523520 }
524521
525- return new \cli \progress \Bar ( $ message , $ count );
522+ return new \cli \progress \Bar ( $ message , $ count, $ interval );
526523}
527524
528525function parse_url ( $ url ) {
@@ -775,6 +772,16 @@ function trailingslashit( $string ) {
775772 return rtrim ( $ string , '/ \\' ) . '/ ' ;
776773}
777774
775+ /**
776+ * Convert Windows EOLs to *nix.
777+ *
778+ * @param string $str String to convert.
779+ * @return string String with carriage return / newline pairs reduced to newlines.
780+ */
781+ function normalize_eols ( $ str ) {
782+ return str_replace ( "\r\n" , "\n" , $ str );
783+ }
784+
778785/**
779786 * Get the system's temp directory. Warns user if it isn't writable.
780787 *
@@ -790,14 +797,8 @@ function get_temp_dir() {
790797 return $ temp ;
791798 }
792799
793- $ temp = '/tmp/ ' ;
794-
795- // `sys_get_temp_dir()` introduced PHP 5.2.1.
796- if ( $ try = sys_get_temp_dir () ) {
797- $ temp = trailingslashit ( $ try );
798- } elseif ( $ try = ini_get ( 'upload_tmp_dir ' ) ) {
799- $ temp = trailingslashit ( $ try );
800- }
800+ // `sys_get_temp_dir()` introduced PHP 5.2.1. Will always return something.
801+ $ temp = trailingslashit ( sys_get_temp_dir () );
801802
802803 if ( ! is_writable ( $ temp ) ) {
803804 \WP_CLI ::warning ( "Temp directory isn't writable: {$ temp }" );
@@ -1110,7 +1111,9 @@ function glob_brace( $pattern, $dummy_flags = null ) {
11101111function get_suggestion ( $ target , array $ options , $ threshold = 2 ) {
11111112
11121113 $ suggestion_map = array (
1114+ 'add ' => 'create ' ,
11131115 'check ' => 'check-update ' ,
1116+ 'capability ' => 'cap ' ,
11141117 'clear ' => 'flush ' ,
11151118 'decrement ' => 'decr ' ,
11161119 'del ' => 'delete ' ,
@@ -1126,10 +1129,11 @@ function get_suggestion( $target, array $options, $threshold = 2 ) {
11261129 'regen ' => 'regenerate ' ,
11271130 'rep ' => 'replace ' ,
11281131 'repl ' => 'replace ' ,
1132+ 'trash ' => 'delete ' ,
11291133 'v ' => 'version ' ,
11301134 );
11311135
1132- if ( array_key_exists ( $ target , $ suggestion_map ) ) {
1136+ if ( array_key_exists ( $ target , $ suggestion_map ) && in_array ( $ suggestion_map [ $ target ], $ options , true ) ) {
11331137 return $ suggestion_map [ $ target ];
11341138 }
11351139
@@ -1318,3 +1322,132 @@ function get_php_binary() {
13181322
13191323 return 'php ' ;
13201324}
1325+
1326+ /**
1327+ * Windows compatible `proc_open()`.
1328+ * Works around bug in PHP, and also deals with *nix-like `ENV_VAR=blah cmd` environment variable prefixes.
1329+ *
1330+ * @access public
1331+ *
1332+ * @param string $command Command to execute.
1333+ * @param array $descriptorspec Indexed array of descriptor numbers and their values.
1334+ * @param array &$pipes Indexed array of file pointers that correspond to PHP's end of any pipes that are created.
1335+ * @param string $cwd Initial working directory for the command.
1336+ * @param array $env Array of environment variables.
1337+ * @param array $other_options Array of additional options (Windows only).
1338+ *
1339+ * @return string Command stripped of any environment variable settings.
1340+ */
1341+ function proc_open_compat ( $ cmd , $ descriptorspec , &$ pipes , $ cwd = null , $ env = null , $ other_options = null ) {
1342+ if ( is_windows () ) {
1343+ // Need to encompass the whole command in double quotes - PHP bug https://bugs.php.net/bug.php?id=49139
1344+ $ cmd = '" ' . _proc_open_compat_win_env ( $ cmd , $ env ) . '" ' ;
1345+ }
1346+ return proc_open ( $ cmd , $ descriptorspec , $ pipes , $ cwd , $ env , $ other_options );
1347+ }
1348+
1349+ /**
1350+ * For use by `proc_open_compat()` only. Separated out for ease of testing. Windows only.
1351+ * Turns *nix-like `ENV_VAR=blah command` environment variable prefixes into stripped `cmd` with prefixed environment variables added to passed in environment array.
1352+ *
1353+ * @access private
1354+ *
1355+ * @param string $command Command to execute.
1356+ * @param array &$env Array of existing environment variables. Will be modified if any settings in command.
1357+ *
1358+ * @return string Command stripped of any environment variable settings.
1359+ */
1360+ function _proc_open_compat_win_env ( $ cmd , &$ env ) {
1361+ if ( false !== strpos ( $ cmd , '= ' ) ) {
1362+ while ( preg_match ( '/^([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|[^ ]*) / ' , $ cmd , $ matches ) ) {
1363+ $ cmd = substr ( $ cmd , strlen ( $ matches [0 ] ) );
1364+ if ( null === $ env ) {
1365+ $ env = array ();
1366+ }
1367+ $ env [ $ matches [1 ] ] = isset ( $ matches [2 ][0 ] ) && '" ' === $ matches [2 ][0 ] ? substr ( $ matches [2 ], 1 , -1 ) : $ matches [2 ];
1368+ }
1369+ }
1370+ return $ cmd ;
1371+ }
1372+
1373+ /**
1374+ * First half of escaping for LIKE special characters % and _ before preparing for MySQL.
1375+ *
1376+ * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security.
1377+ *
1378+ * Copied from core "wp-includes/wp-db.php". Avoids dependency on WP 4.4 wpdb.
1379+ *
1380+ * @access public
1381+ *
1382+ * @param string $text The raw text to be escaped. The input typed by the user should have no
1383+ * extra or deleted slashes.
1384+ * @return string Text in the form of a LIKE phrase. The output is not SQL safe. Call $wpdb::prepare()
1385+ * or real_escape next.
1386+ */
1387+ function esc_like ( $ text ) {
1388+ return addcslashes ( $ text , '_% \\' );
1389+ }
1390+
1391+ /**
1392+ * Escapes (backticks) MySQL identifiers (aka schema object names) - i.e. column names, table names, and database/index/alias/view etc names.
1393+ * See https://dev.mysql.com/doc/refman/5.5/en/identifiers.html
1394+ *
1395+ * @param string|array $idents A single identifier or an array of identifiers.
1396+ * @return string|array An escaped string if given a string, or an array of escaped strings if given an array of strings.
1397+ */
1398+ function esc_sql_ident ( $ idents ) {
1399+ $ backtick = function ( $ v ) {
1400+ // Escape any backticks in the identifier by doubling.
1401+ return '` ' . str_replace ( '` ' , '`` ' , $ v ) . '` ' ;
1402+ };
1403+ if ( is_string ( $ idents ) ) {
1404+ return $ backtick ( $ idents );
1405+ }
1406+ return array_map ( $ backtick , $ idents );
1407+ }
1408+
1409+ /**
1410+ * Check whether a given string is a valid JSON representation.
1411+ *
1412+ * @param string $argument String to evaluate.
1413+ * @param bool $ignore_scalars Optional. Whether to ignore scalar values.
1414+ * Defaults to true.
1415+ *
1416+ * @return bool Whether the provided string is a valid JSON representation.
1417+ */
1418+ function is_json ( $ argument , $ ignore_scalars = true ) {
1419+ if ( ! is_string ( $ argument ) || '' === $ argument ) {
1420+ return false ;
1421+ }
1422+
1423+ if ( $ ignore_scalars && ! in_array ( $ argument [0 ], array ( '{ ' , '[ ' ), true ) ) {
1424+ return false ;
1425+ }
1426+
1427+ json_decode ( $ argument , $ assoc = true );
1428+
1429+ return json_last_error () === JSON_ERROR_NONE ;
1430+ }
1431+
1432+ /**
1433+ * Parse known shell arrays included in the $assoc_args array.
1434+ *
1435+ * @param array $assoc_args Associative array of arguments.
1436+ * @param array $array_arguments Array of argument keys that should receive an
1437+ * array through the shell.
1438+ *
1439+ * @return array
1440+ */
1441+ function parse_shell_arrays ( $ assoc_args , $ array_arguments ) {
1442+ if ( empty ( $ assoc_args ) || empty ( $ array_arguments ) ) {
1443+ return $ assoc_args ;
1444+ }
1445+
1446+ foreach ( $ array_arguments as $ key ) {
1447+ if ( array_key_exists ( $ key , $ assoc_args ) && is_json ( $ assoc_args [ $ key ] ) ) {
1448+ $ assoc_args [ $ key ] = json_decode ( $ assoc_args [ $ key ], $ assoc = true );
1449+ }
1450+ }
1451+
1452+ return $ assoc_args ;
1453+ }
0 commit comments