PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / 3.1.13.4
JetBackup – Backup, Restore & Migrate v3.1.13.4
3.1.22.4 3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / 3rdparty / phpseclib3 / File / ANSI.php
backup / src / JetBackup / 3rdparty / phpseclib3 / File Last commit date
ASN1 9 months ago .htaccess 9 months ago ANSI.php 9 months ago ASN1.php 9 months ago X509.php 9 months ago index.html 9 months ago web.config 9 months ago
ANSI.php
533 lines
1 <?php
2
3 /**
4 * Pure-PHP ANSI Decoder
5 *
6 * PHP version 5
7 *
8 * If you call read() in \phpseclib3\Net\SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
9 * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
10 * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
11 * color to display them in, etc. \phpseclib3\File\ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
12 *
13 * @author Jim Wigginton <terrafrost@php.net>
14 * @copyright 2012 Jim Wigginton
15 * @license http://www.opensource.org/licenses/mit-license.html MIT License
16 * @link http://phpseclib.sourceforge.net
17 */
18
19 declare(strict_types=1);
20
21 namespace phpseclib3\File;
22
23 /**
24 * Pure-PHP ANSI Decoder
25 *
26 * @author Jim Wigginton <terrafrost@php.net>
27 */
28 class ANSI
29 {
30 /**
31 * Max Width
32 *
33 * @var int
34 */
35 private $max_x;
36
37 /**
38 * Max Height
39 *
40 * @var int
41 */
42 private $max_y;
43
44 /**
45 * Max History
46 *
47 * @var int
48 */
49 private $max_history;
50
51 /**
52 * History
53 *
54 * @var array
55 */
56 private $history;
57
58 /**
59 * History Attributes
60 *
61 * @var array
62 */
63 private $history_attrs;
64
65 /**
66 * Current Column
67 *
68 * @var int
69 */
70 private $x;
71
72 /**
73 * Current Row
74 *
75 * @var int
76 */
77 private $y;
78
79 /**
80 * Old Column
81 *
82 * @var int
83 */
84 private $old_x;
85
86 /**
87 * Old Row
88 *
89 * @var int
90 */
91 private $old_y;
92
93 /**
94 * An empty attribute cell
95 *
96 * @var object
97 */
98 private $base_attr_cell;
99
100 /**
101 * The current attribute cell
102 *
103 * @var object
104 */
105 private $attr_cell;
106
107 /**
108 * An empty attribute row
109 *
110 * @var array
111 */
112 private $attr_row;
113
114 /**
115 * The current screen text
116 *
117 * @var list<string>
118 */
119 private $screen;
120
121 /**
122 * The current screen attributes
123 *
124 * @var array
125 */
126 private $attrs;
127
128 /**
129 * Current ANSI code
130 *
131 * @var string
132 */
133 private $ansi;
134
135 /**
136 * Tokenization
137 *
138 * @var array
139 */
140 private $tokenization;
141
142 /**
143 * Default Constructor.
144 *
145 * @return ANSI
146 */
147 public function __construct()
148 {
149 $attr_cell = new \stdClass();
150 $attr_cell->bold = false;
151 $attr_cell->underline = false;
152 $attr_cell->blink = false;
153 $attr_cell->background = 'black';
154 $attr_cell->foreground = 'white';
155 $attr_cell->reverse = false;
156 $this->base_attr_cell = clone $attr_cell;
157 $this->attr_cell = clone $attr_cell;
158
159 $this->setHistory(200);
160 $this->setDimensions(80, 24);
161 }
162
163 /**
164 * Set terminal width and height
165 *
166 * Resets the screen as well
167 */
168 public function setDimensions(int $x, int $y): void
169 {
170 $this->max_x = $x - 1;
171 $this->max_y = $y - 1;
172 $this->x = $this->y = 0;
173 $this->history = $this->history_attrs = [];
174 $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
175 $this->screen = array_fill(0, $this->max_y + 1, '');
176 $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
177 $this->ansi = '';
178 }
179
180 /**
181 * Set the number of lines that should be logged past the terminal height
182 */
183 public function setHistory(int $history): void
184 {
185 $this->max_history = $history;
186 }
187
188 /**
189 * Load a string
190 */
191 public function loadString(string $source): void
192 {
193 $this->setDimensions($this->max_x + 1, $this->max_y + 1);
194 $this->appendString($source);
195 }
196
197 /**
198 * Appdend a string
199 */
200 public function appendString(string $source): void
201 {
202 $this->tokenization = [''];
203 for ($i = 0; $i < strlen($source); $i++) {
204 if (strlen($this->ansi)) {
205 $this->ansi .= $source[$i];
206 $chr = ord($source[$i]);
207 // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
208 // single character CSI's not currently supported
209 switch (true) {
210 case $this->ansi == "\x1B=":
211 $this->ansi = '';
212 continue 2;
213 case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
214 case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
215 break;
216 default:
217 continue 2;
218 }
219 $this->tokenization[] = $this->ansi;
220 $this->tokenization[] = '';
221 // http://ascii-table.com/ansi-escape-sequences-vt-100.php
222 switch ($this->ansi) {
223 case "\x1B[H": // Move cursor to upper left corner
224 $this->old_x = $this->x;
225 $this->old_y = $this->y;
226 $this->x = $this->y = 0;
227 break;
228 case "\x1B[J": // Clear screen from cursor down
229 $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
230 $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
231
232 $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
233 $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
234
235 if (count($this->history) == $this->max_history) {
236 array_shift($this->history);
237 array_shift($this->history_attrs);
238 }
239 // fall-through
240 case "\x1B[K": // Clear screen from cursor right
241 $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
242
243 array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - ($this->x - 1), $this->base_attr_cell));
244 break;
245 case "\x1B[2K": // Clear entire line
246 $this->screen[$this->y] = str_repeat(' ', $this->x);
247 $this->attrs[$this->y] = $this->attr_row;
248 break;
249 case "\x1B[?1h": // set cursor key to application
250 case "\x1B[?25h": // show the cursor
251 case "\x1B(B": // set united states g0 character set
252 break;
253 case "\x1BE": // Move to next line
254 $this->newLine();
255 $this->x = 0;
256 break;
257 default:
258 switch (true) {
259 case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
260 $this->old_y = $this->y;
261 $this->y += (int) $match[1];
262 break;
263 case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
264 $this->old_x = $this->x;
265 $this->old_y = $this->y;
266 $this->x = $match[2] - 1;
267 $this->y = (int) $match[1] - 1;
268 break;
269 case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
270 $this->old_x = $this->x;
271 $this->x += $match[1];
272 break;
273 case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
274 $this->old_x = $this->x;
275 $this->x -= $match[1];
276 if ($this->x < 0) {
277 $this->x = 0;
278 }
279 break;
280 case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
281 break;
282 case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
283 $attr_cell = &$this->attr_cell;
284 $mods = explode(';', $match[1]);
285 foreach ($mods as $mod) {
286 switch ($mod) {
287 case '':
288 case '0': // Turn off character attributes
289 $attr_cell = clone $this->base_attr_cell;
290 break;
291 case '1': // Turn bold mode on
292 $attr_cell->bold = true;
293 break;
294 case '4': // Turn underline mode on
295 $attr_cell->underline = true;
296 break;
297 case '5': // Turn blinking mode on
298 $attr_cell->blink = true;
299 break;
300 case '7': // Turn reverse video on
301 $attr_cell->reverse = !$attr_cell->reverse;
302 $temp = $attr_cell->background;
303 $attr_cell->background = $attr_cell->foreground;
304 $attr_cell->foreground = $temp;
305 break;
306 default: // set colors
307 //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
308 $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
309 //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
310 $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
311 switch ($mod) {
312 // @codingStandardsIgnoreStart
313 case '30': $front = 'black'; break;
314 case '31': $front = 'red'; break;
315 case '32': $front = 'green'; break;
316 case '33': $front = 'yellow'; break;
317 case '34': $front = 'blue'; break;
318 case '35': $front = 'magenta'; break;
319 case '36': $front = 'cyan'; break;
320 case '37': $front = 'white'; break;
321
322 case '40': $back = 'black'; break;
323 case '41': $back = 'red'; break;
324 case '42': $back = 'green'; break;
325 case '43': $back = 'yellow'; break;
326 case '44': $back = 'blue'; break;
327 case '45': $back = 'magenta'; break;
328 case '46': $back = 'cyan'; break;
329 case '47': $back = 'white'; break;
330 // @codingStandardsIgnoreEnd
331
332 default:
333 //user_error('Unsupported attribute: ' . $mod);
334 $this->ansi = '';
335 break 2;
336 }
337 }
338 }
339 break;
340 default:
341 //user_error("{$this->ansi} is unsupported\r\n");
342 }
343 }
344 $this->ansi = '';
345 continue;
346 }
347
348 $this->tokenization[count($this->tokenization) - 1] .= $source[$i];
349 switch ($source[$i]) {
350 case "\r":
351 $this->x = 0;
352 break;
353 case "\n":
354 $this->newLine();
355 break;
356 case "\x08": // backspace
357 if ($this->x) {
358 $this->x--;
359 $this->attrs[$this->y][$this->x] = clone $this->base_attr_cell;
360 $this->screen[$this->y] = substr_replace(
361 $this->screen[$this->y],
362 $source[$i],
363 $this->x,
364 1
365 );
366 }
367 break;
368 case "\x0F": // shift
369 break;
370 case "\x1B": // start ANSI escape code
371 $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
372 //if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
373 // array_pop($this->tokenization);
374 //}
375 $this->ansi .= "\x1B";
376 break;
377 default:
378 $this->attrs[$this->y][$this->x] = clone $this->attr_cell;
379 if ($this->x > strlen($this->screen[$this->y])) {
380 $this->screen[$this->y] = str_repeat(' ', $this->x);
381 }
382 $this->screen[$this->y] = substr_replace(
383 $this->screen[$this->y],
384 $source[$i],
385 $this->x,
386 1
387 );
388
389 if ($this->x > $this->max_x) {
390 $this->x = 0;
391 $this->newLine();
392 } else {
393 $this->x++;
394 }
395 }
396 }
397 }
398
399 /**
400 * Add a new line
401 *
402 * Also update the $this->screen and $this->history buffers
403 */
404 private function newLine(): void
405 {
406 //if ($this->y < $this->max_y) {
407 // $this->y++;
408 //}
409
410 while ($this->y >= $this->max_y) {
411 $this->history = array_merge($this->history, [array_shift($this->screen)]);
412 $this->screen[] = '';
413
414 $this->history_attrs = array_merge($this->history_attrs, [array_shift($this->attrs)]);
415 $this->attrs[] = $this->attr_row;
416
417 if (count($this->history) >= $this->max_history) {
418 array_shift($this->history);
419 array_shift($this->history_attrs);
420 }
421
422 $this->y--;
423 }
424 $this->y++;
425 }
426
427 /**
428 * Returns the current coordinate without preformating
429 */
430 private function processCoordinate(\stdClass $last_attr, \stdClass $cur_attr, string $char): string
431 {
432 $output = '';
433
434 if ($last_attr != $cur_attr) {
435 $close = $open = '';
436 if ($last_attr->foreground != $cur_attr->foreground) {
437 if ($cur_attr->foreground != 'white') {
438 $open .= '<span style="color: ' . $cur_attr->foreground . '">';
439 }
440 if ($last_attr->foreground != 'white') {
441 $close = '</span>' . $close;
442 }
443 }
444 if ($last_attr->background != $cur_attr->background) {
445 if ($cur_attr->background != 'black') {
446 $open .= '<span style="background: ' . $cur_attr->background . '">';
447 }
448 if ($last_attr->background != 'black') {
449 $close = '</span>' . $close;
450 }
451 }
452 if ($last_attr->bold != $cur_attr->bold) {
453 if ($cur_attr->bold) {
454 $open .= '<b>';
455 } else {
456 $close = '</b>' . $close;
457 }
458 }
459 if ($last_attr->underline != $cur_attr->underline) {
460 if ($cur_attr->underline) {
461 $open .= '<u>';
462 } else {
463 $close = '</u>' . $close;
464 }
465 }
466 if ($last_attr->blink != $cur_attr->blink) {
467 if ($cur_attr->blink) {
468 $open .= '<blink>';
469 } else {
470 $close = '</blink>' . $close;
471 }
472 }
473 $output .= $close . $open;
474 }
475
476 $output .= htmlspecialchars($char);
477
478 return $output;
479 }
480
481 /**
482 * Returns the current screen without preformating
483 */
484 private function getScreenHelper(): string
485 {
486 $output = '';
487 $last_attr = $this->base_attr_cell;
488 for ($i = 0; $i <= $this->max_y; $i++) {
489 for ($j = 0; $j <= $this->max_x; $j++) {
490 $cur_attr = $this->attrs[$i][$j];
491 $output .= $this->processCoordinate($last_attr, $cur_attr, $this->screen[$i][$j] ?? '');
492 $last_attr = $this->attrs[$i][$j];
493 }
494 $output .= "\r\n";
495 }
496 $output = substr($output, 0, -2);
497 // close any remaining open tags
498 $output .= $this->processCoordinate($last_attr, $this->base_attr_cell, '');
499 return rtrim($output);
500 }
501
502 /**
503 * Returns the current screen
504 */
505 public function getScreen(): string
506 {
507 return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->getScreenHelper() . '</pre>';
508 }
509
510 /**
511 * Returns the current screen and the x previous lines
512 */
513 public function getHistory(): string
514 {
515 $scrollback = '';
516 $last_attr = $this->base_attr_cell;
517 for ($i = 0; $i < count($this->history); $i++) {
518 for ($j = 0; $j <= $this->max_x + 1; $j++) {
519 $cur_attr = $this->history_attrs[$i][$j];
520 $scrollback .= $this->processCoordinate($last_attr, $cur_attr, $this->history[$i][$j] ?? '');
521 $last_attr = $this->history_attrs[$i][$j];
522 }
523 $scrollback .= "\r\n";
524 }
525 $base_attr_cell = $this->base_attr_cell;
526 $this->base_attr_cell = $last_attr;
527 $scrollback .= $this->getScreen();
528 $this->base_attr_cell = $base_attr_cell;
529
530 return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
531 }
532 }
533