Passed
Push — master ( 34e8da...f497d2 )
by
unknown
06:10 queued 02:50
created
lib/utils/timezoneutil.php 3 patches
Indentation   +1398 added lines, -1398 removed lines patch added patch discarded remove patch
@@ -8,1402 +8,1402 @@
 block discarded – undo
8 8
  */
9 9
 
10 10
 class TimezoneUtil {
11
-	/**
12
-	 * list of MS and AS compatible timezones.
13
-	 *
14
-	 * origin: http://msdn.microsoft.com/en-us/library/ms912391%28v=winembedded.11%29.aspx
15
-	 * dots of tz identifiers were removed
16
-	 *
17
-	 * Updated at: 01.06.2012
18
-	 */
19
-	private static $mstzones = [
20
-		"000" => ["Dateline Standard Time",                    "(GMT-12:00) International Date Line West"],
21
-		"001" => ["Samoa Standard Time",                       "(GMT-11:00) Midway Island, Samoa"],
22
-		"002" => ["Hawaiian Standard Time",                    "(GMT-10:00) Hawaii"],
23
-		"003" => ["Alaskan Standard Time",                     "(GMT-09:00) Alaska"],
24
-		"004" => ["Pacific Standard Time",                     "(GMT-08:00) Pacific Time (US and Canada); Tijuana"],
25
-		"010" => ["Mountain Standard Time",                    "(GMT-07:00) Mountain Time (US and Canada)"],
26
-		"013" => ["Mexico Standard Time 2",                    "(GMT-07:00) Chihuahua, La Paz, Mazatlan"],
27
-		"015" => ["US Mountain Standard Time",                 "(GMT-07:00) Arizona"],
28
-		"020" => ["Central Standard Time",                     "(GMT-06:00) Central Time (US and Canada"],
29
-		"025" => ["Canada Central Standard Time",              "(GMT-06:00) Saskatchewan"],
30
-		"030" => ["Mexico Standard Time",                      "(GMT-06:00) Guadalajara, Mexico City, Monterrey"],
31
-		"033" => ["Central America Standard Time",             "(GMT-06:00) Central America"],
32
-		"035" => ["Eastern Standard Time",                     "(GMT-05:00) Eastern Time (US and Canada)"],
33
-		"040" => ["US Eastern Standard Time",                  "(GMT-05:00) Indiana (East)"],
34
-		"045" => ["SA Pacific Standard Time",                  "(GMT-05:00) Bogota, Lima, Quito"],
35
-		"uk1" => ["Venezuela Standard Time",                   "(GMT-04:30) Caracas"],                     // added
36
-		"050" => ["Atlantic Standard Time",                    "(GMT-04:00) Atlantic Time (Canada)"],
37
-		"055" => ["SA Western Standard Time",                  "(GMT-04:00) Caracas, La Paz"],
38
-		"056" => ["Pacific SA Standard Time",                  "(GMT-04:00) Santiago"],
39
-		"060" => ["Newfoundland and Labrador Standard Time",   "(GMT-03:30) Newfoundland and Labrador"],
40
-		"065" => ["E South America Standard Time",             "(GMT-03:00) Brasilia"],
41
-		"070" => ["SA Eastern Standard Time",                  "(GMT-03:00) Buenos Aires, Georgetown"],
42
-		"073" => ["Greenland Standard Time",                   "(GMT-03:00) Greenland"],
43
-		"075" => ["Mid-Atlantic Standard Time",                "(GMT-02:00) Mid-Atlantic"],
44
-		"080" => ["Azores Standard Time",                      "(GMT-01:00) Azores"],
45
-		"083" => ["Cape Verde Standard Time",                  "(GMT-01:00) Cape Verde Islands"],
46
-		"085" => ["GMT Standard Time",                         "(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London"],
47
-		"090" => ["Greenwich Standard Time",                   "(GMT) Casablanca, Monrovia"],
48
-		"095" => ["Central Europe Standard Time",              "(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague"],
49
-		"100" => ["Central European Standard Time",            "(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb"],
50
-		"105" => ["Romance Standard Time",                     "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"],
51
-		"110" => ["W Europe Standard Time",                    "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
52
-		"111" => ["W. Europe Standard Time",                   "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
53
-		"113" => ["W Central Africa Standard Time",            "(GMT+01:00) West Central Africa"],
54
-		"115" => ["E Europe Standard Time",                    "(GMT+02:00) Bucharest"],
55
-		"120" => ["Egypt Standard Time",                       "(GMT+02:00) Cairo"],
56
-		"125" => ["FLE Standard Time",                         "(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius"],
57
-		"130" => ["GTB Standard Time",                         "(GMT+02:00) Athens, Istanbul, Minsk"],
58
-		"135" => ["Israel Standard Time",                      "(GMT+02:00) Jerusalem"],
59
-		"140" => ["South Africa Standard Time",                "(GMT+02:00) Harare, Pretoria"],
60
-		"145" => ["Russian Standard Time",                     "(GMT+03:00) Moscow, St. Petersburg, Volgograd"],
61
-		"150" => ["Arab Standard Time",                        "(GMT+03:00) Kuwait, Riyadh"],
62
-		"155" => ["E Africa Standard Time",                    "(GMT+03:00) Nairobi"],
63
-		"158" => ["Arabic Standard Time",                      "(GMT+03:00) Baghdad"],
64
-		"160" => ["Iran Standard Time",                        "(GMT+03:30) Tehran"],
65
-		"165" => ["Arabian Standard Time",                     "(GMT+04:00) Abu Dhabi, Muscat"],
66
-		"170" => ["Caucasus Standard Time",                    "(GMT+04:00) Baku, Tbilisi, Yerevan"],
67
-		"175" => ["Transitional Islamic State of Afghanistan Standard Time", "(GMT+04:30) Kabul"],
68
-		"180" => ["Ekaterinburg Standard Time",                "(GMT+05:00) Ekaterinburg"],
69
-		"185" => ["West Asia Standard Time",                   "(GMT+05:00) Islamabad, Karachi, Tashkent"],
70
-		"190" => ["India Standard Time",                       "(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi"],
71
-		"193" => ["Nepal Standard Time",                       "(GMT+05:45) Kathmandu"],
72
-		"195" => ["Central Asia Standard Time",                "(GMT+06:00) Astana, Dhaka"],
73
-		"200" => ["Sri Lanka Standard Time",                   "(GMT+06:00) Sri Jayawardenepura"],
74
-		"201" => ["N Central Asia Standard Time",              "(GMT+06:00) Almaty, Novosibirsk"],
75
-		"203" => ["Myanmar Standard Time",                     "(GMT+06:30) Yangon Rangoon"],
76
-		"205" => ["SE Asia Standard Time",                     "(GMT+07:00) Bangkok, Hanoi, Jakarta"],
77
-		"207" => ["North Asia Standard Time",                  "(GMT+07:00) Krasnoyarsk"],
78
-		"210" => ["China Standard Time",                       "(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi"],
79
-		"215" => ["Singapore Standard Time",                   "(GMT+08:00) Kuala Lumpur, Singapore"],
80
-		"220" => ["Taipei Standard Time",                      "(GMT+08:00) Taipei"],
81
-		"225" => ["W Australia Standard Time",                 "(GMT+08:00) Perth"],
82
-		"227" => ["North Asia East Standard Time",             "(GMT+08:00) Irkutsk, Ulaanbaatar"],
83
-		"230" => ["Korea Standard Time",                       "(GMT+09:00) Seoul"],
84
-		"235" => ["Tokyo Standard Time",                       "(GMT+09:00) Osaka, Sapporo, Tokyo"],
85
-		"240" => ["Yakutsk Standard Time",                     "(GMT+09:00) Yakutsk"],
86
-		"245" => ["AUS Central Standard Time",                 "(GMT+09:30) Darwin"],
87
-		"250" => ["Cen Australia Standard Time",               "(GMT+09:30) Adelaide"],
88
-		"255" => ["AUS Eastern Standard Time",                 "(GMT+10:00) Canberra, Melbourne, Sydney"],
89
-		"260" => ["E Australia Standard Time",                 "(GMT+10:00) Brisbane"],
90
-		"265" => ["Tasmania Standard Time",                    "(GMT+10:00) Hobart"],
91
-		"270" => ["Vladivostok Standard Time",                 "(GMT+10:00) Vladivostok"],
92
-		"275" => ["West Pacific Standard Time",                "(GMT+10:00) Guam, Port Moresby"],
93
-		"280" => ["Central Pacific Standard Time",             "(GMT+11:00) Magadan, Solomon Islands, New Caledonia"],
94
-		"285" => ["Fiji Islands Standard Time",                "(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands"],
95
-		"290" => ["New Zealand Standard Time",                 "(GMT+12:00) Auckland, Wellington"],
96
-		"300" => ["Tonga Standard Time",                       "(GMT+13:00) Nuku'alofa"],
97
-	];
98
-
99
-	/**
100
-	 * Python generated offset list
101
-	 * dots in keys were removed.
102
-	 *
103
-	 * Array indices
104
-	 *  0 = lBias
105
-	 *  1 = lStandardBias
106
-	 *  2 = lDSTBias
107
-	 *  3 = wStartYear
108
-	 *  4 = wStartMonth
109
-	 *  5 = wStartDOW
110
-	 *  6 = wStartDay
111
-	 *  7 = wStartHour
112
-	 *  8 = wStartMinute
113
-	 *  9 = wStartSecond
114
-	 * 10 = wStartMilliseconds
115
-	 * 11 = wEndYear
116
-	 * 12 = wEndMonth
117
-	 * 13 = wEndDOW
118
-	 * 14 = wEndDay
119
-	 * 15 = wEndHour
120
-	 * 16 = wEndMinute
121
-	 * 17 = wEndSecond
122
-	 * 18 = wEndMilloseconds
123
-	 *
124
-	 * As the $tzoneoffsets and the $mstzones need to be resolved in both directions,
125
-	 * some offsets are commented as they are not available in the $mstzones.
126
-	 *
127
-	 * Created at: 01.06.2012
128
-	 */
129
-	private static $tzonesoffsets = [
130
-		"Transitional Islamic State of Afghanistan Standard Time" => [-270, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
131
-		"Alaskan Standard Time" => [540, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
132
-		"Arab Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
133
-		"Arabian Standard Time" => [-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
134
-		"Arabic Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
135
-		// "Argentina Standard Time"                   => array(180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
136
-		"Atlantic Standard Time" => [240, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
137
-		"AUS Central Standard Time" => [-570, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
138
-		"AUS Eastern Standard Time" => [-600, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
139
-		// "Azerbaijan Standard Time"                  => array(-240, 0, -60,  0, 10, 0, 5, 5, 0, 0, 0,  0, 3, 0, 5, 4, 0, 0, 0),
140
-		"Azores Standard Time" => [60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
141
-		// "Bangladesh Standard Time"                  => array(-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
142
-		"Canada Central Standard Time" => [360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
143
-		"Cape Verde Standard Time" => [60, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
144
-		"Caucasus Standard Time" => [-240, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
145
-		"Cen Australia Standard Time" => [-570, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
146
-		"Central America Standard Time" => [360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
147
-		"Central Asia Standard Time" => [-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
148
-		// "Central Brazilian Standard Time"           => array(240, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999),
149
-		"Central Europe Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
150
-		"Central European Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
151
-		"Central Pacific Standard Time" => [-660, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
152
-		"Central Standard Time" => [360, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
153
-		"Mexico Standard Time" => [360, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0],
154
-		"China Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
155
-		"Dateline Standard Time" => [720, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
156
-		"E Africa Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
157
-		"E Australia Standard Time" => [-600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
158
-		"E Europe Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
159
-		"E South America Standard Time" => [180, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999],
160
-		"Eastern Standard Time" => [300, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
161
-		"Egypt Standard Time" => [-120, 0, -60,  0, 9, 4, 5, 23, 59, 59, 999,  0, 4, 4, 5, 23, 59, 59, 999],
162
-		"Ekaterinburg Standard Time" => [-300, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
163
-		"Fiji Islands Standard Time" => [-720, 0, -60,  0, 3, 0, 5, 3, 0, 0, 0,  0, 10, 0, 4, 2, 0, 0, 0],
164
-		"FLE Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 4, 0, 0, 0,  0, 3, 0, 5, 3, 0, 0, 0],
165
-		// "Georgian Standard Time"                    => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
166
-		"GMT Standard Time" => [0, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 3, 0, 5, 1, 0, 0, 0],
167
-		"Greenland Standard Time" => [180, 0, -60,  0, 10, 6, 5, 23, 0, 0, 0,  0, 3, 6, 4, 22, 0, 0, 0],
168
-		"Greenwich Standard Time" => [0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
169
-		"GTB Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 4, 0, 0, 0,  0, 3, 0, 5, 3, 0, 0, 0],
170
-		"Hawaiian Standard Time" => [600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
171
-		"India Standard Time" => [-330, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
172
-		"Iran Standard Time" => [-210, 0, -60,  0, 9, 1, 3, 23, 59, 59, 999,  0, 3, 6, 3, 23, 59, 59, 999],
173
-		"Israel Standard Time" => [-120, 0, -60,  0, 9, 0, 4, 2, 0, 0, 0,  0, 3, 5, 5, 2, 0, 0, 0],
174
-		// "Jordan Standard Time"                      => array(-120, 0, -60,  0, 10, 5, 5, 1, 0, 0, 0,  0, 3, 4, 5, 23, 59, 59, 999),
175
-		// "Kamchatka Standard Time"                   => array(-720, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
176
-		"Korea Standard Time" => [-540, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
177
-		// "Magadan Standard Time"                     => array(-660, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
178
-		// "Mauritius Standard Time"                   => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
179
-		"Mid-Atlantic Standard Time" => [120, 0, -60,  0, 9, 0, 5, 2, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
180
-		// "Middle East Standard Time"                 => array(-120, 0, -60,  0, 10, 6, 5, 23, 59, 59, 999,  0, 3, 6, 4, 23, 59, 59, 999),
181
-		// "Montevideo Standard Time"                  => array(180, 0, -60,  0, 3, 0, 2, 2, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0),
182
-		// "Morocco Standard Time"                     => array(0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
183
-		"Mountain Standard Time" => [420, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
184
-		"Mexico Standard Time 2" => [420, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0],
185
-		"Myanmar Standard Time" => [-390, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
186
-		"N Central Asia Standard Time" => [-360, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
187
-		// "Namibia Standard Time"                     => array(-60, 0, -60,  0, 4, 0, 1, 2, 0, 0, 0,  0, 9, 0, 1, 2, 0, 0, 0),
188
-		"Nepal Standard Time" => [-345, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
189
-		"New Zealand Standard Time" => [-720, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 9, 0, 5, 2, 0, 0, 0],
190
-		"Newfoundland and Labrador Standard Time" => [210, 0, -60,  0, 11, 0, 1, 0, 1, 0, 0,  0, 3, 0, 2, 0, 1, 0, 0],
191
-		"North Asia East Standard Time" => [-480, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
192
-		"North Asia Standard Time" => [-420, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
193
-		"Pacific SA Standard Time" => [240, 0, -60,  0, 3, 6, 2, 23, 59, 59, 999,  0, 10, 6, 2, 23, 59, 59, 999],
194
-		"Pacific Standard Time" => [480, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
195
-		// "Pacific Standard Time (Mexico)"            => array(480, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0),
196
-		// "Pakistan Standard Time"                    => array(-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
197
-		// "Paraguay Standard Time"                    => array(240, 0, -60,  0, 4, 6, 1, 23, 59, 59, 999,  0, 10, 6, 1, 23, 59, 59, 999),
198
-		"Romance Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
199
-		"Russian Standard Time" => [-180, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
200
-		"SA Eastern Standard Time" => [180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
201
-		"SA Pacific Standard Time" => [300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
202
-		"SA Western Standard Time" => [240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
203
-		"Samoa Standard Time" => [660, 0, -60,  0, 3, 6, 5, 23, 59, 59, 999,  0, 9, 6, 5, 23, 59, 59, 999],
204
-		"SE Asia Standard Time" => [-420, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
205
-		"Singapore Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
206
-		"South Africa Standard Time" => [-120, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
207
-		"Sri Lanka Standard Time" => [-330, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
208
-		// "Syria Standard Time"                       => array(-120, 0, -60,  0, 10, 4, 5, 23, 59, 59, 999,  0, 4, 4, 1, 23, 59, 59, 999),
209
-		"Taipei Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
210
-		"Tasmania Standard Time" => [-600, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
211
-		"Tokyo Standard Time" => [-540, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
212
-		"Tonga Standard Time" => [-780, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
213
-		// "Ulaanbaatar Standard Time"                 => array(-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
214
-		"US Eastern Standard Time" => [300, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
215
-		"US Mountain Standard Time" => [420, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
216
-		// "UTC"                                       => array(0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
217
-		// "UTC+12"                                    => array(-720, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
218
-		// "UTC-02"                                    => array(120, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
219
-		// "UTC-11"                                    => array(660, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
220
-		"Venezuela Standard Time" => [270, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
221
-		"Vladivostok Standard Time" => [-600, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
222
-		"W Australia Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
223
-		"W Central Africa Standard Time" => [-60, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
224
-		"W Europe Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
225
-		"West Asia Standard Time" => [-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
226
-		"West Pacific Standard Time" => [-600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
227
-		"Yakutsk Standard Time" => [-540, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
228
-	];
229
-
230
-	/**
231
-	 * Generated list of PHP timezones in GMT timezones.
232
-	 *
233
-	 * Created at: 01.06.2012
234
-	 */
235
-	private static $phptimezones = [
236
-		// -720 min
237
-		"Dateline Standard Time" => [
238
-			"Etc/GMT+12",
239
-		],
240
-
241
-		// -660 min
242
-		"Samoa Standard Time" => [
243
-			"Etc/GMT+11",
244
-			"Pacific/Midway",
245
-			"Pacific/Niue",
246
-			"Pacific/Pago_Pago",
247
-			"Pacific/Samoa",
248
-			"US/Samoa",
249
-		],
250
-
251
-		// -600 min
252
-		"Hawaiian Standard Time" => [
253
-			"America/Adak",
254
-			"America/Atka",
255
-			"Etc/GMT+10",
256
-			"HST",
257
-			"Pacific/Honolulu",
258
-			"Pacific/Johnston",
259
-			"Pacific/Rarotonga",
260
-			"Pacific/Tahiti",
261
-			"US/Aleutian",
262
-			"US/Hawaii",
263
-		],
264
-
265
-		// -570 min
266
-		"-570" => [
267
-			"Pacific/Marquesas",
268
-		],
269
-
270
-		// -540 min
271
-		"Alaskan Standard Time" => [
272
-			"America/Anchorage",
273
-			"America/Juneau",
274
-			"America/Nome",
275
-			"America/Sitka",
276
-			"America/Yakutat",
277
-			"Etc/GMT+9",
278
-			"Pacific/Gambier",
279
-			"US/Alaska",
280
-		],
281
-
282
-		// -480 min
283
-		"Pacific Standard Time" => [
284
-			"America/Dawson",
285
-			"America/Ensenada",
286
-			"America/Los_Angeles",
287
-			"America/Metlakatla",
288
-			"America/Santa_Isabel",
289
-			"America/Tijuana",
290
-			"America/Vancouver",
291
-			"America/Whitehorse",
292
-			"Canada/Pacific",
293
-			"Canada/Yukon",
294
-			"Etc/GMT+8",
295
-			"Mexico/BajaNorte",
296
-			"Pacific/Pitcairn",
297
-			"PST8PDT",
298
-			"US/Pacific",
299
-			"US/Pacific-New",
300
-		],
301
-
302
-		// -420 min
303
-		"US Mountain Standard Time" => [
304
-			"America/Boise",
305
-			"America/Cambridge_Bay",
306
-			"America/Chihuahua",
307
-			"America/Creston",
308
-			"America/Dawson_Creek",
309
-			"America/Denver",
310
-			"America/Edmonton",
311
-			"America/Hermosillo",
312
-			"America/Inuvik",
313
-			"America/Mazatlan",
314
-			"America/Ojinaga",
315
-			"America/Phoenix",
316
-			"America/Shiprock",
317
-			"America/Yellowknife",
318
-			"Canada/Mountain",
319
-			"Etc/GMT+7",
320
-			"Mexico/BajaSur",
321
-			"MST",
322
-			"MST7MDT",
323
-			"Navajo",
324
-			"US/Arizona",
325
-			"US/Mountain",
326
-		],
327
-
328
-		// -360 min
329
-		"Central Standard Time" => [
330
-			"America/Chicago",
331
-			"America/Indiana/Knox",
332
-			"America/Indiana/Tell_City",
333
-			"America/Knox_IN",
334
-			"America/North_Dakota/Beulah",
335
-			"America/North_Dakota/Center",
336
-			"America/North_Dakota/New_Salem",
337
-			"America/Rainy_River",
338
-			"America/Rankin_Inlet",
339
-			"America/Regina",
340
-			"America/Resolute",
341
-			"America/Swift_Current",
342
-			"America/Tegucigalpa",
343
-			"America/Winnipeg",
344
-			"US/Central",
345
-			"US/Indiana-Starke",
346
-			"CST6CDT",
347
-			"Etc/GMT+6",
348
-		],
349
-		"Canada Central Standard Time" => [
350
-			"Canada/Central",
351
-			"Canada/East-Saskatchewan",
352
-			"Canada/Saskatchewan",
353
-		],
354
-		"Mexico Standard Time" => [
355
-			"America/Mexico_City",
356
-			"America/Monterrey",
357
-			"Mexico/General",
358
-		],
359
-		"Central America Standard Time" => [
360
-			"America/Bahia_Banderas",
361
-			"America/Belize",
362
-			"America/Cancun",
363
-			"America/Costa_Rica",
364
-			"America/El_Salvador",
365
-			"America/Guatemala",
366
-			"America/Managua",
367
-			"America/Matamoros",
368
-			"America/Menominee",
369
-			"America/Merida",
370
-			"Chile/EasterIsland",
371
-			"Pacific/Easter",
372
-			"Pacific/Galapagos",
373
-		],
374
-
375
-		// -300 min
376
-		"US Eastern Standard Time" => [
377
-			"America/Detroit",
378
-			"America/Fort_Wayne",
379
-			"America/Grand_Turk",
380
-			"America/Indiana/Indianapolis",
381
-			"America/Indiana/Marengo",
382
-			"America/Indiana/Petersburg",
383
-			"America/Indiana/Vevay",
384
-			"America/Indiana/Vincennes",
385
-			"America/Indiana/Winamac",
386
-			"America/Indianapolis",
387
-			"America/Jamaica",
388
-			"America/Kentucky/Louisville",
389
-			"America/Kentucky/Monticello",
390
-			"America/Louisville",
391
-			"America/Montreal",
392
-			"America/New_York",
393
-			"America/Thunder_Bay",
394
-			"America/Toronto",
395
-			"Canada/Eastern",
396
-			"Cuba",
397
-			"EST",
398
-			"EST5EDT",
399
-			"Etc/GMT+5",
400
-			"Jamaica",
401
-			"US/East-Indiana",
402
-			"US/Eastern",
403
-			"US/Michigan",
404
-		],
405
-		"SA Pacific Standard Time" => [
406
-			"America/Atikokan",
407
-			"America/Bogota",
408
-			"America/Cayman",
409
-			"America/Coral_Harbour",
410
-			"America/Guayaquil",
411
-			"America/Havana",
412
-			"America/Iqaluit",
413
-			"America/Lima",
414
-			"America/Nassau",
415
-			"America/Nipigon",
416
-			"America/Panama",
417
-			"America/Pangnirtung",
418
-			"America/Port-au-Prince",
419
-		],
420
-
421
-		// -270 min
422
-		"Venezuela Standard Time" => [
423
-			"America/Caracas",
424
-		],
425
-		// -240 min
426
-		"Atlantic Standard Time" => [
427
-			"America/Barbados",
428
-			"America/Blanc-Sablon",
429
-			"America/Glace_Bay",
430
-			"America/Goose_Bay",
431
-			"America/Halifax",
432
-			"America/Lower_Princes",
433
-			"America/St_Barthelemy",
434
-			"America/St_Kitts",
435
-			"America/St_Lucia",
436
-			"America/St_Thomas",
437
-			"America/St_Vincent",
438
-			"America/Thule",
439
-			"America/Tortola",
440
-			"America/Virgin",
441
-			"Atlantic/Bermuda",
442
-			"Canada/Atlantic",
443
-			"Etc/GMT+4",
444
-		],
445
-		"SA Western Standard Time" => [
446
-			"America/Anguilla",
447
-			"America/Antigua",
448
-			"America/Aruba",
449
-			"America/Asuncion",
450
-			"America/Boa_Vista",
451
-			"America/Campo_Grande",
452
-			"America/Cuiaba",
453
-			"America/Curacao",
454
-			"America/Dominica",
455
-			"America/Eirunepe",
456
-			"America/Grenada",
457
-			"America/Guadeloupe",
458
-			"America/Guyana",
459
-			"America/Kralendijk",
460
-			"America/La_Paz",
461
-			"America/Manaus",
462
-			"America/Marigot",
463
-			"America/Martinique",
464
-			"America/Moncton",
465
-			"America/Montserrat",
466
-			"America/Port_of_Spain",
467
-			"America/Porto_Acre",
468
-			"America/Porto_Velho",
469
-			"America/Puerto_Rico",
470
-			"America/Rio_Branco",
471
-			"Brazil/Acre",
472
-			"Brazil/West",
473
-		],
474
-		"Pacific SA Standard Time" => [
475
-			"America/Santiago",
476
-			"America/Santo_Domingo",
477
-			"Antarctica/Palmer",
478
-			"Chile/Continental",
479
-		],
480
-
481
-		// -210 min
482
-		"Newfoundland and Labrador Standard Time" => [
483
-			"America/St_Johns",
484
-			"Canada/Newfoundland",
485
-		],
486
-
487
-		// -180 min
488
-		"E South America Standard Time" => [
489
-			"America/Araguaina",
490
-			"America/Bahia",
491
-			"America/Belem",
492
-			"America/Fortaleza",
493
-			"America/Maceio",
494
-			"America/Recife",
495
-			"America/Sao_Paulo",
496
-			"Brazil/East",
497
-			"Etc/GMT+3",
498
-		],
499
-		"SA Eastern Standard Time" => [
500
-			"America/Argentina/Buenos_Aires",
501
-			"America/Argentina/Catamarca",
502
-			"America/Argentina/ComodRivadavia",
503
-			"America/Argentina/Cordoba",
504
-			"America/Argentina/Jujuy",
505
-			"America/Argentina/La_Rioja",
506
-			"America/Argentina/Mendoza",
507
-			"America/Argentina/Rio_Gallegos",
508
-			"America/Argentina/Salta",
509
-			"America/Argentina/San_Juan",
510
-			"America/Argentina/San_Luis",
511
-			"America/Argentina/Tucuman",
512
-			"America/Argentina/Ushuaia",
513
-			"America/Buenos_Aires",
514
-			"America/Catamarca",
515
-			"America/Cayenne",
516
-			"America/Cordoba",
517
-			"America/Godthab",
518
-			"America/Jujuy",
519
-			"America/Mendoza",
520
-			"America/Miquelon",
521
-			"America/Montevideo",
522
-			"America/Paramaribo",
523
-			"America/Rosario",
524
-			"America/Santarem",
525
-		],
526
-		"Greenland Standard Time" => [
527
-			"Antarctica/Rothera",
528
-			"Atlantic/Stanley",
529
-		],
530
-
531
-		// -120 min
532
-		"Mid-Atlantic Standard Time" => [
533
-			"America/Noronha",
534
-			"Atlantic/South_Georgia",
535
-			"Brazil/DeNoronha",
536
-			"Etc/GMT+2",
537
-		],
538
-
539
-		// -60 min
540
-		"Azores Standard Time" => [
541
-			"Atlantic/Azores",
542
-			"Etc/GMT+1",
543
-		],
544
-		"Cape Verde Standard Time" => [
545
-			"America/Scoresbysund",
546
-			"Atlantic/Cape_Verde",
547
-		],
548
-
549
-		// 0 min
550
-		"GMT Standard Time" => [
551
-			"Eire",
552
-			"Etc/GMT",
553
-			"Etc/GMT+0",
554
-			"Etc/GMT-0",
555
-			"Etc/GMT0",
556
-			"Etc/Greenwich",
557
-			"Etc/UCT",
558
-			"Etc/Universal",
559
-			"Etc/UTC",
560
-			"Etc/Zulu",
561
-			"Europe/Belfast",
562
-			"Europe/Dublin",
563
-			"Europe/Guernsey",
564
-			"Europe/Isle_of_Man",
565
-			"Europe/Jersey",
566
-			"Europe/Lisbon",
567
-			"Europe/London",
568
-			"Factory",
569
-			"GB",
570
-			"GB-Eire",
571
-			"GMT",
572
-			"GMT+0",
573
-			"GMT-0",
574
-			"GMT0",
575
-			"Greenwich",
576
-			"Iceland",
577
-			"Portugal",
578
-			"UCT",
579
-			"Universal",
580
-			"UTC",
581
-		],
582
-		"Greenwich Standard Time" => [
583
-			"Africa/Abidjan",
584
-			"Africa/Accra",
585
-			"Africa/Bamako",
586
-			"Africa/Banjul",
587
-			"Africa/Bissau",
588
-			"Africa/Casablanca",
589
-			"Africa/Conakry",
590
-			"Africa/Dakar",
591
-			"Africa/El_Aaiun",
592
-			"Africa/Freetown",
593
-			"Africa/Lome",
594
-			"Africa/Monrovia",
595
-			"Africa/Nouakchott",
596
-			"Africa/Ouagadougou",
597
-			"Africa/Sao_Tome",
598
-			"Africa/Timbuktu",
599
-			"America/Danmarkshavn",
600
-			"Atlantic/Canary",
601
-			"Atlantic/Faeroe",
602
-			"Atlantic/Faroe",
603
-			"Atlantic/Madeira",
604
-			"Atlantic/Reykjavik",
605
-			"Atlantic/St_Helena",
606
-			"Zulu",
607
-		],
608
-
609
-		// +60 min
610
-		"Central Europe Standard Time" => [
611
-			"Europe/Belgrade",
612
-			"Europe/Bratislava",
613
-			"Europe/Budapest",
614
-			"Europe/Ljubljana",
615
-			"Europe/Prague",
616
-			"Europe/Vaduz",
617
-		],
618
-		"Central European Standard Time" => [
619
-			"Europe/Sarajevo",
620
-			"Europe/Skopje",
621
-			"Europe/Warsaw",
622
-			"Europe/Zagreb",
623
-			"MET",
624
-			"Poland",
625
-		],
626
-		"Romance Standard Time" => [
627
-			"Europe/Andorra",
628
-			"Europe/Brussels",
629
-			"Europe/Copenhagen",
630
-			"Europe/Gibraltar",
631
-			"Europe/Madrid",
632
-			"Europe/Malta",
633
-			"Europe/Monaco",
634
-			"Europe/Paris",
635
-			"Europe/Podgorica",
636
-			"Europe/San_Marino",
637
-			"Europe/Tirane",
638
-		],
639
-		"W Europe Standard Time" => [
640
-			"Europe/Amsterdam",
641
-			"Europe/Berlin",
642
-			"Europe/Luxembourg",
643
-			"Europe/Vatican",
644
-			"Europe/Rome",
645
-			"Europe/Stockholm",
646
-			"Arctic/Longyearbyen",
647
-			"Europe/Vienna",
648
-			"Europe/Zurich",
649
-			"Europe/Oslo",
650
-			"WET",
651
-			"CET",
652
-			"Etc/GMT-1",
653
-		],
654
-		"W Central Africa Standard Time" => [
655
-			"Africa/Algiers",
656
-			"Africa/Bangui",
657
-			"Africa/Brazzaville",
658
-			"Africa/Ceuta",
659
-			"Africa/Douala",
660
-			"Africa/Kinshasa",
661
-			"Africa/Lagos",
662
-			"Africa/Libreville",
663
-			"Africa/Luanda",
664
-			"Africa/Malabo",
665
-			"Africa/Ndjamena",
666
-			"Africa/Niamey",
667
-			"Africa/Porto-Novo",
668
-			"Africa/Tunis",
669
-			"Africa/Windhoek",
670
-			"Atlantic/Jan_Mayen",
671
-		],
672
-
673
-		// +120 min
674
-		"E Europe Standard Time" => [
675
-			"Europe/Bucharest",
676
-			"EET",
677
-			"Etc/GMT-2",
678
-			"Europe/Chisinau",
679
-			"Europe/Mariehamn",
680
-			"Europe/Nicosia",
681
-			"Europe/Simferopol",
682
-			"Europe/Tiraspol",
683
-			"Europe/Uzhgorod",
684
-			"Europe/Zaporozhye",
685
-		],
686
-		"Egypt Standard Time" => [
687
-			"Africa/Cairo",
688
-			"Africa/Tripoli",
689
-			"Egypt",
690
-			"Libya",
691
-		],
692
-		"FLE Standard Time" => [
693
-			"Europe/Helsinki",
694
-			"Europe/Kiev",
695
-			"Europe/Riga",
696
-			"Europe/Sofia",
697
-			"Europe/Tallinn",
698
-			"Europe/Vilnius",
699
-		],
700
-		"GTB Standard Time" => [
701
-			"Asia/Istanbul",
702
-			"Europe/Athens",
703
-			"Europe/Istanbul",
704
-			"Turkey",
705
-		],
706
-		"Israel Standard Time" => [
707
-			"Asia/Amman",
708
-			"Asia/Beirut",
709
-			"Asia/Damascus",
710
-			"Asia/Gaza",
711
-			"Asia/Hebron",
712
-			"Asia/Nicosia",
713
-			"Asia/Tel_Aviv",
714
-			"Asia/Jerusalem",
715
-			"Israel",
716
-		],
717
-		"South Africa Standard Time" => [
718
-			"Africa/Blantyre",
719
-			"Africa/Bujumbura",
720
-			"Africa/Gaborone",
721
-			"Africa/Harare",
722
-			"Africa/Johannesburg",
723
-			"Africa/Kigali",
724
-			"Africa/Lubumbashi",
725
-			"Africa/Lusaka",
726
-			"Africa/Maputo",
727
-			"Africa/Maseru",
728
-			"Africa/Mbabane",
729
-		],
730
-
731
-		// +180 min
732
-		"Russian Standard Time" => [
733
-			"Antarctica/Syowa",
734
-			"Europe/Kaliningrad",
735
-			"Europe/Minsk",
736
-			"Etc/GMT-3",
737
-		],
738
-		"Arab Standard Time" => [
739
-			"Asia/Qatar",
740
-			"Asia/Kuwait",
741
-			"Asia/Riyadh",
742
-		],
743
-		"E Africa Standard Time" => [
744
-			"Africa/Addis_Ababa",
745
-			"Africa/Asmara",
746
-			"Africa/Asmera",
747
-			"Africa/Dar_es_Salaam",
748
-			"Africa/Djibouti",
749
-			"Africa/Juba",
750
-			"Africa/Kampala",
751
-			"Africa/Khartoum",
752
-			"Africa/Mogadishu",
753
-			"Africa/Nairobi",
754
-		],
755
-		"Arabic Standard Time" => [
756
-			"Asia/Aden",
757
-			"Asia/Baghdad",
758
-			"Asia/Bahrain",
759
-			"Indian/Antananarivo",
760
-			"Indian/Comoro",
761
-			"Indian/Mayotte",
762
-		],
763
-
764
-		// +210 min
765
-		"Iran Standard Time" => [
766
-			"Asia/Tehran",
767
-			"Iran",
768
-		],
769
-
770
-		// +240 min
771
-		"Arabian Standard Time" => [
772
-			"Asia/Dubai",
773
-			"Asia/Muscat",
774
-			"Indian/Mahe",
775
-			"Indian/Mauritius",
776
-			"Indian/Reunion",
777
-		],
778
-		"Caucasus Standard Time" => [
779
-			"Asia/Baku",
780
-			"Asia/Tbilisi",
781
-			"Asia/Yerevan",
782
-			"Etc/GMT-4",
783
-			"Europe/Moscow",
784
-			"Europe/Samara",
785
-			"Europe/Volgograd",
786
-			"W-SU",
787
-		],
788
-
789
-		// +270 min
790
-		"Transitional Islamic State of Afghanistan Standard Time" => [
791
-			"Asia/Kabul",
792
-		],
793
-
794
-		// +300 min
795
-		"Ekaterinburg Standard Time" => [
796
-			"Antarctica/Mawson",
797
-		],
798
-		"West Asia Standard Time" => [
799
-			"Asia/Aqtau",
800
-			"Asia/Aqtobe",
801
-			"Asia/Ashgabat",
802
-			"Asia/Ashkhabad",
803
-			"Asia/Dushanbe",
804
-			"Asia/Karachi",
805
-			"Asia/Oral",
806
-			"Asia/Samarkand",
807
-			"Asia/Tashkent",
808
-			"Etc/GMT-5",
809
-			"Indian/Kerguelen",
810
-			"Indian/Maldives",
811
-		],
812
-
813
-		// +330 min
814
-		"India Standard Time" => [
815
-			"Asia/Calcutta",
816
-			"Asia/Colombo",
817
-			"Asia/Kolkata",
818
-		],
819
-
820
-		// +345 min
821
-		"Nepal Standard Time" => [
822
-			"Asia/Kathmandu",
823
-			"Asia/Katmandu",
824
-		],
825
-
826
-		// +360 min
827
-		"Central Asia Standard Time" => [
828
-			"Asia/Dacca",
829
-			"Asia/Dhaka",
830
-		],
831
-		"Sri Lanka Standard Time" => [
832
-			"Indian/Chagos",
833
-		],
834
-		"N Central Asia Standard Time" => [
835
-			"Antarctica/Vostok",
836
-			"Asia/Almaty",
837
-			"Asia/Bishkek",
838
-			"Asia/Qyzylorda",
839
-			"Asia/Thimbu",
840
-			"Asia/Thimphu",
841
-			"Asia/Yekaterinburg",
842
-			"Etc/GMT-6",
843
-		],
844
-
845
-		// +390 min
846
-		"Myanmar Standard Time" => [
847
-			"Asia/Rangoon",
848
-			"Indian/Cocos",
849
-		],
850
-
851
-		// +420 min
852
-		"SE Asia Standard Time" => [
853
-			"Asia/Bangkok",
854
-			"Asia/Ho_Chi_Minh",
855
-			"Asia/Hovd",
856
-			"Asia/Jakarta",
857
-			"Asia/Phnom_Penh",
858
-			"Asia/Saigon",
859
-			"Indian/Christmas",
860
-		],
861
-		"North Asia Standard Time" => [
862
-			"Antarctica/Davis",
863
-			"Asia/Novokuznetsk",
864
-			"Asia/Novosibirsk",
865
-			"Asia/Omsk",
866
-			"Asia/Pontianak",
867
-			"Asia/Vientiane",
868
-			"Etc/GMT-7",
869
-		],
870
-
871
-		// +480 min
872
-		"China Standard Time" => [
873
-			"Asia/Brunei",
874
-			"Asia/Choibalsan",
875
-			"Asia/Chongqing",
876
-			"Asia/Chungking",
877
-			"Asia/Harbin",
878
-			"Asia/Hong_Kong",
879
-			"Asia/Shanghai",
880
-			"Asia/Ujung_Pandang",
881
-			"Asia/Urumqi",
882
-			"Hongkong",
883
-			"PRC",
884
-			"ROC",
885
-		],
886
-		"Singapore Standard Time" => [
887
-			"Singapore",
888
-			"Asia/Singapore",
889
-			"Asia/Kuala_Lumpur",
890
-		],
891
-		"Taipei Standard Time" => [
892
-			"Asia/Taipei",
893
-		],
894
-		"W Australia Standard Time" => [
895
-			"Australia/Perth",
896
-			"Australia/West",
897
-		],
898
-		"North Asia East Standard Time" => [
899
-			"Antarctica/Casey",
900
-			"Asia/Kashgar",
901
-			"Asia/Krasnoyarsk",
902
-			"Asia/Kuching",
903
-			"Asia/Macao",
904
-			"Asia/Macau",
905
-			"Asia/Makassar",
906
-			"Asia/Manila",
907
-			"Etc/GMT-8",
908
-			"Asia/Ulaanbaatar",
909
-			"Asia/Ulan_Bator",
910
-		],
911
-
912
-		// +525 min
913
-		"525" => [
914
-			"Australia/Eucla",
915
-		],
916
-
917
-		// +540 min
918
-		"Korea Standard Time" => [
919
-			"Asia/Seoul",
920
-			"Asia/Pyongyang",
921
-			"ROK",
922
-		],
923
-		"Tokyo Standard Time" => [
924
-			"Asia/Tokyo",
925
-			"Japan",
926
-			"Etc/GMT-9",
927
-		],
928
-		"Yakutsk Standard Time" => [
929
-			"Asia/Dili",
930
-			"Asia/Irkutsk",
931
-			"Asia/Jayapura",
932
-			"Pacific/Palau",
933
-		],
934
-
935
-		// +570 min
936
-		"AUS Central Standard Time" => [
937
-			"Australia/Darwin",
938
-			"Australia/North",
939
-		],
940
-		// DST
941
-		"Cen Australia Standard Time" => [
942
-			"Australia/Adelaide",
943
-			"Australia/Broken_Hill",
944
-			"Australia/South",
945
-			"Australia/Yancowinna",
946
-		],
947
-
948
-		// +600 min
949
-		"AUS Eastern Standard Time" => [
950
-			"Australia/Canberra",
951
-			"Australia/Melbourne",
952
-			"Australia/Sydney",
953
-			"Australia/Currie",
954
-			"Australia/ACT",
955
-			"Australia/NSW",
956
-			"Australia/Victoria",
957
-		],
958
-		"E Australia Standard Time" => [
959
-			"Etc/GMT-10",
960
-			"Australia/Brisbane",
961
-			"Australia/Queensland",
962
-			"Australia/Lindeman",
963
-		],
964
-		"Tasmania Standard Time" => [
965
-			"Australia/Hobart",
966
-			"Australia/Tasmania",
967
-		],
968
-		"Vladivostok Standard Time" => [
969
-			"Antarctica/DumontDUrville",
970
-		],
971
-		"West Pacific Standard Time" => [
972
-			"Asia/Yakutsk",
973
-			"Pacific/Chuuk",
974
-			"Pacific/Guam",
975
-			"Pacific/Port_Moresby",
976
-			"Pacific/Saipan",
977
-			"Pacific/Truk",
978
-			"Pacific/Yap",
979
-		],
980
-
981
-		// +630 min
982
-		"630" => [
983
-			"Australia/LHI",
984
-			"Australia/Lord_Howe",
985
-		],
986
-
987
-		// +660 min
988
-		"Central Pacific Standard Time" => [
989
-			"Antarctica/Macquarie",
990
-			"Asia/Sakhalin",
991
-			"Asia/Vladivostok",
992
-			"Etc/GMT-11",
993
-			"Pacific/Efate",
994
-			"Pacific/Guadalcanal",
995
-			"Pacific/Kosrae",
996
-			"Pacific/Noumea",
997
-			"Pacific/Pohnpei",
998
-			"Pacific/Ponape",
999
-		],
1000
-
1001
-		// 690 min
1002
-		"690" => [
1003
-			"Pacific/Norfolk",
1004
-		],
1005
-
1006
-		// +720 min
1007
-		"Fiji Islands Standard Time" => [
1008
-			"Asia/Anadyr",
1009
-			"Asia/Kamchatka",
1010
-			"Asia/Magadan",
1011
-			"Kwajalein",
1012
-		],
1013
-		"New Zealand Standard Time" => [
1014
-			"Antarctica/McMurdo",
1015
-			"Antarctica/South_Pole",
1016
-			"Etc/GMT-12",
1017
-			"NZ",
1018
-			"Pacific/Auckland",
1019
-			"Pacific/Fiji",
1020
-			"Pacific/Funafuti",
1021
-			"Pacific/Kwajalein",
1022
-			"Pacific/Majuro",
1023
-			"Pacific/Nauru",
1024
-			"Pacific/Tarawa",
1025
-			"Pacific/Wake",
1026
-			"Pacific/Wallis",
1027
-		],
1028
-
1029
-		// +765 min
1030
-		"765" => [
1031
-			"NZ-CHAT",
1032
-			"Pacific/Chatham",
1033
-		],
1034
-
1035
-		// +780 min
1036
-		"Tonga Standard Time" => [
1037
-			"Etc/GMT-13",
1038
-			"Pacific/Apia",
1039
-			"Pacific/Enderbury",
1040
-			"Pacific/Tongatapu",
1041
-		],
1042
-
1043
-		// +840 min
1044
-		"840" => [
1045
-			"Etc/GMT-14",
1046
-			"Pacific/Fakaofo",
1047
-			"Pacific/Kiritimati",
1048
-		],
1049
-	];
1050
-
1051
-	/**
1052
-	 * Returns a full timezone array.
1053
-	 *
1054
-	 * @param string $phptimezone (opt) a php timezone string.
1055
-	 *                            If omitted the env. default timezone is used.
1056
-	 *
1057
-	 * @return array
1058
-	 */
1059
-	public static function GetFullTZ($phptimezone = false) {
1060
-		if ($phptimezone === false) {
1061
-			$phptimezone = date_default_timezone_get();
1062
-		}
1063
-
1064
-		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::GetFullTZ() for " . $phptimezone);
1065
-
1066
-		$servertzname = self::guessTZNameFromPHPName($phptimezone);
1067
-
1068
-		return self::GetFullTZFromTZName($servertzname);
1069
-	}
1070
-
1071
-	/**
1072
-	 * Returns a full timezone array.
1073
-	 *
1074
-	 * @param string $tzname a TZID value
1075
-	 *
1076
-	 * @return array
1077
-	 */
1078
-	public static function GetFullTZFromTZName($tzname) {
1079
-		if (!array_key_exists($tzname, self::$tzonesoffsets)) {
1080
-			SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetFullTZFromTZName('%s'): Is a PHP TimeZone, converting", $tzname));
1081
-			$tzname = self::guessTZNameFromPHPName($tzname);
1082
-		}
1083
-
1084
-		$offset = self::$tzonesoffsets[$tzname];
1085
-
1086
-		return [
1087
-			"bias" => $offset[0],
1088
-			"tzname" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
1089
-			"dstendyear" => $offset[3],
1090
-			"dstendmonth" => $offset[4],
1091
-			"dstendday" => $offset[5],
1092
-			"dstendweek" => $offset[6],
1093
-			"dstendhour" => $offset[7],
1094
-			"dstendminute" => $offset[8],
1095
-			"dstendsecond" => $offset[9],
1096
-			"dstendmillis" => $offset[10],
1097
-			"stdbias" => $offset[1],
1098
-			"tznamedst" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
1099
-			"dststartyear" => $offset[11],
1100
-			"dststartmonth" => $offset[12],
1101
-			"dststartday" => $offset[13],
1102
-			"dststartweek" => $offset[14],
1103
-			"dststarthour" => $offset[15],
1104
-			"dststartminute" => $offset[16],
1105
-			"dststartsecond" => $offset[17],
1106
-			"dststartmillis" => $offset[18],
1107
-			"dstbias" => $offset[2],
1108
-		];
1109
-	}
1110
-
1111
-	/**
1112
-	 * Sets the timezone name by matching data from the offset (bias etc).
1113
-	 *
1114
-	 * @param array $offset a grommunio-sync timezone array
1115
-	 * @param mixed $tz
1116
-	 *
1117
-	 * @return array
1118
-	 */
1119
-	public static function FillTZNames($tz) {
1120
-		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::FillTZNames() filling up bias " . $tz["bias"]);
1121
-		if (!isset($tz["bias"])) {
1122
-			SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::FillTZNames() submitted TZ array does not have a bias");
1123
-		}
1124
-		else {
1125
-			$tzname = self::guessTZNameFromOffset($tz);
1126
-			$tz['tzname'] = $tz['tznamedst'] = self::encodeTZName(self::getMSTZnameFromTZName($tzname));
1127
-		}
1128
-
1129
-		return $tz;
1130
-	}
1131
-
1132
-	/**
1133
-	 * Tries to find a timezone using the Bias and other offset parameters.
1134
-	 *
1135
-	 * @param array $offset a grommunio-sync timezone array
1136
-	 *
1137
-	 * @return string
1138
-	 */
1139
-	private static function guessTZNameFromOffset($offset) {
1140
-		// try to find a quite exact match
1141
-		foreach (self::$tzonesoffsets as $tzname => $tzoffset) {
1142
-			if ($offset["bias"] == $tzoffset[0] &&
1143
-				isset($offset["dstendmonth"]) && $offset["dstendmonth"] == $tzoffset[4] &&
1144
-				isset($offset["dstendday"]) && $offset["dstendday"] == $tzoffset[6] &&
1145
-				isset($offset["dststartmonth"]) && $offset["dststartmonth"] == $tzoffset[12] &&
1146
-				isset($offset["dststartday"]) && $offset["dststartday"] == $tzoffset[14]) {
1147
-				return $tzname;
1148
-			}
1149
-		}
1150
-
1151
-		// try to find a bias match
1152
-		foreach (self::$tzonesoffsets as $tzname => $tzoffset) {
1153
-			if ($offset["bias"] == $tzoffset[0]) {
1154
-				return $tzname;
1155
-			}
1156
-		}
1157
-
1158
-		// nothing found? return gmt
1159
-		SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::guessTZNameFromOffset() no timezone found for the data submitted. Returning 'GMT Standard Time'.");
1160
-
1161
-		return "GMT Standard Time";
1162
-	}
1163
-
1164
-	/**
1165
-	 * Tries to find a AS timezone for a php timezone.
1166
-	 *
1167
-	 * @param string $phpname a php timezone name
1168
-	 *
1169
-	 * @return string
1170
-	 */
1171
-	private static function guessTZNameFromPHPName($phpname) {
1172
-		foreach (self::$phptimezones as $tzn => $phptzs) {
1173
-			if (in_array($phpname, $phptzs)) {
1174
-				if (!is_int($tzn)) {
1175
-					return $tzn;
1176
-				}
1177
-
1178
-				break;
1179
-			}
1180
-		}
1181
-		SLog::Write(LOGLEVEL_ERROR, sprintf("TimezoneUtil::guessTZNameFromPHPName() no compatible timezone found for '%s'. Returning 'GMT Standard Time'. Please contact the grommunio dev team.", $phpname));
1182
-
1183
-		return self::$mstzones["085"][0];
1184
-	}
1185
-
1186
-	/**
1187
-	 * Returns an AS compatible tz name.
1188
-	 *
1189
-	 * @param string $name internal timezone name
1190
-	 *
1191
-	 * @return string
1192
-	 */
1193
-	private static function getMSTZnameFromTZName($name) {
1194
-		// if $name is empty, get the timezone from system
1195
-		if (trim($name) == '') {
1196
-			$name = date_default_timezone_get();
1197
-			SLog::Write(LOGLEVEL_INFO, sprintf("TimezoneUtil::getMSTZnameFromTZName(): empty timezone name sent. Got timezone from the system: '%s'", $name));
1198
-		}
1199
-
1200
-		foreach (self::$mstzones as $mskey => $msdefs) {
1201
-			if ($name == $msdefs[0]) {
1202
-				return $msdefs[1];
1203
-			}
1204
-		}
1205
-
1206
-		// Not found? Then retrieve the correct TZName first and try again.
1207
-		// That's ugly and needs a proper fix. But for now this method can convert
1208
-		// - Europe/Berlin
1209
-		// - W Europe Standard Time
1210
-		// to "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
1211
-		// which is more correct than the hardcoded default of (GMT+00:00...)
1212
-		$tzName = '';
1213
-		foreach (self::$phptimezones as $tzn => $phptzs) {
1214
-			if (in_array($name, $phptzs)) {
1215
-				$tzName = $tzn;
1216
-
1217
-				break;
1218
-			}
1219
-		}
1220
-		if ($tzName != '') {
1221
-			foreach (self::$mstzones as $mskey => $msdefs) {
1222
-				if ($tzName == $msdefs[0]) {
1223
-					return $msdefs[1];
1224
-				}
1225
-			}
1226
-		}
1227
-
1228
-		SLog::Write(LOGLEVEL_WARN, sprintf("TimezoneUtil::getMSTZnameFromTZName() no MS name found for '%s'. Returning '(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London'", $name));
1229
-
1230
-		return self::$mstzones["085"][1];
1231
-	}
1232
-
1233
-	/**
1234
-	 * Encodes the tz name to UTF-16 compatible with a syncblob.
1235
-	 *
1236
-	 * @param string $name timezone name
1237
-	 *
1238
-	 * @return string
1239
-	 */
1240
-	private static function encodeTZName($name) {
1241
-		return substr(iconv('UTF-8', 'UTF-16', $name), 2, -1);
1242
-	}
1243
-
1244
-	/**
1245
-	 * Test to check if $mstzones and $tzonesoffsets can be resolved
1246
-	 * in both directions.
1247
-	 *
1248
-	 * @return
1249
-	 */
1250
-	public static function TZtest() {
1251
-		foreach (self::$mstzones as $mskey => $msdefs) {
1252
-			if (!array_key_exists($msdefs[0], self::$tzonesoffsets)) {
1253
-				echo "key   '" . $msdefs[0] . "'   not found in tzonesoffsets\n";
1254
-			}
1255
-		}
1256
-
1257
-		foreach (self::$tzonesoffsets as $tzname => $offset) {
1258
-			$found = false;
1259
-			foreach (self::$mstzones as $mskey => $msdefs) {
1260
-				if ($tzname == $msdefs[0]) {
1261
-					$found = true;
1262
-
1263
-					break;
1264
-				}
1265
-			}
1266
-			if (!$found) {
1267
-				echo "key    '{$tzname}' NOT FOUND\n";
1268
-			}
1269
-		}
1270
-	}
1271
-
1272
-	/**
1273
-	 * Pack timezone info for Sync.
1274
-	 *
1275
-	 * @param array $tz
1276
-	 *
1277
-	 * @return string
1278
-	 */
1279
-	public static function GetSyncBlobFromTZ($tz) {
1280
-		// set the correct TZ name (done using the Bias)
1281
-		if (!isset($tz["tzname"]) || !$tz["tzname"] || !isset($tz["tznamedst"]) || !$tz["tznamedst"]) {
1282
-			$tz = TimezoneUtil::FillTZNames($tz);
1283
-		}
1284
-
1285
-		return pack(
1286
-			"la64vvvvvvvv" . "la64vvvvvvvv" . "l",
1287
-			$tz["bias"],
1288
-			$tz["tzname"],
1289
-			0,
1290
-			$tz["dstendmonth"],
1291
-			$tz["dstendday"],
1292
-			$tz["dstendweek"],
1293
-			$tz["dstendhour"],
1294
-			$tz["dstendminute"],
1295
-			$tz["dstendsecond"],
1296
-			$tz["dstendmillis"],
1297
-			$tz["stdbias"],
1298
-			$tz["tznamedst"],
1299
-			0,
1300
-			$tz["dststartmonth"],
1301
-			$tz["dststartday"],
1302
-			$tz["dststartweek"],
1303
-			$tz["dststarthour"],
1304
-			$tz["dststartminute"],
1305
-			$tz["dststartsecond"],
1306
-			$tz["dststartmillis"],
1307
-			$tz["dstbias"]
1308
-		);
1309
-	}
1310
-
1311
-	/**
1312
-	 * Generate date object from string and timezone.
1313
-	 *
1314
-	 * @param string $value
1315
-	 * @param string $timezone
1316
-	 *
1317
-	 * @return int epoch
1318
-	 */
1319
-	public static function MakeUTCDate($value, $timezone = null) {
1320
-		$tz = null;
1321
-		if ($timezone) {
1322
-			$tz = timezone_open($timezone);
1323
-		}
1324
-		if (!$tz) {
1325
-			// If there is no timezone set, we use the default timezone
1326
-			$tz = timezone_open(date_default_timezone_get());
1327
-		}
1328
-		// 20110930T090000Z
1329
-		$date = date_create_from_format('Ymd\THis\Z', $value, timezone_open("UTC"));
1330
-		if (!$date) {
1331
-			// 20110930T090000
1332
-			$date = date_create_from_format('Ymd\THis', $value, $tz);
1333
-		}
1334
-		if (!$date) {
1335
-			// 20110930 (Append T000000Z to the date, so it starts at midnight)
1336
-			$date = date_create_from_format('Ymd\THis\Z', $value . "T000000Z", $tz);
1337
-		}
1338
-
1339
-		return date_timestamp_get($date);
1340
-	}
1341
-
1342
-	/**
1343
-	 * Generate a tzid from various formats.
1344
-	 *
1345
-	 * @param string $timezone
1346
-	 *
1347
-	 * @return timezone id
1348
-	 */
1349
-	public static function ParseTimezone($timezone) {
1350
-		// (GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna
1351
-		if (preg_match('/GMT(\\+|\\-)0(\d)/', $timezone, $matches)) {
1352
-			return "Etc/GMT" . $matches[1] . $matches[2];
1353
-		}
1354
-		// (GMT+10.00) XXX / XXX / XXX / XXX
1355
-		if (preg_match('/GMT(\\+|\\-)1(\d)/', $timezone, $matches)) {
1356
-			return "Etc/GMT" . $matches[1] . "1" . $matches[2];
1357
-		}
1358
-		// /inverse.ca/20101018_1/Europe/Amsterdam or /inverse.ca/20101018_1/America/Argentina/Buenos_Aires
1359
-		if (preg_match('/\/[.[:word:]]+\/\w+\/(\w+)\/([\w\/]+)/', $timezone, $matches)) {
1360
-			return $matches[1] . "/" . $matches[2];
1361
-		}
1362
-
1363
-		return self::getMSTZnameFromTZName(trim($timezone, '"'));
1364
-	}
1365
-
1366
-	/**
1367
-	 * Returns a timezone supported by PHP for DateTimeZone constructor.
1368
-	 *
1369
-	 * @see http://php.net/manual/en/timezones.php
1370
-	 *
1371
-	 * @param string $timezone
1372
-	 *
1373
-	 * @return string
1374
-	 */
1375
-	public static function GetPhpSupportedTimezone($timezone) {
1376
-		if (in_array($timezone, DateTimeZone::listIdentifiers())) {
1377
-			SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetPhpSupportedTimezone(): '%s' is a PHP supported timezone", $timezone));
1378
-
1379
-			return $timezone;
1380
-		}
1381
-		$dtz = date_default_timezone_get();
1382
-		SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetPhpSupportedTimezone(): '%s' is not a PHP supported timezone. Returning default timezone: '%s'", $timezone, $dtz));
1383
-
1384
-		return $dtz;
1385
-	}
1386
-
1387
-	/**
1388
-	 * Returns official timezone name from windows timezone name.
1389
-	 * E.g. "W Europe Standard Time" for "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna".
1390
-	 *
1391
-	 * @param string $winTz Timezone name in windows
1392
-	 *
1393
-	 * @return string timezone name
1394
-	 */
1395
-	public static function GetTZNameFromWinTZ($winTz = false) {
1396
-		// Return "GMT Standard Time" per default
1397
-		if ($winTz === false) {
1398
-			return self::$mstzones['085'][0];
1399
-		}
1400
-
1401
-		foreach (self::$mstzones as $mskey => $msdefs) {
1402
-			if ($winTz == $msdefs[1]) {
1403
-				return $msdefs[0];
1404
-			}
1405
-		}
1406
-
1407
-		return self::$mstzones['085'][0];
1408
-	}
11
+    /**
12
+     * list of MS and AS compatible timezones.
13
+     *
14
+     * origin: http://msdn.microsoft.com/en-us/library/ms912391%28v=winembedded.11%29.aspx
15
+     * dots of tz identifiers were removed
16
+     *
17
+     * Updated at: 01.06.2012
18
+     */
19
+    private static $mstzones = [
20
+        "000" => ["Dateline Standard Time",                    "(GMT-12:00) International Date Line West"],
21
+        "001" => ["Samoa Standard Time",                       "(GMT-11:00) Midway Island, Samoa"],
22
+        "002" => ["Hawaiian Standard Time",                    "(GMT-10:00) Hawaii"],
23
+        "003" => ["Alaskan Standard Time",                     "(GMT-09:00) Alaska"],
24
+        "004" => ["Pacific Standard Time",                     "(GMT-08:00) Pacific Time (US and Canada); Tijuana"],
25
+        "010" => ["Mountain Standard Time",                    "(GMT-07:00) Mountain Time (US and Canada)"],
26
+        "013" => ["Mexico Standard Time 2",                    "(GMT-07:00) Chihuahua, La Paz, Mazatlan"],
27
+        "015" => ["US Mountain Standard Time",                 "(GMT-07:00) Arizona"],
28
+        "020" => ["Central Standard Time",                     "(GMT-06:00) Central Time (US and Canada"],
29
+        "025" => ["Canada Central Standard Time",              "(GMT-06:00) Saskatchewan"],
30
+        "030" => ["Mexico Standard Time",                      "(GMT-06:00) Guadalajara, Mexico City, Monterrey"],
31
+        "033" => ["Central America Standard Time",             "(GMT-06:00) Central America"],
32
+        "035" => ["Eastern Standard Time",                     "(GMT-05:00) Eastern Time (US and Canada)"],
33
+        "040" => ["US Eastern Standard Time",                  "(GMT-05:00) Indiana (East)"],
34
+        "045" => ["SA Pacific Standard Time",                  "(GMT-05:00) Bogota, Lima, Quito"],
35
+        "uk1" => ["Venezuela Standard Time",                   "(GMT-04:30) Caracas"],                     // added
36
+        "050" => ["Atlantic Standard Time",                    "(GMT-04:00) Atlantic Time (Canada)"],
37
+        "055" => ["SA Western Standard Time",                  "(GMT-04:00) Caracas, La Paz"],
38
+        "056" => ["Pacific SA Standard Time",                  "(GMT-04:00) Santiago"],
39
+        "060" => ["Newfoundland and Labrador Standard Time",   "(GMT-03:30) Newfoundland and Labrador"],
40
+        "065" => ["E South America Standard Time",             "(GMT-03:00) Brasilia"],
41
+        "070" => ["SA Eastern Standard Time",                  "(GMT-03:00) Buenos Aires, Georgetown"],
42
+        "073" => ["Greenland Standard Time",                   "(GMT-03:00) Greenland"],
43
+        "075" => ["Mid-Atlantic Standard Time",                "(GMT-02:00) Mid-Atlantic"],
44
+        "080" => ["Azores Standard Time",                      "(GMT-01:00) Azores"],
45
+        "083" => ["Cape Verde Standard Time",                  "(GMT-01:00) Cape Verde Islands"],
46
+        "085" => ["GMT Standard Time",                         "(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London"],
47
+        "090" => ["Greenwich Standard Time",                   "(GMT) Casablanca, Monrovia"],
48
+        "095" => ["Central Europe Standard Time",              "(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague"],
49
+        "100" => ["Central European Standard Time",            "(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb"],
50
+        "105" => ["Romance Standard Time",                     "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"],
51
+        "110" => ["W Europe Standard Time",                    "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
52
+        "111" => ["W. Europe Standard Time",                   "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
53
+        "113" => ["W Central Africa Standard Time",            "(GMT+01:00) West Central Africa"],
54
+        "115" => ["E Europe Standard Time",                    "(GMT+02:00) Bucharest"],
55
+        "120" => ["Egypt Standard Time",                       "(GMT+02:00) Cairo"],
56
+        "125" => ["FLE Standard Time",                         "(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius"],
57
+        "130" => ["GTB Standard Time",                         "(GMT+02:00) Athens, Istanbul, Minsk"],
58
+        "135" => ["Israel Standard Time",                      "(GMT+02:00) Jerusalem"],
59
+        "140" => ["South Africa Standard Time",                "(GMT+02:00) Harare, Pretoria"],
60
+        "145" => ["Russian Standard Time",                     "(GMT+03:00) Moscow, St. Petersburg, Volgograd"],
61
+        "150" => ["Arab Standard Time",                        "(GMT+03:00) Kuwait, Riyadh"],
62
+        "155" => ["E Africa Standard Time",                    "(GMT+03:00) Nairobi"],
63
+        "158" => ["Arabic Standard Time",                      "(GMT+03:00) Baghdad"],
64
+        "160" => ["Iran Standard Time",                        "(GMT+03:30) Tehran"],
65
+        "165" => ["Arabian Standard Time",                     "(GMT+04:00) Abu Dhabi, Muscat"],
66
+        "170" => ["Caucasus Standard Time",                    "(GMT+04:00) Baku, Tbilisi, Yerevan"],
67
+        "175" => ["Transitional Islamic State of Afghanistan Standard Time", "(GMT+04:30) Kabul"],
68
+        "180" => ["Ekaterinburg Standard Time",                "(GMT+05:00) Ekaterinburg"],
69
+        "185" => ["West Asia Standard Time",                   "(GMT+05:00) Islamabad, Karachi, Tashkent"],
70
+        "190" => ["India Standard Time",                       "(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi"],
71
+        "193" => ["Nepal Standard Time",                       "(GMT+05:45) Kathmandu"],
72
+        "195" => ["Central Asia Standard Time",                "(GMT+06:00) Astana, Dhaka"],
73
+        "200" => ["Sri Lanka Standard Time",                   "(GMT+06:00) Sri Jayawardenepura"],
74
+        "201" => ["N Central Asia Standard Time",              "(GMT+06:00) Almaty, Novosibirsk"],
75
+        "203" => ["Myanmar Standard Time",                     "(GMT+06:30) Yangon Rangoon"],
76
+        "205" => ["SE Asia Standard Time",                     "(GMT+07:00) Bangkok, Hanoi, Jakarta"],
77
+        "207" => ["North Asia Standard Time",                  "(GMT+07:00) Krasnoyarsk"],
78
+        "210" => ["China Standard Time",                       "(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi"],
79
+        "215" => ["Singapore Standard Time",                   "(GMT+08:00) Kuala Lumpur, Singapore"],
80
+        "220" => ["Taipei Standard Time",                      "(GMT+08:00) Taipei"],
81
+        "225" => ["W Australia Standard Time",                 "(GMT+08:00) Perth"],
82
+        "227" => ["North Asia East Standard Time",             "(GMT+08:00) Irkutsk, Ulaanbaatar"],
83
+        "230" => ["Korea Standard Time",                       "(GMT+09:00) Seoul"],
84
+        "235" => ["Tokyo Standard Time",                       "(GMT+09:00) Osaka, Sapporo, Tokyo"],
85
+        "240" => ["Yakutsk Standard Time",                     "(GMT+09:00) Yakutsk"],
86
+        "245" => ["AUS Central Standard Time",                 "(GMT+09:30) Darwin"],
87
+        "250" => ["Cen Australia Standard Time",               "(GMT+09:30) Adelaide"],
88
+        "255" => ["AUS Eastern Standard Time",                 "(GMT+10:00) Canberra, Melbourne, Sydney"],
89
+        "260" => ["E Australia Standard Time",                 "(GMT+10:00) Brisbane"],
90
+        "265" => ["Tasmania Standard Time",                    "(GMT+10:00) Hobart"],
91
+        "270" => ["Vladivostok Standard Time",                 "(GMT+10:00) Vladivostok"],
92
+        "275" => ["West Pacific Standard Time",                "(GMT+10:00) Guam, Port Moresby"],
93
+        "280" => ["Central Pacific Standard Time",             "(GMT+11:00) Magadan, Solomon Islands, New Caledonia"],
94
+        "285" => ["Fiji Islands Standard Time",                "(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands"],
95
+        "290" => ["New Zealand Standard Time",                 "(GMT+12:00) Auckland, Wellington"],
96
+        "300" => ["Tonga Standard Time",                       "(GMT+13:00) Nuku'alofa"],
97
+    ];
98
+
99
+    /**
100
+     * Python generated offset list
101
+     * dots in keys were removed.
102
+     *
103
+     * Array indices
104
+     *  0 = lBias
105
+     *  1 = lStandardBias
106
+     *  2 = lDSTBias
107
+     *  3 = wStartYear
108
+     *  4 = wStartMonth
109
+     *  5 = wStartDOW
110
+     *  6 = wStartDay
111
+     *  7 = wStartHour
112
+     *  8 = wStartMinute
113
+     *  9 = wStartSecond
114
+     * 10 = wStartMilliseconds
115
+     * 11 = wEndYear
116
+     * 12 = wEndMonth
117
+     * 13 = wEndDOW
118
+     * 14 = wEndDay
119
+     * 15 = wEndHour
120
+     * 16 = wEndMinute
121
+     * 17 = wEndSecond
122
+     * 18 = wEndMilloseconds
123
+     *
124
+     * As the $tzoneoffsets and the $mstzones need to be resolved in both directions,
125
+     * some offsets are commented as they are not available in the $mstzones.
126
+     *
127
+     * Created at: 01.06.2012
128
+     */
129
+    private static $tzonesoffsets = [
130
+        "Transitional Islamic State of Afghanistan Standard Time" => [-270, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
131
+        "Alaskan Standard Time" => [540, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
132
+        "Arab Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
133
+        "Arabian Standard Time" => [-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
134
+        "Arabic Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
135
+        // "Argentina Standard Time"                   => array(180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
136
+        "Atlantic Standard Time" => [240, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
137
+        "AUS Central Standard Time" => [-570, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
138
+        "AUS Eastern Standard Time" => [-600, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
139
+        // "Azerbaijan Standard Time"                  => array(-240, 0, -60,  0, 10, 0, 5, 5, 0, 0, 0,  0, 3, 0, 5, 4, 0, 0, 0),
140
+        "Azores Standard Time" => [60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
141
+        // "Bangladesh Standard Time"                  => array(-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
142
+        "Canada Central Standard Time" => [360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
143
+        "Cape Verde Standard Time" => [60, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
144
+        "Caucasus Standard Time" => [-240, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
145
+        "Cen Australia Standard Time" => [-570, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
146
+        "Central America Standard Time" => [360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
147
+        "Central Asia Standard Time" => [-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
148
+        // "Central Brazilian Standard Time"           => array(240, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999),
149
+        "Central Europe Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
150
+        "Central European Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
151
+        "Central Pacific Standard Time" => [-660, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
152
+        "Central Standard Time" => [360, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
153
+        "Mexico Standard Time" => [360, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0],
154
+        "China Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
155
+        "Dateline Standard Time" => [720, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
156
+        "E Africa Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
157
+        "E Australia Standard Time" => [-600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
158
+        "E Europe Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
159
+        "E South America Standard Time" => [180, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999],
160
+        "Eastern Standard Time" => [300, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
161
+        "Egypt Standard Time" => [-120, 0, -60,  0, 9, 4, 5, 23, 59, 59, 999,  0, 4, 4, 5, 23, 59, 59, 999],
162
+        "Ekaterinburg Standard Time" => [-300, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
163
+        "Fiji Islands Standard Time" => [-720, 0, -60,  0, 3, 0, 5, 3, 0, 0, 0,  0, 10, 0, 4, 2, 0, 0, 0],
164
+        "FLE Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 4, 0, 0, 0,  0, 3, 0, 5, 3, 0, 0, 0],
165
+        // "Georgian Standard Time"                    => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
166
+        "GMT Standard Time" => [0, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 3, 0, 5, 1, 0, 0, 0],
167
+        "Greenland Standard Time" => [180, 0, -60,  0, 10, 6, 5, 23, 0, 0, 0,  0, 3, 6, 4, 22, 0, 0, 0],
168
+        "Greenwich Standard Time" => [0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
169
+        "GTB Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 4, 0, 0, 0,  0, 3, 0, 5, 3, 0, 0, 0],
170
+        "Hawaiian Standard Time" => [600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
171
+        "India Standard Time" => [-330, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
172
+        "Iran Standard Time" => [-210, 0, -60,  0, 9, 1, 3, 23, 59, 59, 999,  0, 3, 6, 3, 23, 59, 59, 999],
173
+        "Israel Standard Time" => [-120, 0, -60,  0, 9, 0, 4, 2, 0, 0, 0,  0, 3, 5, 5, 2, 0, 0, 0],
174
+        // "Jordan Standard Time"                      => array(-120, 0, -60,  0, 10, 5, 5, 1, 0, 0, 0,  0, 3, 4, 5, 23, 59, 59, 999),
175
+        // "Kamchatka Standard Time"                   => array(-720, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
176
+        "Korea Standard Time" => [-540, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
177
+        // "Magadan Standard Time"                     => array(-660, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
178
+        // "Mauritius Standard Time"                   => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
179
+        "Mid-Atlantic Standard Time" => [120, 0, -60,  0, 9, 0, 5, 2, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
180
+        // "Middle East Standard Time"                 => array(-120, 0, -60,  0, 10, 6, 5, 23, 59, 59, 999,  0, 3, 6, 4, 23, 59, 59, 999),
181
+        // "Montevideo Standard Time"                  => array(180, 0, -60,  0, 3, 0, 2, 2, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0),
182
+        // "Morocco Standard Time"                     => array(0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
183
+        "Mountain Standard Time" => [420, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
184
+        "Mexico Standard Time 2" => [420, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0],
185
+        "Myanmar Standard Time" => [-390, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
186
+        "N Central Asia Standard Time" => [-360, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
187
+        // "Namibia Standard Time"                     => array(-60, 0, -60,  0, 4, 0, 1, 2, 0, 0, 0,  0, 9, 0, 1, 2, 0, 0, 0),
188
+        "Nepal Standard Time" => [-345, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
189
+        "New Zealand Standard Time" => [-720, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 9, 0, 5, 2, 0, 0, 0],
190
+        "Newfoundland and Labrador Standard Time" => [210, 0, -60,  0, 11, 0, 1, 0, 1, 0, 0,  0, 3, 0, 2, 0, 1, 0, 0],
191
+        "North Asia East Standard Time" => [-480, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
192
+        "North Asia Standard Time" => [-420, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
193
+        "Pacific SA Standard Time" => [240, 0, -60,  0, 3, 6, 2, 23, 59, 59, 999,  0, 10, 6, 2, 23, 59, 59, 999],
194
+        "Pacific Standard Time" => [480, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
195
+        // "Pacific Standard Time (Mexico)"            => array(480, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0),
196
+        // "Pakistan Standard Time"                    => array(-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
197
+        // "Paraguay Standard Time"                    => array(240, 0, -60,  0, 4, 6, 1, 23, 59, 59, 999,  0, 10, 6, 1, 23, 59, 59, 999),
198
+        "Romance Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
199
+        "Russian Standard Time" => [-180, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
200
+        "SA Eastern Standard Time" => [180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
201
+        "SA Pacific Standard Time" => [300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
202
+        "SA Western Standard Time" => [240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
203
+        "Samoa Standard Time" => [660, 0, -60,  0, 3, 6, 5, 23, 59, 59, 999,  0, 9, 6, 5, 23, 59, 59, 999],
204
+        "SE Asia Standard Time" => [-420, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
205
+        "Singapore Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
206
+        "South Africa Standard Time" => [-120, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
207
+        "Sri Lanka Standard Time" => [-330, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
208
+        // "Syria Standard Time"                       => array(-120, 0, -60,  0, 10, 4, 5, 23, 59, 59, 999,  0, 4, 4, 1, 23, 59, 59, 999),
209
+        "Taipei Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
210
+        "Tasmania Standard Time" => [-600, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
211
+        "Tokyo Standard Time" => [-540, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
212
+        "Tonga Standard Time" => [-780, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
213
+        // "Ulaanbaatar Standard Time"                 => array(-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
214
+        "US Eastern Standard Time" => [300, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
215
+        "US Mountain Standard Time" => [420, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
216
+        // "UTC"                                       => array(0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
217
+        // "UTC+12"                                    => array(-720, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
218
+        // "UTC-02"                                    => array(120, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
219
+        // "UTC-11"                                    => array(660, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
220
+        "Venezuela Standard Time" => [270, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
221
+        "Vladivostok Standard Time" => [-600, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
222
+        "W Australia Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
223
+        "W Central Africa Standard Time" => [-60, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
224
+        "W Europe Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
225
+        "West Asia Standard Time" => [-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
226
+        "West Pacific Standard Time" => [-600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
227
+        "Yakutsk Standard Time" => [-540, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
228
+    ];
229
+
230
+    /**
231
+     * Generated list of PHP timezones in GMT timezones.
232
+     *
233
+     * Created at: 01.06.2012
234
+     */
235
+    private static $phptimezones = [
236
+        // -720 min
237
+        "Dateline Standard Time" => [
238
+            "Etc/GMT+12",
239
+        ],
240
+
241
+        // -660 min
242
+        "Samoa Standard Time" => [
243
+            "Etc/GMT+11",
244
+            "Pacific/Midway",
245
+            "Pacific/Niue",
246
+            "Pacific/Pago_Pago",
247
+            "Pacific/Samoa",
248
+            "US/Samoa",
249
+        ],
250
+
251
+        // -600 min
252
+        "Hawaiian Standard Time" => [
253
+            "America/Adak",
254
+            "America/Atka",
255
+            "Etc/GMT+10",
256
+            "HST",
257
+            "Pacific/Honolulu",
258
+            "Pacific/Johnston",
259
+            "Pacific/Rarotonga",
260
+            "Pacific/Tahiti",
261
+            "US/Aleutian",
262
+            "US/Hawaii",
263
+        ],
264
+
265
+        // -570 min
266
+        "-570" => [
267
+            "Pacific/Marquesas",
268
+        ],
269
+
270
+        // -540 min
271
+        "Alaskan Standard Time" => [
272
+            "America/Anchorage",
273
+            "America/Juneau",
274
+            "America/Nome",
275
+            "America/Sitka",
276
+            "America/Yakutat",
277
+            "Etc/GMT+9",
278
+            "Pacific/Gambier",
279
+            "US/Alaska",
280
+        ],
281
+
282
+        // -480 min
283
+        "Pacific Standard Time" => [
284
+            "America/Dawson",
285
+            "America/Ensenada",
286
+            "America/Los_Angeles",
287
+            "America/Metlakatla",
288
+            "America/Santa_Isabel",
289
+            "America/Tijuana",
290
+            "America/Vancouver",
291
+            "America/Whitehorse",
292
+            "Canada/Pacific",
293
+            "Canada/Yukon",
294
+            "Etc/GMT+8",
295
+            "Mexico/BajaNorte",
296
+            "Pacific/Pitcairn",
297
+            "PST8PDT",
298
+            "US/Pacific",
299
+            "US/Pacific-New",
300
+        ],
301
+
302
+        // -420 min
303
+        "US Mountain Standard Time" => [
304
+            "America/Boise",
305
+            "America/Cambridge_Bay",
306
+            "America/Chihuahua",
307
+            "America/Creston",
308
+            "America/Dawson_Creek",
309
+            "America/Denver",
310
+            "America/Edmonton",
311
+            "America/Hermosillo",
312
+            "America/Inuvik",
313
+            "America/Mazatlan",
314
+            "America/Ojinaga",
315
+            "America/Phoenix",
316
+            "America/Shiprock",
317
+            "America/Yellowknife",
318
+            "Canada/Mountain",
319
+            "Etc/GMT+7",
320
+            "Mexico/BajaSur",
321
+            "MST",
322
+            "MST7MDT",
323
+            "Navajo",
324
+            "US/Arizona",
325
+            "US/Mountain",
326
+        ],
327
+
328
+        // -360 min
329
+        "Central Standard Time" => [
330
+            "America/Chicago",
331
+            "America/Indiana/Knox",
332
+            "America/Indiana/Tell_City",
333
+            "America/Knox_IN",
334
+            "America/North_Dakota/Beulah",
335
+            "America/North_Dakota/Center",
336
+            "America/North_Dakota/New_Salem",
337
+            "America/Rainy_River",
338
+            "America/Rankin_Inlet",
339
+            "America/Regina",
340
+            "America/Resolute",
341
+            "America/Swift_Current",
342
+            "America/Tegucigalpa",
343
+            "America/Winnipeg",
344
+            "US/Central",
345
+            "US/Indiana-Starke",
346
+            "CST6CDT",
347
+            "Etc/GMT+6",
348
+        ],
349
+        "Canada Central Standard Time" => [
350
+            "Canada/Central",
351
+            "Canada/East-Saskatchewan",
352
+            "Canada/Saskatchewan",
353
+        ],
354
+        "Mexico Standard Time" => [
355
+            "America/Mexico_City",
356
+            "America/Monterrey",
357
+            "Mexico/General",
358
+        ],
359
+        "Central America Standard Time" => [
360
+            "America/Bahia_Banderas",
361
+            "America/Belize",
362
+            "America/Cancun",
363
+            "America/Costa_Rica",
364
+            "America/El_Salvador",
365
+            "America/Guatemala",
366
+            "America/Managua",
367
+            "America/Matamoros",
368
+            "America/Menominee",
369
+            "America/Merida",
370
+            "Chile/EasterIsland",
371
+            "Pacific/Easter",
372
+            "Pacific/Galapagos",
373
+        ],
374
+
375
+        // -300 min
376
+        "US Eastern Standard Time" => [
377
+            "America/Detroit",
378
+            "America/Fort_Wayne",
379
+            "America/Grand_Turk",
380
+            "America/Indiana/Indianapolis",
381
+            "America/Indiana/Marengo",
382
+            "America/Indiana/Petersburg",
383
+            "America/Indiana/Vevay",
384
+            "America/Indiana/Vincennes",
385
+            "America/Indiana/Winamac",
386
+            "America/Indianapolis",
387
+            "America/Jamaica",
388
+            "America/Kentucky/Louisville",
389
+            "America/Kentucky/Monticello",
390
+            "America/Louisville",
391
+            "America/Montreal",
392
+            "America/New_York",
393
+            "America/Thunder_Bay",
394
+            "America/Toronto",
395
+            "Canada/Eastern",
396
+            "Cuba",
397
+            "EST",
398
+            "EST5EDT",
399
+            "Etc/GMT+5",
400
+            "Jamaica",
401
+            "US/East-Indiana",
402
+            "US/Eastern",
403
+            "US/Michigan",
404
+        ],
405
+        "SA Pacific Standard Time" => [
406
+            "America/Atikokan",
407
+            "America/Bogota",
408
+            "America/Cayman",
409
+            "America/Coral_Harbour",
410
+            "America/Guayaquil",
411
+            "America/Havana",
412
+            "America/Iqaluit",
413
+            "America/Lima",
414
+            "America/Nassau",
415
+            "America/Nipigon",
416
+            "America/Panama",
417
+            "America/Pangnirtung",
418
+            "America/Port-au-Prince",
419
+        ],
420
+
421
+        // -270 min
422
+        "Venezuela Standard Time" => [
423
+            "America/Caracas",
424
+        ],
425
+        // -240 min
426
+        "Atlantic Standard Time" => [
427
+            "America/Barbados",
428
+            "America/Blanc-Sablon",
429
+            "America/Glace_Bay",
430
+            "America/Goose_Bay",
431
+            "America/Halifax",
432
+            "America/Lower_Princes",
433
+            "America/St_Barthelemy",
434
+            "America/St_Kitts",
435
+            "America/St_Lucia",
436
+            "America/St_Thomas",
437
+            "America/St_Vincent",
438
+            "America/Thule",
439
+            "America/Tortola",
440
+            "America/Virgin",
441
+            "Atlantic/Bermuda",
442
+            "Canada/Atlantic",
443
+            "Etc/GMT+4",
444
+        ],
445
+        "SA Western Standard Time" => [
446
+            "America/Anguilla",
447
+            "America/Antigua",
448
+            "America/Aruba",
449
+            "America/Asuncion",
450
+            "America/Boa_Vista",
451
+            "America/Campo_Grande",
452
+            "America/Cuiaba",
453
+            "America/Curacao",
454
+            "America/Dominica",
455
+            "America/Eirunepe",
456
+            "America/Grenada",
457
+            "America/Guadeloupe",
458
+            "America/Guyana",
459
+            "America/Kralendijk",
460
+            "America/La_Paz",
461
+            "America/Manaus",
462
+            "America/Marigot",
463
+            "America/Martinique",
464
+            "America/Moncton",
465
+            "America/Montserrat",
466
+            "America/Port_of_Spain",
467
+            "America/Porto_Acre",
468
+            "America/Porto_Velho",
469
+            "America/Puerto_Rico",
470
+            "America/Rio_Branco",
471
+            "Brazil/Acre",
472
+            "Brazil/West",
473
+        ],
474
+        "Pacific SA Standard Time" => [
475
+            "America/Santiago",
476
+            "America/Santo_Domingo",
477
+            "Antarctica/Palmer",
478
+            "Chile/Continental",
479
+        ],
480
+
481
+        // -210 min
482
+        "Newfoundland and Labrador Standard Time" => [
483
+            "America/St_Johns",
484
+            "Canada/Newfoundland",
485
+        ],
486
+
487
+        // -180 min
488
+        "E South America Standard Time" => [
489
+            "America/Araguaina",
490
+            "America/Bahia",
491
+            "America/Belem",
492
+            "America/Fortaleza",
493
+            "America/Maceio",
494
+            "America/Recife",
495
+            "America/Sao_Paulo",
496
+            "Brazil/East",
497
+            "Etc/GMT+3",
498
+        ],
499
+        "SA Eastern Standard Time" => [
500
+            "America/Argentina/Buenos_Aires",
501
+            "America/Argentina/Catamarca",
502
+            "America/Argentina/ComodRivadavia",
503
+            "America/Argentina/Cordoba",
504
+            "America/Argentina/Jujuy",
505
+            "America/Argentina/La_Rioja",
506
+            "America/Argentina/Mendoza",
507
+            "America/Argentina/Rio_Gallegos",
508
+            "America/Argentina/Salta",
509
+            "America/Argentina/San_Juan",
510
+            "America/Argentina/San_Luis",
511
+            "America/Argentina/Tucuman",
512
+            "America/Argentina/Ushuaia",
513
+            "America/Buenos_Aires",
514
+            "America/Catamarca",
515
+            "America/Cayenne",
516
+            "America/Cordoba",
517
+            "America/Godthab",
518
+            "America/Jujuy",
519
+            "America/Mendoza",
520
+            "America/Miquelon",
521
+            "America/Montevideo",
522
+            "America/Paramaribo",
523
+            "America/Rosario",
524
+            "America/Santarem",
525
+        ],
526
+        "Greenland Standard Time" => [
527
+            "Antarctica/Rothera",
528
+            "Atlantic/Stanley",
529
+        ],
530
+
531
+        // -120 min
532
+        "Mid-Atlantic Standard Time" => [
533
+            "America/Noronha",
534
+            "Atlantic/South_Georgia",
535
+            "Brazil/DeNoronha",
536
+            "Etc/GMT+2",
537
+        ],
538
+
539
+        // -60 min
540
+        "Azores Standard Time" => [
541
+            "Atlantic/Azores",
542
+            "Etc/GMT+1",
543
+        ],
544
+        "Cape Verde Standard Time" => [
545
+            "America/Scoresbysund",
546
+            "Atlantic/Cape_Verde",
547
+        ],
548
+
549
+        // 0 min
550
+        "GMT Standard Time" => [
551
+            "Eire",
552
+            "Etc/GMT",
553
+            "Etc/GMT+0",
554
+            "Etc/GMT-0",
555
+            "Etc/GMT0",
556
+            "Etc/Greenwich",
557
+            "Etc/UCT",
558
+            "Etc/Universal",
559
+            "Etc/UTC",
560
+            "Etc/Zulu",
561
+            "Europe/Belfast",
562
+            "Europe/Dublin",
563
+            "Europe/Guernsey",
564
+            "Europe/Isle_of_Man",
565
+            "Europe/Jersey",
566
+            "Europe/Lisbon",
567
+            "Europe/London",
568
+            "Factory",
569
+            "GB",
570
+            "GB-Eire",
571
+            "GMT",
572
+            "GMT+0",
573
+            "GMT-0",
574
+            "GMT0",
575
+            "Greenwich",
576
+            "Iceland",
577
+            "Portugal",
578
+            "UCT",
579
+            "Universal",
580
+            "UTC",
581
+        ],
582
+        "Greenwich Standard Time" => [
583
+            "Africa/Abidjan",
584
+            "Africa/Accra",
585
+            "Africa/Bamako",
586
+            "Africa/Banjul",
587
+            "Africa/Bissau",
588
+            "Africa/Casablanca",
589
+            "Africa/Conakry",
590
+            "Africa/Dakar",
591
+            "Africa/El_Aaiun",
592
+            "Africa/Freetown",
593
+            "Africa/Lome",
594
+            "Africa/Monrovia",
595
+            "Africa/Nouakchott",
596
+            "Africa/Ouagadougou",
597
+            "Africa/Sao_Tome",
598
+            "Africa/Timbuktu",
599
+            "America/Danmarkshavn",
600
+            "Atlantic/Canary",
601
+            "Atlantic/Faeroe",
602
+            "Atlantic/Faroe",
603
+            "Atlantic/Madeira",
604
+            "Atlantic/Reykjavik",
605
+            "Atlantic/St_Helena",
606
+            "Zulu",
607
+        ],
608
+
609
+        // +60 min
610
+        "Central Europe Standard Time" => [
611
+            "Europe/Belgrade",
612
+            "Europe/Bratislava",
613
+            "Europe/Budapest",
614
+            "Europe/Ljubljana",
615
+            "Europe/Prague",
616
+            "Europe/Vaduz",
617
+        ],
618
+        "Central European Standard Time" => [
619
+            "Europe/Sarajevo",
620
+            "Europe/Skopje",
621
+            "Europe/Warsaw",
622
+            "Europe/Zagreb",
623
+            "MET",
624
+            "Poland",
625
+        ],
626
+        "Romance Standard Time" => [
627
+            "Europe/Andorra",
628
+            "Europe/Brussels",
629
+            "Europe/Copenhagen",
630
+            "Europe/Gibraltar",
631
+            "Europe/Madrid",
632
+            "Europe/Malta",
633
+            "Europe/Monaco",
634
+            "Europe/Paris",
635
+            "Europe/Podgorica",
636
+            "Europe/San_Marino",
637
+            "Europe/Tirane",
638
+        ],
639
+        "W Europe Standard Time" => [
640
+            "Europe/Amsterdam",
641
+            "Europe/Berlin",
642
+            "Europe/Luxembourg",
643
+            "Europe/Vatican",
644
+            "Europe/Rome",
645
+            "Europe/Stockholm",
646
+            "Arctic/Longyearbyen",
647
+            "Europe/Vienna",
648
+            "Europe/Zurich",
649
+            "Europe/Oslo",
650
+            "WET",
651
+            "CET",
652
+            "Etc/GMT-1",
653
+        ],
654
+        "W Central Africa Standard Time" => [
655
+            "Africa/Algiers",
656
+            "Africa/Bangui",
657
+            "Africa/Brazzaville",
658
+            "Africa/Ceuta",
659
+            "Africa/Douala",
660
+            "Africa/Kinshasa",
661
+            "Africa/Lagos",
662
+            "Africa/Libreville",
663
+            "Africa/Luanda",
664
+            "Africa/Malabo",
665
+            "Africa/Ndjamena",
666
+            "Africa/Niamey",
667
+            "Africa/Porto-Novo",
668
+            "Africa/Tunis",
669
+            "Africa/Windhoek",
670
+            "Atlantic/Jan_Mayen",
671
+        ],
672
+
673
+        // +120 min
674
+        "E Europe Standard Time" => [
675
+            "Europe/Bucharest",
676
+            "EET",
677
+            "Etc/GMT-2",
678
+            "Europe/Chisinau",
679
+            "Europe/Mariehamn",
680
+            "Europe/Nicosia",
681
+            "Europe/Simferopol",
682
+            "Europe/Tiraspol",
683
+            "Europe/Uzhgorod",
684
+            "Europe/Zaporozhye",
685
+        ],
686
+        "Egypt Standard Time" => [
687
+            "Africa/Cairo",
688
+            "Africa/Tripoli",
689
+            "Egypt",
690
+            "Libya",
691
+        ],
692
+        "FLE Standard Time" => [
693
+            "Europe/Helsinki",
694
+            "Europe/Kiev",
695
+            "Europe/Riga",
696
+            "Europe/Sofia",
697
+            "Europe/Tallinn",
698
+            "Europe/Vilnius",
699
+        ],
700
+        "GTB Standard Time" => [
701
+            "Asia/Istanbul",
702
+            "Europe/Athens",
703
+            "Europe/Istanbul",
704
+            "Turkey",
705
+        ],
706
+        "Israel Standard Time" => [
707
+            "Asia/Amman",
708
+            "Asia/Beirut",
709
+            "Asia/Damascus",
710
+            "Asia/Gaza",
711
+            "Asia/Hebron",
712
+            "Asia/Nicosia",
713
+            "Asia/Tel_Aviv",
714
+            "Asia/Jerusalem",
715
+            "Israel",
716
+        ],
717
+        "South Africa Standard Time" => [
718
+            "Africa/Blantyre",
719
+            "Africa/Bujumbura",
720
+            "Africa/Gaborone",
721
+            "Africa/Harare",
722
+            "Africa/Johannesburg",
723
+            "Africa/Kigali",
724
+            "Africa/Lubumbashi",
725
+            "Africa/Lusaka",
726
+            "Africa/Maputo",
727
+            "Africa/Maseru",
728
+            "Africa/Mbabane",
729
+        ],
730
+
731
+        // +180 min
732
+        "Russian Standard Time" => [
733
+            "Antarctica/Syowa",
734
+            "Europe/Kaliningrad",
735
+            "Europe/Minsk",
736
+            "Etc/GMT-3",
737
+        ],
738
+        "Arab Standard Time" => [
739
+            "Asia/Qatar",
740
+            "Asia/Kuwait",
741
+            "Asia/Riyadh",
742
+        ],
743
+        "E Africa Standard Time" => [
744
+            "Africa/Addis_Ababa",
745
+            "Africa/Asmara",
746
+            "Africa/Asmera",
747
+            "Africa/Dar_es_Salaam",
748
+            "Africa/Djibouti",
749
+            "Africa/Juba",
750
+            "Africa/Kampala",
751
+            "Africa/Khartoum",
752
+            "Africa/Mogadishu",
753
+            "Africa/Nairobi",
754
+        ],
755
+        "Arabic Standard Time" => [
756
+            "Asia/Aden",
757
+            "Asia/Baghdad",
758
+            "Asia/Bahrain",
759
+            "Indian/Antananarivo",
760
+            "Indian/Comoro",
761
+            "Indian/Mayotte",
762
+        ],
763
+
764
+        // +210 min
765
+        "Iran Standard Time" => [
766
+            "Asia/Tehran",
767
+            "Iran",
768
+        ],
769
+
770
+        // +240 min
771
+        "Arabian Standard Time" => [
772
+            "Asia/Dubai",
773
+            "Asia/Muscat",
774
+            "Indian/Mahe",
775
+            "Indian/Mauritius",
776
+            "Indian/Reunion",
777
+        ],
778
+        "Caucasus Standard Time" => [
779
+            "Asia/Baku",
780
+            "Asia/Tbilisi",
781
+            "Asia/Yerevan",
782
+            "Etc/GMT-4",
783
+            "Europe/Moscow",
784
+            "Europe/Samara",
785
+            "Europe/Volgograd",
786
+            "W-SU",
787
+        ],
788
+
789
+        // +270 min
790
+        "Transitional Islamic State of Afghanistan Standard Time" => [
791
+            "Asia/Kabul",
792
+        ],
793
+
794
+        // +300 min
795
+        "Ekaterinburg Standard Time" => [
796
+            "Antarctica/Mawson",
797
+        ],
798
+        "West Asia Standard Time" => [
799
+            "Asia/Aqtau",
800
+            "Asia/Aqtobe",
801
+            "Asia/Ashgabat",
802
+            "Asia/Ashkhabad",
803
+            "Asia/Dushanbe",
804
+            "Asia/Karachi",
805
+            "Asia/Oral",
806
+            "Asia/Samarkand",
807
+            "Asia/Tashkent",
808
+            "Etc/GMT-5",
809
+            "Indian/Kerguelen",
810
+            "Indian/Maldives",
811
+        ],
812
+
813
+        // +330 min
814
+        "India Standard Time" => [
815
+            "Asia/Calcutta",
816
+            "Asia/Colombo",
817
+            "Asia/Kolkata",
818
+        ],
819
+
820
+        // +345 min
821
+        "Nepal Standard Time" => [
822
+            "Asia/Kathmandu",
823
+            "Asia/Katmandu",
824
+        ],
825
+
826
+        // +360 min
827
+        "Central Asia Standard Time" => [
828
+            "Asia/Dacca",
829
+            "Asia/Dhaka",
830
+        ],
831
+        "Sri Lanka Standard Time" => [
832
+            "Indian/Chagos",
833
+        ],
834
+        "N Central Asia Standard Time" => [
835
+            "Antarctica/Vostok",
836
+            "Asia/Almaty",
837
+            "Asia/Bishkek",
838
+            "Asia/Qyzylorda",
839
+            "Asia/Thimbu",
840
+            "Asia/Thimphu",
841
+            "Asia/Yekaterinburg",
842
+            "Etc/GMT-6",
843
+        ],
844
+
845
+        // +390 min
846
+        "Myanmar Standard Time" => [
847
+            "Asia/Rangoon",
848
+            "Indian/Cocos",
849
+        ],
850
+
851
+        // +420 min
852
+        "SE Asia Standard Time" => [
853
+            "Asia/Bangkok",
854
+            "Asia/Ho_Chi_Minh",
855
+            "Asia/Hovd",
856
+            "Asia/Jakarta",
857
+            "Asia/Phnom_Penh",
858
+            "Asia/Saigon",
859
+            "Indian/Christmas",
860
+        ],
861
+        "North Asia Standard Time" => [
862
+            "Antarctica/Davis",
863
+            "Asia/Novokuznetsk",
864
+            "Asia/Novosibirsk",
865
+            "Asia/Omsk",
866
+            "Asia/Pontianak",
867
+            "Asia/Vientiane",
868
+            "Etc/GMT-7",
869
+        ],
870
+
871
+        // +480 min
872
+        "China Standard Time" => [
873
+            "Asia/Brunei",
874
+            "Asia/Choibalsan",
875
+            "Asia/Chongqing",
876
+            "Asia/Chungking",
877
+            "Asia/Harbin",
878
+            "Asia/Hong_Kong",
879
+            "Asia/Shanghai",
880
+            "Asia/Ujung_Pandang",
881
+            "Asia/Urumqi",
882
+            "Hongkong",
883
+            "PRC",
884
+            "ROC",
885
+        ],
886
+        "Singapore Standard Time" => [
887
+            "Singapore",
888
+            "Asia/Singapore",
889
+            "Asia/Kuala_Lumpur",
890
+        ],
891
+        "Taipei Standard Time" => [
892
+            "Asia/Taipei",
893
+        ],
894
+        "W Australia Standard Time" => [
895
+            "Australia/Perth",
896
+            "Australia/West",
897
+        ],
898
+        "North Asia East Standard Time" => [
899
+            "Antarctica/Casey",
900
+            "Asia/Kashgar",
901
+            "Asia/Krasnoyarsk",
902
+            "Asia/Kuching",
903
+            "Asia/Macao",
904
+            "Asia/Macau",
905
+            "Asia/Makassar",
906
+            "Asia/Manila",
907
+            "Etc/GMT-8",
908
+            "Asia/Ulaanbaatar",
909
+            "Asia/Ulan_Bator",
910
+        ],
911
+
912
+        // +525 min
913
+        "525" => [
914
+            "Australia/Eucla",
915
+        ],
916
+
917
+        // +540 min
918
+        "Korea Standard Time" => [
919
+            "Asia/Seoul",
920
+            "Asia/Pyongyang",
921
+            "ROK",
922
+        ],
923
+        "Tokyo Standard Time" => [
924
+            "Asia/Tokyo",
925
+            "Japan",
926
+            "Etc/GMT-9",
927
+        ],
928
+        "Yakutsk Standard Time" => [
929
+            "Asia/Dili",
930
+            "Asia/Irkutsk",
931
+            "Asia/Jayapura",
932
+            "Pacific/Palau",
933
+        ],
934
+
935
+        // +570 min
936
+        "AUS Central Standard Time" => [
937
+            "Australia/Darwin",
938
+            "Australia/North",
939
+        ],
940
+        // DST
941
+        "Cen Australia Standard Time" => [
942
+            "Australia/Adelaide",
943
+            "Australia/Broken_Hill",
944
+            "Australia/South",
945
+            "Australia/Yancowinna",
946
+        ],
947
+
948
+        // +600 min
949
+        "AUS Eastern Standard Time" => [
950
+            "Australia/Canberra",
951
+            "Australia/Melbourne",
952
+            "Australia/Sydney",
953
+            "Australia/Currie",
954
+            "Australia/ACT",
955
+            "Australia/NSW",
956
+            "Australia/Victoria",
957
+        ],
958
+        "E Australia Standard Time" => [
959
+            "Etc/GMT-10",
960
+            "Australia/Brisbane",
961
+            "Australia/Queensland",
962
+            "Australia/Lindeman",
963
+        ],
964
+        "Tasmania Standard Time" => [
965
+            "Australia/Hobart",
966
+            "Australia/Tasmania",
967
+        ],
968
+        "Vladivostok Standard Time" => [
969
+            "Antarctica/DumontDUrville",
970
+        ],
971
+        "West Pacific Standard Time" => [
972
+            "Asia/Yakutsk",
973
+            "Pacific/Chuuk",
974
+            "Pacific/Guam",
975
+            "Pacific/Port_Moresby",
976
+            "Pacific/Saipan",
977
+            "Pacific/Truk",
978
+            "Pacific/Yap",
979
+        ],
980
+
981
+        // +630 min
982
+        "630" => [
983
+            "Australia/LHI",
984
+            "Australia/Lord_Howe",
985
+        ],
986
+
987
+        // +660 min
988
+        "Central Pacific Standard Time" => [
989
+            "Antarctica/Macquarie",
990
+            "Asia/Sakhalin",
991
+            "Asia/Vladivostok",
992
+            "Etc/GMT-11",
993
+            "Pacific/Efate",
994
+            "Pacific/Guadalcanal",
995
+            "Pacific/Kosrae",
996
+            "Pacific/Noumea",
997
+            "Pacific/Pohnpei",
998
+            "Pacific/Ponape",
999
+        ],
1000
+
1001
+        // 690 min
1002
+        "690" => [
1003
+            "Pacific/Norfolk",
1004
+        ],
1005
+
1006
+        // +720 min
1007
+        "Fiji Islands Standard Time" => [
1008
+            "Asia/Anadyr",
1009
+            "Asia/Kamchatka",
1010
+            "Asia/Magadan",
1011
+            "Kwajalein",
1012
+        ],
1013
+        "New Zealand Standard Time" => [
1014
+            "Antarctica/McMurdo",
1015
+            "Antarctica/South_Pole",
1016
+            "Etc/GMT-12",
1017
+            "NZ",
1018
+            "Pacific/Auckland",
1019
+            "Pacific/Fiji",
1020
+            "Pacific/Funafuti",
1021
+            "Pacific/Kwajalein",
1022
+            "Pacific/Majuro",
1023
+            "Pacific/Nauru",
1024
+            "Pacific/Tarawa",
1025
+            "Pacific/Wake",
1026
+            "Pacific/Wallis",
1027
+        ],
1028
+
1029
+        // +765 min
1030
+        "765" => [
1031
+            "NZ-CHAT",
1032
+            "Pacific/Chatham",
1033
+        ],
1034
+
1035
+        // +780 min
1036
+        "Tonga Standard Time" => [
1037
+            "Etc/GMT-13",
1038
+            "Pacific/Apia",
1039
+            "Pacific/Enderbury",
1040
+            "Pacific/Tongatapu",
1041
+        ],
1042
+
1043
+        // +840 min
1044
+        "840" => [
1045
+            "Etc/GMT-14",
1046
+            "Pacific/Fakaofo",
1047
+            "Pacific/Kiritimati",
1048
+        ],
1049
+    ];
1050
+
1051
+    /**
1052
+     * Returns a full timezone array.
1053
+     *
1054
+     * @param string $phptimezone (opt) a php timezone string.
1055
+     *                            If omitted the env. default timezone is used.
1056
+     *
1057
+     * @return array
1058
+     */
1059
+    public static function GetFullTZ($phptimezone = false) {
1060
+        if ($phptimezone === false) {
1061
+            $phptimezone = date_default_timezone_get();
1062
+        }
1063
+
1064
+        SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::GetFullTZ() for " . $phptimezone);
1065
+
1066
+        $servertzname = self::guessTZNameFromPHPName($phptimezone);
1067
+
1068
+        return self::GetFullTZFromTZName($servertzname);
1069
+    }
1070
+
1071
+    /**
1072
+     * Returns a full timezone array.
1073
+     *
1074
+     * @param string $tzname a TZID value
1075
+     *
1076
+     * @return array
1077
+     */
1078
+    public static function GetFullTZFromTZName($tzname) {
1079
+        if (!array_key_exists($tzname, self::$tzonesoffsets)) {
1080
+            SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetFullTZFromTZName('%s'): Is a PHP TimeZone, converting", $tzname));
1081
+            $tzname = self::guessTZNameFromPHPName($tzname);
1082
+        }
1083
+
1084
+        $offset = self::$tzonesoffsets[$tzname];
1085
+
1086
+        return [
1087
+            "bias" => $offset[0],
1088
+            "tzname" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
1089
+            "dstendyear" => $offset[3],
1090
+            "dstendmonth" => $offset[4],
1091
+            "dstendday" => $offset[5],
1092
+            "dstendweek" => $offset[6],
1093
+            "dstendhour" => $offset[7],
1094
+            "dstendminute" => $offset[8],
1095
+            "dstendsecond" => $offset[9],
1096
+            "dstendmillis" => $offset[10],
1097
+            "stdbias" => $offset[1],
1098
+            "tznamedst" => self::encodeTZName(self::getMSTZnameFromTZName($tzname)),
1099
+            "dststartyear" => $offset[11],
1100
+            "dststartmonth" => $offset[12],
1101
+            "dststartday" => $offset[13],
1102
+            "dststartweek" => $offset[14],
1103
+            "dststarthour" => $offset[15],
1104
+            "dststartminute" => $offset[16],
1105
+            "dststartsecond" => $offset[17],
1106
+            "dststartmillis" => $offset[18],
1107
+            "dstbias" => $offset[2],
1108
+        ];
1109
+    }
1110
+
1111
+    /**
1112
+     * Sets the timezone name by matching data from the offset (bias etc).
1113
+     *
1114
+     * @param array $offset a grommunio-sync timezone array
1115
+     * @param mixed $tz
1116
+     *
1117
+     * @return array
1118
+     */
1119
+    public static function FillTZNames($tz) {
1120
+        SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::FillTZNames() filling up bias " . $tz["bias"]);
1121
+        if (!isset($tz["bias"])) {
1122
+            SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::FillTZNames() submitted TZ array does not have a bias");
1123
+        }
1124
+        else {
1125
+            $tzname = self::guessTZNameFromOffset($tz);
1126
+            $tz['tzname'] = $tz['tznamedst'] = self::encodeTZName(self::getMSTZnameFromTZName($tzname));
1127
+        }
1128
+
1129
+        return $tz;
1130
+    }
1131
+
1132
+    /**
1133
+     * Tries to find a timezone using the Bias and other offset parameters.
1134
+     *
1135
+     * @param array $offset a grommunio-sync timezone array
1136
+     *
1137
+     * @return string
1138
+     */
1139
+    private static function guessTZNameFromOffset($offset) {
1140
+        // try to find a quite exact match
1141
+        foreach (self::$tzonesoffsets as $tzname => $tzoffset) {
1142
+            if ($offset["bias"] == $tzoffset[0] &&
1143
+                isset($offset["dstendmonth"]) && $offset["dstendmonth"] == $tzoffset[4] &&
1144
+                isset($offset["dstendday"]) && $offset["dstendday"] == $tzoffset[6] &&
1145
+                isset($offset["dststartmonth"]) && $offset["dststartmonth"] == $tzoffset[12] &&
1146
+                isset($offset["dststartday"]) && $offset["dststartday"] == $tzoffset[14]) {
1147
+                return $tzname;
1148
+            }
1149
+        }
1150
+
1151
+        // try to find a bias match
1152
+        foreach (self::$tzonesoffsets as $tzname => $tzoffset) {
1153
+            if ($offset["bias"] == $tzoffset[0]) {
1154
+                return $tzname;
1155
+            }
1156
+        }
1157
+
1158
+        // nothing found? return gmt
1159
+        SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::guessTZNameFromOffset() no timezone found for the data submitted. Returning 'GMT Standard Time'.");
1160
+
1161
+        return "GMT Standard Time";
1162
+    }
1163
+
1164
+    /**
1165
+     * Tries to find a AS timezone for a php timezone.
1166
+     *
1167
+     * @param string $phpname a php timezone name
1168
+     *
1169
+     * @return string
1170
+     */
1171
+    private static function guessTZNameFromPHPName($phpname) {
1172
+        foreach (self::$phptimezones as $tzn => $phptzs) {
1173
+            if (in_array($phpname, $phptzs)) {
1174
+                if (!is_int($tzn)) {
1175
+                    return $tzn;
1176
+                }
1177
+
1178
+                break;
1179
+            }
1180
+        }
1181
+        SLog::Write(LOGLEVEL_ERROR, sprintf("TimezoneUtil::guessTZNameFromPHPName() no compatible timezone found for '%s'. Returning 'GMT Standard Time'. Please contact the grommunio dev team.", $phpname));
1182
+
1183
+        return self::$mstzones["085"][0];
1184
+    }
1185
+
1186
+    /**
1187
+     * Returns an AS compatible tz name.
1188
+     *
1189
+     * @param string $name internal timezone name
1190
+     *
1191
+     * @return string
1192
+     */
1193
+    private static function getMSTZnameFromTZName($name) {
1194
+        // if $name is empty, get the timezone from system
1195
+        if (trim($name) == '') {
1196
+            $name = date_default_timezone_get();
1197
+            SLog::Write(LOGLEVEL_INFO, sprintf("TimezoneUtil::getMSTZnameFromTZName(): empty timezone name sent. Got timezone from the system: '%s'", $name));
1198
+        }
1199
+
1200
+        foreach (self::$mstzones as $mskey => $msdefs) {
1201
+            if ($name == $msdefs[0]) {
1202
+                return $msdefs[1];
1203
+            }
1204
+        }
1205
+
1206
+        // Not found? Then retrieve the correct TZName first and try again.
1207
+        // That's ugly and needs a proper fix. But for now this method can convert
1208
+        // - Europe/Berlin
1209
+        // - W Europe Standard Time
1210
+        // to "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
1211
+        // which is more correct than the hardcoded default of (GMT+00:00...)
1212
+        $tzName = '';
1213
+        foreach (self::$phptimezones as $tzn => $phptzs) {
1214
+            if (in_array($name, $phptzs)) {
1215
+                $tzName = $tzn;
1216
+
1217
+                break;
1218
+            }
1219
+        }
1220
+        if ($tzName != '') {
1221
+            foreach (self::$mstzones as $mskey => $msdefs) {
1222
+                if ($tzName == $msdefs[0]) {
1223
+                    return $msdefs[1];
1224
+                }
1225
+            }
1226
+        }
1227
+
1228
+        SLog::Write(LOGLEVEL_WARN, sprintf("TimezoneUtil::getMSTZnameFromTZName() no MS name found for '%s'. Returning '(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London'", $name));
1229
+
1230
+        return self::$mstzones["085"][1];
1231
+    }
1232
+
1233
+    /**
1234
+     * Encodes the tz name to UTF-16 compatible with a syncblob.
1235
+     *
1236
+     * @param string $name timezone name
1237
+     *
1238
+     * @return string
1239
+     */
1240
+    private static function encodeTZName($name) {
1241
+        return substr(iconv('UTF-8', 'UTF-16', $name), 2, -1);
1242
+    }
1243
+
1244
+    /**
1245
+     * Test to check if $mstzones and $tzonesoffsets can be resolved
1246
+     * in both directions.
1247
+     *
1248
+     * @return
1249
+     */
1250
+    public static function TZtest() {
1251
+        foreach (self::$mstzones as $mskey => $msdefs) {
1252
+            if (!array_key_exists($msdefs[0], self::$tzonesoffsets)) {
1253
+                echo "key   '" . $msdefs[0] . "'   not found in tzonesoffsets\n";
1254
+            }
1255
+        }
1256
+
1257
+        foreach (self::$tzonesoffsets as $tzname => $offset) {
1258
+            $found = false;
1259
+            foreach (self::$mstzones as $mskey => $msdefs) {
1260
+                if ($tzname == $msdefs[0]) {
1261
+                    $found = true;
1262
+
1263
+                    break;
1264
+                }
1265
+            }
1266
+            if (!$found) {
1267
+                echo "key    '{$tzname}' NOT FOUND\n";
1268
+            }
1269
+        }
1270
+    }
1271
+
1272
+    /**
1273
+     * Pack timezone info for Sync.
1274
+     *
1275
+     * @param array $tz
1276
+     *
1277
+     * @return string
1278
+     */
1279
+    public static function GetSyncBlobFromTZ($tz) {
1280
+        // set the correct TZ name (done using the Bias)
1281
+        if (!isset($tz["tzname"]) || !$tz["tzname"] || !isset($tz["tznamedst"]) || !$tz["tznamedst"]) {
1282
+            $tz = TimezoneUtil::FillTZNames($tz);
1283
+        }
1284
+
1285
+        return pack(
1286
+            "la64vvvvvvvv" . "la64vvvvvvvv" . "l",
1287
+            $tz["bias"],
1288
+            $tz["tzname"],
1289
+            0,
1290
+            $tz["dstendmonth"],
1291
+            $tz["dstendday"],
1292
+            $tz["dstendweek"],
1293
+            $tz["dstendhour"],
1294
+            $tz["dstendminute"],
1295
+            $tz["dstendsecond"],
1296
+            $tz["dstendmillis"],
1297
+            $tz["stdbias"],
1298
+            $tz["tznamedst"],
1299
+            0,
1300
+            $tz["dststartmonth"],
1301
+            $tz["dststartday"],
1302
+            $tz["dststartweek"],
1303
+            $tz["dststarthour"],
1304
+            $tz["dststartminute"],
1305
+            $tz["dststartsecond"],
1306
+            $tz["dststartmillis"],
1307
+            $tz["dstbias"]
1308
+        );
1309
+    }
1310
+
1311
+    /**
1312
+     * Generate date object from string and timezone.
1313
+     *
1314
+     * @param string $value
1315
+     * @param string $timezone
1316
+     *
1317
+     * @return int epoch
1318
+     */
1319
+    public static function MakeUTCDate($value, $timezone = null) {
1320
+        $tz = null;
1321
+        if ($timezone) {
1322
+            $tz = timezone_open($timezone);
1323
+        }
1324
+        if (!$tz) {
1325
+            // If there is no timezone set, we use the default timezone
1326
+            $tz = timezone_open(date_default_timezone_get());
1327
+        }
1328
+        // 20110930T090000Z
1329
+        $date = date_create_from_format('Ymd\THis\Z', $value, timezone_open("UTC"));
1330
+        if (!$date) {
1331
+            // 20110930T090000
1332
+            $date = date_create_from_format('Ymd\THis', $value, $tz);
1333
+        }
1334
+        if (!$date) {
1335
+            // 20110930 (Append T000000Z to the date, so it starts at midnight)
1336
+            $date = date_create_from_format('Ymd\THis\Z', $value . "T000000Z", $tz);
1337
+        }
1338
+
1339
+        return date_timestamp_get($date);
1340
+    }
1341
+
1342
+    /**
1343
+     * Generate a tzid from various formats.
1344
+     *
1345
+     * @param string $timezone
1346
+     *
1347
+     * @return timezone id
1348
+     */
1349
+    public static function ParseTimezone($timezone) {
1350
+        // (GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna
1351
+        if (preg_match('/GMT(\\+|\\-)0(\d)/', $timezone, $matches)) {
1352
+            return "Etc/GMT" . $matches[1] . $matches[2];
1353
+        }
1354
+        // (GMT+10.00) XXX / XXX / XXX / XXX
1355
+        if (preg_match('/GMT(\\+|\\-)1(\d)/', $timezone, $matches)) {
1356
+            return "Etc/GMT" . $matches[1] . "1" . $matches[2];
1357
+        }
1358
+        // /inverse.ca/20101018_1/Europe/Amsterdam or /inverse.ca/20101018_1/America/Argentina/Buenos_Aires
1359
+        if (preg_match('/\/[.[:word:]]+\/\w+\/(\w+)\/([\w\/]+)/', $timezone, $matches)) {
1360
+            return $matches[1] . "/" . $matches[2];
1361
+        }
1362
+
1363
+        return self::getMSTZnameFromTZName(trim($timezone, '"'));
1364
+    }
1365
+
1366
+    /**
1367
+     * Returns a timezone supported by PHP for DateTimeZone constructor.
1368
+     *
1369
+     * @see http://php.net/manual/en/timezones.php
1370
+     *
1371
+     * @param string $timezone
1372
+     *
1373
+     * @return string
1374
+     */
1375
+    public static function GetPhpSupportedTimezone($timezone) {
1376
+        if (in_array($timezone, DateTimeZone::listIdentifiers())) {
1377
+            SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetPhpSupportedTimezone(): '%s' is a PHP supported timezone", $timezone));
1378
+
1379
+            return $timezone;
1380
+        }
1381
+        $dtz = date_default_timezone_get();
1382
+        SLog::Write(LOGLEVEL_DEBUG, sprintf("TimezoneUtil::GetPhpSupportedTimezone(): '%s' is not a PHP supported timezone. Returning default timezone: '%s'", $timezone, $dtz));
1383
+
1384
+        return $dtz;
1385
+    }
1386
+
1387
+    /**
1388
+     * Returns official timezone name from windows timezone name.
1389
+     * E.g. "W Europe Standard Time" for "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna".
1390
+     *
1391
+     * @param string $winTz Timezone name in windows
1392
+     *
1393
+     * @return string timezone name
1394
+     */
1395
+    public static function GetTZNameFromWinTZ($winTz = false) {
1396
+        // Return "GMT Standard Time" per default
1397
+        if ($winTz === false) {
1398
+            return self::$mstzones['085'][0];
1399
+        }
1400
+
1401
+        foreach (self::$mstzones as $mskey => $msdefs) {
1402
+            if ($winTz == $msdefs[1]) {
1403
+                return $msdefs[0];
1404
+            }
1405
+        }
1406
+
1407
+        return self::$mstzones['085'][0];
1408
+    }
1409 1409
 }
Please login to merge, or discard this patch.
Spacing   +160 added lines, -160 removed lines patch added patch discarded remove patch
@@ -17,83 +17,83 @@  discard block
 block discarded – undo
17 17
 	 * Updated at: 01.06.2012
18 18
 	 */
19 19
 	private static $mstzones = [
20
-		"000" => ["Dateline Standard Time",                    "(GMT-12:00) International Date Line West"],
21
-		"001" => ["Samoa Standard Time",                       "(GMT-11:00) Midway Island, Samoa"],
22
-		"002" => ["Hawaiian Standard Time",                    "(GMT-10:00) Hawaii"],
23
-		"003" => ["Alaskan Standard Time",                     "(GMT-09:00) Alaska"],
24
-		"004" => ["Pacific Standard Time",                     "(GMT-08:00) Pacific Time (US and Canada); Tijuana"],
25
-		"010" => ["Mountain Standard Time",                    "(GMT-07:00) Mountain Time (US and Canada)"],
26
-		"013" => ["Mexico Standard Time 2",                    "(GMT-07:00) Chihuahua, La Paz, Mazatlan"],
27
-		"015" => ["US Mountain Standard Time",                 "(GMT-07:00) Arizona"],
28
-		"020" => ["Central Standard Time",                     "(GMT-06:00) Central Time (US and Canada"],
29
-		"025" => ["Canada Central Standard Time",              "(GMT-06:00) Saskatchewan"],
30
-		"030" => ["Mexico Standard Time",                      "(GMT-06:00) Guadalajara, Mexico City, Monterrey"],
31
-		"033" => ["Central America Standard Time",             "(GMT-06:00) Central America"],
32
-		"035" => ["Eastern Standard Time",                     "(GMT-05:00) Eastern Time (US and Canada)"],
33
-		"040" => ["US Eastern Standard Time",                  "(GMT-05:00) Indiana (East)"],
34
-		"045" => ["SA Pacific Standard Time",                  "(GMT-05:00) Bogota, Lima, Quito"],
35
-		"uk1" => ["Venezuela Standard Time",                   "(GMT-04:30) Caracas"],                     // added
36
-		"050" => ["Atlantic Standard Time",                    "(GMT-04:00) Atlantic Time (Canada)"],
37
-		"055" => ["SA Western Standard Time",                  "(GMT-04:00) Caracas, La Paz"],
38
-		"056" => ["Pacific SA Standard Time",                  "(GMT-04:00) Santiago"],
39
-		"060" => ["Newfoundland and Labrador Standard Time",   "(GMT-03:30) Newfoundland and Labrador"],
40
-		"065" => ["E South America Standard Time",             "(GMT-03:00) Brasilia"],
41
-		"070" => ["SA Eastern Standard Time",                  "(GMT-03:00) Buenos Aires, Georgetown"],
42
-		"073" => ["Greenland Standard Time",                   "(GMT-03:00) Greenland"],
43
-		"075" => ["Mid-Atlantic Standard Time",                "(GMT-02:00) Mid-Atlantic"],
44
-		"080" => ["Azores Standard Time",                      "(GMT-01:00) Azores"],
45
-		"083" => ["Cape Verde Standard Time",                  "(GMT-01:00) Cape Verde Islands"],
46
-		"085" => ["GMT Standard Time",                         "(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London"],
47
-		"090" => ["Greenwich Standard Time",                   "(GMT) Casablanca, Monrovia"],
48
-		"095" => ["Central Europe Standard Time",              "(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague"],
49
-		"100" => ["Central European Standard Time",            "(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb"],
50
-		"105" => ["Romance Standard Time",                     "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"],
51
-		"110" => ["W Europe Standard Time",                    "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
52
-		"111" => ["W. Europe Standard Time",                   "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
53
-		"113" => ["W Central Africa Standard Time",            "(GMT+01:00) West Central Africa"],
54
-		"115" => ["E Europe Standard Time",                    "(GMT+02:00) Bucharest"],
55
-		"120" => ["Egypt Standard Time",                       "(GMT+02:00) Cairo"],
56
-		"125" => ["FLE Standard Time",                         "(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius"],
57
-		"130" => ["GTB Standard Time",                         "(GMT+02:00) Athens, Istanbul, Minsk"],
58
-		"135" => ["Israel Standard Time",                      "(GMT+02:00) Jerusalem"],
59
-		"140" => ["South Africa Standard Time",                "(GMT+02:00) Harare, Pretoria"],
60
-		"145" => ["Russian Standard Time",                     "(GMT+03:00) Moscow, St. Petersburg, Volgograd"],
61
-		"150" => ["Arab Standard Time",                        "(GMT+03:00) Kuwait, Riyadh"],
62
-		"155" => ["E Africa Standard Time",                    "(GMT+03:00) Nairobi"],
63
-		"158" => ["Arabic Standard Time",                      "(GMT+03:00) Baghdad"],
64
-		"160" => ["Iran Standard Time",                        "(GMT+03:30) Tehran"],
65
-		"165" => ["Arabian Standard Time",                     "(GMT+04:00) Abu Dhabi, Muscat"],
66
-		"170" => ["Caucasus Standard Time",                    "(GMT+04:00) Baku, Tbilisi, Yerevan"],
20
+		"000" => ["Dateline Standard Time", "(GMT-12:00) International Date Line West"],
21
+		"001" => ["Samoa Standard Time", "(GMT-11:00) Midway Island, Samoa"],
22
+		"002" => ["Hawaiian Standard Time", "(GMT-10:00) Hawaii"],
23
+		"003" => ["Alaskan Standard Time", "(GMT-09:00) Alaska"],
24
+		"004" => ["Pacific Standard Time", "(GMT-08:00) Pacific Time (US and Canada); Tijuana"],
25
+		"010" => ["Mountain Standard Time", "(GMT-07:00) Mountain Time (US and Canada)"],
26
+		"013" => ["Mexico Standard Time 2", "(GMT-07:00) Chihuahua, La Paz, Mazatlan"],
27
+		"015" => ["US Mountain Standard Time", "(GMT-07:00) Arizona"],
28
+		"020" => ["Central Standard Time", "(GMT-06:00) Central Time (US and Canada"],
29
+		"025" => ["Canada Central Standard Time", "(GMT-06:00) Saskatchewan"],
30
+		"030" => ["Mexico Standard Time", "(GMT-06:00) Guadalajara, Mexico City, Monterrey"],
31
+		"033" => ["Central America Standard Time", "(GMT-06:00) Central America"],
32
+		"035" => ["Eastern Standard Time", "(GMT-05:00) Eastern Time (US and Canada)"],
33
+		"040" => ["US Eastern Standard Time", "(GMT-05:00) Indiana (East)"],
34
+		"045" => ["SA Pacific Standard Time", "(GMT-05:00) Bogota, Lima, Quito"],
35
+		"uk1" => ["Venezuela Standard Time", "(GMT-04:30) Caracas"], // added
36
+		"050" => ["Atlantic Standard Time", "(GMT-04:00) Atlantic Time (Canada)"],
37
+		"055" => ["SA Western Standard Time", "(GMT-04:00) Caracas, La Paz"],
38
+		"056" => ["Pacific SA Standard Time", "(GMT-04:00) Santiago"],
39
+		"060" => ["Newfoundland and Labrador Standard Time", "(GMT-03:30) Newfoundland and Labrador"],
40
+		"065" => ["E South America Standard Time", "(GMT-03:00) Brasilia"],
41
+		"070" => ["SA Eastern Standard Time", "(GMT-03:00) Buenos Aires, Georgetown"],
42
+		"073" => ["Greenland Standard Time", "(GMT-03:00) Greenland"],
43
+		"075" => ["Mid-Atlantic Standard Time", "(GMT-02:00) Mid-Atlantic"],
44
+		"080" => ["Azores Standard Time", "(GMT-01:00) Azores"],
45
+		"083" => ["Cape Verde Standard Time", "(GMT-01:00) Cape Verde Islands"],
46
+		"085" => ["GMT Standard Time", "(GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London"],
47
+		"090" => ["Greenwich Standard Time", "(GMT) Casablanca, Monrovia"],
48
+		"095" => ["Central Europe Standard Time", "(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague"],
49
+		"100" => ["Central European Standard Time", "(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb"],
50
+		"105" => ["Romance Standard Time", "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"],
51
+		"110" => ["W Europe Standard Time", "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
52
+		"111" => ["W. Europe Standard Time", "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"],
53
+		"113" => ["W Central Africa Standard Time", "(GMT+01:00) West Central Africa"],
54
+		"115" => ["E Europe Standard Time", "(GMT+02:00) Bucharest"],
55
+		"120" => ["Egypt Standard Time", "(GMT+02:00) Cairo"],
56
+		"125" => ["FLE Standard Time", "(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius"],
57
+		"130" => ["GTB Standard Time", "(GMT+02:00) Athens, Istanbul, Minsk"],
58
+		"135" => ["Israel Standard Time", "(GMT+02:00) Jerusalem"],
59
+		"140" => ["South Africa Standard Time", "(GMT+02:00) Harare, Pretoria"],
60
+		"145" => ["Russian Standard Time", "(GMT+03:00) Moscow, St. Petersburg, Volgograd"],
61
+		"150" => ["Arab Standard Time", "(GMT+03:00) Kuwait, Riyadh"],
62
+		"155" => ["E Africa Standard Time", "(GMT+03:00) Nairobi"],
63
+		"158" => ["Arabic Standard Time", "(GMT+03:00) Baghdad"],
64
+		"160" => ["Iran Standard Time", "(GMT+03:30) Tehran"],
65
+		"165" => ["Arabian Standard Time", "(GMT+04:00) Abu Dhabi, Muscat"],
66
+		"170" => ["Caucasus Standard Time", "(GMT+04:00) Baku, Tbilisi, Yerevan"],
67 67
 		"175" => ["Transitional Islamic State of Afghanistan Standard Time", "(GMT+04:30) Kabul"],
68
-		"180" => ["Ekaterinburg Standard Time",                "(GMT+05:00) Ekaterinburg"],
69
-		"185" => ["West Asia Standard Time",                   "(GMT+05:00) Islamabad, Karachi, Tashkent"],
70
-		"190" => ["India Standard Time",                       "(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi"],
71
-		"193" => ["Nepal Standard Time",                       "(GMT+05:45) Kathmandu"],
72
-		"195" => ["Central Asia Standard Time",                "(GMT+06:00) Astana, Dhaka"],
73
-		"200" => ["Sri Lanka Standard Time",                   "(GMT+06:00) Sri Jayawardenepura"],
74
-		"201" => ["N Central Asia Standard Time",              "(GMT+06:00) Almaty, Novosibirsk"],
75
-		"203" => ["Myanmar Standard Time",                     "(GMT+06:30) Yangon Rangoon"],
76
-		"205" => ["SE Asia Standard Time",                     "(GMT+07:00) Bangkok, Hanoi, Jakarta"],
77
-		"207" => ["North Asia Standard Time",                  "(GMT+07:00) Krasnoyarsk"],
78
-		"210" => ["China Standard Time",                       "(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi"],
79
-		"215" => ["Singapore Standard Time",                   "(GMT+08:00) Kuala Lumpur, Singapore"],
80
-		"220" => ["Taipei Standard Time",                      "(GMT+08:00) Taipei"],
81
-		"225" => ["W Australia Standard Time",                 "(GMT+08:00) Perth"],
82
-		"227" => ["North Asia East Standard Time",             "(GMT+08:00) Irkutsk, Ulaanbaatar"],
83
-		"230" => ["Korea Standard Time",                       "(GMT+09:00) Seoul"],
84
-		"235" => ["Tokyo Standard Time",                       "(GMT+09:00) Osaka, Sapporo, Tokyo"],
85
-		"240" => ["Yakutsk Standard Time",                     "(GMT+09:00) Yakutsk"],
86
-		"245" => ["AUS Central Standard Time",                 "(GMT+09:30) Darwin"],
87
-		"250" => ["Cen Australia Standard Time",               "(GMT+09:30) Adelaide"],
88
-		"255" => ["AUS Eastern Standard Time",                 "(GMT+10:00) Canberra, Melbourne, Sydney"],
89
-		"260" => ["E Australia Standard Time",                 "(GMT+10:00) Brisbane"],
90
-		"265" => ["Tasmania Standard Time",                    "(GMT+10:00) Hobart"],
91
-		"270" => ["Vladivostok Standard Time",                 "(GMT+10:00) Vladivostok"],
92
-		"275" => ["West Pacific Standard Time",                "(GMT+10:00) Guam, Port Moresby"],
93
-		"280" => ["Central Pacific Standard Time",             "(GMT+11:00) Magadan, Solomon Islands, New Caledonia"],
94
-		"285" => ["Fiji Islands Standard Time",                "(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands"],
95
-		"290" => ["New Zealand Standard Time",                 "(GMT+12:00) Auckland, Wellington"],
96
-		"300" => ["Tonga Standard Time",                       "(GMT+13:00) Nuku'alofa"],
68
+		"180" => ["Ekaterinburg Standard Time", "(GMT+05:00) Ekaterinburg"],
69
+		"185" => ["West Asia Standard Time", "(GMT+05:00) Islamabad, Karachi, Tashkent"],
70
+		"190" => ["India Standard Time", "(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi"],
71
+		"193" => ["Nepal Standard Time", "(GMT+05:45) Kathmandu"],
72
+		"195" => ["Central Asia Standard Time", "(GMT+06:00) Astana, Dhaka"],
73
+		"200" => ["Sri Lanka Standard Time", "(GMT+06:00) Sri Jayawardenepura"],
74
+		"201" => ["N Central Asia Standard Time", "(GMT+06:00) Almaty, Novosibirsk"],
75
+		"203" => ["Myanmar Standard Time", "(GMT+06:30) Yangon Rangoon"],
76
+		"205" => ["SE Asia Standard Time", "(GMT+07:00) Bangkok, Hanoi, Jakarta"],
77
+		"207" => ["North Asia Standard Time", "(GMT+07:00) Krasnoyarsk"],
78
+		"210" => ["China Standard Time", "(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi"],
79
+		"215" => ["Singapore Standard Time", "(GMT+08:00) Kuala Lumpur, Singapore"],
80
+		"220" => ["Taipei Standard Time", "(GMT+08:00) Taipei"],
81
+		"225" => ["W Australia Standard Time", "(GMT+08:00) Perth"],
82
+		"227" => ["North Asia East Standard Time", "(GMT+08:00) Irkutsk, Ulaanbaatar"],
83
+		"230" => ["Korea Standard Time", "(GMT+09:00) Seoul"],
84
+		"235" => ["Tokyo Standard Time", "(GMT+09:00) Osaka, Sapporo, Tokyo"],
85
+		"240" => ["Yakutsk Standard Time", "(GMT+09:00) Yakutsk"],
86
+		"245" => ["AUS Central Standard Time", "(GMT+09:30) Darwin"],
87
+		"250" => ["Cen Australia Standard Time", "(GMT+09:30) Adelaide"],
88
+		"255" => ["AUS Eastern Standard Time", "(GMT+10:00) Canberra, Melbourne, Sydney"],
89
+		"260" => ["E Australia Standard Time", "(GMT+10:00) Brisbane"],
90
+		"265" => ["Tasmania Standard Time", "(GMT+10:00) Hobart"],
91
+		"270" => ["Vladivostok Standard Time", "(GMT+10:00) Vladivostok"],
92
+		"275" => ["West Pacific Standard Time", "(GMT+10:00) Guam, Port Moresby"],
93
+		"280" => ["Central Pacific Standard Time", "(GMT+11:00) Magadan, Solomon Islands, New Caledonia"],
94
+		"285" => ["Fiji Islands Standard Time", "(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands"],
95
+		"290" => ["New Zealand Standard Time", "(GMT+12:00) Auckland, Wellington"],
96
+		"300" => ["Tonga Standard Time", "(GMT+13:00) Nuku'alofa"],
97 97
 	];
98 98
 
99 99
 	/**
@@ -127,104 +127,104 @@  discard block
 block discarded – undo
127 127
 	 * Created at: 01.06.2012
128 128
 	 */
129 129
 	private static $tzonesoffsets = [
130
-		"Transitional Islamic State of Afghanistan Standard Time" => [-270, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
131
-		"Alaskan Standard Time" => [540, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
132
-		"Arab Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
133
-		"Arabian Standard Time" => [-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
134
-		"Arabic Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
130
+		"Transitional Islamic State of Afghanistan Standard Time" => [-270, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
131
+		"Alaskan Standard Time" => [540, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
132
+		"Arab Standard Time" => [-180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
133
+		"Arabian Standard Time" => [-240, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
134
+		"Arabic Standard Time" => [-180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
135 135
 		// "Argentina Standard Time"                   => array(180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
136
-		"Atlantic Standard Time" => [240, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
137
-		"AUS Central Standard Time" => [-570, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
138
-		"AUS Eastern Standard Time" => [-600, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
136
+		"Atlantic Standard Time" => [240, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
137
+		"AUS Central Standard Time" => [-570, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
138
+		"AUS Eastern Standard Time" => [-600, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 10, 0, 1, 2, 0, 0, 0],
139 139
 		// "Azerbaijan Standard Time"                  => array(-240, 0, -60,  0, 10, 0, 5, 5, 0, 0, 0,  0, 3, 0, 5, 4, 0, 0, 0),
140
-		"Azores Standard Time" => [60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
140
+		"Azores Standard Time" => [60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
141 141
 		// "Bangladesh Standard Time"                  => array(-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
142
-		"Canada Central Standard Time" => [360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
143
-		"Cape Verde Standard Time" => [60, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
144
-		"Caucasus Standard Time" => [-240, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
145
-		"Cen Australia Standard Time" => [-570, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
146
-		"Central America Standard Time" => [360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
147
-		"Central Asia Standard Time" => [-360, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
142
+		"Canada Central Standard Time" => [360, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
143
+		"Cape Verde Standard Time" => [60, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
144
+		"Caucasus Standard Time" => [-240, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
145
+		"Cen Australia Standard Time" => [-570, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 10, 0, 1, 2, 0, 0, 0],
146
+		"Central America Standard Time" => [360, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
147
+		"Central Asia Standard Time" => [-360, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
148 148
 		// "Central Brazilian Standard Time"           => array(240, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999),
149
-		"Central Europe Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
150
-		"Central European Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
151
-		"Central Pacific Standard Time" => [-660, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
152
-		"Central Standard Time" => [360, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
153
-		"Mexico Standard Time" => [360, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0],
154
-		"China Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
155
-		"Dateline Standard Time" => [720, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
156
-		"E Africa Standard Time" => [-180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
157
-		"E Australia Standard Time" => [-600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
158
-		"E Europe Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
159
-		"E South America Standard Time" => [180, 0, -60,  0, 2, 6, 4, 23, 59, 59, 999,  0, 10, 6, 3, 23, 59, 59, 999],
160
-		"Eastern Standard Time" => [300, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
161
-		"Egypt Standard Time" => [-120, 0, -60,  0, 9, 4, 5, 23, 59, 59, 999,  0, 4, 4, 5, 23, 59, 59, 999],
162
-		"Ekaterinburg Standard Time" => [-300, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
163
-		"Fiji Islands Standard Time" => [-720, 0, -60,  0, 3, 0, 5, 3, 0, 0, 0,  0, 10, 0, 4, 2, 0, 0, 0],
164
-		"FLE Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 4, 0, 0, 0,  0, 3, 0, 5, 3, 0, 0, 0],
149
+		"Central Europe Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
150
+		"Central European Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
151
+		"Central Pacific Standard Time" => [-660, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
152
+		"Central Standard Time" => [360, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
153
+		"Mexico Standard Time" => [360, 0, -60, 0, 10, 0, 5, 2, 0, 0, 0, 0, 4, 0, 1, 2, 0, 0, 0],
154
+		"China Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
155
+		"Dateline Standard Time" => [720, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
156
+		"E Africa Standard Time" => [-180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
157
+		"E Australia Standard Time" => [-600, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
158
+		"E Europe Standard Time" => [-120, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
159
+		"E South America Standard Time" => [180, 0, -60, 0, 2, 6, 4, 23, 59, 59, 999, 0, 10, 6, 3, 23, 59, 59, 999],
160
+		"Eastern Standard Time" => [300, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
161
+		"Egypt Standard Time" => [-120, 0, -60, 0, 9, 4, 5, 23, 59, 59, 999, 0, 4, 4, 5, 23, 59, 59, 999],
162
+		"Ekaterinburg Standard Time" => [-300, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
163
+		"Fiji Islands Standard Time" => [-720, 0, -60, 0, 3, 0, 5, 3, 0, 0, 0, 0, 10, 0, 4, 2, 0, 0, 0],
164
+		"FLE Standard Time" => [-120, 0, -60, 0, 10, 0, 5, 4, 0, 0, 0, 0, 3, 0, 5, 3, 0, 0, 0],
165 165
 		// "Georgian Standard Time"                    => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
166
-		"GMT Standard Time" => [0, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 3, 0, 5, 1, 0, 0, 0],
167
-		"Greenland Standard Time" => [180, 0, -60,  0, 10, 6, 5, 23, 0, 0, 0,  0, 3, 6, 4, 22, 0, 0, 0],
168
-		"Greenwich Standard Time" => [0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
169
-		"GTB Standard Time" => [-120, 0, -60,  0, 10, 0, 5, 4, 0, 0, 0,  0, 3, 0, 5, 3, 0, 0, 0],
170
-		"Hawaiian Standard Time" => [600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
171
-		"India Standard Time" => [-330, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
172
-		"Iran Standard Time" => [-210, 0, -60,  0, 9, 1, 3, 23, 59, 59, 999,  0, 3, 6, 3, 23, 59, 59, 999],
173
-		"Israel Standard Time" => [-120, 0, -60,  0, 9, 0, 4, 2, 0, 0, 0,  0, 3, 5, 5, 2, 0, 0, 0],
166
+		"GMT Standard Time" => [0, 0, -60, 0, 10, 0, 5, 2, 0, 0, 0, 0, 3, 0, 5, 1, 0, 0, 0],
167
+		"Greenland Standard Time" => [180, 0, -60, 0, 10, 6, 5, 23, 0, 0, 0, 0, 3, 6, 4, 22, 0, 0, 0],
168
+		"Greenwich Standard Time" => [0, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
169
+		"GTB Standard Time" => [-120, 0, -60, 0, 10, 0, 5, 4, 0, 0, 0, 0, 3, 0, 5, 3, 0, 0, 0],
170
+		"Hawaiian Standard Time" => [600, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
171
+		"India Standard Time" => [-330, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
172
+		"Iran Standard Time" => [-210, 0, -60, 0, 9, 1, 3, 23, 59, 59, 999, 0, 3, 6, 3, 23, 59, 59, 999],
173
+		"Israel Standard Time" => [-120, 0, -60, 0, 9, 0, 4, 2, 0, 0, 0, 0, 3, 5, 5, 2, 0, 0, 0],
174 174
 		// "Jordan Standard Time"                      => array(-120, 0, -60,  0, 10, 5, 5, 1, 0, 0, 0,  0, 3, 4, 5, 23, 59, 59, 999),
175 175
 		// "Kamchatka Standard Time"                   => array(-720, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
176
-		"Korea Standard Time" => [-540, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
176
+		"Korea Standard Time" => [-540, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
177 177
 		// "Magadan Standard Time"                     => array(-660, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0),
178 178
 		// "Mauritius Standard Time"                   => array(-240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
179
-		"Mid-Atlantic Standard Time" => [120, 0, -60,  0, 9, 0, 5, 2, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
179
+		"Mid-Atlantic Standard Time" => [120, 0, -60, 0, 9, 0, 5, 2, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
180 180
 		// "Middle East Standard Time"                 => array(-120, 0, -60,  0, 10, 6, 5, 23, 59, 59, 999,  0, 3, 6, 4, 23, 59, 59, 999),
181 181
 		// "Montevideo Standard Time"                  => array(180, 0, -60,  0, 3, 0, 2, 2, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0),
182 182
 		// "Morocco Standard Time"                     => array(0, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
183
-		"Mountain Standard Time" => [420, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
184
-		"Mexico Standard Time 2" => [420, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0],
185
-		"Myanmar Standard Time" => [-390, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
186
-		"N Central Asia Standard Time" => [-360, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
183
+		"Mountain Standard Time" => [420, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
184
+		"Mexico Standard Time 2" => [420, 0, -60, 0, 10, 0, 5, 2, 0, 0, 0, 0, 4, 0, 1, 2, 0, 0, 0],
185
+		"Myanmar Standard Time" => [-390, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
186
+		"N Central Asia Standard Time" => [-360, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
187 187
 		// "Namibia Standard Time"                     => array(-60, 0, -60,  0, 4, 0, 1, 2, 0, 0, 0,  0, 9, 0, 1, 2, 0, 0, 0),
188
-		"Nepal Standard Time" => [-345, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
189
-		"New Zealand Standard Time" => [-720, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 9, 0, 5, 2, 0, 0, 0],
190
-		"Newfoundland and Labrador Standard Time" => [210, 0, -60,  0, 11, 0, 1, 0, 1, 0, 0,  0, 3, 0, 2, 0, 1, 0, 0],
191
-		"North Asia East Standard Time" => [-480, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
192
-		"North Asia Standard Time" => [-420, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
193
-		"Pacific SA Standard Time" => [240, 0, -60,  0, 3, 6, 2, 23, 59, 59, 999,  0, 10, 6, 2, 23, 59, 59, 999],
194
-		"Pacific Standard Time" => [480, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
188
+		"Nepal Standard Time" => [-345, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
189
+		"New Zealand Standard Time" => [-720, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 9, 0, 5, 2, 0, 0, 0],
190
+		"Newfoundland and Labrador Standard Time" => [210, 0, -60, 0, 11, 0, 1, 0, 1, 0, 0, 0, 3, 0, 2, 0, 1, 0, 0],
191
+		"North Asia East Standard Time" => [-480, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
192
+		"North Asia Standard Time" => [-420, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
193
+		"Pacific SA Standard Time" => [240, 0, -60, 0, 3, 6, 2, 23, 59, 59, 999, 0, 10, 6, 2, 23, 59, 59, 999],
194
+		"Pacific Standard Time" => [480, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
195 195
 		// "Pacific Standard Time (Mexico)"            => array(480, 0, -60,  0, 10, 0, 5, 2, 0, 0, 0,  0, 4, 0, 1, 2, 0, 0, 0),
196 196
 		// "Pakistan Standard Time"                    => array(-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
197 197
 		// "Paraguay Standard Time"                    => array(240, 0, -60,  0, 4, 6, 1, 23, 59, 59, 999,  0, 10, 6, 1, 23, 59, 59, 999),
198
-		"Romance Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
199
-		"Russian Standard Time" => [-180, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
200
-		"SA Eastern Standard Time" => [180, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
201
-		"SA Pacific Standard Time" => [300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
202
-		"SA Western Standard Time" => [240, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
203
-		"Samoa Standard Time" => [660, 0, -60,  0, 3, 6, 5, 23, 59, 59, 999,  0, 9, 6, 5, 23, 59, 59, 999],
204
-		"SE Asia Standard Time" => [-420, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
205
-		"Singapore Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
206
-		"South Africa Standard Time" => [-120, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
207
-		"Sri Lanka Standard Time" => [-330, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
198
+		"Romance Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
199
+		"Russian Standard Time" => [-180, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
200
+		"SA Eastern Standard Time" => [180, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
201
+		"SA Pacific Standard Time" => [300, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
202
+		"SA Western Standard Time" => [240, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
203
+		"Samoa Standard Time" => [660, 0, -60, 0, 3, 6, 5, 23, 59, 59, 999, 0, 9, 6, 5, 23, 59, 59, 999],
204
+		"SE Asia Standard Time" => [-420, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
205
+		"Singapore Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
206
+		"South Africa Standard Time" => [-120, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
207
+		"Sri Lanka Standard Time" => [-330, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
208 208
 		// "Syria Standard Time"                       => array(-120, 0, -60,  0, 10, 4, 5, 23, 59, 59, 999,  0, 4, 4, 1, 23, 59, 59, 999),
209
-		"Taipei Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
210
-		"Tasmania Standard Time" => [-600, 0, -60,  0, 4, 0, 1, 3, 0, 0, 0,  0, 10, 0, 1, 2, 0, 0, 0],
211
-		"Tokyo Standard Time" => [-540, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
212
-		"Tonga Standard Time" => [-780, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
209
+		"Taipei Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
210
+		"Tasmania Standard Time" => [-600, 0, -60, 0, 4, 0, 1, 3, 0, 0, 0, 0, 10, 0, 1, 2, 0, 0, 0],
211
+		"Tokyo Standard Time" => [-540, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
212
+		"Tonga Standard Time" => [-780, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
213 213
 		// "Ulaanbaatar Standard Time"                 => array(-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
214
-		"US Eastern Standard Time" => [300, 0, -60,  0, 11, 0, 1, 2, 0, 0, 0,  0, 3, 0, 2, 2, 0, 0, 0],
215
-		"US Mountain Standard Time" => [420, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
214
+		"US Eastern Standard Time" => [300, 0, -60, 0, 11, 0, 1, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0, 0, 0],
215
+		"US Mountain Standard Time" => [420, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
216 216
 		// "UTC"                                       => array(0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
217 217
 		// "UTC+12"                                    => array(-720, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
218 218
 		// "UTC-02"                                    => array(120, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
219 219
 		// "UTC-11"                                    => array(660, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0),
220
-		"Venezuela Standard Time" => [270, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
221
-		"Vladivostok Standard Time" => [-600, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
222
-		"W Australia Standard Time" => [-480, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
223
-		"W Central Africa Standard Time" => [-60, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
224
-		"W Europe Standard Time" => [-60, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
225
-		"West Asia Standard Time" => [-300, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
226
-		"West Pacific Standard Time" => [-600, 0, -60,  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0],
227
-		"Yakutsk Standard Time" => [-540, 0, -60,  0, 10, 0, 5, 3, 0, 0, 0,  0, 3, 0, 5, 2, 0, 0, 0],
220
+		"Venezuela Standard Time" => [270, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
221
+		"Vladivostok Standard Time" => [-600, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
222
+		"W Australia Standard Time" => [-480, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
223
+		"W Central Africa Standard Time" => [-60, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
224
+		"W Europe Standard Time" => [-60, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
225
+		"West Asia Standard Time" => [-300, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
226
+		"West Pacific Standard Time" => [-600, 0, -60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
227
+		"Yakutsk Standard Time" => [-540, 0, -60, 0, 10, 0, 5, 3, 0, 0, 0, 0, 3, 0, 5, 2, 0, 0, 0],
228 228
 	];
229 229
 
230 230
 	/**
@@ -1061,7 +1061,7 @@  discard block
 block discarded – undo
1061 1061
 			$phptimezone = date_default_timezone_get();
1062 1062
 		}
1063 1063
 
1064
-		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::GetFullTZ() for " . $phptimezone);
1064
+		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::GetFullTZ() for ".$phptimezone);
1065 1065
 
1066 1066
 		$servertzname = self::guessTZNameFromPHPName($phptimezone);
1067 1067
 
@@ -1117,7 +1117,7 @@  discard block
 block discarded – undo
1117 1117
 	 * @return array
1118 1118
 	 */
1119 1119
 	public static function FillTZNames($tz) {
1120
-		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::FillTZNames() filling up bias " . $tz["bias"]);
1120
+		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::FillTZNames() filling up bias ".$tz["bias"]);
1121 1121
 		if (!isset($tz["bias"])) {
1122 1122
 			SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::FillTZNames() submitted TZ array does not have a bias");
1123 1123
 		}
@@ -1250,7 +1250,7 @@  discard block
 block discarded – undo
1250 1250
 	public static function TZtest() {
1251 1251
 		foreach (self::$mstzones as $mskey => $msdefs) {
1252 1252
 			if (!array_key_exists($msdefs[0], self::$tzonesoffsets)) {
1253
-				echo "key   '" . $msdefs[0] . "'   not found in tzonesoffsets\n";
1253
+				echo "key   '".$msdefs[0]."'   not found in tzonesoffsets\n";
1254 1254
 			}
1255 1255
 		}
1256 1256
 
@@ -1283,7 +1283,7 @@  discard block
 block discarded – undo
1283 1283
 		}
1284 1284
 
1285 1285
 		return pack(
1286
-			"la64vvvvvvvv" . "la64vvvvvvvv" . "l",
1286
+			"la64vvvvvvvv"."la64vvvvvvvv"."l",
1287 1287
 			$tz["bias"],
1288 1288
 			$tz["tzname"],
1289 1289
 			0,
@@ -1333,7 +1333,7 @@  discard block
 block discarded – undo
1333 1333
 		}
1334 1334
 		if (!$date) {
1335 1335
 			// 20110930 (Append T000000Z to the date, so it starts at midnight)
1336
-			$date = date_create_from_format('Ymd\THis\Z', $value . "T000000Z", $tz);
1336
+			$date = date_create_from_format('Ymd\THis\Z', $value."T000000Z", $tz);
1337 1337
 		}
1338 1338
 
1339 1339
 		return date_timestamp_get($date);
@@ -1349,15 +1349,15 @@  discard block
 block discarded – undo
1349 1349
 	public static function ParseTimezone($timezone) {
1350 1350
 		// (GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna
1351 1351
 		if (preg_match('/GMT(\\+|\\-)0(\d)/', $timezone, $matches)) {
1352
-			return "Etc/GMT" . $matches[1] . $matches[2];
1352
+			return "Etc/GMT".$matches[1].$matches[2];
1353 1353
 		}
1354 1354
 		// (GMT+10.00) XXX / XXX / XXX / XXX
1355 1355
 		if (preg_match('/GMT(\\+|\\-)1(\d)/', $timezone, $matches)) {
1356
-			return "Etc/GMT" . $matches[1] . "1" . $matches[2];
1356
+			return "Etc/GMT".$matches[1]."1".$matches[2];
1357 1357
 		}
1358 1358
 		// /inverse.ca/20101018_1/Europe/Amsterdam or /inverse.ca/20101018_1/America/Argentina/Buenos_Aires
1359 1359
 		if (preg_match('/\/[.[:word:]]+\/\w+\/(\w+)\/([\w\/]+)/', $timezone, $matches)) {
1360
-			return $matches[1] . "/" . $matches[2];
1360
+			return $matches[1]."/".$matches[2];
1361 1361
 		}
1362 1362
 
1363 1363
 		return self::getMSTZnameFromTZName(trim($timezone, '"'));
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1120,8 +1120,7 @@
 block discarded – undo
1120 1120
 		SLog::Write(LOGLEVEL_DEBUG, "TimezoneUtil::FillTZNames() filling up bias " . $tz["bias"]);
1121 1121
 		if (!isset($tz["bias"])) {
1122 1122
 			SLog::Write(LOGLEVEL_WARN, "TimezoneUtil::FillTZNames() submitted TZ array does not have a bias");
1123
-		}
1124
-		else {
1123
+		} else {
1125 1124
 			$tzname = self::guessTZNameFromOffset($tz);
1126 1125
 			$tz['tzname'] = $tz['tznamedst'] = self::encodeTZName(self::getMSTZnameFromTZName($tzname));
1127 1126
 		}
Please login to merge, or discard this patch.
lib/utils/stringstreamwrapper.php 3 patches
Indentation   +152 added lines, -152 removed lines patch added patch discarded remove patch
@@ -9,158 +9,158 @@
 block discarded – undo
9 9
  */
10 10
 
11 11
 class StringStreamWrapper {
12
-	public const PROTOCOL = "stringstream";
13
-
14
-	private $stringstream;
15
-	private $position;
16
-	private $stringlength;
17
-	private $truncateHtmlSafe;
18
-	private $context;
19
-
20
-	/**
21
-	 * Opens the stream
22
-	 * The string to be streamed is passed over the context.
23
-	 *
24
-	 * @param string $path        Specifies the URL that was passed to the original function
25
-	 * @param string $mode        The mode used to open the file, as detailed for fopen()
26
-	 * @param int    $options     Holds additional flags set by the streams API
27
-	 * @param string $opened_path if the path is opened successfully, and STREAM_USE_PATH is set in options,
28
-	 *                            opened_path should be set to the full path of the file/resource that was actually opened
29
-	 *
30
-	 * @return bool
31
-	 */
32
-	public function stream_open($path, $mode, $options, &$opened_path) {
33
-		$contextOptions = stream_context_get_options($this->context);
34
-		if (!isset($contextOptions[self::PROTOCOL]['string'])) {
35
-			return false;
36
-		}
37
-
38
-		$this->position = 0;
39
-
40
-		// this is our stream!
41
-		$this->stringstream = $contextOptions[self::PROTOCOL]['string'];
42
-		$this->truncateHtmlSafe = (isset($contextOptions[self::PROTOCOL]['truncatehtmlsafe'])) ? $contextOptions[self::PROTOCOL]['truncatehtmlsafe'] : false;
43
-
44
-		$this->stringlength = strlen($this->stringstream);
45
-		SLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d - HTML-safe-truncate: %s", $this->stringlength, Utils::PrintAsString($this->truncateHtmlSafe)));
46
-
47
-		return true;
48
-	}
49
-
50
-	/**
51
-	 * Reads from stream.
52
-	 *
53
-	 * @param int $len amount of bytes to be read
54
-	 *
55
-	 * @return string
56
-	 */
57
-	public function stream_read($len) {
58
-		$data = substr($this->stringstream, $this->position, $len);
59
-		$this->position += strlen($data);
60
-
61
-		return $data;
62
-	}
63
-
64
-	/**
65
-	 * Writes data to the stream.
66
-	 *
67
-	 * @param string $data
68
-	 *
69
-	 * @return int
70
-	 */
71
-	public function stream_write($data) {
72
-		$l = strlen($data);
73
-		$this->stringstream = substr($this->stringstream, 0, $this->position) . $data . substr($this->stringstream, $this->position += $l);
74
-		$this->stringlength = strlen($this->stringstream);
75
-
76
-		return $l;
77
-	}
78
-
79
-	/**
80
-	 * Stream "seek" functionality.
81
-	 *
82
-	 * @param int $offset
83
-	 * @param int $whence
84
-	 *
85
-	 * @return bool
86
-	 */
87
-	public function stream_seek($offset, $whence = SEEK_SET) {
88
-		if ($whence == SEEK_CUR) {
89
-			$this->position += $offset;
90
-		}
91
-		elseif ($whence == SEEK_END) {
92
-			$this->position = $this->stringlength + $offset;
93
-		}
94
-		else {
95
-			$this->position = $offset;
96
-		}
97
-
98
-		return true;
99
-	}
100
-
101
-	/**
102
-	 * Returns the current position on stream.
103
-	 *
104
-	 * @return int
105
-	 */
106
-	public function stream_tell() {
107
-		return $this->position;
108
-	}
109
-
110
-	/**
111
-	 * Indicates if 'end of file' is reached.
112
-	 *
113
-	 * @return bool
114
-	 */
115
-	public function stream_eof() {
116
-		return $this->position >= $this->stringlength;
117
-	}
118
-
119
-	/**
120
-	 * Truncates the stream to the new size.
121
-	 *
122
-	 * @param int $new_size
123
-	 *
124
-	 * @return bool
125
-	 */
126
-	public function stream_truncate($new_size) {
127
-		// cut the string!
128
-		$this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size, $this->truncateHtmlSafe);
129
-		$this->stringlength = strlen($this->stringstream);
130
-
131
-		if ($this->position > $this->stringlength) {
132
-			SLog::Write(LOGLEVEL_WARN, sprintf("StringStreamWrapper->stream_truncate(): stream position (%d) ahead of new size of %d. Repositioning pointer to end of stream.", $this->position, $this->stringlength));
133
-			$this->position = $this->stringlength;
134
-		}
135
-
136
-		return true;
137
-	}
138
-
139
-	/**
140
-	 * Retrieves information about a stream.
141
-	 *
142
-	 * @return array
143
-	 */
144
-	public function stream_stat() {
145
-		return [
146
-			7 => $this->stringlength,
147
-			'size' => $this->stringlength,
148
-		];
149
-	}
150
-
151
-	/**
152
-	 * Instantiates a StringStreamWrapper.
153
-	 *
154
-	 * @param string $string           The string to be wrapped
155
-	 * @param bool   $truncatehtmlsafe Indicates if a truncation should be done html-safe - default: false
156
-	 *
157
-	 * @return StringStreamWrapper
158
-	 */
159
-	public static function Open($string, $truncatehtmlsafe = false) {
160
-		$context = stream_context_create([self::PROTOCOL => ['string' => &$string, 'truncatehtmlsafe' => $truncatehtmlsafe]]);
161
-
162
-		return fopen(self::PROTOCOL . "://", 'r', false, $context);
163
-	}
12
+    public const PROTOCOL = "stringstream";
13
+
14
+    private $stringstream;
15
+    private $position;
16
+    private $stringlength;
17
+    private $truncateHtmlSafe;
18
+    private $context;
19
+
20
+    /**
21
+     * Opens the stream
22
+     * The string to be streamed is passed over the context.
23
+     *
24
+     * @param string $path        Specifies the URL that was passed to the original function
25
+     * @param string $mode        The mode used to open the file, as detailed for fopen()
26
+     * @param int    $options     Holds additional flags set by the streams API
27
+     * @param string $opened_path if the path is opened successfully, and STREAM_USE_PATH is set in options,
28
+     *                            opened_path should be set to the full path of the file/resource that was actually opened
29
+     *
30
+     * @return bool
31
+     */
32
+    public function stream_open($path, $mode, $options, &$opened_path) {
33
+        $contextOptions = stream_context_get_options($this->context);
34
+        if (!isset($contextOptions[self::PROTOCOL]['string'])) {
35
+            return false;
36
+        }
37
+
38
+        $this->position = 0;
39
+
40
+        // this is our stream!
41
+        $this->stringstream = $contextOptions[self::PROTOCOL]['string'];
42
+        $this->truncateHtmlSafe = (isset($contextOptions[self::PROTOCOL]['truncatehtmlsafe'])) ? $contextOptions[self::PROTOCOL]['truncatehtmlsafe'] : false;
43
+
44
+        $this->stringlength = strlen($this->stringstream);
45
+        SLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d - HTML-safe-truncate: %s", $this->stringlength, Utils::PrintAsString($this->truncateHtmlSafe)));
46
+
47
+        return true;
48
+    }
49
+
50
+    /**
51
+     * Reads from stream.
52
+     *
53
+     * @param int $len amount of bytes to be read
54
+     *
55
+     * @return string
56
+     */
57
+    public function stream_read($len) {
58
+        $data = substr($this->stringstream, $this->position, $len);
59
+        $this->position += strlen($data);
60
+
61
+        return $data;
62
+    }
63
+
64
+    /**
65
+     * Writes data to the stream.
66
+     *
67
+     * @param string $data
68
+     *
69
+     * @return int
70
+     */
71
+    public function stream_write($data) {
72
+        $l = strlen($data);
73
+        $this->stringstream = substr($this->stringstream, 0, $this->position) . $data . substr($this->stringstream, $this->position += $l);
74
+        $this->stringlength = strlen($this->stringstream);
75
+
76
+        return $l;
77
+    }
78
+
79
+    /**
80
+     * Stream "seek" functionality.
81
+     *
82
+     * @param int $offset
83
+     * @param int $whence
84
+     *
85
+     * @return bool
86
+     */
87
+    public function stream_seek($offset, $whence = SEEK_SET) {
88
+        if ($whence == SEEK_CUR) {
89
+            $this->position += $offset;
90
+        }
91
+        elseif ($whence == SEEK_END) {
92
+            $this->position = $this->stringlength + $offset;
93
+        }
94
+        else {
95
+            $this->position = $offset;
96
+        }
97
+
98
+        return true;
99
+    }
100
+
101
+    /**
102
+     * Returns the current position on stream.
103
+     *
104
+     * @return int
105
+     */
106
+    public function stream_tell() {
107
+        return $this->position;
108
+    }
109
+
110
+    /**
111
+     * Indicates if 'end of file' is reached.
112
+     *
113
+     * @return bool
114
+     */
115
+    public function stream_eof() {
116
+        return $this->position >= $this->stringlength;
117
+    }
118
+
119
+    /**
120
+     * Truncates the stream to the new size.
121
+     *
122
+     * @param int $new_size
123
+     *
124
+     * @return bool
125
+     */
126
+    public function stream_truncate($new_size) {
127
+        // cut the string!
128
+        $this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size, $this->truncateHtmlSafe);
129
+        $this->stringlength = strlen($this->stringstream);
130
+
131
+        if ($this->position > $this->stringlength) {
132
+            SLog::Write(LOGLEVEL_WARN, sprintf("StringStreamWrapper->stream_truncate(): stream position (%d) ahead of new size of %d. Repositioning pointer to end of stream.", $this->position, $this->stringlength));
133
+            $this->position = $this->stringlength;
134
+        }
135
+
136
+        return true;
137
+    }
138
+
139
+    /**
140
+     * Retrieves information about a stream.
141
+     *
142
+     * @return array
143
+     */
144
+    public function stream_stat() {
145
+        return [
146
+            7 => $this->stringlength,
147
+            'size' => $this->stringlength,
148
+        ];
149
+    }
150
+
151
+    /**
152
+     * Instantiates a StringStreamWrapper.
153
+     *
154
+     * @param string $string           The string to be wrapped
155
+     * @param bool   $truncatehtmlsafe Indicates if a truncation should be done html-safe - default: false
156
+     *
157
+     * @return StringStreamWrapper
158
+     */
159
+    public static function Open($string, $truncatehtmlsafe = false) {
160
+        $context = stream_context_create([self::PROTOCOL => ['string' => &$string, 'truncatehtmlsafe' => $truncatehtmlsafe]]);
161
+
162
+        return fopen(self::PROTOCOL . "://", 'r', false, $context);
163
+    }
164 164
 }
165 165
 
166 166
 stream_wrapper_register(StringStreamWrapper::PROTOCOL, "StringStreamWrapper");
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
 	 */
71 71
 	public function stream_write($data) {
72 72
 		$l = strlen($data);
73
-		$this->stringstream = substr($this->stringstream, 0, $this->position) . $data . substr($this->stringstream, $this->position += $l);
73
+		$this->stringstream = substr($this->stringstream, 0, $this->position).$data.substr($this->stringstream, $this->position += $l);
74 74
 		$this->stringlength = strlen($this->stringstream);
75 75
 
76 76
 		return $l;
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
 	public static function Open($string, $truncatehtmlsafe = false) {
160 160
 		$context = stream_context_create([self::PROTOCOL => ['string' => &$string, 'truncatehtmlsafe' => $truncatehtmlsafe]]);
161 161
 
162
-		return fopen(self::PROTOCOL . "://", 'r', false, $context);
162
+		return fopen(self::PROTOCOL."://", 'r', false, $context);
163 163
 	}
164 164
 }
165 165
 
Please login to merge, or discard this patch.
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -87,11 +87,9 @@
 block discarded – undo
87 87
 	public function stream_seek($offset, $whence = SEEK_SET) {
88 88
 		if ($whence == SEEK_CUR) {
89 89
 			$this->position += $offset;
90
-		}
91
-		elseif ($whence == SEEK_END) {
90
+		} elseif ($whence == SEEK_END) {
92 91
 			$this->position = $this->stringlength + $offset;
93
-		}
94
-		else {
92
+		} else {
95 93
 			$this->position = $offset;
96 94
 		}
97 95
 
Please login to merge, or discard this patch.
lib/utils/g_RFC822.php 4 patches
Indentation   +952 added lines, -952 removed lines patch added patch discarded remove patch
@@ -75,956 +75,956 @@
 block discarded – undo
75 75
  * @license BSD
76 76
  */
77 77
 class Mail_RFC822 {
78
-	/**
79
-	 * The address being parsed by the RFC822 object.
80
-	 *
81
-	 * @var string
82
-	 */
83
-	public $address = '';
84
-
85
-	/**
86
-	 * The default domain to use for unqualified addresses.
87
-	 *
88
-	 * @var string
89
-	 */
90
-	public $default_domain = 'localhost';
91
-
92
-	/**
93
-	 * Should we return a nested array showing groups, or flatten everything?
94
-	 *
95
-	 * @var bool
96
-	 */
97
-	public $nestGroups = true;
98
-
99
-	/**
100
-	 * Whether or not to validate atoms for non-ascii characters.
101
-	 *
102
-	 * @var bool
103
-	 */
104
-	public $validate = true;
105
-
106
-	/**
107
-	 * The array of raw addresses built up as we parse.
108
-	 *
109
-	 * @var array
110
-	 */
111
-	public $addresses = [];
112
-
113
-	/**
114
-	 * The final array of parsed address information that we build up.
115
-	 *
116
-	 * @var array
117
-	 */
118
-	public $structure = [];
119
-
120
-	/**
121
-	 * The current error message, if any.
122
-	 *
123
-	 * @var string
124
-	 */
125
-	public $error;
126
-
127
-	/**
128
-	 * An internal counter/pointer.
129
-	 *
130
-	 * @var int
131
-	 */
132
-	public $index;
133
-
134
-	/**
135
-	 * The number of groups that have been found in the address list.
136
-	 *
137
-	 * @var int
138
-	 */
139
-	public $num_groups = 0;
140
-
141
-	/**
142
-	 * A variable so that we can tell whether or not we're inside a
143
-	 * Mail_RFC822 object.
144
-	 *
145
-	 * @var bool
146
-	 */
147
-	public $mailRFC822 = true;
148
-
149
-	/**
150
-	 * A limit after which processing stops.
151
-	 *
152
-	 * @var int
153
-	 */
154
-	public $limit;
155
-
156
-	/**
157
-	 * Sets up the object. The address must either be set here or when
158
-	 * calling parseAddressList(). One or the other.
159
-	 *
160
-	 * @param string     $address        the address(es) to validate
161
-	 * @param string     $default_domain Default domain/host etc. If not supplied, will be set to localhost.
162
-	 * @param bool       $nest_groups    whether to return the structure with groups nested for easier viewing
163
-	 * @param bool       $validate       Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
164
-	 * @param null|mixed $limit
165
-	 *
166
-	 * @return object mail_RFC822 A new Mail_RFC822 object
167
-	 */
168
-	public function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) {
169
-		if (isset($address)) {
170
-			$this->address = $address;
171
-		}
172
-		if (isset($default_domain)) {
173
-			$this->default_domain = $default_domain;
174
-		}
175
-		if (isset($nest_groups)) {
176
-			$this->nestGroups = $nest_groups;
177
-		}
178
-		if (isset($validate)) {
179
-			$this->validate = $validate;
180
-		}
181
-		if (isset($limit)) {
182
-			$this->limit = $limit;
183
-		}
184
-	}
185
-
186
-	/**
187
-	 * Starts the whole process. The address must either be set here
188
-	 * or when creating the object. One or the other.
189
-	 *
190
-	 * @param string     $address        the address(es) to validate
191
-	 * @param string     $default_domain default domain/host etc
192
-	 * @param bool       $nest_groups    whether to return the structure with groups nested for easier viewing
193
-	 * @param bool       $validate       Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
194
-	 * @param null|mixed $limit
195
-	 *
196
-	 * @return array a structured array of addresses
197
-	 */
198
-	public function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) {
199
-		if (!isset($this) || !isset($this->mailRFC822)) {
200
-			$obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit);
201
-
202
-			return $obj->parseAddressList();
203
-		}
204
-
205
-		if (isset($address)) {
206
-			$this->address = $address;
207
-		}
208
-		// grommunio-sync addition
209
-		if (strlen(trim($this->address)) == 0) {
210
-			return [];
211
-		}
212
-		if (isset($default_domain)) {
213
-			$this->default_domain = $default_domain;
214
-		}
215
-		if (isset($nest_groups)) {
216
-			$this->nestGroups = $nest_groups;
217
-		}
218
-		if (isset($validate)) {
219
-			$this->validate = $validate;
220
-		}
221
-		if (isset($limit)) {
222
-			$this->limit = $limit;
223
-		}
224
-
225
-		$this->structure = [];
226
-		$this->addresses = [];
227
-		$this->error = null;
228
-		$this->index = null;
229
-
230
-		// Unfold any long lines in $this->address.
231
-		$this->address = preg_replace('/\r?\n/', "\r\n", $this->address);
232
-		$this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address);
233
-
234
-		while ($this->address = $this->_splitAddresses($this->address));
235
-
236
-		if ($this->address === false || isset($this->error)) {
237
-			// require_once 'PEAR.php';
238
-			return $this->raiseError($this->error);
239
-		}
240
-
241
-		// Validate each address individually.  If we encounter an invalid
242
-		// address, stop iterating and return an error immediately.
243
-		foreach ($this->addresses as $address) {
244
-			$valid = $this->_validateAddress($address);
245
-
246
-			if ($valid === false || isset($this->error)) {
247
-				// require_once 'PEAR.php';
248
-				return $this->raiseError($this->error);
249
-			}
250
-
251
-			if (!$this->nestGroups) {
252
-				$this->structure = array_merge($this->structure, $valid);
253
-			}
254
-			else {
255
-				$this->structure[] = $valid;
256
-			}
257
-		}
258
-
259
-		return $this->structure;
260
-	}
261
-
262
-	/**
263
-	 * Splits an address into separate addresses.
264
-	 *
265
-	 * @param string $address the addresses to split
266
-	 *
267
-	 * @return bool success or failure
268
-	 */
269
-	protected function _splitAddresses($address) {
270
-		if (!empty($this->limit) && count($this->addresses) == $this->limit) {
271
-			return '';
272
-		}
273
-
274
-		if ($this->_isGroup($address) && !isset($this->error)) {
275
-			$split_char = ';';
276
-			$is_group = true;
277
-		}
278
-		elseif (!isset($this->error)) {
279
-			$split_char = ',';
280
-			$is_group = false;
281
-		}
282
-		elseif (isset($this->error)) {
283
-			return false;
284
-		}
285
-
286
-		// Split the string based on the above ten or so lines.
287
-		$parts = explode($split_char, $address);
288
-		$string = $this->_splitCheck($parts, $split_char);
289
-
290
-		// If a group...
291
-		if ($is_group) {
292
-			// If $string does not contain a colon outside of
293
-			// brackets/quotes etc then something's fubar.
294
-
295
-			// First check there's a colon at all:
296
-			if (strpos($string, ':') === false) {
297
-				$this->error = 'Invalid address: ' . $string;
298
-
299
-				return false;
300
-			}
301
-
302
-			// Now check it's outside of brackets/quotes:
303
-			if (!$this->_splitCheck(explode(':', $string), ':')) {
304
-				return false;
305
-			}
306
-
307
-			// We must have a group at this point, so increase the counter:
308
-			++$this->num_groups;
309
-		}
310
-
311
-		// $string now contains the first full address/group.
312
-		// Add to the addresses array.
313
-		$this->addresses[] = [
314
-			'address' => trim($string),
315
-			'group' => $is_group,
316
-		];
317
-
318
-		// Remove the now stored address from the initial line, the +1
319
-		// is to account for the explode character.
320
-		$address = trim(substr($address, strlen($string) + 1));
321
-
322
-		// If the next char is a comma and this was a group, then
323
-		// there are more addresses, otherwise, if there are any more
324
-		// chars, then there is another address.
325
-		if ($is_group && substr($address, 0, 1) == ',') {
326
-			return trim(substr($address, 1));
327
-		}
328
-		if (strlen($address) > 0) {
329
-			return $address;
330
-		}
331
-
332
-		return '';
333
-		// If you got here then something's off
334
-		return false;
335
-	}
336
-
337
-	/**
338
-	 * Checks for a group at the start of the string.
339
-	 *
340
-	 * @param string $address the address to check
341
-	 *
342
-	 * @return bool whether or not there is a group at the start of the string
343
-	 */
344
-	protected function _isGroup($address) {
345
-		// First comma not in quotes, angles or escaped:
346
-		$parts = explode(',', $address);
347
-		$string = $this->_splitCheck($parts, ',');
348
-
349
-		// Now we have the first address, we can reliably check for a
350
-		// group by searching for a colon that's not escaped or in
351
-		// quotes or angle brackets.
352
-		if (count($parts = explode(':', $string)) > 1) {
353
-			$string2 = $this->_splitCheck($parts, ':');
354
-
355
-			return $string2 !== $string;
356
-		}
357
-
358
-		return false;
359
-	}
360
-
361
-	/**
362
-	 * A common function that will check an exploded string.
363
-	 *
364
-	 * @param array  $parts the exloded string
365
-	 * @param string $char  the char that was exploded on
366
-	 *
367
-	 * @return mixed false if the string contains unclosed quotes/brackets, or the string on success
368
-	 */
369
-	protected function _splitCheck($parts, $char) {
370
-		$string = $parts[0];
371
-
372
-		for ($i = 0; $i < count($parts); ++$i) {
373
-			if ($this->_hasUnclosedQuotes($string) ||
374
-				$this->_hasUnclosedBrackets($string, '<>') ||
375
-				$this->_hasUnclosedBrackets($string, '[]') ||
376
-				$this->_hasUnclosedBrackets($string, '()') ||
377
-				substr($string, -1) == '\\') {
378
-				if (isset($parts[$i + 1])) {
379
-					$string = $string . $char . $parts[$i + 1];
380
-				}
381
-				else {
382
-					$this->error = 'Invalid address spec. Unclosed bracket or quotes';
383
-
384
-					return false;
385
-				}
386
-			}
387
-			else {
388
-				$this->index = $i;
389
-
390
-				break;
391
-			}
392
-		}
393
-
394
-		return $string;
395
-	}
396
-
397
-	/**
398
-	 * Checks if a string has unclosed quotes or not.
399
-	 *
400
-	 * @param string $string the string to check
401
-	 *
402
-	 * @return bool true if there are unclosed quotes inside the string,
403
-	 *              false otherwise
404
-	 */
405
-	protected function _hasUnclosedQuotes($string) {
406
-		$string = trim($string);
407
-		$iMax = strlen($string);
408
-		$in_quote = false;
409
-		$i = $slashes = 0;
410
-
411
-		for (; $i < $iMax; ++$i) {
412
-			switch ($string[$i]) {
413
-			case '\\':
414
-				++$slashes;
415
-
416
-				break;
417
-
418
-			case '"':
419
-				if ($slashes % 2 == 0) {
420
-					$in_quote = !$in_quote;
421
-				}
422
-				// Fall through to default action below.
423
-
424
-				// no break
425
-			default:
426
-				$slashes = 0;
427
-
428
-				break;
429
-			}
430
-		}
431
-
432
-		return $in_quote;
433
-	}
434
-
435
-	/**
436
-	 * Checks if a string has an unclosed brackets or not. IMPORTANT:
437
-	 * This function handles both angle brackets and square brackets;.
438
-	 *
439
-	 * @param string $string the string to check
440
-	 * @param string $chars  the characters to check for
441
-	 *
442
-	 * @return bool true if there are unclosed brackets inside the string, false otherwise
443
-	 */
444
-	protected function _hasUnclosedBrackets($string, $chars) {
445
-		$num_angle_start = substr_count($string, $chars[0]);
446
-		$num_angle_end = substr_count($string, $chars[1]);
447
-
448
-		$this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]);
449
-		$this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]);
450
-
451
-		if ($num_angle_start < $num_angle_end) {
452
-			$this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')';
453
-
454
-			return false;
455
-		}
456
-
457
-		return $num_angle_start > $num_angle_end;
458
-	}
459
-
460
-	/**
461
-	 * Sub function that is used only by hasUnclosedBrackets().
462
-	 *
463
-	 * @param string $string the string to check
464
-	 * @param int    &$num   The number of occurrences
465
-	 * @param string $char   the character to count
466
-	 *
467
-	 * @return int the number of occurrences of $char in $string, adjusted for backslashes
468
-	 */
469
-	protected function _hasUnclosedBracketsSub($string, &$num, $char) {
470
-		$parts = explode($char, $string);
471
-		for ($i = 0; $i < count($parts); ++$i) {
472
-			if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) {
473
-				--$num;
474
-			}
475
-			if (isset($parts[$i + 1])) {
476
-				$parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1];
477
-			}
478
-		}
479
-
480
-		return $num;
481
-	}
482
-
483
-	/**
484
-	 * Function to begin checking the address.
485
-	 *
486
-	 * @param string $address the address to validate
487
-	 *
488
-	 * @return mixed false on failure, or a structured array of address information on success
489
-	 */
490
-	protected function _validateAddress($address) {
491
-		$is_group = false;
492
-		$addresses = [];
493
-
494
-		if ($address['group']) {
495
-			$is_group = true;
496
-
497
-			// Get the group part of the name
498
-			$parts = explode(':', $address['address']);
499
-			$groupname = $this->_splitCheck($parts, ':');
500
-			$structure = [];
501
-
502
-			// And validate the group part of the name.
503
-			if (!$this->_validatePhrase($groupname)) {
504
-				$this->error = 'Group name did not validate.';
505
-
506
-				return false;
507
-			}
508
-			// Don't include groups if we are not nesting
509
-			// them. This avoids returning invalid addresses.
510
-			if ($this->nestGroups) {
511
-				$structure = new stdClass();
512
-				$structure->groupname = $groupname;
513
-			}
514
-
515
-			$address['address'] = ltrim(substr($address['address'], strlen($groupname . ':')));
516
-		}
517
-
518
-		// If a group then split on comma and put into an array.
519
-		// Otherwise, Just put the whole address in an array.
520
-		if ($is_group) {
521
-			while (strlen($address['address']) > 0) {
522
-				$parts = explode(',', $address['address']);
523
-				$addresses[] = $this->_splitCheck($parts, ',');
524
-				$address['address'] = trim(substr($address['address'], strlen(end($addresses) . ',')));
525
-			}
526
-		}
527
-		else {
528
-			$addresses[] = $address['address'];
529
-		}
530
-
531
-		// Trim the whitespace from all of the address strings.
532
-		array_map('trim', $addresses);
533
-
534
-		// Validate each mailbox.
535
-		// Format could be one of: name <[email protected]>
536
-		//                         [email protected]
537
-		//                         geezer
538
-		// ... or any other format valid by RFC 822.
539
-		for ($i = 0; $i < count($addresses); ++$i) {
540
-			if (!$this->validateMailbox($addresses[$i])) {
541
-				if (empty($this->error)) {
542
-					$this->error = 'Validation failed for: ' . $addresses[$i];
543
-				}
544
-
545
-				return false;
546
-			}
547
-		}
548
-
549
-		// Nested format
550
-		if ($this->nestGroups) {
551
-			if ($is_group) {
552
-				$structure->addresses = $addresses;
553
-			}
554
-			else {
555
-				$structure = $addresses[0];
556
-			}
557
-
558
-			// Flat format
559
-		}
560
-		else {
561
-			if ($is_group) {
562
-				$structure = array_merge($structure, $addresses);
563
-			}
564
-			else {
565
-				$structure = $addresses;
566
-			}
567
-		}
568
-
569
-		return $structure;
570
-	}
571
-
572
-	/**
573
-	 * Function to validate a phrase.
574
-	 *
575
-	 * @param string $phrase the phrase to check
576
-	 *
577
-	 * @return bool success or failure
578
-	 */
579
-	protected function _validatePhrase($phrase) {
580
-		// Splits on one or more Tab or space.
581
-		$parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY);
582
-
583
-		$phrase_parts = [];
584
-		while (count($parts) > 0) {
585
-			$phrase_parts[] = $this->_splitCheck($parts, ' ');
586
-			for ($i = 0; $i < $this->index + 1; ++$i) {
587
-				array_shift($parts);
588
-			}
589
-		}
590
-
591
-		foreach ($phrase_parts as $part) {
592
-			// If quoted string:
593
-			if (substr($part, 0, 1) == '"') {
594
-				if (!$this->_validateQuotedString($part)) {
595
-					return false;
596
-				}
597
-
598
-				continue;
599
-			}
600
-
601
-			// Otherwise it's an atom:
602
-			if (!$this->_validateAtom($part)) {
603
-				return false;
604
-			}
605
-		}
606
-
607
-		return true;
608
-	}
609
-
610
-	/**
611
-	 * Function to validate an atom which from rfc822 is:
612
-	 * atom = 1*<any CHAR except specials, SPACE and CTLs>.
613
-	 *
614
-	 * If validation ($this->validate) has been turned off, then
615
-	 * validateAtom() doesn't actually check anything. This is so that you
616
-	 * can split a list of addresses up before encoding personal names
617
-	 * (umlauts, etc.), for example.
618
-	 *
619
-	 * @param string $atom the string to check
620
-	 *
621
-	 * @return bool success or failure
622
-	 */
623
-	protected function _validateAtom($atom) {
624
-		if (!$this->validate) {
625
-			// Validation has been turned off; assume the atom is okay.
626
-			return true;
627
-		}
628
-
629
-		// Check for any char from ASCII 0 - ASCII 127
630
-		if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) {
631
-			return false;
632
-		}
633
-
634
-		// Check for specials:
635
-		if (preg_match('/[][()<>@,;\\:". ]/', $atom)) {
636
-			return false;
637
-		}
638
-
639
-		// Check for control characters (ASCII 0-31):
640
-		if (preg_match('/[\\x00-\\x1F]+/', $atom)) {
641
-			return false;
642
-		}
643
-
644
-		return true;
645
-	}
646
-
647
-	/**
648
-	 * Function to validate quoted string, which is:
649
-	 * quoted-string = <"> *(qtext/quoted-pair) <">.
650
-	 *
651
-	 * @param string $qstring The string to check
652
-	 *
653
-	 * @return bool success or failure
654
-	 */
655
-	protected function _validateQuotedString($qstring) {
656
-		// Leading and trailing "
657
-		$qstring = substr($qstring, 1, -1);
658
-
659
-		// Perform check, removing quoted characters first.
660
-		return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring));
661
-	}
662
-
663
-	/**
664
-	 * Function to validate a mailbox, which is:
665
-	 * mailbox =   addr-spec         ; simple address
666
-	 *           / phrase route-addr ; name and route-addr.
667
-	 *
668
-	 * @param string &$mailbox The string to check
669
-	 *
670
-	 * @return bool success or failure
671
-	 */
672
-	public function validateMailbox(&$mailbox) {
673
-		// A couple of defaults.
674
-		$phrase = '';
675
-		$comment = '';
676
-		$comments = [];
677
-
678
-		// Catch any RFC822 comments and store them separately.
679
-		$_mailbox = $mailbox;
680
-		while (strlen(trim($_mailbox)) > 0) {
681
-			$parts = explode('(', $_mailbox);
682
-			$before_comment = $this->_splitCheck($parts, '(');
683
-			if ($before_comment != $_mailbox) {
684
-				// First char should be a (.
685
-				$comment = substr(str_replace($before_comment, '', $_mailbox), 1);
686
-				$parts = explode(')', $comment);
687
-				$comment = $this->_splitCheck($parts, ')');
688
-				$comments[] = $comment;
689
-
690
-				// +2 is for the brackets
691
-				$_mailbox = substr($_mailbox, strpos($_mailbox, '(' . $comment) + strlen($comment) + 2);
692
-			}
693
-			else {
694
-				break;
695
-			}
696
-		}
697
-
698
-		foreach ($comments as $comment) {
699
-			$mailbox = str_replace("({$comment})", '', $mailbox);
700
-		}
701
-
702
-		$mailbox = trim($mailbox);
703
-
704
-		// Check for name + route-addr
705
-		if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') {
706
-			$parts = explode('<', $mailbox);
707
-			$name = $this->_splitCheck($parts, '<');
708
-
709
-			$phrase = trim($name);
710
-			$route_addr = trim(substr($mailbox, strlen($name . '<'), -1));
711
-
712
-			// grommunio-sync fix for umlauts and other special chars
713
-			if (substr($phrase, 0, 1) != '"' && substr($phrase, -1) != '"') {
714
-				$phrase = '"' . $phrase . '"';
715
-			}
716
-
717
-			if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) {
718
-				return false;
719
-			}
720
-
721
-			// Only got addr-spec
722
-		}
723
-		else {
724
-			// First snip angle brackets if present.
725
-			if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') {
726
-				$addr_spec = substr($mailbox, 1, -1);
727
-			}
728
-			else {
729
-				$addr_spec = $mailbox;
730
-			}
731
-
732
-			if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
733
-				return false;
734
-			}
735
-		}
736
-
737
-		// Construct the object that will be returned.
738
-		$mbox = new stdClass();
739
-
740
-		// Add the phrase (even if empty) and comments
741
-		$mbox->personal = $phrase;
742
-		$mbox->comment = isset($comments) ? $comments : [];
743
-
744
-		if (isset($route_addr)) {
745
-			$mbox->mailbox = $route_addr['local_part'];
746
-			$mbox->host = $route_addr['domain'];
747
-			$route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : '';
748
-		}
749
-		else {
750
-			$mbox->mailbox = $addr_spec['local_part'];
751
-			$mbox->host = $addr_spec['domain'];
752
-		}
753
-
754
-		$mailbox = $mbox;
755
-
756
-		return true;
757
-	}
758
-
759
-	/**
760
-	 * This function validates a route-addr which is:
761
-	 * route-addr = "<" [route] addr-spec ">".
762
-	 *
763
-	 * Angle brackets have already been removed at the point of
764
-	 * getting to this function.
765
-	 *
766
-	 * @param string $route_addr the string to check
767
-	 *
768
-	 * @return mixed false on failure, or an array containing validated address/route information on success
769
-	 */
770
-	protected function _validateRouteAddr($route_addr) {
771
-		// Check for colon.
772
-		if (strpos($route_addr, ':') !== false) {
773
-			$parts = explode(':', $route_addr);
774
-			$route = $this->_splitCheck($parts, ':');
775
-		}
776
-		else {
777
-			$route = $route_addr;
778
-		}
779
-
780
-		// If $route is same as $route_addr then the colon was in
781
-		// quotes or brackets or, of course, non existent.
782
-		if ($route === $route_addr) {
783
-			unset($route);
784
-			$addr_spec = $route_addr;
785
-			if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
786
-				return false;
787
-			}
788
-		}
789
-		else {
790
-			// Validate route part.
791
-			if (($route = $this->_validateRoute($route)) === false) {
792
-				return false;
793
-			}
794
-
795
-			$addr_spec = substr($route_addr, strlen($route . ':'));
796
-
797
-			// Validate addr-spec part.
798
-			if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
799
-				return false;
800
-			}
801
-		}
802
-
803
-		if (isset($route)) {
804
-			$return['adl'] = $route;
805
-		}
806
-		else {
807
-			$return['adl'] = '';
808
-		}
809
-
810
-		return array_merge($return, $addr_spec);
811
-	}
812
-
813
-	/**
814
-	 * Function to validate a route, which is:
815
-	 * route = 1#("@" domain) ":".
816
-	 *
817
-	 * @param string $route the string to check
818
-	 *
819
-	 * @return mixed false on failure, or the validated $route on success
820
-	 */
821
-	protected function _validateRoute($route) {
822
-		// Split on comma.
823
-		$domains = explode(',', trim($route));
824
-
825
-		foreach ($domains as $domain) {
826
-			$domain = str_replace('@', '', trim($domain));
827
-			if (!$this->_validateDomain($domain)) {
828
-				return false;
829
-			}
830
-		}
831
-
832
-		return $route;
833
-	}
834
-
835
-	/**
836
-	 * Function to validate a domain, though this is not quite what
837
-	 * you expect of a strict internet domain.
838
-	 *
839
-	 * domain = sub-domain *("." sub-domain)
840
-	 *
841
-	 * @param string $domain the string to check
842
-	 *
843
-	 * @return mixed false on failure, or the validated domain on success
844
-	 */
845
-	protected function _validateDomain($domain) {
846
-		// Note the different use of $subdomains and $sub_domains
847
-		$subdomains = explode('.', $domain);
848
-
849
-		while (count($subdomains) > 0) {
850
-			$sub_domains[] = $this->_splitCheck($subdomains, '.');
851
-			for ($i = 0; $i < $this->index + 1; ++$i) {
852
-				array_shift($subdomains);
853
-			}
854
-		}
855
-
856
-		foreach ($sub_domains as $sub_domain) {
857
-			if (!$this->_validateSubdomain(trim($sub_domain))) {
858
-				return false;
859
-			}
860
-		}
861
-
862
-		// Managed to get here, so return input.
863
-		return $domain;
864
-	}
865
-
866
-	/**
867
-	 * Function to validate a subdomain:
868
-	 *   subdomain = domain-ref / domain-literal.
869
-	 *
870
-	 * @param string $subdomain the string to check
871
-	 *
872
-	 * @return bool success or failure
873
-	 */
874
-	protected function _validateSubdomain($subdomain) {
875
-		if (preg_match('|^\[(.*)]$|', $subdomain, $arr)) {
876
-			if (!$this->_validateDliteral($arr[1])) {
877
-				return false;
878
-			}
879
-		}
880
-		else {
881
-			if (!$this->_validateAtom($subdomain)) {
882
-				return false;
883
-			}
884
-		}
885
-
886
-		// Got here, so return successful.
887
-		return true;
888
-	}
889
-
890
-	/**
891
-	 * Function to validate a domain literal:
892
-	 *   domain-literal =  "[" *(dtext / quoted-pair) "]".
893
-	 *
894
-	 * @param string $dliteral the string to check
895
-	 *
896
-	 * @return bool success or failure
897
-	 */
898
-	protected function _validateDliteral($dliteral) {
899
-		return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && ((!isset($matches[1])) || $matches[1] != '\\');
900
-	}
901
-
902
-	/**
903
-	 * Function to validate an addr-spec.
904
-	 *
905
-	 * addr-spec = local-part "@" domain
906
-	 *
907
-	 * @param string $addr_spec the string to check
908
-	 *
909
-	 * @return mixed false on failure, or the validated addr-spec on success
910
-	 */
911
-	protected function _validateAddrSpec($addr_spec) {
912
-		$addr_spec = trim($addr_spec);
913
-
914
-		// Split on @ sign if there is one.
915
-		if (strpos($addr_spec, '@') !== false) {
916
-			$parts = explode('@', $addr_spec);
917
-			$local_part = $this->_splitCheck($parts, '@');
918
-			$domain = substr($addr_spec, strlen($local_part . '@'));
919
-
920
-		// No @ sign so assume the default domain.
921
-		}
922
-		else {
923
-			$local_part = $addr_spec;
924
-			$domain = $this->default_domain;
925
-		}
926
-
927
-		if (($local_part = $this->_validateLocalPart($local_part)) === false) {
928
-			return false;
929
-		}
930
-		if (($domain = $this->_validateDomain($domain)) === false) {
931
-			return false;
932
-		}
933
-
934
-		// Got here so return successful.
935
-		return ['local_part' => $local_part, 'domain' => $domain];
936
-	}
937
-
938
-	/**
939
-	 * Function to validate the local part of an address:
940
-	 *   local-part = word *("." word).
941
-	 *
942
-	 * @param string $local_part
943
-	 *
944
-	 * @return mixed false on failure, or the validated local part on success
945
-	 */
946
-	protected function _validateLocalPart($local_part) {
947
-		$parts = explode('.', $local_part);
948
-		$words = [];
949
-
950
-		// Split the local_part into words.
951
-		while (count($parts) > 0) {
952
-			$words[] = $this->_splitCheck($parts, '.');
953
-			for ($i = 0; $i < $this->index + 1; ++$i) {
954
-				array_shift($parts);
955
-			}
956
-		}
957
-
958
-		// Validate each word.
959
-		foreach ($words as $word) {
960
-			// word cannot be empty (#17317)
961
-			if ($word === '') {
962
-				return false;
963
-			}
964
-			// If this word contains an unquoted space, it is invalid. (6.2.4)
965
-			if (strpos($word, ' ') && $word[0] !== '"') {
966
-				return false;
967
-			}
968
-
969
-			if ($this->_validatePhrase(trim($word)) === false) {
970
-				return false;
971
-			}
972
-		}
973
-
974
-		// Managed to get here, so return the input.
975
-		return $local_part;
976
-	}
977
-
978
-	/**
979
-	 * Returns an approximate count of how many addresses are in the
980
-	 * given string. This is APPROXIMATE as it only splits based on a
981
-	 * comma which has no preceding backslash. Could be useful as
982
-	 * large amounts of addresses will end up producing *large*
983
-	 * structures when used with parseAddressList().
984
-	 *
985
-	 * @param string $data Addresses to count
986
-	 *
987
-	 * @return int Approximate count
988
-	 */
989
-	public function approximateCount($data) {
990
-		return count(preg_split('/(?<!\\\\),/', $data));
991
-	}
992
-
993
-	/**
994
-	 * This is a email validating function separate to the rest of the
995
-	 * class. It simply validates whether an email is of the common
996
-	 * internet form: <user>@<domain>. This can be sufficient for most
997
-	 * people. Optional stricter mode can be utilised which restricts
998
-	 * mailbox characters allowed to alphanumeric, full stop, hyphen
999
-	 * and underscore.
1000
-	 *
1001
-	 * @param string $data   Address to check
1002
-	 * @param bool   $strict Optional stricter mode
1003
-	 *
1004
-	 * @return mixed False if it fails, an indexed array
1005
-	 *               username/domain if it matches
1006
-	 */
1007
-	public function isValidInetAddress($data, $strict = false) {
1008
-		$regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i';
1009
-		if (preg_match($regex, trim($data), $matches)) {
1010
-			return [$matches[1], $matches[2]];
1011
-		}
1012
-
1013
-		return false;
1014
-	}
1015
-
1016
-	/**
1017
-	 * grommunio-sync helper for error logging
1018
-	 * removing PEAR dependency.
1019
-	 *
1020
-	 * @param  string  debug message
1021
-	 * @param mixed $message
1022
-	 *
1023
-	 * @return bool always false as there was an error
1024
-	 */
1025
-	public function raiseError($message) {
1026
-		SLog::Write(LOGLEVEL_ERROR, "z_RFC822 error: " . $message);
1027
-
1028
-		return false;
1029
-	}
78
+    /**
79
+     * The address being parsed by the RFC822 object.
80
+     *
81
+     * @var string
82
+     */
83
+    public $address = '';
84
+
85
+    /**
86
+     * The default domain to use for unqualified addresses.
87
+     *
88
+     * @var string
89
+     */
90
+    public $default_domain = 'localhost';
91
+
92
+    /**
93
+     * Should we return a nested array showing groups, or flatten everything?
94
+     *
95
+     * @var bool
96
+     */
97
+    public $nestGroups = true;
98
+
99
+    /**
100
+     * Whether or not to validate atoms for non-ascii characters.
101
+     *
102
+     * @var bool
103
+     */
104
+    public $validate = true;
105
+
106
+    /**
107
+     * The array of raw addresses built up as we parse.
108
+     *
109
+     * @var array
110
+     */
111
+    public $addresses = [];
112
+
113
+    /**
114
+     * The final array of parsed address information that we build up.
115
+     *
116
+     * @var array
117
+     */
118
+    public $structure = [];
119
+
120
+    /**
121
+     * The current error message, if any.
122
+     *
123
+     * @var string
124
+     */
125
+    public $error;
126
+
127
+    /**
128
+     * An internal counter/pointer.
129
+     *
130
+     * @var int
131
+     */
132
+    public $index;
133
+
134
+    /**
135
+     * The number of groups that have been found in the address list.
136
+     *
137
+     * @var int
138
+     */
139
+    public $num_groups = 0;
140
+
141
+    /**
142
+     * A variable so that we can tell whether or not we're inside a
143
+     * Mail_RFC822 object.
144
+     *
145
+     * @var bool
146
+     */
147
+    public $mailRFC822 = true;
148
+
149
+    /**
150
+     * A limit after which processing stops.
151
+     *
152
+     * @var int
153
+     */
154
+    public $limit;
155
+
156
+    /**
157
+     * Sets up the object. The address must either be set here or when
158
+     * calling parseAddressList(). One or the other.
159
+     *
160
+     * @param string     $address        the address(es) to validate
161
+     * @param string     $default_domain Default domain/host etc. If not supplied, will be set to localhost.
162
+     * @param bool       $nest_groups    whether to return the structure with groups nested for easier viewing
163
+     * @param bool       $validate       Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
164
+     * @param null|mixed $limit
165
+     *
166
+     * @return object mail_RFC822 A new Mail_RFC822 object
167
+     */
168
+    public function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) {
169
+        if (isset($address)) {
170
+            $this->address = $address;
171
+        }
172
+        if (isset($default_domain)) {
173
+            $this->default_domain = $default_domain;
174
+        }
175
+        if (isset($nest_groups)) {
176
+            $this->nestGroups = $nest_groups;
177
+        }
178
+        if (isset($validate)) {
179
+            $this->validate = $validate;
180
+        }
181
+        if (isset($limit)) {
182
+            $this->limit = $limit;
183
+        }
184
+    }
185
+
186
+    /**
187
+     * Starts the whole process. The address must either be set here
188
+     * or when creating the object. One or the other.
189
+     *
190
+     * @param string     $address        the address(es) to validate
191
+     * @param string     $default_domain default domain/host etc
192
+     * @param bool       $nest_groups    whether to return the structure with groups nested for easier viewing
193
+     * @param bool       $validate       Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
194
+     * @param null|mixed $limit
195
+     *
196
+     * @return array a structured array of addresses
197
+     */
198
+    public function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) {
199
+        if (!isset($this) || !isset($this->mailRFC822)) {
200
+            $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit);
201
+
202
+            return $obj->parseAddressList();
203
+        }
204
+
205
+        if (isset($address)) {
206
+            $this->address = $address;
207
+        }
208
+        // grommunio-sync addition
209
+        if (strlen(trim($this->address)) == 0) {
210
+            return [];
211
+        }
212
+        if (isset($default_domain)) {
213
+            $this->default_domain = $default_domain;
214
+        }
215
+        if (isset($nest_groups)) {
216
+            $this->nestGroups = $nest_groups;
217
+        }
218
+        if (isset($validate)) {
219
+            $this->validate = $validate;
220
+        }
221
+        if (isset($limit)) {
222
+            $this->limit = $limit;
223
+        }
224
+
225
+        $this->structure = [];
226
+        $this->addresses = [];
227
+        $this->error = null;
228
+        $this->index = null;
229
+
230
+        // Unfold any long lines in $this->address.
231
+        $this->address = preg_replace('/\r?\n/', "\r\n", $this->address);
232
+        $this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address);
233
+
234
+        while ($this->address = $this->_splitAddresses($this->address));
235
+
236
+        if ($this->address === false || isset($this->error)) {
237
+            // require_once 'PEAR.php';
238
+            return $this->raiseError($this->error);
239
+        }
240
+
241
+        // Validate each address individually.  If we encounter an invalid
242
+        // address, stop iterating and return an error immediately.
243
+        foreach ($this->addresses as $address) {
244
+            $valid = $this->_validateAddress($address);
245
+
246
+            if ($valid === false || isset($this->error)) {
247
+                // require_once 'PEAR.php';
248
+                return $this->raiseError($this->error);
249
+            }
250
+
251
+            if (!$this->nestGroups) {
252
+                $this->structure = array_merge($this->structure, $valid);
253
+            }
254
+            else {
255
+                $this->structure[] = $valid;
256
+            }
257
+        }
258
+
259
+        return $this->structure;
260
+    }
261
+
262
+    /**
263
+     * Splits an address into separate addresses.
264
+     *
265
+     * @param string $address the addresses to split
266
+     *
267
+     * @return bool success or failure
268
+     */
269
+    protected function _splitAddresses($address) {
270
+        if (!empty($this->limit) && count($this->addresses) == $this->limit) {
271
+            return '';
272
+        }
273
+
274
+        if ($this->_isGroup($address) && !isset($this->error)) {
275
+            $split_char = ';';
276
+            $is_group = true;
277
+        }
278
+        elseif (!isset($this->error)) {
279
+            $split_char = ',';
280
+            $is_group = false;
281
+        }
282
+        elseif (isset($this->error)) {
283
+            return false;
284
+        }
285
+
286
+        // Split the string based on the above ten or so lines.
287
+        $parts = explode($split_char, $address);
288
+        $string = $this->_splitCheck($parts, $split_char);
289
+
290
+        // If a group...
291
+        if ($is_group) {
292
+            // If $string does not contain a colon outside of
293
+            // brackets/quotes etc then something's fubar.
294
+
295
+            // First check there's a colon at all:
296
+            if (strpos($string, ':') === false) {
297
+                $this->error = 'Invalid address: ' . $string;
298
+
299
+                return false;
300
+            }
301
+
302
+            // Now check it's outside of brackets/quotes:
303
+            if (!$this->_splitCheck(explode(':', $string), ':')) {
304
+                return false;
305
+            }
306
+
307
+            // We must have a group at this point, so increase the counter:
308
+            ++$this->num_groups;
309
+        }
310
+
311
+        // $string now contains the first full address/group.
312
+        // Add to the addresses array.
313
+        $this->addresses[] = [
314
+            'address' => trim($string),
315
+            'group' => $is_group,
316
+        ];
317
+
318
+        // Remove the now stored address from the initial line, the +1
319
+        // is to account for the explode character.
320
+        $address = trim(substr($address, strlen($string) + 1));
321
+
322
+        // If the next char is a comma and this was a group, then
323
+        // there are more addresses, otherwise, if there are any more
324
+        // chars, then there is another address.
325
+        if ($is_group && substr($address, 0, 1) == ',') {
326
+            return trim(substr($address, 1));
327
+        }
328
+        if (strlen($address) > 0) {
329
+            return $address;
330
+        }
331
+
332
+        return '';
333
+        // If you got here then something's off
334
+        return false;
335
+    }
336
+
337
+    /**
338
+     * Checks for a group at the start of the string.
339
+     *
340
+     * @param string $address the address to check
341
+     *
342
+     * @return bool whether or not there is a group at the start of the string
343
+     */
344
+    protected function _isGroup($address) {
345
+        // First comma not in quotes, angles or escaped:
346
+        $parts = explode(',', $address);
347
+        $string = $this->_splitCheck($parts, ',');
348
+
349
+        // Now we have the first address, we can reliably check for a
350
+        // group by searching for a colon that's not escaped or in
351
+        // quotes or angle brackets.
352
+        if (count($parts = explode(':', $string)) > 1) {
353
+            $string2 = $this->_splitCheck($parts, ':');
354
+
355
+            return $string2 !== $string;
356
+        }
357
+
358
+        return false;
359
+    }
360
+
361
+    /**
362
+     * A common function that will check an exploded string.
363
+     *
364
+     * @param array  $parts the exloded string
365
+     * @param string $char  the char that was exploded on
366
+     *
367
+     * @return mixed false if the string contains unclosed quotes/brackets, or the string on success
368
+     */
369
+    protected function _splitCheck($parts, $char) {
370
+        $string = $parts[0];
371
+
372
+        for ($i = 0; $i < count($parts); ++$i) {
373
+            if ($this->_hasUnclosedQuotes($string) ||
374
+                $this->_hasUnclosedBrackets($string, '<>') ||
375
+                $this->_hasUnclosedBrackets($string, '[]') ||
376
+                $this->_hasUnclosedBrackets($string, '()') ||
377
+                substr($string, -1) == '\\') {
378
+                if (isset($parts[$i + 1])) {
379
+                    $string = $string . $char . $parts[$i + 1];
380
+                }
381
+                else {
382
+                    $this->error = 'Invalid address spec. Unclosed bracket or quotes';
383
+
384
+                    return false;
385
+                }
386
+            }
387
+            else {
388
+                $this->index = $i;
389
+
390
+                break;
391
+            }
392
+        }
393
+
394
+        return $string;
395
+    }
396
+
397
+    /**
398
+     * Checks if a string has unclosed quotes or not.
399
+     *
400
+     * @param string $string the string to check
401
+     *
402
+     * @return bool true if there are unclosed quotes inside the string,
403
+     *              false otherwise
404
+     */
405
+    protected function _hasUnclosedQuotes($string) {
406
+        $string = trim($string);
407
+        $iMax = strlen($string);
408
+        $in_quote = false;
409
+        $i = $slashes = 0;
410
+
411
+        for (; $i < $iMax; ++$i) {
412
+            switch ($string[$i]) {
413
+            case '\\':
414
+                ++$slashes;
415
+
416
+                break;
417
+
418
+            case '"':
419
+                if ($slashes % 2 == 0) {
420
+                    $in_quote = !$in_quote;
421
+                }
422
+                // Fall through to default action below.
423
+
424
+                // no break
425
+            default:
426
+                $slashes = 0;
427
+
428
+                break;
429
+            }
430
+        }
431
+
432
+        return $in_quote;
433
+    }
434
+
435
+    /**
436
+     * Checks if a string has an unclosed brackets or not. IMPORTANT:
437
+     * This function handles both angle brackets and square brackets;.
438
+     *
439
+     * @param string $string the string to check
440
+     * @param string $chars  the characters to check for
441
+     *
442
+     * @return bool true if there are unclosed brackets inside the string, false otherwise
443
+     */
444
+    protected function _hasUnclosedBrackets($string, $chars) {
445
+        $num_angle_start = substr_count($string, $chars[0]);
446
+        $num_angle_end = substr_count($string, $chars[1]);
447
+
448
+        $this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]);
449
+        $this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]);
450
+
451
+        if ($num_angle_start < $num_angle_end) {
452
+            $this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')';
453
+
454
+            return false;
455
+        }
456
+
457
+        return $num_angle_start > $num_angle_end;
458
+    }
459
+
460
+    /**
461
+     * Sub function that is used only by hasUnclosedBrackets().
462
+     *
463
+     * @param string $string the string to check
464
+     * @param int    &$num   The number of occurrences
465
+     * @param string $char   the character to count
466
+     *
467
+     * @return int the number of occurrences of $char in $string, adjusted for backslashes
468
+     */
469
+    protected function _hasUnclosedBracketsSub($string, &$num, $char) {
470
+        $parts = explode($char, $string);
471
+        for ($i = 0; $i < count($parts); ++$i) {
472
+            if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) {
473
+                --$num;
474
+            }
475
+            if (isset($parts[$i + 1])) {
476
+                $parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1];
477
+            }
478
+        }
479
+
480
+        return $num;
481
+    }
482
+
483
+    /**
484
+     * Function to begin checking the address.
485
+     *
486
+     * @param string $address the address to validate
487
+     *
488
+     * @return mixed false on failure, or a structured array of address information on success
489
+     */
490
+    protected function _validateAddress($address) {
491
+        $is_group = false;
492
+        $addresses = [];
493
+
494
+        if ($address['group']) {
495
+            $is_group = true;
496
+
497
+            // Get the group part of the name
498
+            $parts = explode(':', $address['address']);
499
+            $groupname = $this->_splitCheck($parts, ':');
500
+            $structure = [];
501
+
502
+            // And validate the group part of the name.
503
+            if (!$this->_validatePhrase($groupname)) {
504
+                $this->error = 'Group name did not validate.';
505
+
506
+                return false;
507
+            }
508
+            // Don't include groups if we are not nesting
509
+            // them. This avoids returning invalid addresses.
510
+            if ($this->nestGroups) {
511
+                $structure = new stdClass();
512
+                $structure->groupname = $groupname;
513
+            }
514
+
515
+            $address['address'] = ltrim(substr($address['address'], strlen($groupname . ':')));
516
+        }
517
+
518
+        // If a group then split on comma and put into an array.
519
+        // Otherwise, Just put the whole address in an array.
520
+        if ($is_group) {
521
+            while (strlen($address['address']) > 0) {
522
+                $parts = explode(',', $address['address']);
523
+                $addresses[] = $this->_splitCheck($parts, ',');
524
+                $address['address'] = trim(substr($address['address'], strlen(end($addresses) . ',')));
525
+            }
526
+        }
527
+        else {
528
+            $addresses[] = $address['address'];
529
+        }
530
+
531
+        // Trim the whitespace from all of the address strings.
532
+        array_map('trim', $addresses);
533
+
534
+        // Validate each mailbox.
535
+        // Format could be one of: name <[email protected]>
536
+        //                         [email protected]
537
+        //                         geezer
538
+        // ... or any other format valid by RFC 822.
539
+        for ($i = 0; $i < count($addresses); ++$i) {
540
+            if (!$this->validateMailbox($addresses[$i])) {
541
+                if (empty($this->error)) {
542
+                    $this->error = 'Validation failed for: ' . $addresses[$i];
543
+                }
544
+
545
+                return false;
546
+            }
547
+        }
548
+
549
+        // Nested format
550
+        if ($this->nestGroups) {
551
+            if ($is_group) {
552
+                $structure->addresses = $addresses;
553
+            }
554
+            else {
555
+                $structure = $addresses[0];
556
+            }
557
+
558
+            // Flat format
559
+        }
560
+        else {
561
+            if ($is_group) {
562
+                $structure = array_merge($structure, $addresses);
563
+            }
564
+            else {
565
+                $structure = $addresses;
566
+            }
567
+        }
568
+
569
+        return $structure;
570
+    }
571
+
572
+    /**
573
+     * Function to validate a phrase.
574
+     *
575
+     * @param string $phrase the phrase to check
576
+     *
577
+     * @return bool success or failure
578
+     */
579
+    protected function _validatePhrase($phrase) {
580
+        // Splits on one or more Tab or space.
581
+        $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY);
582
+
583
+        $phrase_parts = [];
584
+        while (count($parts) > 0) {
585
+            $phrase_parts[] = $this->_splitCheck($parts, ' ');
586
+            for ($i = 0; $i < $this->index + 1; ++$i) {
587
+                array_shift($parts);
588
+            }
589
+        }
590
+
591
+        foreach ($phrase_parts as $part) {
592
+            // If quoted string:
593
+            if (substr($part, 0, 1) == '"') {
594
+                if (!$this->_validateQuotedString($part)) {
595
+                    return false;
596
+                }
597
+
598
+                continue;
599
+            }
600
+
601
+            // Otherwise it's an atom:
602
+            if (!$this->_validateAtom($part)) {
603
+                return false;
604
+            }
605
+        }
606
+
607
+        return true;
608
+    }
609
+
610
+    /**
611
+     * Function to validate an atom which from rfc822 is:
612
+     * atom = 1*<any CHAR except specials, SPACE and CTLs>.
613
+     *
614
+     * If validation ($this->validate) has been turned off, then
615
+     * validateAtom() doesn't actually check anything. This is so that you
616
+     * can split a list of addresses up before encoding personal names
617
+     * (umlauts, etc.), for example.
618
+     *
619
+     * @param string $atom the string to check
620
+     *
621
+     * @return bool success or failure
622
+     */
623
+    protected function _validateAtom($atom) {
624
+        if (!$this->validate) {
625
+            // Validation has been turned off; assume the atom is okay.
626
+            return true;
627
+        }
628
+
629
+        // Check for any char from ASCII 0 - ASCII 127
630
+        if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) {
631
+            return false;
632
+        }
633
+
634
+        // Check for specials:
635
+        if (preg_match('/[][()<>@,;\\:". ]/', $atom)) {
636
+            return false;
637
+        }
638
+
639
+        // Check for control characters (ASCII 0-31):
640
+        if (preg_match('/[\\x00-\\x1F]+/', $atom)) {
641
+            return false;
642
+        }
643
+
644
+        return true;
645
+    }
646
+
647
+    /**
648
+     * Function to validate quoted string, which is:
649
+     * quoted-string = <"> *(qtext/quoted-pair) <">.
650
+     *
651
+     * @param string $qstring The string to check
652
+     *
653
+     * @return bool success or failure
654
+     */
655
+    protected function _validateQuotedString($qstring) {
656
+        // Leading and trailing "
657
+        $qstring = substr($qstring, 1, -1);
658
+
659
+        // Perform check, removing quoted characters first.
660
+        return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring));
661
+    }
662
+
663
+    /**
664
+     * Function to validate a mailbox, which is:
665
+     * mailbox =   addr-spec         ; simple address
666
+     *           / phrase route-addr ; name and route-addr.
667
+     *
668
+     * @param string &$mailbox The string to check
669
+     *
670
+     * @return bool success or failure
671
+     */
672
+    public function validateMailbox(&$mailbox) {
673
+        // A couple of defaults.
674
+        $phrase = '';
675
+        $comment = '';
676
+        $comments = [];
677
+
678
+        // Catch any RFC822 comments and store them separately.
679
+        $_mailbox = $mailbox;
680
+        while (strlen(trim($_mailbox)) > 0) {
681
+            $parts = explode('(', $_mailbox);
682
+            $before_comment = $this->_splitCheck($parts, '(');
683
+            if ($before_comment != $_mailbox) {
684
+                // First char should be a (.
685
+                $comment = substr(str_replace($before_comment, '', $_mailbox), 1);
686
+                $parts = explode(')', $comment);
687
+                $comment = $this->_splitCheck($parts, ')');
688
+                $comments[] = $comment;
689
+
690
+                // +2 is for the brackets
691
+                $_mailbox = substr($_mailbox, strpos($_mailbox, '(' . $comment) + strlen($comment) + 2);
692
+            }
693
+            else {
694
+                break;
695
+            }
696
+        }
697
+
698
+        foreach ($comments as $comment) {
699
+            $mailbox = str_replace("({$comment})", '', $mailbox);
700
+        }
701
+
702
+        $mailbox = trim($mailbox);
703
+
704
+        // Check for name + route-addr
705
+        if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') {
706
+            $parts = explode('<', $mailbox);
707
+            $name = $this->_splitCheck($parts, '<');
708
+
709
+            $phrase = trim($name);
710
+            $route_addr = trim(substr($mailbox, strlen($name . '<'), -1));
711
+
712
+            // grommunio-sync fix for umlauts and other special chars
713
+            if (substr($phrase, 0, 1) != '"' && substr($phrase, -1) != '"') {
714
+                $phrase = '"' . $phrase . '"';
715
+            }
716
+
717
+            if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) {
718
+                return false;
719
+            }
720
+
721
+            // Only got addr-spec
722
+        }
723
+        else {
724
+            // First snip angle brackets if present.
725
+            if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') {
726
+                $addr_spec = substr($mailbox, 1, -1);
727
+            }
728
+            else {
729
+                $addr_spec = $mailbox;
730
+            }
731
+
732
+            if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
733
+                return false;
734
+            }
735
+        }
736
+
737
+        // Construct the object that will be returned.
738
+        $mbox = new stdClass();
739
+
740
+        // Add the phrase (even if empty) and comments
741
+        $mbox->personal = $phrase;
742
+        $mbox->comment = isset($comments) ? $comments : [];
743
+
744
+        if (isset($route_addr)) {
745
+            $mbox->mailbox = $route_addr['local_part'];
746
+            $mbox->host = $route_addr['domain'];
747
+            $route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : '';
748
+        }
749
+        else {
750
+            $mbox->mailbox = $addr_spec['local_part'];
751
+            $mbox->host = $addr_spec['domain'];
752
+        }
753
+
754
+        $mailbox = $mbox;
755
+
756
+        return true;
757
+    }
758
+
759
+    /**
760
+     * This function validates a route-addr which is:
761
+     * route-addr = "<" [route] addr-spec ">".
762
+     *
763
+     * Angle brackets have already been removed at the point of
764
+     * getting to this function.
765
+     *
766
+     * @param string $route_addr the string to check
767
+     *
768
+     * @return mixed false on failure, or an array containing validated address/route information on success
769
+     */
770
+    protected function _validateRouteAddr($route_addr) {
771
+        // Check for colon.
772
+        if (strpos($route_addr, ':') !== false) {
773
+            $parts = explode(':', $route_addr);
774
+            $route = $this->_splitCheck($parts, ':');
775
+        }
776
+        else {
777
+            $route = $route_addr;
778
+        }
779
+
780
+        // If $route is same as $route_addr then the colon was in
781
+        // quotes or brackets or, of course, non existent.
782
+        if ($route === $route_addr) {
783
+            unset($route);
784
+            $addr_spec = $route_addr;
785
+            if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
786
+                return false;
787
+            }
788
+        }
789
+        else {
790
+            // Validate route part.
791
+            if (($route = $this->_validateRoute($route)) === false) {
792
+                return false;
793
+            }
794
+
795
+            $addr_spec = substr($route_addr, strlen($route . ':'));
796
+
797
+            // Validate addr-spec part.
798
+            if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
799
+                return false;
800
+            }
801
+        }
802
+
803
+        if (isset($route)) {
804
+            $return['adl'] = $route;
805
+        }
806
+        else {
807
+            $return['adl'] = '';
808
+        }
809
+
810
+        return array_merge($return, $addr_spec);
811
+    }
812
+
813
+    /**
814
+     * Function to validate a route, which is:
815
+     * route = 1#("@" domain) ":".
816
+     *
817
+     * @param string $route the string to check
818
+     *
819
+     * @return mixed false on failure, or the validated $route on success
820
+     */
821
+    protected function _validateRoute($route) {
822
+        // Split on comma.
823
+        $domains = explode(',', trim($route));
824
+
825
+        foreach ($domains as $domain) {
826
+            $domain = str_replace('@', '', trim($domain));
827
+            if (!$this->_validateDomain($domain)) {
828
+                return false;
829
+            }
830
+        }
831
+
832
+        return $route;
833
+    }
834
+
835
+    /**
836
+     * Function to validate a domain, though this is not quite what
837
+     * you expect of a strict internet domain.
838
+     *
839
+     * domain = sub-domain *("." sub-domain)
840
+     *
841
+     * @param string $domain the string to check
842
+     *
843
+     * @return mixed false on failure, or the validated domain on success
844
+     */
845
+    protected function _validateDomain($domain) {
846
+        // Note the different use of $subdomains and $sub_domains
847
+        $subdomains = explode('.', $domain);
848
+
849
+        while (count($subdomains) > 0) {
850
+            $sub_domains[] = $this->_splitCheck($subdomains, '.');
851
+            for ($i = 0; $i < $this->index + 1; ++$i) {
852
+                array_shift($subdomains);
853
+            }
854
+        }
855
+
856
+        foreach ($sub_domains as $sub_domain) {
857
+            if (!$this->_validateSubdomain(trim($sub_domain))) {
858
+                return false;
859
+            }
860
+        }
861
+
862
+        // Managed to get here, so return input.
863
+        return $domain;
864
+    }
865
+
866
+    /**
867
+     * Function to validate a subdomain:
868
+     *   subdomain = domain-ref / domain-literal.
869
+     *
870
+     * @param string $subdomain the string to check
871
+     *
872
+     * @return bool success or failure
873
+     */
874
+    protected function _validateSubdomain($subdomain) {
875
+        if (preg_match('|^\[(.*)]$|', $subdomain, $arr)) {
876
+            if (!$this->_validateDliteral($arr[1])) {
877
+                return false;
878
+            }
879
+        }
880
+        else {
881
+            if (!$this->_validateAtom($subdomain)) {
882
+                return false;
883
+            }
884
+        }
885
+
886
+        // Got here, so return successful.
887
+        return true;
888
+    }
889
+
890
+    /**
891
+     * Function to validate a domain literal:
892
+     *   domain-literal =  "[" *(dtext / quoted-pair) "]".
893
+     *
894
+     * @param string $dliteral the string to check
895
+     *
896
+     * @return bool success or failure
897
+     */
898
+    protected function _validateDliteral($dliteral) {
899
+        return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && ((!isset($matches[1])) || $matches[1] != '\\');
900
+    }
901
+
902
+    /**
903
+     * Function to validate an addr-spec.
904
+     *
905
+     * addr-spec = local-part "@" domain
906
+     *
907
+     * @param string $addr_spec the string to check
908
+     *
909
+     * @return mixed false on failure, or the validated addr-spec on success
910
+     */
911
+    protected function _validateAddrSpec($addr_spec) {
912
+        $addr_spec = trim($addr_spec);
913
+
914
+        // Split on @ sign if there is one.
915
+        if (strpos($addr_spec, '@') !== false) {
916
+            $parts = explode('@', $addr_spec);
917
+            $local_part = $this->_splitCheck($parts, '@');
918
+            $domain = substr($addr_spec, strlen($local_part . '@'));
919
+
920
+        // No @ sign so assume the default domain.
921
+        }
922
+        else {
923
+            $local_part = $addr_spec;
924
+            $domain = $this->default_domain;
925
+        }
926
+
927
+        if (($local_part = $this->_validateLocalPart($local_part)) === false) {
928
+            return false;
929
+        }
930
+        if (($domain = $this->_validateDomain($domain)) === false) {
931
+            return false;
932
+        }
933
+
934
+        // Got here so return successful.
935
+        return ['local_part' => $local_part, 'domain' => $domain];
936
+    }
937
+
938
+    /**
939
+     * Function to validate the local part of an address:
940
+     *   local-part = word *("." word).
941
+     *
942
+     * @param string $local_part
943
+     *
944
+     * @return mixed false on failure, or the validated local part on success
945
+     */
946
+    protected function _validateLocalPart($local_part) {
947
+        $parts = explode('.', $local_part);
948
+        $words = [];
949
+
950
+        // Split the local_part into words.
951
+        while (count($parts) > 0) {
952
+            $words[] = $this->_splitCheck($parts, '.');
953
+            for ($i = 0; $i < $this->index + 1; ++$i) {
954
+                array_shift($parts);
955
+            }
956
+        }
957
+
958
+        // Validate each word.
959
+        foreach ($words as $word) {
960
+            // word cannot be empty (#17317)
961
+            if ($word === '') {
962
+                return false;
963
+            }
964
+            // If this word contains an unquoted space, it is invalid. (6.2.4)
965
+            if (strpos($word, ' ') && $word[0] !== '"') {
966
+                return false;
967
+            }
968
+
969
+            if ($this->_validatePhrase(trim($word)) === false) {
970
+                return false;
971
+            }
972
+        }
973
+
974
+        // Managed to get here, so return the input.
975
+        return $local_part;
976
+    }
977
+
978
+    /**
979
+     * Returns an approximate count of how many addresses are in the
980
+     * given string. This is APPROXIMATE as it only splits based on a
981
+     * comma which has no preceding backslash. Could be useful as
982
+     * large amounts of addresses will end up producing *large*
983
+     * structures when used with parseAddressList().
984
+     *
985
+     * @param string $data Addresses to count
986
+     *
987
+     * @return int Approximate count
988
+     */
989
+    public function approximateCount($data) {
990
+        return count(preg_split('/(?<!\\\\),/', $data));
991
+    }
992
+
993
+    /**
994
+     * This is a email validating function separate to the rest of the
995
+     * class. It simply validates whether an email is of the common
996
+     * internet form: <user>@<domain>. This can be sufficient for most
997
+     * people. Optional stricter mode can be utilised which restricts
998
+     * mailbox characters allowed to alphanumeric, full stop, hyphen
999
+     * and underscore.
1000
+     *
1001
+     * @param string $data   Address to check
1002
+     * @param bool   $strict Optional stricter mode
1003
+     *
1004
+     * @return mixed False if it fails, an indexed array
1005
+     *               username/domain if it matches
1006
+     */
1007
+    public function isValidInetAddress($data, $strict = false) {
1008
+        $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i';
1009
+        if (preg_match($regex, trim($data), $matches)) {
1010
+            return [$matches[1], $matches[2]];
1011
+        }
1012
+
1013
+        return false;
1014
+    }
1015
+
1016
+    /**
1017
+     * grommunio-sync helper for error logging
1018
+     * removing PEAR dependency.
1019
+     *
1020
+     * @param  string  debug message
1021
+     * @param mixed $message
1022
+     *
1023
+     * @return bool always false as there was an error
1024
+     */
1025
+    public function raiseError($message) {
1026
+        SLog::Write(LOGLEVEL_ERROR, "z_RFC822 error: " . $message);
1027
+
1028
+        return false;
1029
+    }
1030 1030
 }
Please login to merge, or discard this patch.
Switch Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -410,22 +410,22 @@
 block discarded – undo
410 410
 
411 411
 		for (; $i < $iMax; ++$i) {
412 412
 			switch ($string[$i]) {
413
-			case '\\':
414
-				++$slashes;
413
+			    case '\\':
414
+				    ++$slashes;
415 415
 
416
-				break;
416
+				    break;
417 417
 
418
-			case '"':
419
-				if ($slashes % 2 == 0) {
420
-					$in_quote = !$in_quote;
421
-				}
422
-				// Fall through to default action below.
418
+			    case '"':
419
+				    if ($slashes % 2 == 0) {
420
+					    $in_quote = !$in_quote;
421
+				    }
422
+				    // Fall through to default action below.
423 423
 
424
-				// no break
425
-			default:
426
-				$slashes = 0;
424
+				    // no break
425
+			    default:
426
+				    $slashes = 0;
427 427
 
428
-				break;
428
+				    break;
429 429
 			}
430 430
 		}
431 431
 
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
 
295 295
 			// First check there's a colon at all:
296 296
 			if (strpos($string, ':') === false) {
297
-				$this->error = 'Invalid address: ' . $string;
297
+				$this->error = 'Invalid address: '.$string;
298 298
 
299 299
 				return false;
300 300
 			}
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 				$this->_hasUnclosedBrackets($string, '()') ||
377 377
 				substr($string, -1) == '\\') {
378 378
 				if (isset($parts[$i + 1])) {
379
-					$string = $string . $char . $parts[$i + 1];
379
+					$string = $string.$char.$parts[$i + 1];
380 380
 				}
381 381
 				else {
382 382
 					$this->error = 'Invalid address spec. Unclosed bracket or quotes';
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
 		$this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]);
450 450
 
451 451
 		if ($num_angle_start < $num_angle_end) {
452
-			$this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')';
452
+			$this->error = 'Invalid address spec. Unmatched quote or bracket ('.$chars.')';
453 453
 
454 454
 			return false;
455 455
 		}
@@ -473,7 +473,7 @@  discard block
 block discarded – undo
473 473
 				--$num;
474 474
 			}
475 475
 			if (isset($parts[$i + 1])) {
476
-				$parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1];
476
+				$parts[$i + 1] = $parts[$i].$char.$parts[$i + 1];
477 477
 			}
478 478
 		}
479 479
 
@@ -512,7 +512,7 @@  discard block
 block discarded – undo
512 512
 				$structure->groupname = $groupname;
513 513
 			}
514 514
 
515
-			$address['address'] = ltrim(substr($address['address'], strlen($groupname . ':')));
515
+			$address['address'] = ltrim(substr($address['address'], strlen($groupname.':')));
516 516
 		}
517 517
 
518 518
 		// If a group then split on comma and put into an array.
@@ -521,7 +521,7 @@  discard block
 block discarded – undo
521 521
 			while (strlen($address['address']) > 0) {
522 522
 				$parts = explode(',', $address['address']);
523 523
 				$addresses[] = $this->_splitCheck($parts, ',');
524
-				$address['address'] = trim(substr($address['address'], strlen(end($addresses) . ',')));
524
+				$address['address'] = trim(substr($address['address'], strlen(end($addresses).',')));
525 525
 			}
526 526
 		}
527 527
 		else {
@@ -539,7 +539,7 @@  discard block
 block discarded – undo
539 539
 		for ($i = 0; $i < count($addresses); ++$i) {
540 540
 			if (!$this->validateMailbox($addresses[$i])) {
541 541
 				if (empty($this->error)) {
542
-					$this->error = 'Validation failed for: ' . $addresses[$i];
542
+					$this->error = 'Validation failed for: '.$addresses[$i];
543 543
 				}
544 544
 
545 545
 				return false;
@@ -688,7 +688,7 @@  discard block
 block discarded – undo
688 688
 				$comments[] = $comment;
689 689
 
690 690
 				// +2 is for the brackets
691
-				$_mailbox = substr($_mailbox, strpos($_mailbox, '(' . $comment) + strlen($comment) + 2);
691
+				$_mailbox = substr($_mailbox, strpos($_mailbox, '('.$comment) + strlen($comment) + 2);
692 692
 			}
693 693
 			else {
694 694
 				break;
@@ -707,11 +707,11 @@  discard block
 block discarded – undo
707 707
 			$name = $this->_splitCheck($parts, '<');
708 708
 
709 709
 			$phrase = trim($name);
710
-			$route_addr = trim(substr($mailbox, strlen($name . '<'), -1));
710
+			$route_addr = trim(substr($mailbox, strlen($name.'<'), -1));
711 711
 
712 712
 			// grommunio-sync fix for umlauts and other special chars
713 713
 			if (substr($phrase, 0, 1) != '"' && substr($phrase, -1) != '"') {
714
-				$phrase = '"' . $phrase . '"';
714
+				$phrase = '"'.$phrase.'"';
715 715
 			}
716 716
 
717 717
 			if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) {
@@ -792,7 +792,7 @@  discard block
 block discarded – undo
792 792
 				return false;
793 793
 			}
794 794
 
795
-			$addr_spec = substr($route_addr, strlen($route . ':'));
795
+			$addr_spec = substr($route_addr, strlen($route.':'));
796 796
 
797 797
 			// Validate addr-spec part.
798 798
 			if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
@@ -915,7 +915,7 @@  discard block
 block discarded – undo
915 915
 		if (strpos($addr_spec, '@') !== false) {
916 916
 			$parts = explode('@', $addr_spec);
917 917
 			$local_part = $this->_splitCheck($parts, '@');
918
-			$domain = substr($addr_spec, strlen($local_part . '@'));
918
+			$domain = substr($addr_spec, strlen($local_part.'@'));
919 919
 
920 920
 		// No @ sign so assume the default domain.
921 921
 		}
@@ -1023,7 +1023,7 @@  discard block
 block discarded – undo
1023 1023
 	 * @return bool always false as there was an error
1024 1024
 	 */
1025 1025
 	public function raiseError($message) {
1026
-		SLog::Write(LOGLEVEL_ERROR, "z_RFC822 error: " . $message);
1026
+		SLog::Write(LOGLEVEL_ERROR, "z_RFC822 error: ".$message);
1027 1027
 
1028 1028
 		return false;
1029 1029
 	}
Please login to merge, or discard this patch.
Braces   +18 added lines, -36 removed lines patch added patch discarded remove patch
@@ -250,8 +250,7 @@  discard block
 block discarded – undo
250 250
 
251 251
 			if (!$this->nestGroups) {
252 252
 				$this->structure = array_merge($this->structure, $valid);
253
-			}
254
-			else {
253
+			} else {
255 254
 				$this->structure[] = $valid;
256 255
 			}
257 256
 		}
@@ -274,12 +273,10 @@  discard block
 block discarded – undo
274 273
 		if ($this->_isGroup($address) && !isset($this->error)) {
275 274
 			$split_char = ';';
276 275
 			$is_group = true;
277
-		}
278
-		elseif (!isset($this->error)) {
276
+		} elseif (!isset($this->error)) {
279 277
 			$split_char = ',';
280 278
 			$is_group = false;
281
-		}
282
-		elseif (isset($this->error)) {
279
+		} elseif (isset($this->error)) {
283 280
 			return false;
284 281
 		}
285 282
 
@@ -377,14 +374,12 @@  discard block
 block discarded – undo
377 374
 				substr($string, -1) == '\\') {
378 375
 				if (isset($parts[$i + 1])) {
379 376
 					$string = $string . $char . $parts[$i + 1];
380
-				}
381
-				else {
377
+				} else {
382 378
 					$this->error = 'Invalid address spec. Unclosed bracket or quotes';
383 379
 
384 380
 					return false;
385 381
 				}
386
-			}
387
-			else {
382
+			} else {
388 383
 				$this->index = $i;
389 384
 
390 385
 				break;
@@ -523,8 +518,7 @@  discard block
 block discarded – undo
523 518
 				$addresses[] = $this->_splitCheck($parts, ',');
524 519
 				$address['address'] = trim(substr($address['address'], strlen(end($addresses) . ',')));
525 520
 			}
526
-		}
527
-		else {
521
+		} else {
528 522
 			$addresses[] = $address['address'];
529 523
 		}
530 524
 
@@ -550,18 +544,15 @@  discard block
 block discarded – undo
550 544
 		if ($this->nestGroups) {
551 545
 			if ($is_group) {
552 546
 				$structure->addresses = $addresses;
553
-			}
554
-			else {
547
+			} else {
555 548
 				$structure = $addresses[0];
556 549
 			}
557 550
 
558 551
 			// Flat format
559
-		}
560
-		else {
552
+		} else {
561 553
 			if ($is_group) {
562 554
 				$structure = array_merge($structure, $addresses);
563
-			}
564
-			else {
555
+			} else {
565 556
 				$structure = $addresses;
566 557
 			}
567 558
 		}
@@ -689,8 +680,7 @@  discard block
 block discarded – undo
689 680
 
690 681
 				// +2 is for the brackets
691 682
 				$_mailbox = substr($_mailbox, strpos($_mailbox, '(' . $comment) + strlen($comment) + 2);
692
-			}
693
-			else {
683
+			} else {
694 684
 				break;
695 685
 			}
696 686
 		}
@@ -719,13 +709,11 @@  discard block
 block discarded – undo
719 709
 			}
720 710
 
721 711
 			// Only got addr-spec
722
-		}
723
-		else {
712
+		} else {
724 713
 			// First snip angle brackets if present.
725 714
 			if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') {
726 715
 				$addr_spec = substr($mailbox, 1, -1);
727
-			}
728
-			else {
716
+			} else {
729 717
 				$addr_spec = $mailbox;
730 718
 			}
731 719
 
@@ -745,8 +733,7 @@  discard block
 block discarded – undo
745 733
 			$mbox->mailbox = $route_addr['local_part'];
746 734
 			$mbox->host = $route_addr['domain'];
747 735
 			$route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : '';
748
-		}
749
-		else {
736
+		} else {
750 737
 			$mbox->mailbox = $addr_spec['local_part'];
751 738
 			$mbox->host = $addr_spec['domain'];
752 739
 		}
@@ -772,8 +759,7 @@  discard block
 block discarded – undo
772 759
 		if (strpos($route_addr, ':') !== false) {
773 760
 			$parts = explode(':', $route_addr);
774 761
 			$route = $this->_splitCheck($parts, ':');
775
-		}
776
-		else {
762
+		} else {
777 763
 			$route = $route_addr;
778 764
 		}
779 765
 
@@ -785,8 +771,7 @@  discard block
 block discarded – undo
785 771
 			if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
786 772
 				return false;
787 773
 			}
788
-		}
789
-		else {
774
+		} else {
790 775
 			// Validate route part.
791 776
 			if (($route = $this->_validateRoute($route)) === false) {
792 777
 				return false;
@@ -802,8 +787,7 @@  discard block
 block discarded – undo
802 787
 
803 788
 		if (isset($route)) {
804 789
 			$return['adl'] = $route;
805
-		}
806
-		else {
790
+		} else {
807 791
 			$return['adl'] = '';
808 792
 		}
809 793
 
@@ -876,8 +860,7 @@  discard block
 block discarded – undo
876 860
 			if (!$this->_validateDliteral($arr[1])) {
877 861
 				return false;
878 862
 			}
879
-		}
880
-		else {
863
+		} else {
881 864
 			if (!$this->_validateAtom($subdomain)) {
882 865
 				return false;
883 866
 			}
@@ -918,8 +901,7 @@  discard block
 block discarded – undo
918 901
 			$domain = substr($addr_spec, strlen($local_part . '@'));
919 902
 
920 903
 		// No @ sign so assume the default domain.
921
-		}
922
-		else {
904
+		} else {
923 905
 			$local_part = $addr_spec;
924 906
 			$domain = $this->default_domain;
925 907
 		}
Please login to merge, or discard this patch.
lib/utils/utils.php 3 patches
Indentation   +928 added lines, -928 removed lines patch added patch discarded remove patch
@@ -8,960 +8,960 @@  discard block
 block discarded – undo
8 8
  */
9 9
 
10 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)));
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 = "";
58
-
59
-		if (isset($country) && $street != "") {
60
-			$out = $country;
61
-		}
62
-
63
-		$zcs = "";
64
-		if (isset($zip) && $zip != "") {
65
-			$zcs = $zip;
66
-		}
67
-		if (isset($city) && $city != "") {
68
-			$zcs .= (($zcs) ? " " : "") . $city;
69
-		}
70
-		if (isset($state) && $state != "") {
71
-			$zcs .= (($zcs) ? " " : "") . $state;
72
-		}
73
-		if ($zcs) {
74
-			$out = $zcs . "\r\n" . $out;
75
-		}
76
-
77
-		if (isset($street) && $street != "") {
78
-			$out = $street . (($out) ? "\r\n\r\n" . $out : "");
79
-		}
80
-
81
-		return ($out) ? $out : null;
82
-	}
83
-
84
-	/**
85
-	 * Build the fileas string from the components according to the configuration.
86
-	 *
87
-	 * @param string $lastname
88
-	 * @param string $firstname
89
-	 * @param string $middlename
90
-	 * @param string $company
91
-	 *
92
-	 * @return string fileas
93
-	 */
94
-	public static function BuildFileAs($lastname = "", $firstname = "", $middlename = "", $company = "") {
95
-		if (defined('FILEAS_ORDER')) {
96
-			$fileas = $lastfirst = $firstlast = "";
97
-			$names = trim($firstname . " " . $middlename);
98
-			$lastname = trim($lastname);
99
-			$company = trim($company);
100
-
101
-			// lastfirst is "lastname, firstname middlename"
102
-			// firstlast is "firstname middlename lastname"
103
-			if (strlen($lastname) > 0) {
104
-				$lastfirst = $lastname;
105
-				if (strlen($names) > 0) {
106
-					$lastfirst .= ", {$names}";
107
-					$firstlast = "{$names} {$lastname}";
108
-				}
109
-				else {
110
-					$firstlast = $lastname;
111
-				}
112
-			}
113
-			elseif (strlen($names) > 0) {
114
-				$lastfirst = $firstlast = $names;
115
-			}
116
-
117
-			// if fileas with a company is selected
118
-			// but company is empty then it will
119
-			// fallback to firstlast or lastfirst
120
-			// (depending on which is selected for company)
121
-			switch (FILEAS_ORDER) {
122
-				case SYNC_FILEAS_COMPANYONLY:
123
-					if (strlen($company) > 0) {
124
-						$fileas = $company;
125
-					}
126
-					elseif (strlen($firstlast) > 0) {
127
-						$fileas = $lastfirst;
128
-					}
129
-					break;
130
-
131
-				case SYNC_FILEAS_COMPANYLAST:
132
-					if (strlen($company) > 0) {
133
-						$fileas = $company;
134
-						if (strlen($lastfirst) > 0) {
135
-							$fileas .= "({$lastfirst})";
136
-						}
137
-					}
138
-					elseif (strlen($lastfirst) > 0) {
139
-						$fileas = $lastfirst;
140
-					}
141
-					break;
142
-
143
-				case SYNC_FILEAS_COMPANYFIRST:
144
-					if (strlen($company) > 0) {
145
-						$fileas = $company;
146
-						if (strlen($firstlast) > 0) {
147
-							$fileas .= " ({$firstlast})";
148
-						}
149
-					}
150
-					elseif (strlen($firstlast) > 0) {
151
-						$fileas = $firstlast;
152
-					}
153
-					break;
154
-
155
-				case SYNC_FILEAS_FIRSTCOMPANY:
156
-					if (strlen($firstlast) > 0) {
157
-						$fileas = $firstlast;
158
-						if (strlen($company) > 0) {
159
-							$fileas .= " ({$company})";
160
-						}
161
-					}
162
-					elseif (strlen($company) > 0) {
163
-						$fileas = $company;
164
-					}
165
-					break;
166
-
167
-				case SYNC_FILEAS_LASTCOMPANY:
168
-					if (strlen($lastfirst) > 0) {
169
-						$fileas = $lastfirst;
170
-						if (strlen($company) > 0) {
171
-							$fileas .= " ({$company})";
172
-						}
173
-					}
174
-					elseif (strlen($company) > 0) {
175
-						$fileas = $company;
176
-					}
177
-					break;
178
-
179
-				case SYNC_FILEAS_LASTFIRST:
180
-					if (strlen($lastfirst) > 0) {
181
-						$fileas = $lastfirst;
182
-					}
183
-					break;
184
-
185
-				default:
186
-					$fileas = $firstlast;
187
-					break;
188
-			}
189
-			if (strlen($fileas) == 0) {
190
-				SLog::Write(LOGLEVEL_DEBUG, "Fileas is empty.");
191
-			}
192
-
193
-			return $fileas;
194
-		}
195
-		SLog::Write(LOGLEVEL_DEBUG, "FILEAS_ORDER not defined. Add it to your config.php.");
196
-
197
-		return null;
198
-	}
199
-
200
-	/**
201
-	 * Checks if the PHP-MAPI extension is available and in a requested version.
202
-	 *
203
-	 * @param string $version the version to be checked ("6.30.10-18495", parts or build number)
204
-	 *
205
-	 * @return bool installed version is superior to the checked string
206
-	 */
207
-	public static function CheckMapiExtVersion($version = "") {
208
-		if (!extension_loaded("mapi")) {
209
-			return false;
210
-		}
211
-		// compare build number if requested
212
-		if (preg_match('/^\d+$/', $version) && strlen($version) > 3) {
213
-			$vs = preg_split('/-/', phpversion("mapi"));
214
-
215
-			return $version <= $vs[1];
216
-		}
217
-		if (version_compare(phpversion("mapi"), $version) == -1) {
218
-			return false;
219
-		}
220
-
221
-		return true;
222
-	}
223
-
224
-	/**
225
-	 * Parses and returns an ecoded vCal-Uid from an OL compatible GlobalObjectID.
226
-	 *
227
-	 * @param string $olUid an OL compatible GlobalObjectID
228
-	 *
229
-	 * @return string the vCal-Uid if available in the olUid, else the original olUid as HEX
230
-	 */
231
-	public static function GetICalUidFromOLUid($olUid) {
232
-		// check if "vCal-Uid" is somewhere in outlookid case-insensitive
233
-		$icalUid = stristr($olUid, "vCal-Uid");
234
-		if ($icalUid !== false) {
235
-			// get the length of the ical id - go back 4 position from where "vCal-Uid" was found
236
-			$begin = unpack("V", substr($olUid, strlen($icalUid) * (-1) - 4, 4));
237
-			// remove "vCal-Uid" and packed "1" and use the ical id length
238
-			return substr($icalUid, 12, ($begin[1] - 13));
239
-		}
240
-
241
-		return strtoupper(bin2hex($olUid));
242
-	}
243
-
244
-	/**
245
-	 * Checks the given UID if it is an OL compatible GlobalObjectID
246
-	 * If not, the given UID is encoded inside the GlobalObjectID.
247
-	 *
248
-	 * @param string $icalUid an appointment uid as HEX
249
-	 *
250
-	 * @return string an OL compatible GlobalObjectID
251
-	 */
252
-	public static function GetOLUidFromICalUid($icalUid) {
253
-		if (strlen($icalUid) <= 64) {
254
-			$len = 13 + strlen($icalUid);
255
-			$OLUid = pack("V", $len);
256
-			$OLUid .= "vCal-Uid";
257
-			$OLUid .= pack("V", 1);
258
-			$OLUid .= $icalUid;
259
-
260
-			return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000" . bin2hex($OLUid) . "00");
261
-		}
262
-
263
-		return hex2bin($icalUid);
264
-	}
265
-
266
-	/**
267
-	 * Extracts the basedate of the GlobalObjectID and the RecurStartTime.
268
-	 *
269
-	 * @param string $goid           OL compatible GlobalObjectID
270
-	 * @param long   $recurStartTime
271
-	 *
272
-	 * @return long basedate
273
-	 */
274
-	public static function ExtractBaseDate($goid, $recurStartTime) {
275
-		$hexbase = substr(bin2hex($goid), 32, 8);
276
-		$day = hexdec(substr($hexbase, 6, 2));
277
-		$month = hexdec(substr($hexbase, 4, 2));
278
-		$year = hexdec(substr($hexbase, 0, 4));
279
-
280
-		if ($day && $month && $year) {
281
-			$h = $recurStartTime >> 12;
282
-			$m = ($recurStartTime - $h * 4096) >> 6;
283
-			$s = $recurStartTime - $h * 4096 - $m * 64;
284
-
285
-			return gmmktime($h, $m, $s, $month, $day, $year);
286
-		}
287
-
288
-		return false;
289
-	}
290
-
291
-	/**
292
-	 * Converts SYNC_FILTERTYPE into a timestamp.
293
-	 *
294
-	 * @param int $filtertype Filtertype
295
-	 *
296
-	 * @return long
297
-	 */
298
-	public static function GetCutOffDate($filtertype) {
299
-		$back = Utils::GetFiltertypeInterval($filtertype);
300
-
301
-		if ($back === false) {
302
-			return 0; // unlimited
303
-		}
304
-
305
-		return time() - $back;
306
-	}
307
-
308
-	/**
309
-	 * Returns the interval indicated by the filtertype.
310
-	 *
311
-	 * @param int $filtertype
312
-	 *
313
-	 * @return bool|long returns false on invalid filtertype
314
-	 */
315
-	public static function GetFiltertypeInterval($filtertype) {
316
-		$back = false;
317
-
318
-		switch ($filtertype) {
319
-			case SYNC_FILTERTYPE_1DAY:
320
-				$back = 60 * 60 * 24;
321
-				break;
322
-
323
-			case SYNC_FILTERTYPE_3DAYS:
324
-				$back = 60 * 60 * 24 * 3;
325
-				break;
326
-
327
-			case SYNC_FILTERTYPE_1WEEK:
328
-				$back = 60 * 60 * 24 * 7;
329
-				break;
330
-
331
-			case SYNC_FILTERTYPE_2WEEKS:
332
-				$back = 60 * 60 * 24 * 14;
333
-				break;
334
-
335
-			case SYNC_FILTERTYPE_1MONTH:
336
-				$back = 60 * 60 * 24 * 31;
337
-				break;
338
-
339
-			case SYNC_FILTERTYPE_3MONTHS:
340
-				$back = 60 * 60 * 24 * 31 * 3;
341
-				break;
342
-
343
-			case SYNC_FILTERTYPE_6MONTHS:
344
-				$back = 60 * 60 * 24 * 31 * 6;
345
-				break;
346
-
347
-			default:
348
-				$back = false;
349
-		}
350
-
351
-		return $back;
352
-	}
353
-
354
-	/**
355
-	 * Converts SYNC_TRUNCATION into bytes.
356
-	 *
357
-	 * @param int       SYNC_TRUNCATION
358
-	 * @param mixed $truncation
359
-	 *
360
-	 * @return long
361
-	 */
362
-	public static function GetTruncSize($truncation) {
363
-		switch ($truncation) {
364
-			case SYNC_TRUNCATION_HEADERS:
365
-				return 0;
366
-
367
-			case SYNC_TRUNCATION_512B:
368
-				return 512;
369
-
370
-			case SYNC_TRUNCATION_1K:
371
-				return 1024;
372
-
373
-			case SYNC_TRUNCATION_2K:
374
-				return 2 * 1024;
375
-
376
-			case SYNC_TRUNCATION_5K:
377
-				return 5 * 1024;
378
-
379
-			case SYNC_TRUNCATION_10K:
380
-				return 10 * 1024;
381
-
382
-			case SYNC_TRUNCATION_20K:
383
-				return 20 * 1024;
384
-
385
-			case SYNC_TRUNCATION_50K:
386
-				return 50 * 1024;
387
-
388
-			case SYNC_TRUNCATION_100K:
389
-				return 100 * 1024;
390
-
391
-			case SYNC_TRUNCATION_ALL:
392
-				return 1024 * 1024; // We'll limit to 1MB anyway
393
-
394
-			default:
395
-				return 1024; // Default to 1Kb
396
-		}
397
-	}
398
-
399
-	/**
400
-	 * Truncate an UTF-8 encoded string correctly.
401
-	 *
402
-	 * If it's not possible to truncate properly, an empty string is returned
403
-	 *
404
-	 * @param string $string   the string
405
-	 * @param string $length   position where string should be cut
406
-	 * @param bool   $htmlsafe doesn't cut html tags in half, doesn't ensure correct html - default: false
407
-	 *
408
-	 * @return string truncated string
409
-	 */
410
-	public static function Utf8_truncate($string, $length, $htmlsafe = false) {
411
-		// make sure length is always an integer
412
-		$length = (int) $length;
413
-
414
-		// if the input string is shorter then the trunction, make sure it's valid UTF-8!
415
-		if (strlen($string) <= $length) {
416
-			$length = strlen($string) - 1;
417
-		}
418
-
419
-		// The intent is not to cut HTML tags in half which causes displaying issues (see ZP-1240).
420
-		// The used method just tries to cut outside of tags, without checking tag validity and closing tags.
421
-		if ($htmlsafe) {
422
-			$offset = 0 - strlen($string) + $length;
423
-			$validPos = strrpos($string, "<", $offset);
424
-			if ($validPos > strrpos($string, ">", $offset)) {
425
-				$length = $validPos;
426
-			}
427
-		}
428
-
429
-		while ($length >= 0) {
430
-			if ((ord($string[$length]) < 0x80) || (ord($string[$length]) >= 0xC0)) {
431
-				return substr($string, 0, $length);
432
-			}
433
-			--$length;
434
-		}
435
-
436
-		return "";
437
-	}
438
-
439
-	/**
440
-	 * Indicates if the specified folder type is a system folder.
441
-	 *
442
-	 * @param int $foldertype
443
-	 *
444
-	 * @return bool
445
-	 */
446
-	public static function IsSystemFolder($foldertype) {
447
-		return (
448
-			$foldertype == SYNC_FOLDER_TYPE_INBOX ||
449
-			$foldertype == SYNC_FOLDER_TYPE_DRAFTS ||
450
-			$foldertype == SYNC_FOLDER_TYPE_WASTEBASKET ||
451
-			$foldertype == SYNC_FOLDER_TYPE_SENTMAIL ||
452
-			$foldertype == SYNC_FOLDER_TYPE_OUTBOX ||
453
-			$foldertype == SYNC_FOLDER_TYPE_TASK ||
454
-			$foldertype == SYNC_FOLDER_TYPE_APPOINTMENT ||
455
-			$foldertype == SYNC_FOLDER_TYPE_CONTACT ||
456
-			$foldertype == SYNC_FOLDER_TYPE_NOTE ||
457
-			$foldertype == SYNC_FOLDER_TYPE_JOURNAL
458
-			) ? true : false;
459
-	}
460
-
461
-	/**
462
-	 * Checks for valid email addresses
463
-	 * The used regex actually only checks if a valid email address is part of the submitted string
464
-	 * it also returns true for the mailbox format, but this is not checked explicitly.
465
-	 *
466
-	 * @param string $email address to be checked
467
-	 *
468
-	 * @return bool
469
-	 */
470
-	public static function CheckEmail($email) {
471
-		return strpos($email, '@') !== false ? true : false;
472
-	}
473
-
474
-	/**
475
-	 * Checks if a string is base64 encoded.
476
-	 *
477
-	 * @param string $string the string to be checked
478
-	 *
479
-	 * @return bool
480
-	 */
481
-	public static function IsBase64String($string) {
482
-		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);
483
-	}
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)));
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 = "";
58
+
59
+        if (isset($country) && $street != "") {
60
+            $out = $country;
61
+        }
62
+
63
+        $zcs = "";
64
+        if (isset($zip) && $zip != "") {
65
+            $zcs = $zip;
66
+        }
67
+        if (isset($city) && $city != "") {
68
+            $zcs .= (($zcs) ? " " : "") . $city;
69
+        }
70
+        if (isset($state) && $state != "") {
71
+            $zcs .= (($zcs) ? " " : "") . $state;
72
+        }
73
+        if ($zcs) {
74
+            $out = $zcs . "\r\n" . $out;
75
+        }
76
+
77
+        if (isset($street) && $street != "") {
78
+            $out = $street . (($out) ? "\r\n\r\n" . $out : "");
79
+        }
80
+
81
+        return ($out) ? $out : null;
82
+    }
83
+
84
+    /**
85
+     * Build the fileas string from the components according to the configuration.
86
+     *
87
+     * @param string $lastname
88
+     * @param string $firstname
89
+     * @param string $middlename
90
+     * @param string $company
91
+     *
92
+     * @return string fileas
93
+     */
94
+    public static function BuildFileAs($lastname = "", $firstname = "", $middlename = "", $company = "") {
95
+        if (defined('FILEAS_ORDER')) {
96
+            $fileas = $lastfirst = $firstlast = "";
97
+            $names = trim($firstname . " " . $middlename);
98
+            $lastname = trim($lastname);
99
+            $company = trim($company);
100
+
101
+            // lastfirst is "lastname, firstname middlename"
102
+            // firstlast is "firstname middlename lastname"
103
+            if (strlen($lastname) > 0) {
104
+                $lastfirst = $lastname;
105
+                if (strlen($names) > 0) {
106
+                    $lastfirst .= ", {$names}";
107
+                    $firstlast = "{$names} {$lastname}";
108
+                }
109
+                else {
110
+                    $firstlast = $lastname;
111
+                }
112
+            }
113
+            elseif (strlen($names) > 0) {
114
+                $lastfirst = $firstlast = $names;
115
+            }
116
+
117
+            // if fileas with a company is selected
118
+            // but company is empty then it will
119
+            // fallback to firstlast or lastfirst
120
+            // (depending on which is selected for company)
121
+            switch (FILEAS_ORDER) {
122
+                case SYNC_FILEAS_COMPANYONLY:
123
+                    if (strlen($company) > 0) {
124
+                        $fileas = $company;
125
+                    }
126
+                    elseif (strlen($firstlast) > 0) {
127
+                        $fileas = $lastfirst;
128
+                    }
129
+                    break;
130
+
131
+                case SYNC_FILEAS_COMPANYLAST:
132
+                    if (strlen($company) > 0) {
133
+                        $fileas = $company;
134
+                        if (strlen($lastfirst) > 0) {
135
+                            $fileas .= "({$lastfirst})";
136
+                        }
137
+                    }
138
+                    elseif (strlen($lastfirst) > 0) {
139
+                        $fileas = $lastfirst;
140
+                    }
141
+                    break;
142
+
143
+                case SYNC_FILEAS_COMPANYFIRST:
144
+                    if (strlen($company) > 0) {
145
+                        $fileas = $company;
146
+                        if (strlen($firstlast) > 0) {
147
+                            $fileas .= " ({$firstlast})";
148
+                        }
149
+                    }
150
+                    elseif (strlen($firstlast) > 0) {
151
+                        $fileas = $firstlast;
152
+                    }
153
+                    break;
154
+
155
+                case SYNC_FILEAS_FIRSTCOMPANY:
156
+                    if (strlen($firstlast) > 0) {
157
+                        $fileas = $firstlast;
158
+                        if (strlen($company) > 0) {
159
+                            $fileas .= " ({$company})";
160
+                        }
161
+                    }
162
+                    elseif (strlen($company) > 0) {
163
+                        $fileas = $company;
164
+                    }
165
+                    break;
166
+
167
+                case SYNC_FILEAS_LASTCOMPANY:
168
+                    if (strlen($lastfirst) > 0) {
169
+                        $fileas = $lastfirst;
170
+                        if (strlen($company) > 0) {
171
+                            $fileas .= " ({$company})";
172
+                        }
173
+                    }
174
+                    elseif (strlen($company) > 0) {
175
+                        $fileas = $company;
176
+                    }
177
+                    break;
178
+
179
+                case SYNC_FILEAS_LASTFIRST:
180
+                    if (strlen($lastfirst) > 0) {
181
+                        $fileas = $lastfirst;
182
+                    }
183
+                    break;
184
+
185
+                default:
186
+                    $fileas = $firstlast;
187
+                    break;
188
+            }
189
+            if (strlen($fileas) == 0) {
190
+                SLog::Write(LOGLEVEL_DEBUG, "Fileas is empty.");
191
+            }
192
+
193
+            return $fileas;
194
+        }
195
+        SLog::Write(LOGLEVEL_DEBUG, "FILEAS_ORDER not defined. Add it to your config.php.");
196
+
197
+        return null;
198
+    }
199
+
200
+    /**
201
+     * Checks if the PHP-MAPI extension is available and in a requested version.
202
+     *
203
+     * @param string $version the version to be checked ("6.30.10-18495", parts or build number)
204
+     *
205
+     * @return bool installed version is superior to the checked string
206
+     */
207
+    public static function CheckMapiExtVersion($version = "") {
208
+        if (!extension_loaded("mapi")) {
209
+            return false;
210
+        }
211
+        // compare build number if requested
212
+        if (preg_match('/^\d+$/', $version) && strlen($version) > 3) {
213
+            $vs = preg_split('/-/', phpversion("mapi"));
214
+
215
+            return $version <= $vs[1];
216
+        }
217
+        if (version_compare(phpversion("mapi"), $version) == -1) {
218
+            return false;
219
+        }
220
+
221
+        return true;
222
+    }
223
+
224
+    /**
225
+     * Parses and returns an ecoded vCal-Uid from an OL compatible GlobalObjectID.
226
+     *
227
+     * @param string $olUid an OL compatible GlobalObjectID
228
+     *
229
+     * @return string the vCal-Uid if available in the olUid, else the original olUid as HEX
230
+     */
231
+    public static function GetICalUidFromOLUid($olUid) {
232
+        // check if "vCal-Uid" is somewhere in outlookid case-insensitive
233
+        $icalUid = stristr($olUid, "vCal-Uid");
234
+        if ($icalUid !== false) {
235
+            // get the length of the ical id - go back 4 position from where "vCal-Uid" was found
236
+            $begin = unpack("V", substr($olUid, strlen($icalUid) * (-1) - 4, 4));
237
+            // remove "vCal-Uid" and packed "1" and use the ical id length
238
+            return substr($icalUid, 12, ($begin[1] - 13));
239
+        }
240
+
241
+        return strtoupper(bin2hex($olUid));
242
+    }
243
+
244
+    /**
245
+     * Checks the given UID if it is an OL compatible GlobalObjectID
246
+     * If not, the given UID is encoded inside the GlobalObjectID.
247
+     *
248
+     * @param string $icalUid an appointment uid as HEX
249
+     *
250
+     * @return string an OL compatible GlobalObjectID
251
+     */
252
+    public static function GetOLUidFromICalUid($icalUid) {
253
+        if (strlen($icalUid) <= 64) {
254
+            $len = 13 + strlen($icalUid);
255
+            $OLUid = pack("V", $len);
256
+            $OLUid .= "vCal-Uid";
257
+            $OLUid .= pack("V", 1);
258
+            $OLUid .= $icalUid;
259
+
260
+            return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000" . bin2hex($OLUid) . "00");
261
+        }
262
+
263
+        return hex2bin($icalUid);
264
+    }
265
+
266
+    /**
267
+     * Extracts the basedate of the GlobalObjectID and the RecurStartTime.
268
+     *
269
+     * @param string $goid           OL compatible GlobalObjectID
270
+     * @param long   $recurStartTime
271
+     *
272
+     * @return long basedate
273
+     */
274
+    public static function ExtractBaseDate($goid, $recurStartTime) {
275
+        $hexbase = substr(bin2hex($goid), 32, 8);
276
+        $day = hexdec(substr($hexbase, 6, 2));
277
+        $month = hexdec(substr($hexbase, 4, 2));
278
+        $year = hexdec(substr($hexbase, 0, 4));
279
+
280
+        if ($day && $month && $year) {
281
+            $h = $recurStartTime >> 12;
282
+            $m = ($recurStartTime - $h * 4096) >> 6;
283
+            $s = $recurStartTime - $h * 4096 - $m * 64;
284
+
285
+            return gmmktime($h, $m, $s, $month, $day, $year);
286
+        }
287
+
288
+        return false;
289
+    }
290
+
291
+    /**
292
+     * Converts SYNC_FILTERTYPE into a timestamp.
293
+     *
294
+     * @param int $filtertype Filtertype
295
+     *
296
+     * @return long
297
+     */
298
+    public static function GetCutOffDate($filtertype) {
299
+        $back = Utils::GetFiltertypeInterval($filtertype);
300
+
301
+        if ($back === false) {
302
+            return 0; // unlimited
303
+        }
304
+
305
+        return time() - $back;
306
+    }
307
+
308
+    /**
309
+     * Returns the interval indicated by the filtertype.
310
+     *
311
+     * @param int $filtertype
312
+     *
313
+     * @return bool|long returns false on invalid filtertype
314
+     */
315
+    public static function GetFiltertypeInterval($filtertype) {
316
+        $back = false;
317
+
318
+        switch ($filtertype) {
319
+            case SYNC_FILTERTYPE_1DAY:
320
+                $back = 60 * 60 * 24;
321
+                break;
322
+
323
+            case SYNC_FILTERTYPE_3DAYS:
324
+                $back = 60 * 60 * 24 * 3;
325
+                break;
326
+
327
+            case SYNC_FILTERTYPE_1WEEK:
328
+                $back = 60 * 60 * 24 * 7;
329
+                break;
330
+
331
+            case SYNC_FILTERTYPE_2WEEKS:
332
+                $back = 60 * 60 * 24 * 14;
333
+                break;
334
+
335
+            case SYNC_FILTERTYPE_1MONTH:
336
+                $back = 60 * 60 * 24 * 31;
337
+                break;
338
+
339
+            case SYNC_FILTERTYPE_3MONTHS:
340
+                $back = 60 * 60 * 24 * 31 * 3;
341
+                break;
342
+
343
+            case SYNC_FILTERTYPE_6MONTHS:
344
+                $back = 60 * 60 * 24 * 31 * 6;
345
+                break;
346
+
347
+            default:
348
+                $back = false;
349
+        }
350
+
351
+        return $back;
352
+    }
353
+
354
+    /**
355
+     * Converts SYNC_TRUNCATION into bytes.
356
+     *
357
+     * @param int       SYNC_TRUNCATION
358
+     * @param mixed $truncation
359
+     *
360
+     * @return long
361
+     */
362
+    public static function GetTruncSize($truncation) {
363
+        switch ($truncation) {
364
+            case SYNC_TRUNCATION_HEADERS:
365
+                return 0;
366
+
367
+            case SYNC_TRUNCATION_512B:
368
+                return 512;
369
+
370
+            case SYNC_TRUNCATION_1K:
371
+                return 1024;
372
+
373
+            case SYNC_TRUNCATION_2K:
374
+                return 2 * 1024;
375
+
376
+            case SYNC_TRUNCATION_5K:
377
+                return 5 * 1024;
378
+
379
+            case SYNC_TRUNCATION_10K:
380
+                return 10 * 1024;
381
+
382
+            case SYNC_TRUNCATION_20K:
383
+                return 20 * 1024;
384
+
385
+            case SYNC_TRUNCATION_50K:
386
+                return 50 * 1024;
387
+
388
+            case SYNC_TRUNCATION_100K:
389
+                return 100 * 1024;
390
+
391
+            case SYNC_TRUNCATION_ALL:
392
+                return 1024 * 1024; // We'll limit to 1MB anyway
393
+
394
+            default:
395
+                return 1024; // Default to 1Kb
396
+        }
397
+    }
398
+
399
+    /**
400
+     * Truncate an UTF-8 encoded string correctly.
401
+     *
402
+     * If it's not possible to truncate properly, an empty string is returned
403
+     *
404
+     * @param string $string   the string
405
+     * @param string $length   position where string should be cut
406
+     * @param bool   $htmlsafe doesn't cut html tags in half, doesn't ensure correct html - default: false
407
+     *
408
+     * @return string truncated string
409
+     */
410
+    public static function Utf8_truncate($string, $length, $htmlsafe = false) {
411
+        // make sure length is always an integer
412
+        $length = (int) $length;
413
+
414
+        // if the input string is shorter then the trunction, make sure it's valid UTF-8!
415
+        if (strlen($string) <= $length) {
416
+            $length = strlen($string) - 1;
417
+        }
418
+
419
+        // The intent is not to cut HTML tags in half which causes displaying issues (see ZP-1240).
420
+        // The used method just tries to cut outside of tags, without checking tag validity and closing tags.
421
+        if ($htmlsafe) {
422
+            $offset = 0 - strlen($string) + $length;
423
+            $validPos = strrpos($string, "<", $offset);
424
+            if ($validPos > strrpos($string, ">", $offset)) {
425
+                $length = $validPos;
426
+            }
427
+        }
428
+
429
+        while ($length >= 0) {
430
+            if ((ord($string[$length]) < 0x80) || (ord($string[$length]) >= 0xC0)) {
431
+                return substr($string, 0, $length);
432
+            }
433
+            --$length;
434
+        }
435
+
436
+        return "";
437
+    }
438
+
439
+    /**
440
+     * Indicates if the specified folder type is a system folder.
441
+     *
442
+     * @param int $foldertype
443
+     *
444
+     * @return bool
445
+     */
446
+    public static function IsSystemFolder($foldertype) {
447
+        return (
448
+            $foldertype == SYNC_FOLDER_TYPE_INBOX ||
449
+            $foldertype == SYNC_FOLDER_TYPE_DRAFTS ||
450
+            $foldertype == SYNC_FOLDER_TYPE_WASTEBASKET ||
451
+            $foldertype == SYNC_FOLDER_TYPE_SENTMAIL ||
452
+            $foldertype == SYNC_FOLDER_TYPE_OUTBOX ||
453
+            $foldertype == SYNC_FOLDER_TYPE_TASK ||
454
+            $foldertype == SYNC_FOLDER_TYPE_APPOINTMENT ||
455
+            $foldertype == SYNC_FOLDER_TYPE_CONTACT ||
456
+            $foldertype == SYNC_FOLDER_TYPE_NOTE ||
457
+            $foldertype == SYNC_FOLDER_TYPE_JOURNAL
458
+            ) ? true : false;
459
+    }
460
+
461
+    /**
462
+     * Checks for valid email addresses
463
+     * The used regex actually only checks if a valid email address is part of the submitted string
464
+     * it also returns true for the mailbox format, but this is not checked explicitly.
465
+     *
466
+     * @param string $email address to be checked
467
+     *
468
+     * @return bool
469
+     */
470
+    public static function CheckEmail($email) {
471
+        return strpos($email, '@') !== false ? true : false;
472
+    }
473
+
474
+    /**
475
+     * Checks if a string is base64 encoded.
476
+     *
477
+     * @param string $string the string to be checked
478
+     *
479
+     * @return bool
480
+     */
481
+    public static function IsBase64String($string) {
482
+        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);
483
+    }
484 484
 
485
-	/**
486
-	 * Returns a command string for a given command code.
487
-	 *
488
-	 * @param int $code
489
-	 *
490
-	 * @return string or false if code is unknown
491
-	 */
492
-	public static function GetCommandFromCode($code) {
493
-		switch ($code) {
494
-			case GSync::COMMAND_SYNC:                 return 'Sync';
485
+    /**
486
+     * Returns a command string for a given command code.
487
+     *
488
+     * @param int $code
489
+     *
490
+     * @return string or false if code is unknown
491
+     */
492
+    public static function GetCommandFromCode($code) {
493
+        switch ($code) {
494
+            case GSync::COMMAND_SYNC:                 return 'Sync';
495 495
 
496
-			case GSync::COMMAND_SENDMAIL:             return 'SendMail';
496
+            case GSync::COMMAND_SENDMAIL:             return 'SendMail';
497 497
 
498
-			case GSync::COMMAND_SMARTFORWARD:         return 'SmartForward';
498
+            case GSync::COMMAND_SMARTFORWARD:         return 'SmartForward';
499 499
 
500
-			case GSync::COMMAND_SMARTREPLY:           return 'SmartReply';
500
+            case GSync::COMMAND_SMARTREPLY:           return 'SmartReply';
501 501
 
502
-			case GSync::COMMAND_GETATTACHMENT:        return 'GetAttachment';
502
+            case GSync::COMMAND_GETATTACHMENT:        return 'GetAttachment';
503 503
 
504
-			case GSync::COMMAND_FOLDERSYNC:           return 'FolderSync';
504
+            case GSync::COMMAND_FOLDERSYNC:           return 'FolderSync';
505 505
 
506
-			case GSync::COMMAND_FOLDERCREATE:         return 'FolderCreate';
506
+            case GSync::COMMAND_FOLDERCREATE:         return 'FolderCreate';
507 507
 
508
-			case GSync::COMMAND_FOLDERDELETE:         return 'FolderDelete';
508
+            case GSync::COMMAND_FOLDERDELETE:         return 'FolderDelete';
509 509
 
510
-			case GSync::COMMAND_FOLDERUPDATE:         return 'FolderUpdate';
510
+            case GSync::COMMAND_FOLDERUPDATE:         return 'FolderUpdate';
511 511
 
512
-			case GSync::COMMAND_MOVEITEMS:            return 'MoveItems';
512
+            case GSync::COMMAND_MOVEITEMS:            return 'MoveItems';
513 513
 
514
-			case GSync::COMMAND_GETITEMESTIMATE:      return 'GetItemEstimate';
514
+            case GSync::COMMAND_GETITEMESTIMATE:      return 'GetItemEstimate';
515 515
 
516
-			case GSync::COMMAND_MEETINGRESPONSE:      return 'MeetingResponse';
516
+            case GSync::COMMAND_MEETINGRESPONSE:      return 'MeetingResponse';
517 517
 
518
-			case GSync::COMMAND_SEARCH:               return 'Search';
518
+            case GSync::COMMAND_SEARCH:               return 'Search';
519 519
 
520
-			case GSync::COMMAND_SETTINGS:             return 'Settings';
520
+            case GSync::COMMAND_SETTINGS:             return 'Settings';
521 521
 
522
-			case GSync::COMMAND_PING:                 return 'Ping';
522
+            case GSync::COMMAND_PING:                 return 'Ping';
523 523
 
524
-			case GSync::COMMAND_ITEMOPERATIONS:       return 'ItemOperations';
524
+            case GSync::COMMAND_ITEMOPERATIONS:       return 'ItemOperations';
525 525
 
526
-			case GSync::COMMAND_PROVISION:            return 'Provision';
526
+            case GSync::COMMAND_PROVISION:            return 'Provision';
527 527
 
528
-			case GSync::COMMAND_RESOLVERECIPIENTS:    return 'ResolveRecipients';
528
+            case GSync::COMMAND_RESOLVERECIPIENTS:    return 'ResolveRecipients';
529 529
 
530
-			case GSync::COMMAND_VALIDATECERT:         return 'ValidateCert';
531
-			// Deprecated commands
532
-			case GSync::COMMAND_GETHIERARCHY:         return 'GetHierarchy';
530
+            case GSync::COMMAND_VALIDATECERT:         return 'ValidateCert';
531
+            // Deprecated commands
532
+            case GSync::COMMAND_GETHIERARCHY:         return 'GetHierarchy';
533 533
 
534
-			case GSync::COMMAND_CREATECOLLECTION:     return 'CreateCollection';
534
+            case GSync::COMMAND_CREATECOLLECTION:     return 'CreateCollection';
535 535
 
536
-			case GSync::COMMAND_DELETECOLLECTION:     return 'DeleteCollection';
536
+            case GSync::COMMAND_DELETECOLLECTION:     return 'DeleteCollection';
537 537
 
538
-			case GSync::COMMAND_MOVECOLLECTION:       return 'MoveCollection';
538
+            case GSync::COMMAND_MOVECOLLECTION:       return 'MoveCollection';
539 539
 
540
-			case GSync::COMMAND_NOTIFY:               return 'Notify';
541
-		}
540
+            case GSync::COMMAND_NOTIFY:               return 'Notify';
541
+        }
542 542
 
543
-		return false;
544
-	}
543
+        return false;
544
+    }
545 545
 
546
-	/**
547
-	 * Returns a command code for a given command.
548
-	 *
549
-	 * @param string $command
550
-	 *
551
-	 * @return int or false if command is unknown
552
-	 */
553
-	public static function GetCodeFromCommand($command) {
554
-		switch ($command) {
555
-			case 'Sync':                 return GSync::COMMAND_SYNC;
546
+    /**
547
+     * Returns a command code for a given command.
548
+     *
549
+     * @param string $command
550
+     *
551
+     * @return int or false if command is unknown
552
+     */
553
+    public static function GetCodeFromCommand($command) {
554
+        switch ($command) {
555
+            case 'Sync':                 return GSync::COMMAND_SYNC;
556 556
 
557
-			case 'SendMail':             return GSync::COMMAND_SENDMAIL;
557
+            case 'SendMail':             return GSync::COMMAND_SENDMAIL;
558 558
 
559
-			case 'SmartForward':         return GSync::COMMAND_SMARTFORWARD;
559
+            case 'SmartForward':         return GSync::COMMAND_SMARTFORWARD;
560 560
 
561
-			case 'SmartReply':           return GSync::COMMAND_SMARTREPLY;
561
+            case 'SmartReply':           return GSync::COMMAND_SMARTREPLY;
562 562
 
563
-			case 'GetAttachment':        return GSync::COMMAND_GETATTACHMENT;
563
+            case 'GetAttachment':        return GSync::COMMAND_GETATTACHMENT;
564 564
 
565
-			case 'FolderSync':           return GSync::COMMAND_FOLDERSYNC;
565
+            case 'FolderSync':           return GSync::COMMAND_FOLDERSYNC;
566 566
 
567
-			case 'FolderCreate':         return GSync::COMMAND_FOLDERCREATE;
567
+            case 'FolderCreate':         return GSync::COMMAND_FOLDERCREATE;
568 568
 
569
-			case 'FolderDelete':         return GSync::COMMAND_FOLDERDELETE;
569
+            case 'FolderDelete':         return GSync::COMMAND_FOLDERDELETE;
570 570
 
571
-			case 'FolderUpdate':         return GSync::COMMAND_FOLDERUPDATE;
571
+            case 'FolderUpdate':         return GSync::COMMAND_FOLDERUPDATE;
572 572
 
573
-			case 'MoveItems':            return GSync::COMMAND_MOVEITEMS;
573
+            case 'MoveItems':            return GSync::COMMAND_MOVEITEMS;
574 574
 
575
-			case 'GetItemEstimate':      return GSync::COMMAND_GETITEMESTIMATE;
575
+            case 'GetItemEstimate':      return GSync::COMMAND_GETITEMESTIMATE;
576 576
 
577
-			case 'MeetingResponse':      return GSync::COMMAND_MEETINGRESPONSE;
577
+            case 'MeetingResponse':      return GSync::COMMAND_MEETINGRESPONSE;
578 578
 
579
-			case 'Search':               return GSync::COMMAND_SEARCH;
579
+            case 'Search':               return GSync::COMMAND_SEARCH;
580 580
 
581
-			case 'Settings':             return GSync::COMMAND_SETTINGS;
581
+            case 'Settings':             return GSync::COMMAND_SETTINGS;
582 582
 
583
-			case 'Ping':                 return GSync::COMMAND_PING;
583
+            case 'Ping':                 return GSync::COMMAND_PING;
584 584
 
585
-			case 'ItemOperations':       return GSync::COMMAND_ITEMOPERATIONS;
585
+            case 'ItemOperations':       return GSync::COMMAND_ITEMOPERATIONS;
586 586
 
587
-			case 'Provision':            return GSync::COMMAND_PROVISION;
587
+            case 'Provision':            return GSync::COMMAND_PROVISION;
588 588
 
589
-			case 'ResolveRecipients':    return GSync::COMMAND_RESOLVERECIPIENTS;
589
+            case 'ResolveRecipients':    return GSync::COMMAND_RESOLVERECIPIENTS;
590 590
 
591
-			case 'ValidateCert':         return GSync::COMMAND_VALIDATECERT;
592
-			// Deprecated commands
593
-			case 'GetHierarchy':         return GSync::COMMAND_GETHIERARCHY;
591
+            case 'ValidateCert':         return GSync::COMMAND_VALIDATECERT;
592
+            // Deprecated commands
593
+            case 'GetHierarchy':         return GSync::COMMAND_GETHIERARCHY;
594 594
 
595
-			case 'CreateCollection':     return GSync::COMMAND_CREATECOLLECTION;
595
+            case 'CreateCollection':     return GSync::COMMAND_CREATECOLLECTION;
596 596
 
597
-			case 'DeleteCollection':     return GSync::COMMAND_DELETECOLLECTION;
597
+            case 'DeleteCollection':     return GSync::COMMAND_DELETECOLLECTION;
598 598
 
599
-			case 'MoveCollection':       return GSync::COMMAND_MOVECOLLECTION;
600
-
601
-			case 'Notify':               return GSync::COMMAND_NOTIFY;
602
-		}
603
-
604
-		return false;
605
-	}
606
-
607
-	/**
608
-	 * Normalize the given timestamp to the start of the day.
609
-	 *
610
-	 * @param long $timestamp
611
-	 *
612
-	 * @return long
613
-	 */
614
-	public static function getDayStartOfTimestamp($timestamp) {
615
-		return $timestamp - ($timestamp % (60 * 60 * 24));
616
-	}
617
-
618
-	/**
619
-	 * Returns a formatted string output from an optional timestamp.
620
-	 * If no timestamp is sent, NOW is used.
621
-	 *
622
-	 * @param long $timestamp
623
-	 *
624
-	 * @return string
625
-	 */
626
-	public static function GetFormattedTime($timestamp = false) {
627
-		if (!$timestamp) {
628
-			return @strftime("%d/%m/%Y %H:%M:%S");
629
-		}
630
-
631
-		return @strftime("%d/%m/%Y %H:%M:%S", $timestamp);
632
-	}
633
-
634
-	/**
635
-	 * Get charset name from a codepage.
636
-	 *
637
-	 * @see http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
638
-	 *
639
-	 * Table taken from common/codepage.cpp
640
-	 *
641
-	 * @param int codepage Codepage
642
-	 * @param mixed $codepage
643
-	 *
644
-	 * @return string iconv-compatible charset name
645
-	 */
646
-	public static function GetCodepageCharset($codepage) {
647
-		$codepages = [
648
-			20106 => "DIN_66003",
649
-			20108 => "NS_4551-1",
650
-			20107 => "SEN_850200_B",
651
-			950 => "big5",
652
-			50221 => "csISO2022JP",
653
-			51932 => "euc-jp",
654
-			51936 => "euc-cn",
655
-			51949 => "euc-kr",
656
-			949 => "euc-kr",
657
-			936 => "gb18030",
658
-			52936 => "csgb2312",
659
-			852 => "ibm852",
660
-			866 => "ibm866",
661
-			50220 => "iso-2022-jp",
662
-			50222 => "iso-2022-jp",
663
-			50225 => "iso-2022-kr",
664
-			1252 => "windows-1252",
665
-			28591 => "iso-8859-1",
666
-			28592 => "iso-8859-2",
667
-			28593 => "iso-8859-3",
668
-			28594 => "iso-8859-4",
669
-			28595 => "iso-8859-5",
670
-			28596 => "iso-8859-6",
671
-			28597 => "iso-8859-7",
672
-			28598 => "iso-8859-8",
673
-			28599 => "iso-8859-9",
674
-			28603 => "iso-8859-13",
675
-			28605 => "iso-8859-15",
676
-			20866 => "koi8-r",
677
-			21866 => "koi8-u",
678
-			932 => "shift-jis",
679
-			1200 => "unicode",
680
-			1201 => "unicodebig",
681
-			65000 => "utf-7",
682
-			65001 => "utf-8",
683
-			1250 => "windows-1250",
684
-			1251 => "windows-1251",
685
-			1253 => "windows-1253",
686
-			1254 => "windows-1254",
687
-			1255 => "windows-1255",
688
-			1256 => "windows-1256",
689
-			1257 => "windows-1257",
690
-			1258 => "windows-1258",
691
-			874 => "windows-874",
692
-			20127 => "us-ascii",
693
-		];
694
-
695
-		if (isset($codepages[$codepage])) {
696
-			return $codepages[$codepage];
697
-		}
698
-		// Defaulting to iso-8859-15 since it is more likely for someone to make a mistake in the codepage
699
-		// when using west-european charsets then when using other charsets since utf-8 is binary compatible
700
-		// with the bottom 7 bits of west-european
701
-		return "iso-8859-15";
702
-	}
703
-
704
-	/**
705
-	 * Converts a string encoded with codepage into an UTF-8 string.
706
-	 *
707
-	 * @param int    $codepage
708
-	 * @param string $string
709
-	 *
710
-	 * @return string
711
-	 */
712
-	public static function ConvertCodepageStringToUtf8($codepage, $string) {
713
-		if (function_exists("iconv")) {
714
-			$charset = self::GetCodepageCharset($codepage);
715
-
716
-			return iconv($charset, "utf-8", $string);
717
-		}
718
-
719
-		SLog::Write(LOGLEVEL_WARN, "Utils::ConvertCodepageStringToUtf8() 'iconv' is not available. Charset conversion skipped.");
720
-
721
-		return $string;
722
-	}
723
-
724
-	/**
725
-	 * Converts a string to another charset.
726
-	 *
727
-	 * @param int    $in
728
-	 * @param int    $out
729
-	 * @param string $string
730
-	 *
731
-	 * @return string
732
-	 */
733
-	public static function ConvertCodepage($in, $out, $string) {
734
-		// do nothing if both charsets are the same
735
-		if ($in == $out) {
736
-			return $string;
737
-		}
738
-
739
-		if (function_exists("iconv")) {
740
-			$inCharset = self::GetCodepageCharset($in);
741
-			$outCharset = self::GetCodepageCharset($out);
742
-
743
-			return iconv($inCharset, $outCharset, $string);
744
-		}
745
-
746
-		SLog::Write(LOGLEVEL_WARN, "Utils::ConvertCodepage() 'iconv' is not available. Charset conversion skipped.");
747
-
748
-		return $string;
749
-	}
750
-
751
-	/**
752
-	 * Returns the best match of preferred body preference types.
753
-	 *
754
-	 * @param array $bpTypes
755
-	 *
756
-	 * @return int
757
-	 */
758
-	public static function GetBodyPreferenceBestMatch($bpTypes) {
759
-		if ($bpTypes === false) {
760
-			return SYNC_BODYPREFERENCE_PLAIN;
761
-		}
762
-		// The best choice is RTF, then HTML and then MIME in order to save bandwidth
763
-		// because MIME is a complete message including the headers and attachments
764
-		if (in_array(SYNC_BODYPREFERENCE_RTF, $bpTypes)) {
765
-			return SYNC_BODYPREFERENCE_RTF;
766
-		}
767
-		if (in_array(SYNC_BODYPREFERENCE_HTML, $bpTypes)) {
768
-			return SYNC_BODYPREFERENCE_HTML;
769
-		}
770
-		if (in_array(SYNC_BODYPREFERENCE_MIME, $bpTypes)) {
771
-			return SYNC_BODYPREFERENCE_MIME;
772
-		}
773
-
774
-		return SYNC_BODYPREFERENCE_PLAIN;
775
-	}
776
-
777
-	/**
778
-	 * Checks if a file has the same owner and group as the parent directory.
779
-	 * If not, owner and group are fixed (being updated to the owner/group of the directory).
780
-	 * If the given file is a special file (i.g., /dev/null, fifo), nothing is changed.
781
-	 * Function code contributed by Robert Scheck aka rsc.
782
-	 *
783
-	 * @param string $file
784
-	 *
785
-	 * @return bool
786
-	 */
787
-	public static function FixFileOwner($file) {
788
-		if (!function_exists('posix_getuid')) {
789
-			SLog::Write(LOGLEVEL_DEBUG, "Utils::FixeFileOwner(): Posix subsystem not available, skipping.");
790
-
791
-			return false;
792
-		}
793
-		if (posix_getuid() == 0 && is_file($file)) {
794
-			$dir = dirname($file);
795
-			$perm_dir = stat($dir);
796
-			$perm_file = stat($file);
797
-
798
-			if ($perm_file['uid'] == 0 && $perm_dir['uid'] == 0 && $perm_dir['gid'] == 0) {
799
-				unlink($file);
800
-
801
-				throw new FatalException("FixFileOwner: {$dir} must be owned by the nginx/apache/php user instead of root for debian based systems and by root:grosync for RHEL-based systems");
802
-			}
803
-
804
-			if ($perm_dir['uid'] !== $perm_file['uid'] || $perm_dir['gid'] !== $perm_file['gid']) {
805
-				chown($file, $perm_dir['uid']);
806
-				chgrp($file, $perm_dir['gid']);
807
-				chmod($file, 0664);
808
-			}
809
-		}
810
-
811
-		return true;
812
-	}
813
-
814
-	/**
815
-	 * Returns AS-style LastVerbExecuted value from the server value.
816
-	 *
817
-	 * @param int $verb
818
-	 *
819
-	 * @return int
820
-	 */
821
-	public static function GetLastVerbExecuted($verb) {
822
-		switch ($verb) {
823
-			case NOTEIVERB_REPLYTOSENDER:   return AS_REPLYTOSENDER;
824
-
825
-			case NOTEIVERB_REPLYTOALL:      return AS_REPLYTOALL;
826
-
827
-			case NOTEIVERB_FORWARD:         return AS_FORWARD;
828
-		}
829
-
830
-		return 0;
831
-	}
832
-
833
-	/**
834
-	 * Returns the local part from email address.
835
-	 *
836
-	 * @param string $email
837
-	 *
838
-	 * @return string
839
-	 */
840
-	public static function GetLocalPartFromEmail($email) {
841
-		$pos = strpos($email, '@');
842
-		if ($pos === false) {
843
-			return $email;
844
-		}
845
-
846
-		return substr($email, 0, $pos);
847
-	}
848
-
849
-	/**
850
-	 * Format bytes to a more human readable value.
851
-	 *
852
-	 * @param int $bytes
853
-	 * @param int $precision
854
-	 *
855
-	 * @return string|void
856
-	 */
857
-	public static function FormatBytes($bytes, $precision = 2) {
858
-		if ($bytes <= 0) {
859
-			return '0 B';
860
-		}
861
-
862
-		$units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB'];
863
-		$base = log($bytes, 1024);
864
-		$fBase = floor($base);
865
-		$pow = pow(1024, $base - $fBase);
866
-
867
-		return sprintf("%.{$precision}f %s", $pow, $units[$fBase]);
868
-	}
869
-
870
-	/**
871
-	 * Returns folder origin identifier from its id.
872
-	 *
873
-	 * @param string $folderid
874
-	 *
875
-	 * @return bool|string matches values of DeviceManager::FLD_ORIGIN_*
876
-	 */
877
-	public static function GetFolderOriginFromId($folderid) {
878
-		$origin = substr($folderid, 0, 1);
879
-
880
-		switch ($origin) {
881
-			case DeviceManager::FLD_ORIGIN_CONFIG:
882
-			case DeviceManager::FLD_ORIGIN_GAB:
883
-			case DeviceManager::FLD_ORIGIN_SHARED:
884
-			case DeviceManager::FLD_ORIGIN_USER:
885
-			case DeviceManager::FLD_ORIGIN_IMPERSONATED:
886
-				return $origin;
887
-		}
888
-		SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginFromId(): Unknown folder origin for folder with id '%s'", $folderid));
889
-
890
-		return false;
891
-	}
892
-
893
-	/**
894
-	 * Returns folder origin as string from its id.
895
-	 *
896
-	 * @param string $folderid
897
-	 *
898
-	 * @return string
899
-	 */
900
-	public static function GetFolderOriginStringFromId($folderid) {
901
-		$origin = substr($folderid, 0, 1);
902
-
903
-		switch ($origin) {
904
-			case DeviceManager::FLD_ORIGIN_CONFIG:
905
-				return 'configured';
906
-
907
-			case DeviceManager::FLD_ORIGIN_GAB:
908
-				return 'GAB';
909
-
910
-			case DeviceManager::FLD_ORIGIN_SHARED:
911
-				return 'shared';
912
-
913
-			case DeviceManager::FLD_ORIGIN_USER:
914
-				return 'user';
915
-
916
-			case DeviceManager::FLD_ORIGIN_IMPERSONATED:
917
-				return 'impersonated';
918
-		}
919
-		SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginStringFromId(): Unknown folder origin for folder with id '%s'", $folderid));
920
-
921
-		return 'unknown';
922
-	}
923
-
924
-	/**
925
-	 * Splits the id into folder id and message id parts. A colon in the $id indicates
926
-	 * that the id has folderid:messageid format.
927
-	 *
928
-	 * @param string $id
929
-	 *
930
-	 * @return array
931
-	 */
932
-	public static function SplitMessageId($id) {
933
-		if (strpos($id, ':') !== false) {
934
-			return explode(':', $id);
935
-		}
936
-
937
-		return [null, $id];
938
-	}
939
-
940
-	/**
941
-	 * Converts a string freebusy type into a numeric status.
942
-	 *
943
-	 * @param string $fbType
944
-	 *
945
-	 * @return int
946
-	 */
947
-	public static function GetFbStatusFromType($fbType) {
948
-		switch ($fbType) {
949
-			case 'Free':
950
-				return fbFree;
951
-
952
-			case 'Tentative':
953
-				return fbTentative;
954
-
955
-			case 'Busy':
956
-				return fbBusy;
957
-
958
-			case 'OOF':
959
-				return fbOutOfOffice;
960
-		}
961
-		SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFbStatusFromType(): Unknown free busy type '%s'", $fbType));
962
-
963
-		return fbNoData;
964
-	}
599
+            case 'MoveCollection':       return GSync::COMMAND_MOVECOLLECTION;
600
+
601
+            case 'Notify':               return GSync::COMMAND_NOTIFY;
602
+        }
603
+
604
+        return false;
605
+    }
606
+
607
+    /**
608
+     * Normalize the given timestamp to the start of the day.
609
+     *
610
+     * @param long $timestamp
611
+     *
612
+     * @return long
613
+     */
614
+    public static function getDayStartOfTimestamp($timestamp) {
615
+        return $timestamp - ($timestamp % (60 * 60 * 24));
616
+    }
617
+
618
+    /**
619
+     * Returns a formatted string output from an optional timestamp.
620
+     * If no timestamp is sent, NOW is used.
621
+     *
622
+     * @param long $timestamp
623
+     *
624
+     * @return string
625
+     */
626
+    public static function GetFormattedTime($timestamp = false) {
627
+        if (!$timestamp) {
628
+            return @strftime("%d/%m/%Y %H:%M:%S");
629
+        }
630
+
631
+        return @strftime("%d/%m/%Y %H:%M:%S", $timestamp);
632
+    }
633
+
634
+    /**
635
+     * Get charset name from a codepage.
636
+     *
637
+     * @see http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
638
+     *
639
+     * Table taken from common/codepage.cpp
640
+     *
641
+     * @param int codepage Codepage
642
+     * @param mixed $codepage
643
+     *
644
+     * @return string iconv-compatible charset name
645
+     */
646
+    public static function GetCodepageCharset($codepage) {
647
+        $codepages = [
648
+            20106 => "DIN_66003",
649
+            20108 => "NS_4551-1",
650
+            20107 => "SEN_850200_B",
651
+            950 => "big5",
652
+            50221 => "csISO2022JP",
653
+            51932 => "euc-jp",
654
+            51936 => "euc-cn",
655
+            51949 => "euc-kr",
656
+            949 => "euc-kr",
657
+            936 => "gb18030",
658
+            52936 => "csgb2312",
659
+            852 => "ibm852",
660
+            866 => "ibm866",
661
+            50220 => "iso-2022-jp",
662
+            50222 => "iso-2022-jp",
663
+            50225 => "iso-2022-kr",
664
+            1252 => "windows-1252",
665
+            28591 => "iso-8859-1",
666
+            28592 => "iso-8859-2",
667
+            28593 => "iso-8859-3",
668
+            28594 => "iso-8859-4",
669
+            28595 => "iso-8859-5",
670
+            28596 => "iso-8859-6",
671
+            28597 => "iso-8859-7",
672
+            28598 => "iso-8859-8",
673
+            28599 => "iso-8859-9",
674
+            28603 => "iso-8859-13",
675
+            28605 => "iso-8859-15",
676
+            20866 => "koi8-r",
677
+            21866 => "koi8-u",
678
+            932 => "shift-jis",
679
+            1200 => "unicode",
680
+            1201 => "unicodebig",
681
+            65000 => "utf-7",
682
+            65001 => "utf-8",
683
+            1250 => "windows-1250",
684
+            1251 => "windows-1251",
685
+            1253 => "windows-1253",
686
+            1254 => "windows-1254",
687
+            1255 => "windows-1255",
688
+            1256 => "windows-1256",
689
+            1257 => "windows-1257",
690
+            1258 => "windows-1258",
691
+            874 => "windows-874",
692
+            20127 => "us-ascii",
693
+        ];
694
+
695
+        if (isset($codepages[$codepage])) {
696
+            return $codepages[$codepage];
697
+        }
698
+        // Defaulting to iso-8859-15 since it is more likely for someone to make a mistake in the codepage
699
+        // when using west-european charsets then when using other charsets since utf-8 is binary compatible
700
+        // with the bottom 7 bits of west-european
701
+        return "iso-8859-15";
702
+    }
703
+
704
+    /**
705
+     * Converts a string encoded with codepage into an UTF-8 string.
706
+     *
707
+     * @param int    $codepage
708
+     * @param string $string
709
+     *
710
+     * @return string
711
+     */
712
+    public static function ConvertCodepageStringToUtf8($codepage, $string) {
713
+        if (function_exists("iconv")) {
714
+            $charset = self::GetCodepageCharset($codepage);
715
+
716
+            return iconv($charset, "utf-8", $string);
717
+        }
718
+
719
+        SLog::Write(LOGLEVEL_WARN, "Utils::ConvertCodepageStringToUtf8() 'iconv' is not available. Charset conversion skipped.");
720
+
721
+        return $string;
722
+    }
723
+
724
+    /**
725
+     * Converts a string to another charset.
726
+     *
727
+     * @param int    $in
728
+     * @param int    $out
729
+     * @param string $string
730
+     *
731
+     * @return string
732
+     */
733
+    public static function ConvertCodepage($in, $out, $string) {
734
+        // do nothing if both charsets are the same
735
+        if ($in == $out) {
736
+            return $string;
737
+        }
738
+
739
+        if (function_exists("iconv")) {
740
+            $inCharset = self::GetCodepageCharset($in);
741
+            $outCharset = self::GetCodepageCharset($out);
742
+
743
+            return iconv($inCharset, $outCharset, $string);
744
+        }
745
+
746
+        SLog::Write(LOGLEVEL_WARN, "Utils::ConvertCodepage() 'iconv' is not available. Charset conversion skipped.");
747
+
748
+        return $string;
749
+    }
750
+
751
+    /**
752
+     * Returns the best match of preferred body preference types.
753
+     *
754
+     * @param array $bpTypes
755
+     *
756
+     * @return int
757
+     */
758
+    public static function GetBodyPreferenceBestMatch($bpTypes) {
759
+        if ($bpTypes === false) {
760
+            return SYNC_BODYPREFERENCE_PLAIN;
761
+        }
762
+        // The best choice is RTF, then HTML and then MIME in order to save bandwidth
763
+        // because MIME is a complete message including the headers and attachments
764
+        if (in_array(SYNC_BODYPREFERENCE_RTF, $bpTypes)) {
765
+            return SYNC_BODYPREFERENCE_RTF;
766
+        }
767
+        if (in_array(SYNC_BODYPREFERENCE_HTML, $bpTypes)) {
768
+            return SYNC_BODYPREFERENCE_HTML;
769
+        }
770
+        if (in_array(SYNC_BODYPREFERENCE_MIME, $bpTypes)) {
771
+            return SYNC_BODYPREFERENCE_MIME;
772
+        }
773
+
774
+        return SYNC_BODYPREFERENCE_PLAIN;
775
+    }
776
+
777
+    /**
778
+     * Checks if a file has the same owner and group as the parent directory.
779
+     * If not, owner and group are fixed (being updated to the owner/group of the directory).
780
+     * If the given file is a special file (i.g., /dev/null, fifo), nothing is changed.
781
+     * Function code contributed by Robert Scheck aka rsc.
782
+     *
783
+     * @param string $file
784
+     *
785
+     * @return bool
786
+     */
787
+    public static function FixFileOwner($file) {
788
+        if (!function_exists('posix_getuid')) {
789
+            SLog::Write(LOGLEVEL_DEBUG, "Utils::FixeFileOwner(): Posix subsystem not available, skipping.");
790
+
791
+            return false;
792
+        }
793
+        if (posix_getuid() == 0 && is_file($file)) {
794
+            $dir = dirname($file);
795
+            $perm_dir = stat($dir);
796
+            $perm_file = stat($file);
797
+
798
+            if ($perm_file['uid'] == 0 && $perm_dir['uid'] == 0 && $perm_dir['gid'] == 0) {
799
+                unlink($file);
800
+
801
+                throw new FatalException("FixFileOwner: {$dir} must be owned by the nginx/apache/php user instead of root for debian based systems and by root:grosync for RHEL-based systems");
802
+            }
803
+
804
+            if ($perm_dir['uid'] !== $perm_file['uid'] || $perm_dir['gid'] !== $perm_file['gid']) {
805
+                chown($file, $perm_dir['uid']);
806
+                chgrp($file, $perm_dir['gid']);
807
+                chmod($file, 0664);
808
+            }
809
+        }
810
+
811
+        return true;
812
+    }
813
+
814
+    /**
815
+     * Returns AS-style LastVerbExecuted value from the server value.
816
+     *
817
+     * @param int $verb
818
+     *
819
+     * @return int
820
+     */
821
+    public static function GetLastVerbExecuted($verb) {
822
+        switch ($verb) {
823
+            case NOTEIVERB_REPLYTOSENDER:   return AS_REPLYTOSENDER;
824
+
825
+            case NOTEIVERB_REPLYTOALL:      return AS_REPLYTOALL;
826
+
827
+            case NOTEIVERB_FORWARD:         return AS_FORWARD;
828
+        }
829
+
830
+        return 0;
831
+    }
832
+
833
+    /**
834
+     * Returns the local part from email address.
835
+     *
836
+     * @param string $email
837
+     *
838
+     * @return string
839
+     */
840
+    public static function GetLocalPartFromEmail($email) {
841
+        $pos = strpos($email, '@');
842
+        if ($pos === false) {
843
+            return $email;
844
+        }
845
+
846
+        return substr($email, 0, $pos);
847
+    }
848
+
849
+    /**
850
+     * Format bytes to a more human readable value.
851
+     *
852
+     * @param int $bytes
853
+     * @param int $precision
854
+     *
855
+     * @return string|void
856
+     */
857
+    public static function FormatBytes($bytes, $precision = 2) {
858
+        if ($bytes <= 0) {
859
+            return '0 B';
860
+        }
861
+
862
+        $units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB'];
863
+        $base = log($bytes, 1024);
864
+        $fBase = floor($base);
865
+        $pow = pow(1024, $base - $fBase);
866
+
867
+        return sprintf("%.{$precision}f %s", $pow, $units[$fBase]);
868
+    }
869
+
870
+    /**
871
+     * Returns folder origin identifier from its id.
872
+     *
873
+     * @param string $folderid
874
+     *
875
+     * @return bool|string matches values of DeviceManager::FLD_ORIGIN_*
876
+     */
877
+    public static function GetFolderOriginFromId($folderid) {
878
+        $origin = substr($folderid, 0, 1);
879
+
880
+        switch ($origin) {
881
+            case DeviceManager::FLD_ORIGIN_CONFIG:
882
+            case DeviceManager::FLD_ORIGIN_GAB:
883
+            case DeviceManager::FLD_ORIGIN_SHARED:
884
+            case DeviceManager::FLD_ORIGIN_USER:
885
+            case DeviceManager::FLD_ORIGIN_IMPERSONATED:
886
+                return $origin;
887
+        }
888
+        SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginFromId(): Unknown folder origin for folder with id '%s'", $folderid));
889
+
890
+        return false;
891
+    }
892
+
893
+    /**
894
+     * Returns folder origin as string from its id.
895
+     *
896
+     * @param string $folderid
897
+     *
898
+     * @return string
899
+     */
900
+    public static function GetFolderOriginStringFromId($folderid) {
901
+        $origin = substr($folderid, 0, 1);
902
+
903
+        switch ($origin) {
904
+            case DeviceManager::FLD_ORIGIN_CONFIG:
905
+                return 'configured';
906
+
907
+            case DeviceManager::FLD_ORIGIN_GAB:
908
+                return 'GAB';
909
+
910
+            case DeviceManager::FLD_ORIGIN_SHARED:
911
+                return 'shared';
912
+
913
+            case DeviceManager::FLD_ORIGIN_USER:
914
+                return 'user';
915
+
916
+            case DeviceManager::FLD_ORIGIN_IMPERSONATED:
917
+                return 'impersonated';
918
+        }
919
+        SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFolderOriginStringFromId(): Unknown folder origin for folder with id '%s'", $folderid));
920
+
921
+        return 'unknown';
922
+    }
923
+
924
+    /**
925
+     * Splits the id into folder id and message id parts. A colon in the $id indicates
926
+     * that the id has folderid:messageid format.
927
+     *
928
+     * @param string $id
929
+     *
930
+     * @return array
931
+     */
932
+    public static function SplitMessageId($id) {
933
+        if (strpos($id, ':') !== false) {
934
+            return explode(':', $id);
935
+        }
936
+
937
+        return [null, $id];
938
+    }
939
+
940
+    /**
941
+     * Converts a string freebusy type into a numeric status.
942
+     *
943
+     * @param string $fbType
944
+     *
945
+     * @return int
946
+     */
947
+    public static function GetFbStatusFromType($fbType) {
948
+        switch ($fbType) {
949
+            case 'Free':
950
+                return fbFree;
951
+
952
+            case 'Tentative':
953
+                return fbTentative;
954
+
955
+            case 'Busy':
956
+                return fbBusy;
957
+
958
+            case 'OOF':
959
+                return fbOutOfOffice;
960
+        }
961
+        SLog::Write(LOGLEVEL_WARN, sprintf("Utils->GetFbStatusFromType(): Unknown free busy type '%s'", $fbType));
962
+
963
+        return fbNoData;
964
+    }
965 965
 }
966 966
 
967 967
 // TODO Win1252/UTF8 functions are deprecated and will be removed sometime
@@ -969,41 +969,41 @@  discard block
 block discarded – undo
969 969
 // STORE_SUPPORTS_UNICODE is true and the conversion will not be done
970 970
 // for other backends.
971 971
 function utf8_to_windows1252($string, $option = "", $force_convert = false) {
972
-	// if the store supports unicode return the string without converting it
973
-	if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
974
-		return $string;
975
-	}
972
+    // if the store supports unicode return the string without converting it
973
+    if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
974
+        return $string;
975
+    }
976 976
 
977
-	if (function_exists("iconv")) {
978
-		return @iconv("UTF-8", "Windows-1252" . $option, $string);
979
-	}
977
+    if (function_exists("iconv")) {
978
+        return @iconv("UTF-8", "Windows-1252" . $option, $string);
979
+    }
980 980
 
981
-	return utf8_decode($string); // no euro support here
981
+    return utf8_decode($string); // no euro support here
982 982
 }
983 983
 
984 984
 function windows1252_to_utf8($string, $option = "", $force_convert = false) {
985
-	// if the store supports unicode return the string without converting it
986
-	if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
987
-		return $string;
988
-	}
985
+    // if the store supports unicode return the string without converting it
986
+    if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
987
+        return $string;
988
+    }
989 989
 
990
-	if (function_exists("iconv")) {
991
-		return @iconv("Windows-1252", "UTF-8" . $option, $string);
992
-	}
990
+    if (function_exists("iconv")) {
991
+        return @iconv("Windows-1252", "UTF-8" . $option, $string);
992
+    }
993 993
 
994
-	return utf8_encode($string); // no euro support here
994
+    return utf8_encode($string); // no euro support here
995 995
 }
996 996
 
997 997
 function w2u($string) {
998
-	return windows1252_to_utf8($string);
998
+    return windows1252_to_utf8($string);
999 999
 }
1000 1000
 function u2w($string) {
1001
-	return utf8_to_windows1252($string);
1001
+    return utf8_to_windows1252($string);
1002 1002
 }
1003 1003
 
1004 1004
 function w2ui($string) {
1005
-	return windows1252_to_utf8($string, "//TRANSLIT");
1005
+    return windows1252_to_utf8($string, "//TRANSLIT");
1006 1006
 }
1007 1007
 function u2wi($string) {
1008
-	return utf8_to_windows1252($string, "//TRANSLIT");
1008
+    return utf8_to_windows1252($string, "//TRANSLIT");
1009 1009
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -65,17 +65,17 @@  discard block
 block discarded – undo
65 65
 			$zcs = $zip;
66 66
 		}
67 67
 		if (isset($city) && $city != "") {
68
-			$zcs .= (($zcs) ? " " : "") . $city;
68
+			$zcs .= (($zcs) ? " " : "").$city;
69 69
 		}
70 70
 		if (isset($state) && $state != "") {
71
-			$zcs .= (($zcs) ? " " : "") . $state;
71
+			$zcs .= (($zcs) ? " " : "").$state;
72 72
 		}
73 73
 		if ($zcs) {
74
-			$out = $zcs . "\r\n" . $out;
74
+			$out = $zcs."\r\n".$out;
75 75
 		}
76 76
 
77 77
 		if (isset($street) && $street != "") {
78
-			$out = $street . (($out) ? "\r\n\r\n" . $out : "");
78
+			$out = $street.(($out) ? "\r\n\r\n".$out : "");
79 79
 		}
80 80
 
81 81
 		return ($out) ? $out : null;
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 	public static function BuildFileAs($lastname = "", $firstname = "", $middlename = "", $company = "") {
95 95
 		if (defined('FILEAS_ORDER')) {
96 96
 			$fileas = $lastfirst = $firstlast = "";
97
-			$names = trim($firstname . " " . $middlename);
97
+			$names = trim($firstname." ".$middlename);
98 98
 			$lastname = trim($lastname);
99 99
 			$company = trim($company);
100 100
 
@@ -257,7 +257,7 @@  discard block
 block discarded – undo
257 257
 			$OLUid .= pack("V", 1);
258 258
 			$OLUid .= $icalUid;
259 259
 
260
-			return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000" . bin2hex($OLUid) . "00");
260
+			return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000".bin2hex($OLUid)."00");
261 261
 		}
262 262
 
263 263
 		return hex2bin($icalUid);
@@ -409,7 +409,7 @@  discard block
 block discarded – undo
409 409
 	 */
410 410
 	public static function Utf8_truncate($string, $length, $htmlsafe = false) {
411 411
 		// make sure length is always an integer
412
-		$length = (int) $length;
412
+		$length = (int)$length;
413 413
 
414 414
 		// if the input string is shorter then the trunction, make sure it's valid UTF-8!
415 415
 		if (strlen($string) <= $length) {
@@ -479,7 +479,7 @@  discard block
 block discarded – undo
479 479
 	 * @return bool
480 480
 	 */
481 481
 	public static function IsBase64String($string) {
482
-		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);
482
+		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);
483 483
 	}
484 484
 
485 485
 	/**
@@ -975,7 +975,7 @@  discard block
 block discarded – undo
975 975
 	}
976 976
 
977 977
 	if (function_exists("iconv")) {
978
-		return @iconv("UTF-8", "Windows-1252" . $option, $string);
978
+		return @iconv("UTF-8", "Windows-1252".$option, $string);
979 979
 	}
980 980
 
981 981
 	return utf8_decode($string); // no euro support here
@@ -988,7 +988,7 @@  discard block
 block discarded – undo
988 988
 	}
989 989
 
990 990
 	if (function_exists("iconv")) {
991
-		return @iconv("Windows-1252", "UTF-8" . $option, $string);
991
+		return @iconv("Windows-1252", "UTF-8".$option, $string);
992 992
 	}
993 993
 
994 994
 	return utf8_encode($string); // no euro support here
Please login to merge, or discard this patch.
Braces   +8 added lines, -16 removed lines patch added patch discarded remove patch
@@ -33,8 +33,7 @@  discard block
 block discarded – undo
33 33
 		if ($pos === false) {
34 34
 			$user = $domainuser;
35 35
 			$domain = '';
36
-		}
37
-		else {
36
+		} else {
38 37
 			$domain = substr($domainuser, 0, $pos);
39 38
 			$user = substr($domainuser, $pos + 1);
40 39
 		}
@@ -105,12 +104,10 @@  discard block
 block discarded – undo
105 104
 				if (strlen($names) > 0) {
106 105
 					$lastfirst .= ", {$names}";
107 106
 					$firstlast = "{$names} {$lastname}";
108
-				}
109
-				else {
107
+				} else {
110 108
 					$firstlast = $lastname;
111 109
 				}
112
-			}
113
-			elseif (strlen($names) > 0) {
110
+			} elseif (strlen($names) > 0) {
114 111
 				$lastfirst = $firstlast = $names;
115 112
 			}
116 113
 
@@ -122,8 +119,7 @@  discard block
 block discarded – undo
122 119
 				case SYNC_FILEAS_COMPANYONLY:
123 120
 					if (strlen($company) > 0) {
124 121
 						$fileas = $company;
125
-					}
126
-					elseif (strlen($firstlast) > 0) {
122
+					} elseif (strlen($firstlast) > 0) {
127 123
 						$fileas = $lastfirst;
128 124
 					}
129 125
 					break;
@@ -134,8 +130,7 @@  discard block
 block discarded – undo
134 130
 						if (strlen($lastfirst) > 0) {
135 131
 							$fileas .= "({$lastfirst})";
136 132
 						}
137
-					}
138
-					elseif (strlen($lastfirst) > 0) {
133
+					} elseif (strlen($lastfirst) > 0) {
139 134
 						$fileas = $lastfirst;
140 135
 					}
141 136
 					break;
@@ -146,8 +141,7 @@  discard block
 block discarded – undo
146 141
 						if (strlen($firstlast) > 0) {
147 142
 							$fileas .= " ({$firstlast})";
148 143
 						}
149
-					}
150
-					elseif (strlen($firstlast) > 0) {
144
+					} elseif (strlen($firstlast) > 0) {
151 145
 						$fileas = $firstlast;
152 146
 					}
153 147
 					break;
@@ -158,8 +152,7 @@  discard block
 block discarded – undo
158 152
 						if (strlen($company) > 0) {
159 153
 							$fileas .= " ({$company})";
160 154
 						}
161
-					}
162
-					elseif (strlen($company) > 0) {
155
+					} elseif (strlen($company) > 0) {
163 156
 						$fileas = $company;
164 157
 					}
165 158
 					break;
@@ -170,8 +163,7 @@  discard block
 block discarded – undo
170 163
 						if (strlen($company) > 0) {
171 164
 							$fileas .= " ({$company})";
172 165
 						}
173
-					}
174
-					elseif (strlen($company) > 0) {
166
+					} elseif (strlen($company) > 0) {
175 167
 						$fileas = $company;
176 168
 					}
177 169
 					break;
Please login to merge, or discard this patch.
lib/exceptions/notimplementedexception.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -8,5 +8,5 @@
 block discarded – undo
8 8
  * available which is non-fatal.
9 9
  */
10 10
 class NotImplementedException extends GSyncException {
11
-	protected $defaultLogLevel = LOGLEVEL_ERROR;
11
+    protected $defaultLogLevel = LOGLEVEL_ERROR;
12 12
 }
Please login to merge, or discard this patch.
lib/exceptions/syncobjectbrokenexception.php 1 patch
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -9,28 +9,28 @@
 block discarded – undo
9 9
  */
10 10
 
11 11
 class SyncObjectBrokenException extends GSyncException {
12
-	protected $defaultLogLevel = LOGLEVEL_WARN;
13
-	private $syncObject;
12
+    protected $defaultLogLevel = LOGLEVEL_WARN;
13
+    private $syncObject;
14 14
 
15
-	/**
16
-	 * Returns the SyncObject which caused this Exception (if set).
17
-	 *
18
-	 * @return SyncObject
19
-	 */
20
-	public function GetSyncObject() {
21
-		return isset($this->syncObject) ? $this->syncObject : false;
22
-	}
15
+    /**
16
+     * Returns the SyncObject which caused this Exception (if set).
17
+     *
18
+     * @return SyncObject
19
+     */
20
+    public function GetSyncObject() {
21
+        return isset($this->syncObject) ? $this->syncObject : false;
22
+    }
23 23
 
24
-	/**
25
-	 * Sets the SyncObject which caused the exception so it can be later retrieved.
26
-	 *
27
-	 * @param SyncObject $syncobject
28
-	 *
29
-	 * @return bool
30
-	 */
31
-	public function SetSyncObject($syncobject) {
32
-		$this->syncObject = $syncobject;
24
+    /**
25
+     * Sets the SyncObject which caused the exception so it can be later retrieved.
26
+     *
27
+     * @param SyncObject $syncobject
28
+     *
29
+     * @return bool
30
+     */
31
+    public function SetSyncObject($syncobject) {
32
+        $this->syncObject = $syncobject;
33 33
 
34
-		return true;
35
-	}
34
+        return true;
35
+    }
36 36
 }
Please login to merge, or discard this patch.
lib/exceptions/authenticationrequiredexception.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -7,9 +7,9 @@
 block discarded – undo
7 7
  * Exception sending a "401 Unauthorized" to the mobile
8 8
  */
9 9
 class AuthenticationRequiredException extends HTTPReturnCodeException {
10
-	protected $defaultLogLevel = LOGLEVEL_INFO;
11
-	protected $httpReturnCode = HTTP_CODE_401;
12
-	protected $httpReturnMessage = "Unauthorized";
13
-	protected $httpHeaders = ['WWW-Authenticate: Basic realm="GSync"'];
14
-	protected $showLegal = true;
10
+    protected $defaultLogLevel = LOGLEVEL_INFO;
11
+    protected $httpReturnCode = HTTP_CODE_401;
12
+    protected $httpReturnMessage = "Unauthorized";
13
+    protected $httpHeaders = ['WWW-Authenticate: Basic realm="GSync"'];
14
+    protected $showLegal = true;
15 15
 }
Please login to merge, or discard this patch.
lib/exceptions/statusexception.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -7,5 +7,5 @@
 block discarded – undo
7 7
  * Main exception related to errors regarding synchronization
8 8
  */
9 9
 class StatusException extends GSyncException {
10
-	protected $defaultLogLevel = LOGLEVEL_INFO;
10
+    protected $defaultLogLevel = LOGLEVEL_INFO;
11 11
 }
Please login to merge, or discard this patch.
lib/exceptions/gsyncexception.php 2 patches
Indentation   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -8,34 +8,34 @@
 block discarded – undo
8 8
  */
9 9
 
10 10
 class GSyncException extends Exception {
11
-	protected $defaultLogLevel = LOGLEVEL_FATAL;
12
-	protected $httpReturnCode = HTTP_CODE_500;
13
-	protected $httpReturnMessage = "Internal Server Error";
14
-	protected $httpHeaders = [];
15
-	protected $showLegal = true;
11
+    protected $defaultLogLevel = LOGLEVEL_FATAL;
12
+    protected $httpReturnCode = HTTP_CODE_500;
13
+    protected $httpReturnMessage = "Internal Server Error";
14
+    protected $httpHeaders = [];
15
+    protected $showLegal = true;
16 16
 
17
-	public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) {
18
-		if (!$message) {
19
-			$message = $this->httpReturnMessage;
20
-		}
17
+    public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) {
18
+        if (!$message) {
19
+            $message = $this->httpReturnMessage;
20
+        }
21 21
 
22
-		if (!$logLevel) {
23
-			$logLevel = $this->defaultLogLevel;
24
-		}
22
+        if (!$logLevel) {
23
+            $logLevel = $this->defaultLogLevel;
24
+        }
25 25
 
26
-		parent::__construct($message, (int) $code);
27
-		SLog::Write($logLevel, get_class($this) . ': ' . $message . ' - code: ' . $code . ' - file: ' . $this->getFile() . ':' . $this->getLine(), false);
28
-	}
26
+        parent::__construct($message, (int) $code);
27
+        SLog::Write($logLevel, get_class($this) . ': ' . $message . ' - code: ' . $code . ' - file: ' . $this->getFile() . ':' . $this->getLine(), false);
28
+    }
29 29
 
30
-	public function getHTTPCodeString() {
31
-		return $this->httpReturnCode . " " . $this->httpReturnMessage;
32
-	}
30
+    public function getHTTPCodeString() {
31
+        return $this->httpReturnCode . " " . $this->httpReturnMessage;
32
+    }
33 33
 
34
-	public function getHTTPHeaders() {
35
-		return $this->httpHeaders;
36
-	}
34
+    public function getHTTPHeaders() {
35
+        return $this->httpHeaders;
36
+    }
37 37
 
38
-	public function showLegalNotice() {
39
-		return $this->showLegal;
40
-	}
38
+    public function showLegalNotice() {
39
+        return $this->showLegal;
40
+    }
41 41
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -23,12 +23,12 @@
 block discarded – undo
23 23
 			$logLevel = $this->defaultLogLevel;
24 24
 		}
25 25
 
26
-		parent::__construct($message, (int) $code);
27
-		SLog::Write($logLevel, get_class($this) . ': ' . $message . ' - code: ' . $code . ' - file: ' . $this->getFile() . ':' . $this->getLine(), false);
26
+		parent::__construct($message, (int)$code);
27
+		SLog::Write($logLevel, get_class($this).': '.$message.' - code: '.$code.' - file: '.$this->getFile().':'.$this->getLine(), false);
28 28
 	}
29 29
 
30 30
 	public function getHTTPCodeString() {
31
-		return $this->httpReturnCode . " " . $this->httpReturnMessage;
31
+		return $this->httpReturnCode." ".$this->httpReturnMessage;
32 32
 	}
33 33
 
34 34
 	public function getHTTPHeaders() {
Please login to merge, or discard this patch.