OSDN Git Service

convert recursive_unserialize_replace() function to a class
[wvm/wvm.git] / php / utils.php
1 <?php
2
3 // Utilities that do NOT depend on WordPress code.
4
5 namespace WP_CLI\Utils;
6
7 use \WP_CLI\Dispatcher;
8 use \WP_CLI\Iterators\Transform;
9
10 function load_dependencies() {
11         if ( 0 === strpos( WP_CLI_ROOT, 'phar:' ) ) {
12                 require WP_CLI_ROOT . '/vendor/autoload.php';
13                 return;
14         }
15
16         $has_autoload = false;
17
18         foreach ( get_vendor_paths() as $vendor_path ) {
19                 if ( file_exists( $vendor_path . '/autoload.php' ) ) {
20                         require $vendor_path . '/autoload.php';
21                         $has_autoload = true;
22                         break;
23                 }
24         }
25
26         if ( !$has_autoload ) {
27                 fputs( STDERR, "Internal error: Can't find Composer autoloader.\n" );
28                 exit(3);
29         }
30 }
31
32 function get_vendor_paths() {
33         return array(
34                 WP_CLI_ROOT . '/../../../vendor',  // part of a larger project / installed via Composer (preferred)
35                 WP_CLI_ROOT . '/vendor',           // top-level project / installed as Git clone
36         );
37 }
38
39 // Using require() directly inside a class grants access to private methods to the loaded code
40 function load_file( $path ) {
41         require $path;
42 }
43
44 function load_command( $name ) {
45         $path = WP_CLI_ROOT . "/php/commands/$name.php";
46
47         if ( is_readable( $path ) ) {
48                 include_once $path;
49         }
50 }
51
52 function load_all_commands() {
53         $cmd_dir = WP_CLI_ROOT . '/php/commands';
54
55         $iterator = new \DirectoryIterator( $cmd_dir );
56
57         foreach ( $iterator as $filename ) {
58                 if ( '.php' != substr( $filename, -4 ) )
59                         continue;
60
61                 include_once "$cmd_dir/$filename";
62         }
63 }
64
65 /**
66  * Like array_map(), except it returns a new iterator, instead of a modified array.
67  *
68  * Example:
69  *
70  *     $arr = array('Football', 'Socker');
71  *
72  *     $it = iterator_map($arr, 'strtolower', function($val) {
73  *       return str_replace('foo', 'bar', $val);
74  *     });
75  *
76  *     foreach ( $it as $val ) {
77  *       var_dump($val);
78  *     }
79  *
80  * @param array|object Either a plain array or another iterator
81  * @param callback The function to apply to an element
82  * @return object An iterator that applies the given callback(s)
83  */
84 function iterator_map( $it, $fn ) {
85         if ( is_array( $it ) ) {
86                 $it = new \ArrayIterator( $it );
87         }
88
89         if ( !method_exists( $it, 'add_transform' ) ) {
90                 $it = new Transform( $it );
91         }
92
93         foreach ( array_slice( func_get_args(), 1 ) as $fn ) {
94                 $it->add_transform( $fn );
95         }
96
97         return $it;
98 }
99
100 /**
101  * Search for file by walking up the directory tree until the first file is found or until $stop_check($dir) returns true
102  * @param string|array The files (or file) to search for
103  * @param string|null The directory to start searching from; defaults to CWD
104  * @param callable Function which is passed the current dir each time a directory level is traversed
105  * @return null|string Null if the file was not found
106  */
107 function find_file_upward( $files, $dir = null, $stop_check = null ) {
108         $files = (array) $files;
109         if ( is_null( $dir ) ) {
110                 $dir = getcwd();
111         }
112         while ( is_readable( $dir ) ) {
113                 // Stop walking up when the supplied callable returns true being passed the $dir
114                 if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) {
115                         return null;
116                 }
117
118                 foreach ( $files as $file ) {
119                         $path = $dir . DIRECTORY_SEPARATOR . $file;
120                         if ( file_exists( $path ) ) {
121                                 return $path;
122                         }
123                 }
124
125                 $parent_dir = dirname( $dir );
126                 if ( empty($parent_dir) || $parent_dir === $dir ) {
127                         break;
128                 }
129                 $dir = $parent_dir;
130         }
131         return null;
132 }
133
134 function is_path_absolute( $path ) {
135         // Windows
136         if ( isset($path[1]) && ':' === $path[1] )
137                 return true;
138
139         return $path[0] === '/';
140 }
141
142 /**
143  * Composes positional arguments into a command string.
144  *
145  * @param array
146  * @return string
147  */
148 function args_to_str( $args ) {
149         return ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) );
150 }
151
152 /**
153  * Composes associative arguments into a command string.
154  *
155  * @param array
156  * @return string
157  */
158 function assoc_args_to_str( $assoc_args ) {
159         $str = '';
160
161         foreach ( $assoc_args as $key => $value ) {
162                 if ( true === $value )
163                         $str .= " --$key";
164                 else
165                         $str .= " --$key=" . escapeshellarg( $value );
166         }
167
168         return $str;
169 }
170
171 /**
172  * Given a template string and an arbitrary number of arguments,
173  * returns the final command, with the parameters escaped.
174  */
175 function esc_cmd( $cmd ) {
176         if ( func_num_args() < 2 )
177                 trigger_error( 'esc_cmd() requires at least two arguments.', E_USER_WARNING );
178
179         $args = func_get_args();
180
181         $cmd = array_shift( $args );
182
183         return vsprintf( $cmd, array_map( 'escapeshellarg', $args ) );
184 }
185
186 function locate_wp_config() {
187         static $path;
188
189         if ( null === $path ) {
190                 if ( file_exists( ABSPATH . 'wp-config.php' ) )
191                         $path = ABSPATH . 'wp-config.php';
192                 elseif ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) )
193                         $path = ABSPATH . '../wp-config.php';
194                 else
195                         $path = false;
196
197                 if ( $path )
198                         $path = realpath( $path );
199         }
200
201         return $path;
202 }
203
204 /**
205  * Output items in a table, JSON, CSV, ids, or the total count
206  *
207  * @param string        $format     Format to use: 'table', 'json', 'csv', 'ids', 'count'
208  * @param array         $items      Data to output
209  * @param array|string  $fields     Named fields for each item of data. Can be array or comma-separated list
210  */
211 function format_items( $format, $items, $fields ) {
212         $assoc_args = compact( 'format', 'fields' );
213         $formatter = new \WP_CLI\Formatter( $assoc_args );
214         $formatter->display_items( $items );
215 }
216
217 /**
218  * Write data as CSV to a given file.
219  *
220  * @param resource $fd         File descriptor
221  * @param array    $rows       Array of rows to output
222  * @param array    $headers    List of CSV columns (optional)
223  */
224 function write_csv( $fd, $rows, $headers = array() ) {
225         if ( ! empty( $headers ) ) {
226                 fputcsv( $fd, $headers );
227         }
228
229         foreach ( $rows as $row ) {
230                 if ( ! empty( $headers ) ) {
231                         $row = pick_fields( $row, $headers );
232                 }
233
234                 fputcsv( $fd, array_values( $row ) );
235         }
236 }
237
238 /**
239  * Pick fields from an associative array or object.
240  *
241  * @param array|object Associative array or object to pick fields from
242  * @param array List of fields to pick
243  * @return array
244  */
245 function pick_fields( $item, $fields ) {
246         $item = (object) $item;
247
248         $values = array();
249
250         foreach ( $fields as $field ) {
251                 $values[ $field ] = isset( $item->$field ) ? $item->$field : null;
252         }
253
254         return $values;
255 }
256
257 /**
258  * Launch system's $EDITOR to edit text
259  *
260  * @param  str  $content  Text to edit (eg post content)
261  * @return str|bool       Edited text, if file is saved from editor
262  *                        False, if no change to file
263  */
264 function launch_editor_for_input( $input, $title = 'WP-CLI' ) {
265
266         $tmpfile = wp_tempnam( $title );
267
268         if ( !$tmpfile )
269                 \WP_CLI::error( 'Error creating temporary file.' );
270
271         $output = '';
272         file_put_contents( $tmpfile, $input );
273
274         $editor = getenv( 'EDITOR' );
275         if ( !$editor ) {
276                 if ( isset( $_SERVER['OS'] ) && false !== strpos( $_SERVER['OS'], 'indows' ) )
277                         $editor = 'notepad';
278                 else
279                         $editor = 'vi';
280         }
281
282         \WP_CLI::launch( "$editor " . escapeshellarg( $tmpfile ) );
283
284         $output = file_get_contents( $tmpfile );
285
286         unlink( $tmpfile );
287
288         if ( $output === $input )
289                 return false;
290
291         return $output;
292 }
293
294 /**
295  * @param string MySQL host string, as defined in wp-config.php
296  * @return array
297  */
298 function mysql_host_to_cli_args( $raw_host ) {
299         $assoc_args = array();
300
301         $host_parts = explode( ':',  $raw_host );
302         if ( count( $host_parts ) == 2 ) {
303                 list( $assoc_args['host'], $extra ) = $host_parts;
304                 $extra = trim( $extra );
305                 if ( is_numeric( $extra ) ) {
306                         $assoc_args['port'] = intval( $extra );
307                         $assoc_args['protocol'] = 'tcp';
308                 } else if ( $extra !== '' ) {
309                         $assoc_args['socket'] = $extra;
310                 }
311         } else {
312                 $assoc_args['host'] = $raw_host;
313         }
314
315         return $assoc_args;
316 }
317
318 function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) {
319         if ( !$descriptors )
320                 $descriptors = array( STDIN, STDOUT, STDERR );
321
322         if ( isset( $assoc_args['host'] ) ) {
323                 $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) );
324         }
325
326         $env = (array) $_ENV;
327         if ( isset( $assoc_args['pass'] ) ) {
328                 $env['MYSQL_PWD'] = $assoc_args['pass'];
329                 unset( $assoc_args['pass'] );
330         }
331
332         $final_cmd = $cmd . assoc_args_to_str( $assoc_args );
333
334         $proc = proc_open( $final_cmd, $descriptors, $pipes, null, $env );
335         if ( !$proc )
336                 exit(1);
337
338         $r = proc_close( $proc );
339
340         if ( $r ) exit( $r );
341 }
342
343 /**
344  * Render PHP or other types of files using Mustache templates.
345  *
346  * IMPORTANT: Automatic HTML escaping is disabled!
347  */
348 function mustache_render( $template_name, $data ) {
349         if ( ! file_exists( $template_name ) )
350                 $template_name = WP_CLI_ROOT . "/templates/$template_name";
351
352         $template = file_get_contents( $template_name );
353
354         $m = new \Mustache_Engine( array(
355                 'escape' => function ( $val ) { return $val; }
356         ) );
357
358         return $m->render( $template, $data );
359 }
360
361 function make_progress_bar( $message, $count ) {
362         if ( \cli\Shell::isPiped() )
363                 return new \WP_CLI\NoOp;
364
365         return new \cli\progress\Bar( $message, $count );
366 }
367
368 function parse_url( $url ) {
369         $url_parts = \parse_url( $url );
370
371         if ( !isset( $url_parts['scheme'] ) ) {
372                 $url_parts = parse_url( 'http://' . $url );
373         }
374
375         return $url_parts;
376 }
377
378 /**
379  * Check if we're running in a Windows environment (cmd.exe).
380  */
381 function is_windows() {
382         return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
383 }
384