Issues (1513)

lib/utils/utils.php (33 issues)

1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
5
 * SPDX-FileCopyrightText: Copyright 2020-2024 grommunio GmbH
6
 *
7
 * Several utility functions
8
 */
9
10
class Utils {
11
	/**
12
	 * Prints a variable as string
13
	 * If a boolean is sent, 'true' or 'false' is displayed.
14
	 *
15
	 * @param string $var
16
	 *
17
	 * @return string
18
	 */
19
	public static function PrintAsString($var) {
20
		return ($var) ? (($var === true) ? 'true' : $var) : (($var === false) ? 'false' : (($var === '') ? 'empty' : (($var === null) ? 'null' : $var)));
0 ignored issues
show
The condition $var === true is always false.
Loading history...
The condition $var === false is always false.
Loading history...
The condition $var === null is always false.
Loading history...
21
	}
22
23
	/**
24
	 * Splits a "domain\user" string into two values
25
	 * If the string contains only the user, domain is returned empty.
26
	 *
27
	 * @param string $domainuser
28
	 *
29
	 * @return array index 0: user  1: domain
30
	 */
31
	public static function SplitDomainUser($domainuser) {
32
		$pos = strrpos($domainuser, '\\');
33
		if ($pos === false) {
34
			$user = $domainuser;
35
			$domain = '';
36
		}
37
		else {
38
			$domain = substr($domainuser, 0, $pos);
39
			$user = substr($domainuser, $pos + 1);
40
		}
41
42
		return [$user, $domain];
43
	}
44
45
	/**
46
	 * Build an address string from the components.
47
	 *
48
	 * @param string $street  the street
49
	 * @param string $zip     the zip code
50
	 * @param string $city    the city
51
	 * @param string $state   the state
52
	 * @param string $country the country
53
	 *
54
	 * @return string the address string or null
55
	 */
56
	public static function BuildAddressString($street, $zip, $city, $state, $country) {
57
		$out = $country ?? "";
58
59
		$zcs = $zip ?? "";
60
		if ($city != "") {
61
			$zcs .= (($zcs) ? " " : "") . $city;
62
		}
63
		if ($state != "") {
64
			$zcs .= (($zcs) ? " " : "") . $state;
65
		}
66
		if ($zcs) {
67
			$out = $zcs . "\r\n" . $out;
68
		}
69
70
		if ($street != "") {
71
			$out = $street . (($out) ? "\r\n\r\n" . $out : "");
72
		}
73
74
		return $out ?? null;
75
	}
76
77
	/**
78
	 * Build the fileas string from the components according to the configuration.
79
	 *
80
	 * @param string $lastname
81
	 * @param string $firstname
82
	 * @param string $middlename
83
	 * @param string $company
84
	 *
85
	 * @return string fileas
86
	 */
87
	public static function BuildFileAs($lastname = "", $firstname = "", $middlename = "", $company = "") {
88
		if (defined('FILEAS_ORDER')) {
89
			$fileas = $lastfirst = $firstlast = "";
90
			$names = trim($firstname . " " . $middlename);
91
			$lastname = trim($lastname);
92
			$company = trim($company);
93
94
			// lastfirst is "lastname, firstname middlename"
95
			// firstlast is "firstname middlename lastname"
96
			if (strlen($lastname) > 0) {
97
				$lastfirst = $lastname;
98
				if (strlen($names) > 0) {
99
					$lastfirst .= ", {$names}";
100
					$firstlast = "{$names} {$lastname}";
101
				}
102
				else {
103
					$firstlast = $lastname;
104
				}
105
			}
106
			elseif (strlen($names) > 0) {
107
				$lastfirst = $firstlast = $names;
108
			}
109
110
			// if fileas with a company is selected
111
			// but company is empty then it will
112
			// fallback to firstlast or lastfirst
113
			// (depending on which is selected for company)
114
			switch (FILEAS_ORDER) {
115
				case SYNC_FILEAS_COMPANYONLY:
116
					if (strlen($company) > 0) {
117
						$fileas = $company;
118
					}
119
					elseif (strlen($firstlast) > 0) {
120
						$fileas = $lastfirst;
121
					}
122
					break;
123
124
				case SYNC_FILEAS_COMPANYLAST:
125
					if (strlen($company) > 0) {
126
						$fileas = $company;
127
						if (strlen($lastfirst) > 0) {
128
							$fileas .= "({$lastfirst})";
129
						}
130
					}
131
					elseif (strlen($lastfirst) > 0) {
132
						$fileas = $lastfirst;
133
					}
134
					break;
135
136
				case SYNC_FILEAS_COMPANYFIRST:
137
					if (strlen($company) > 0) {
138
						$fileas = $company;
139
						if (strlen($firstlast) > 0) {
140
							$fileas .= " ({$firstlast})";
141
						}
142
					}
143
					elseif (strlen($firstlast) > 0) {
144
						$fileas = $firstlast;
145
					}
146
					break;
147
148
				case SYNC_FILEAS_FIRSTCOMPANY:
149
					if (strlen($firstlast) > 0) {
150
						$fileas = $firstlast;
151
						if (strlen($company) > 0) {
152
							$fileas .= " ({$company})";
153
						}
154
					}
155
					elseif (strlen($company) > 0) {
156
						$fileas = $company;
157
					}
158
					break;
159
160
				case SYNC_FILEAS_LASTCOMPANY:
161
					if (strlen($lastfirst) > 0) {
162
						$fileas = $lastfirst;
163
						if (strlen($company) > 0) {
164
							$fileas .= " ({$company})";
165
						}
166
					}
167
					elseif (strlen($company) > 0) {
168
						$fileas = $company;
169
					}
170
					break;
171
172
				case SYNC_FILEAS_LASTFIRST:
173
					if (strlen($lastfirst) > 0) {
174
						$fileas = $lastfirst;
175
					}
176
					break;
177
178
				default:
179
					$fileas = $firstlast;
180
					break;
181
			}
182
			if (strlen($fileas) == 0) {
183
				SLog::Write(LOGLEVEL_DEBUG, "Fileas is empty.");
184
			}
185
186
			return $fileas;
187
		}
188
		SLog::Write(LOGLEVEL_DEBUG, "FILEAS_ORDER not defined. Add it to your config.php.");
189
190
		return null;
191
	}
192
193
	/**
194
	 * Extracts the basedate of the GlobalObjectID and the RecurStartTime.
195
	 *
196
	 * @param string $goid           OL compatible GlobalObjectID
197
	 * @param long   $recurStartTime
0 ignored issues
show
The type long was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
198
	 *
199
	 * @return long basedate
200
	 */
201
	public static function ExtractBaseDate($goid, $recurStartTime) {
202
		$hexbase = substr(bin2hex($goid), 32, 8);
203
		$day = hexdec(substr($hexbase, 6, 2));
204
		$month = hexdec(substr($hexbase, 4, 2));
205
		$year = hexdec(substr($hexbase, 0, 4));
206
207
		if ($day && $month && $year) {
208
			$h = $recurStartTime >> 12;
209
			$m = ($recurStartTime - $h * 4096) >> 6;
210
			$s = $recurStartTime - $h * 4096 - $m * 64;
211
212
			return gmmktime($h, $m, $s, $month, $day, $year);
0 ignored issues
show
Bug Best Practice introduced by
The expression return gmmktime($h, $m, $s, $month, $day, $year) returns the type integer which is incompatible with the documented return type long.
Loading history...
It seems like $month can also be of type double; however, parameter $month of gmmktime() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

212
			return gmmktime($h, $m, $s, /** @scrutinizer ignore-type */ $month, $day, $year);
Loading history...
It seems like $day can also be of type double; however, parameter $day of gmmktime() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

212
			return gmmktime($h, $m, $s, $month, /** @scrutinizer ignore-type */ $day, $year);
Loading history...
It seems like $year can also be of type double; however, parameter $year of gmmktime() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

212
			return gmmktime($h, $m, $s, $month, $day, /** @scrutinizer ignore-type */ $year);
Loading history...
213
		}
214
215
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type long.
Loading history...
216
	}
217
218
	/**
219
	 * Converts SYNC_FILTERTYPE into a timestamp.
220
	 *
221
	 * @param int $filtertype Filtertype
222
	 *
223
	 * @return long
224
	 */
225
	public static function GetCutOffDate($filtertype) {
226
		$back = Utils::GetFiltertypeInterval($filtertype);
227
228
		if ($back === false) {
229
			return 0; // unlimited
0 ignored issues
show
Bug Best Practice introduced by
The expression return 0 returns the type integer which is incompatible with the documented return type long.
Loading history...
230
		}
231
232
		return time() - $back;
0 ignored issues
show
Bug Best Practice introduced by
The expression return time() - $back returns the type integer which is incompatible with the documented return type long.
Loading history...
233
	}
234
235
	/**
236
	 * Returns the interval indicated by the filtertype.
237
	 *
238
	 * @param int $filtertype
239
	 *
240
	 * @return bool|long returns false on invalid filtertype
241
	 */
242
	public static function GetFiltertypeInterval($filtertype) {
243
		$back = false;
244
245
		switch ($filtertype) {
246
			case SYNC_FILTERTYPE_1DAY:
247
				$back = 60 * 60 * 24;
248
				break;
249
250
			case SYNC_FILTERTYPE_3DAYS:
251
				$back = 60 * 60 * 24 * 3;
252
				break;
253
254
			case SYNC_FILTERTYPE_1WEEK:
255
				$back = 60 * 60 * 24 * 7;
256
				break;
257
258
			case SYNC_FILTERTYPE_2WEEKS:
259
				$back = 60 * 60 * 24 * 14;
260
				break;
261
262
			case SYNC_FILTERTYPE_1MONTH:
263
				$back = 60 * 60 * 24 * 31;
264
				break;
265
266
			case SYNC_FILTERTYPE_3MONTHS:
267
				$back = 60 * 60 * 24 * 31 * 3;
268
				break;
269
270
			case SYNC_FILTERTYPE_6MONTHS:
271
				$back = 60 * 60 * 24 * 31 * 6;
272
				break;
273
274
			default:
275
				$back = false;
276
		}
277
278
		return $back;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $back also could return the type integer which is incompatible with the documented return type boolean|long.
Loading history...
279
	}
280
281
	/**
282
	 * Converts SYNC_TRUNCATION into bytes.
283
	 *
284
	 * @param int       SYNC_TRUNCATION
0 ignored issues
show
The type SYNC_TRUNCATION was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
285
	 * @param mixed $truncation
286
	 *
287
	 * @return long
288
	 */
289
	public static function GetTruncSize($truncation) {
290
		switch ($truncation) {
291
			case SYNC_TRUNCATION_HEADERS:
292
				return 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 0 returns the type integer which is incompatible with the documented return type long.
Loading history...
293
294
			case SYNC_TRUNCATION_512B:
295
				return 512;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 512 returns the type integer which is incompatible with the documented return type long.
Loading history...
296
297
			case SYNC_TRUNCATION_1K:
298
				return 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
299
300
			case SYNC_TRUNCATION_2K:
301
				return 2 * 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 2 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
302
303
			case SYNC_TRUNCATION_5K:
304
				return 5 * 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 5 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
305
306
			case SYNC_TRUNCATION_10K:
307
				return 10 * 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 10 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
308
309
			case SYNC_TRUNCATION_20K:
310
				return 20 * 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 20 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
311
312
			case SYNC_TRUNCATION_50K:
313
				return 50 * 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 50 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
314
315
			case SYNC_TRUNCATION_100K:
316
				return 100 * 1024;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 100 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
317
318
			case SYNC_TRUNCATION_ALL:
319
				return 1024 * 1024; // We'll limit to 1MB anyway
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1024 * 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
320
321
			default:
322
				return 1024; // Default to 1Kb
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1024 returns the type integer which is incompatible with the documented return type long.
Loading history...
323
		}
324
	}
325
326
	/**
327
	 * Truncate an UTF-8 encoded string correctly.
328
	 *
329
	 * If it's not possible to truncate properly, an empty string is returned
330
	 *
331
	 * @param string $string   the string
332
	 * @param string $length   position where string should be cut
333
	 * @param bool   $htmlsafe doesn't cut html tags in half, doesn't ensure correct html - default: false
334
	 *
335
	 * @return string truncated string
336
	 */
337
	public static function Utf8_truncate($string, $length, $htmlsafe = false) {
338
		// skip empty strings
339
		if (empty($string)) {
340
			return "";
341
		}
342
343
		// make sure length is always an integer
344
		$length = (int) $length;
345
346
		// if the input string is shorter then the trunction, make sure it's valid UTF-8!
347
		if (strlen($string) <= $length) {
348
			$length = strlen($string) - 1;
349
		}
350
351
		// The intent is not to cut HTML tags in half which causes displaying issues.
352
		// The used method just tries to cut outside of tags, without checking tag validity and closing tags.
353
		if ($htmlsafe) {
354
			$offset = 0 - strlen($string) + $length;
355
			$validPos = strrpos($string, "<", $offset);
356
			if ($validPos > strrpos($string, ">", $offset)) {
357
				$length = $validPos;
358
			}
359
		}
360
361
		while ($length >= 0) {
362
			if ((ord($string[$length]) < 0x80) || (ord($string[$length]) >= 0xC0)) {
363
				return substr($string, 0, $length);
364
			}
365
			--$length;
366
		}
367
368
		return "";
369
	}
370
371
	/**
372
	 * Indicates if the specified folder type is a system folder.
373
	 *
374
	 * @param int $foldertype
375
	 *
376
	 * @return bool
377
	 */
378
	public static function IsSystemFolder($foldertype) {
379
		return (
380
			$foldertype == SYNC_FOLDER_TYPE_INBOX ||
381
			$foldertype == SYNC_FOLDER_TYPE_DRAFTS ||
382
			$foldertype == SYNC_FOLDER_TYPE_WASTEBASKET ||
383
			$foldertype == SYNC_FOLDER_TYPE_SENTMAIL ||
384
			$foldertype == SYNC_FOLDER_TYPE_OUTBOX ||
385
			$foldertype == SYNC_FOLDER_TYPE_TASK ||
386
			$foldertype == SYNC_FOLDER_TYPE_APPOINTMENT ||
387
			$foldertype == SYNC_FOLDER_TYPE_CONTACT ||
388
			$foldertype == SYNC_FOLDER_TYPE_NOTE ||
389
			$foldertype == SYNC_FOLDER_TYPE_JOURNAL
390
		) ? true : false;
391
	}
392
393
	/**
394
	 * Checks for valid email addresses
395
	 * The used regex actually only checks if a valid email address is part of the submitted string
396
	 * it also returns true for the mailbox format, but this is not checked explicitly.
397
	 *
398
	 * @param string $email address to be checked
399
	 *
400
	 * @return bool
401
	 */
402
	public static function CheckEmail($email) {
403
		return strpos($email, '@') !== false ? true : false;
404
	}
405
406
	/**
407
	 * Checks if a string is base64 encoded.
408
	 *
409
	 * @param string $string the string to be checked
410
	 *
411
	 * @return bool
412
	 */
413
	public static function IsBase64String($string) {
414
		return (bool) preg_match("#^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+/]{4})?$#", $string);
415
	}
416
417
	/**
418
	 * Returns a command string for a given command code.
419
	 *
420
	 * @param int $code
421
	 *
422
	 * @return string or false if code is unknown
423
	 */
424
	public static function GetCommandFromCode($code) {
425
		switch ($code) {
426
			case GSync::COMMAND_SYNC:                 return 'Sync';
427
428
			case GSync::COMMAND_SENDMAIL:             return 'SendMail';
429
430
			case GSync::COMMAND_SMARTFORWARD:         return 'SmartForward';
431
432
			case GSync::COMMAND_SMARTREPLY:           return 'SmartReply';
433
434
			case GSync::COMMAND_GETATTACHMENT:        return 'GetAttachment';
435
436
			case GSync::COMMAND_FOLDERSYNC:           return 'FolderSync';
437
438
			case GSync::COMMAND_FOLDERCREATE:         return 'FolderCreate';
439
440
			case GSync::COMMAND_FOLDERDELETE:         return 'FolderDelete';
441
442
			case GSync::COMMAND_FOLDERUPDATE:         return 'FolderUpdate';
443
444
			case GSync::COMMAND_MOVEITEMS:            return 'MoveItems';
445
446
			case GSync::COMMAND_GETITEMESTIMATE:      return 'GetItemEstimate';
447
448
			case GSync::COMMAND_MEETINGRESPONSE:      return 'MeetingResponse';
449
450
			case GSync::COMMAND_SEARCH:               return 'Search';
451
452
			case GSync::COMMAND_SETTINGS:             return 'Settings';
453
454
			case GSync::COMMAND_PING:                 return 'Ping';
455
456
			case GSync::COMMAND_ITEMOPERATIONS:       return 'ItemOperations';
457
458
			case GSync::COMMAND_PROVISION:            return 'Provision';
459
460
			case GSync::COMMAND_RESOLVERECIPIENTS:    return 'ResolveRecipients';
461
462
			case GSync::COMMAND_VALIDATECERT:         return 'ValidateCert';
463
464
				// Deprecated commands
465
			case GSync::COMMAND_GETHIERARCHY:         return 'GetHierarchy';
466
467
			case GSync::COMMAND_CREATECOLLECTION:     return 'CreateCollection';
468
469
			case GSync::COMMAND_DELETECOLLECTION:     return 'DeleteCollection';
470
471
			case GSync::COMMAND_MOVECOLLECTION:       return 'MoveCollection';
472
473
			case GSync::COMMAND_NOTIFY:               return 'Notify';
474
475
			case GSync::COMMAND_FIND:                 return 'Find';
476
		}
477
478
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
479
	}
480
481
	/**
482
	 * Returns a command code for a given command.
483
	 *
484
	 * @param string $command
485
	 *
486
	 * @return int or false if command is unknown
487
	 */
488
	public static function GetCodeFromCommand($command) {
489
		switch ($command) {
490
			case 'Sync':                 return GSync::COMMAND_SYNC;
491
492
			case 'SendMail':             return GSync::COMMAND_SENDMAIL;
493
494
			case 'SmartForward':         return GSync::COMMAND_SMARTFORWARD;
495
496
			case 'SmartReply':           return GSync::COMMAND_SMARTREPLY;
497
498
			case 'GetAttachment':        return GSync::COMMAND_GETATTACHMENT;
499
500
			case 'FolderSync':           return GSync::COMMAND_FOLDERSYNC;
501
502
			case 'FolderCreate':         return GSync::COMMAND_FOLDERCREATE;
503
504
			case 'FolderDelete':         return GSync::COMMAND_FOLDERDELETE;
505
506
			case 'FolderUpdate':         return GSync::COMMAND_FOLDERUPDATE;
507
508
			case 'MoveItems':            return GSync::COMMAND_MOVEITEMS;
509
510
			case 'GetItemEstimate':      return GSync::COMMAND_GETITEMESTIMATE;
511
512
			case 'MeetingResponse':      return GSync::COMMAND_MEETINGRESPONSE;
513
514
			case 'Search':               return GSync::COMMAND_SEARCH;
515
516
			case 'Settings':             return GSync::COMMAND_SETTINGS;
517
518
			case 'Ping':                 return GSync::COMMAND_PING;
519
520
			case 'ItemOperations':       return GSync::COMMAND_ITEMOPERATIONS;
521
522
			case 'Provision':            return GSync::COMMAND_PROVISION;
523
524
			case 'ResolveRecipients':    return GSync::COMMAND_RESOLVERECIPIENTS;
525
526
			case 'ValidateCert':         return GSync::COMMAND_VALIDATECERT;
527
528
				// Deprecated commands
529
			case 'GetHierarchy':         return GSync::COMMAND_GETHIERARCHY;
530
531
			case 'CreateCollection':     return GSync::COMMAND_CREATECOLLECTION;
532
533
			case 'DeleteCollection':     return GSync::COMMAND_DELETECOLLECTION;
534
535
			case 'MoveCollection':       return GSync::COMMAND_MOVECOLLECTION;
536
537
			case 'Notify':               return GSync::COMMAND_NOTIFY;
538
539
			case 'Find':                 return GSync::COMMAND_FIND;
540
		}
541
542
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
543
	}
544
545
	/**
546
	 * Normalize the given timestamp to the start of the day.
547
	 *
548
	 * @param long $timestamp
549
	 *
550
	 * @return long
551
	 */
552
	public static function getDayStartOfTimestamp($timestamp) {
553
		return $timestamp - ($timestamp % (60 * 60 * 24));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $timestamp - $timestamp % 60 * 60 * 24 returns the type integer which is incompatible with the documented return type long.
Loading history...
554
	}
555
556
	/**
557
	 * Returns a formatted string output from an optional timestamp.
558
	 * If no timestamp is sent, NOW is used.
559
	 *
560
	 * @param long $timestamp
561
	 *
562
	 * @return string
563
	 */
564
	public static function GetFormattedTime($timestamp = false) {
565
		if (!$timestamp) {
566
			$timestamp = time();
567
		}
568
569
		return date("d/m/Y H:i:s", $timestamp);
0 ignored issues
show
It seems like $timestamp can also be of type long; however, parameter $timestamp of date() does only seem to accept integer|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

569
		return date("d/m/Y H:i:s", /** @scrutinizer ignore-type */ $timestamp);
Loading history...
570
	}
571
572
	/**
573
	 * Get charset name from a codepage.
574
	 *
575
	 * @see http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
576
	 *
577
	 * Table taken from common/codepage.cpp
578
	 *
579
	 * @param int codepage Codepage
0 ignored issues
show
The type codepage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
580
	 * @param mixed $codepage
581
	 *
582
	 * @return string iconv-compatible charset name
583
	 */
584
	public static function GetCodepageCharset($codepage) {
585
		$codepages = [
586
			20106 => "DIN_66003",
587
			20108 => "NS_4551-1",
588
			20107 => "SEN_850200_B",
589
			950 => "big5",
590
			50221 => "csISO2022JP",
591
			51932 => "euc-jp",
592
			51936 => "euc-cn",
593
			51949 => "euc-kr",
594
			949 => "euc-kr",
595
			936 => "gb18030",
596
			52936 => "csgb2312",
597
			852 => "ibm852",
598
			866 => "ibm866",
599
			50220 => "iso-2022-jp",
600
			50222 => "iso-2022-jp",
601
			50225 => "iso-2022-kr",
602
			1252 => "windows-1252",
603
			28591 => "iso-8859-1",
604
			28592 => "iso-8859-2",
605
			28593 => "iso-8859-3",
606
			28594 => "iso-8859-4",
607
			28595 => "iso-8859-5",
608
			28596 => "iso-8859-6",
609
			28597 => "iso-8859-7",
610
			28598 => "iso-8859-8",
611
			28599 => "iso-8859-9",
612
			28603 => "iso-8859-13",
613
			28605 => "iso-8859-15",
614
			20866 => "koi8-r",
615
			21866 => "koi8-u",
616
			932 => "shift-jis",
617
			1200 => "unicode",
618
			1201 => "unicodebig",
619
			65000 => "utf-7",
620
			65001 => "utf-8",
621
			1250 => "windows-1250",
622
			1251 => "windows-1251",
623
			1253 => "windows-1253",
624
			1254 => "windows-1254",
625
			1255 => "windows-1255",
626
			1256 => "windows-1256",
627
			1257 => "windows-1257",
628
			1258 => "windows-1258",
629
			874 => "windows-874",
630
			20127 => "us-ascii",
631
		];
632
633
		if (isset($codepages[$codepage])) {
634
			return $codepages[$codepage];
635
		}
636
637
		// Defaulting to iso-8859-15 since it is more likely for someone to make a mistake in the codepage
638
		// when using west-european charsets then when using other charsets since utf-8 is binary compatible
639
		// with the bottom 7 bits of west-european
640
		return "iso-8859-15";
641
	}
642
643
	/**
644
	 * Converts a string encoded with codepage into an UTF-8 string.
645
	 *
646
	 * @param int    $codepage
647
	 * @param string $string
648
	 *
649
	 * @return string
650
	 */
651
	public static function ConvertCodepageStringToUtf8($codepage, $string) {
652
		if (function_exists("iconv")) {
653
			$charset = self::GetCodepageCharset($codepage);
654
655
			return iconv($charset, "utf-8", $string);
656
		}
657
658
		SLog::Write(LOGLEVEL_WARN, "Utils::ConvertCodepageStringToUtf8() 'iconv' is not available. Charset conversion skipped.");
659
660
		return $string;
661
	}
662
663
	/**
664
	 * Converts a string to another charset.
665
	 *
666
	 * @param int    $in
667
	 * @param int    $out
668
	 * @param string $string
669
	 *
670
	 * @return string
671
	 */
672
	public static function ConvertCodepage($in, $out, $string) {
673
		// do nothing if both charsets are the same
674
		if ($in == $out) {
675
			return $string;
676
		}
677
678
		if (function_exists("iconv")) {
679
			$inCharset = self::GetCodepageCharset($in);
680
			$outCharset = self::GetCodepageCharset($out);
681
682
			return iconv($inCharset, $outCharset, $string);
683
		}
684
685
		SLog::Write(LOGLEVEL_WARN, "Utils::ConvertCodepage() 'iconv' is not available. Charset conversion skipped.");
686
687
		return $string;
688
	}
689
690
	/**
691
	 * Returns the best match of preferred body preference types.
692
	 *
693
	 * @param array $bpTypes
694
	 *
695
	 * @return int
696
	 */
697
	public static function GetBodyPreferenceBestMatch($bpTypes) {
698
		if ($bpTypes === false) {
0 ignored issues
show
The condition $bpTypes === false is always false.
Loading history...
699
			return SYNC_BODYPREFERENCE_PLAIN;
700
		}
701
		// The bettter choice is HTML and then MIME in order to save bandwidth
702
		// because MIME is a complete message including the headers and attachments
703
		if (in_array(SYNC_BODYPREFERENCE_HTML, $bpTypes)) {
704
			return SYNC_BODYPREFERENCE_HTML;
705
		}
706
		if (in_array(SYNC_BODYPREFERENCE_MIME, $bpTypes)) {
707
			return SYNC_BODYPREFERENCE_MIME;
708
		}
709
710
		return SYNC_BODYPREFERENCE_PLAIN;
711
	}
712
713
	/**
714
	 * Returns AS-style LastVerbExecuted value from the server value.
715
	 *
716
	 * @param int $verb
717
	 *
718
	 * @return int
719
	 */
720
	public static function GetLastVerbExecuted($verb) {
721
		switch ($verb) {
722
			case NOTEIVERB_REPLYTOSENDER:   return AS_REPLYTOSENDER;
723
724
			case NOTEIVERB_REPLYTOALL:      return AS_REPLYTOALL;
725
726
			case NOTEIVERB_FORWARD:         return AS_FORWARD;
727
		}
728
729
		return 0;
730
	}
731
732
	/**
733
	 * Returns the local part from email address.
734
	 *
735
	 * @param string $email
736
	 *
737
	 * @return string
738
	 */
739
	public static function GetLocalPartFromEmail($email) {
740
		$pos = strpos($email, '@');
741
		if ($pos === false) {
742
			return $email;
743
		}
744
745
		return substr($email, 0, $pos);
746
	}
747
748
	/**
749
	 * Format bytes to a more human readable value.
750
	 *
751
	 * @param int $bytes
752
	 * @param int $precision
753
	 *
754
	 * @return string|void
755
	 */
756
	public static function FormatBytes($bytes, $precision = 2) {
757
		if ($bytes <= 0) {
758
			return '0 B';
759
		}
760
761
		$units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB'];
762
		$base = log($bytes, 1024);
763
		$fBase = floor($base);
764
		$pow = pow(1024, $base - $fBase);
765
766
		return sprintf("%.{$precision}f %s", $pow, $units[$fBase]);
767
	}
768
769
	/**
770
	 * Returns folder origin identifier from its id.
771
	 *
772
	 * @param string $folderid
773
	 *
774
	 * @return bool|string matches values of DeviceManager::FLD_ORIGIN_*
775
	 */
776
	public static function GetFolderOriginFromId($folderid) {
777
		$origin = substr($folderid, 0, 1);
778
779
		switch ($origin) {
780
			case DeviceManager::FLD_ORIGIN_CONFIG:
781
			case DeviceManager::FLD_ORIGIN_GAB:
782
			case DeviceManager::FLD_ORIGIN_SHARED:
783
			case DeviceManager::FLD_ORIGIN_USER:
784
			case DeviceManager::FLD_ORIGIN_IMPERSONATED:
785
				return $origin;
786
		}
787
		SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginFromId(): Unknown folder origin for folder with id '%s'", $folderid));
788
789
		return false;
790
	}
791
792
	/**
793
	 * Returns folder origin as string from its id.
794
	 *
795
	 * @param string $folderid
796
	 *
797
	 * @return string
798
	 */
799
	public static function GetFolderOriginStringFromId($folderid) {
800
		$origin = substr($folderid, 0, 1);
801
802
		switch ($origin) {
803
			case DeviceManager::FLD_ORIGIN_CONFIG:
804
				return 'configured';
805
806
			case DeviceManager::FLD_ORIGIN_GAB:
807
				return 'GAB';
808
809
			case DeviceManager::FLD_ORIGIN_SHARED:
810
				return 'shared';
811
812
			case DeviceManager::FLD_ORIGIN_USER:
813
				return 'user';
814
815
			case DeviceManager::FLD_ORIGIN_IMPERSONATED:
816
				return 'impersonated';
817
		}
818
		SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginStringFromId(): Unknown folder origin for folder with id '%s'", $folderid));
819
820
		return 'unknown';
821
	}
822
823
	/**
824
	 * Splits the id into folder id and message id parts. A colon in the $id indicates
825
	 * that the id has folderid:messageid format.
826
	 *
827
	 * @param string $id
828
	 *
829
	 * @return array
830
	 */
831
	public static function SplitMessageId($id) {
832
		if (strpos($id, ':') !== false) {
833
			return explode(':', $id);
834
		}
835
836
		return [null, $id];
837
	}
838
839
	/**
840
	 * Transforms an AS timestamp into a unix timestamp.
841
	 *
842
	 * @param string $ts
843
	 *
844
	 * @return long
845
	 */
846
	public static function ParseDate($ts) {
847
		if (preg_match("/(\\d{4})[^0-9]*(\\d{2})[^0-9]*(\\d{2})(T(\\d{2})[^0-9]*(\\d{2})[^0-9]*(\\d{2})(.\\d+)?Z){0,1}$/", $ts, $matches)) {
848
			if ($matches[1] >= 2038) {
849
				$matches[1] = 2038;
850
				$matches[2] = 1;
851
				$matches[3] = 18;
852
				$matches[5] = $matches[6] = $matches[7] = 0;
853
			}
854
855
			if (!isset($matches[5])) {
856
				$matches[5] = 0;
857
			}
858
			if (!isset($matches[6])) {
859
				$matches[6] = 0;
860
			}
861
			if (!isset($matches[7])) {
862
				$matches[7] = 0;
863
			}
864
865
			return gmmktime($matches[5], $matches[6], $matches[7], $matches[2], $matches[3], $matches[1]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return gmmktime($matches...atches[3], $matches[1]) returns the type integer which is incompatible with the documented return type long.
Loading history...
866
		}
867
868
		return 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 0 returns the type integer which is incompatible with the documented return type long.
Loading history...
869
	}
870
871
	/**
872
	 * Transforms an unix timestamp into an AS timestamp or a human readable format.
873
	 *
874
	 * Oh yeah, this is beautiful. Exchange outputs date fields differently in calendar items
875
	 * and emails. We could just always send one or the other, but unfortunately nokia's 'Mail for
876
	 * exchange' depends on this quirk. So we have to send a different date type depending on where
877
	 * it's used. Sigh.
878
	 *
879
	 * @param int $ts
880
	 * @param int $type int (StreamerType) (optional) if not set a human readable format is returned
881
	 *
882
	 * @return string
883
	 */
884
	public static function FormatDate($ts, $type = "") {
885
		// fallback to a human readable format (used for logging)
886
		$formatString = "yyyy-MM-dd HH:mm:SS' UTC'";
887
		if ($type == Streamer::STREAMER_TYPE_DATE) {
888
			$formatString = "yyyyMMdd'T'HHmmSS'Z'";
889
		}
890
		elseif ($type == Streamer::STREAMER_TYPE_DATE_DASHES) {
891
			$formatString = "yyyy-MM-dd'T'HH:mm:SS'.000Z'";
892
		}
893
894
		$formatter = datefmt_create(
895
			'en_US',
896
			IntlDateFormatter::FULL,
897
			IntlDateFormatter::FULL,
898
			'UTC',
899
			IntlDateFormatter::GREGORIAN,
900
			$formatString
901
		);
902
903
		return datefmt_format($formatter, $ts);
904
	}
905
906
	/**
907
	 * Returns the appropriate SyncObjectResponse object based on message class.
908
	 *
909
	 * @param string $messageClass
910
	 *
911
	 * @return object
912
	 */
913
	public static function GetResponseFromMessageClass($messageClass) {
914
		$messageClass = strtolower($messageClass);
915
916
		switch ($messageClass) {
917
			case 'syncappointment':
918
				return new SyncAppointmentResponse();
919
920
			case 'synccontact':
921
				return new SyncContactResponse();
922
923
			case 'syncnote':
924
				return new SyncNoteResponse();
925
926
			case 'synctask':
927
				return new SyncTaskResponse();
928
929
			default:
930
				return new SyncMailResponse();
931
		}
932
933
		return new SyncMailResponse();
0 ignored issues
show
return new SyncMailResponse() is not 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...
934
	}
935
}
936