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 / Property.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
Property.php
643 lines
1 <?php
2
3 namespace AmeliaVendor\Sabre\VObject;
4
5 use AmeliaVendor\Sabre\Xml;
6
7 /**
8 * Property.
9 *
10 * A property is always in a KEY:VALUE structure, and may optionally contain
11 * parameters.
12 *
13 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
14 * @author Evert Pot (http://evertpot.com/)
15 * @license http://sabre.io/license/ Modified BSD License
16 */
17 abstract class Property extends Node
18 {
19 /**
20 * Property name.
21 *
22 * This will contain a string such as DTSTART, SUMMARY, FN.
23 *
24 * @var string
25 */
26 public $name;
27
28 /**
29 * Property group.
30 *
31 * This is only used in vcards
32 *
33 * @var string|null
34 */
35 public $group;
36
37 /**
38 * List of parameters.
39 *
40 * @var array
41 */
42 public $parameters = [];
43
44 /**
45 * Current value.
46 *
47 * @var mixed
48 */
49 protected $value;
50
51 /**
52 * In case this is a multi-value property. This string will be used as a
53 * delimiter.
54 *
55 * @var string
56 */
57 public $delimiter = ';';
58
59 /**
60 * The line number in the original iCalendar / vCard file
61 * that corresponds with the current node
62 * if the node was read from a file.
63 */
64 public $lineIndex;
65
66 /**
67 * The line string from the original iCalendar / vCard file
68 * that corresponds with the current node
69 * if the node was read from a file.
70 */
71 public $lineString;
72
73 /**
74 * Creates the generic property.
75 *
76 * Parameters must be specified in key=>value syntax.
77 *
78 * @param Component $root The root document
79 * @param string $name
80 * @param string|array|null $value
81 * @param array $parameters List of parameters
82 * @param string $group The vcard property group
83 */
84 public function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null, ?int $lineIndex = null, ?string $lineString = null)
85 {
86 $this->name = $name;
87 $this->group = $group;
88
89 $this->root = $root;
90
91 foreach ($parameters as $k => $v) {
92 $this->add($k, $v);
93 }
94
95 if (!is_null($value)) {
96 $this->setValue($value);
97 }
98
99 if (!is_null($lineIndex)) {
100 $this->lineIndex = $lineIndex;
101 }
102
103 if (!is_null($lineString)) {
104 $this->lineString = $lineString;
105 }
106 }
107
108 /**
109 * Updates the current value.
110 *
111 * This may be either a single, or multiple strings in an array.
112 *
113 * @param string|array $value
114 */
115 public function setValue($value)
116 {
117 $this->value = $value;
118 }
119
120 /**
121 * Returns the current value.
122 *
123 * This method will always return a singular value. If this was a
124 * multi-value object, some decision will be made first on how to represent
125 * it as a string.
126 *
127 * To get the correct multi-value version, use getParts.
128 *
129 * @return string
130 */
131 public function getValue()
132 {
133 if (is_array($this->value)) {
134 if (0 == count($this->value)) {
135 return;
136 } elseif (1 === count($this->value)) {
137 return $this->value[0];
138 } else {
139 return $this->getRawMimeDirValue();
140 }
141 } else {
142 return $this->value;
143 }
144 }
145
146 /**
147 * Sets a multi-valued property.
148 */
149 public function setParts(array $parts)
150 {
151 $this->value = $parts;
152 }
153
154 /**
155 * Returns a multi-valued property.
156 *
157 * This method always returns an array, if there was only a single value,
158 * it will still be wrapped in an array.
159 *
160 * @return array
161 */
162 public function getParts()
163 {
164 if (is_null($this->value)) {
165 return [];
166 } elseif (is_array($this->value)) {
167 return $this->value;
168 } else {
169 return [$this->value];
170 }
171 }
172
173 /**
174 * Adds a new parameter.
175 *
176 * If a parameter with same name already existed, the values will be
177 * combined.
178 * If nameless parameter is added, we try to guess its name.
179 *
180 * @param string $name
181 * @param string|array|null $value
182 */
183 public function add($name, $value = null)
184 {
185 $noName = false;
186 if (null === $name) {
187 $name = Parameter::guessParameterNameByValue($value);
188 $noName = true;
189 }
190
191 if (isset($this->parameters[strtoupper($name)])) {
192 $this->parameters[strtoupper($name)]->addValue($value);
193 } else {
194 $param = new Parameter($this->root, $name, $value);
195 $param->noName = $noName;
196 $this->parameters[$param->name] = $param;
197 }
198 }
199
200 /**
201 * Returns an iterable list of children.
202 *
203 * @return array
204 */
205 public function parameters()
206 {
207 return $this->parameters;
208 }
209
210 /**
211 * Returns the type of value.
212 *
213 * This corresponds to the VALUE= parameter. Every property also has a
214 * 'default' valueType.
215 *
216 * @return string
217 */
218 abstract public function getValueType();
219
220 /**
221 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
222 *
223 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
224 * not yet done, but parameters are not included.
225 *
226 * @param string $val
227 */
228 abstract public function setRawMimeDirValue($val);
229
230 /**
231 * Returns a raw mime-dir representation of the value.
232 *
233 * @return string
234 */
235 abstract public function getRawMimeDirValue();
236
237 /**
238 * Turns the object back into a serialized blob.
239 *
240 * @return string
241 */
242 public function serialize()
243 {
244 $str = $this->name;
245 if ($this->group) {
246 $str = $this->group.'.'.$this->name;
247 }
248
249 foreach ($this->parameters() as $param) {
250 $str .= ';'.$param->serialize();
251 }
252
253 $str .= ':'.$this->getRawMimeDirValue();
254
255 $str = \preg_replace(
256 '/(
257 (?:^.)? # 1 additional byte in first line because of missing single space (see next line)
258 .{1,74} # max 75 bytes per line (1 byte is used for a single space added after every CRLF)
259 (?![\x80-\xbf]) # prevent splitting multibyte characters
260 )/x',
261 "$1\r\n ",
262 $str
263 );
264
265 // remove single space after last CRLF
266 return \substr($str, 0, -1);
267 }
268
269 /**
270 * Returns the value, in the format it should be encoded for JSON.
271 *
272 * This method must always return an array.
273 *
274 * @return array
275 */
276 public function getJsonValue()
277 {
278 return $this->getParts();
279 }
280
281 /**
282 * Sets the JSON value, as it would appear in a jCard or jCal object.
283 *
284 * The value must always be an array.
285 */
286 public function setJsonValue(array $value)
287 {
288 if (1 === count($value)) {
289 $this->setValue(reset($value));
290 } else {
291 $this->setValue($value);
292 }
293 }
294
295 /**
296 * This method returns an array, with the representation as it should be
297 * encoded in JSON. This is used to create jCard or jCal documents.
298 *
299 * @return array
300 */
301 #[\ReturnTypeWillChange]
302 public function jsonSerialize()
303 {
304 $parameters = [];
305
306 foreach ($this->parameters as $parameter) {
307 if ('VALUE' === $parameter->name) {
308 continue;
309 }
310 $parameters[strtolower($parameter->name)] = $parameter->jsonSerialize();
311 }
312 // In jCard, we need to encode the property-group as a separate 'group'
313 // parameter.
314 if ($this->group) {
315 $parameters['group'] = $this->group;
316 }
317
318 return array_merge(
319 [
320 strtolower($this->name),
321 (object) $parameters,
322 strtolower($this->getValueType()),
323 ],
324 $this->getJsonValue()
325 );
326 }
327
328 /**
329 * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
330 * object.
331 */
332 public function setXmlValue(array $value)
333 {
334 $this->setJsonValue($value);
335 }
336
337 /**
338 * This method serializes the data into XML. This is used to create xCard or
339 * xCal documents.
340 *
341 * @param Xml\Writer $writer XML writer
342 */
343 public function xmlSerialize(Xml\Writer $writer): void
344 {
345 $parameters = [];
346
347 foreach ($this->parameters as $parameter) {
348 if ('VALUE' === $parameter->name) {
349 continue;
350 }
351
352 $parameters[] = $parameter;
353 }
354
355 $writer->startElement(strtolower($this->name));
356
357 if (!empty($parameters)) {
358 $writer->startElement('parameters');
359
360 foreach ($parameters as $parameter) {
361 $writer->startElement(strtolower($parameter->name));
362 $writer->write($parameter);
363 $writer->endElement();
364 }
365
366 $writer->endElement();
367 }
368
369 $this->xmlSerializeValue($writer);
370 $writer->endElement();
371 }
372
373 /**
374 * This method serializes only the value of a property. This is used to
375 * create xCard or xCal documents.
376 *
377 * @param Xml\Writer $writer XML writer
378 */
379 protected function xmlSerializeValue(Xml\Writer $writer)
380 {
381 $valueType = strtolower($this->getValueType());
382
383 foreach ($this->getJsonValue() as $values) {
384 foreach ((array) $values as $value) {
385 $writer->writeElement($valueType, $value);
386 }
387 }
388 }
389
390 /**
391 * Called when this object is being cast to a string.
392 *
393 * If the property only had a single value, you will get just that. In the
394 * case the property had multiple values, the contents will be escaped and
395 * combined with ,.
396 *
397 * @return string
398 */
399 public function __toString()
400 {
401 return (string) $this->getValue();
402 }
403
404 /* ArrayAccess interface {{{ */
405
406 /**
407 * Checks if an array element exists.
408 *
409 * @param mixed $name
410 *
411 * @return bool
412 */
413 #[\ReturnTypeWillChange]
414 public function offsetExists($name)
415 {
416 if (is_int($name)) {
417 return parent::offsetExists($name);
418 }
419
420 $name = strtoupper($name);
421
422 foreach ($this->parameters as $parameter) {
423 if ($parameter->name == $name) {
424 return true;
425 }
426 }
427
428 return false;
429 }
430
431 /**
432 * Returns a parameter.
433 *
434 * If the parameter does not exist, null is returned.
435 *
436 * @param string $name
437 *
438 * @return Node
439 */
440 #[\ReturnTypeWillChange]
441 public function offsetGet($name)
442 {
443 if (is_int($name)) {
444 return parent::offsetGet($name);
445 }
446 $name = strtoupper($name);
447
448 if (!isset($this->parameters[$name])) {
449 return;
450 }
451
452 return $this->parameters[$name];
453 }
454
455 /**
456 * Creates a new parameter.
457 *
458 * @param string $name
459 * @param mixed $value
460 */
461 #[\ReturnTypeWillChange]
462 public function offsetSet($name, $value)
463 {
464 if (is_int($name)) {
465 parent::offsetSet($name, $value);
466 // @codeCoverageIgnoreStart
467 // This will never be reached, because an exception is always
468 // thrown.
469 return;
470 // @codeCoverageIgnoreEnd
471 }
472
473 $param = new Parameter($this->root, $name, $value);
474 $this->parameters[$param->name] = $param;
475 }
476
477 /**
478 * Removes one or more parameters with the specified name.
479 *
480 * @param string $name
481 */
482 #[\ReturnTypeWillChange]
483 public function offsetUnset($name)
484 {
485 if (is_int($name)) {
486 parent::offsetUnset($name);
487 // @codeCoverageIgnoreStart
488 // This will never be reached, because an exception is always
489 // thrown.
490 return;
491 // @codeCoverageIgnoreEnd
492 }
493
494 unset($this->parameters[strtoupper($name)]);
495 }
496
497 /* }}} */
498
499 /**
500 * This method is automatically called when the object is cloned.
501 * Specifically, this will ensure all child elements are also cloned.
502 */
503 public function __clone()
504 {
505 foreach ($this->parameters as $key => $child) {
506 $this->parameters[$key] = clone $child;
507 $this->parameters[$key]->parent = $this;
508 }
509 }
510
511 /**
512 * Validates the node for correctness.
513 *
514 * The following options are supported:
515 * - Node::REPAIR - If something is broken, and automatic repair may
516 * be attempted.
517 *
518 * An array is returned with warnings.
519 *
520 * Every item in the array has the following properties:
521 * * level - (number between 1 and 3 with severity information)
522 * * message - (human readable message)
523 * * node - (reference to the offending node)
524 *
525 * @param int $options
526 *
527 * @return array
528 */
529 public function validate($options = 0)
530 {
531 $warnings = [];
532
533 // Checking if our value is UTF-8
534 if (!StringUtil::isUTF8($this->getRawMimeDirValue())) {
535 $oldValue = $this->getRawMimeDirValue();
536 $level = 3;
537 if ($options & self::REPAIR) {
538 $newValue = StringUtil::convertToUTF8($oldValue);
539 if (true || StringUtil::isUTF8($newValue)) {
540 $this->setRawMimeDirValue($newValue);
541 $level = 1;
542 }
543 }
544
545 if (preg_match('%([\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])%', $oldValue, $matches)) {
546 $message = 'Property contained a control character (0x'.bin2hex($matches[1]).')';
547 } else {
548 $message = 'Property is not valid UTF-8! '.$oldValue;
549 }
550
551 $warnings[] = [
552 'level' => $level,
553 'message' => $message,
554 'node' => $this,
555 ];
556 }
557
558 // Checking if the propertyname does not contain any invalid bytes.
559 if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) {
560 $warnings[] = [
561 'level' => $options & self::REPAIR ? 1 : 3,
562 'message' => 'The propertyname: '.$this->name.' contains invalid characters. Only A-Z, 0-9 and - are allowed',
563 'node' => $this,
564 ];
565 if ($options & self::REPAIR) {
566 // Uppercasing and converting underscores to dashes.
567 $this->name = strtoupper(
568 str_replace('_', '-', $this->name)
569 );
570 // Removing every other invalid character
571 $this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name);
572 }
573 }
574
575 if ($encoding = $this->offsetGet('ENCODING')) {
576 if (Document::VCARD40 === $this->root->getDocumentType()) {
577 $warnings[] = [
578 'level' => 3,
579 'message' => 'ENCODING parameter is not valid in vCard 4.',
580 'node' => $this,
581 ];
582 } else {
583 $encoding = (string) $encoding;
584
585 $allowedEncoding = [];
586
587 switch ($this->root->getDocumentType()) {
588 case Document::ICALENDAR20:
589 $allowedEncoding = ['8BIT', 'BASE64'];
590 break;
591 case Document::VCARD21:
592 $allowedEncoding = ['QUOTED-PRINTABLE', 'BASE64', '8BIT'];
593 break;
594 case Document::VCARD30:
595 $allowedEncoding = ['B'];
596 //Repair vCard30 that use BASE64 encoding
597 if ($options & self::REPAIR) {
598 if ('BASE64' === strtoupper($encoding)) {
599 $encoding = 'B';
600 $this['ENCODING'] = $encoding;
601 $warnings[] = [
602 'level' => 1,
603 'message' => 'ENCODING=BASE64 has been transformed to ENCODING=B.',
604 'node' => $this,
605 ];
606 }
607 }
608 break;
609 }
610 if ($allowedEncoding && !in_array(strtoupper($encoding), $allowedEncoding)) {
611 $warnings[] = [
612 'level' => 3,
613 'message' => 'ENCODING='.strtoupper($encoding).' is not valid for this document type.',
614 'node' => $this,
615 ];
616 }
617 }
618 }
619
620 // Validating inner parameters
621 foreach ($this->parameters as $param) {
622 $warnings = array_merge($warnings, $param->validate($options));
623 }
624
625 return $warnings;
626 }
627
628 /**
629 * Call this method on a document if you're done using it.
630 *
631 * It's intended to remove all circular references, so PHP can easily clean
632 * it up.
633 */
634 public function destroy()
635 {
636 parent::destroy();
637 foreach ($this->parameters as $param) {
638 $param->destroy();
639 }
640 $this->parameters = [];
641 }
642 }
643