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

317 lines
10KB

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