国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
11KB

  1. <?php if (!defined('DEDEINC')) exit('Request Error!');
  2. // Copyright 2020 The DedeBiz Authors. All rights reserved.
  3. // license that can be found in the LICENSE file.
  4. // @copyright Copyright (c) 2020, DedeBIZ.COM
  5. // @license https://www.dedebiz.com/license
  6. // @link https://www.dedebiz.com
  7. /*
  8. The MIT License (MIT)
  9. Copyright (c) 2014-2019 British Columbia Institute of Technology
  10. Copyright (c) 2019-2020 CodeIgniter Foundation
  11. */
  12. function is_cli()
  13. {
  14. return (PHP_SAPI === 'cli' || defined('STDIN'));
  15. }
  16. class DedeCli
  17. {
  18. public static $readline_support = false;
  19. protected static $initialized = false;
  20. protected static $wait_msg = "Press any key to continue...";
  21. protected static $segments = [];
  22. protected static $options = [];
  23. protected static $foreground_colors = [
  24. 'black' => '0;30',
  25. 'dark_gray' => '1;30',
  26. 'blue' => '0;34',
  27. 'dark_blue' => '1;34',
  28. 'light_blue' => '1;34',
  29. 'green' => '0;32',
  30. 'light_green' => '1;32',
  31. 'cyan' => '0;36',
  32. 'light_cyan' => '1;36',
  33. 'red' => '0;31',
  34. 'light_red' => '1;31',
  35. 'purple' => '0;35',
  36. 'light_purple' => '1;35',
  37. 'light_yellow' => '0;33',
  38. 'yellow' => '1;33',
  39. 'light_gray' => '0;37',
  40. 'white' => '1;37',
  41. ];
  42. protected static $background_colors = [
  43. 'black' => '40',
  44. 'red' => '41',
  45. 'green' => '42',
  46. 'yellow' => '43',
  47. 'blue' => '44',
  48. 'magenta' => '45',
  49. 'cyan' => '46',
  50. 'light_gray' => '47',
  51. ];
  52. public static function init()
  53. {
  54. if (is_cli())
  55. {
  56. static::$readline_support = extension_loaded('readline');
  57. static::parseCommandLine();
  58. static::$initialized = true;
  59. } else
  60. {
  61. define('STDOUT', 'php://output');
  62. }
  63. }
  64. private static function parseCommandLine()
  65. {
  66. $optionsFound = false;
  67. for ($i=1; $i < $_SERVER['argc']; $i++)
  68. {
  69. if (! $optionsFound && strpos($_SERVER['argv'][$i], '-') === false)
  70. {
  71. static::$segments[] = $_SERVER['argv'][$i];
  72. continue;
  73. }
  74. $optionsFound = true;
  75. if (substr($_SERVER['argv'][$i], 0, 1) != '-')
  76. {
  77. continue;
  78. }
  79. $arg = str_replace('-', '', $_SERVER['argv'][$i]);
  80. $value = null;
  81. if (isset($_SERVER['argv'][$i+1]) && substr($_SERVER['argv'][$i+1], 0, 1) != '-')
  82. {
  83. $value = $_SERVER['argv'][$i+1];
  84. $i++;
  85. }
  86. static::$options[$arg] = $value;
  87. $optionsFound = false;
  88. }
  89. }
  90. public static function getOption(string $name)
  91. {
  92. if (! array_key_exists($name, static::$options))
  93. {
  94. return null;
  95. }
  96. $val = static::$options[$name] === null
  97. ? true
  98. : static::$options[$name];
  99. return $val;
  100. }
  101. public static function getOptions()
  102. {
  103. return static::$options;
  104. }
  105. public static function getOptionString(): string
  106. {
  107. if (! count(static::$options))
  108. {
  109. return '';
  110. }
  111. $out = '';
  112. foreach (static::$options as $name => $value)
  113. {
  114. if (mb_strpos($value, ' ') !== false)
  115. {
  116. $value = '"'.$value.'"';
  117. }
  118. $out .= "-{$name} $value ";
  119. }
  120. return $out;
  121. }
  122. public static function newLine(int $num = 1)
  123. {
  124. for ($i = 0; $i < $num; $i++)
  125. {
  126. static::write('');
  127. }
  128. }
  129. public static function isWindows()
  130. {
  131. return 'win' === strtolower(substr(php_uname("s"), 0, 3));
  132. }
  133. public static function color(string $text, string $foreground, string $background = null, string $format = null)
  134. {
  135. if (static::isWindows() && ! isset($_SERVER['ANSICON']))
  136. {
  137. return $text;
  138. }
  139. if ( ! array_key_exists($foreground, static::$foreground_colors))
  140. {
  141. throw new \RuntimeException('Invalid CLI foreground color: '.$foreground);
  142. }
  143. if ($background !== null && ! array_key_exists($background, static::$background_colors))
  144. {
  145. throw new \RuntimeException('Invalid CLI background color: '.$background);
  146. }
  147. $string = "\033[".static::$foreground_colors[$foreground]."m";
  148. if ($background !== null)
  149. {
  150. $string .= "\033[".static::$background_colors[$background]."m";
  151. }
  152. if ($format === 'underline')
  153. {
  154. $string .= "\033[4m";
  155. }
  156. $string .= $text."\033[0m";
  157. return $string;
  158. }
  159. public static function getWidth(int $default = 80): int
  160. {
  161. if (static::isWindows())
  162. {
  163. return $default;
  164. }
  165. return (int)shell_exec('tput cols');
  166. }
  167. public static function getHeight(int $default = 32): int
  168. {
  169. if (static::isWindows())
  170. {
  171. return $default;
  172. }
  173. return (int)shell_exec('tput lines');
  174. }
  175. public static function showProgress($thisStep = 1, int $totalSteps = 10)
  176. {
  177. static $inProgress = false;
  178. if ($inProgress !== false && $inProgress <= $thisStep)
  179. {
  180. fwrite(STDOUT, "\033[1A");
  181. }
  182. $inProgress = $thisStep;
  183. if ($thisStep !== false)
  184. {
  185. $thisStep = abs($thisStep);
  186. $totalSteps = $totalSteps < 1 ? 1 : $totalSteps;
  187. $percent = intval(($thisStep / $totalSteps) * 100);
  188. $step = (int)round($percent / 10);
  189. fwrite(STDOUT, "[\033[32m".str_repeat('#', $step).str_repeat('.', 10 - $step)."\033[0m]");
  190. fwrite(STDOUT, sprintf(" %3d%% Complete", $percent).PHP_EOL);
  191. }
  192. else
  193. {
  194. fwrite(STDOUT, "\007");
  195. }
  196. }
  197. public static function wrap(string $string = null, int $max = 0, int $pad_left = 0): string
  198. {
  199. if (empty($string))
  200. {
  201. return '';
  202. }
  203. if ($max == 0)
  204. {
  205. $max = DedeCli::getWidth();
  206. }
  207. if (DedeCli::getWidth() < $max)
  208. {
  209. $max = DedeCli::getWidth();
  210. }
  211. $max = $max - $pad_left;
  212. $lines = wordwrap($string, $max);
  213. if ($pad_left > 0)
  214. {
  215. $lines = explode(PHP_EOL, $lines);
  216. $first = true;
  217. array_walk($lines, function (&$line, $index) use ($max, $pad_left, &$first)
  218. {
  219. if ( ! $first)
  220. {
  221. $line = str_repeat(" ", $pad_left).$line;
  222. }
  223. else
  224. {
  225. $first = false;
  226. }
  227. });
  228. $lines = implode(PHP_EOL, $lines);
  229. }
  230. return $lines;
  231. }
  232. public static function clearScreen()
  233. {
  234. static::isWindows()
  235. ? static::newLine(40)
  236. : fwrite(STDOUT, chr(27)."[H".chr(27)."[2J");
  237. }
  238. public static function input(string $prefix = null): string
  239. {
  240. if (static::$readline_support)
  241. {
  242. return readline($prefix);
  243. }
  244. echo $prefix;
  245. return fgets(STDIN);
  246. }
  247. /**
  248. * 询问用户输入.这个可以1个或2个参数.
  249. *
  250. * 使用:
  251. *
  252. * // 等待任何输入
  253. * DedeCli::prompt();
  254. *
  255. * $color = DedeCli::prompt('What is your favorite color?');
  256. *
  257. * $color = DedeCli::prompt('What is your favourite color?', 'white');
  258. *
  259. * $ready = DedeCli::prompt('Are you ready?', array('y','n'));
  260. *
  261. * @return string the user input
  262. */
  263. public static function prompt(): string
  264. {
  265. $args = func_get_args();
  266. $options = [];
  267. $output = '';
  268. $default = null;
  269. $arg_count = count($args);
  270. $required = end($args) === true;
  271. $required === true && --$arg_count;
  272. switch ($arg_count)
  273. {
  274. case 2:
  275. // E.g: $ready = DedeCli::prompt('Are you ready?', array('y','n'));
  276. if (is_array($args[1]))
  277. {
  278. list($output, $options) = $args;
  279. }
  280. // E.g: $color = DedeCli::prompt('What is your favourite color?', 'white');
  281. elseif (is_string($args[1]))
  282. {
  283. list($output, $default) = $args;
  284. }
  285. break;
  286. case 1:
  287. // E.g: $ready = DedeCli::prompt(array('y','n'));
  288. if (is_array($args[0]))
  289. {
  290. $options = $args[0];
  291. }
  292. // E.g: $ready = DedeCli::prompt('What did you do today?');
  293. elseif (is_string($args[0]))
  294. {
  295. $output = $args[0];
  296. }
  297. break;
  298. }
  299. if ($output !== '')
  300. {
  301. $extra_output = '';
  302. if ($default !== null)
  303. {
  304. $extra_output = ' [ Default: "'.$default.'" ]';
  305. }
  306. elseif ($options !== [])
  307. {
  308. $extra_output = ' [ '.implode(', ', $options).' ]';
  309. }
  310. fwrite(STDOUT, $output.$extra_output.': ');
  311. }
  312. $input = trim(static::input()) ? : $default;
  313. if (empty($input) && $required === true)
  314. {
  315. static::write('This is required.');
  316. static::newLine();
  317. $input = forward_static_call_array([__CLASS__, 'prompt'], $args);
  318. }
  319. if ( ! empty($options) && ! in_array($input, $options))
  320. {
  321. static::write('This is not a valid option. Please try again.');
  322. static::newLine();
  323. $input = forward_static_call_array([__CLASS__, 'prompt'], $args);
  324. }
  325. return empty($input) ? '' : $input;
  326. }
  327. public static function wait(int $seconds, bool $countdown = false)
  328. {
  329. if ($countdown === true)
  330. {
  331. $time = $seconds;
  332. while ($time > 0)
  333. {
  334. fwrite(STDOUT, $time.'... ');
  335. sleep(1);
  336. $time--;
  337. }
  338. static::write();
  339. }
  340. else
  341. {
  342. if ($seconds > 0)
  343. {
  344. sleep($seconds);
  345. }
  346. else
  347. {
  348. static::write(static::$wait_msg);
  349. static::input();
  350. }
  351. }
  352. }
  353. public static function error(string $text, string $foreground = 'light_red', string $background = null)
  354. {
  355. if ($foreground || $background)
  356. {
  357. $text = static::color($text, $foreground, $background);
  358. }
  359. fwrite(STDERR, $text.PHP_EOL);
  360. }
  361. public static function write(string $text = '', string $foreground = null, string $background = null)
  362. {
  363. if ($foreground || $background)
  364. {
  365. $text = static::color($text, $foreground, $background);
  366. }
  367. fwrite(STDOUT, $text.PHP_EOL);
  368. }
  369. }
  370. DedeCli::init();