PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/cli.php

https://bitbucket.org/sriedel/iccrm-wip
PHP | 438 lines | 235 code | 66 blank | 137 comment | 26 complexity | bc32fba825b8fbaec7bff4f491a67492 MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2012 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * Cli class
  15. *
  16. * Interact with the command line by accepting input options, parameters and output text
  17. *
  18. * @package Fuel
  19. * @category Core
  20. * @author Phil Sturgeon
  21. * @link http://docs.fuelphp.com/classes/cli.html
  22. */
  23. class Cli
  24. {
  25. public static $readline_support = false;
  26. public static $wait_msg = 'Press any key to continue...';
  27. protected static $args = array();
  28. protected static $foreground_colors = array(
  29. 'black' => '0;30',
  30. 'dark_gray' => '1;30',
  31. 'blue' => '0;34',
  32. 'dark_blue' => '1;34',
  33. 'light_blue' => '1;34',
  34. 'green' => '0;32',
  35. 'light_green' => '1;32',
  36. 'cyan' => '0;36',
  37. 'light_cyan' => '1;36',
  38. 'red' => '0;31',
  39. 'light_red' => '1;31',
  40. 'purple' => '0;35',
  41. 'light_purple' => '1;35',
  42. 'light_yellow' => '0;33',
  43. 'yellow' => '1;33',
  44. 'light_gray' => '0;37',
  45. 'white' => '1;37',
  46. );
  47. protected static $background_colors = array(
  48. 'black' => '40',
  49. 'red' => '41',
  50. 'green' => '42',
  51. 'yellow' => '43',
  52. 'blue' => '44',
  53. 'magenta' => '45',
  54. 'cyan' => '46',
  55. 'light_gray' => '47',
  56. );
  57. /**
  58. * Static constructor. Parses all the CLI params.
  59. */
  60. public static function _init()
  61. {
  62. if ( ! \Fuel::$is_cli)
  63. {
  64. throw new \Exception('Cli class cannot be used outside of the command line.');
  65. }
  66. for ($i = 1; $i < $_SERVER['argc']; $i++)
  67. {
  68. $arg = explode('=', $_SERVER['argv'][$i]);
  69. static::$args[$i] = $arg[0];
  70. if (count($arg) > 1 || strncmp($arg[0], '-', 1) === 0)
  71. {
  72. static::$args[ltrim($arg[0], '-')] = isset($arg[1]) ? $arg[1] : true;
  73. }
  74. }
  75. // Readline is an extension for PHP that makes interactive with PHP much more bash-like
  76. // http://www.php.net/manual/en/readline.installation.php
  77. static::$readline_support = extension_loaded('readline');
  78. }
  79. /**
  80. * Returns the option with the given name. You can also give the option
  81. * number.
  82. *
  83. * Named options must be in the following formats:
  84. * php index.php user -v --v -name=John --name=John
  85. *
  86. * @param string|int $name the name of the option (int if unnamed)
  87. * @return string
  88. */
  89. public static function option($name, $default = null)
  90. {
  91. if ( ! isset(static::$args[$name]))
  92. {
  93. return \Fuel::value($default);
  94. }
  95. return static::$args[$name];
  96. }
  97. /**
  98. * Get input from the shell, using readline or the standard STDIN
  99. *
  100. * Named options must be in the following formats:
  101. * php index.php user -v --v -name=John --name=John
  102. *
  103. * @param string|int $name the name of the option (int if unnamed)
  104. * @return string
  105. */
  106. public static function input($prefix = '')
  107. {
  108. if (static::$readline_support)
  109. {
  110. return readline($prefix);
  111. }
  112. echo $prefix;
  113. return fgets(STDIN);
  114. }
  115. /**
  116. * Asks the user for input. This can have either 1 or 2 arguments.
  117. *
  118. * Usage:
  119. *
  120. * // Waits for any key press
  121. * CLI::prompt();
  122. *
  123. * // Takes any input
  124. * $color = CLI::prompt('What is your favorite color?');
  125. *
  126. * // Takes any input, but offers default
  127. * $color = CLI::prompt('What is your favourite color?', 'white');
  128. *
  129. * // Will only accept the options in the array
  130. * $ready = CLI::prompt('Are you ready?', array('y','n'));
  131. *
  132. * @return string the user input
  133. */
  134. public static function prompt()
  135. {
  136. $args = func_get_args();
  137. $options = array();
  138. $output = '';
  139. $default = null;
  140. // How many we got
  141. $arg_count = count($args);
  142. // Is the last argument a boolean? True means required
  143. $required = end($args) === true;
  144. // Reduce the argument count if required was passed, we don't care about that anymore
  145. $required === true and --$arg_count;
  146. // This method can take a few crazy combinations of arguments, so lets work it out
  147. switch ($arg_count)
  148. {
  149. case 2:
  150. // E.g: $ready = CLI::prompt('Are you ready?', array('y','n'));
  151. if (is_array($args[1]))
  152. {
  153. list($output, $options)=$args;
  154. }
  155. // E.g: $color = CLI::prompt('What is your favourite color?', 'white');
  156. elseif (is_string($args[1]))
  157. {
  158. list($output, $default)=$args;
  159. }
  160. break;
  161. case 1:
  162. // No question (probably been asked already) so just show options
  163. // E.g: $ready = CLI::prompt(array('y','n'));
  164. if (is_array($args[0]))
  165. {
  166. $options = $args[0];
  167. }
  168. // Question without options
  169. // E.g: $ready = CLI::prompt('What did you do today?');
  170. elseif (is_string($args[0]))
  171. {
  172. $output = $args[0];
  173. }
  174. break;
  175. }
  176. // If a question has been asked with the read
  177. if ($output !== '')
  178. {
  179. $extra_output = '';
  180. if ($default !== null)
  181. {
  182. $extra_output = ' [ Default: "'.$default.'" ]';
  183. }
  184. elseif ($options !== array())
  185. {
  186. $extra_output = ' [ '.implode(', ', $options).' ]';
  187. }
  188. fwrite(STDOUT, $output.$extra_output.': ');
  189. }
  190. // Read the input from keyboard.
  191. $input = trim(static::input()) ?: $default;
  192. // No input provided and we require one (default will stop this being called)
  193. if (empty($input) and $required === true)
  194. {
  195. static::write('This is required.');
  196. static::new_line();
  197. $input = forward_static_call_array(array(__CLASS__, 'prompt'), $args);
  198. }
  199. // If options are provided and the choice is not in the array, tell them to try again
  200. if ( ! empty($options) and ! in_array($input, $options))
  201. {
  202. static::write('This is not a valid option. Please try again.');
  203. static::new_line();
  204. $input = forward_static_call_array(array(__CLASS__, 'prompt'), $args);
  205. }
  206. return $input;
  207. }
  208. /**
  209. * Outputs a string to the cli. If you send an array it will implode them
  210. * with a line break.
  211. *
  212. * @param string|array $text the text to output, or array of lines
  213. */
  214. public static function write($text = '', $foreground = null, $background = null)
  215. {
  216. if (is_array($text))
  217. {
  218. $text = implode(PHP_EOL, $text);
  219. }
  220. if ($foreground or $background)
  221. {
  222. $text = static::color($text, $foreground, $background);
  223. }
  224. fwrite(STDOUT, $text.PHP_EOL);
  225. }
  226. /**
  227. * Outputs an error to the CLI using STDERR instead of STDOUT
  228. *
  229. * @param string|array $text the text to output, or array of errors
  230. */
  231. public static function error($text = '', $foreground = 'light_red', $background = null)
  232. {
  233. if (is_array($text))
  234. {
  235. $text = implode(PHP_EOL, $text);
  236. }
  237. if ($foreground OR $background)
  238. {
  239. $text = static::color($text, $foreground, $background);
  240. }
  241. fwrite(STDERR, $text.PHP_EOL);
  242. }
  243. /**
  244. * Beeps a certain number of times.
  245. *
  246. * @param int $num the number of times to beep
  247. */
  248. public static function beep($num = 1)
  249. {
  250. echo str_repeat("\x07", $num);
  251. }
  252. /**
  253. * Waits a certain number of seconds, optionally showing a wait message and
  254. * waiting for a key press.
  255. *
  256. * @param int $seconds number of seconds
  257. * @param bool $countdown show a countdown or not
  258. */
  259. public static function wait($seconds = 0, $countdown = false)
  260. {
  261. if ($countdown === true)
  262. {
  263. $time = $seconds;
  264. while ($time > 0)
  265. {
  266. fwrite(STDOUT, $time.'... ');
  267. sleep(1);
  268. $time--;
  269. }
  270. static::write();
  271. }
  272. else
  273. {
  274. if ($seconds > 0)
  275. {
  276. sleep($seconds);
  277. }
  278. else
  279. {
  280. static::write(static::$wait_msg);
  281. static::input();
  282. }
  283. }
  284. }
  285. /**
  286. * if operating system === windows
  287. */
  288. public static function is_windows()
  289. {
  290. return 'win' === strtolower(substr(php_uname("s"), 0, 3));
  291. }
  292. /**
  293. * Enter a number of empty lines
  294. *
  295. * @param integer Number of lines to output
  296. * @return void
  297. */
  298. public static function new_line($num = 1)
  299. {
  300. // Do it once or more, write with empty string gives us a new line
  301. for($i = 0; $i < $num; $i++)
  302. {
  303. static::write();
  304. }
  305. }
  306. /**
  307. * Clears the screen of output
  308. *
  309. * @return void
  310. */
  311. public static function clear_screen()
  312. {
  313. static::is_windows()
  314. // Windows is a bit crap at this, but their terminal is tiny so shove this in
  315. ? static::new_line(40)
  316. // Anything with a flair of Unix will handle these magic characters
  317. : fwrite(STDOUT, chr(27)."[H".chr(27)."[2J");
  318. }
  319. /**
  320. * Returns the given text with the correct color codes for a foreground and
  321. * optionally a background color.
  322. *
  323. * @param string $text the text to color
  324. * @param string $foreground the foreground color
  325. * @param string $background the background color
  326. * @return string the color coded string
  327. */
  328. public static function color($text, $foreground, $background = null)
  329. {
  330. if (static::is_windows() and ! \Input::server('ANSICON'))
  331. {
  332. return $text;
  333. }
  334. if ( ! array_key_exists($foreground, static::$foreground_colors))
  335. {
  336. throw new \FuelException('Invalid CLI foreground color: '.$foreground);
  337. }
  338. if ( $background !== null and ! array_key_exists($background, static::$background_colors))
  339. {
  340. throw new \FuelException('Invalid CLI background color: '.$background);
  341. }
  342. $string = "\033[".static::$foreground_colors[$foreground]."m";
  343. if ($background !== null)
  344. {
  345. $string .= "\033[".static::$background_colors[$background]."m";
  346. }
  347. $string .= $text."\033[0m";
  348. return $string;
  349. }
  350. /**
  351. * Spawn Background Process
  352. *
  353. * Launches a background process (note, provides no security itself, $call must be sanitised prior to use)
  354. * @param string $call the system call to make
  355. * @return void
  356. * @author raccettura
  357. * @link http://robert.accettura.com/blog/2006/09/14/asynchronous-processing-with-php/
  358. */
  359. public static function spawn($call, $output = '/dev/null')
  360. {
  361. // Windows
  362. if(static::is_windows())
  363. {
  364. pclose(popen('start /b '.$call, 'r'));
  365. }
  366. // Some sort of UNIX
  367. else
  368. {
  369. pclose(popen($call.' > '.$output.' &', 'r'));
  370. }
  371. }
  372. }