国内流行的内容管理系统(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.

369 lines
11KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. //Copyright 2020 The DedeBiz Authors. All rights reserved.
  4. //license that can be found in the LICENSE file.
  5. //@copyright Copyright (c) 2022, DedeBIZ.COM
  6. //@license https://www.dedebiz.com/license
  7. //@link https://www.dedebiz.com
  8. /*
  9. The MIT License (MIT)
  10. Copyright (c) 2014-2019 British Columbia Institute of Technology
  11. Copyright (c) 2019-2020 CodeIgniter Foundation
  12. */
  13. function is_cli()
  14. {
  15. return (PHP_SAPI === 'cli' || defined('STDIN'));
  16. }
  17. class DedeCli
  18. {
  19. public static $readline_support = false;
  20. protected static $initialized = false;
  21. protected static $wait_msg = "Press any key to continue";
  22. protected static $segments = [];
  23. protected static $options = [];
  24. protected static $foreground_colors = [
  25. 'black' => '0;30',
  26. 'dark_gray' => '1;30',
  27. 'blue' => '0;34',
  28. 'dark_blue' => '1;34',
  29. 'light_blue' => '1;34',
  30. 'green' => '0;32',
  31. 'light_green' => '1;32',
  32. 'cyan' => '0;36',
  33. 'light_cyan' => '1;36',
  34. 'red' => '0;31',
  35. 'light_red' => '1;31',
  36. 'purple' => '0;35',
  37. 'light_purple' => '1;35',
  38. 'light_yellow' => '0;33',
  39. 'yellow' => '1;33',
  40. 'light_gray' => '0;37',
  41. 'white' => '1;37',
  42. ];
  43. protected static $background_colors = [
  44. 'black' => '40',
  45. 'red' => '41',
  46. 'green' => '42',
  47. 'yellow' => '43',
  48. 'blue' => '44',
  49. 'magenta' => '45',
  50. 'cyan' => '46',
  51. 'light_gray' => '47',
  52. ];
  53. public static function init()
  54. {
  55. if (is_cli())
  56. {
  57. static::$readline_support = extension_loaded('readline');
  58. static::parseCommandLine();
  59. static::$initialized = true;
  60. } else {
  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, int $pos = 0,int $total = 0)
  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. $addstr = "";
  191. if ($pos > 0 && $total > 0) {
  192. $addstr .= " Pos:{$pos},Total:{$total}";
  193. }
  194. fwrite(STDOUT, sprintf(" %3d%% Complete{$addstr}", $percent).PHP_EOL);
  195. } else {
  196. fwrite(STDOUT, "\007");
  197. }
  198. }
  199. public static function wrap(string $string = null, int $max = 0, int $pad_left = 0): string
  200. {
  201. if (empty($string))
  202. {
  203. return '';
  204. }
  205. if ($max == 0)
  206. {
  207. $max = DedeCli::getWidth();
  208. }
  209. if (DedeCli::getWidth() < $max)
  210. {
  211. $max = DedeCli::getWidth();
  212. }
  213. $max = $max - $pad_left;
  214. $lines = wordwrap($string, $max);
  215. if ($pad_left > 0)
  216. {
  217. $lines = explode(PHP_EOL, $lines);
  218. $first = true;
  219. array_walk($lines, function (&$line, $index) use ($max, $pad_left, &$first)
  220. {
  221. if ( ! $first)
  222. {
  223. $line = str_repeat(" ", $pad_left).$line;
  224. } else {
  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. } else {
  340. if ($seconds > 0)
  341. {
  342. sleep($seconds);
  343. } else {
  344. static::write(static::$wait_msg);
  345. static::input();
  346. }
  347. }
  348. }
  349. public static function error(string $text, string $foreground = 'light_red', string $background = null)
  350. {
  351. if ($foreground || $background)
  352. {
  353. $text = static::color($text, $foreground, $background);
  354. }
  355. fwrite(STDERR, $text.PHP_EOL);
  356. }
  357. public static function write(string $text = '', string $foreground = null, string $background = null)
  358. {
  359. if ($foreground || $background)
  360. {
  361. $text = static::color($text, $foreground, $background);
  362. }
  363. fwrite(STDOUT, $text.PHP_EOL);
  364. }
  365. }
  366. DedeCli::init();