PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.4
Booking for Appointments and Events Calendar – Amelia v2.4.4
2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / vendor / sabre / vobject / lib / Cli.php
ameliabooking / vendor / sabre / vobject / lib Last commit date
Component 6 months ago ITip 6 months ago Parser 6 months ago Property 6 months ago Recur 6 months ago Splitter 6 months ago TimezoneGuesser 6 months ago timezonedata 1 year ago BirthdayCalendarGenerator.php 6 months ago Cli.php 6 months ago Component.php 6 months ago DateTimeParser.php 6 months ago Document.php 6 months ago ElementList.php 6 months ago EofException.php 6 months ago FreeBusyData.php 6 months ago FreeBusyGenerator.php 6 months ago InvalidDataException.php 6 months ago Node.php 6 months ago PHPUnitAssertions.php 6 months ago Parameter.php 6 months ago ParseException.php 6 months ago Property.php 6 months ago Reader.php 6 months ago Settings.php 6 months ago StringUtil.php 6 months ago TimeZoneUtil.php 6 months ago UUIDUtil.php 6 months ago VCardConverter.php 6 months ago Version.php 6 months ago Writer.php 6 months ago
Cli.php
592 lines
1 <?php
2
3 namespace AmeliaVendor\Sabre\VObject;
4
5 use InvalidArgumentException;
6 /**
7 * This is the CLI interface for sabre-vobject.
8 *
9 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
10 * @author Evert Pot (http://evertpot.com/)
11 * @license http://sabre.io/license/ Modified BSD License
12 */
13 class Cli
14 {
15 /**
16 * No output.
17 *
18 * @var bool
19 */
20 protected $quiet = false;
21 /**
22 * Help display.
23 *
24 * @var bool
25 */
26 protected $showHelp = false;
27 /**
28 * Whether to spit out 'mimedir' or 'json' format.
29 *
30 * @var string
31 */
32 protected $format;
33 /**
34 * JSON pretty print.
35 *
36 * @var bool
37 */
38 protected $pretty;
39 /**
40 * Source file.
41 *
42 * @var string
43 */
44 protected $inputPath;
45 /**
46 * Destination file.
47 *
48 * @var string
49 */
50 protected $outputPath;
51 /**
52 * output stream.
53 *
54 * @var resource
55 */
56 protected $stdout;
57 /**
58 * stdin.
59 *
60 * @var resource
61 */
62 protected $stdin;
63 /**
64 * stderr.
65 *
66 * @var resource
67 */
68 protected $stderr;
69 /**
70 * Input format (one of json or mimedir).
71 *
72 * @var string
73 */
74 protected $inputFormat;
75 /**
76 * Makes the parser less strict.
77 *
78 * @var bool
79 */
80 protected $forgiving = false;
81 /**
82 * Main function.
83 *
84 * @return int
85 */
86 public function main(array $argv)
87 {
88 // @codeCoverageIgnoreStart
89 // We cannot easily test this, so we'll skip it. Pretty basic anyway.
90 if (!$this->stderr) {
91 $this->stderr = fopen('php://stderr', 'w');
92 }
93 if (!$this->stdout) {
94 $this->stdout = fopen('php://stdout', 'w');
95 }
96 if (!$this->stdin) {
97 $this->stdin = fopen('php://stdin', 'r');
98 }
99 // @codeCoverageIgnoreEnd
100 try {
101 list($options, $positional) = $this->parseArguments($argv);
102 if (isset($options['q'])) {
103 $this->quiet = true;
104 }
105 $this->log($this->colorize('green', 'sabre/vobject ') . $this->colorize('yellow', Version::VERSION));
106 foreach ($options as $name => $value) {
107 switch ($name) {
108 case 'q':
109 // Already handled earlier.
110 break;
111 case 'h':
112 case 'help':
113 $this->showHelp();
114 return 0;
115 break;
116 case 'format':
117 switch ($value) {
118 // jcard/jcal documents
119 case 'jcard':
120 case 'jcal':
121 // specific document versions
122 case 'vcard21':
123 case 'vcard30':
124 case 'vcard40':
125 case 'icalendar20':
126 // specific formats
127 case 'json':
128 case 'mimedir':
129 // icalendar/vcad
130 case 'icalendar':
131 case 'vcard':
132 $this->format = $value;
133 break;
134 default:
135 throw new InvalidArgumentException('Unknown format: ' . $value);
136 }
137 break;
138 case 'pretty':
139 if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
140 $this->pretty = true;
141 }
142 break;
143 case 'forgiving':
144 $this->forgiving = true;
145 break;
146 case 'inputformat':
147 switch ($value) {
148 // json formats
149 case 'jcard':
150 case 'jcal':
151 case 'json':
152 $this->inputFormat = 'json';
153 break;
154 // mimedir formats
155 case 'mimedir':
156 case 'icalendar':
157 case 'vcard':
158 case 'vcard21':
159 case 'vcard30':
160 case 'vcard40':
161 case 'icalendar20':
162 $this->inputFormat = 'mimedir';
163 break;
164 default:
165 throw new InvalidArgumentException('Unknown format: ' . $value);
166 }
167 break;
168 default:
169 throw new InvalidArgumentException('Unknown option: ' . $name);
170 }
171 }
172 if (0 === count($positional)) {
173 $this->showHelp();
174 return 1;
175 }
176 if (1 === count($positional)) {
177 throw new InvalidArgumentException('Inputfile is a required argument');
178 }
179 if (count($positional) > 3) {
180 throw new InvalidArgumentException('Too many arguments');
181 }
182 if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'])) {
183 throw new InvalidArgumentException('Unknown command: ' . $positional[0]);
184 }
185 } catch (InvalidArgumentException $e) {
186 $this->showHelp();
187 $this->log('Error: ' . $e->getMessage(), 'red');
188 return 1;
189 }
190 $command = $positional[0];
191 $this->inputPath = $positional[1];
192 $this->outputPath = isset($positional[2]) ? $positional[2] : '-';
193 if ('-' !== $this->outputPath) {
194 $this->stdout = fopen($this->outputPath, 'w');
195 }
196 if (!$this->inputFormat) {
197 if ('.json' === substr($this->inputPath, -5)) {
198 $this->inputFormat = 'json';
199 } else {
200 $this->inputFormat = 'mimedir';
201 }
202 }
203 if (!$this->format) {
204 if ('.json' === substr($this->outputPath, -5)) {
205 $this->format = 'json';
206 } else {
207 $this->format = 'mimedir';
208 }
209 }
210 $realCode = 0;
211 try {
212 while ($input = $this->readInput()) {
213 $returnCode = $this->{$command}($input);
214 if (0 !== $returnCode) {
215 $realCode = $returnCode;
216 }
217 }
218 } catch (EofException $e) {
219 // end of file
220 } catch (\Exception $e) {
221 $this->log('Error: ' . $e->getMessage(), 'red');
222 return 2;
223 }
224 return $realCode;
225 }
226 /**
227 * Shows the help message.
228 */
229 protected function showHelp()
230 {
231 $this->log('Usage:', 'yellow');
232 $this->log(' vobject [options] command [arguments]');
233 $this->log('');
234 $this->log('Options:', 'yellow');
235 $this->log($this->colorize('green', ' -q ') . "Don't output anything.");
236 $this->log($this->colorize('green', ' -help -h ') . 'Display this help message.');
237 $this->log($this->colorize('green', ' --format ') . 'Convert to a specific format. Must be one of: vcard, vcard21,');
238 $this->log($this->colorize('green', ' --forgiving ') . 'Makes the parser less strict.');
239 $this->log(' vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.');
240 $this->log($this->colorize('green', ' --inputformat ') . 'If the input format cannot be guessed from the extension, it');
241 $this->log(' must be specified here.');
242 // Only PHP 5.4 and up
243 if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
244 $this->log($this->colorize('green', ' --pretty ') . 'json pretty-print.');
245 }
246 $this->log('');
247 $this->log('Commands:', 'yellow');
248 $this->log($this->colorize('green', ' validate') . ' source_file Validates a file for correctness.');
249 $this->log($this->colorize('green', ' repair') . ' source_file [output_file] Repairs a file.');
250 $this->log($this->colorize('green', ' convert') . ' source_file [output_file] Converts a file.');
251 $this->log($this->colorize('green', ' color') . ' source_file Colorize a file, useful for debugging.');
252 $this->log(<<<HELP
253
254 If source_file is set as '-', STDIN will be used.
255 If output_file is omitted, STDOUT will be used.
256 All other output is sent to STDERR.
257
258 HELP);
259 $this->log('Examples:', 'yellow');
260 $this->log(' vobject convert contact.vcf contact.json');
261 $this->log(' vobject convert --format=vcard40 old.vcf new.vcf');
262 $this->log(' vobject convert --inputformat=json --format=mimedir - -');
263 $this->log(' vobject color calendar.ics');
264 $this->log('');
265 $this->log('https://github.com/fruux/sabre-vobject', 'purple');
266 }
267 /**
268 * Validates a VObject file.
269 *
270 * @return int
271 */
272 protected function validate(Component $vObj)
273 {
274 $returnCode = 0;
275 switch ($vObj->name) {
276 case 'VCALENDAR':
277 $this->log('iCalendar: ' . (string) $vObj->VERSION);
278 break;
279 case 'VCARD':
280 $this->log('vCard: ' . (string) $vObj->VERSION);
281 break;
282 }
283 $warnings = $vObj->validate();
284 if (!count($warnings)) {
285 $this->log(' No warnings!');
286 } else {
287 $levels = [1 => 'REPAIRED', 2 => 'WARNING', 3 => 'ERROR'];
288 $returnCode = 2;
289 foreach ($warnings as $warn) {
290 $extra = '';
291 if ($warn['node'] instanceof Property) {
292 $extra = ' (property: "' . $warn['node']->name . '")';
293 }
294 $this->log(' [' . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
295 }
296 }
297 return $returnCode;
298 }
299 /**
300 * Repairs a VObject file.
301 *
302 * @return int
303 */
304 protected function repair(Component $vObj)
305 {
306 $returnCode = 0;
307 switch ($vObj->name) {
308 case 'VCALENDAR':
309 $this->log('iCalendar: ' . (string) $vObj->VERSION);
310 break;
311 case 'VCARD':
312 $this->log('vCard: ' . (string) $vObj->VERSION);
313 break;
314 }
315 $warnings = $vObj->validate(Node::REPAIR);
316 if (!count($warnings)) {
317 $this->log(' No warnings!');
318 } else {
319 $levels = [1 => 'REPAIRED', 2 => 'WARNING', 3 => 'ERROR'];
320 $returnCode = 2;
321 foreach ($warnings as $warn) {
322 $extra = '';
323 if ($warn['node'] instanceof Property) {
324 $extra = ' (property: "' . $warn['node']->name . '")';
325 }
326 $this->log(' [' . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
327 }
328 }
329 fwrite($this->stdout, $vObj->serialize());
330 return $returnCode;
331 }
332 /**
333 * Converts a vObject file to a new format.
334 *
335 * @param Component $vObj
336 *
337 * @return int
338 */
339 protected function convert($vObj)
340 {
341 $json = false;
342 $convertVersion = null;
343 $forceInput = null;
344 switch ($this->format) {
345 case 'json':
346 $json = true;
347 if ('VCARD' === $vObj->name) {
348 $convertVersion = Document::VCARD40;
349 }
350 break;
351 case 'jcard':
352 $json = true;
353 $forceInput = 'VCARD';
354 $convertVersion = Document::VCARD40;
355 break;
356 case 'jcal':
357 $json = true;
358 $forceInput = 'VCALENDAR';
359 break;
360 case 'mimedir':
361 case 'icalendar':
362 case 'icalendar20':
363 case 'vcard':
364 break;
365 case 'vcard21':
366 $convertVersion = Document::VCARD21;
367 break;
368 case 'vcard30':
369 $convertVersion = Document::VCARD30;
370 break;
371 case 'vcard40':
372 $convertVersion = Document::VCARD40;
373 break;
374 }
375 if ($forceInput && $vObj->name !== $forceInput) {
376 throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
377 }
378 if ($convertVersion) {
379 $vObj = $vObj->convert($convertVersion);
380 }
381 if ($json) {
382 $jsonOptions = 0;
383 if ($this->pretty) {
384 $jsonOptions = JSON_PRETTY_PRINT;
385 }
386 fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
387 } else {
388 fwrite($this->stdout, $vObj->serialize());
389 }
390 return 0;
391 }
392 /**
393 * Colorizes a file.
394 *
395 * @param Component $vObj
396 */
397 protected function color($vObj)
398 {
399 $this->serializeComponent($vObj);
400 }
401 /**
402 * Returns an ansi color string for a color name.
403 *
404 * @param string $color
405 *
406 * @return string
407 */
408 protected function colorize($color, $str, $resetTo = 'default')
409 {
410 $colors = ['cyan' => '1;36', 'red' => '1;31', 'yellow' => '1;33', 'blue' => '0;34', 'green' => '0;32', 'default' => '0', 'purple' => '0;35'];
411 return "\x1b[" . $colors[$color] . 'm' . $str . "\x1b[" . $colors[$resetTo] . 'm';
412 }
413 /**
414 * Writes out a string in specific color.
415 *
416 * @param string $color
417 * @param string $str
418 */
419 protected function cWrite($color, $str)
420 {
421 fwrite($this->stdout, $this->colorize($color, $str));
422 }
423 protected function serializeComponent(Component $vObj)
424 {
425 $this->cWrite('cyan', 'BEGIN');
426 $this->cWrite('red', ':');
427 $this->cWrite('yellow', $vObj->name . "\n");
428 /**
429 * Gives a component a 'score' for sorting purposes.
430 *
431 * This is solely used by the childrenSort method.
432 *
433 * A higher score means the item will be lower in the list.
434 * To avoid score collisions, each "score category" has a reasonable
435 * space to accommodate elements. The $key is added to the $score to
436 * preserve the original relative order of elements.
437 *
438 * @param int $key
439 * @param array $array
440 *
441 * @return int
442 */
443 $sortScore = function ($key, $array) {
444 if ($array[$key] instanceof Component) {
445 // We want to encode VTIMEZONE first, this is a personal
446 // preference.
447 if ('VTIMEZONE' === $array[$key]->name) {
448 $score = 300000000;
449 return $score + $key;
450 } else {
451 $score = 400000000;
452 return $score + $key;
453 }
454 } else if ($array[$key] instanceof Property) {
455 if ('VERSION' === $array[$key]->name) {
456 $score = 100000000;
457 return $score + $key;
458 } else {
459 // All other properties
460 $score = 200000000;
461 return $score + $key;
462 }
463 }
464 };
465 $children = $vObj->children();
466 $tmp = $children;
467 uksort($children, function ($a, $b) use ($sortScore, $tmp) {
468 $sA = $sortScore($a, $tmp);
469 $sB = $sortScore($b, $tmp);
470 return $sA - $sB;
471 });
472 foreach ($children as $child) {
473 if ($child instanceof Component) {
474 $this->serializeComponent($child);
475 } else {
476 $this->serializeProperty($child);
477 }
478 }
479 $this->cWrite('cyan', 'END');
480 $this->cWrite('red', ':');
481 $this->cWrite('yellow', $vObj->name . "\n");
482 }
483 /**
484 * Colorizes a property.
485 */
486 protected function serializeProperty(Property $property)
487 {
488 if ($property->group) {
489 $this->cWrite('default', $property->group);
490 $this->cWrite('red', '.');
491 }
492 $this->cWrite('yellow', $property->name);
493 foreach ($property->parameters as $param) {
494 $this->cWrite('red', ';');
495 $this->cWrite('blue', $param->serialize());
496 }
497 $this->cWrite('red', ':');
498 if ($property instanceof \AmeliaVendor\Sabre\VObject\Property\Binary) {
499 $this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
500 } else {
501 $parts = $property->getParts();
502 $first1 = true;
503 // Looping through property values
504 foreach ($parts as $part) {
505 if ($first1) {
506 $first1 = false;
507 } else {
508 $this->cWrite('red', $property->delimiter);
509 }
510 $first2 = true;
511 // Looping through property sub-values
512 foreach ((array) $part as $subPart) {
513 if ($first2) {
514 $first2 = false;
515 } else {
516 // The sub-value delimiter is always comma
517 $this->cWrite('red', ',');
518 }
519 $subPart = strtr($subPart, ['\\' => $this->colorize('purple', '\\\\', 'green'), ';' => $this->colorize('purple', '\;', 'green'), ',' => $this->colorize('purple', '\,', 'green'), "\n" => $this->colorize('purple', "\\n\n\t", 'green'), "\r" => '']);
520 $this->cWrite('green', $subPart);
521 }
522 }
523 }
524 $this->cWrite('default', "\n");
525 }
526 /**
527 * Parses the list of arguments.
528 */
529 protected function parseArguments(array $argv)
530 {
531 $positional = [];
532 $options = [];
533 for ($ii = 0; $ii < count($argv); ++$ii) {
534 // Skipping the first argument.
535 if (0 === $ii) {
536 continue;
537 }
538 $v = $argv[$ii];
539 if ('--' === substr($v, 0, 2)) {
540 // This is a long-form option.
541 $optionName = substr($v, 2);
542 $optionValue = true;
543 if (strpos($optionName, '=')) {
544 list($optionName, $optionValue) = explode('=', $optionName);
545 }
546 $options[$optionName] = $optionValue;
547 } elseif ('-' === substr($v, 0, 1) && strlen($v) > 1) {
548 // This is a short-form option.
549 foreach (str_split(substr($v, 1)) as $option) {
550 $options[$option] = true;
551 }
552 } else {
553 $positional[] = $v;
554 }
555 }
556 return [$options, $positional];
557 }
558 protected $parser;
559 /**
560 * Reads the input file.
561 *
562 * @return Component
563 */
564 protected function readInput()
565 {
566 if (!$this->parser) {
567 if ('-' !== $this->inputPath) {
568 $this->stdin = fopen($this->inputPath, 'r');
569 }
570 if ('mimedir' === $this->inputFormat) {
571 $this->parser = new Parser\MimeDir($this->stdin, $this->forgiving ? Reader::OPTION_FORGIVING : 0);
572 } else {
573 $this->parser = new Parser\Json($this->stdin, $this->forgiving ? Reader::OPTION_FORGIVING : 0);
574 }
575 }
576 return $this->parser->parse();
577 }
578 /**
579 * Sends a message to STDERR.
580 *
581 * @param string $msg
582 */
583 protected function log($msg, $color = 'default')
584 {
585 if (!$this->quiet) {
586 if ('default' !== $color) {
587 $msg = $this->colorize($color, $msg);
588 }
589 fwrite($this->stderr, $msg . "\n");
590 }
591 }
592 }