Completed
Branch develop (cec3a6)
by
unknown
19:26
created
htdocs/includes/sabre/sabre/vobject/lib/Property/VCard/PhoneNumber.php 1 patch
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -13,18 +13,18 @@
 block discarded – undo
13 13
  */
14 14
 class PhoneNumber extends Property\Text
15 15
 {
16
-    protected $structuredValues = [];
16
+	protected $structuredValues = [];
17 17
 
18
-    /**
19
-     * Returns the type of value.
20
-     *
21
-     * This corresponds to the VALUE= parameter. Every property also has a
22
-     * 'default' valueType.
23
-     *
24
-     * @return string
25
-     */
26
-    public function getValueType()
27
-    {
28
-        return 'PHONE-NUMBER';
29
-    }
18
+	/**
19
+	 * Returns the type of value.
20
+	 *
21
+	 * This corresponds to the VALUE= parameter. Every property also has a
22
+	 * 'default' valueType.
23
+	 *
24
+	 * @return string
25
+	 */
26
+	public function getValueType()
27
+	{
28
+		return 'PHONE-NUMBER';
29
+	}
30 30
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Property/VCard/LanguageTag.php 1 patch
Indentation   +33 added lines, -33 removed lines patch added patch discarded remove patch
@@ -15,39 +15,39 @@
 block discarded – undo
15 15
  */
16 16
 class LanguageTag extends Property
17 17
 {
18
-    /**
19
-     * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
20
-     *
21
-     * This has been 'unfolded', so only 1 line will be passed. Unescaping is
22
-     * not yet done, but parameters are not included.
23
-     *
24
-     * @param string $val
25
-     */
26
-    public function setRawMimeDirValue($val)
27
-    {
28
-        $this->setValue($val);
29
-    }
18
+	/**
19
+	 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
20
+	 *
21
+	 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
22
+	 * not yet done, but parameters are not included.
23
+	 *
24
+	 * @param string $val
25
+	 */
26
+	public function setRawMimeDirValue($val)
27
+	{
28
+		$this->setValue($val);
29
+	}
30 30
 
31
-    /**
32
-     * Returns a raw mime-dir representation of the value.
33
-     *
34
-     * @return string
35
-     */
36
-    public function getRawMimeDirValue()
37
-    {
38
-        return $this->getValue();
39
-    }
31
+	/**
32
+	 * Returns a raw mime-dir representation of the value.
33
+	 *
34
+	 * @return string
35
+	 */
36
+	public function getRawMimeDirValue()
37
+	{
38
+		return $this->getValue();
39
+	}
40 40
 
41
-    /**
42
-     * Returns the type of value.
43
-     *
44
-     * This corresponds to the VALUE= parameter. Every property also has a
45
-     * 'default' valueType.
46
-     *
47
-     * @return string
48
-     */
49
-    public function getValueType()
50
-    {
51
-        return 'LANGUAGE-TAG';
52
-    }
41
+	/**
42
+	 * Returns the type of value.
43
+	 *
44
+	 * This corresponds to the VALUE= parameter. Every property also has a
45
+	 * 'default' valueType.
46
+	 *
47
+	 * @return string
48
+	 */
49
+	public function getValueType()
50
+	{
51
+		return 'LANGUAGE-TAG';
52
+	}
53 53
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Property/VCard/DateTime.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -13,16 +13,16 @@
 block discarded – undo
13 13
  */
14 14
 class DateTime extends DateAndOrTime
15 15
 {
16
-    /**
17
-     * Returns the type of value.
18
-     *
19
-     * This corresponds to the VALUE= parameter. Every property also has a
20
-     * 'default' valueType.
21
-     *
22
-     * @return string
23
-     */
24
-    public function getValueType()
25
-    {
26
-        return 'DATE-TIME';
27
-    }
16
+	/**
17
+	 * Returns the type of value.
18
+	 *
19
+	 * This corresponds to the VALUE= parameter. Every property also has a
20
+	 * 'default' valueType.
21
+	 *
22
+	 * @return string
23
+	 */
24
+	public function getValueType()
25
+	{
26
+		return 'DATE-TIME';
27
+	}
28 28
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Property/FlatText.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -24,23 +24,23 @@
 block discarded – undo
24 24
  */
25 25
 class FlatText extends Text
26 26
 {
27
-    /**
28
-     * Field separator.
29
-     *
30
-     * @var string
31
-     */
32
-    public $delimiter = ',';
27
+	/**
28
+	 * Field separator.
29
+	 *
30
+	 * @var string
31
+	 */
32
+	public $delimiter = ',';
33 33
 
34
-    /**
35
-     * Sets the value as a quoted-printable encoded string.
36
-     *
37
-     * Overriding this so we're not splitting on a ; delimiter.
38
-     *
39
-     * @param string $val
40
-     */
41
-    public function setQuotedPrintableValue($val)
42
-    {
43
-        $val = quoted_printable_decode($val);
44
-        $this->setValue($val);
45
-    }
34
+	/**
35
+	 * Sets the value as a quoted-printable encoded string.
36
+	 *
37
+	 * Overriding this so we're not splitting on a ; delimiter.
38
+	 *
39
+	 * @param string $val
40
+	 */
41
+	public function setQuotedPrintableValue($val)
42
+	{
43
+		$val = quoted_printable_decode($val);
44
+		$this->setValue($val);
45
+	}
46 46
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Property/FloatValue.php 1 patch
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -17,108 +17,108 @@
 block discarded – undo
17 17
  */
18 18
 class FloatValue extends Property
19 19
 {
20
-    /**
21
-     * In case this is a multi-value property. This string will be used as a
22
-     * delimiter.
23
-     *
24
-     * @var string
25
-     */
26
-    public $delimiter = ';';
20
+	/**
21
+	 * In case this is a multi-value property. This string will be used as a
22
+	 * delimiter.
23
+	 *
24
+	 * @var string
25
+	 */
26
+	public $delimiter = ';';
27 27
 
28
-    /**
29
-     * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
30
-     *
31
-     * This has been 'unfolded', so only 1 line will be passed. Unescaping is
32
-     * not yet done, but parameters are not included.
33
-     *
34
-     * @param string $val
35
-     */
36
-    public function setRawMimeDirValue($val)
37
-    {
38
-        $val = explode($this->delimiter, $val);
39
-        foreach ($val as &$item) {
40
-            $item = (float) $item;
41
-        }
42
-        $this->setParts($val);
43
-    }
28
+	/**
29
+	 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
30
+	 *
31
+	 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
32
+	 * not yet done, but parameters are not included.
33
+	 *
34
+	 * @param string $val
35
+	 */
36
+	public function setRawMimeDirValue($val)
37
+	{
38
+		$val = explode($this->delimiter, $val);
39
+		foreach ($val as &$item) {
40
+			$item = (float) $item;
41
+		}
42
+		$this->setParts($val);
43
+	}
44 44
 
45
-    /**
46
-     * Returns a raw mime-dir representation of the value.
47
-     *
48
-     * @return string
49
-     */
50
-    public function getRawMimeDirValue()
51
-    {
52
-        return implode(
53
-            $this->delimiter,
54
-            $this->getParts()
55
-        );
56
-    }
45
+	/**
46
+	 * Returns a raw mime-dir representation of the value.
47
+	 *
48
+	 * @return string
49
+	 */
50
+	public function getRawMimeDirValue()
51
+	{
52
+		return implode(
53
+			$this->delimiter,
54
+			$this->getParts()
55
+		);
56
+	}
57 57
 
58
-    /**
59
-     * Returns the type of value.
60
-     *
61
-     * This corresponds to the VALUE= parameter. Every property also has a
62
-     * 'default' valueType.
63
-     *
64
-     * @return string
65
-     */
66
-    public function getValueType()
67
-    {
68
-        return 'FLOAT';
69
-    }
58
+	/**
59
+	 * Returns the type of value.
60
+	 *
61
+	 * This corresponds to the VALUE= parameter. Every property also has a
62
+	 * 'default' valueType.
63
+	 *
64
+	 * @return string
65
+	 */
66
+	public function getValueType()
67
+	{
68
+		return 'FLOAT';
69
+	}
70 70
 
71
-    /**
72
-     * Returns the value, in the format it should be encoded for JSON.
73
-     *
74
-     * This method must always return an array.
75
-     *
76
-     * @return array
77
-     */
78
-    public function getJsonValue()
79
-    {
80
-        $val = array_map('floatval', $this->getParts());
71
+	/**
72
+	 * Returns the value, in the format it should be encoded for JSON.
73
+	 *
74
+	 * This method must always return an array.
75
+	 *
76
+	 * @return array
77
+	 */
78
+	public function getJsonValue()
79
+	{
80
+		$val = array_map('floatval', $this->getParts());
81 81
 
82
-        // Special-casing the GEO property.
83
-        //
84
-        // See:
85
-        // http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
86
-        if ('GEO' === $this->name) {
87
-            return [$val];
88
-        }
82
+		// Special-casing the GEO property.
83
+		//
84
+		// See:
85
+		// http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
86
+		if ('GEO' === $this->name) {
87
+			return [$val];
88
+		}
89 89
 
90
-        return $val;
91
-    }
90
+		return $val;
91
+	}
92 92
 
93
-    /**
94
-     * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
95
-     * object.
96
-     */
97
-    public function setXmlValue(array $value)
98
-    {
99
-        $value = array_map('floatval', $value);
100
-        parent::setXmlValue($value);
101
-    }
93
+	/**
94
+	 * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
95
+	 * object.
96
+	 */
97
+	public function setXmlValue(array $value)
98
+	{
99
+		$value = array_map('floatval', $value);
100
+		parent::setXmlValue($value);
101
+	}
102 102
 
103
-    /**
104
-     * This method serializes only the value of a property. This is used to
105
-     * create xCard or xCal documents.
106
-     *
107
-     * @param Xml\Writer $writer XML writer
108
-     */
109
-    protected function xmlSerializeValue(Xml\Writer $writer)
110
-    {
111
-        // Special-casing the GEO property.
112
-        //
113
-        // See:
114
-        // http://tools.ietf.org/html/rfc6321#section-3.4.1.2
115
-        if ('GEO' === $this->name) {
116
-            $value = array_map('floatval', $this->getParts());
103
+	/**
104
+	 * This method serializes only the value of a property. This is used to
105
+	 * create xCard or xCal documents.
106
+	 *
107
+	 * @param Xml\Writer $writer XML writer
108
+	 */
109
+	protected function xmlSerializeValue(Xml\Writer $writer)
110
+	{
111
+		// Special-casing the GEO property.
112
+		//
113
+		// See:
114
+		// http://tools.ietf.org/html/rfc6321#section-3.4.1.2
115
+		if ('GEO' === $this->name) {
116
+			$value = array_map('floatval', $this->getParts());
117 117
 
118
-            $writer->writeElement('latitude', $value[0]);
119
-            $writer->writeElement('longitude', $value[1]);
120
-        } else {
121
-            parent::xmlSerializeValue($writer);
122
-        }
123
-    }
118
+			$writer->writeElement('latitude', $value[0]);
119
+			$writer->writeElement('longitude', $value[1]);
120
+		} else {
121
+			parent::xmlSerializeValue($writer);
122
+		}
123
+	}
124 124
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/XML.php 1 patch
Indentation   +354 added lines, -354 removed lines patch added patch discarded remove patch
@@ -20,358 +20,358 @@
 block discarded – undo
20 20
  */
21 21
 class XML extends Parser
22 22
 {
23
-    const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
24
-    const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
25
-
26
-    /**
27
-     * The input data.
28
-     *
29
-     * @var array
30
-     */
31
-    protected $input;
32
-
33
-    /**
34
-     * A pointer/reference to the input.
35
-     *
36
-     * @var array
37
-     */
38
-    private $pointer;
39
-
40
-    /**
41
-     * Document, root component.
42
-     *
43
-     * @var \Sabre\VObject\Document
44
-     */
45
-    protected $root;
46
-
47
-    /**
48
-     * Creates the parser.
49
-     *
50
-     * Optionally, it's possible to parse the input stream here.
51
-     *
52
-     * @param mixed $input
53
-     * @param int   $options any parser options (OPTION constants)
54
-     */
55
-    public function __construct($input = null, $options = 0)
56
-    {
57
-        if (0 === $options) {
58
-            $options = parent::OPTION_FORGIVING;
59
-        }
60
-
61
-        parent::__construct($input, $options);
62
-    }
63
-
64
-    /**
65
-     * Parse xCal or xCard.
66
-     *
67
-     * @param resource|string $input
68
-     * @param int             $options
69
-     *
70
-     * @throws \Exception
71
-     *
72
-     * @return \Sabre\VObject\Document
73
-     */
74
-    public function parse($input = null, $options = 0)
75
-    {
76
-        if (!is_null($input)) {
77
-            $this->setInput($input);
78
-        }
79
-
80
-        if (0 !== $options) {
81
-            $this->options = $options;
82
-        }
83
-
84
-        if (is_null($this->input)) {
85
-            throw new EofException('End of input stream, or no input supplied');
86
-        }
87
-
88
-        switch ($this->input['name']) {
89
-            case '{'.self::XCAL_NAMESPACE.'}icalendar':
90
-                $this->root = new VCalendar([], false);
91
-                $this->pointer = &$this->input['value'][0];
92
-                $this->parseVCalendarComponents($this->root);
93
-                break;
94
-
95
-            case '{'.self::XCARD_NAMESPACE.'}vcards':
96
-                foreach ($this->input['value'] as &$vCard) {
97
-                    $this->root = new VCard(['version' => '4.0'], false);
98
-                    $this->pointer = &$vCard;
99
-                    $this->parseVCardComponents($this->root);
100
-
101
-                    // We just parse the first <vcard /> element.
102
-                    break;
103
-                }
104
-                break;
105
-
106
-            default:
107
-                throw new ParseException('Unsupported XML standard');
108
-        }
109
-
110
-        return $this->root;
111
-    }
112
-
113
-    /**
114
-     * Parse a xCalendar component.
115
-     */
116
-    protected function parseVCalendarComponents(Component $parentComponent)
117
-    {
118
-        foreach ($this->pointer['value'] ?: [] as $children) {
119
-            switch (static::getTagName($children['name'])) {
120
-                case 'properties':
121
-                    $this->pointer = &$children['value'];
122
-                    $this->parseProperties($parentComponent);
123
-                    break;
124
-
125
-                case 'components':
126
-                    $this->pointer = &$children;
127
-                    $this->parseComponent($parentComponent);
128
-                    break;
129
-            }
130
-        }
131
-    }
132
-
133
-    /**
134
-     * Parse a xCard component.
135
-     */
136
-    protected function parseVCardComponents(Component $parentComponent)
137
-    {
138
-        $this->pointer = &$this->pointer['value'];
139
-        $this->parseProperties($parentComponent);
140
-    }
141
-
142
-    /**
143
-     * Parse xCalendar and xCard properties.
144
-     *
145
-     * @param string $propertyNamePrefix
146
-     */
147
-    protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '')
148
-    {
149
-        foreach ($this->pointer ?: [] as $xmlProperty) {
150
-            list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
151
-
152
-            $propertyName = $tagName;
153
-            $propertyValue = [];
154
-            $propertyParameters = [];
155
-            $propertyType = 'text';
156
-
157
-            // A property which is not part of the standard.
158
-            if (self::XCAL_NAMESPACE !== $namespace
159
-                && self::XCARD_NAMESPACE !== $namespace) {
160
-                $propertyName = 'xml';
161
-                $value = '<'.$tagName.' xmlns="'.$namespace.'"';
162
-
163
-                foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
164
-                    $value .= ' '.$attributeName.'="'.str_replace('"', '\"', $attributeValue).'"';
165
-                }
166
-
167
-                $value .= '>'.$xmlProperty['value'].'</'.$tagName.'>';
168
-
169
-                $propertyValue = [$value];
170
-
171
-                $this->createProperty(
172
-                    $parentComponent,
173
-                    $propertyName,
174
-                    $propertyParameters,
175
-                    $propertyType,
176
-                    $propertyValue
177
-                );
178
-
179
-                continue;
180
-            }
181
-
182
-            // xCard group.
183
-            if ('group' === $propertyName) {
184
-                if (!isset($xmlProperty['attributes']['name'])) {
185
-                    continue;
186
-                }
187
-
188
-                $this->pointer = &$xmlProperty['value'];
189
-                $this->parseProperties(
190
-                    $parentComponent,
191
-                    strtoupper($xmlProperty['attributes']['name']).'.'
192
-                );
193
-
194
-                continue;
195
-            }
196
-
197
-            // Collect parameters.
198
-            foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
199
-                if (!is_array($xmlPropertyChild)
200
-                    || 'parameters' !== static::getTagName($xmlPropertyChild['name'])) {
201
-                    continue;
202
-                }
203
-
204
-                $xmlParameters = $xmlPropertyChild['value'];
205
-
206
-                foreach ($xmlParameters as $xmlParameter) {
207
-                    $propertyParameterValues = [];
208
-
209
-                    foreach ($xmlParameter['value'] as $xmlParameterValues) {
210
-                        $propertyParameterValues[] = $xmlParameterValues['value'];
211
-                    }
212
-
213
-                    $propertyParameters[static::getTagName($xmlParameter['name'])]
214
-                        = implode(',', $propertyParameterValues);
215
-                }
216
-
217
-                array_splice($xmlProperty['value'], $i, 1);
218
-            }
219
-
220
-            $propertyNameExtended = ($this->root instanceof VCalendar
221
-                                      ? 'xcal'
222
-                                      : 'xcard').':'.$propertyName;
223
-
224
-            switch ($propertyNameExtended) {
225
-                case 'xcal:geo':
226
-                    $propertyType = 'float';
227
-                    $propertyValue['latitude'] = 0;
228
-                    $propertyValue['longitude'] = 0;
229
-
230
-                    foreach ($xmlProperty['value'] as $xmlRequestChild) {
231
-                        $propertyValue[static::getTagName($xmlRequestChild['name'])]
232
-                            = $xmlRequestChild['value'];
233
-                    }
234
-                    break;
235
-
236
-                case 'xcal:request-status':
237
-                    $propertyType = 'text';
238
-
239
-                    foreach ($xmlProperty['value'] as $xmlRequestChild) {
240
-                        $propertyValue[static::getTagName($xmlRequestChild['name'])]
241
-                            = $xmlRequestChild['value'];
242
-                    }
243
-                    break;
244
-
245
-                case 'xcal:freebusy':
246
-                    $propertyType = 'freebusy';
247
-                    // We don't break because we only want to set
248
-                    // another property type.
249
-
250
-                    // no break
251
-                case 'xcal:categories':
252
-                case 'xcal:resources':
253
-                case 'xcal:exdate':
254
-                    foreach ($xmlProperty['value'] as $specialChild) {
255
-                        $propertyValue[static::getTagName($specialChild['name'])]
256
-                            = $specialChild['value'];
257
-                    }
258
-                    break;
259
-
260
-                case 'xcal:rdate':
261
-                    $propertyType = 'date-time';
262
-
263
-                    foreach ($xmlProperty['value'] as $specialChild) {
264
-                        $tagName = static::getTagName($specialChild['name']);
265
-
266
-                        if ('period' === $tagName) {
267
-                            $propertyParameters['value'] = 'PERIOD';
268
-                            $propertyValue[] = implode('/', $specialChild['value']);
269
-                        } else {
270
-                            $propertyValue[] = $specialChild['value'];
271
-                        }
272
-                    }
273
-                    break;
274
-
275
-                default:
276
-                    $propertyType = static::getTagName($xmlProperty['value'][0]['name']);
277
-
278
-                    foreach ($xmlProperty['value'] as $value) {
279
-                        $propertyValue[] = $value['value'];
280
-                    }
281
-
282
-                    if ('date' === $propertyType) {
283
-                        $propertyParameters['value'] = 'DATE';
284
-                    }
285
-                    break;
286
-            }
287
-
288
-            $this->createProperty(
289
-                $parentComponent,
290
-                $propertyNamePrefix.$propertyName,
291
-                $propertyParameters,
292
-                $propertyType,
293
-                $propertyValue
294
-            );
295
-        }
296
-    }
297
-
298
-    /**
299
-     * Parse a component.
300
-     */
301
-    protected function parseComponent(Component $parentComponent)
302
-    {
303
-        $components = $this->pointer['value'] ?: [];
304
-
305
-        foreach ($components as $component) {
306
-            $componentName = static::getTagName($component['name']);
307
-            $currentComponent = $this->root->createComponent(
308
-                $componentName,
309
-                null,
310
-                false
311
-            );
312
-
313
-            $this->pointer = &$component;
314
-            $this->parseVCalendarComponents($currentComponent);
315
-
316
-            $parentComponent->add($currentComponent);
317
-        }
318
-    }
319
-
320
-    /**
321
-     * Create a property.
322
-     *
323
-     * @param string $name
324
-     * @param array  $parameters
325
-     * @param string $type
326
-     * @param mixed  $value
327
-     */
328
-    protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value)
329
-    {
330
-        $property = $this->root->createProperty(
331
-            $name,
332
-            null,
333
-            $parameters,
334
-            $type
335
-        );
336
-        $parentComponent->add($property);
337
-        $property->setXmlValue($value);
338
-    }
339
-
340
-    /**
341
-     * Sets the input data.
342
-     *
343
-     * @param resource|string $input
344
-     */
345
-    public function setInput($input)
346
-    {
347
-        if (is_resource($input)) {
348
-            $input = stream_get_contents($input);
349
-        }
350
-
351
-        if (is_string($input)) {
352
-            $reader = new SabreXml\Reader();
353
-            $reader->elementMap['{'.self::XCAL_NAMESPACE.'}period']
354
-                = XML\Element\KeyValue::class;
355
-            $reader->elementMap['{'.self::XCAL_NAMESPACE.'}recur']
356
-                = XML\Element\KeyValue::class;
357
-            $reader->xml($input);
358
-            $input = $reader->parse();
359
-        }
360
-
361
-        $this->input = $input;
362
-    }
363
-
364
-    /**
365
-     * Get tag name from a Clark notation.
366
-     *
367
-     * @param string $clarkedTagName
368
-     *
369
-     * @return string
370
-     */
371
-    protected static function getTagName($clarkedTagName)
372
-    {
373
-        list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
374
-
375
-        return $tagName;
376
-    }
23
+	const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
24
+	const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
25
+
26
+	/**
27
+	 * The input data.
28
+	 *
29
+	 * @var array
30
+	 */
31
+	protected $input;
32
+
33
+	/**
34
+	 * A pointer/reference to the input.
35
+	 *
36
+	 * @var array
37
+	 */
38
+	private $pointer;
39
+
40
+	/**
41
+	 * Document, root component.
42
+	 *
43
+	 * @var \Sabre\VObject\Document
44
+	 */
45
+	protected $root;
46
+
47
+	/**
48
+	 * Creates the parser.
49
+	 *
50
+	 * Optionally, it's possible to parse the input stream here.
51
+	 *
52
+	 * @param mixed $input
53
+	 * @param int   $options any parser options (OPTION constants)
54
+	 */
55
+	public function __construct($input = null, $options = 0)
56
+	{
57
+		if (0 === $options) {
58
+			$options = parent::OPTION_FORGIVING;
59
+		}
60
+
61
+		parent::__construct($input, $options);
62
+	}
63
+
64
+	/**
65
+	 * Parse xCal or xCard.
66
+	 *
67
+	 * @param resource|string $input
68
+	 * @param int             $options
69
+	 *
70
+	 * @throws \Exception
71
+	 *
72
+	 * @return \Sabre\VObject\Document
73
+	 */
74
+	public function parse($input = null, $options = 0)
75
+	{
76
+		if (!is_null($input)) {
77
+			$this->setInput($input);
78
+		}
79
+
80
+		if (0 !== $options) {
81
+			$this->options = $options;
82
+		}
83
+
84
+		if (is_null($this->input)) {
85
+			throw new EofException('End of input stream, or no input supplied');
86
+		}
87
+
88
+		switch ($this->input['name']) {
89
+			case '{'.self::XCAL_NAMESPACE.'}icalendar':
90
+				$this->root = new VCalendar([], false);
91
+				$this->pointer = &$this->input['value'][0];
92
+				$this->parseVCalendarComponents($this->root);
93
+				break;
94
+
95
+			case '{'.self::XCARD_NAMESPACE.'}vcards':
96
+				foreach ($this->input['value'] as &$vCard) {
97
+					$this->root = new VCard(['version' => '4.0'], false);
98
+					$this->pointer = &$vCard;
99
+					$this->parseVCardComponents($this->root);
100
+
101
+					// We just parse the first <vcard /> element.
102
+					break;
103
+				}
104
+				break;
105
+
106
+			default:
107
+				throw new ParseException('Unsupported XML standard');
108
+		}
109
+
110
+		return $this->root;
111
+	}
112
+
113
+	/**
114
+	 * Parse a xCalendar component.
115
+	 */
116
+	protected function parseVCalendarComponents(Component $parentComponent)
117
+	{
118
+		foreach ($this->pointer['value'] ?: [] as $children) {
119
+			switch (static::getTagName($children['name'])) {
120
+				case 'properties':
121
+					$this->pointer = &$children['value'];
122
+					$this->parseProperties($parentComponent);
123
+					break;
124
+
125
+				case 'components':
126
+					$this->pointer = &$children;
127
+					$this->parseComponent($parentComponent);
128
+					break;
129
+			}
130
+		}
131
+	}
132
+
133
+	/**
134
+	 * Parse a xCard component.
135
+	 */
136
+	protected function parseVCardComponents(Component $parentComponent)
137
+	{
138
+		$this->pointer = &$this->pointer['value'];
139
+		$this->parseProperties($parentComponent);
140
+	}
141
+
142
+	/**
143
+	 * Parse xCalendar and xCard properties.
144
+	 *
145
+	 * @param string $propertyNamePrefix
146
+	 */
147
+	protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '')
148
+	{
149
+		foreach ($this->pointer ?: [] as $xmlProperty) {
150
+			list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
151
+
152
+			$propertyName = $tagName;
153
+			$propertyValue = [];
154
+			$propertyParameters = [];
155
+			$propertyType = 'text';
156
+
157
+			// A property which is not part of the standard.
158
+			if (self::XCAL_NAMESPACE !== $namespace
159
+				&& self::XCARD_NAMESPACE !== $namespace) {
160
+				$propertyName = 'xml';
161
+				$value = '<'.$tagName.' xmlns="'.$namespace.'"';
162
+
163
+				foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
164
+					$value .= ' '.$attributeName.'="'.str_replace('"', '\"', $attributeValue).'"';
165
+				}
166
+
167
+				$value .= '>'.$xmlProperty['value'].'</'.$tagName.'>';
168
+
169
+				$propertyValue = [$value];
170
+
171
+				$this->createProperty(
172
+					$parentComponent,
173
+					$propertyName,
174
+					$propertyParameters,
175
+					$propertyType,
176
+					$propertyValue
177
+				);
178
+
179
+				continue;
180
+			}
181
+
182
+			// xCard group.
183
+			if ('group' === $propertyName) {
184
+				if (!isset($xmlProperty['attributes']['name'])) {
185
+					continue;
186
+				}
187
+
188
+				$this->pointer = &$xmlProperty['value'];
189
+				$this->parseProperties(
190
+					$parentComponent,
191
+					strtoupper($xmlProperty['attributes']['name']).'.'
192
+				);
193
+
194
+				continue;
195
+			}
196
+
197
+			// Collect parameters.
198
+			foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
199
+				if (!is_array($xmlPropertyChild)
200
+					|| 'parameters' !== static::getTagName($xmlPropertyChild['name'])) {
201
+					continue;
202
+				}
203
+
204
+				$xmlParameters = $xmlPropertyChild['value'];
205
+
206
+				foreach ($xmlParameters as $xmlParameter) {
207
+					$propertyParameterValues = [];
208
+
209
+					foreach ($xmlParameter['value'] as $xmlParameterValues) {
210
+						$propertyParameterValues[] = $xmlParameterValues['value'];
211
+					}
212
+
213
+					$propertyParameters[static::getTagName($xmlParameter['name'])]
214
+						= implode(',', $propertyParameterValues);
215
+				}
216
+
217
+				array_splice($xmlProperty['value'], $i, 1);
218
+			}
219
+
220
+			$propertyNameExtended = ($this->root instanceof VCalendar
221
+									  ? 'xcal'
222
+									  : 'xcard').':'.$propertyName;
223
+
224
+			switch ($propertyNameExtended) {
225
+				case 'xcal:geo':
226
+					$propertyType = 'float';
227
+					$propertyValue['latitude'] = 0;
228
+					$propertyValue['longitude'] = 0;
229
+
230
+					foreach ($xmlProperty['value'] as $xmlRequestChild) {
231
+						$propertyValue[static::getTagName($xmlRequestChild['name'])]
232
+							= $xmlRequestChild['value'];
233
+					}
234
+					break;
235
+
236
+				case 'xcal:request-status':
237
+					$propertyType = 'text';
238
+
239
+					foreach ($xmlProperty['value'] as $xmlRequestChild) {
240
+						$propertyValue[static::getTagName($xmlRequestChild['name'])]
241
+							= $xmlRequestChild['value'];
242
+					}
243
+					break;
244
+
245
+				case 'xcal:freebusy':
246
+					$propertyType = 'freebusy';
247
+					// We don't break because we only want to set
248
+					// another property type.
249
+
250
+					// no break
251
+				case 'xcal:categories':
252
+				case 'xcal:resources':
253
+				case 'xcal:exdate':
254
+					foreach ($xmlProperty['value'] as $specialChild) {
255
+						$propertyValue[static::getTagName($specialChild['name'])]
256
+							= $specialChild['value'];
257
+					}
258
+					break;
259
+
260
+				case 'xcal:rdate':
261
+					$propertyType = 'date-time';
262
+
263
+					foreach ($xmlProperty['value'] as $specialChild) {
264
+						$tagName = static::getTagName($specialChild['name']);
265
+
266
+						if ('period' === $tagName) {
267
+							$propertyParameters['value'] = 'PERIOD';
268
+							$propertyValue[] = implode('/', $specialChild['value']);
269
+						} else {
270
+							$propertyValue[] = $specialChild['value'];
271
+						}
272
+					}
273
+					break;
274
+
275
+				default:
276
+					$propertyType = static::getTagName($xmlProperty['value'][0]['name']);
277
+
278
+					foreach ($xmlProperty['value'] as $value) {
279
+						$propertyValue[] = $value['value'];
280
+					}
281
+
282
+					if ('date' === $propertyType) {
283
+						$propertyParameters['value'] = 'DATE';
284
+					}
285
+					break;
286
+			}
287
+
288
+			$this->createProperty(
289
+				$parentComponent,
290
+				$propertyNamePrefix.$propertyName,
291
+				$propertyParameters,
292
+				$propertyType,
293
+				$propertyValue
294
+			);
295
+		}
296
+	}
297
+
298
+	/**
299
+	 * Parse a component.
300
+	 */
301
+	protected function parseComponent(Component $parentComponent)
302
+	{
303
+		$components = $this->pointer['value'] ?: [];
304
+
305
+		foreach ($components as $component) {
306
+			$componentName = static::getTagName($component['name']);
307
+			$currentComponent = $this->root->createComponent(
308
+				$componentName,
309
+				null,
310
+				false
311
+			);
312
+
313
+			$this->pointer = &$component;
314
+			$this->parseVCalendarComponents($currentComponent);
315
+
316
+			$parentComponent->add($currentComponent);
317
+		}
318
+	}
319
+
320
+	/**
321
+	 * Create a property.
322
+	 *
323
+	 * @param string $name
324
+	 * @param array  $parameters
325
+	 * @param string $type
326
+	 * @param mixed  $value
327
+	 */
328
+	protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value)
329
+	{
330
+		$property = $this->root->createProperty(
331
+			$name,
332
+			null,
333
+			$parameters,
334
+			$type
335
+		);
336
+		$parentComponent->add($property);
337
+		$property->setXmlValue($value);
338
+	}
339
+
340
+	/**
341
+	 * Sets the input data.
342
+	 *
343
+	 * @param resource|string $input
344
+	 */
345
+	public function setInput($input)
346
+	{
347
+		if (is_resource($input)) {
348
+			$input = stream_get_contents($input);
349
+		}
350
+
351
+		if (is_string($input)) {
352
+			$reader = new SabreXml\Reader();
353
+			$reader->elementMap['{'.self::XCAL_NAMESPACE.'}period']
354
+				= XML\Element\KeyValue::class;
355
+			$reader->elementMap['{'.self::XCAL_NAMESPACE.'}recur']
356
+				= XML\Element\KeyValue::class;
357
+			$reader->xml($input);
358
+			$input = $reader->parse();
359
+		}
360
+
361
+		$this->input = $input;
362
+	}
363
+
364
+	/**
365
+	 * Get tag name from a Clark notation.
366
+	 *
367
+	 * @param string $clarkedTagName
368
+	 *
369
+	 * @return string
370
+	 */
371
+	protected static function getTagName($clarkedTagName)
372
+	{
373
+		list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
374
+
375
+		return $tagName;
376
+	}
377 377
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/Json.php 1 patch
Indentation   +166 added lines, -166 removed lines patch added patch discarded remove patch
@@ -21,170 +21,170 @@
 block discarded – undo
21 21
  */
22 22
 class Json extends Parser
23 23
 {
24
-    /**
25
-     * The input data.
26
-     *
27
-     * @var array
28
-     */
29
-    protected $input;
30
-
31
-    /**
32
-     * Root component.
33
-     *
34
-     * @var Document
35
-     */
36
-    protected $root;
37
-
38
-    /**
39
-     * This method starts the parsing process.
40
-     *
41
-     * If the input was not supplied during construction, it's possible to pass
42
-     * it here instead.
43
-     *
44
-     * If either input or options are not supplied, the defaults will be used.
45
-     *
46
-     * @param resource|string|array|null $input
47
-     * @param int                        $options
48
-     *
49
-     * @return \Sabre\VObject\Document
50
-     */
51
-    public function parse($input = null, $options = 0)
52
-    {
53
-        if (!is_null($input)) {
54
-            $this->setInput($input);
55
-        }
56
-        if (is_null($this->input)) {
57
-            throw new EofException('End of input stream, or no input supplied');
58
-        }
59
-
60
-        if (0 !== $options) {
61
-            $this->options = $options;
62
-        }
63
-
64
-        switch ($this->input[0]) {
65
-            case 'vcalendar':
66
-                $this->root = new VCalendar([], false);
67
-                break;
68
-            case 'vcard':
69
-                $this->root = new VCard([], false);
70
-                break;
71
-            default:
72
-                throw new ParseException('The root component must either be a vcalendar, or a vcard');
73
-        }
74
-        foreach ($this->input[1] as $prop) {
75
-            $this->root->add($this->parseProperty($prop));
76
-        }
77
-        if (isset($this->input[2])) {
78
-            foreach ($this->input[2] as $comp) {
79
-                $this->root->add($this->parseComponent($comp));
80
-            }
81
-        }
82
-
83
-        // Resetting the input so we can throw an feof exception the next time.
84
-        $this->input = null;
85
-
86
-        return $this->root;
87
-    }
88
-
89
-    /**
90
-     * Parses a component.
91
-     *
92
-     * @return \Sabre\VObject\Component
93
-     */
94
-    public function parseComponent(array $jComp)
95
-    {
96
-        // We can remove $self from PHP 5.4 onward.
97
-        $self = $this;
98
-
99
-        $properties = array_map(
100
-            function ($jProp) use ($self) {
101
-                return $self->parseProperty($jProp);
102
-            },
103
-            $jComp[1]
104
-        );
105
-
106
-        if (isset($jComp[2])) {
107
-            $components = array_map(
108
-                function ($jComp) use ($self) {
109
-                    return $self->parseComponent($jComp);
110
-                },
111
-                $jComp[2]
112
-            );
113
-        } else {
114
-            $components = [];
115
-        }
116
-
117
-        return $this->root->createComponent(
118
-            $jComp[0],
119
-            array_merge($properties, $components),
120
-            $defaults = false
121
-        );
122
-    }
123
-
124
-    /**
125
-     * Parses properties.
126
-     *
127
-     * @return \Sabre\VObject\Property
128
-     */
129
-    public function parseProperty(array $jProp)
130
-    {
131
-        list(
132
-            $propertyName,
133
-            $parameters,
134
-            $valueType
135
-        ) = $jProp;
136
-
137
-        $propertyName = strtoupper($propertyName);
138
-
139
-        // This is the default class we would be using if we didn't know the
140
-        // value type. We're using this value later in this function.
141
-        $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
142
-
143
-        $parameters = (array) $parameters;
144
-
145
-        $value = array_slice($jProp, 3);
146
-
147
-        $valueType = strtoupper($valueType);
148
-
149
-        if (isset($parameters['group'])) {
150
-            $propertyName = $parameters['group'].'.'.$propertyName;
151
-            unset($parameters['group']);
152
-        }
153
-
154
-        $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
155
-        $prop->setJsonValue($value);
156
-
157
-        // We have to do something awkward here. FlatText as well as Text
158
-        // represents TEXT values. We have to normalize these here. In the
159
-        // future we can get rid of FlatText once we're allowed to break BC
160
-        // again.
161
-        if (FlatText::class === $defaultPropertyClass) {
162
-            $defaultPropertyClass = Text::class;
163
-        }
164
-
165
-        // If the value type we received (e.g.: TEXT) was not the default value
166
-        // type for the given property (e.g.: BDAY), we need to add a VALUE=
167
-        // parameter.
168
-        if ($defaultPropertyClass !== get_class($prop)) {
169
-            $prop['VALUE'] = $valueType;
170
-        }
171
-
172
-        return $prop;
173
-    }
174
-
175
-    /**
176
-     * Sets the input data.
177
-     *
178
-     * @param resource|string|array $input
179
-     */
180
-    public function setInput($input)
181
-    {
182
-        if (is_resource($input)) {
183
-            $input = stream_get_contents($input);
184
-        }
185
-        if (is_string($input)) {
186
-            $input = json_decode($input);
187
-        }
188
-        $this->input = $input;
189
-    }
24
+	/**
25
+	 * The input data.
26
+	 *
27
+	 * @var array
28
+	 */
29
+	protected $input;
30
+
31
+	/**
32
+	 * Root component.
33
+	 *
34
+	 * @var Document
35
+	 */
36
+	protected $root;
37
+
38
+	/**
39
+	 * This method starts the parsing process.
40
+	 *
41
+	 * If the input was not supplied during construction, it's possible to pass
42
+	 * it here instead.
43
+	 *
44
+	 * If either input or options are not supplied, the defaults will be used.
45
+	 *
46
+	 * @param resource|string|array|null $input
47
+	 * @param int                        $options
48
+	 *
49
+	 * @return \Sabre\VObject\Document
50
+	 */
51
+	public function parse($input = null, $options = 0)
52
+	{
53
+		if (!is_null($input)) {
54
+			$this->setInput($input);
55
+		}
56
+		if (is_null($this->input)) {
57
+			throw new EofException('End of input stream, or no input supplied');
58
+		}
59
+
60
+		if (0 !== $options) {
61
+			$this->options = $options;
62
+		}
63
+
64
+		switch ($this->input[0]) {
65
+			case 'vcalendar':
66
+				$this->root = new VCalendar([], false);
67
+				break;
68
+			case 'vcard':
69
+				$this->root = new VCard([], false);
70
+				break;
71
+			default:
72
+				throw new ParseException('The root component must either be a vcalendar, or a vcard');
73
+		}
74
+		foreach ($this->input[1] as $prop) {
75
+			$this->root->add($this->parseProperty($prop));
76
+		}
77
+		if (isset($this->input[2])) {
78
+			foreach ($this->input[2] as $comp) {
79
+				$this->root->add($this->parseComponent($comp));
80
+			}
81
+		}
82
+
83
+		// Resetting the input so we can throw an feof exception the next time.
84
+		$this->input = null;
85
+
86
+		return $this->root;
87
+	}
88
+
89
+	/**
90
+	 * Parses a component.
91
+	 *
92
+	 * @return \Sabre\VObject\Component
93
+	 */
94
+	public function parseComponent(array $jComp)
95
+	{
96
+		// We can remove $self from PHP 5.4 onward.
97
+		$self = $this;
98
+
99
+		$properties = array_map(
100
+			function ($jProp) use ($self) {
101
+				return $self->parseProperty($jProp);
102
+			},
103
+			$jComp[1]
104
+		);
105
+
106
+		if (isset($jComp[2])) {
107
+			$components = array_map(
108
+				function ($jComp) use ($self) {
109
+					return $self->parseComponent($jComp);
110
+				},
111
+				$jComp[2]
112
+			);
113
+		} else {
114
+			$components = [];
115
+		}
116
+
117
+		return $this->root->createComponent(
118
+			$jComp[0],
119
+			array_merge($properties, $components),
120
+			$defaults = false
121
+		);
122
+	}
123
+
124
+	/**
125
+	 * Parses properties.
126
+	 *
127
+	 * @return \Sabre\VObject\Property
128
+	 */
129
+	public function parseProperty(array $jProp)
130
+	{
131
+		list(
132
+			$propertyName,
133
+			$parameters,
134
+			$valueType
135
+		) = $jProp;
136
+
137
+		$propertyName = strtoupper($propertyName);
138
+
139
+		// This is the default class we would be using if we didn't know the
140
+		// value type. We're using this value later in this function.
141
+		$defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
142
+
143
+		$parameters = (array) $parameters;
144
+
145
+		$value = array_slice($jProp, 3);
146
+
147
+		$valueType = strtoupper($valueType);
148
+
149
+		if (isset($parameters['group'])) {
150
+			$propertyName = $parameters['group'].'.'.$propertyName;
151
+			unset($parameters['group']);
152
+		}
153
+
154
+		$prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
155
+		$prop->setJsonValue($value);
156
+
157
+		// We have to do something awkward here. FlatText as well as Text
158
+		// represents TEXT values. We have to normalize these here. In the
159
+		// future we can get rid of FlatText once we're allowed to break BC
160
+		// again.
161
+		if (FlatText::class === $defaultPropertyClass) {
162
+			$defaultPropertyClass = Text::class;
163
+		}
164
+
165
+		// If the value type we received (e.g.: TEXT) was not the default value
166
+		// type for the given property (e.g.: BDAY), we need to add a VALUE=
167
+		// parameter.
168
+		if ($defaultPropertyClass !== get_class($prop)) {
169
+			$prop['VALUE'] = $valueType;
170
+		}
171
+
172
+		return $prop;
173
+	}
174
+
175
+	/**
176
+	 * Sets the input data.
177
+	 *
178
+	 * @param resource|string|array $input
179
+	 */
180
+	public function setInput($input)
181
+	{
182
+		if (is_resource($input)) {
183
+			$input = stream_get_contents($input);
184
+		}
185
+		if (is_string($input)) {
186
+			$input = json_decode($input);
187
+		}
188
+		$this->input = $input;
189
+	}
190 190
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/Parser.php 1 patch
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -13,63 +13,63 @@
 block discarded – undo
13 13
  */
14 14
 abstract class Parser
15 15
 {
16
-    /**
17
-     * Turning on this option makes the parser more forgiving.
18
-     *
19
-     * In the case of the MimeDir parser, this means that the parser will
20
-     * accept slashes and underscores in property names, and it will also
21
-     * attempt to fix Microsoft vCard 2.1's broken line folding.
22
-     */
23
-    const OPTION_FORGIVING = 1;
16
+	/**
17
+	 * Turning on this option makes the parser more forgiving.
18
+	 *
19
+	 * In the case of the MimeDir parser, this means that the parser will
20
+	 * accept slashes and underscores in property names, and it will also
21
+	 * attempt to fix Microsoft vCard 2.1's broken line folding.
22
+	 */
23
+	const OPTION_FORGIVING = 1;
24 24
 
25
-    /**
26
-     * If this option is turned on, any lines we cannot parse will be ignored
27
-     * by the reader.
28
-     */
29
-    const OPTION_IGNORE_INVALID_LINES = 2;
25
+	/**
26
+	 * If this option is turned on, any lines we cannot parse will be ignored
27
+	 * by the reader.
28
+	 */
29
+	const OPTION_IGNORE_INVALID_LINES = 2;
30 30
 
31
-    /**
32
-     * Bitmask of parser options.
33
-     *
34
-     * @var int
35
-     */
36
-    protected $options;
31
+	/**
32
+	 * Bitmask of parser options.
33
+	 *
34
+	 * @var int
35
+	 */
36
+	protected $options;
37 37
 
38
-    /**
39
-     * Creates the parser.
40
-     *
41
-     * Optionally, it's possible to parse the input stream here.
42
-     *
43
-     * @param mixed $input
44
-     * @param int   $options any parser options (OPTION constants)
45
-     */
46
-    public function __construct($input = null, $options = 0)
47
-    {
48
-        if (!is_null($input)) {
49
-            $this->setInput($input);
50
-        }
51
-        $this->options = $options;
52
-    }
38
+	/**
39
+	 * Creates the parser.
40
+	 *
41
+	 * Optionally, it's possible to parse the input stream here.
42
+	 *
43
+	 * @param mixed $input
44
+	 * @param int   $options any parser options (OPTION constants)
45
+	 */
46
+	public function __construct($input = null, $options = 0)
47
+	{
48
+		if (!is_null($input)) {
49
+			$this->setInput($input);
50
+		}
51
+		$this->options = $options;
52
+	}
53 53
 
54
-    /**
55
-     * This method starts the parsing process.
56
-     *
57
-     * If the input was not supplied during construction, it's possible to pass
58
-     * it here instead.
59
-     *
60
-     * If either input or options are not supplied, the defaults will be used.
61
-     *
62
-     * @param mixed $input
63
-     * @param int   $options
64
-     *
65
-     * @return array
66
-     */
67
-    abstract public function parse($input = null, $options = 0);
54
+	/**
55
+	 * This method starts the parsing process.
56
+	 *
57
+	 * If the input was not supplied during construction, it's possible to pass
58
+	 * it here instead.
59
+	 *
60
+	 * If either input or options are not supplied, the defaults will be used.
61
+	 *
62
+	 * @param mixed $input
63
+	 * @param int   $options
64
+	 *
65
+	 * @return array
66
+	 */
67
+	abstract public function parse($input = null, $options = 0);
68 68
 
69
-    /**
70
-     * Sets the input data.
71
-     *
72
-     * @param mixed $input
73
-     */
74
-    abstract public function setInput($input);
69
+	/**
70
+	 * Sets the input data.
71
+	 *
72
+	 * @param mixed $input
73
+	 */
74
+	abstract public function setInput($input);
75 75
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Parser/MimeDir.php 1 patch
Indentation   +628 added lines, -628 removed lines patch added patch discarded remove patch
@@ -25,316 +25,316 @@  discard block
 block discarded – undo
25 25
  */
26 26
 class MimeDir extends Parser
27 27
 {
28
-    /**
29
-     * The input stream.
30
-     *
31
-     * @var resource
32
-     */
33
-    protected $input;
34
-
35
-    /**
36
-     * Root component.
37
-     *
38
-     * @var Component
39
-     */
40
-    protected $root;
41
-
42
-    /**
43
-     * By default all input will be assumed to be UTF-8.
44
-     *
45
-     * However, both iCalendar and vCard might be encoded using different
46
-     * character sets. The character set is usually set in the mime-type.
47
-     *
48
-     * If this is the case, use setEncoding to specify that a different
49
-     * encoding will be used. If this is set, the parser will automatically
50
-     * convert all incoming data to UTF-8.
51
-     *
52
-     * @var string
53
-     */
54
-    protected $charset = 'UTF-8';
55
-
56
-    /**
57
-     * The list of character sets we support when decoding.
58
-     *
59
-     * This would be a const expression but for now we need to support PHP 5.5
60
-     */
61
-    protected static $SUPPORTED_CHARSETS = [
62
-        'UTF-8',
63
-        'ISO-8859-1',
64
-        'Windows-1252',
65
-    ];
66
-
67
-    /**
68
-     * Parses an iCalendar or vCard file.
69
-     *
70
-     * Pass a stream or a string. If null is parsed, the existing buffer is
71
-     * used.
72
-     *
73
-     * @param string|resource|null $input
74
-     * @param int                  $options
75
-     *
76
-     * @return \Sabre\VObject\Document
77
-     */
78
-    public function parse($input = null, $options = 0)
79
-    {
80
-        $this->root = null;
81
-
82
-        if (!is_null($input)) {
83
-            $this->setInput($input);
84
-        }
85
-
86
-        if (0 !== $options) {
87
-            $this->options = $options;
88
-        }
89
-
90
-        $this->parseDocument();
91
-
92
-        return $this->root;
93
-    }
94
-
95
-    /**
96
-     * By default all input will be assumed to be UTF-8.
97
-     *
98
-     * However, both iCalendar and vCard might be encoded using different
99
-     * character sets. The character set is usually set in the mime-type.
100
-     *
101
-     * If this is the case, use setEncoding to specify that a different
102
-     * encoding will be used. If this is set, the parser will automatically
103
-     * convert all incoming data to UTF-8.
104
-     *
105
-     * @param string $charset
106
-     */
107
-    public function setCharset($charset)
108
-    {
109
-        if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
110
-            throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: '.implode(', ', self::$SUPPORTED_CHARSETS).')');
111
-        }
112
-        $this->charset = $charset;
113
-    }
114
-
115
-    /**
116
-     * Sets the input buffer. Must be a string or stream.
117
-     *
118
-     * @param resource|string $input
119
-     */
120
-    public function setInput($input)
121
-    {
122
-        // Resetting the parser
123
-        $this->lineIndex = 0;
124
-        $this->startLine = 0;
125
-
126
-        if (is_string($input)) {
127
-            // Converting to a stream.
128
-            $stream = fopen('php://temp', 'r+');
129
-            fwrite($stream, $input);
130
-            rewind($stream);
131
-            $this->input = $stream;
132
-        } elseif (is_resource($input)) {
133
-            $this->input = $input;
134
-        } else {
135
-            throw new \InvalidArgumentException('This parser can only read from strings or streams.');
136
-        }
137
-    }
138
-
139
-    /**
140
-     * Parses an entire document.
141
-     */
142
-    protected function parseDocument()
143
-    {
144
-        $line = $this->readLine();
145
-
146
-        // BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
147
-        // It's 0xEF 0xBB 0xBF in UTF-8 hex.
148
-        if (3 <= strlen($line)
149
-            && 0xef === ord($line[0])
150
-            && 0xbb === ord($line[1])
151
-            && 0xbf === ord($line[2])) {
152
-            $line = substr($line, 3);
153
-        }
154
-
155
-        switch (strtoupper($line)) {
156
-            case 'BEGIN:VCALENDAR':
157
-                $class = VCalendar::$componentMap['VCALENDAR'];
158
-                break;
159
-            case 'BEGIN:VCARD':
160
-                $class = VCard::$componentMap['VCARD'];
161
-                break;
162
-            default:
163
-                throw new ParseException('This parser only supports VCARD and VCALENDAR files');
164
-        }
165
-
166
-        $this->root = new $class([], false);
167
-
168
-        while (true) {
169
-            // Reading until we hit END:
170
-            try {
171
-                $line = $this->readLine();
172
-            } catch (EofException $oEx) {
173
-                $line = 'END:'.$this->root->name;
174
-            }
175
-            if ('END:' === strtoupper(substr($line, 0, 4))) {
176
-                break;
177
-            }
178
-            $result = $this->parseLine($line);
179
-            if ($result) {
180
-                $this->root->add($result);
181
-            }
182
-        }
183
-
184
-        $name = strtoupper(substr($line, 4));
185
-        if ($name !== $this->root->name) {
186
-            throw new ParseException('Invalid MimeDir file. expected: "END:'.$this->root->name.'" got: "END:'.$name.'"');
187
-        }
188
-    }
189
-
190
-    /**
191
-     * Parses a line, and if it hits a component, it will also attempt to parse
192
-     * the entire component.
193
-     *
194
-     * @param string $line Unfolded line
195
-     *
196
-     * @return Node
197
-     */
198
-    protected function parseLine($line)
199
-    {
200
-        // Start of a new component
201
-        if ('BEGIN:' === strtoupper(substr($line, 0, 6))) {
202
-            if (substr($line, 6) === $this->root->name) {
203
-                throw new ParseException('Invalid MimeDir file. Unexpected component: "'.$line.'" in document type '.$this->root->name);
204
-            }
205
-            $component = $this->root->createComponent(substr($line, 6), [], false);
206
-
207
-            while (true) {
208
-                // Reading until we hit END:
209
-                $line = $this->readLine();
210
-                if ('END:' === strtoupper(substr($line, 0, 4))) {
211
-                    break;
212
-                }
213
-                $result = $this->parseLine($line);
214
-                if ($result) {
215
-                    $component->add($result);
216
-                }
217
-            }
218
-
219
-            $name = strtoupper(substr($line, 4));
220
-            if ($name !== $component->name) {
221
-                throw new ParseException('Invalid MimeDir file. expected: "END:'.$component->name.'" got: "END:'.$name.'"');
222
-            }
223
-
224
-            return $component;
225
-        } else {
226
-            // Property reader
227
-            $property = $this->readProperty($line);
228
-            if (!$property) {
229
-                // Ignored line
230
-                return false;
231
-            }
232
-
233
-            return $property;
234
-        }
235
-    }
236
-
237
-    /**
238
-     * We need to look ahead 1 line every time to see if we need to 'unfold'
239
-     * the next line.
240
-     *
241
-     * If that was not the case, we store it here.
242
-     *
243
-     * @var string|null
244
-     */
245
-    protected $lineBuffer;
246
-
247
-    /**
248
-     * The real current line number.
249
-     */
250
-    protected $lineIndex = 0;
251
-
252
-    /**
253
-     * In the case of unfolded lines, this property holds the line number for
254
-     * the start of the line.
255
-     *
256
-     * @var int
257
-     */
258
-    protected $startLine = 0;
259
-
260
-    /**
261
-     * Contains a 'raw' representation of the current line.
262
-     *
263
-     * @var string
264
-     */
265
-    protected $rawLine;
266
-
267
-    /**
268
-     * Reads a single line from the buffer.
269
-     *
270
-     * This method strips any newlines and also takes care of unfolding.
271
-     *
272
-     * @throws \Sabre\VObject\EofException
273
-     *
274
-     * @return string
275
-     */
276
-    protected function readLine()
277
-    {
278
-        if (!\is_null($this->lineBuffer)) {
279
-            $rawLine = $this->lineBuffer;
280
-            $this->lineBuffer = null;
281
-        } else {
282
-            do {
283
-                $eof = \feof($this->input);
284
-
285
-                $rawLine = \fgets($this->input);
286
-
287
-                if ($eof || (\feof($this->input) && false === $rawLine)) {
288
-                    throw new EofException('End of document reached prematurely');
289
-                }
290
-                if (false === $rawLine) {
291
-                    throw new ParseException('Error reading from input stream');
292
-                }
293
-                $rawLine = \rtrim($rawLine, "\r\n");
294
-            } while ('' === $rawLine); // Skipping empty lines
295
-            ++$this->lineIndex;
296
-        }
297
-        $line = $rawLine;
298
-
299
-        $this->startLine = $this->lineIndex;
300
-
301
-        // Looking ahead for folded lines.
302
-        while (true) {
303
-            $nextLine = \rtrim(\fgets($this->input), "\r\n");
304
-            ++$this->lineIndex;
305
-            if (!$nextLine) {
306
-                break;
307
-            }
308
-            if ("\t" === $nextLine[0] || ' ' === $nextLine[0]) {
309
-                $curLine = \substr($nextLine, 1);
310
-                $line .= $curLine;
311
-                $rawLine .= "\n ".$curLine;
312
-            } else {
313
-                $this->lineBuffer = $nextLine;
314
-                break;
315
-            }
316
-        }
317
-        $this->rawLine = $rawLine;
318
-
319
-        return $line;
320
-    }
321
-
322
-    /**
323
-     * Reads a property or component from a line.
324
-     */
325
-    protected function readProperty($line)
326
-    {
327
-        if ($this->options & self::OPTION_FORGIVING) {
328
-            $propNameToken = 'A-Z0-9\-\._\\/';
329
-        } else {
330
-            $propNameToken = 'A-Z0-9\-\.';
331
-        }
332
-
333
-        $paramNameToken = 'A-Z0-9\-';
334
-        $safeChar = '^";:,';
335
-        $qSafeChar = '^"';
336
-
337
-        $regex = "/
28
+	/**
29
+	 * The input stream.
30
+	 *
31
+	 * @var resource
32
+	 */
33
+	protected $input;
34
+
35
+	/**
36
+	 * Root component.
37
+	 *
38
+	 * @var Component
39
+	 */
40
+	protected $root;
41
+
42
+	/**
43
+	 * By default all input will be assumed to be UTF-8.
44
+	 *
45
+	 * However, both iCalendar and vCard might be encoded using different
46
+	 * character sets. The character set is usually set in the mime-type.
47
+	 *
48
+	 * If this is the case, use setEncoding to specify that a different
49
+	 * encoding will be used. If this is set, the parser will automatically
50
+	 * convert all incoming data to UTF-8.
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $charset = 'UTF-8';
55
+
56
+	/**
57
+	 * The list of character sets we support when decoding.
58
+	 *
59
+	 * This would be a const expression but for now we need to support PHP 5.5
60
+	 */
61
+	protected static $SUPPORTED_CHARSETS = [
62
+		'UTF-8',
63
+		'ISO-8859-1',
64
+		'Windows-1252',
65
+	];
66
+
67
+	/**
68
+	 * Parses an iCalendar or vCard file.
69
+	 *
70
+	 * Pass a stream or a string. If null is parsed, the existing buffer is
71
+	 * used.
72
+	 *
73
+	 * @param string|resource|null $input
74
+	 * @param int                  $options
75
+	 *
76
+	 * @return \Sabre\VObject\Document
77
+	 */
78
+	public function parse($input = null, $options = 0)
79
+	{
80
+		$this->root = null;
81
+
82
+		if (!is_null($input)) {
83
+			$this->setInput($input);
84
+		}
85
+
86
+		if (0 !== $options) {
87
+			$this->options = $options;
88
+		}
89
+
90
+		$this->parseDocument();
91
+
92
+		return $this->root;
93
+	}
94
+
95
+	/**
96
+	 * By default all input will be assumed to be UTF-8.
97
+	 *
98
+	 * However, both iCalendar and vCard might be encoded using different
99
+	 * character sets. The character set is usually set in the mime-type.
100
+	 *
101
+	 * If this is the case, use setEncoding to specify that a different
102
+	 * encoding will be used. If this is set, the parser will automatically
103
+	 * convert all incoming data to UTF-8.
104
+	 *
105
+	 * @param string $charset
106
+	 */
107
+	public function setCharset($charset)
108
+	{
109
+		if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
110
+			throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: '.implode(', ', self::$SUPPORTED_CHARSETS).')');
111
+		}
112
+		$this->charset = $charset;
113
+	}
114
+
115
+	/**
116
+	 * Sets the input buffer. Must be a string or stream.
117
+	 *
118
+	 * @param resource|string $input
119
+	 */
120
+	public function setInput($input)
121
+	{
122
+		// Resetting the parser
123
+		$this->lineIndex = 0;
124
+		$this->startLine = 0;
125
+
126
+		if (is_string($input)) {
127
+			// Converting to a stream.
128
+			$stream = fopen('php://temp', 'r+');
129
+			fwrite($stream, $input);
130
+			rewind($stream);
131
+			$this->input = $stream;
132
+		} elseif (is_resource($input)) {
133
+			$this->input = $input;
134
+		} else {
135
+			throw new \InvalidArgumentException('This parser can only read from strings or streams.');
136
+		}
137
+	}
138
+
139
+	/**
140
+	 * Parses an entire document.
141
+	 */
142
+	protected function parseDocument()
143
+	{
144
+		$line = $this->readLine();
145
+
146
+		// BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
147
+		// It's 0xEF 0xBB 0xBF in UTF-8 hex.
148
+		if (3 <= strlen($line)
149
+			&& 0xef === ord($line[0])
150
+			&& 0xbb === ord($line[1])
151
+			&& 0xbf === ord($line[2])) {
152
+			$line = substr($line, 3);
153
+		}
154
+
155
+		switch (strtoupper($line)) {
156
+			case 'BEGIN:VCALENDAR':
157
+				$class = VCalendar::$componentMap['VCALENDAR'];
158
+				break;
159
+			case 'BEGIN:VCARD':
160
+				$class = VCard::$componentMap['VCARD'];
161
+				break;
162
+			default:
163
+				throw new ParseException('This parser only supports VCARD and VCALENDAR files');
164
+		}
165
+
166
+		$this->root = new $class([], false);
167
+
168
+		while (true) {
169
+			// Reading until we hit END:
170
+			try {
171
+				$line = $this->readLine();
172
+			} catch (EofException $oEx) {
173
+				$line = 'END:'.$this->root->name;
174
+			}
175
+			if ('END:' === strtoupper(substr($line, 0, 4))) {
176
+				break;
177
+			}
178
+			$result = $this->parseLine($line);
179
+			if ($result) {
180
+				$this->root->add($result);
181
+			}
182
+		}
183
+
184
+		$name = strtoupper(substr($line, 4));
185
+		if ($name !== $this->root->name) {
186
+			throw new ParseException('Invalid MimeDir file. expected: "END:'.$this->root->name.'" got: "END:'.$name.'"');
187
+		}
188
+	}
189
+
190
+	/**
191
+	 * Parses a line, and if it hits a component, it will also attempt to parse
192
+	 * the entire component.
193
+	 *
194
+	 * @param string $line Unfolded line
195
+	 *
196
+	 * @return Node
197
+	 */
198
+	protected function parseLine($line)
199
+	{
200
+		// Start of a new component
201
+		if ('BEGIN:' === strtoupper(substr($line, 0, 6))) {
202
+			if (substr($line, 6) === $this->root->name) {
203
+				throw new ParseException('Invalid MimeDir file. Unexpected component: "'.$line.'" in document type '.$this->root->name);
204
+			}
205
+			$component = $this->root->createComponent(substr($line, 6), [], false);
206
+
207
+			while (true) {
208
+				// Reading until we hit END:
209
+				$line = $this->readLine();
210
+				if ('END:' === strtoupper(substr($line, 0, 4))) {
211
+					break;
212
+				}
213
+				$result = $this->parseLine($line);
214
+				if ($result) {
215
+					$component->add($result);
216
+				}
217
+			}
218
+
219
+			$name = strtoupper(substr($line, 4));
220
+			if ($name !== $component->name) {
221
+				throw new ParseException('Invalid MimeDir file. expected: "END:'.$component->name.'" got: "END:'.$name.'"');
222
+			}
223
+
224
+			return $component;
225
+		} else {
226
+			// Property reader
227
+			$property = $this->readProperty($line);
228
+			if (!$property) {
229
+				// Ignored line
230
+				return false;
231
+			}
232
+
233
+			return $property;
234
+		}
235
+	}
236
+
237
+	/**
238
+	 * We need to look ahead 1 line every time to see if we need to 'unfold'
239
+	 * the next line.
240
+	 *
241
+	 * If that was not the case, we store it here.
242
+	 *
243
+	 * @var string|null
244
+	 */
245
+	protected $lineBuffer;
246
+
247
+	/**
248
+	 * The real current line number.
249
+	 */
250
+	protected $lineIndex = 0;
251
+
252
+	/**
253
+	 * In the case of unfolded lines, this property holds the line number for
254
+	 * the start of the line.
255
+	 *
256
+	 * @var int
257
+	 */
258
+	protected $startLine = 0;
259
+
260
+	/**
261
+	 * Contains a 'raw' representation of the current line.
262
+	 *
263
+	 * @var string
264
+	 */
265
+	protected $rawLine;
266
+
267
+	/**
268
+	 * Reads a single line from the buffer.
269
+	 *
270
+	 * This method strips any newlines and also takes care of unfolding.
271
+	 *
272
+	 * @throws \Sabre\VObject\EofException
273
+	 *
274
+	 * @return string
275
+	 */
276
+	protected function readLine()
277
+	{
278
+		if (!\is_null($this->lineBuffer)) {
279
+			$rawLine = $this->lineBuffer;
280
+			$this->lineBuffer = null;
281
+		} else {
282
+			do {
283
+				$eof = \feof($this->input);
284
+
285
+				$rawLine = \fgets($this->input);
286
+
287
+				if ($eof || (\feof($this->input) && false === $rawLine)) {
288
+					throw new EofException('End of document reached prematurely');
289
+				}
290
+				if (false === $rawLine) {
291
+					throw new ParseException('Error reading from input stream');
292
+				}
293
+				$rawLine = \rtrim($rawLine, "\r\n");
294
+			} while ('' === $rawLine); // Skipping empty lines
295
+			++$this->lineIndex;
296
+		}
297
+		$line = $rawLine;
298
+
299
+		$this->startLine = $this->lineIndex;
300
+
301
+		// Looking ahead for folded lines.
302
+		while (true) {
303
+			$nextLine = \rtrim(\fgets($this->input), "\r\n");
304
+			++$this->lineIndex;
305
+			if (!$nextLine) {
306
+				break;
307
+			}
308
+			if ("\t" === $nextLine[0] || ' ' === $nextLine[0]) {
309
+				$curLine = \substr($nextLine, 1);
310
+				$line .= $curLine;
311
+				$rawLine .= "\n ".$curLine;
312
+			} else {
313
+				$this->lineBuffer = $nextLine;
314
+				break;
315
+			}
316
+		}
317
+		$this->rawLine = $rawLine;
318
+
319
+		return $line;
320
+	}
321
+
322
+	/**
323
+	 * Reads a property or component from a line.
324
+	 */
325
+	protected function readProperty($line)
326
+	{
327
+		if ($this->options & self::OPTION_FORGIVING) {
328
+			$propNameToken = 'A-Z0-9\-\._\\/';
329
+		} else {
330
+			$propNameToken = 'A-Z0-9\-\.';
331
+		}
332
+
333
+		$paramNameToken = 'A-Z0-9\-';
334
+		$safeChar = '^";:,';
335
+		$qSafeChar = '^"';
336
+
337
+		$regex = "/
338 338
             ^(?P<name> [$propNameToken]+ ) (?=[;:])        # property name
339 339
             |
340 340
             (?<=:)(?P<propValue> .+)$                      # property value
@@ -347,337 +347,337 @@  discard block
 block discarded – undo
347 347
             ) (?=[;:,])
348 348
             /xi";
349 349
 
350
-        //echo $regex, "\n"; exit();
351
-        preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
350
+		//echo $regex, "\n"; exit();
351
+		preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
352 352
 
353
-        $property = [
354
-            'name' => null,
355
-            'parameters' => [],
356
-            'value' => null,
357
-        ];
353
+		$property = [
354
+			'name' => null,
355
+			'parameters' => [],
356
+			'value' => null,
357
+		];
358 358
 
359
-        $lastParam = null;
359
+		$lastParam = null;
360 360
 
361
-        /*
361
+		/*
362 362
          * Looping through all the tokens.
363 363
          *
364 364
          * Note that we are looping through them in reverse order, because if a
365 365
          * sub-pattern matched, the subsequent named patterns will not show up
366 366
          * in the result.
367 367
          */
368
-        foreach ($matches as $match) {
369
-            if (isset($match['paramValue'])) {
370
-                if ($match['paramValue'] && '"' === $match['paramValue'][0]) {
371
-                    $value = substr($match['paramValue'], 1, -1);
372
-                } else {
373
-                    $value = $match['paramValue'];
374
-                }
375
-
376
-                $value = $this->unescapeParam($value);
377
-
378
-                if (is_null($lastParam)) {
379
-                    if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
380
-                        // When the property can't be matched and the configuration
381
-                        // option is set to ignore invalid lines, we ignore this line
382
-                        // This can happen when servers provide faulty data as iCloud
383
-                        //  frequently does with X-APPLE-STRUCTURED-LOCATION
384
-                        continue;
385
-                    }
386
-                    throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
387
-                }
388
-                if (is_null($property['parameters'][$lastParam])) {
389
-                    $property['parameters'][$lastParam] = $value;
390
-                } elseif (is_array($property['parameters'][$lastParam])) {
391
-                    $property['parameters'][$lastParam][] = $value;
392
-                } elseif ($property['parameters'][$lastParam] === $value) {
393
-                    // When the current value of the parameter is the same as the
394
-                    // new one, then we can leave the current parameter as it is.
395
-                } else {
396
-                    $property['parameters'][$lastParam] = [
397
-                        $property['parameters'][$lastParam],
398
-                        $value,
399
-                    ];
400
-                }
401
-                continue;
402
-            }
403
-            if (isset($match['paramName'])) {
404
-                $lastParam = strtoupper($match['paramName']);
405
-                if (!isset($property['parameters'][$lastParam])) {
406
-                    $property['parameters'][$lastParam] = null;
407
-                }
408
-                continue;
409
-            }
410
-            if (isset($match['propValue'])) {
411
-                $property['value'] = $match['propValue'];
412
-                continue;
413
-            }
414
-            if (isset($match['name']) && $match['name']) {
415
-                $property['name'] = strtoupper($match['name']);
416
-                continue;
417
-            }
418
-
419
-            // @codeCoverageIgnoreStart
420
-            throw new \LogicException('This code should not be reachable');
421
-            // @codeCoverageIgnoreEnd
422
-        }
423
-
424
-        if (is_null($property['value'])) {
425
-            $property['value'] = '';
426
-        }
427
-        if (!$property['name']) {
428
-            if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
429
-                return false;
430
-            }
431
-            throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
432
-        }
433
-
434
-        // vCard 2.1 states that parameters may appear without a name, and only
435
-        // a value. We can deduce the value based on its name.
436
-        //
437
-        // Our parser will get those as parameters without a value instead, so
438
-        // we're filtering these parameters out first.
439
-        $namedParameters = [];
440
-        $namelessParameters = [];
441
-
442
-        foreach ($property['parameters'] as $name => $value) {
443
-            if (!is_null($value)) {
444
-                $namedParameters[$name] = $value;
445
-            } else {
446
-                $namelessParameters[] = $name;
447
-            }
448
-        }
449
-
450
-        $propObj = $this->root->createProperty($property['name'], null, $namedParameters);
451
-
452
-        foreach ($namelessParameters as $namelessParameter) {
453
-            $propObj->add(null, $namelessParameter);
454
-        }
455
-
456
-        if (isset($propObj['ENCODING']) && 'QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) {
457
-            $propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
458
-        } else {
459
-            $charset = $this->charset;
460
-            if (Document::VCARD21 === $this->root->getDocumentType() && isset($propObj['CHARSET'])) {
461
-                // vCard 2.1 allows the character set to be specified per property.
462
-                $charset = (string) $propObj['CHARSET'];
463
-            }
464
-            switch (strtolower($charset)) {
465
-                case 'utf-8':
466
-                    break;
467
-                case 'windows-1252':
468
-                case 'iso-8859-1':
469
-                    $property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
470
-                    break;
471
-                default:
472
-                    throw new ParseException('Unsupported CHARSET: '.$propObj['CHARSET']);
473
-            }
474
-            $propObj->setRawMimeDirValue($property['value']);
475
-        }
476
-
477
-        return $propObj;
478
-    }
479
-
480
-    /**
481
-     * Unescapes a property value.
482
-     *
483
-     * vCard 2.1 says:
484
-     *   * Semi-colons must be escaped in some property values, specifically
485
-     *     ADR, ORG and N.
486
-     *   * Semi-colons must be escaped in parameter values, because semi-colons
487
-     *     are also use to separate values.
488
-     *   * No mention of escaping backslashes with another backslash.
489
-     *   * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
490
-     *     span values over more than 1 line.
491
-     *
492
-     * vCard 3.0 says:
493
-     *   * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
494
-     *     escaped, all time time.
495
-     *   * Comma's are used for delimiters in multiple values
496
-     *   * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
497
-     *     as in some properties semi-colon is used for separators.
498
-     *   * Properties using semi-colons: N, ADR, GEO, ORG
499
-     *   * Both ADR and N's individual parts may be broken up further with a
500
-     *     comma.
501
-     *   * Properties using commas: NICKNAME, CATEGORIES
502
-     *
503
-     * vCard 4.0 (rfc6350) says:
504
-     *   * Commas must be escaped.
505
-     *   * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
506
-     *     delimiter, depending on the property.
507
-     *   * Backslashes must be escaped
508
-     *   * Newlines must be escaped as either \N or \n.
509
-     *   * Some compound properties may contain multiple parts themselves, so a
510
-     *     comma within a semi-colon delimited property may also be unescaped
511
-     *     to denote multiple parts _within_ the compound property.
512
-     *   * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
513
-     *   * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
514
-     *
515
-     * Even though the spec says that commas must always be escaped, the
516
-     * example for GEO in Section 6.5.2 seems to violate this.
517
-     *
518
-     * iCalendar 2.0 (rfc5545) says:
519
-     *   * Commas or semi-colons may be used as delimiters, depending on the
520
-     *     property.
521
-     *   * Commas, semi-colons, backslashes, newline (\N or \n) are always
522
-     *     escaped, unless they are delimiters.
523
-     *   * Colons shall not be escaped.
524
-     *   * Commas can be considered the 'default delimiter' and is described as
525
-     *     the delimiter in cases where the order of the multiple values is
526
-     *     insignificant.
527
-     *   * Semi-colons are described as the delimiter for 'structured values'.
528
-     *     They are specifically used in Semi-colons are used as a delimiter in
529
-     *     REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
530
-     *
531
-     * Now for the parameters
532
-     *
533
-     * If delimiter is not set (empty string) this method will just return a string.
534
-     * If it's a comma or a semi-colon the string will be split on those
535
-     * characters, and always return an array.
536
-     *
537
-     * @param string $input
538
-     * @param string $delimiter
539
-     *
540
-     * @return string|string[]
541
-     */
542
-    public static function unescapeValue($input, $delimiter = ';')
543
-    {
544
-        $regex = '#  (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
545
-        if ($delimiter) {
546
-            $regex .= ' | ('.$delimiter.')';
547
-        }
548
-        $regex .= ') #x';
549
-
550
-        $matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
551
-
552
-        $resultArray = [];
553
-        $result = '';
554
-
555
-        foreach ($matches as $match) {
556
-            switch ($match) {
557
-                case '\\\\':
558
-                    $result .= '\\';
559
-                    break;
560
-                case '\N':
561
-                case '\n':
562
-                    $result .= "\n";
563
-                    break;
564
-                case '\;':
565
-                    $result .= ';';
566
-                    break;
567
-                case '\,':
568
-                    $result .= ',';
569
-                    break;
570
-                case $delimiter:
571
-                    $resultArray[] = $result;
572
-                    $result = '';
573
-                    break;
574
-                default:
575
-                    $result .= $match;
576
-                    break;
577
-            }
578
-        }
579
-
580
-        $resultArray[] = $result;
581
-
582
-        return $delimiter ? $resultArray : $result;
583
-    }
584
-
585
-    /**
586
-     * Unescapes a parameter value.
587
-     *
588
-     * vCard 2.1:
589
-     *   * Does not mention a mechanism for this. In addition, double quotes
590
-     *     are never used to wrap values.
591
-     *   * This means that parameters can simply not contain colons or
592
-     *     semi-colons.
593
-     *
594
-     * vCard 3.0 (rfc2425, rfc2426):
595
-     *   * Parameters _may_ be surrounded by double quotes.
596
-     *   * If this is not the case, semi-colon, colon and comma may simply not
597
-     *     occur (the comma used for multiple parameter values though).
598
-     *   * If it is surrounded by double-quotes, it may simply not contain
599
-     *     double-quotes.
600
-     *   * This means that a parameter can in no case encode double-quotes, or
601
-     *     newlines.
602
-     *
603
-     * vCard 4.0 (rfc6350)
604
-     *   * Behavior seems to be identical to vCard 3.0
605
-     *
606
-     * iCalendar 2.0 (rfc5545)
607
-     *   * Behavior seems to be identical to vCard 3.0
608
-     *
609
-     * Parameter escaping mechanism (rfc6868) :
610
-     *   * This rfc describes a new way to escape parameter values.
611
-     *   * New-line is encoded as ^n
612
-     *   * ^ is encoded as ^^.
613
-     *   * " is encoded as ^'
614
-     *
615
-     * @param string $input
616
-     */
617
-    private function unescapeParam($input)
618
-    {
619
-        return
620
-            preg_replace_callback(
621
-                '#(\^(\^|n|\'))#',
622
-                function ($matches) {
623
-                    switch ($matches[2]) {
624
-                        case 'n':
625
-                            return "\n";
626
-                        case '^':
627
-                            return '^';
628
-                        case '\'':
629
-                            return '"';
630
-
631
-                    // @codeCoverageIgnoreStart
632
-                    }
633
-                    // @codeCoverageIgnoreEnd
634
-                },
635
-                $input
636
-            );
637
-    }
638
-
639
-    /**
640
-     * Gets the full quoted printable value.
641
-     *
642
-     * We need a special method for this, because newlines have both a meaning
643
-     * in vCards, and in QuotedPrintable.
644
-     *
645
-     * This method does not do any decoding.
646
-     *
647
-     * @return string
648
-     */
649
-    private function extractQuotedPrintableValue()
650
-    {
651
-        // We need to parse the raw line again to get the start of the value.
652
-        //
653
-        // We are basically looking for the first colon (:), but we need to
654
-        // skip over the parameters first, as they may contain one.
655
-        $regex = '/^
368
+		foreach ($matches as $match) {
369
+			if (isset($match['paramValue'])) {
370
+				if ($match['paramValue'] && '"' === $match['paramValue'][0]) {
371
+					$value = substr($match['paramValue'], 1, -1);
372
+				} else {
373
+					$value = $match['paramValue'];
374
+				}
375
+
376
+				$value = $this->unescapeParam($value);
377
+
378
+				if (is_null($lastParam)) {
379
+					if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
380
+						// When the property can't be matched and the configuration
381
+						// option is set to ignore invalid lines, we ignore this line
382
+						// This can happen when servers provide faulty data as iCloud
383
+						//  frequently does with X-APPLE-STRUCTURED-LOCATION
384
+						continue;
385
+					}
386
+					throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
387
+				}
388
+				if (is_null($property['parameters'][$lastParam])) {
389
+					$property['parameters'][$lastParam] = $value;
390
+				} elseif (is_array($property['parameters'][$lastParam])) {
391
+					$property['parameters'][$lastParam][] = $value;
392
+				} elseif ($property['parameters'][$lastParam] === $value) {
393
+					// When the current value of the parameter is the same as the
394
+					// new one, then we can leave the current parameter as it is.
395
+				} else {
396
+					$property['parameters'][$lastParam] = [
397
+						$property['parameters'][$lastParam],
398
+						$value,
399
+					];
400
+				}
401
+				continue;
402
+			}
403
+			if (isset($match['paramName'])) {
404
+				$lastParam = strtoupper($match['paramName']);
405
+				if (!isset($property['parameters'][$lastParam])) {
406
+					$property['parameters'][$lastParam] = null;
407
+				}
408
+				continue;
409
+			}
410
+			if (isset($match['propValue'])) {
411
+				$property['value'] = $match['propValue'];
412
+				continue;
413
+			}
414
+			if (isset($match['name']) && $match['name']) {
415
+				$property['name'] = strtoupper($match['name']);
416
+				continue;
417
+			}
418
+
419
+			// @codeCoverageIgnoreStart
420
+			throw new \LogicException('This code should not be reachable');
421
+			// @codeCoverageIgnoreEnd
422
+		}
423
+
424
+		if (is_null($property['value'])) {
425
+			$property['value'] = '';
426
+		}
427
+		if (!$property['name']) {
428
+			if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
429
+				return false;
430
+			}
431
+			throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
432
+		}
433
+
434
+		// vCard 2.1 states that parameters may appear without a name, and only
435
+		// a value. We can deduce the value based on its name.
436
+		//
437
+		// Our parser will get those as parameters without a value instead, so
438
+		// we're filtering these parameters out first.
439
+		$namedParameters = [];
440
+		$namelessParameters = [];
441
+
442
+		foreach ($property['parameters'] as $name => $value) {
443
+			if (!is_null($value)) {
444
+				$namedParameters[$name] = $value;
445
+			} else {
446
+				$namelessParameters[] = $name;
447
+			}
448
+		}
449
+
450
+		$propObj = $this->root->createProperty($property['name'], null, $namedParameters);
451
+
452
+		foreach ($namelessParameters as $namelessParameter) {
453
+			$propObj->add(null, $namelessParameter);
454
+		}
455
+
456
+		if (isset($propObj['ENCODING']) && 'QUOTED-PRINTABLE' === strtoupper($propObj['ENCODING'])) {
457
+			$propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
458
+		} else {
459
+			$charset = $this->charset;
460
+			if (Document::VCARD21 === $this->root->getDocumentType() && isset($propObj['CHARSET'])) {
461
+				// vCard 2.1 allows the character set to be specified per property.
462
+				$charset = (string) $propObj['CHARSET'];
463
+			}
464
+			switch (strtolower($charset)) {
465
+				case 'utf-8':
466
+					break;
467
+				case 'windows-1252':
468
+				case 'iso-8859-1':
469
+					$property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
470
+					break;
471
+				default:
472
+					throw new ParseException('Unsupported CHARSET: '.$propObj['CHARSET']);
473
+			}
474
+			$propObj->setRawMimeDirValue($property['value']);
475
+		}
476
+
477
+		return $propObj;
478
+	}
479
+
480
+	/**
481
+	 * Unescapes a property value.
482
+	 *
483
+	 * vCard 2.1 says:
484
+	 *   * Semi-colons must be escaped in some property values, specifically
485
+	 *     ADR, ORG and N.
486
+	 *   * Semi-colons must be escaped in parameter values, because semi-colons
487
+	 *     are also use to separate values.
488
+	 *   * No mention of escaping backslashes with another backslash.
489
+	 *   * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
490
+	 *     span values over more than 1 line.
491
+	 *
492
+	 * vCard 3.0 says:
493
+	 *   * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
494
+	 *     escaped, all time time.
495
+	 *   * Comma's are used for delimiters in multiple values
496
+	 *   * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
497
+	 *     as in some properties semi-colon is used for separators.
498
+	 *   * Properties using semi-colons: N, ADR, GEO, ORG
499
+	 *   * Both ADR and N's individual parts may be broken up further with a
500
+	 *     comma.
501
+	 *   * Properties using commas: NICKNAME, CATEGORIES
502
+	 *
503
+	 * vCard 4.0 (rfc6350) says:
504
+	 *   * Commas must be escaped.
505
+	 *   * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
506
+	 *     delimiter, depending on the property.
507
+	 *   * Backslashes must be escaped
508
+	 *   * Newlines must be escaped as either \N or \n.
509
+	 *   * Some compound properties may contain multiple parts themselves, so a
510
+	 *     comma within a semi-colon delimited property may also be unescaped
511
+	 *     to denote multiple parts _within_ the compound property.
512
+	 *   * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
513
+	 *   * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
514
+	 *
515
+	 * Even though the spec says that commas must always be escaped, the
516
+	 * example for GEO in Section 6.5.2 seems to violate this.
517
+	 *
518
+	 * iCalendar 2.0 (rfc5545) says:
519
+	 *   * Commas or semi-colons may be used as delimiters, depending on the
520
+	 *     property.
521
+	 *   * Commas, semi-colons, backslashes, newline (\N or \n) are always
522
+	 *     escaped, unless they are delimiters.
523
+	 *   * Colons shall not be escaped.
524
+	 *   * Commas can be considered the 'default delimiter' and is described as
525
+	 *     the delimiter in cases where the order of the multiple values is
526
+	 *     insignificant.
527
+	 *   * Semi-colons are described as the delimiter for 'structured values'.
528
+	 *     They are specifically used in Semi-colons are used as a delimiter in
529
+	 *     REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
530
+	 *
531
+	 * Now for the parameters
532
+	 *
533
+	 * If delimiter is not set (empty string) this method will just return a string.
534
+	 * If it's a comma or a semi-colon the string will be split on those
535
+	 * characters, and always return an array.
536
+	 *
537
+	 * @param string $input
538
+	 * @param string $delimiter
539
+	 *
540
+	 * @return string|string[]
541
+	 */
542
+	public static function unescapeValue($input, $delimiter = ';')
543
+	{
544
+		$regex = '#  (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
545
+		if ($delimiter) {
546
+			$regex .= ' | ('.$delimiter.')';
547
+		}
548
+		$regex .= ') #x';
549
+
550
+		$matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
551
+
552
+		$resultArray = [];
553
+		$result = '';
554
+
555
+		foreach ($matches as $match) {
556
+			switch ($match) {
557
+				case '\\\\':
558
+					$result .= '\\';
559
+					break;
560
+				case '\N':
561
+				case '\n':
562
+					$result .= "\n";
563
+					break;
564
+				case '\;':
565
+					$result .= ';';
566
+					break;
567
+				case '\,':
568
+					$result .= ',';
569
+					break;
570
+				case $delimiter:
571
+					$resultArray[] = $result;
572
+					$result = '';
573
+					break;
574
+				default:
575
+					$result .= $match;
576
+					break;
577
+			}
578
+		}
579
+
580
+		$resultArray[] = $result;
581
+
582
+		return $delimiter ? $resultArray : $result;
583
+	}
584
+
585
+	/**
586
+	 * Unescapes a parameter value.
587
+	 *
588
+	 * vCard 2.1:
589
+	 *   * Does not mention a mechanism for this. In addition, double quotes
590
+	 *     are never used to wrap values.
591
+	 *   * This means that parameters can simply not contain colons or
592
+	 *     semi-colons.
593
+	 *
594
+	 * vCard 3.0 (rfc2425, rfc2426):
595
+	 *   * Parameters _may_ be surrounded by double quotes.
596
+	 *   * If this is not the case, semi-colon, colon and comma may simply not
597
+	 *     occur (the comma used for multiple parameter values though).
598
+	 *   * If it is surrounded by double-quotes, it may simply not contain
599
+	 *     double-quotes.
600
+	 *   * This means that a parameter can in no case encode double-quotes, or
601
+	 *     newlines.
602
+	 *
603
+	 * vCard 4.0 (rfc6350)
604
+	 *   * Behavior seems to be identical to vCard 3.0
605
+	 *
606
+	 * iCalendar 2.0 (rfc5545)
607
+	 *   * Behavior seems to be identical to vCard 3.0
608
+	 *
609
+	 * Parameter escaping mechanism (rfc6868) :
610
+	 *   * This rfc describes a new way to escape parameter values.
611
+	 *   * New-line is encoded as ^n
612
+	 *   * ^ is encoded as ^^.
613
+	 *   * " is encoded as ^'
614
+	 *
615
+	 * @param string $input
616
+	 */
617
+	private function unescapeParam($input)
618
+	{
619
+		return
620
+			preg_replace_callback(
621
+				'#(\^(\^|n|\'))#',
622
+				function ($matches) {
623
+					switch ($matches[2]) {
624
+						case 'n':
625
+							return "\n";
626
+						case '^':
627
+							return '^';
628
+						case '\'':
629
+							return '"';
630
+
631
+					// @codeCoverageIgnoreStart
632
+					}
633
+					// @codeCoverageIgnoreEnd
634
+				},
635
+				$input
636
+			);
637
+	}
638
+
639
+	/**
640
+	 * Gets the full quoted printable value.
641
+	 *
642
+	 * We need a special method for this, because newlines have both a meaning
643
+	 * in vCards, and in QuotedPrintable.
644
+	 *
645
+	 * This method does not do any decoding.
646
+	 *
647
+	 * @return string
648
+	 */
649
+	private function extractQuotedPrintableValue()
650
+	{
651
+		// We need to parse the raw line again to get the start of the value.
652
+		//
653
+		// We are basically looking for the first colon (:), but we need to
654
+		// skip over the parameters first, as they may contain one.
655
+		$regex = '/^
656 656
             (?: [^:])+ # Anything but a colon
657 657
             (?: "[^"]")* # A parameter in double quotes
658 658
             : # start of the value we really care about
659 659
             (.*)$
660 660
         /xs';
661 661
 
662
-        preg_match($regex, $this->rawLine, $matches);
663
-
664
-        $value = $matches[1];
665
-        // Removing the first whitespace character from every line. Kind of
666
-        // like unfolding, but we keep the newline.
667
-        $value = str_replace("\n ", "\n", $value);
668
-
669
-        // Microsoft products don't always correctly fold lines, they may be
670
-        // missing a whitespace. So if 'forgiving' is turned on, we will take
671
-        // those as well.
672
-        if ($this->options & self::OPTION_FORGIVING) {
673
-            while ('=' === substr($value, -1) && $this->lineBuffer) {
674
-                // Reading the line
675
-                $this->readLine();
676
-                // Grabbing the raw form
677
-                $value .= "\n".$this->rawLine;
678
-            }
679
-        }
680
-
681
-        return $value;
682
-    }
662
+		preg_match($regex, $this->rawLine, $matches);
663
+
664
+		$value = $matches[1];
665
+		// Removing the first whitespace character from every line. Kind of
666
+		// like unfolding, but we keep the newline.
667
+		$value = str_replace("\n ", "\n", $value);
668
+
669
+		// Microsoft products don't always correctly fold lines, they may be
670
+		// missing a whitespace. So if 'forgiving' is turned on, we will take
671
+		// those as well.
672
+		if ($this->options & self::OPTION_FORGIVING) {
673
+			while ('=' === substr($value, -1) && $this->lineBuffer) {
674
+				// Reading the line
675
+				$this->readLine();
676
+				// Grabbing the raw form
677
+				$value .= "\n".$this->rawLine;
678
+			}
679
+		}
680
+
681
+		return $value;
682
+	}
683 683
 }
Please login to merge, or discard this patch.