1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Horde_Cli
15: {
16: 17: 18: 19: 20:
21: protected $_console;
22:
23: 24: 25: 26: 27:
28: protected $_newline;
29:
30: 31: 32: 33: 34:
35: protected $_clearscreen = '';
36:
37: 38: 39: 40: 41:
42: protected $_indent;
43:
44: 45: 46: 47: 48:
49: protected $_bold_start = '';
50:
51: 52: 53: 54: 55:
56: protected $_bold_end = '';
57:
58: 59: 60: 61: 62:
63: protected $_red_start = '';
64: protected $_green_start = '';
65: protected $_yellow_start = '';
66: protected $_blue_start = '';
67:
68: 69: 70: 71: 72:
73: protected $_red_end = '';
74: protected $_green_end = '';
75: protected $_yellow_end = '';
76: protected $_blue_end = '';
77:
78: 79: 80: 81: 82:
83: protected $_terminalForegrounds = array(
84: 'normal' => "\x1B[0m",
85: 'black' => "\x1B[0m",
86: 'bold' => "\x1b[1m",
87: 'red' => "\x1B[31m",
88: 'green' => "\x1B[32m",
89: 'brown' => "\x1B[33m",
90: 'blue' => "\x1B[34m",
91: 'magenta' => "\x1B[35m",
92: 'cyan' => "\x1B[36m",
93: 'lightgray' => "\x1B[37m",
94: 'white' => "\x1B[1m\x1B[37m",
95: 'darkgray' => "\x1B[1m\x1B[0m",
96: 'lightred' => "\x1B[1m\x1B[31m",
97: 'lightgreen' => "\x1B[1m\x1B[32m",
98: 'yellow' => "\x1B[1m\x1B[33m",
99: 'lightblue' => "\x1B[1m\x1B[34m",
100: 'lightmagenta' => "\x1B[1m\x1B[35m",
101: 'lightcyan' => "\x1B[1m\x1B[36m",
102: );
103:
104: 105: 106: 107: 108:
109: protected $_terminalBackgrounds = array(
110: 'normal' => "\x1B[0m",
111: 'black' => "\x1B[0m",
112: 'red' => "\x1B[41m",
113: 'green' => "\x1B[42m",
114: 'brown' => "\x1B[43m",
115: 'blue' => "\x1B[44m",
116: 'magenta' => "\x1B[45m",
117: 'cyan' => "\x1B[46m",
118: 'lightgray' => "\x1B[47m",
119: );
120:
121: 122: 123: 124: 125: 126:
127: public function __construct()
128: {
129: $this->_console = $this->runningFromCLI();
130:
131: if ($this->_console) {
132: $this->_newline = "\n";
133: $this->_indent = ' ';
134:
135: $term = getenv('TERM');
136: if ($term) {
137: if (preg_match('/^(xterm|vt220|linux)/', $term)) {
138: $this->_clearscreen = "\x1b[2J\x1b[H";
139: $this->_bold_start = "\x1b[1m";
140: $this->_red_start = "\x1b[01;31m";
141: $this->_green_start = "\x1b[01;32m";
142: $this->_yellow_start = "\x1b[01;33m";
143: $this->_blue_start = "\x1b[01;34m";
144: $this->_bold_end = $this->_red_end = $this->_green_end = $this->_yellow_end = $this->_blue_end = "\x1b[0m";
145: } elseif (preg_match('/^vt100/', $term)) {
146: $this->_clearscreen = "\x1b[2J\x1b[H";
147: $this->_bold_start = "\x1b[1m";
148: $this->_bold_end = "\x1b[0m";
149: }
150: }
151: } else {
152: $this->_newline = '<br />';
153: $this->_indent = str_repeat(' ', 4);
154:
155: $this->_bold_start = '<strong>';
156: $this->_bold_end = '</strong>';
157: $this->_red_start = '<span style="color:red">';
158: $this->_green_start = '<span style="color:green">';
159: $this->_yellow_start = '<span style="color:yellow">';
160: $this->_blue_start = '<span style="color:blue">';
161: $this->_red_end = $this->_green_end = $this->_yellow_end = $this->_blue_end = '</span>';
162: }
163:
164:
165:
166: if ($this->_console) {
167: register_shutdown_function(array($this, 'shutdown'));
168: }
169: }
170:
171: 172: 173: 174: 175: 176: 177:
178: public function writeln($text = '', $pre = false)
179: {
180: if ($pre) {
181: echo $this->_newline . $text;
182: } else {
183: echo $text . $this->_newline;
184: }
185: }
186:
187: 188: 189:
190: public function clearScreen()
191: {
192: echo $this->_clearscreen;
193: }
194:
195: 196: 197: 198: 199: 200: 201:
202: public function indent($text)
203: {
204: return $this->_indent . $text;
205: }
206:
207: 208: 209: 210: 211: 212: 213:
214: public function bold($text)
215: {
216: return $this->_bold_start . $text . $this->_bold_end;
217: }
218:
219: 220: 221: 222: 223: 224: 225:
226: public function red($text)
227: {
228: return $this->_red_start . $text . $this->_red_end;
229: }
230:
231: 232: 233: 234: 235: 236: 237:
238: public function green($text)
239: {
240: return $this->_green_start . $text . $this->_green_end;
241: }
242:
243: 244: 245: 246: 247: 248: 249:
250: public function blue($text)
251: {
252: return $this->_blue_start . $text . $this->_blue_end;
253: }
254:
255: 256: 257: 258: 259: 260: 261:
262: public function yellow($text)
263: {
264: return $this->_yellow_start . $text . $this->_yellow_end;
265: }
266:
267: 268: 269: 270: 271: 272: 273:
274: public function message($message, $type = 'cli.message')
275: {
276: $message = wordwrap(str_replace("\n", "\n ", $message),
277: 68, "\n ", true);
278:
279: switch ($type) {
280: case 'cli.error':
281: $type_message = $this->red('[ ERROR! ] ');
282: break;
283:
284: case 'cli.warning':
285: $type_message = $this->yellow('[ WARN ] ');
286: break;
287:
288: case 'cli.success':
289: $type_message = $this->green('[ OK ] ');
290: break;
291:
292: case 'cli.message':
293: $type_message = $this->blue('[ INFO ] ');
294: break;
295:
296: default:
297: $type_message = '';
298: }
299:
300: $this->writeln($type_message . $message);
301: }
302:
303: 304: 305: 306: 307: 308:
309: public function fatal($error)
310: {
311: if ($error instanceof Exception) {
312: $trace = $error;
313: } else {
314: $trace = debug_backtrace();
315: }
316: $backtrace = new Horde_Support_Backtrace($trace);
317: if (is_object($error) && method_exists($error, 'getMessage')) {
318: $error = $error->getMessage();
319: }
320: $this->writeln();
321: $this->writeln($this->red('===================='));
322: $this->writeln();
323: $this->writeln($this->red(Horde_Cli_Translation::t("Fatal Error:")));
324: $this->writeln($this->red($error));
325: $this->writeln();
326: $this->writeln((string)$backtrace);
327: $this->writeln($this->red('===================='));
328: exit(1);
329: }
330:
331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342:
343: public function prompt($prompt, $choices = null, $default = null)
344: {
345:
346: while (true) {
347:
348: if (is_array($choices) && !empty($choices)) {
349: $this->writeln(wordwrap($prompt) . ' ', !is_array($choices));
350: foreach ($choices as $key => $choice) {
351: $this->writeln($this->indent('(' . $this->bold($key) . ') ' . $choice));
352: }
353: $question = Horde_Cli_Translation::t("Type your choice");
354: if ($default !== null) {
355: $question .= ' [' . $default . ']';
356: }
357: $this->writeln($question . ': ', true);
358: @ob_flush();
359:
360:
361: $response = trim(fgets(STDIN));
362: if ($response === '' && $default !== null) {
363: $response = $default;
364: }
365: if (isset($choices[$response])) {
366: return $response;
367: } else {
368: $this->writeln($this->red(sprintf(Horde_Cli_Translation::t("\"%s\" is not a valid choice."), $response)));
369: }
370: } else {
371: if ($default !== null) {
372: $prompt .= ' [' . $default . ']';
373: }
374: $this->writeln(wordwrap($prompt) . ' ', true);
375: @ob_flush();
376: $response = trim(fgets(STDIN));
377: if ($response === '' && $default !== null) {
378: $response = $default;
379: }
380: return $response;
381: }
382: }
383:
384: return true;
385: }
386:
387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397:
398: public function passwordPrompt($prompt)
399: {
400: $prompt .= ' ';
401:
402: if (preg_match('/^win/i', PHP_OS)) {
403: $vbscript = sys_get_temp_dir() . 'prompt_password.vbs';
404: file_put_contents($vbscript, 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))');
405: $command = "cscript //nologo " . escapeshellarg($vbscript);
406: $password = rtrim(shell_exec($command));
407: unlink($vbscript);
408: } else {
409: $command = '/usr/bin/env bash -c "echo OK"';
410: if (rtrim(shell_exec($command)) !== 'OK') {
411:
412: return $this->prompt($prompt);
413: }
414: $command = '/usr/bin/env bash -c "read -s -p ' . escapeshellarg($prompt) . ' mypassword && echo \$mypassword"';
415: $password = rtrim(shell_exec($command));
416: echo "\n";
417: }
418:
419: return $password;
420: }
421:
422: 423: 424: 425: 426: 427:
428: public function readStdin()
429: {
430: $in = '';
431: while (!feof(STDIN)) {
432: $in .= fgets(STDIN, 1024);
433: }
434: return $in;
435: }
436:
437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447:
448: static public function init()
449: {
450: 451:
452: $cli = new self();
453:
454: @set_time_limit(0);
455: ob_implicit_flush(true);
456: ini_set('html_errors', false);
457: set_exception_handler(array($cli, 'fatal'));
458: if (!isset($_SERVER['HTTP_HOST'])) {
459: $_SERVER['HTTP_HOST'] = '127.0.0.1';
460: }
461: if (!isset($_SERVER['SERVER_NAME'])) {
462: $_SERVER['SERVER_NAME'] = '127.0.0.1';
463: }
464: if (!isset($_SERVER['SERVER_PORT'])) {
465: $_SERVER['SERVER_PORT'] = '';
466: }
467: if (!isset($_SERVER['REMOTE_ADDR'])) {
468: $_SERVER['REMOTE_ADDR'] = '';
469: }
470: $_SERVER['PHP_SELF'] = isset($argv) ? $argv[0] : '';
471: if (!defined('STDIN')) {
472: define('STDIN', fopen('php://stdin', 'r'));
473: }
474: if (!defined('STDOUT')) {
475: define('STDOUT', fopen('php://stdout', 'r'));
476: }
477: if (!defined('STDERR')) {
478: define('STDERR', fopen('php://stderr', 'r'));
479: }
480:
481: return $cli;
482: }
483:
484: 485: 486: 487: 488: 489:
490: static public function runningFromCLI()
491: {
492: return (PHP_SAPI == 'cli') ||
493: (((PHP_SAPI == 'cgi') || (PHP_SAPI == 'cgi-fcgi')) &&
494: empty($_SERVER['SERVER_NAME']));
495: }
496:
497: 498: 499:
500: public function shutdown()
501: {
502: if (session_id()) {
503: session_destroy();
504: }
505: }
506:
507: }
508: