GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (149)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/vCard-parser/vCard.php (17 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * vCard class for parsing a vCard and/or creating one
4
 *
5
 * @link https://github.com/nuovo/vCard-parser
6
 * @author Martins Pilsetnieks, Roberts Bruveris
7
 * @see RFC 2426, RFC 2425
8
 * @version 0.4.8
9
*/
10
	class vCard implements Countable, Iterator
11
	{
12
		const MODE_ERROR = 'error';
13
		const MODE_SINGLE = 'single';
14
		const MODE_MULTIPLE = 'multiple';
15
16
		const endl = "\n";
17
18
		/**
19
		 * @var string Current object mode - error, single or multiple (for a single vCard within a file and multiple combined vCards)
20
		 */
21
		private $Mode;  //single, multiple, error
22
23
		private $Path = '';
24
		private $RawData = '';
25
26
		/**
27
		 * @var array Internal options container. Options:
28
		 *	bool Collapse: If true, elements that can have multiple values but have only a single value are returned as that value instead of an array
29
		 *		If false, an array is returned even if it has only one value.
30
		 */
31
		private $Options = array(
32
			'Collapse' => false
33
		);
34
35
		/**
36
		 * @var array Internal data container. Contains vCard objects for multiple vCards and just the data for single vCards.
37
		 */
38
		private $Data = array();
39
40
		/**
41
		 * @static Parts of structured elements according to the spec.
42
		 */
43
		private static $Spec_StructuredElements = array(
44
			'n' => array('lastname', 'firstname', 'additionalnames', 'prefixes', 'suffixes'),
45
			'adr' => array('pobox', 'extendedaddress', 'streetaddress', 'locality', 'region', 'postalcode', 'country'),
46
			'geo' => array('latitude', 'longitude'),
47
			'org' => array('name', 'unit1', 'unit2')
48
		);
49
		private static $Spec_MultipleValueElements = array('nickname', 'categories');
50
51
		private static $Spec_ElementTypes = array(
52
			'email' => array('internet', 'x400', 'pref', 'home', 'work'),
53
			'adr' => array('dom', 'intl', 'postal', 'parcel', 'home', 'work', 'pref'),
54
			'label' => array('dom', 'intl', 'postal', 'parcel', 'home', 'work', 'pref'),
55
			'tel' => array('home', 'msg', 'work', 'pref', 'voice', 'fax', 'cell', 'video', 'pager', 'bbs', 'modem', 'car', 'isdn', 'pcs'),
56
			'impp' => array('personal', 'business', 'home', 'work', 'mobile', 'pref')
57
		);
58
59
		private static $Spec_FileElements = array('photo', 'logo', 'sound');
60
61
		/**
62
		 * vCard constructor
63
		 *
64
		 * @param string Path to file, optional.
65
		 * @param string Raw data, optional.
66
		 * @param array Additional options, optional. Currently supported options:
67
		 *	bool Collapse: If true, elements that can have multiple values but have only a single value are returned as that value instead of an array
68
		 *		If false, an array is returned even if it has only one value.
69
		 *
70
		 * One of these parameters must be provided, otherwise an exception is thrown.
71
		 */
72
		public function __construct($Path = false, $RawData = false, array $Options = null)
73
		{
74
			// Checking preconditions for the parser.
75
			// If path is given, the file should be accessible.
76
			// If raw data is given, it is taken as it is.
77
			// In both cases the real content is put in $this -> RawData
78
			if ($Path)
79
			{
80
				if (!is_readable($Path))
81
				{
82
					throw new Exception('vCard: Path not accessible ('.$Path.')');
83
				}
84
85
				$this -> Path = $Path;
0 ignored issues
show
Documentation Bug introduced by
The property $Path was declared of type string, but $Path is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
86
				$this -> RawData = file_get_contents($this -> Path);
87
			}
88
			elseif ($RawData)
89
			{
90
				$this -> RawData = $RawData;
0 ignored issues
show
Documentation Bug introduced by
The property $RawData was declared of type string, but $RawData is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
91
			}
92
			else
0 ignored issues
show
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
93
			{
94
				//throw new Exception('vCard: No content provided');
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
95
				// Not necessary anymore as possibility to create vCards is added
96
			}
97
98
			if (!$this -> Path && !$this -> RawData)
99
			{
100
				return true;
0 ignored issues
show
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
101
			}
102
103
			if ($Options)
104
			{
105
				$this -> Options = array_merge($this -> Options, $Options);
106
			}
107
108
			// Counting the begin/end separators. If there aren't any or the count doesn't match, there is a problem with the file.
109
			// If there is only one, this is a single vCard, if more, multiple vCards are combined.
110
			$Matches = array();
111
			$vCardBeginCount = preg_match_all('{^BEGIN\:VCARD}miS', $this -> RawData, $Matches);
112
			$vCardEndCount = preg_match_all('{^END\:VCARD}miS', $this -> RawData, $Matches);
113
114
			if (($vCardBeginCount != $vCardEndCount) || !$vCardBeginCount)
115
			{
116
				$this -> Mode = vCard::MODE_ERROR;
117
				throw new Exception('vCard: invalid vCard');
118
			}
119
120
			$this -> Mode = $vCardBeginCount == 1 ? vCard::MODE_SINGLE : vCard::MODE_MULTIPLE;
121
122
			// Removing/changing inappropriate newlines, i.e., all CRs or multiple newlines are changed to a single newline
123
			$this -> RawData = str_replace("\r", "\n", $this -> RawData);
124
			$this -> RawData = preg_replace('{(\n+)}', "\n", $this -> RawData);
125
126
			// In multiple card mode the raw text is split at card beginning markers and each
127
			//	fragment is parsed in a separate vCard object.
128
			if ($this -> Mode == self::MODE_MULTIPLE)
129
			{
130
				$this -> RawData = explode('BEGIN:VCARD', $this -> RawData);
0 ignored issues
show
Documentation Bug introduced by
It seems like explode('BEGIN:VCARD', $this->RawData) of type array is incompatible with the declared type string of property $RawData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
131
				$this -> RawData = array_filter($this -> RawData);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_filter($this->RawData) of type array is incompatible with the declared type string of property $RawData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
132
133
				foreach ($this -> RawData as $SinglevCardRawData)
134
				{
135
					// Prepending "BEGIN:VCARD" to the raw string because we exploded on that one.
136
					// If there won't be the BEGIN marker in the new object, it will fail.
137
					$SinglevCardRawData = 'BEGIN:VCARD'."\n".$SinglevCardRawData;
138
139
					$ClassName = get_class($this);
140
					$this -> Data[] = new $ClassName(false, $SinglevCardRawData);
141
				}
142
			}
143
			else
144
			{
145
				// Protect the BASE64 final = sign (detected by the line beginning with whitespace), otherwise the next replace will get rid of it
146
				$this -> RawData = preg_replace('{(\n\s.+)=(\n)}', '$1-base64=-$2', $this -> RawData);
147
148
				// Joining multiple lines that are split with a hard wrap and indicated by an equals sign at the end of line
149
				// (quoted-printable-encoded values in v2.1 vCards)
150
				$this -> RawData = str_replace("=\n", '', $this -> RawData);
151
152
				// Joining multiple lines that are split with a soft wrap (space or tab on the beginning of the next line
153
				$this -> RawData = str_replace(array("\n ", "\n\t"), '-wrap-', $this -> RawData);
154
155
				// Restoring the BASE64 final equals sign (see a few lines above)
156
				$this -> RawData = str_replace("-base64=-\n", "=\n", $this -> RawData);
157
158
				$Lines = explode("\n", $this -> RawData);
159
160
				foreach ($Lines as $Line)
161
				{
162
					// Lines without colons are skipped because, most likely, they contain no data.
163
					if (strpos($Line, ':') === false)
164
					{
165
						continue;
166
					}
167
168
					// Each line is split into two parts. The key contains the element name and additional parameters, if present,
169
					//	value is just the value
170
					list($Key, $Value) = explode(':', $Line, 2);
171
172
					// Key is transformed to lowercase because, even though the element and parameter names are written in uppercase,
173
					//	it is quite possible that they will be in lower- or mixed case.
174
					// The key is trimmed to allow for non-significant WSP characters as allowed by v2.1
175
					$Key = strtolower(trim(self::Unescape($Key)));
176
177
					// These two lines can be skipped as they aren't necessary at all.
178
					if ($Key == 'begin' || $Key == 'end')
179
					{
180
						continue;
181
					}
182
183
					if ((strpos($Key, 'agent') === 0) && (stripos($Value, 'begin:vcard') !== false))
184
					{
185
						$ClassName = get_class($this);
186
						$Value = new $ClassName(false, str_replace('-wrap-', "\n", $Value));
187
						if (!isset($this -> Data[$Key]))
188
						{
189
							$this -> Data[$Key] = array();
190
						}
191
						$this -> Data[$Key][] = $Value;
192
						continue;
193
					}
194
					else
195
					{
196
						$Value = str_replace('-wrap-', '', $Value);
197
					}
198
199
					$Value = trim(self::Unescape($Value));
200
					$Type = array();
201
202
					// Here additional parameters are parsed
203
					$KeyParts = explode(';', $Key);
204
					$Key = $KeyParts[0];
205
					$Encoding = false;
206
207
					if (strpos($Key, 'item') === 0)
208
					{
209
						$TmpKey = explode('.', $Key, 2);
210
						$Key = $TmpKey[1];
211
						$ItemIndex = (int)str_ireplace('item', '', $TmpKey[0]);
0 ignored issues
show
$ItemIndex is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
212
					}
213
214
					if (count($KeyParts) > 1)
215
					{
216
						$Parameters = self::ParseParameters($Key, array_slice($KeyParts, 1));
217
218
						foreach ($Parameters as $ParamKey => $ParamValue)
219
						{
220
							switch ($ParamKey)
221
							{
222
								case 'encoding':
223
									$Encoding = $ParamValue;
224
									if (in_array($ParamValue, array('b', 'base64')))
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
225
									{
226
										//$Value = base64_decode($Value);
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
227
									}
228
									elseif ($ParamValue == 'quoted-printable') // v2.1
229
									{
230
										$Value = quoted_printable_decode($Value);
231
									}
232
									break;
233
								case 'charset': // v2.1
234
									if ($ParamValue != 'utf-8' && $ParamValue != 'utf8')
235
									{
236
										$Value = mb_convert_encoding($Value, 'UTF-8', $ParamValue);
237
									}
238
									break;
239
								case 'type':
240
									$Type = $ParamValue;
241
									break;
242
							}
243
						}
244
					}
245
246
					// Checking files for colon-separated additional parameters (Apple's Address Book does this), for example, "X-ABCROP-RECTANGLE" for photos
247
					if (in_array($Key, self::$Spec_FileElements) && isset($Parameters['encoding']) && in_array($Parameters['encoding'], array('b', 'base64')))
248
					{
249
						// If colon is present in the value, it must contain Address Book parameters
250
						//	(colon is an invalid character for base64 so it shouldn't appear in valid files)
251
						if (strpos($Value, ':') !== false)
252
						{
253
							$Value = explode(':', $Value);
254
							$Value = array_pop($Value);
255
						}
256
					}
257
258
					// Values are parsed according to their type
259
					if (isset(self::$Spec_StructuredElements[$Key]))
260
					{
261
						$Value = self::ParseStructuredValue($Value, $Key);
262
						if ($Type)
263
						{
264
							$Value['type'] = $Type;
265
						}
266
					}
267
					else
268
					{
269
						if (in_array($Key, self::$Spec_MultipleValueElements))
270
						{
271
							$Value = self::ParseMultipleTextValue($Value, $Key);
0 ignored issues
show
The call to vCard::ParseMultipleTextValue() has too many arguments starting with $Key.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
272
						}
273
274
						if ($Type)
275
						{
276
							$Value = array(
277
								'value' => $Value,
278
								'type' => $Type
279
							);
280
						}
281
					}
282
283
					if (is_array($Value) && $Encoding)
284
					{
285
						$Value['encoding'] = $Encoding;
286
					}
287
288
					if (!isset($this -> Data[$Key]))
289
					{
290
						$this -> Data[$Key] = array();
291
					}
292
293
					$this -> Data[$Key][] = $Value;
294
				}
295
			}
296
		}
297
298
		/**
299
		 * Magic method to get the various vCard values as object members, e.g.
300
		 *	a call to $vCard -> N gets the "N" value
301
		 *
302
		 * @param string Key
303
		 *
304
		 * @return mixed Value
305
		 */
306
		public function __get($Key)
307
		{
308
			$Key = strtolower($Key);
309
			if (isset($this -> Data[$Key]))
310
			{
311
				if ($Key == 'agent')
312
				{
313
					return $this -> Data[$Key];
314
				}
315
				elseif (in_array($Key, self::$Spec_FileElements))
316
				{
317
					$Value = $this -> Data[$Key];
318
					foreach ($Value as $K => $V)
319
					{
320
						if (stripos($V['value'], 'uri:') === 0)
321
						{
322
							$Value[$K]['value'] = substr($V, 4);
323
							$Value[$K]['encoding'] = 'uri';
324
						}
325
					}
326
					return $Value;
327
				}
328
329
				if ($this -> Options['Collapse'] && is_array($this -> Data[$Key]) && (count($this -> Data[$Key]) == 1))
330
				{
331
					return $this -> Data[$Key][0];
332
				}
333
				return $this -> Data[$Key];
334
			}
335
			elseif ($Key == 'Mode')
336
			{
337
				return $this -> Mode;
338
			}
339
			return array();
340
		}
341
342
		/**
343
		 * Saves an embedded file
344
		 *
345
		 * @param string Key
346
		 * @param int Index of the file, defaults to 0
347
		 * @param string Target path where the file should be saved, including the filename
348
		 *
349
		 * @return bool Operation status
350
		 */
351
		public function SaveFile($Key, $Index = 0, $TargetPath = '')
352
		{
353
			if (!isset($this -> Data[$Key]))
354
			{
355
				return false;
356
			}
357
			if (!isset($this -> Data[$Key][$Index]))
358
			{
359
				return false;
360
			}
361
362
			// Returing false if it is an image URL
363
			if (stripos($this -> Data[$Key][$Index]['value'], 'uri:') === 0)
364
			{
365
				return false;
366
			}
367
368
			if (is_writable($TargetPath) || (!file_exists($TargetPath) && is_writable(dirname($TargetPath))))
369
			{
370
				$RawContent = $this -> Data[$Key][$Index]['value'];
371
				if (isset($this -> Data[$Key][$Index]['encoding']) && $this -> Data[$Key][$Index]['encoding'] == 'b')
372
				{
373
					$RawContent = base64_decode($RawContent);
374
				}
375
				$Status = file_put_contents($TargetPath, $RawContent);
376
				return (bool)$Status;
377
			}
378
			else
379
			{
380
				throw new Exception('vCard: Cannot save file ('.$Key.'), target path not writable ('.$TargetPath.')');
381
			}
382
			return false;
0 ignored issues
show
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
383
		}
384
385
		/**
386
		 * Magic method for adding data to the vCard
387
		 *
388
		 * @param string Key
389
		 * @param string Method call arguments. First element is value.
390
		 *
391
		 * @return vCard Current object for method chaining
392
		 */
393
		public function __call($Key, $Arguments)
394
		{
395
			$Key = strtolower($Key);
396
397
			if (!isset($this -> Data[$Key]))
398
			{
399
				$this -> Data[$Key] = array();
400
			}
401
402
			$Value = isset($Arguments[0]) ? $Arguments[0] : false;
403
404
			if (count($Arguments) > 1)
405
			{
406
				$Types = array_map('strtolower', array_values(array_slice($Arguments, 1)));
407
408
				if (isset(self::$Spec_StructuredElements[$Key]) &&
409
					in_array(strtolower($Arguments[1]), self::$Spec_StructuredElements[$Key])
410
				)
411
				{
412
					$LastElementIndex = 0;
413
414
					if (count($this -> Data[$Key]))
415
					{
416
						$LastElementIndex = count($this -> Data[$Key]) - 1;
417
					}
418
419
					if (isset($this -> Data[$Key][$LastElementIndex]))
420
					{
421
						if (empty($this -> Data[$Key][$LastElementIndex][$Types[0]]))
422
						{
423
							$this -> Data[$Key][$LastElementIndex][$Types[0]] = $Value;
424
						}
425
						else
426
						{
427
							$LastElementIndex++;
428
						}
429
					}
430
431
					if (!isset($this -> Data[$Key][$LastElementIndex]))
432
					{
433
						$this -> Data[$Key][$LastElementIndex] = array(
434
							$Types[0] => $Value
435
						);
436
					}
437
				}
438
				elseif (isset(self::$Spec_ElementTypes[$Key]))
439
				{
440
					$this -> Data[$Key][] = array(
441
						'value' => $Value,
442
						'type' => $Types
443
					);
444
				}
445
			}
446
			elseif ($Value)
447
			{
448
				$this -> Data[$Key][] = $Value;
449
			}
450
451
			return $this;
452
		}
453
454
		/**
455
		 * Magic method for getting vCard content out
456
		 *
457
		 * @return string Raw vCard content
458
		 */
459
		public function __toString()
460
		{
461
			$Text = 'BEGIN:VCARD'.self::endl;
462
			$Text .= 'VERSION:3.0'.self::endl;
463
464
			foreach ($this -> Data as $Key => $Values)
465
			{
466
				$KeyUC = strtoupper($Key);
467
				$Key = strtolower($Key);
468
469
				if (in_array($KeyUC, array('PHOTO', 'VERSION')))
470
				{
471
					continue;
472
				}
473
474
				foreach ($Values as $Index => $Value)
475
				{
476
					$Text .= $KeyUC;
477
					if (is_array($Value) && isset($Value['type']))
478
					{
479
						$Text .= ';TYPE='.self::PrepareTypeStrForOutput($Value['type']);
480
					}
481
					$Text .= ':';
482
483
					if (isset(self::$Spec_StructuredElements[$Key]))
484
					{
485
						$PartArray = array();
486
						foreach (self::$Spec_StructuredElements[$Key] as $Part)
487
						{
488
							$PartArray[] = isset($Value[$Part]) ? $Value[$Part] : '';
489
						}
490
						$Text .= implode(';', $PartArray);
491
					}
492
					elseif (is_array($Value) && isset(self::$Spec_ElementTypes[$Key]))
493
					{
494
						$Text .= $Value['value'];
495
					}
496
					else
497
					{
498
						$Text .= $Value;
499
					}
500
501
					$Text .= self::endl;
502
				}
503
			}
504
505
			$Text .= 'END:VCARD'.self::endl;
506
			return $Text;
507
		}
508
509
		// !Helper methods
510
511
		private static function PrepareTypeStrForOutput($Type)
512
		{
513
			return implode(',', array_map('strtoupper', $Type));
514
		}
515
516
	 	/**
517
		 * Removes the escaping slashes from the text.
518
		 *
519
		 * @access private
520
		 *
521
		 * @param string Text to prepare.
522
		 *
523
		 * @return string Resulting text.
524
		 */
525
		private static function Unescape($Text)
526
		{
527
			return str_replace(array('\:', '\;', '\,', "\n"), array(':', ';', ',', ''), $Text);
528
		}
529
530
		/**
531
		 * Separates the various parts of a structured value according to the spec.
532
		 *
533
		 * @access private
534
		 *
535
		 * @param string Raw text string
536
		 * @param string Key (e.g., N, ADR, ORG, etc.)
537
		 *
538
		 * @return array Parts in an associative array.
539
		 */
540
		private static function ParseStructuredValue($Text, $Key)
541
		{
542
			$Text = array_map('trim', explode(';', $Text));
543
544
			$Result = array();
545
			$Ctr = 0;
0 ignored issues
show
$Ctr is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
546
547
			foreach (self::$Spec_StructuredElements[$Key] as $Index => $StructurePart)
548
			{
549
				$Result[$StructurePart] = isset($Text[$Index]) ? $Text[$Index] : null;
550
			}
551
			return $Result;
552
		}
553
554
		/**
555
		 * @access private
556
		 */
557
		private static function ParseMultipleTextValue($Text)
558
		{
559
			return explode(',', $Text);
560
		}
561
562
		/**
563
		 * @access private
564
		 */
565
		private static function ParseParameters($Key, array $RawParams = null)
566
		{
567
			if (!$RawParams)
568
			{
569
				return array();
570
			}
571
572
			// Parameters are split into (key, value) pairs
573
			$Parameters = array();
574
			foreach ($RawParams as $Item)
575
			{
576
				$Parameters[] = explode('=', strtolower($Item));
577
			}
578
579
			$Type = array();
580
			$Result = array();
581
582
			// And each parameter is checked whether anything can/should be done because of it
583
			foreach ($Parameters as $Index => $Parameter)
584
			{
585
				// Skipping empty elements
586
				if (!$Parameter)
587
				{
588
					continue;
589
				}
590
591
				// Handling type parameters without the explicit TYPE parameter name (2.1 valid)
592
				if (count($Parameter) == 1)
593
				{
594
					// Checks if the type value is allowed for the specific element
595
					// The second part of the "if" statement means that email elements can have non-standard types (see the spec)
596
					if (
597
						(isset(self::$Spec_ElementTypes[$Key]) && in_array($Parameter[0], self::$Spec_ElementTypes[$Key])) ||
598
						($Key == 'email' && is_scalar($Parameter[0]))
599
					)
600
					{
601
						$Type[] = $Parameter[0];
602
					}
603
				}
604
				elseif (count($Parameter) > 2)
605
				{
606
					if(count(explode(',', $RawParams[$Index], -1)) > 0)
607
					{
608
						$TempTypeParams = self::ParseParameters($Key, explode(',', $RawParams[$Index]));
609
						if ($TempTypeParams['type'])
610
						{
611
							$Type = array_merge($Type, $TempTypeParams['type']);
612
						}
613
					}
614
				}
615
				else
616
				{
617
					switch ($Parameter[0])
618
					{
619
						case 'encoding':
620
							if (in_array($Parameter[1], array('quoted-printable', 'b', 'base64')))
621
							{
622
								$Result['encoding'] = $Parameter[1] == 'base64' ? 'b' : $Parameter[1];
623
							}
624
							break;
625
						case 'charset':
626
							$Result['charset'] = $Parameter[1];
627
							break;
628
						case 'type':
629
							$Type = array_merge($Type, explode(',', $Parameter[1]));
630
							break;
631
						case 'value':
632
							if (strtolower($Parameter[1]) == 'url')
633
							{
634
								$Result['encoding'] = 'uri';
635
							}
636
							break;
637
					}
638
				}
639
			}
640
641
			$Result['type'] = $Type;
642
643
			return $Result;
644
		}
645
646
		// !Interface methods
647
648
		// Countable interface
649
		public function count()
650
		{
651
			switch ($this -> Mode)
652
			{
653
				case self::MODE_ERROR:
654
					return 0;
655
					break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
656
				case self::MODE_SINGLE:
657
					return 1;
658
					break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
659
				case self::MODE_MULTIPLE:
660
					return count($this -> Data);
661
					break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
662
			}
663
			return 0;
664
		}
665
666
		// Iterator interface
667
		public function rewind()
668
		{
669
			reset($this -> Data);
670
		}
671
672
		public function current()
673
		{
674
			return current($this -> Data);
675
		}
676
677
		public function next()
678
		{
679
			return next($this -> Data);
680
		}
681
682
		public function valid()
683
		{
684
			return ($this -> current() !== false);
685
		}
686
687
		public function key()
688
		{
689
			return key($this -> Data);
690
		}
691
	}
692
?>
0 ignored issues
show
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
693