CLI.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <?php
  2. /**
  3. * @package KO7/Minion
  4. *
  5. * @copyright (c) 2015 Kohana Team
  6. * @copyright (c) 2016-2018 Koseven Team
  7. * @license https://koseven.dev/LICENSE
  8. */
  9. class KO7_Minion_CLI {
  10. public static $wait_msg = 'Press any key to continue...';
  11. public static $invalid_option_msg = 'This is not a valid option. Please try again.';
  12. protected static $foreground_colors = [
  13. 'black' => '0;30',
  14. 'dark_gray' => '1;30',
  15. 'blue' => '0;34',
  16. 'light_blue' => '1;34',
  17. 'green' => '0;32',
  18. 'light_green' => '1;32',
  19. 'cyan' => '0;36',
  20. 'light_cyan' => '1;36',
  21. 'red' => '0;31',
  22. 'light_red' => '1;31',
  23. 'purple' => '0;35',
  24. 'light_purple' => '1;35',
  25. 'brown' => '0;33',
  26. 'yellow' => '1;33',
  27. 'light_gray' => '0;37',
  28. 'white' => '1;37',
  29. ];
  30. protected static $background_colors = [
  31. 'black' => '40',
  32. 'red' => '41',
  33. 'green' => '42',
  34. 'yellow' => '43',
  35. 'blue' => '44',
  36. 'magenta' => '45',
  37. 'cyan' => '46',
  38. 'light_gray' => '47',
  39. ];
  40. /**
  41. * Returns one or more command-line options. Options are specified using
  42. * standard CLI syntax:
  43. *
  44. * php index.php --username=john.smith --password=secret --var="some value with spaces"
  45. *
  46. * // Get the values of "username" and "password"
  47. * $auth = Minion_CLI::options('username', 'password');
  48. *
  49. * @param string $options,... option name
  50. * @return array
  51. */
  52. public static function options($options = NULL)
  53. {
  54. // Get all of the requested options
  55. $options = func_get_args();
  56. // Found option values
  57. $values = [];
  58. // Skip the first option, it is always the file executed
  59. for ($i = 1; $i < $_SERVER['argc']; ++$i)
  60. {
  61. if ( ! isset($_SERVER['argv'][$i]))
  62. {
  63. // No more args left
  64. break;
  65. }
  66. // Get the option
  67. $opt = $_SERVER['argv'][$i];
  68. if (substr($opt, 0, 2) !== '--')
  69. {
  70. // This is a positional argument
  71. $values[] = $opt;
  72. continue;
  73. }
  74. // Remove the "--" prefix
  75. $opt = substr($opt, 2);
  76. if (strpos($opt, '='))
  77. {
  78. // Separate the name and value
  79. list ($opt, $value) = explode('=', $opt, 2);
  80. }
  81. else
  82. {
  83. $value = NULL;
  84. }
  85. $values[$opt] = $value;
  86. }
  87. if ($options)
  88. {
  89. foreach ($values as $opt => $value)
  90. {
  91. if ( ! in_array($opt, $options))
  92. {
  93. // Set the given value
  94. unset($values[$opt]);
  95. }
  96. }
  97. }
  98. return count($options) == 1 ? array_pop($values) : $values;
  99. }
  100. /**
  101. * Reads input from the user. This can have either 1 or 2 arguments.
  102. *
  103. * Usage:
  104. *
  105. * // Takes any input
  106. * $color = Minion_CLI::read('What is your favorite color?');
  107. *
  108. * // Will only accept the options in the array
  109. * $ready = Minion_CLI::read('Are you ready?', ['y','n']);
  110. *
  111. * @param string $text text to show user before waiting for input
  112. * @param array $options array of options the user is shown
  113. * @return string the user input
  114. */
  115. public static function read($text = '', array $options = NULL)
  116. {
  117. // If a question has been asked with the read
  118. if ( ! empty($options))
  119. {
  120. $text .= ' [ '.implode(', ', $options).' ]';
  121. }
  122. if ($text != '')
  123. {
  124. $text .= ': ';
  125. }
  126. fwrite(STDOUT, $text);
  127. // Read the input from keyboard.
  128. $input = trim(fgets(STDIN));
  129. // If options are provided and the choice is not in the array, tell them to try again
  130. if ( ! empty($options) && ! in_array($input, $options))
  131. {
  132. Minion_CLI::write(Minion_CLI::$invalid_option_msg);
  133. $input = Minion_CLI::read($text, $options);
  134. }
  135. // Read the input
  136. return $input;
  137. }
  138. /**
  139. * Experimental feature.
  140. *
  141. * Reads hidden input from the user
  142. *
  143. * Usage:
  144. *
  145. * $password = Minion_CLI::password('Enter your password');
  146. *
  147. * @author Mathew Davies.
  148. * @return string
  149. */
  150. public static function password($text = '')
  151. {
  152. $text .= ': ';
  153. if (KO7::$is_windows)
  154. {
  155. $vbscript = sys_get_temp_dir().'Minion_CLI_Password.vbs';
  156. // Create temporary file
  157. file_put_contents($vbscript, 'wscript.echo(InputBox("'.addslashes($text).'"))');
  158. $password = shell_exec('cscript //nologo '.escapeshellarg($vbscript));
  159. // Remove temporary file.
  160. unlink($vbscript);
  161. }
  162. else
  163. {
  164. $password = shell_exec('/usr/bin/env bash -c \'read -s -p "'.escapeshellcmd($text).'" var && echo $var\'');
  165. }
  166. Minion_CLI::write();
  167. return trim($password);
  168. }
  169. /**
  170. * Outputs a string to the cli. If you send an array it will implode them
  171. * with a line break.
  172. *
  173. * @param string|array $text the text to output, or array of lines
  174. */
  175. public static function write($text = '')
  176. {
  177. if (is_array($text))
  178. {
  179. foreach ($text as $line)
  180. {
  181. Minion_CLI::write($line);
  182. }
  183. }
  184. else
  185. {
  186. fwrite(STDOUT, $text.PHP_EOL);
  187. }
  188. }
  189. /**
  190. * Outputs a replacable line to the cli. You can continue replacing the
  191. * line until `TRUE` is passed as the second parameter in order to indicate
  192. * you are done modifying the line.
  193. *
  194. * // Sample progress indicator
  195. * Minion_CLI::write_replace('0%');
  196. * Minion_CLI::write_replace('25%');
  197. * Minion_CLI::write_replace('50%');
  198. * Minion_CLI::write_replace('75%');
  199. * // Done writing this line
  200. * Minion_CLI::write_replace('100%', TRUE);
  201. *
  202. * @param string $text the text to output
  203. * @param boolean $end_line whether the line is done being replaced
  204. */
  205. public static function write_replace($text = '', $end_line = FALSE)
  206. {
  207. // Append a newline if $end_line is TRUE
  208. $text = $end_line ? $text.PHP_EOL : $text;
  209. if (Kohana::$is_windows)
  210. {
  211. fwrite(STDOUT, "\r".$text);
  212. }
  213. else
  214. {
  215. fwrite(STDOUT, "\r\033[K".$text);
  216. }
  217. }
  218. /**
  219. * Waits a certain number of seconds, optionally showing a wait message and
  220. * waiting for a key press.
  221. *
  222. * @author Fuel Development Team
  223. * @license MIT License
  224. * @copyright 2010 - 2011 Fuel Development Team
  225. * @link http://fuelphp.com
  226. * @param int $seconds number of seconds
  227. * @param bool $countdown show a countdown or not
  228. */
  229. public static function wait($seconds = 0, $countdown = FALSE)
  230. {
  231. if ($countdown === TRUE)
  232. {
  233. $time = $seconds;
  234. while ($time > 0)
  235. {
  236. fwrite(STDOUT, $time.'... ');
  237. sleep(1);
  238. --$time;
  239. }
  240. Minion_CLI::write();
  241. }
  242. else
  243. {
  244. if ($seconds > 0)
  245. {
  246. sleep($seconds);
  247. }
  248. else
  249. {
  250. Minion_CLI::write(Minion_CLI::$wait_msg);
  251. Minion_CLI::read();
  252. }
  253. }
  254. }
  255. /**
  256. * Returns the given text with the correct color codes for a foreground and
  257. * optionally a background color.
  258. *
  259. * @author Fuel Development Team
  260. * @license MIT License
  261. * @copyright 2010 - 2011 Fuel Development Team
  262. * @link http://fuelphp.com
  263. * @param string $text the text to color
  264. * @param string $foreground the foreground color
  265. * @param string $background the background color
  266. * @return string the color coded string
  267. */
  268. public static function color($text, $foreground, $background = null)
  269. {
  270. if (KO7::$is_windows)
  271. return $text;
  272. if ( ! array_key_exists($foreground, Minion_CLI::$foreground_colors))
  273. throw new KO7_Exception('Invalid CLI foreground color: '.$foreground);
  274. if ($background !== NULL AND ! array_key_exists($background, Minion_CLI::$background_colors))
  275. throw new KO7_Exception('Invalid CLI background color: '.$background);
  276. $string = "\033[".Minion_CLI::$foreground_colors[$foreground]."m";
  277. if ($background !== NULL)
  278. {
  279. $string .= "\033[".Minion_CLI::$background_colors[$background]."m";
  280. }
  281. $string .= $text."\033[0m";
  282. return $string;
  283. }
  284. }