%PDF- %PDF-
Direktori : /var/www/html/ceaa/wp-content/plugins/buddypress/cli/features/bootstrap/ |
Current File : /var/www/html/ceaa/wp-content/plugins/buddypress/cli/features/bootstrap/utils.php |
<?php // Utilities that do NOT depend on WordPress code. namespace WP_CLI\Utils; use \Composer\Semver\Comparator; use \Composer\Semver\Semver; use \WP_CLI; use \WP_CLI\Dispatcher; use \WP_CLI\Iterators\Transform; const PHAR_STREAM_PREFIX = 'phar://'; function inside_phar() { return 0 === strpos( WP_CLI_ROOT, PHAR_STREAM_PREFIX ); } // Files that need to be read by external programs have to be extracted from the Phar archive. function extract_from_phar( $path ) { if ( ! inside_phar() ) { return $path; } $fname = basename( $path ); $tmp_path = get_temp_dir() . "wp-cli-$fname"; copy( $path, $tmp_path ); register_shutdown_function( function() use ( $tmp_path ) { @unlink( $tmp_path ); } ); return $tmp_path; } function load_dependencies() { if ( inside_phar() ) { if ( file_exists( WP_CLI_ROOT . '/vendor/autoload.php' ) ) { require WP_CLI_ROOT . '/vendor/autoload.php'; } elseif ( file_exists( dirname( dirname( WP_CLI_ROOT ) ) . '/autoload.php' ) ) { require dirname( dirname( WP_CLI_ROOT ) ) . '/autoload.php'; } return; } $has_autoload = false; foreach ( get_vendor_paths() as $vendor_path ) { if ( file_exists( $vendor_path . '/autoload.php' ) ) { require $vendor_path . '/autoload.php'; $has_autoload = true; break; } } if ( !$has_autoload ) { fputs( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); exit(3); } } function get_vendor_paths() { $vendor_paths = array( WP_CLI_ROOT . '/../../../vendor', // part of a larger project / installed via Composer (preferred) WP_CLI_ROOT . '/vendor', // top-level project / installed as Git clone ); $maybe_composer_json = WP_CLI_ROOT . '/../../../composer.json'; if ( file_exists( $maybe_composer_json ) && is_readable( $maybe_composer_json ) ) { $composer = json_decode( file_get_contents( $maybe_composer_json ) ); if ( ! empty( $composer->config ) && ! empty( $composer->config->{'vendor-dir'} ) ) { array_unshift( $vendor_paths, WP_CLI_ROOT . '/../../../' . $composer->config->{'vendor-dir'} ); } } return $vendor_paths; } // Using require() directly inside a class grants access to private methods to the loaded code function load_file( $path ) { require_once $path; } function load_command( $name ) { $path = WP_CLI_ROOT . "/php/commands/$name.php"; if ( is_readable( $path ) ) { include_once $path; } } /** * Like array_map(), except it returns a new iterator, instead of a modified array. * * Example: * * $arr = array('Football', 'Socker'); * * $it = iterator_map($arr, 'strtolower', function($val) { * return str_replace('foo', 'bar', $val); * }); * * foreach ( $it as $val ) { * var_dump($val); * } * * @param array|object Either a plain array or another iterator * @param callback The function to apply to an element * @return object An iterator that applies the given callback(s) */ function iterator_map( $it, $fn ) { if ( is_array( $it ) ) { $it = new \ArrayIterator( $it ); } if ( !method_exists( $it, 'add_transform' ) ) { $it = new Transform( $it ); } foreach ( array_slice( func_get_args(), 1 ) as $fn ) { $it->add_transform( $fn ); } return $it; } /** * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true * @param string|array The files (or file) to search for * @param string|null The directory to start searching from; defaults to CWD * @param callable Function which is passed the current dir each time a directory level is traversed * @return null|string Null if the file was not found */ function find_file_upward( $files, $dir = null, $stop_check = null ) { $files = (array) $files; if ( is_null( $dir ) ) { $dir = getcwd(); } while ( @is_readable( $dir ) ) { // Stop walking up when the supplied callable returns true being passed the $dir if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) { return null; } foreach ( $files as $file ) { $path = $dir . DIRECTORY_SEPARATOR . $file; if ( file_exists( $path ) ) { return $path; } } $parent_dir = dirname( $dir ); if ( empty($parent_dir) || $parent_dir === $dir ) { break; } $dir = $parent_dir; } return null; } function is_path_absolute( $path ) { // Windows if ( isset($path[1]) && ':' === $path[1] ) return true; return $path[0] === '/'; } /** * Composes positional arguments into a command string. * * @param array * @return string */ function args_to_str( $args ) { return ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); } /** * Composes associative arguments into a command string. * * @param array * @return string */ function assoc_args_to_str( $assoc_args ) { $str = ''; foreach ( $assoc_args as $key => $value ) { if ( true === $value ) { $str .= " --$key"; } elseif( is_array( $value ) ) { foreach( $value as $_ => $v ) { $str .= assoc_args_to_str( array( $key => $v ) ); } } else { $str .= " --$key=" . escapeshellarg( $value ); } } return $str; } /** * Given a template string and an arbitrary number of arguments, * returns the final command, with the parameters escaped. */ function esc_cmd( $cmd ) { if ( func_num_args() < 2 ) trigger_error( 'esc_cmd() requires at least two arguments.', E_USER_WARNING ); $args = func_get_args(); $cmd = array_shift( $args ); return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) ); } function locate_wp_config() { static $path; if ( null === $path ) { if ( file_exists( ABSPATH . 'wp-config.php' ) ) $path = ABSPATH . 'wp-config.php'; elseif ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) $path = ABSPATH . '../wp-config.php'; else $path = false; if ( $path ) $path = realpath( $path ); } return $path; } function wp_version_compare( $since, $operator ) { return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); } /** * Render a collection of items as an ASCII table, JSON, CSV, YAML, list of ids, or count. * * Given a collection of items with a consistent data structure: * * ``` * $items = array( * array( * 'key' => 'foo', * 'value' => 'bar', * ) * ); * ``` * * Render `$items` as an ASCII table: * * ``` * WP_CLI\Utils\format_items( 'table', $items, array( 'key', 'value' ) ); * * # +-----+-------+ * # | key | value | * # +-----+-------+ * # | foo | bar | * # +-----+-------+ * ``` * * Or render `$items` as YAML: * * ``` * WP_CLI\Utils\format_items( 'yaml', $items, array( 'key', 'value' ) ); * * # --- * # - * # key: foo * # value: bar * ``` * * @access public * @category Output * * @param string $format Format to use: 'table', 'json', 'csv', 'yaml', 'ids', 'count' * @param array $items An array of items to output. * @param array|string $fields Named fields for each item of data. Can be array or comma-separated list. * @return null */ function format_items( $format, $items, $fields ) { $assoc_args = compact( 'format', 'fields' ); $formatter = new \WP_CLI\Formatter( $assoc_args ); $formatter->display_items( $items ); } /** * Write data as CSV to a given file. * * @access public * * @param resource $fd File descriptor * @param array $rows Array of rows to output * @param array $headers List of CSV columns (optional) */ function write_csv( $fd, $rows, $headers = array() ) { if ( ! empty( $headers ) ) { fputcsv( $fd, $headers ); } foreach ( $rows as $row ) { if ( ! empty( $headers ) ) { $row = pick_fields( $row, $headers ); } fputcsv( $fd, array_values( $row ) ); } } /** * Pick fields from an associative array or object. * * @param array|object Associative array or object to pick fields from * @param array List of fields to pick * @return array */ function pick_fields( $item, $fields ) { $item = (object) $item; $values = array(); foreach ( $fields as $field ) { $values[ $field ] = isset( $item->$field ) ? $item->$field : null; } return $values; } /** * Launch system's $EDITOR for the user to edit some text. * * @access public * @category Input * * @param string $content Some form of text to edit (e.g. post content) * @return string|bool Edited text, if file is saved from editor; false, if no change to file. */ function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { check_proc_available( 'launch_editor_for_input' ); $tmpdir = get_temp_dir(); do { $tmpfile = basename( $filename ); $tmpfile = preg_replace( '|\.[^.]*$|', '', $tmpfile ); $tmpfile .= '-' . substr( md5( rand() ), 0, 6 ); $tmpfile = $tmpdir . $tmpfile . '.tmp'; $fp = @fopen( $tmpfile, 'x' ); if ( ! $fp && is_writable( $tmpdir ) && file_exists( $tmpfile ) ) { $tmpfile = ''; continue; } if ( $fp ) { fclose( $fp ); } } while( ! $tmpfile ); if ( ! $tmpfile ) { \WP_CLI::error( 'Error creating temporary file.' ); } $output = ''; file_put_contents( $tmpfile, $input ); $editor = getenv( 'EDITOR' ); if ( !$editor ) { if ( isset( $_SERVER['OS'] ) && false !== strpos( $_SERVER['OS'], 'indows' ) ) $editor = 'notepad'; else $editor = 'vi'; } $descriptorspec = array( STDIN, STDOUT, STDERR ); $process = proc_open( "$editor " . escapeshellarg( $tmpfile ), $descriptorspec, $pipes ); $r = proc_close( $process ); if ( $r ) { exit( $r ); } $output = file_get_contents( $tmpfile ); unlink( $tmpfile ); if ( $output === $input ) return false; return $output; } /** * @param string MySQL host string, as defined in wp-config.php * @return array */ function mysql_host_to_cli_args( $raw_host ) { $assoc_args = array(); $host_parts = explode( ':', $raw_host ); if ( count( $host_parts ) == 2 ) { list( $assoc_args['host'], $extra ) = $host_parts; $extra = trim( $extra ); if ( is_numeric( $extra ) ) { $assoc_args['port'] = intval( $extra ); $assoc_args['protocol'] = 'tcp'; } else if ( $extra !== '' ) { $assoc_args['socket'] = $extra; } } else { $assoc_args['host'] = $raw_host; } return $assoc_args; } function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { check_proc_available( 'run_mysql_command' ); if ( !$descriptors ) $descriptors = array( STDIN, STDOUT, STDERR ); if ( isset( $assoc_args['host'] ) ) { $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); } $pass = $assoc_args['pass']; unset( $assoc_args['pass'] ); $old_pass = getenv( 'MYSQL_PWD' ); putenv( 'MYSQL_PWD=' . $pass ); $final_cmd = force_env_on_nix_systems( $cmd ) . assoc_args_to_str( $assoc_args ); $proc = proc_open( $final_cmd, $descriptors, $pipes ); if ( !$proc ) exit(1); $r = proc_close( $proc ); putenv( 'MYSQL_PWD=' . $old_pass ); if ( $r ) exit( $r ); } /** * Render PHP or other types of files using Mustache templates. * * IMPORTANT: Automatic HTML escaping is disabled! */ function mustache_render( $template_name, $data = array() ) { if ( ! file_exists( $template_name ) ) $template_name = WP_CLI_ROOT . "/templates/$template_name"; $template = file_get_contents( $template_name ); $m = new \Mustache_Engine( array( 'escape' => function ( $val ) { return $val; }, ) ); return $m->render( $template, $data ); } /** * Create a progress bar to display percent completion of a given operation. * * Progress bar is written to STDOUT, and disabled when command is piped. Progress * advances with `$progress->tick()`, and completes with `$progress->finish()`. * Process bar also indicates elapsed time and expected total time. * * ``` * # `wp user generate` ticks progress bar each time a new user is created. * # * # $ wp user generate --count=500 * # Generating users 22 % [=======> ] 0:05 / 0:23 * * $progress = \WP_CLI\Utils\make_progress_bar( 'Generating users', $count ); * for ( $i = 0; $i < $count; $i++ ) { * // uses wp_insert_user() to insert the user * $progress->tick(); * } * $progress->finish(); * ``` * * @access public * @category Output * * @param string $message Text to display before the progress bar. * @param integer $count Total number of ticks to be performed. * @return cli\progress\Bar|WP_CLI\NoOp */ function make_progress_bar( $message, $count ) { if ( \cli\Shell::isPiped() ) return new \WP_CLI\NoOp; return new \cli\progress\Bar( $message, $count ); } function parse_url( $url ) { $url_parts = \parse_url( $url ); if ( !isset( $url_parts['scheme'] ) ) { $url_parts = parse_url( 'http://' . $url ); } return $url_parts; } /** * Check if we're running in a Windows environment (cmd.exe). * * @return bool */ function is_windows() { return false !== ( $test_is_windows = getenv( 'WP_CLI_TEST_IS_WINDOWS' ) ) ? (bool) $test_is_windows : strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; } /** * Replace magic constants in some PHP source code. * * @param string $source The PHP code to manipulate. * @param string $path The path to use instead of the magic constants */ function replace_path_consts( $source, $path ) { $replacements = array( '__FILE__' => "'$path'", '__DIR__' => "'" . dirname( $path ) . "'", ); $old = array_keys( $replacements ); $new = array_values( $replacements ); return str_replace( $old, $new, $source ); } /** * Make a HTTP request to a remote URL. * * Wraps the Requests HTTP library to ensure every request includes a cert. * * ``` * # `wp core download` verifies the hash for a downloaded WordPress archive * * $md5_response = Utils\http_request( 'GET', $download_url . '.md5' ); * if ( 20 != substr( $md5_response->status_code, 0, 2 ) ) { * WP_CLI::error( "Couldn't access md5 hash for release (HTTP code {$response->status_code})" ); * } * ``` * * @access public * * @param string $method HTTP method (GET, POST, DELETE, etc.) * @param string $url URL to make the HTTP request to. * @param array $headers Add specific headers to the request. * @param array $options * @return object */ function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { $cert_path = '/rmccue/requests/library/Requests/Transport/cacert.pem'; if ( inside_phar() ) { // cURL can't read Phar archives $options['verify'] = extract_from_phar( WP_CLI_VENDOR_DIR . $cert_path ); } else { foreach( get_vendor_paths() as $vendor_path ) { if ( file_exists( $vendor_path . $cert_path ) ) { $options['verify'] = $vendor_path . $cert_path; break; } } if ( empty( $options['verify'] ) ){ WP_CLI::error( "Cannot find SSL certificate." ); } } try { $request = \Requests::request( $url, $headers, $data, $method, $options ); return $request; } catch( \Requests_Exception $ex ) { // CURLE_SSL_CACERT_BADFILE only defined for PHP >= 7. if ( 'curlerror' !== $ex->getType() || ! in_array( curl_errno( $ex->getData() ), array( CURLE_SSL_CONNECT_ERROR, CURLE_SSL_CERTPROBLEM, 77 /*CURLE_SSL_CACERT_BADFILE*/ ), true ) ) { \WP_CLI::error( sprintf( "Failed to get url '%s': %s.", $url, $ex->getMessage() ) ); } // Handle SSL certificate issues gracefully \WP_CLI::warning( sprintf( "Re-trying without verify after failing to get verified url '%s' %s.", $url, $ex->getMessage() ) ); $options['verify'] = false; try { return \Requests::request( $url, $headers, $data, $method, $options ); } catch( \Requests_Exception $ex ) { \WP_CLI::error( sprintf( "Failed to get non-verified url '%s' %s.", $url, $ex->getMessage() ) ); } } } /** * Increments a version string using the "x.y.z-pre" format * * Can increment the major, minor or patch number by one * If $new_version == "same" the version string is not changed * If $new_version is not a known keyword, it will be used as the new version string directly * * @param string $current_version * @param string $new_version * @return string */ function increment_version( $current_version, $new_version ) { // split version assuming the format is x.y.z-pre $current_version = explode( '-', $current_version, 2 ); $current_version[0] = explode( '.', $current_version[0] ); switch ( $new_version ) { case 'same': // do nothing break; case 'patch': $current_version[0][2]++; $current_version = array( $current_version[0] ); // drop possible pre-release info break; case 'minor': $current_version[0][1]++; $current_version[0][2] = 0; $current_version = array( $current_version[0] ); // drop possible pre-release info break; case 'major': $current_version[0][0]++; $current_version[0][1] = 0; $current_version[0][2] = 0; $current_version = array( $current_version[0] ); // drop possible pre-release info break; default: // not a keyword $current_version = array( array( $new_version ) ); break; } // reconstruct version string $current_version[0] = implode( '.', $current_version[0] ); $current_version = implode( '-', $current_version ); return $current_version; } /** * Compare two version strings to get the named semantic version. * * @access public * * @param string $new_version * @param string $original_version * @return string $name 'major', 'minor', 'patch' */ function get_named_sem_ver( $new_version, $original_version ) { if ( ! Comparator::greaterThan( $new_version, $original_version ) ) { return ''; } $parts = explode( '-', $original_version ); $bits = explode( '.', $parts[0] ); $major = $bits[0]; if ( isset( $bits[1] ) ) { $minor = $bits[1]; } if ( isset( $bits[2] ) ) { $patch = $bits[2]; } if ( ! is_null( $minor ) && Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { return 'patch'; } else if ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { return 'minor'; } else { return 'major'; } } /** * Return the flag value or, if it's not set, the $default value. * * Because flags can be negated (e.g. --no-quiet to negate --quiet), this * function provides a safer alternative to using * `isset( $assoc_args['quiet'] )` or similar. * * @access public * @category Input * * @param array $assoc_args Arguments array. * @param string $flag Flag to get the value. * @param mixed $default Default value for the flag. Default: NULL * @return mixed */ function get_flag_value( $assoc_args, $flag, $default = null ) { return isset( $assoc_args[ $flag ] ) ? $assoc_args[ $flag ] : $default; } /** * Get the home directory. * * @access public * @category System * * @return string */ function get_home_dir() { $home = getenv( 'HOME' ); if ( ! $home ) { // In Windows $HOME may not be defined $home = getenv( 'HOMEDRIVE' ) . getenv( 'HOMEPATH' ); } return rtrim( $home, '/\\' ); } /** * Appends a trailing slash. * * @access public * @category System * * @param string $string What to add the trailing slash to. * @return string String with trailing slash added. */ function trailingslashit( $string ) { return rtrim( $string, '/\\' ) . '/'; } /** * Get the system's temp directory. Warns user if it isn't writable. * * @access public * @category System * * @return string */ function get_temp_dir() { static $temp = ''; if ( $temp ) { return $temp; } // `sys_get_temp_dir()` introduced PHP 5.2.1. if ( $try = sys_get_temp_dir() ) { $temp = trailingslashit( $try ); } elseif ( $try = ini_get( 'upload_tmp_dir' ) ) { $temp = trailingslashit( $try ); } else { $temp = '/tmp/'; } if ( ! @is_writable( $temp ) ) { \WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); } return $temp; } /** * Parse a SSH url for its host, port, and path. * * Similar to parse_url(), but adds support for defined SSH aliases. * * ``` * host OR host/path/to/wordpress OR host:port/path/to/wordpress * ``` * * @access public * * @return mixed */ function parse_ssh_url( $url, $component = -1 ) { preg_match( '#^((docker|docker\-compose|ssh|vagrant):)?(([^@:]+)@)?([^:/~]+)(:([\d]*))?((/|~)(.+))?$#', $url, $matches ); $bits = array(); foreach( array( 2 => 'scheme', 4 => 'user', 5 => 'host', 7 => 'port', 8 => 'path', ) as $i => $key ) { if ( ! empty( $matches[ $i ] ) ) { $bits[ $key ] = $matches[ $i ]; } } switch ( $component ) { case PHP_URL_SCHEME: return isset( $bits['scheme'] ) ? $bits['scheme'] : null; case PHP_URL_USER: return isset( $bits['user'] ) ? $bits['user'] : null; case PHP_URL_HOST: return isset( $bits['host'] ) ? $bits['host'] : null; case PHP_URL_PATH: return isset( $bits['path'] ) ? $bits['path'] : null; case PHP_URL_PORT: return isset( $bits['port'] ) ? $bits['port'] : null; default: return $bits; } } /** * Report the results of the same operation against multiple resources. * * @access public * @category Input * * @param string $noun Resource being affected (e.g. plugin) * @param string $verb Type of action happening to the noun (e.g. activate) * @param integer $total Total number of resource being affected. * @param integer $successes Number of successful operations. * @param integer $failures Number of failures. */ function report_batch_operation_results( $noun, $verb, $total, $successes, $failures ) { $plural_noun = $noun . 's'; $past_tense_verb = past_tense_verb( $verb ); $past_tense_verb_upper = ucfirst( $past_tense_verb ); if ( $failures ) { if ( $successes ) { WP_CLI::error( "Only {$past_tense_verb} {$successes} of {$total} {$plural_noun}." ); } else { WP_CLI::error( "No {$plural_noun} {$past_tense_verb}." ); } } else { if ( $successes ) { WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}." ); } else { $message = $total > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); WP_CLI::success( "{$message} already {$past_tense_verb}." ); } } } /** * Parse a string of command line arguments into an $argv-esqe variable. * * @access public * @category Input * * @param string $arguments * @return array */ function parse_str_to_argv( $arguments ) { preg_match_all ('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $arguments, $matches ); $argv = isset( $matches[0] ) ? $matches[0] : array(); $argv = array_map( function( $arg ){ foreach( array( '"', "'" ) as $char ) { if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { $arg = substr( $arg, 1, -1 ); break; } } return $arg; }, $argv ); return $argv; } /** * Locale-independent version of basename() * * @access public * * @param string $path * @param string $suffix * @return string */ function basename( $path, $suffix = '' ) { return urldecode( \basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) ); } /** * Checks whether the output of the current script is a TTY or a pipe / redirect * * Returns true if STDOUT output is being redirected to a pipe or a file; false is * output is being sent directly to the terminal. * * If an env variable SHELL_PIPE exists, returned result depends it's * value. Strings like 1, 0, yes, no, that validate to booleans are accepted. * * To enable ASCII formatting even when shell is piped, use the * ENV variable SHELL_PIPE=0 * * @access public * * @return bool */ function isPiped() { $shellPipe = getenv('SHELL_PIPE'); if ($shellPipe !== false) { return filter_var($shellPipe, FILTER_VALIDATE_BOOLEAN); } else { return (function_exists('posix_isatty') && !posix_isatty(STDOUT)); } } /** * Expand within paths to their matching paths. * * Has no effect on paths which do not use glob patterns. * * @param string|array $paths Single path as a string, or an array of paths. * @param int $flags Optional. Flags to pass to glob. Defaults to GLOB_BRACE. * * @return array Expanded paths. */ function expand_globs( $paths, $flags = 'default' ) { // Compatibility for systems without GLOB_BRACE. $glob_func = 'glob'; if ( 'default' === $flags ) { if ( ! defined( 'GLOB_BRACE' ) || getenv( 'WP_CLI_TEST_EXPAND_GLOBS_NO_GLOB_BRACE' ) ) { $glob_func = 'WP_CLI\Utils\glob_brace'; } else { $flags = GLOB_BRACE; } } $expanded = array(); foreach ( (array) $paths as $path ) { $matching = array( $path ); if ( preg_match( '/[' . preg_quote( '*?[]{}!', '/' ) . ']/', $path ) ) { $matching = $glob_func( $path, $flags ) ?: array(); } $expanded = array_merge( $expanded, $matching ); } return array_values( array_unique( $expanded ) ); } /** * Simulate a `glob()` with the `GLOB_BRACE` flag set. For systems (eg Alpine Linux) built against a libc library (eg https://www.musl-libc.org/) that lacks it. * Copied and adapted from Zend Framework's `Glob::fallbackGlob()` and Glob::nextBraceSub()`. * * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * * @param string $pattern Filename pattern. * @param void $dummy_flags Not used. * * @return array Array of paths. */ function glob_brace( $pattern, $dummy_flags = null ) { static $next_brace_sub; if ( ! $next_brace_sub ) { // Find the end of the subpattern in a brace expression. $next_brace_sub = function ( $pattern, $current ) { $length = strlen( $pattern ); $depth = 0; while ( $current < $length ) { if ( '\\' === $pattern[ $current ] ) { if ( ++$current === $length ) { break; } $current++; } else { if ( ( '}' === $pattern[ $current ] && $depth-- === 0 ) || ( ',' === $pattern[ $current ] && 0 === $depth ) ) { break; } elseif ( '{' === $pattern[ $current++ ] ) { $depth++; } } } return $current < $length ? $current : null; }; } $length = strlen( $pattern ); // Find first opening brace. for ( $begin = 0; $begin < $length; $begin++ ) { if ( '\\' === $pattern[ $begin ] ) { $begin++; } elseif ( '{' === $pattern[ $begin ] ) { break; } } // Find comma or matching closing brace. if ( null === ( $next = $next_brace_sub( $pattern, $begin + 1 ) ) ) { return glob( $pattern ); } $rest = $next; // Point `$rest` to matching closing brace. while ( '}' !== $pattern[ $rest ] ) { if ( null === ( $rest = $next_brace_sub( $pattern, $rest + 1 ) ) ) { return glob( $pattern ); } } $paths = array(); $p = $begin + 1; // For each comma-separated subpattern. do { $subpattern = substr( $pattern, 0, $begin ) . substr( $pattern, $p, $next - $p ) . substr( $pattern, $rest + 1 ); if ( ( $result = glob_brace( $subpattern ) ) ) { $paths = array_merge( $paths, $result ); } if ( '}' === $pattern[ $next ] ) { break; } $p = $next + 1; $next = $next_brace_sub( $pattern, $p ); } while ( null !== $next ); return array_values( array_unique( $paths ) ); } /** * Get the closest suggestion for a mis-typed target term amongst a list of * options. * * Uses the Levenshtein algorithm to calculate the relative "distance" between * terms. * * If the "distance" to the closest term is higher than the threshold, an empty * string is returned. * * @param string $target Target term to get a suggestion for. * @param array $options Array with possible options. * @param int $threshold Threshold above which to return an empty string. * * @return string */ function get_suggestion( $target, array $options, $threshold = 2 ) { if ( empty( $options ) ) { return ''; } foreach ( $options as $option ) { $distance = levenshtein( $option, $target ); $levenshtein[ $option ] = $distance; } // Sort known command strings by distance to user entry. asort( $levenshtein ); // Fetch the closest command string. reset( $levenshtein ); $suggestion = key( $levenshtein ); // Only return a suggestion if below a given threshold. return $levenshtein[ $suggestion ] <= $threshold && $suggestion !== $target ? (string) $suggestion : ''; } /** * Get a Phar-safe version of a path. * * For paths inside a Phar, this strips the outer filesystem's location to * reduce the path to what it needs to be within the Phar archive. * * Use the __FILE__ or __DIR__ constants as a starting point. * * @param string $path An absolute path that might be within a Phar. * * @return string A Phar-safe version of the path. */ function phar_safe_path( $path ) { if ( ! inside_phar() ) { return $path; } return str_replace( PHAR_STREAM_PREFIX . WP_CLI_PHAR_PATH . '/', PHAR_STREAM_PREFIX, $path ); } /** * Check whether a given Command object is part of the bundled set of * commands. * * This function accepts both a fully qualified class name as a string as * well as an object that extends `WP_CLI\Dispatcher\CompositeCommand`. * * @param \WP_CLI\Dispatcher\CompositeCommand|string $command * * @return bool */ function is_bundled_command( $command ) { static $classes; if ( null === $classes ) { $classes = array(); $class_map = WP_CLI_VENDOR_DIR . '/composer/autoload_commands_classmap.php'; if ( file_exists( WP_CLI_VENDOR_DIR . '/composer/') ) { $classes = include $class_map; } } if ( is_object( $command ) ) { $command = get_class( $command ); } return is_string( $command ) ? array_key_exists( $command, $classes ) : false; } /** * Maybe prefix command string with "/usr/bin/env". * Removes (if there) if Windows, adds (if not there) if not. * * @param string $command * * @return string */ function force_env_on_nix_systems( $command ) { $env_prefix = '/usr/bin/env '; $env_prefix_len = strlen( $env_prefix ); if ( is_windows() ) { if ( 0 === strncmp( $command, $env_prefix, $env_prefix_len ) ) { $command = substr( $command, $env_prefix_len ); } } else { if ( 0 !== strncmp( $command, $env_prefix, $env_prefix_len ) ) { $command = $env_prefix . $command; } } return $command; } /** * Check that `proc_open()` and `proc_close()` haven't been disabled. * * @param string $context Optional. If set will appear in error message. Default null. * @param bool $return Optional. If set will return false rather than error out. Default false. * * @return bool */ function check_proc_available( $context = null, $return = false ) { if ( ! function_exists( 'proc_open' ) || ! function_exists( 'proc_close' ) ) { if ( $return ) { return false; } $msg = 'The PHP functions `proc_open()` and/or `proc_close()` are disabled. Please check your PHP ini directive `disable_functions` or suhosin settings.'; if ( $context ) { WP_CLI::error( sprintf( "Cannot do '%s': %s", $context, $msg ) ); } else { WP_CLI::error( $msg ); } } return true; } /** * Returns past tense of verb, with limited accuracy. Only regular verbs catered for, apart from "reset". * * @param string $verb Verb to return past tense of. * * @return string */ function past_tense_verb( $verb ) { static $irregular = array( 'reset' => 'reset' ); if ( isset( $irregular[ $verb ] ) ) { return $irregular[ $verb ]; } $last = substr( $verb, -1 ); if ( 'e' === $last ) { $verb = substr( $verb, 0, -1 ); } elseif ( 'y' === $last && ! preg_match( '/[aeiou]y$/', $verb ) ) { $verb = substr( $verb, 0, -1 ) . 'i'; } elseif ( preg_match( '/^[^aeiou]*[aeiou][^aeiouhwxy]$/', $verb ) ) { // Rule of thumb that most (all?) one-voweled regular verbs ending in vowel + consonant (excluding "h", "w", "x", "y") double their final consonant - misses many cases (eg "submit"). $verb .= $last; } return $verb . 'ed'; }