xref: /PHP-5.3/ext/date/php_date.c (revision 88c2dbe5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
16    +----------------------------------------------------------------------+
17  */
18 
19 /* $Id$ */
20 
21 #include "php.h"
22 #include "php_streams.h"
23 #include "php_main.h"
24 #include "php_globals.h"
25 #include "php_ini.h"
26 #include "ext/standard/info.h"
27 #include "ext/standard/php_versioning.h"
28 #include "ext/standard/php_math.h"
29 #include "php_date.h"
30 #include "zend_interfaces.h"
31 #include "lib/timelib.h"
32 #include <time.h>
33 
34 #ifdef PHP_WIN32
php_date_llabs(__int64 i)35 static __inline __int64 php_date_llabs( __int64 i ) { return i >= 0? i: -i; }
36 #elif defined(__GNUC__) && __GNUC__ < 3
php_date_llabs(__int64_t i)37 static __inline __int64_t php_date_llabs( __int64_t i ) { return i >= 0 ? i : -i; }
38 #else
php_date_llabs(long long i)39 static inline long long php_date_llabs( long long i ) { return i >= 0 ? i : -i; }
40 #endif
41 
42 #ifdef PHP_WIN32
43 #define DATE_I64_BUF_LEN 65
44 # define DATE_I64A(i, s, len) _i64toa_s(i, s, len, 10)
45 # define DATE_A64I(i, s) i = _atoi64(s)
46 #else
47 #define DATE_I64_BUF_LEN 65
48 # define DATE_I64A(i, s, len) \
49 	do { \
50 		int st = snprintf(s, len, "%lld", i); \
51 		s[st] = '\0'; \
52 	} while (0);
53 # define DATE_A64I(i, s) i = atoll(s)
54 #endif
55 
56 /* {{{ arginfo */
57 ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
58 	ZEND_ARG_INFO(0, format)
59 	ZEND_ARG_INFO(0, timestamp)
60 ZEND_END_ARG_INFO()
61 
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
63 	ZEND_ARG_INFO(0, format)
64 	ZEND_ARG_INFO(0, timestamp)
65 ZEND_END_ARG_INFO()
66 
67 ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
68 	ZEND_ARG_INFO(0, format)
69 	ZEND_ARG_INFO(0, timestamp)
70 ZEND_END_ARG_INFO()
71 
72 ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
73 	ZEND_ARG_INFO(0, time)
74 	ZEND_ARG_INFO(0, now)
75 ZEND_END_ARG_INFO()
76 
77 ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
78 	ZEND_ARG_INFO(0, hour)
79 	ZEND_ARG_INFO(0, min)
80 	ZEND_ARG_INFO(0, sec)
81 	ZEND_ARG_INFO(0, mon)
82 	ZEND_ARG_INFO(0, day)
83 	ZEND_ARG_INFO(0, year)
84 ZEND_END_ARG_INFO()
85 
86 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 0, 0, 0)
87 	ZEND_ARG_INFO(0, hour)
88 	ZEND_ARG_INFO(0, min)
89 	ZEND_ARG_INFO(0, sec)
90 	ZEND_ARG_INFO(0, mon)
91 	ZEND_ARG_INFO(0, day)
92 	ZEND_ARG_INFO(0, year)
93 ZEND_END_ARG_INFO()
94 
95 ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
96 	ZEND_ARG_INFO(0, month)
97 	ZEND_ARG_INFO(0, day)
98 	ZEND_ARG_INFO(0, year)
99 ZEND_END_ARG_INFO()
100 
101 ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
102 	ZEND_ARG_INFO(0, format)
103 	ZEND_ARG_INFO(0, timestamp)
104 ZEND_END_ARG_INFO()
105 
106 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
107 	ZEND_ARG_INFO(0, format)
108 	ZEND_ARG_INFO(0, timestamp)
109 ZEND_END_ARG_INFO()
110 
111 ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
112 ZEND_END_ARG_INFO()
113 
114 ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
115 	ZEND_ARG_INFO(0, timestamp)
116 	ZEND_ARG_INFO(0, associative_array)
117 ZEND_END_ARG_INFO()
118 
119 ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
120 	ZEND_ARG_INFO(0, timestamp)
121 ZEND_END_ARG_INFO()
122 
123 ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
124 	ZEND_ARG_INFO(0, timezone_identifier)
125 ZEND_END_ARG_INFO()
126 
127 ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
128 ZEND_END_ARG_INFO()
129 
130 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
131 	ZEND_ARG_INFO(0, time)
132 	ZEND_ARG_INFO(0, format)
133 	ZEND_ARG_INFO(0, latitude)
134 	ZEND_ARG_INFO(0, longitude)
135 	ZEND_ARG_INFO(0, zenith)
136 	ZEND_ARG_INFO(0, gmt_offset)
137 ZEND_END_ARG_INFO()
138 
139 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
140 	ZEND_ARG_INFO(0, time)
141 	ZEND_ARG_INFO(0, format)
142 	ZEND_ARG_INFO(0, latitude)
143 	ZEND_ARG_INFO(0, longitude)
144 	ZEND_ARG_INFO(0, zenith)
145 	ZEND_ARG_INFO(0, gmt_offset)
146 ZEND_END_ARG_INFO()
147 
148 ZEND_BEGIN_ARG_INFO(arginfo_date_sun_info, 0)
149 	ZEND_ARG_INFO(0, time)
150 	ZEND_ARG_INFO(0, latitude)
151 	ZEND_ARG_INFO(0, longitude)
152 ZEND_END_ARG_INFO()
153 
154 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0)
155 	ZEND_ARG_INFO(0, time)
156 	ZEND_ARG_INFO(0, object)
157 ZEND_END_ARG_INFO()
158 
159 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create_from_format, 0, 0, 2)
160 	ZEND_ARG_INFO(0, format)
161 	ZEND_ARG_INFO(0, time)
162 	ZEND_ARG_INFO(0, object)
163 ZEND_END_ARG_INFO()
164 
165 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse, 0, 0, 1)
166 	ZEND_ARG_INFO(0, date)
167 ZEND_END_ARG_INFO()
168 
169 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse_from_format, 0, 0, 2)
170 	ZEND_ARG_INFO(0, format)
171 	ZEND_ARG_INFO(0, date)
172 ZEND_END_ARG_INFO()
173 
174 ZEND_BEGIN_ARG_INFO(arginfo_date_get_last_errors, 0)
175 ZEND_END_ARG_INFO()
176 
177 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
178 	ZEND_ARG_INFO(0, object)
179 	ZEND_ARG_INFO(0, format)
180 ZEND_END_ARG_INFO()
181 
182 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_format, 0, 0, 1)
183 	ZEND_ARG_INFO(0, format)
184 ZEND_END_ARG_INFO()
185 
186 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
187 	ZEND_ARG_INFO(0, object)
188 	ZEND_ARG_INFO(0, modify)
189 ZEND_END_ARG_INFO()
190 
191 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_modify, 0, 0, 1)
192 	ZEND_ARG_INFO(0, modify)
193 ZEND_END_ARG_INFO()
194 
195 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
196 	ZEND_ARG_INFO(0, object)
197 	ZEND_ARG_INFO(0, interval)
198 ZEND_END_ARG_INFO()
199 
200 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_add, 0, 0, 1)
201 	ZEND_ARG_INFO(0, interval)
202 ZEND_END_ARG_INFO()
203 
204 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sub, 0, 0, 2)
205 	ZEND_ARG_INFO(0, object)
206 	ZEND_ARG_INFO(0, interval)
207 ZEND_END_ARG_INFO()
208 
209 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_sub, 0, 0, 1)
210 	ZEND_ARG_INFO(0, interval)
211 ZEND_END_ARG_INFO()
212 
213 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
214 	ZEND_ARG_INFO(0, object)
215 ZEND_END_ARG_INFO()
216 
217 ZEND_BEGIN_ARG_INFO(arginfo_date_method_timezone_get, 0)
218 ZEND_END_ARG_INFO()
219 
220 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
221 	ZEND_ARG_INFO(0, object)
222 	ZEND_ARG_INFO(0, timezone)
223 ZEND_END_ARG_INFO()
224 
225 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timezone_set, 0, 0, 1)
226 	ZEND_ARG_INFO(0, timezone)
227 ZEND_END_ARG_INFO()
228 
229 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_offset_get, 0, 0, 1)
230 	ZEND_ARG_INFO(0, object)
231 ZEND_END_ARG_INFO()
232 
233 ZEND_BEGIN_ARG_INFO(arginfo_date_method_offset_get, 0)
234 ZEND_END_ARG_INFO()
235 
236 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
237 	ZEND_ARG_INFO(0, object)
238 	ZEND_ARG_INFO(0, object2)
239 	ZEND_ARG_INFO(0, absolute)
240 ZEND_END_ARG_INFO()
241 
242 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_diff, 0, 0, 1)
243 	ZEND_ARG_INFO(0, object)
244 	ZEND_ARG_INFO(0, absolute)
245 ZEND_END_ARG_INFO()
246 
247 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
248 	ZEND_ARG_INFO(0, object)
249 	ZEND_ARG_INFO(0, hour)
250 	ZEND_ARG_INFO(0, minute)
251 	ZEND_ARG_INFO(0, second)
252 ZEND_END_ARG_INFO()
253 
254 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_time_set, 0, 0, 2)
255 	ZEND_ARG_INFO(0, hour)
256 	ZEND_ARG_INFO(0, minute)
257 	ZEND_ARG_INFO(0, second)
258 ZEND_END_ARG_INFO()
259 
260 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
261 	ZEND_ARG_INFO(0, object)
262 	ZEND_ARG_INFO(0, year)
263 	ZEND_ARG_INFO(0, month)
264 	ZEND_ARG_INFO(0, day)
265 ZEND_END_ARG_INFO()
266 
267 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_date_set, 0, 0, 3)
268 	ZEND_ARG_INFO(0, year)
269 	ZEND_ARG_INFO(0, month)
270 	ZEND_ARG_INFO(0, day)
271 ZEND_END_ARG_INFO()
272 
273 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
274 	ZEND_ARG_INFO(0, object)
275 	ZEND_ARG_INFO(0, year)
276 	ZEND_ARG_INFO(0, week)
277 	ZEND_ARG_INFO(0, day)
278 ZEND_END_ARG_INFO()
279 
280 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_isodate_set, 0, 0, 2)
281 	ZEND_ARG_INFO(0, year)
282 	ZEND_ARG_INFO(0, week)
283 	ZEND_ARG_INFO(0, day)
284 ZEND_END_ARG_INFO()
285 
286 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
287 	ZEND_ARG_INFO(0, object)
288 	ZEND_ARG_INFO(0, unixtimestamp)
289 ZEND_END_ARG_INFO()
290 
291 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timestamp_set, 0, 0, 1)
292 	ZEND_ARG_INFO(0, unixtimestamp)
293 ZEND_END_ARG_INFO()
294 
295 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_get, 0, 0, 1)
296 	ZEND_ARG_INFO(0, object)
297 ZEND_END_ARG_INFO()
298 
299 ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0)
300 ZEND_END_ARG_INFO()
301 
302 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
303 	ZEND_ARG_INFO(0, timezone)
304 ZEND_END_ARG_INFO()
305 
306 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
307 	ZEND_ARG_INFO(0, object)
308 ZEND_END_ARG_INFO()
309 
310 ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_name_get, 0)
311 ZEND_END_ARG_INFO()
312 
313 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
314 	ZEND_ARG_INFO(0, abbr)
315 	ZEND_ARG_INFO(0, gmtoffset)
316 	ZEND_ARG_INFO(0, isdst)
317 ZEND_END_ARG_INFO()
318 
319 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
320 	ZEND_ARG_INFO(0, object)
321 	ZEND_ARG_INFO(0, datetime)
322 ZEND_END_ARG_INFO()
323 
324 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_method_offset_get, 0, 0, 1)
325 	ZEND_ARG_INFO(0, datetime)
326 ZEND_END_ARG_INFO()
327 
328 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
329 	ZEND_ARG_INFO(0, object)
330 	ZEND_ARG_INFO(0, timestamp_begin)
331 	ZEND_ARG_INFO(0, timestamp_end)
332 ZEND_END_ARG_INFO()
333 
334 ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0)
335 	ZEND_ARG_INFO(0, timestamp_begin)
336 	ZEND_ARG_INFO(0, timestamp_end)
337 ZEND_END_ARG_INFO()
338 
339 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
340 	ZEND_ARG_INFO(0, object)
341 ZEND_END_ARG_INFO()
342 
343 ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0)
344 ZEND_END_ARG_INFO()
345 
346 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
347 	ZEND_ARG_INFO(0, what)
348 	ZEND_ARG_INFO(0, country)
349 ZEND_END_ARG_INFO()
350 
351 ZEND_BEGIN_ARG_INFO(arginfo_timezone_abbreviations_list, 0)
352 ZEND_END_ARG_INFO()
353 
354 ZEND_BEGIN_ARG_INFO(arginfo_timezone_version_get, 0)
355 ZEND_END_ARG_INFO()
356 
357 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
358 	ZEND_ARG_INFO(0, time)
359 ZEND_END_ARG_INFO()
360 
361 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
362 	ZEND_ARG_INFO(0, object)
363 	ZEND_ARG_INFO(0, format)
364 ZEND_END_ARG_INFO()
365 
366 ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0)
367 	ZEND_ARG_INFO(0, format)
368 ZEND_END_ARG_INFO()
369 
370 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_period_construct, 0, 0, 3)
371 	ZEND_ARG_INFO(0, start)
372 	ZEND_ARG_INFO(0, interval)
373 	ZEND_ARG_INFO(0, end)
374 ZEND_END_ARG_INFO()
375 
376 ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0)
377 	ZEND_ARG_INFO(0, interval_spec)
378 ZEND_END_ARG_INFO()
379 /* }}} */
380 
381 /* {{{ Function table */
382 const zend_function_entry date_functions[] = {
383 	PHP_FE(strtotime, arginfo_strtotime)
384 	PHP_FE(date, arginfo_date)
385 	PHP_FE(idate, arginfo_idate)
386 	PHP_FE(gmdate, arginfo_gmdate)
387 	PHP_FE(mktime, arginfo_mktime)
388 	PHP_FE(gmmktime, arginfo_gmmktime)
389 	PHP_FE(checkdate, arginfo_checkdate)
390 
391 #ifdef HAVE_STRFTIME
392 	PHP_FE(strftime, arginfo_strftime)
393 	PHP_FE(gmstrftime, arginfo_gmstrftime)
394 #endif
395 
396 	PHP_FE(time, arginfo_time)
397 	PHP_FE(localtime, arginfo_localtime)
398 	PHP_FE(getdate, arginfo_getdate)
399 
400 	/* Advanced Interface */
401 	PHP_FE(date_create, arginfo_date_create)
402 	PHP_FE(date_create_from_format, arginfo_date_create_from_format)
403 	PHP_FE(date_parse, arginfo_date_parse)
404 	PHP_FE(date_parse_from_format, arginfo_date_parse_from_format)
405 	PHP_FE(date_get_last_errors, arginfo_date_get_last_errors)
406 	PHP_FE(date_format, arginfo_date_format)
407 	PHP_FE(date_modify, arginfo_date_modify)
408 	PHP_FE(date_add, arginfo_date_add)
409 	PHP_FE(date_sub, arginfo_date_sub)
410 	PHP_FE(date_timezone_get, arginfo_date_timezone_get)
411 	PHP_FE(date_timezone_set, arginfo_date_timezone_set)
412 	PHP_FE(date_offset_get, arginfo_date_offset_get)
413 	PHP_FE(date_diff, arginfo_date_diff)
414 
415 	PHP_FE(date_time_set, arginfo_date_time_set)
416 	PHP_FE(date_date_set, arginfo_date_date_set)
417 	PHP_FE(date_isodate_set, arginfo_date_isodate_set)
418 	PHP_FE(date_timestamp_set, arginfo_date_timestamp_set)
419 	PHP_FE(date_timestamp_get, arginfo_date_timestamp_get)
420 
421 	PHP_FE(timezone_open, arginfo_timezone_open)
422 	PHP_FE(timezone_name_get, arginfo_timezone_name_get)
423 	PHP_FE(timezone_name_from_abbr, arginfo_timezone_name_from_abbr)
424 	PHP_FE(timezone_offset_get, arginfo_timezone_offset_get)
425 	PHP_FE(timezone_transitions_get, arginfo_timezone_transitions_get)
426 	PHP_FE(timezone_location_get, arginfo_timezone_location_get)
427 	PHP_FE(timezone_identifiers_list, arginfo_timezone_identifiers_list)
428 	PHP_FE(timezone_abbreviations_list, arginfo_timezone_abbreviations_list)
429 	PHP_FE(timezone_version_get, arginfo_timezone_version_get)
430 
431 	PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string)
432 	PHP_FE(date_interval_format, arginfo_date_interval_format)
433 
434 	/* Options and Configuration */
435 	PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
436 	PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
437 
438 	/* Astronomical functions */
439 	PHP_FE(date_sunrise, arginfo_date_sunrise)
440 	PHP_FE(date_sunset, arginfo_date_sunset)
441 	PHP_FE(date_sun_info, arginfo_date_sun_info)
442 	PHP_FE_END
443 };
444 
445 const zend_function_entry date_funcs_date[] = {
446 	PHP_ME(DateTime,			__construct,		arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
447 	PHP_ME(DateTime,			__wakeup,			NULL, ZEND_ACC_PUBLIC)
448 	PHP_ME(DateTime,			__set_state,		NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
449 	PHP_ME_MAPPING(createFromFormat, date_create_from_format,	arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
450 	PHP_ME_MAPPING(getLastErrors, date_get_last_errors,	arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
451 	PHP_ME_MAPPING(format,		date_format,		arginfo_date_method_format, 0)
452 	PHP_ME_MAPPING(modify,		date_modify,		arginfo_date_method_modify, 0)
453 	PHP_ME_MAPPING(add,			date_add,			arginfo_date_method_add, 0)
454 	PHP_ME_MAPPING(sub,			date_sub,			arginfo_date_method_sub, 0)
455 	PHP_ME_MAPPING(getTimezone, date_timezone_get,	arginfo_date_method_timezone_get, 0)
456 	PHP_ME_MAPPING(setTimezone, date_timezone_set,	arginfo_date_method_timezone_set, 0)
457 	PHP_ME_MAPPING(getOffset,	date_offset_get,	arginfo_date_method_offset_get, 0)
458 	PHP_ME_MAPPING(setTime,		date_time_set,		arginfo_date_method_time_set, 0)
459 	PHP_ME_MAPPING(setDate,		date_date_set,		arginfo_date_method_date_set, 0)
460 	PHP_ME_MAPPING(setISODate,	date_isodate_set,	arginfo_date_method_isodate_set, 0)
461 	PHP_ME_MAPPING(setTimestamp,	date_timestamp_set, arginfo_date_method_timestamp_set, 0)
462 	PHP_ME_MAPPING(getTimestamp,	date_timestamp_get, arginfo_date_method_timestamp_get, 0)
463 	PHP_ME_MAPPING(diff,			date_diff, arginfo_date_method_diff, 0)
464 	PHP_FE_END
465 };
466 
467 const zend_function_entry date_funcs_timezone[] = {
468 	PHP_ME(DateTimeZone,              __construct,                 arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
469 	PHP_ME_MAPPING(getName,           timezone_name_get,           arginfo_timezone_method_name_get, 0)
470 	PHP_ME_MAPPING(getOffset,         timezone_offset_get,         arginfo_timezone_method_offset_get, 0)
471 	PHP_ME_MAPPING(getTransitions,    timezone_transitions_get,    arginfo_timezone_method_transitions_get, 0)
472 	PHP_ME_MAPPING(getLocation,       timezone_location_get,       arginfo_timezone_method_location_get, 0)
473 	PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_timezone_abbreviations_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
474 	PHP_ME_MAPPING(listIdentifiers,   timezone_identifiers_list,   arginfo_timezone_identifiers_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
475 	PHP_FE_END
476 };
477 
478 const zend_function_entry date_funcs_interval[] = {
479 	PHP_ME(DateInterval,              __construct,                 arginfo_date_interval_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
480 	PHP_ME(DateInterval,              __wakeup,                    NULL, ZEND_ACC_PUBLIC)
481 	PHP_ME(DateInterval,              __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
482 	PHP_ME_MAPPING(format,            date_interval_format,        arginfo_date_method_interval_format, 0)
483 	PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string,	arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
484 	PHP_FE_END
485 };
486 
487 const zend_function_entry date_funcs_period[] = {
488 	PHP_ME(DatePeriod,                __construct,                 arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
489 	PHP_ME(DatePeriod,                __wakeup,                    NULL, ZEND_ACC_PUBLIC)
490 	PHP_ME(DatePeriod,                __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
491 	PHP_FE_END
492 };
493 
494 static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
495 static void date_register_classes(TSRMLS_D);
496 /* }}} */
497 
498 ZEND_DECLARE_MODULE_GLOBALS(date)
499 static PHP_GINIT_FUNCTION(date);
500 
501 /* True global */
502 timelib_tzdb *php_date_global_timezone_db;
503 int php_date_global_timezone_db_enabled;
504 
505 #define DATE_DEFAULT_LATITUDE "31.7667"
506 #define DATE_DEFAULT_LONGITUDE "35.2333"
507 
508 /* on 90'35; common sunset declaration (start of sun body appear) */
509 #define DATE_SUNSET_ZENITH "90.583333"
510 
511 /* on 90'35; common sunrise declaration (sun body disappeared) */
512 #define DATE_SUNRISE_ZENITH "90.583333"
513 
514 /* {{{ INI Settings */
515 PHP_INI_BEGIN()
516 	STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdateString, default_timezone, zend_date_globals, date_globals)
517 	PHP_INI_ENTRY("date.default_latitude",           DATE_DEFAULT_LATITUDE,        PHP_INI_ALL, NULL)
518 	PHP_INI_ENTRY("date.default_longitude",          DATE_DEFAULT_LONGITUDE,       PHP_INI_ALL, NULL)
519 	PHP_INI_ENTRY("date.sunset_zenith",              DATE_SUNSET_ZENITH,           PHP_INI_ALL, NULL)
520 	PHP_INI_ENTRY("date.sunrise_zenith",             DATE_SUNRISE_ZENITH,          PHP_INI_ALL, NULL)
521 PHP_INI_END()
522 /* }}} */
523 
524 zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period;
525 
526 
php_date_get_date_ce(void)527 PHPAPI zend_class_entry *php_date_get_date_ce(void)
528 {
529 	return date_ce_date;
530 }
531 
php_date_get_timezone_ce(void)532 PHPAPI zend_class_entry *php_date_get_timezone_ce(void)
533 {
534 	return date_ce_timezone;
535 }
536 
537 static zend_object_handlers date_object_handlers_date;
538 static zend_object_handlers date_object_handlers_timezone;
539 static zend_object_handlers date_object_handlers_interval;
540 static zend_object_handlers date_object_handlers_period;
541 
542 #define DATE_SET_CONTEXT \
543 	zval *object; \
544 	object = getThis(); \
545 
546 #define DATE_FETCH_OBJECT	\
547 	php_date_obj *obj;	\
548 	DATE_SET_CONTEXT; \
549 	if (object) {	\
550 		if (zend_parse_parameters_none() == FAILURE) {	\
551 			return;	\
552 		}	\
553 	} else {	\
554 		if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, date_ce_date) == FAILURE) {	\
555 			RETURN_FALSE;	\
556 		}	\
557 	}	\
558 	obj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);	\
559 
560 #define DATE_CHECK_INITIALIZED(member, class_name) \
561 	if (!(member)) { \
562 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
563 		RETURN_FALSE; \
564 	}
565 
566 static void date_object_free_storage_date(void *object TSRMLS_DC);
567 static void date_object_free_storage_timezone(void *object TSRMLS_DC);
568 static void date_object_free_storage_interval(void *object TSRMLS_DC);
569 static void date_object_free_storage_period(void *object TSRMLS_DC);
570 
571 static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
572 static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
573 static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC);
574 static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC);
575 
576 static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
577 static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
578 static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC);
579 static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC);
580 
581 static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
582 static HashTable *date_object_get_properties(zval *object TSRMLS_DC);
583 static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC);
584 static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC);
585 
586 zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC);
587 void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC);
588 static zval *date_period_read_property(zval *object, zval *member, int type TSRMLS_DC);
589 static void date_period_write_property(zval *object, zval *member, zval *value TSRMLS_DC);
590 
591 /* {{{ Module struct */
592 zend_module_entry date_module_entry = {
593 	STANDARD_MODULE_HEADER_EX,
594 	NULL,
595 	NULL,
596 	"date",                     /* extension name */
597 	date_functions,             /* function list */
598 	PHP_MINIT(date),            /* process startup */
599 	PHP_MSHUTDOWN(date),        /* process shutdown */
600 	PHP_RINIT(date),            /* request startup */
601 	PHP_RSHUTDOWN(date),        /* request shutdown */
602 	PHP_MINFO(date),            /* extension info */
603 	PHP_VERSION,                /* extension version */
604 	PHP_MODULE_GLOBALS(date),   /* globals descriptor */
605 	PHP_GINIT(date),            /* globals ctor */
606 	NULL,                       /* globals dtor */
607 	NULL,                       /* post deactivate */
608 	STANDARD_MODULE_PROPERTIES_EX
609 };
610 /* }}} */
611 
612 
613 /* {{{ PHP_GINIT_FUNCTION */
PHP_GINIT_FUNCTION(date)614 static PHP_GINIT_FUNCTION(date)
615 {
616 	date_globals->default_timezone = NULL;
617 	date_globals->timezone = NULL;
618 	date_globals->tzcache = NULL;
619 }
620 /* }}} */
621 
622 
_php_date_tzinfo_dtor(void * tzinfo)623 static void _php_date_tzinfo_dtor(void *tzinfo)
624 {
625 	timelib_tzinfo **tzi = (timelib_tzinfo **)tzinfo;
626 
627 	timelib_tzinfo_dtor(*tzi);
628 }
629 
630 /* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(date)631 PHP_RINIT_FUNCTION(date)
632 {
633 	if (DATEG(timezone)) {
634 		efree(DATEG(timezone));
635 	}
636 	DATEG(timezone) = NULL;
637 	DATEG(tzcache) = NULL;
638 	DATEG(last_errors) = NULL;
639 
640 	return SUCCESS;
641 }
642 /* }}} */
643 
644 /* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(date)645 PHP_RSHUTDOWN_FUNCTION(date)
646 {
647 	if (DATEG(timezone)) {
648 		efree(DATEG(timezone));
649 	}
650 	DATEG(timezone) = NULL;
651 	if(DATEG(tzcache)) {
652 		zend_hash_destroy(DATEG(tzcache));
653 		FREE_HASHTABLE(DATEG(tzcache));
654 		DATEG(tzcache) = NULL;
655 	}
656 	if (DATEG(last_errors)) {
657 		timelib_error_container_dtor(DATEG(last_errors));
658 		DATEG(last_errors) = NULL;
659 	}
660 
661 	return SUCCESS;
662 }
663 /* }}} */
664 
665 #define DATE_TIMEZONEDB      php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
666 
667 /*
668  * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
669  *  date-time   =  [ day "," ] date time        ; dd mm yy hh:mm:ss zzz
670  *  day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"  /  "Fri"  / "Sat" /  "Sun"
671  *  date        =  1*2DIGIT month 2DIGIT        ; day month year e.g. 20 Jun 82
672  *  month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"  /  "May"  /  "Jun" /  "Jul"  /  "Aug"  /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
673  *  time        =  hour zone                    ; ANSI and Military
674  *  hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
675  *  zone        =  "UT"  / "GMT"  /  "EST" / "EDT"  /  "CST" / "CDT"  /  "MST" / "MDT"  /  "PST" / "PDT"  /  1ALPHA  / ( ("+" / "-") 4DIGIT )
676  */
677 #define DATE_FORMAT_RFC822   "D, d M y H:i:s O"
678 
679 /*
680  * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
681  *  Format must be acceptable both to the ARPANET and to the getdate routine.
682  *  One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
683  *  TIMEZONE can be any timezone name (3 or more letters)
684  */
685 #define DATE_FORMAT_RFC850   "l, d-M-y H:i:s T"
686 
687 /*
688  * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
689  *  Its format must be acceptable both in RFC-822 and to the getdate(3)
690  *  Wdy, DD Mon YY HH:MM:SS TIMEZONE
691  *  There is no hope of having a complete list of timezones.  Universal
692  *  Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
693  *  CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
694  */
695 #define DATE_FORMAT_RFC1036  "D, d M y H:i:s O"
696 
697 /*
698  * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
699  *  RFC-822 Date and Time Specification: RFC-822 Section 5
700  *  The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
701  */
702 #define DATE_FORMAT_RFC1123  "D, d M Y H:i:s O"
703 
704 /*
705  * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
706  *  FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
707  *  CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
708  *
709  *  date-time       =       [ day-of-week "," ] date FWS time [CFWS]
710  *  day-of-week     =       ([FWS] day-name)
711  *  day-name        =       "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
712  *  date            =       day month year
713  *  year            =       4*DIGIT
714  *  month           =       (FWS month-name FWS)
715  *  month-name      =       "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
716  *  day             =       ([FWS] 1*2DIGIT)
717  *  time            =       time-of-day FWS zone
718  *  time-of-day     =       hour ":" minute [ ":" second ]
719  *  hour            =       2DIGIT
720  *  minute          =       2DIGIT
721  *  second          =       2DIGIT
722  *  zone            =       (( "+" / "-" ) 4DIGIT)
723  */
724 #define DATE_FORMAT_RFC2822  "D, d M Y H:i:s O"
725 /*
726  * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
727  *  date-fullyear   = 4DIGIT
728  *  date-month      = 2DIGIT  ; 01-12
729  *  date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
730  *
731  *  time-hour       = 2DIGIT  ; 00-23
732  *  time-minute     = 2DIGIT  ; 00-59
733  *  time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
734  *
735  *  time-secfrac    = "." 1*DIGIT
736  *  time-numoffset  = ("+" / "-") time-hour ":" time-minute
737  *  time-offset     = "Z" / time-numoffset
738  *
739  *  partial-time    = time-hour ":" time-minute ":" time-second [time-secfrac]
740  *  full-date       = date-fullyear "-" date-month "-" date-mday
741  *  full-time       = partial-time time-offset
742  *
743  *  date-time       = full-date "T" full-time
744  */
745 #define DATE_FORMAT_RFC3339  "Y-m-d\\TH:i:sP"
746 
747 #define DATE_FORMAT_ISO8601  "Y-m-d\\TH:i:sO"
748 
749 #define DATE_TZ_ERRMSG \
750 	"It is not safe to rely on the system's timezone settings. You are " \
751 	"*required* to use the date.timezone setting or the " \
752 	"date_default_timezone_set() function. In case you used any of those " \
753 	"methods and you are still getting this warning, you most likely " \
754 	"misspelled the timezone identifier. "
755 
756 #define SUNFUNCS_RET_TIMESTAMP 0
757 #define SUNFUNCS_RET_STRING    1
758 #define SUNFUNCS_RET_DOUBLE    2
759 
760 
761 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(date)762 PHP_MINIT_FUNCTION(date)
763 {
764 	REGISTER_INI_ENTRIES();
765 	date_register_classes(TSRMLS_C);
766 /*
767  * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
768  *   A Date construct is an element whose content MUST conform to the
769  *   "date-time" production in [RFC3339].  In addition, an uppercase "T"
770  *   character MUST be used to separate date and time, and an uppercase
771  *   "Z" character MUST be present in the absence of a numeric time zone offset.
772  */
773 	REGISTER_STRING_CONSTANT("DATE_ATOM",    DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
774 /*
775  * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
776  *   "This is based on RFC 822, RFC 850,  RFC 1036, and  RFC 1123,
777  *   with the variations that the only legal time zone is GMT
778  *   and the separators between the elements of the date must be dashes."
779  */
780 	REGISTER_STRING_CONSTANT("DATE_COOKIE",  DATE_FORMAT_RFC850,  CONST_CS | CONST_PERSISTENT);
781 	REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
782 	REGISTER_STRING_CONSTANT("DATE_RFC822",  DATE_FORMAT_RFC822,  CONST_CS | CONST_PERSISTENT);
783 	REGISTER_STRING_CONSTANT("DATE_RFC850",  DATE_FORMAT_RFC850,  CONST_CS | CONST_PERSISTENT);
784 	REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
785 	REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
786 	REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
787  	REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
788 /*
789  * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
790  *   "All date-times in RSS conform to the Date and Time Specification of RFC 822,
791  *   with the exception that the year may be expressed with two characters or four characters (four preferred)"
792  */
793 	REGISTER_STRING_CONSTANT("DATE_RSS",     DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
794 	REGISTER_STRING_CONSTANT("DATE_W3C",     DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
795 
796 	REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
797 	REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
798 	REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
799 
800 	php_date_global_timezone_db = NULL;
801 	php_date_global_timezone_db_enabled = 0;
802 	DATEG(last_errors) = NULL;
803 	return SUCCESS;
804 }
805 /* }}} */
806 
807 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(date)808 PHP_MSHUTDOWN_FUNCTION(date)
809 {
810 	UNREGISTER_INI_ENTRIES();
811 
812 	if (DATEG(last_errors)) {
813 		timelib_error_container_dtor(DATEG(last_errors));
814 	}
815 
816 	return SUCCESS;
817 }
818 /* }}} */
819 
820 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(date)821 PHP_MINFO_FUNCTION(date)
822 {
823 	const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
824 
825 	php_info_print_table_start();
826 	php_info_print_table_row(2, "date/time support", "enabled");
827 	php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
828 	php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
829 	php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb TSRMLS_CC));
830 	php_info_print_table_end();
831 
832 	DISPLAY_INI_ENTRIES();
833 }
834 /* }}} */
835 
836 /* {{{ Timezone Cache functions */
php_date_parse_tzfile(char * formal_tzname,const timelib_tzdb * tzdb TSRMLS_DC)837 static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb TSRMLS_DC)
838 {
839 	timelib_tzinfo *tzi, **ptzi;
840 
841 	if(!DATEG(tzcache)) {
842 		ALLOC_HASHTABLE(DATEG(tzcache));
843 		zend_hash_init(DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
844 	}
845 
846 	if (zend_hash_find(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void **) &ptzi) == SUCCESS) {
847 		return *ptzi;
848 	}
849 
850 	tzi = timelib_parse_tzfile(formal_tzname, tzdb);
851 	if (tzi) {
852 		zend_hash_add(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void *) &tzi, sizeof(timelib_tzinfo*), NULL);
853 	}
854 	return tzi;
855 }
856 
php_date_parse_tzfile_wrapper(char * formal_tzname,const timelib_tzdb * tzdb)857 timelib_tzinfo *php_date_parse_tzfile_wrapper(char *formal_tzname, const timelib_tzdb *tzdb)
858 {
859 	TSRMLS_FETCH();
860 	return php_date_parse_tzfile(formal_tzname, tzdb TSRMLS_CC);
861 }
862 /* }}} */
863 
864 /* {{{ Helper functions */
guess_timezone(const timelib_tzdb * tzdb TSRMLS_DC)865 static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
866 {
867 	char *env;
868 
869 	/* Checking configure timezone */
870 	if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
871 		return DATEG(timezone);
872 	}
873 	/* Check environment variable */
874 	env = getenv("TZ");
875 	if (env && *env && timelib_timezone_id_is_valid(env, tzdb)) {
876 		return env;
877 	}
878 	/* Check config setting for default timezone */
879 	if (!DATEG(default_timezone)) {
880 		/* Special case: ext/date wasn't initialized yet */
881 		zval ztz;
882 
883 		if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz) &&
884 		    Z_TYPE(ztz) == IS_STRING &&
885 		    Z_STRLEN(ztz) > 0 &&
886 		    timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) {
887 			return Z_STRVAL(ztz);
888 		}
889 	} else if (*DATEG(default_timezone) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
890 		return DATEG(default_timezone);
891 	}
892 #if HAVE_TM_ZONE
893 	/* Try to guess timezone from system information */
894 	{
895 		struct tm *ta, tmbuf;
896 		time_t     the_time;
897 		char      *tzid = NULL;
898 
899 		the_time = time(NULL);
900 		ta = php_localtime_r(&the_time, &tmbuf);
901 		if (ta) {
902 			tzid = timelib_timezone_id_from_abbr(ta->tm_zone, ta->tm_gmtoff, ta->tm_isdst);
903 		}
904 		if (! tzid) {
905 			tzid = "UTC";
906 		}
907 
908 		php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%s/%.1f/%s' instead", tzid, ta ? ta->tm_zone : "Unknown", ta ? (float) (ta->tm_gmtoff / 3600) : 0, ta ? (ta->tm_isdst ? "DST" : "no DST") : "Unknown");
909 		return tzid;
910 	}
911 #endif
912 #ifdef PHP_WIN32
913 	{
914 		char *tzid;
915 		TIME_ZONE_INFORMATION tzi;
916 
917 		switch (GetTimeZoneInformation(&tzi))
918 		{
919 			/* DST in effect */
920 			case TIME_ZONE_ID_DAYLIGHT:
921 				/* If user has disabled DST in the control panel, Windows returns 0 here */
922 				if (tzi.DaylightBias == 0) {
923 					goto php_win_std_time;
924 				}
925 
926 				tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.DaylightBias) * -60, 1);
927 				if (! tzid) {
928 					tzid = "UTC";
929 				}
930 				php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/DST' instead", tzid, ((tzi.Bias + tzi.DaylightBias) / -60.0));
931 				break;
932 
933 			/* no DST or not in effect */
934 			case TIME_ZONE_ID_UNKNOWN:
935 			case TIME_ZONE_ID_STANDARD:
936 			default:
937 php_win_std_time:
938 				tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.StandardBias) * -60, 0);
939 				if (! tzid) {
940 					tzid = "UTC";
941 				}
942 				php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/no DST' instead", tzid, ((tzi.Bias + tzi.StandardBias) / -60.0));
943 				break;
944 
945 		}
946 		return tzid;
947 	}
948 #elif defined(NETWARE)
949 	/* Try to guess timezone from system information */
950 	{
951 		char *tzid = timelib_timezone_id_from_abbr("", ((_timezone * -1) + (daylightOffset * daylightOnOff)), daylightOnOff);
952 		if (tzid) {
953 			return tzid;
954 		}
955 	}
956 #endif
957 	/* Fallback to UTC */
958 	php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We had to select 'UTC' because your platform doesn't provide functionality for the guessing algorithm");
959 	return "UTC";
960 }
961 
get_timezone_info(TSRMLS_D)962 PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
963 {
964 	char *tz;
965 	timelib_tzinfo *tzi;
966 
967 	tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
968 	tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
969 	if (! tzi) {
970 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
971 	}
972 	return tzi;
973 }
974 /* }}} */
975 
976 
977 /* {{{ date() and gmdate() data */
978 #include "ext/standard/php_smart_str.h"
979 
980 static char *mon_full_names[] = {
981 	"January", "February", "March", "April",
982 	"May", "June", "July", "August",
983 	"September", "October", "November", "December"
984 };
985 
986 static char *mon_short_names[] = {
987 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
988 };
989 
990 static char *day_full_names[] = {
991 	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
992 };
993 
994 static char *day_short_names[] = {
995 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
996 };
997 
english_suffix(timelib_sll number)998 static char *english_suffix(timelib_sll number)
999 {
1000 	if (number >= 10 && number <= 19) {
1001 		return "th";
1002 	} else {
1003 		switch (number % 10) {
1004 			case 1: return "st";
1005 			case 2: return "nd";
1006 			case 3: return "rd";
1007 		}
1008 	}
1009 	return "th";
1010 }
1011 /* }}} */
1012 
1013 /* {{{ day of week helpers */
php_date_full_day_name(timelib_sll y,timelib_sll m,timelib_sll d)1014 char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
1015 {
1016 	timelib_sll day_of_week = timelib_day_of_week(y, m, d);
1017 	if (day_of_week < 0) {
1018 		return "Unknown";
1019 	}
1020 	return day_full_names[day_of_week];
1021 }
1022 
php_date_short_day_name(timelib_sll y,timelib_sll m,timelib_sll d)1023 char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
1024 {
1025 	timelib_sll day_of_week = timelib_day_of_week(y, m, d);
1026 	if (day_of_week < 0) {
1027 		return "Unknown";
1028 	}
1029 	return day_short_names[day_of_week];
1030 }
1031 /* }}} */
1032 
1033 /* {{{ date_format - (gm)date helper */
date_format(char * format,int format_len,timelib_time * t,int localtime)1034 static char *date_format(char *format, int format_len, timelib_time *t, int localtime)
1035 {
1036 	smart_str            string = {0};
1037 	int                  i, length;
1038 	char                 buffer[97];
1039 	timelib_time_offset *offset = NULL;
1040 	timelib_sll          isoweek, isoyear;
1041 	int                  rfc_colon;
1042 
1043 	if (!format_len) {
1044 		return estrdup("");
1045 	}
1046 
1047 	if (localtime) {
1048 		if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
1049 			offset = timelib_time_offset_ctor();
1050 			offset->offset = (t->z - (t->dst * 60)) * -60;
1051 			offset->leap_secs = 0;
1052 			offset->is_dst = t->dst;
1053 			offset->abbr = strdup(t->tz_abbr);
1054 		} else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
1055 			offset = timelib_time_offset_ctor();
1056 			offset->offset = (t->z) * -60;
1057 			offset->leap_secs = 0;
1058 			offset->is_dst = 0;
1059 			offset->abbr = malloc(9); /* GMT�xxxx\0 */
1060 			snprintf(offset->abbr, 9, "GMT%c%02d%02d",
1061 			                          localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1062 			                          localtime ? abs(offset->offset / 3600) : 0,
1063 			                          localtime ? abs((offset->offset % 3600) / 60) : 0 );
1064 		} else {
1065 			offset = timelib_get_time_zone_info(t->sse, t->tz_info);
1066 		}
1067 	}
1068 	timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
1069 
1070 	for (i = 0; i < format_len; i++) {
1071 		rfc_colon = 0;
1072 		switch (format[i]) {
1073 			/* day */
1074 			case 'd': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
1075 			case 'D': length = slprintf(buffer, 32, "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
1076 			case 'j': length = slprintf(buffer, 32, "%d", (int) t->d); break;
1077 			case 'l': length = slprintf(buffer, 32, "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
1078 			case 'S': length = slprintf(buffer, 32, "%s", english_suffix(t->d)); break;
1079 			case 'w': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
1080 			case 'N': length = slprintf(buffer, 32, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
1081 			case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
1082 
1083 			/* week */
1084 			case 'W': length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */
1085 			case 'o': length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */
1086 
1087 			/* month */
1088 			case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break;
1089 			case 'm': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
1090 			case 'M': length = slprintf(buffer, 32, "%s", mon_short_names[t->m - 1]); break;
1091 			case 'n': length = slprintf(buffer, 32, "%d", (int) t->m); break;
1092 			case 't': length = slprintf(buffer, 32, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
1093 
1094 			/* year */
1095 			case 'L': length = slprintf(buffer, 32, "%d", timelib_is_leap((int) t->y)); break;
1096 			case 'y': length = slprintf(buffer, 32, "%02d", (int) t->y % 100); break;
1097 			case 'Y': length = slprintf(buffer, 32, "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
1098 
1099 			/* time */
1100 			case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
1101 			case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
1102 			case 'B': {
1103 				int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
1104 				while (retval < 0) {
1105 					retval += 1000;
1106 				}
1107 				retval = retval % 1000;
1108 				length = slprintf(buffer, 32, "%03d", retval);
1109 				break;
1110 			}
1111 			case 'g': length = slprintf(buffer, 32, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
1112 			case 'G': length = slprintf(buffer, 32, "%d", (int) t->h); break;
1113 			case 'h': length = slprintf(buffer, 32, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
1114 			case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
1115 			case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
1116 			case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
1117 			case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000 + 0.5)); break;
1118 
1119 			/* timezone */
1120 			case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
1121 			case 'P': rfc_colon = 1; /* break intentionally missing */
1122 			case 'O': length = slprintf(buffer, 32, "%c%02d%s%02d",
1123 											localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1124 											localtime ? abs(offset->offset / 3600) : 0,
1125 											rfc_colon ? ":" : "",
1126 											localtime ? abs((offset->offset % 3600) / 60) : 0
1127 							  );
1128 					  break;
1129 			case 'T': length = slprintf(buffer, 32, "%s", localtime ? offset->abbr : "GMT"); break;
1130 			case 'e': if (!localtime) {
1131 					      length = slprintf(buffer, 32, "%s", "UTC");
1132 					  } else {
1133 						  switch (t->zone_type) {
1134 							  case TIMELIB_ZONETYPE_ID:
1135 								  length = slprintf(buffer, 32, "%s", t->tz_info->name);
1136 								  break;
1137 							  case TIMELIB_ZONETYPE_ABBR:
1138 								  length = slprintf(buffer, 32, "%s", offset->abbr);
1139 								  break;
1140 							  case TIMELIB_ZONETYPE_OFFSET:
1141 								  length = slprintf(buffer, 32, "%c%02d:%02d",
1142 												((offset->offset < 0) ? '-' : '+'),
1143 												abs(offset->offset / 3600),
1144 												abs((offset->offset % 3600) / 60)
1145 										   );
1146 								  break;
1147 						  }
1148 					  }
1149 					  break;
1150 			case 'Z': length = slprintf(buffer, 32, "%d", localtime ? offset->offset : 0); break;
1151 
1152 			/* full date/time */
1153 			case 'c': length = slprintf(buffer, 96, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
1154 							                (int) t->y, (int) t->m, (int) t->d,
1155 											(int) t->h, (int) t->i, (int) t->s,
1156 											localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1157 											localtime ? abs(offset->offset / 3600) : 0,
1158 											localtime ? abs((offset->offset % 3600) / 60) : 0
1159 							  );
1160 					  break;
1161 			case 'r': length = slprintf(buffer, 96, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
1162 							                php_date_short_day_name(t->y, t->m, t->d),
1163 											(int) t->d, mon_short_names[t->m - 1],
1164 											(int) t->y, (int) t->h, (int) t->i, (int) t->s,
1165 											localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1166 											localtime ? abs(offset->offset / 3600) : 0,
1167 											localtime ? abs((offset->offset % 3600) / 60) : 0
1168 							  );
1169 					  break;
1170 			case 'U': length = slprintf(buffer, 32, "%lld", (timelib_sll) t->sse); break;
1171 
1172 			case '\\': if (i < format_len) i++; /* break intentionally missing */
1173 
1174 			default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
1175 		}
1176 		smart_str_appendl(&string, buffer, length);
1177 	}
1178 
1179 	smart_str_0(&string);
1180 
1181 	if (localtime) {
1182 		timelib_time_offset_dtor(offset);
1183 	}
1184 
1185 	return string.c;
1186 }
1187 
php_date(INTERNAL_FUNCTION_PARAMETERS,int localtime)1188 static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
1189 {
1190 	char   *format;
1191 	int     format_len;
1192 	long    ts;
1193 	char   *string;
1194 
1195 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
1196 		RETURN_FALSE;
1197 	}
1198 	if (ZEND_NUM_ARGS() == 1) {
1199 		ts = time(NULL);
1200 	}
1201 
1202 	string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
1203 
1204 	RETVAL_STRING(string, 0);
1205 }
1206 /* }}} */
1207 
php_format_date(char * format,int format_len,time_t ts,int localtime TSRMLS_DC)1208 PHPAPI char *php_format_date(char *format, int format_len, time_t ts, int localtime TSRMLS_DC) /* {{{ */
1209 {
1210 	timelib_time   *t;
1211 	timelib_tzinfo *tzi;
1212 	char *string;
1213 
1214 	t = timelib_time_ctor();
1215 
1216 	if (localtime) {
1217 		tzi = get_timezone_info(TSRMLS_C);
1218 		t->tz_info = tzi;
1219 		t->zone_type = TIMELIB_ZONETYPE_ID;
1220 		timelib_unixtime2local(t, ts);
1221 	} else {
1222 		tzi = NULL;
1223 		timelib_unixtime2gmt(t, ts);
1224 	}
1225 
1226 	string = date_format(format, format_len, t, localtime);
1227 
1228 	timelib_time_dtor(t);
1229 	return string;
1230 }
1231 /* }}} */
1232 
1233 /* {{{ php_idate
1234  */
php_idate(char format,time_t ts,int localtime)1235 PHPAPI int php_idate(char format, time_t ts, int localtime)
1236 {
1237 	timelib_time   *t;
1238 	timelib_tzinfo *tzi;
1239 	int retval = -1;
1240 	timelib_time_offset *offset = NULL;
1241 	timelib_sll isoweek, isoyear;
1242 	TSRMLS_FETCH();
1243 
1244 	t = timelib_time_ctor();
1245 
1246 	if (!localtime) {
1247 		tzi = get_timezone_info(TSRMLS_C);
1248 		t->tz_info = tzi;
1249 		t->zone_type = TIMELIB_ZONETYPE_ID;
1250 		timelib_unixtime2local(t, ts);
1251 	} else {
1252 		tzi = NULL;
1253 		timelib_unixtime2gmt(t, ts);
1254 	}
1255 
1256 	if (!localtime) {
1257 		if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
1258 			offset = timelib_time_offset_ctor();
1259 			offset->offset = (t->z - (t->dst * 60)) * -60;
1260 			offset->leap_secs = 0;
1261 			offset->is_dst = t->dst;
1262 			offset->abbr = strdup(t->tz_abbr);
1263 		} else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
1264 			offset = timelib_time_offset_ctor();
1265 			offset->offset = (t->z - (t->dst * 60)) * -60;
1266 			offset->leap_secs = 0;
1267 			offset->is_dst = t->dst;
1268 			offset->abbr = malloc(9); /* GMT�xxxx\0 */
1269 			snprintf(offset->abbr, 9, "GMT%c%02d%02d",
1270 			                          !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
1271 			                          !localtime ? abs(offset->offset / 3600) : 0,
1272 			                          !localtime ? abs((offset->offset % 3600) / 60) : 0 );
1273 		} else {
1274 			offset = timelib_get_time_zone_info(t->sse, t->tz_info);
1275 		}
1276 	}
1277 
1278 	timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
1279 
1280 	switch (format) {
1281 		/* day */
1282 		case 'd': case 'j': retval = (int) t->d; break;
1283 
1284 		case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
1285 		case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
1286 
1287 		/* week */
1288 		case 'W': retval = (int) isoweek; break; /* iso weeknr */
1289 
1290 		/* month */
1291 		case 'm': case 'n': retval = (int) t->m; break;
1292 		case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
1293 
1294 		/* year */
1295 		case 'L': retval = (int) timelib_is_leap((int) t->y); break;
1296 		case 'y': retval = (int) (t->y % 100); break;
1297 		case 'Y': retval = (int) t->y; break;
1298 
1299 		/* Swatch Beat a.k.a. Internet Time */
1300 		case 'B':
1301 			retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
1302 			while (retval < 0) {
1303 				retval += 1000;
1304 			}
1305 			retval = retval % 1000;
1306 			break;
1307 
1308 		/* time */
1309 		case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
1310 		case 'H': case 'G': retval = (int) t->h; break;
1311 		case 'i': retval = (int) t->i; break;
1312 		case 's': retval = (int) t->s; break;
1313 
1314 		/* timezone */
1315 		case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
1316 		case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
1317 
1318 		case 'U': retval = (int) t->sse; break;
1319 	}
1320 
1321 	if (!localtime) {
1322 		timelib_time_offset_dtor(offset);
1323 	}
1324 	timelib_time_dtor(t);
1325 
1326 	return retval;
1327 }
1328 /* }}} */
1329 
1330 /* {{{ proto string date(string format [, long timestamp])
1331    Format a local date/time */
PHP_FUNCTION(date)1332 PHP_FUNCTION(date)
1333 {
1334 	php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1335 }
1336 /* }}} */
1337 
1338 /* {{{ proto string gmdate(string format [, long timestamp])
1339    Format a GMT date/time */
PHP_FUNCTION(gmdate)1340 PHP_FUNCTION(gmdate)
1341 {
1342 	php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1343 }
1344 /* }}} */
1345 
1346 /* {{{ proto int idate(string format [, int timestamp])
1347    Format a local time/date as integer */
PHP_FUNCTION(idate)1348 PHP_FUNCTION(idate)
1349 {
1350 	char   *format;
1351 	int     format_len;
1352 	long    ts = 0;
1353 	int ret;
1354 
1355 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
1356 		RETURN_FALSE;
1357 	}
1358 
1359 	if (format_len != 1) {
1360 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
1361 		RETURN_FALSE;
1362 	}
1363 
1364 	if (ZEND_NUM_ARGS() == 1) {
1365 		ts = time(NULL);
1366 	}
1367 
1368 	ret = php_idate(format[0], ts, 0);
1369 	if (ret == -1) {
1370 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized date format token.");
1371 		RETURN_FALSE;
1372 	}
1373 	RETURN_LONG(ret);
1374 }
1375 /* }}} */
1376 
1377 /* {{{ php_date_set_tzdb - NOT THREADSAFE */
php_date_set_tzdb(timelib_tzdb * tzdb)1378 PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
1379 {
1380 	const timelib_tzdb *builtin = timelib_builtin_db();
1381 
1382 	if (php_version_compare(tzdb->version, builtin->version) > 0) {
1383 		php_date_global_timezone_db = tzdb;
1384 		php_date_global_timezone_db_enabled = 1;
1385 	}
1386 }
1387 /* }}} */
1388 
1389 /* {{{ php_parse_date: Backwards compability function */
php_parse_date(char * string,signed long * now)1390 PHPAPI signed long php_parse_date(char *string, signed long *now)
1391 {
1392 	timelib_time *parsed_time;
1393 	timelib_error_container *error = NULL;
1394 	int           error2;
1395 	signed long   retval;
1396 
1397 	parsed_time = timelib_strtotime(string, strlen(string), &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
1398 	if (error->error_count) {
1399 		timelib_error_container_dtor(error);
1400 		return -1;
1401 	}
1402 	timelib_error_container_dtor(error);
1403 	timelib_update_ts(parsed_time, NULL);
1404 	retval = timelib_date_to_int(parsed_time, &error2);
1405 	timelib_time_dtor(parsed_time);
1406 	if (error2) {
1407 		return -1;
1408 	}
1409 	return retval;
1410 }
1411 /* }}} */
1412 
1413 
1414 /* {{{ proto int strtotime(string time [, int now ])
1415    Convert string representation of date and time to a timestamp */
PHP_FUNCTION(strtotime)1416 PHP_FUNCTION(strtotime)
1417 {
1418 	char *times, *initial_ts;
1419 	int   time_len, error1, error2;
1420 	struct timelib_error_container *error;
1421 	long  preset_ts = 0, ts;
1422 
1423 	timelib_time *t, *now;
1424 	timelib_tzinfo *tzi;
1425 
1426 	tzi = get_timezone_info(TSRMLS_C);
1427 
1428 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sl", &times, &time_len, &preset_ts) != FAILURE) {
1429 		/* We have an initial timestamp */
1430 		now = timelib_time_ctor();
1431 
1432 		initial_ts = emalloc(25);
1433 		snprintf(initial_ts, 24, "@%ld UTC", preset_ts);
1434 		t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); /* we ignore the error here, as this should never fail */
1435 		timelib_update_ts(t, tzi);
1436 		now->tz_info = tzi;
1437 		now->zone_type = TIMELIB_ZONETYPE_ID;
1438 		timelib_unixtime2local(now, t->sse);
1439 		timelib_time_dtor(t);
1440 		efree(initial_ts);
1441 	} else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &times, &time_len, &preset_ts) != FAILURE) {
1442 		/* We have no initial timestamp */
1443 		now = timelib_time_ctor();
1444 		now->tz_info = tzi;
1445 		now->zone_type = TIMELIB_ZONETYPE_ID;
1446 		timelib_unixtime2local(now, (timelib_sll) time(NULL));
1447 	} else {
1448 		RETURN_FALSE;
1449 	}
1450 
1451 	if (!time_len) {
1452 		timelib_time_dtor(now);
1453 		RETURN_FALSE;
1454 	}
1455 
1456 	t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
1457 	error1 = error->error_count;
1458 	timelib_error_container_dtor(error);
1459 	timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
1460 	timelib_update_ts(t, tzi);
1461 	ts = timelib_date_to_int(t, &error2);
1462 
1463 	timelib_time_dtor(now);
1464 	timelib_time_dtor(t);
1465 
1466 	if (error1 || error2) {
1467 		RETURN_FALSE;
1468 	} else {
1469 		RETURN_LONG(ts);
1470 	}
1471 }
1472 /* }}} */
1473 
1474 
1475 /* {{{ php_mktime - (gm)mktime helper */
php_mktime(INTERNAL_FUNCTION_PARAMETERS,int gmt)1476 PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1477 {
1478 	long hou = 0, min = 0, sec = 0, mon = 0, day = 0, yea = 0, dst = -1;
1479 	timelib_time *now;
1480 	timelib_tzinfo *tzi = NULL;
1481 	long ts, adjust_seconds = 0;
1482 	int error;
1483 
1484 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
1485 		RETURN_FALSE;
1486 	}
1487 	/* Initialize structure with current time */
1488 	now = timelib_time_ctor();
1489 	if (gmt) {
1490 		timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
1491 	} else {
1492 		tzi = get_timezone_info(TSRMLS_C);
1493 		now->tz_info = tzi;
1494 		now->zone_type = TIMELIB_ZONETYPE_ID;
1495 		timelib_unixtime2local(now, (timelib_sll) time(NULL));
1496 	}
1497 	/* Fill in the new data */
1498 	switch (ZEND_NUM_ARGS()) {
1499 		case 7:
1500 			/* break intentionally missing */
1501 		case 6:
1502 			if (yea >= 0 && yea < 70) {
1503 				yea += 2000;
1504 			} else if (yea >= 70 && yea <= 100) {
1505 				yea += 1900;
1506 			}
1507 			now->y = yea;
1508 			/* break intentionally missing again */
1509 		case 5:
1510 			now->d = day;
1511 			/* break missing intentionally here too */
1512 		case 4:
1513 			now->m = mon;
1514 			/* and here */
1515 		case 3:
1516 			now->s = sec;
1517 			/* yup, this break isn't here on purpose too */
1518 		case 2:
1519 			now->i = min;
1520 			/* last intentionally missing break */
1521 		case 1:
1522 			now->h = hou;
1523 			break;
1524 		default:
1525 			php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead");
1526 	}
1527 	/* Update the timestamp */
1528 	if (gmt) {
1529 		timelib_update_ts(now, NULL);
1530 	} else {
1531 		timelib_update_ts(now, tzi);
1532 	}
1533 	/* Support for the deprecated is_dst parameter */
1534 	if (dst != -1) {
1535 		php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "The is_dst parameter is deprecated");
1536 		if (gmt) {
1537 			/* GMT never uses DST */
1538 			if (dst == 1) {
1539 				adjust_seconds = -3600;
1540 			}
1541 		} else {
1542 			/* Figure out is_dst for current TS */
1543 			timelib_time_offset *tmp_offset;
1544 			tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
1545 			if (dst == 1 && tmp_offset->is_dst == 0) {
1546 				adjust_seconds = -3600;
1547 			}
1548 			if (dst == 0 && tmp_offset->is_dst == 1) {
1549 				adjust_seconds = +3600;
1550 			}
1551 			timelib_time_offset_dtor(tmp_offset);
1552 		}
1553 	}
1554 	/* Clean up and return */
1555 	ts = timelib_date_to_int(now, &error);
1556 	ts += adjust_seconds;
1557 	timelib_time_dtor(now);
1558 
1559 	if (error) {
1560 		RETURN_FALSE;
1561 	} else {
1562 		RETURN_LONG(ts);
1563 	}
1564 }
1565 /* }}} */
1566 
1567 /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
1568    Get UNIX timestamp for a date */
PHP_FUNCTION(mktime)1569 PHP_FUNCTION(mktime)
1570 {
1571 	php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1572 }
1573 /* }}} */
1574 
1575 /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
1576    Get UNIX timestamp for a GMT date */
PHP_FUNCTION(gmmktime)1577 PHP_FUNCTION(gmmktime)
1578 {
1579 	php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1580 }
1581 /* }}} */
1582 
1583 
1584 /* {{{ proto bool checkdate(int month, int day, int year)
1585    Returns true(1) if it is a valid date in gregorian calendar */
PHP_FUNCTION(checkdate)1586 PHP_FUNCTION(checkdate)
1587 {
1588 	long m, d, y;
1589 
1590 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
1591 		RETURN_FALSE;
1592 	}
1593 
1594 	if (y < 1 || y > 32767 || !timelib_valid_date(y, m, d)) {
1595 		RETURN_FALSE;
1596 	}
1597 	RETURN_TRUE;	/* True : This month, day, year arguments are valid */
1598 }
1599 /* }}} */
1600 
1601 #ifdef HAVE_STRFTIME
1602 /* {{{ php_strftime - (gm)strftime helper */
php_strftime(INTERNAL_FUNCTION_PARAMETERS,int gmt)1603 PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1604 {
1605 	char                *format, *buf;
1606 	int                  format_len;
1607 	long                 timestamp = 0;
1608 	struct tm            ta;
1609 	int                  max_reallocs = 5;
1610 	size_t               buf_len = 64, real_len;
1611 	timelib_time        *ts;
1612 	timelib_tzinfo      *tzi;
1613 	timelib_time_offset *offset = NULL;
1614 
1615 	timestamp = (long) time(NULL);
1616 
1617 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &timestamp) == FAILURE) {
1618 		RETURN_FALSE;
1619 	}
1620 
1621 	if (format_len == 0) {
1622 		RETURN_FALSE;
1623 	}
1624 
1625 	ts = timelib_time_ctor();
1626 	if (gmt) {
1627 		tzi = NULL;
1628 		timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
1629 	} else {
1630 		tzi = get_timezone_info(TSRMLS_C);
1631 		ts->tz_info = tzi;
1632 		ts->zone_type = TIMELIB_ZONETYPE_ID;
1633 		timelib_unixtime2local(ts, (timelib_sll) timestamp);
1634 	}
1635 	ta.tm_sec   = ts->s;
1636 	ta.tm_min   = ts->i;
1637 	ta.tm_hour  = ts->h;
1638 	ta.tm_mday  = ts->d;
1639 	ta.tm_mon   = ts->m - 1;
1640 	ta.tm_year  = ts->y - 1900;
1641 	ta.tm_wday  = timelib_day_of_week(ts->y, ts->m, ts->d);
1642 	ta.tm_yday  = timelib_day_of_year(ts->y, ts->m, ts->d);
1643 	if (gmt) {
1644 		ta.tm_isdst = 0;
1645 #if HAVE_TM_GMTOFF
1646 		ta.tm_gmtoff = 0;
1647 #endif
1648 #if HAVE_TM_ZONE
1649 		ta.tm_zone = "GMT";
1650 #endif
1651 	} else {
1652 		offset = timelib_get_time_zone_info(timestamp, tzi);
1653 
1654 		ta.tm_isdst = offset->is_dst;
1655 #if HAVE_TM_GMTOFF
1656 		ta.tm_gmtoff = offset->offset;
1657 #endif
1658 #if HAVE_TM_ZONE
1659 		ta.tm_zone = offset->abbr;
1660 #endif
1661 	}
1662 
1663 	buf = (char *) emalloc(buf_len);
1664 	while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) {
1665 		buf_len *= 2;
1666 		buf = (char *) erealloc(buf, buf_len);
1667 		if (!--max_reallocs) {
1668 			break;
1669 		}
1670 	}
1671 
1672 	timelib_time_dtor(ts);
1673 	if (!gmt) {
1674 		timelib_time_offset_dtor(offset);
1675 	}
1676 
1677 	if (real_len && real_len != buf_len) {
1678 		buf = (char *) erealloc(buf, real_len + 1);
1679 		RETURN_STRINGL(buf, real_len, 0);
1680 	}
1681 	efree(buf);
1682 	RETURN_FALSE;
1683 }
1684 /* }}} */
1685 
1686 /* {{{ proto string strftime(string format [, int timestamp])
1687    Format a local time/date according to locale settings */
PHP_FUNCTION(strftime)1688 PHP_FUNCTION(strftime)
1689 {
1690 	php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1691 }
1692 /* }}} */
1693 
1694 /* {{{ proto string gmstrftime(string format [, int timestamp])
1695    Format a GMT/UCT time/date according to locale settings */
PHP_FUNCTION(gmstrftime)1696 PHP_FUNCTION(gmstrftime)
1697 {
1698 	php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1699 }
1700 /* }}} */
1701 #endif
1702 
1703 /* {{{ proto int time(void)
1704    Return current UNIX timestamp */
PHP_FUNCTION(time)1705 PHP_FUNCTION(time)
1706 {
1707 	RETURN_LONG((long)time(NULL));
1708 }
1709 /* }}} */
1710 
1711 /* {{{ proto array localtime([int timestamp [, bool associative_array]])
1712    Returns the results of the C system call localtime as an associative array if the associative_array argument is set to 1 other wise it is a regular array */
PHP_FUNCTION(localtime)1713 PHP_FUNCTION(localtime)
1714 {
1715 	long timestamp = (long)time(NULL);
1716 	zend_bool associative = 0;
1717 	timelib_tzinfo *tzi;
1718 	timelib_time   *ts;
1719 
1720 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &timestamp, &associative) == FAILURE) {
1721 		RETURN_FALSE;
1722 	}
1723 
1724 	tzi = get_timezone_info(TSRMLS_C);
1725 	ts = timelib_time_ctor();
1726 	ts->tz_info = tzi;
1727 	ts->zone_type = TIMELIB_ZONETYPE_ID;
1728 	timelib_unixtime2local(ts, (timelib_sll) timestamp);
1729 
1730 	array_init(return_value);
1731 
1732 	if (associative) {
1733 		add_assoc_long(return_value, "tm_sec",   ts->s);
1734 		add_assoc_long(return_value, "tm_min",   ts->i);
1735 		add_assoc_long(return_value, "tm_hour",  ts->h);
1736 		add_assoc_long(return_value, "tm_mday",  ts->d);
1737 		add_assoc_long(return_value, "tm_mon",   ts->m - 1);
1738 		add_assoc_long(return_value, "tm_year",  ts->y - 1900);
1739 		add_assoc_long(return_value, "tm_wday",  timelib_day_of_week(ts->y, ts->m, ts->d));
1740 		add_assoc_long(return_value, "tm_yday",  timelib_day_of_year(ts->y, ts->m, ts->d));
1741 		add_assoc_long(return_value, "tm_isdst", ts->dst);
1742 	} else {
1743 		add_next_index_long(return_value, ts->s);
1744 		add_next_index_long(return_value, ts->i);
1745 		add_next_index_long(return_value, ts->h);
1746 		add_next_index_long(return_value, ts->d);
1747 		add_next_index_long(return_value, ts->m - 1);
1748 		add_next_index_long(return_value, ts->y- 1900);
1749 		add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
1750 		add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
1751 		add_next_index_long(return_value, ts->dst);
1752 	}
1753 
1754 	timelib_time_dtor(ts);
1755 }
1756 /* }}} */
1757 
1758 /* {{{ proto array getdate([int timestamp])
1759    Get date/time information */
PHP_FUNCTION(getdate)1760 PHP_FUNCTION(getdate)
1761 {
1762 	long timestamp = (long)time(NULL);
1763 	timelib_tzinfo *tzi;
1764 	timelib_time   *ts;
1765 
1766 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timestamp) == FAILURE) {
1767 		RETURN_FALSE;
1768 	}
1769 
1770 	tzi = get_timezone_info(TSRMLS_C);
1771 	ts = timelib_time_ctor();
1772 	ts->tz_info = tzi;
1773 	ts->zone_type = TIMELIB_ZONETYPE_ID;
1774 	timelib_unixtime2local(ts, (timelib_sll) timestamp);
1775 
1776 	array_init(return_value);
1777 
1778 	add_assoc_long(return_value, "seconds", ts->s);
1779 	add_assoc_long(return_value, "minutes", ts->i);
1780 	add_assoc_long(return_value, "hours", ts->h);
1781 	add_assoc_long(return_value, "mday", ts->d);
1782 	add_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1783 	add_assoc_long(return_value, "mon", ts->m);
1784 	add_assoc_long(return_value, "year", ts->y);
1785 	add_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1786 	add_assoc_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d), 1);
1787 	add_assoc_string(return_value, "month", mon_full_names[ts->m - 1], 1);
1788 	add_index_long(return_value, 0, timestamp);
1789 
1790 	timelib_time_dtor(ts);
1791 }
1792 /* }}} */
1793 
1794 #define PHP_DATE_TIMEZONE_GROUP_AFRICA     0x0001
1795 #define PHP_DATE_TIMEZONE_GROUP_AMERICA    0x0002
1796 #define PHP_DATE_TIMEZONE_GROUP_ANTARCTICA 0x0004
1797 #define PHP_DATE_TIMEZONE_GROUP_ARCTIC     0x0008
1798 #define PHP_DATE_TIMEZONE_GROUP_ASIA       0x0010
1799 #define PHP_DATE_TIMEZONE_GROUP_ATLANTIC   0x0020
1800 #define PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  0x0040
1801 #define PHP_DATE_TIMEZONE_GROUP_EUROPE     0x0080
1802 #define PHP_DATE_TIMEZONE_GROUP_INDIAN     0x0100
1803 #define PHP_DATE_TIMEZONE_GROUP_PACIFIC    0x0200
1804 #define PHP_DATE_TIMEZONE_GROUP_UTC        0x0400
1805 #define PHP_DATE_TIMEZONE_GROUP_ALL        0x07FF
1806 #define PHP_DATE_TIMEZONE_GROUP_ALL_W_BC   0x0FFF
1807 #define PHP_DATE_TIMEZONE_PER_COUNTRY      0x1000
1808 
1809 #define PHP_DATE_PERIOD_EXCLUDE_START_DATE 0x0001
1810 
1811 
1812 /* define an overloaded iterator structure */
1813 typedef struct {
1814 	zend_object_iterator  intern;
1815 	zval                 *date_period_zval;
1816 	zval                 *current;
1817 	php_period_obj       *object;
1818 	int                   current_index;
1819 } date_period_it;
1820 
1821 /* {{{ date_period_it_invalidate_current */
date_period_it_invalidate_current(zend_object_iterator * iter TSRMLS_DC)1822 static void date_period_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
1823 {
1824 	date_period_it *iterator = (date_period_it *)iter;
1825 
1826 	if (iterator->current) {
1827 		zval_ptr_dtor(&iterator->current);
1828 		iterator->current = NULL;
1829 	}
1830 }
1831 /* }}} */
1832 
1833 
1834 /* {{{ date_period_it_dtor */
date_period_it_dtor(zend_object_iterator * iter TSRMLS_DC)1835 static void date_period_it_dtor(zend_object_iterator *iter TSRMLS_DC)
1836 {
1837 	date_period_it *iterator = (date_period_it *)iter;
1838 
1839 	date_period_it_invalidate_current(iter TSRMLS_CC);
1840 
1841 	zval_ptr_dtor(&iterator->date_period_zval);
1842 
1843 	efree(iterator);
1844 }
1845 /* }}} */
1846 
1847 
1848 /* {{{ date_period_it_has_more */
date_period_it_has_more(zend_object_iterator * iter TSRMLS_DC)1849 static int date_period_it_has_more(zend_object_iterator *iter TSRMLS_DC)
1850 {
1851 	date_period_it *iterator = (date_period_it *)iter;
1852 	php_period_obj *object   = iterator->object;
1853 	timelib_time   *it_time = object->current;
1854 
1855 	/* apply modification if it's not the first iteration */
1856 	if (!object->include_start_date || iterator->current_index > 0) {
1857 		it_time->have_relative = 1;
1858 		it_time->relative = *object->interval;
1859 		it_time->sse_uptodate = 0;
1860 		timelib_update_ts(it_time, NULL);
1861 		timelib_update_from_sse(it_time);
1862 	}
1863 
1864 	if (object->end) {
1865 		return object->current->sse < object->end->sse ? SUCCESS : FAILURE;
1866 	} else {
1867 		return (iterator->current_index < object->recurrences) ? SUCCESS : FAILURE;
1868 	}
1869 }
1870 /* }}} */
1871 
1872 
1873 /* {{{ date_period_it_current_data */
date_period_it_current_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)1874 static void date_period_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
1875 {
1876 	date_period_it *iterator = (date_period_it *)iter;
1877 	php_period_obj *object   = iterator->object;
1878 	timelib_time   *it_time = object->current;
1879 	php_date_obj   *newdateobj;
1880 
1881 	/* Create new object */
1882 	MAKE_STD_ZVAL(iterator->current);
1883 	php_date_instantiate(date_ce_date, iterator->current TSRMLS_CC);
1884 	newdateobj = (php_date_obj *) zend_object_store_get_object(iterator->current TSRMLS_CC);
1885 	newdateobj->time = timelib_time_ctor();
1886 	*newdateobj->time = *it_time;
1887 	if (it_time->tz_abbr) {
1888 		newdateobj->time->tz_abbr = strdup(it_time->tz_abbr);
1889 	}
1890 	if (it_time->tz_info) {
1891 		newdateobj->time->tz_info = it_time->tz_info;
1892 	}
1893 
1894 	*data = &iterator->current;
1895 }
1896 /* }}} */
1897 
1898 
1899 /* {{{ date_period_it_current_key */
date_period_it_current_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)1900 static int date_period_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
1901 {
1902 	date_period_it   *iterator = (date_period_it *)iter;
1903 	*int_key = iterator->current_index;
1904 	return HASH_KEY_IS_LONG;
1905 }
1906 /* }}} */
1907 
1908 
1909 /* {{{ date_period_it_move_forward */
date_period_it_move_forward(zend_object_iterator * iter TSRMLS_DC)1910 static void date_period_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
1911 {
1912 	date_period_it   *iterator = (date_period_it *)iter;
1913 
1914 	iterator->current_index++;
1915 	date_period_it_invalidate_current(iter TSRMLS_CC);
1916 }
1917 /* }}} */
1918 
1919 
1920 /* {{{ date_period_it_rewind */
date_period_it_rewind(zend_object_iterator * iter TSRMLS_DC)1921 static void date_period_it_rewind(zend_object_iterator *iter TSRMLS_DC)
1922 {
1923 	date_period_it   *iterator = (date_period_it *)iter;
1924 
1925 	iterator->current_index = 0;
1926 	if (iterator->object->current) {
1927 		timelib_time_dtor(iterator->object->current);
1928 	}
1929 	iterator->object->current = timelib_time_clone(iterator->object->start);
1930 	date_period_it_invalidate_current(iter TSRMLS_CC);
1931 }
1932 /* }}} */
1933 
1934 
1935 /* iterator handler table */
1936 zend_object_iterator_funcs date_period_it_funcs = {
1937 	date_period_it_dtor,
1938 	date_period_it_has_more,
1939 	date_period_it_current_data,
1940 	date_period_it_current_key,
1941 	date_period_it_move_forward,
1942 	date_period_it_rewind,
1943 	date_period_it_invalidate_current
1944 };
1945 
1946 
1947 
date_object_period_get_iterator(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)1948 zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
1949 {
1950 	date_period_it  *iterator = emalloc(sizeof(date_period_it));
1951 	php_period_obj  *dpobj    = (php_period_obj *)zend_object_store_get_object(object TSRMLS_CC);
1952 
1953 	if (by_ref) {
1954 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
1955 	}
1956 
1957 	Z_ADDREF_P(object);
1958 	iterator->intern.data = (void*) dpobj;
1959 	iterator->intern.funcs = &date_period_it_funcs;
1960 	iterator->date_period_zval = object;
1961 	iterator->object = dpobj;
1962 	iterator->current = NULL;
1963 
1964 	return (zend_object_iterator*)iterator;
1965 }
1966 
date_register_classes(TSRMLS_D)1967 static void date_register_classes(TSRMLS_D)
1968 {
1969 	zend_class_entry ce_date, ce_timezone, ce_interval, ce_period;
1970 
1971 	INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
1972 	ce_date.create_object = date_object_new_date;
1973 	date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC);
1974 	memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1975 	date_object_handlers_date.clone_obj = date_object_clone_date;
1976 	date_object_handlers_date.compare_objects = date_object_compare_date;
1977 	date_object_handlers_date.get_properties = date_object_get_properties;
1978 
1979 #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
1980 	zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
1981 
1982 	REGISTER_DATE_CLASS_CONST_STRING("ATOM",    DATE_FORMAT_RFC3339);
1983 	REGISTER_DATE_CLASS_CONST_STRING("COOKIE",  DATE_FORMAT_RFC850);
1984 	REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
1985 	REGISTER_DATE_CLASS_CONST_STRING("RFC822",  DATE_FORMAT_RFC822);
1986 	REGISTER_DATE_CLASS_CONST_STRING("RFC850",  DATE_FORMAT_RFC850);
1987 	REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
1988 	REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
1989 	REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
1990 	REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
1991 	REGISTER_DATE_CLASS_CONST_STRING("RSS",     DATE_FORMAT_RFC1123);
1992 	REGISTER_DATE_CLASS_CONST_STRING("W3C",     DATE_FORMAT_RFC3339);
1993 
1994 
1995 	INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
1996 	ce_timezone.create_object = date_object_new_timezone;
1997 	date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC);
1998 	memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1999 	date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
2000 
2001 #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \
2002 	zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC);
2003 
2004 	REGISTER_TIMEZONE_CLASS_CONST_STRING("AFRICA",      PHP_DATE_TIMEZONE_GROUP_AFRICA);
2005 	REGISTER_TIMEZONE_CLASS_CONST_STRING("AMERICA",     PHP_DATE_TIMEZONE_GROUP_AMERICA);
2006 	REGISTER_TIMEZONE_CLASS_CONST_STRING("ANTARCTICA",  PHP_DATE_TIMEZONE_GROUP_ANTARCTICA);
2007 	REGISTER_TIMEZONE_CLASS_CONST_STRING("ARCTIC",      PHP_DATE_TIMEZONE_GROUP_ARCTIC);
2008 	REGISTER_TIMEZONE_CLASS_CONST_STRING("ASIA",        PHP_DATE_TIMEZONE_GROUP_ASIA);
2009 	REGISTER_TIMEZONE_CLASS_CONST_STRING("ATLANTIC",    PHP_DATE_TIMEZONE_GROUP_ATLANTIC);
2010 	REGISTER_TIMEZONE_CLASS_CONST_STRING("AUSTRALIA",   PHP_DATE_TIMEZONE_GROUP_AUSTRALIA);
2011 	REGISTER_TIMEZONE_CLASS_CONST_STRING("EUROPE",      PHP_DATE_TIMEZONE_GROUP_EUROPE);
2012 	REGISTER_TIMEZONE_CLASS_CONST_STRING("INDIAN",      PHP_DATE_TIMEZONE_GROUP_INDIAN);
2013 	REGISTER_TIMEZONE_CLASS_CONST_STRING("PACIFIC",     PHP_DATE_TIMEZONE_GROUP_PACIFIC);
2014 	REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC",         PHP_DATE_TIMEZONE_GROUP_UTC);
2015 	REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL",         PHP_DATE_TIMEZONE_GROUP_ALL);
2016 	REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
2017 	REGISTER_TIMEZONE_CLASS_CONST_STRING("PER_COUNTRY", PHP_DATE_TIMEZONE_PER_COUNTRY);
2018 
2019 	INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
2020 	ce_interval.create_object = date_object_new_interval;
2021 	date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC);
2022 	memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2023 	date_object_handlers_interval.clone_obj = date_object_clone_interval;
2024 	date_object_handlers_interval.read_property = date_interval_read_property;
2025 	date_object_handlers_interval.write_property = date_interval_write_property;
2026 	date_object_handlers_interval.get_properties = date_object_get_properties_interval;
2027 	date_object_handlers_interval.get_property_ptr_ptr = NULL;
2028 
2029 	INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period);
2030 	ce_period.create_object = date_object_new_period;
2031 	date_ce_period = zend_register_internal_class_ex(&ce_period, NULL, NULL TSRMLS_CC);
2032 	date_ce_period->get_iterator = date_object_period_get_iterator;
2033 	date_ce_period->iterator_funcs.funcs = &date_period_it_funcs;
2034 	zend_class_implements(date_ce_period TSRMLS_CC, 1, zend_ce_traversable);
2035 	memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2036 	date_object_handlers_period.clone_obj = date_object_clone_period;
2037 	date_object_handlers_period.get_properties = date_object_get_properties_period;
2038 	date_object_handlers_period.get_property_ptr_ptr = NULL;
2039 	date_object_handlers_period.read_property = date_period_read_property;
2040 	date_object_handlers_period.write_property = date_period_write_property;
2041 
2042 #define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \
2043 	zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value TSRMLS_CC);
2044 
2045 	REGISTER_PERIOD_CLASS_CONST_STRING("EXCLUDE_START_DATE", PHP_DATE_PERIOD_EXCLUDE_START_DATE);
2046 }
2047 
date_object_new_date_ex(zend_class_entry * class_type,php_date_obj ** ptr TSRMLS_DC)2048 static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
2049 {
2050 	php_date_obj *intern;
2051 	zend_object_value retval;
2052 	zval *tmp;
2053 
2054 	intern = emalloc(sizeof(php_date_obj));
2055 	memset(intern, 0, sizeof(php_date_obj));
2056 	if (ptr) {
2057 		*ptr = intern;
2058 	}
2059 
2060 	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2061 	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_property_ctor, (void *) &tmp, sizeof(zval *));
2062 
2063 	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_date, NULL TSRMLS_CC);
2064 	retval.handlers = &date_object_handlers_date;
2065 
2066 	return retval;
2067 }
2068 
date_object_new_date(zend_class_entry * class_type TSRMLS_DC)2069 static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC)
2070 {
2071 	return date_object_new_date_ex(class_type, NULL TSRMLS_CC);
2072 }
2073 
date_object_clone_date(zval * this_ptr TSRMLS_DC)2074 static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
2075 {
2076 	php_date_obj *new_obj = NULL;
2077 	php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2078 	zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2079 
2080 	zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2081 	if (!old_obj->time) {
2082 		return new_ov;
2083 	}
2084 
2085 	/* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
2086 	new_obj->time = timelib_time_ctor();
2087 	*new_obj->time = *old_obj->time;
2088 	if (old_obj->time->tz_abbr) {
2089 		new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
2090 	}
2091 	if (old_obj->time->tz_info) {
2092 		new_obj->time->tz_info = old_obj->time->tz_info;
2093 	}
2094 
2095 	return new_ov;
2096 }
2097 
date_object_compare_date(zval * d1,zval * d2 TSRMLS_DC)2098 static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC)
2099 {
2100 	if (Z_TYPE_P(d1) == IS_OBJECT && Z_TYPE_P(d2) == IS_OBJECT &&
2101 		instanceof_function(Z_OBJCE_P(d1), date_ce_date TSRMLS_CC) &&
2102 		instanceof_function(Z_OBJCE_P(d2), date_ce_date TSRMLS_CC)) {
2103 		php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC);
2104 		php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC);
2105 
2106 		if (!o1->time || !o2->time) {
2107 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to compare an incomplete DateTime object");
2108 			return 1;
2109 		}
2110 		if (!o1->time->sse_uptodate) {
2111 			timelib_update_ts(o1->time, o1->time->tz_info);
2112 		}
2113 		if (!o2->time->sse_uptodate) {
2114 			timelib_update_ts(o2->time, o2->time->tz_info);
2115 		}
2116 
2117 		return (o1->time->sse == o2->time->sse) ? 0 : ((o1->time->sse < o2->time->sse) ? -1 : 1);
2118 	}
2119 
2120 	return 1;
2121 }
2122 
date_object_get_properties(zval * object TSRMLS_DC)2123 static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
2124 {
2125 	HashTable *props;
2126 	zval *zv;
2127 	php_date_obj     *dateobj;
2128 
2129 
2130 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2131 
2132 	props = zend_std_get_properties(object TSRMLS_CC);
2133 
2134 	if (!dateobj->time || GC_G(gc_active)) {
2135 		return props;
2136 	}
2137 
2138 	/* first we add the date and time in ISO format */
2139 	MAKE_STD_ZVAL(zv);
2140 	ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, dateobj->time, 1), 0);
2141 	zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL);
2142 
2143 	/* then we add the timezone name (or similar) */
2144 	if (dateobj->time->is_localtime) {
2145 		MAKE_STD_ZVAL(zv);
2146 		ZVAL_LONG(zv, dateobj->time->zone_type);
2147 		zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zval), NULL);
2148 
2149 		MAKE_STD_ZVAL(zv);
2150 		switch (dateobj->time->zone_type) {
2151 			case TIMELIB_ZONETYPE_ID:
2152 				ZVAL_STRING(zv, dateobj->time->tz_info->name, 1);
2153 				break;
2154 			case TIMELIB_ZONETYPE_OFFSET: {
2155 				char *tmpstr = emalloc(sizeof("UTC+05:00"));
2156 				timelib_sll utc_offset = dateobj->time->z;
2157 
2158 				snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
2159 					utc_offset > 0 ? '-' : '+',
2160 					abs(utc_offset / 60),
2161 					abs((utc_offset % 60)));
2162 
2163 				ZVAL_STRING(zv, tmpstr, 0);
2164 				}
2165 				break;
2166 			case TIMELIB_ZONETYPE_ABBR:
2167 				ZVAL_STRING(zv, dateobj->time->tz_abbr, 1);
2168 				break;
2169 		}
2170 		zend_hash_update(props, "timezone", 9, &zv, sizeof(zval), NULL);
2171 	}
2172 
2173 	return props;
2174 }
2175 
date_object_new_timezone_ex(zend_class_entry * class_type,php_timezone_obj ** ptr TSRMLS_DC)2176 static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC)
2177 {
2178 	php_timezone_obj *intern;
2179 	zend_object_value retval;
2180 	zval *tmp;
2181 
2182 	intern = emalloc(sizeof(php_timezone_obj));
2183 	memset(intern, 0, sizeof(php_timezone_obj));
2184 	if (ptr) {
2185 		*ptr = intern;
2186 	}
2187 
2188 	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2189 	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_property_ctor, (void *) &tmp, sizeof(zval *));
2190 
2191 	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_timezone, NULL TSRMLS_CC);
2192 	retval.handlers = &date_object_handlers_timezone;
2193 
2194 	return retval;
2195 }
2196 
date_object_new_timezone(zend_class_entry * class_type TSRMLS_DC)2197 static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC)
2198 {
2199 	return date_object_new_timezone_ex(class_type, NULL TSRMLS_CC);
2200 }
2201 
date_object_clone_timezone(zval * this_ptr TSRMLS_DC)2202 static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
2203 {
2204 	php_timezone_obj *new_obj = NULL;
2205 	php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2206 	zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2207 
2208 	zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2209 	if (!old_obj->initialized) {
2210 		return new_ov;
2211 	}
2212 
2213 	new_obj->type = old_obj->type;
2214 	new_obj->initialized = 1;
2215 	switch (new_obj->type) {
2216 		case TIMELIB_ZONETYPE_ID:
2217 			new_obj->tzi.tz = old_obj->tzi.tz;
2218 			break;
2219 		case TIMELIB_ZONETYPE_OFFSET:
2220 			new_obj->tzi.utc_offset = old_obj->tzi.utc_offset;
2221 			break;
2222 		case TIMELIB_ZONETYPE_ABBR:
2223 			new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset;
2224 			new_obj->tzi.z.dst        = old_obj->tzi.z.dst;
2225 			new_obj->tzi.z.abbr       = old_obj->tzi.z.abbr;
2226 			break;
2227 	}
2228 
2229 	return new_ov;
2230 }
2231 
date_object_new_interval_ex(zend_class_entry * class_type,php_interval_obj ** ptr TSRMLS_DC)2232 static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC)
2233 {
2234 	php_interval_obj *intern;
2235 	zend_object_value retval;
2236 	zval *tmp;
2237 
2238 	intern = emalloc(sizeof(php_interval_obj));
2239 	memset(intern, 0, sizeof(php_interval_obj));
2240 	if (ptr) {
2241 		*ptr = intern;
2242 	}
2243 
2244 	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2245 	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_property_ctor, (void *) &tmp, sizeof(zval *));
2246 
2247 	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_interval, NULL TSRMLS_CC);
2248 	retval.handlers = &date_object_handlers_interval;
2249 
2250 	return retval;
2251 }
2252 
date_object_new_interval(zend_class_entry * class_type TSRMLS_DC)2253 static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC)
2254 {
2255 	return date_object_new_interval_ex(class_type, NULL TSRMLS_CC);
2256 }
2257 
date_object_clone_interval(zval * this_ptr TSRMLS_DC)2258 static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC)
2259 {
2260 	php_interval_obj *new_obj = NULL;
2261 	php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2262 	zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2263 
2264 	zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2265 
2266 	/** FIX ME ADD CLONE STUFF **/
2267 	return new_ov;
2268 }
2269 
date_object_get_properties_interval(zval * object TSRMLS_DC)2270 static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
2271 {
2272 	HashTable *props;
2273 	zval *zv;
2274 	php_interval_obj     *intervalobj;
2275 
2276 	intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
2277 
2278 	props = zend_std_get_properties(object TSRMLS_CC);
2279 
2280 	if (!intervalobj->initialized || GC_G(gc_active)) {
2281 		return props;
2282 	}
2283 
2284 #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \
2285 	MAKE_STD_ZVAL(zv); \
2286 	ZVAL_LONG(zv, (long)intervalobj->diff->f); \
2287 	zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zval), NULL);
2288 
2289 	PHP_DATE_INTERVAL_ADD_PROPERTY("y", y);
2290 	PHP_DATE_INTERVAL_ADD_PROPERTY("m", m);
2291 	PHP_DATE_INTERVAL_ADD_PROPERTY("d", d);
2292 	PHP_DATE_INTERVAL_ADD_PROPERTY("h", h);
2293 	PHP_DATE_INTERVAL_ADD_PROPERTY("i", i);
2294 	PHP_DATE_INTERVAL_ADD_PROPERTY("s", s);
2295 	PHP_DATE_INTERVAL_ADD_PROPERTY("weekday", weekday);
2296 	PHP_DATE_INTERVAL_ADD_PROPERTY("weekday_behavior", weekday_behavior);
2297 	PHP_DATE_INTERVAL_ADD_PROPERTY("first_last_day_of", first_last_day_of);
2298 	PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
2299 	if (intervalobj->diff->days != -99999) {
2300 		PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
2301 	} else {
2302 		MAKE_STD_ZVAL(zv);
2303 		ZVAL_FALSE(zv);
2304 		zend_hash_update(props, "days", 5, &zv, sizeof(zval), NULL);
2305 	}
2306 	PHP_DATE_INTERVAL_ADD_PROPERTY("special_type", special.type);
2307 	PHP_DATE_INTERVAL_ADD_PROPERTY("special_amount", special.amount);
2308 	PHP_DATE_INTERVAL_ADD_PROPERTY("have_weekday_relative", have_weekday_relative);
2309 	PHP_DATE_INTERVAL_ADD_PROPERTY("have_special_relative", have_special_relative);
2310 
2311 	return props;
2312 }
2313 
date_object_new_period_ex(zend_class_entry * class_type,php_period_obj ** ptr TSRMLS_DC)2314 static inline zend_object_value date_object_new_period_ex(zend_class_entry *class_type, php_period_obj **ptr TSRMLS_DC)
2315 {
2316 	php_period_obj *intern;
2317 	zend_object_value retval;
2318 	zval *tmp;
2319 
2320 	intern = emalloc(sizeof(php_period_obj));
2321 	memset(intern, 0, sizeof(php_period_obj));
2322 	if (ptr) {
2323 		*ptr = intern;
2324 	}
2325 
2326 	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
2327 	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_property_ctor, (void *) &tmp, sizeof(zval *));
2328 
2329 	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_period, NULL TSRMLS_CC);
2330 	retval.handlers = &date_object_handlers_period;
2331 
2332 	return retval;
2333 }
2334 
date_object_new_period(zend_class_entry * class_type TSRMLS_DC)2335 static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC)
2336 {
2337 	return date_object_new_period_ex(class_type, NULL TSRMLS_CC);
2338 }
2339 
date_object_clone_period(zval * this_ptr TSRMLS_DC)2340 static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC)
2341 {
2342 	php_period_obj *new_obj = NULL;
2343 	php_period_obj *old_obj = (php_period_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
2344 	zend_object_value new_ov = date_object_new_period_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
2345 
2346 	zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
2347 
2348 	/** FIX ME ADD CLONE STUFF **/
2349 	return new_ov;
2350 }
2351 
date_object_free_storage_date(void * object TSRMLS_DC)2352 static void date_object_free_storage_date(void *object TSRMLS_DC)
2353 {
2354 	php_date_obj *intern = (php_date_obj *)object;
2355 
2356 	if (intern->time) {
2357 		timelib_time_dtor(intern->time);
2358 	}
2359 
2360 	zend_object_std_dtor(&intern->std TSRMLS_CC);
2361 	efree(object);
2362 }
2363 
date_object_free_storage_timezone(void * object TSRMLS_DC)2364 static void date_object_free_storage_timezone(void *object TSRMLS_DC)
2365 {
2366 	php_timezone_obj *intern = (php_timezone_obj *)object;
2367 
2368 	if (intern->type == TIMELIB_ZONETYPE_ABBR) {
2369 		free(intern->tzi.z.abbr);
2370 	}
2371 	zend_object_std_dtor(&intern->std TSRMLS_CC);
2372 	efree(object);
2373 }
2374 
date_object_free_storage_interval(void * object TSRMLS_DC)2375 static void date_object_free_storage_interval(void *object TSRMLS_DC)
2376 {
2377 	php_interval_obj *intern = (php_interval_obj *)object;
2378 
2379 	timelib_rel_time_dtor(intern->diff);
2380 	zend_object_std_dtor(&intern->std TSRMLS_CC);
2381 	efree(object);
2382 }
2383 
date_object_free_storage_period(void * object TSRMLS_DC)2384 static void date_object_free_storage_period(void *object TSRMLS_DC)
2385 {
2386 	php_period_obj *intern = (php_period_obj *)object;
2387 
2388 	if (intern->start) {
2389 		timelib_time_dtor(intern->start);
2390 	}
2391 
2392 	if (intern->current) {
2393 		timelib_time_dtor(intern->current);
2394 	}
2395 
2396 	if (intern->end) {
2397 		timelib_time_dtor(intern->end);
2398 	}
2399 
2400 	timelib_rel_time_dtor(intern->interval);
2401 	zend_object_std_dtor(&intern->std TSRMLS_CC);
2402 	efree(object);
2403 }
2404 
2405 /* Advanced Interface */
php_date_instantiate(zend_class_entry * pce,zval * object TSRMLS_DC)2406 PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
2407 {
2408 	Z_TYPE_P(object) = IS_OBJECT;
2409 	object_init_ex(object, pce);
2410 	Z_SET_REFCOUNT_P(object, 1);
2411 	Z_UNSET_ISREF_P(object);
2412 
2413 	return object;
2414 }
2415 
2416 /* Helper function used to store the latest found warnings and errors while
2417  * parsing, from either strtotime or parse_from_format. */
update_errors_warnings(timelib_error_container * last_errors TSRMLS_DC)2418 static void update_errors_warnings(timelib_error_container *last_errors TSRMLS_DC)
2419 {
2420 	if (DATEG(last_errors)) {
2421 		timelib_error_container_dtor(DATEG(last_errors));
2422 		DATEG(last_errors) = NULL;
2423 	}
2424 	DATEG(last_errors) = last_errors;
2425 }
2426 
php_date_initialize(php_date_obj * dateobj,char * time_str,int time_str_len,char * format,zval * timezone_object,int ctor TSRMLS_DC)2427 PHPAPI int php_date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, char *format, zval *timezone_object, int ctor TSRMLS_DC)
2428 {
2429 	timelib_time   *now;
2430 	timelib_tzinfo *tzi = NULL;
2431 	timelib_error_container *err = NULL;
2432 	int type = TIMELIB_ZONETYPE_ID, new_dst;
2433 	char *new_abbr;
2434 	timelib_sll     new_offset;
2435 
2436 	if (dateobj->time) {
2437 		timelib_time_dtor(dateobj->time);
2438 	}
2439 	if (format) {
2440 		dateobj->time = timelib_parse_from_format(format, time_str_len ? time_str : "", time_str_len ? time_str_len : 0, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
2441 	} else {
2442 		dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
2443 	}
2444 
2445 	/* update last errors and warnings */
2446 	update_errors_warnings(err TSRMLS_CC);
2447 
2448 
2449 	if (ctor && err && err->error_count) {
2450 		/* spit out the first library error message, at least */
2451 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
2452 			err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
2453 	}
2454 	if (err && err->error_count) {
2455 		return 0;
2456 	}
2457 
2458 	if (timezone_object) {
2459 		php_timezone_obj *tzobj;
2460 
2461 		tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
2462 		switch (tzobj->type) {
2463 			case TIMELIB_ZONETYPE_ID:
2464 				tzi = tzobj->tzi.tz;
2465 				break;
2466 			case TIMELIB_ZONETYPE_OFFSET:
2467 				new_offset = tzobj->tzi.utc_offset;
2468 				break;
2469 			case TIMELIB_ZONETYPE_ABBR:
2470 				new_offset = tzobj->tzi.z.utc_offset;
2471 				new_dst    = tzobj->tzi.z.dst;
2472 				new_abbr   = strdup(tzobj->tzi.z.abbr);
2473 				break;
2474 		}
2475 		type = tzobj->type;
2476 	} else if (dateobj->time->tz_info) {
2477 		tzi = dateobj->time->tz_info;
2478 	} else {
2479 		tzi = get_timezone_info(TSRMLS_C);
2480 	}
2481 
2482 	now = timelib_time_ctor();
2483 	now->zone_type = type;
2484 	switch (type) {
2485 		case TIMELIB_ZONETYPE_ID:
2486 			now->tz_info = tzi;
2487 			break;
2488 		case TIMELIB_ZONETYPE_OFFSET:
2489 			now->z = new_offset;
2490 			break;
2491 		case TIMELIB_ZONETYPE_ABBR:
2492 			now->z = new_offset;
2493 			now->dst = new_dst;
2494 			now->tz_abbr = new_abbr;
2495 			break;
2496 	}
2497 	timelib_unixtime2local(now, (timelib_sll) time(NULL));
2498 
2499 	timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
2500 	timelib_update_ts(dateobj->time, tzi);
2501 
2502 	dateobj->time->have_relative = 0;
2503 
2504 	timelib_time_dtor(now);
2505 
2506 	return 1;
2507 }
2508 
2509 /* {{{ proto DateTime date_create([string time[, DateTimeZone object]])
2510    Returns new DateTime object
2511 */
PHP_FUNCTION(date_create)2512 PHP_FUNCTION(date_create)
2513 {
2514 	zval           *timezone_object = NULL;
2515 	char           *time_str = NULL;
2516 	int             time_str_len = 0;
2517 
2518 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
2519 		RETURN_FALSE;
2520 	}
2521 
2522 	php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
2523 	if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 0 TSRMLS_CC)) {
2524 		RETURN_FALSE;
2525 	}
2526 }
2527 /* }}} */
2528 
2529 /* {{{ proto DateTime date_create_from_format(string format, string time[, DateTimeZone object])
2530    Returns new DateTime object formatted according to the specified format
2531 */
PHP_FUNCTION(date_create_from_format)2532 PHP_FUNCTION(date_create_from_format)
2533 {
2534 	zval           *timezone_object = NULL;
2535 	char           *time_str = NULL, *format_str = NULL;
2536 	int             time_str_len = 0, format_str_len = 0;
2537 
2538 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|O", &format_str, &format_str_len, &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
2539 		RETURN_FALSE;
2540 	}
2541 
2542 	php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
2543 	if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, format_str, timezone_object, 0 TSRMLS_CC)) {
2544 		RETURN_FALSE;
2545 	}
2546 }
2547 /* }}} */
2548 
2549 /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
2550    Creates new DateTime object
2551 */
PHP_METHOD(DateTime,__construct)2552 PHP_METHOD(DateTime, __construct)
2553 {
2554 	zval *timezone_object = NULL;
2555 	char *time_str = NULL;
2556 	int time_str_len = 0;
2557 	zend_error_handling error_handling;
2558 
2559 	zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
2560 	if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
2561 		php_date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC);
2562 	}
2563 	zend_restore_error_handling(&error_handling TSRMLS_CC);
2564 }
2565 /* }}} */
2566 
php_date_initialize_from_hash(zval ** return_value,php_date_obj ** dateobj,HashTable * myht TSRMLS_DC)2567 static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC)
2568 {
2569 	zval            **z_date = NULL;
2570 	zval            **z_timezone = NULL;
2571 	zval            **z_timezone_type = NULL;
2572 	zval             *tmp_obj = NULL;
2573 	timelib_tzinfo   *tzi;
2574 	php_timezone_obj *tzobj;
2575 
2576 	if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) {
2577 		convert_to_string(*z_date);
2578 		if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) {
2579 			convert_to_long(*z_timezone_type);
2580 			if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) {
2581 				convert_to_string(*z_timezone);
2582 
2583 				switch (Z_LVAL_PP(z_timezone_type)) {
2584 					case TIMELIB_ZONETYPE_OFFSET:
2585 					case TIMELIB_ZONETYPE_ABBR: {
2586 						char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2);
2587 						int ret;
2588 						snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone));
2589 						ret = php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC);
2590 						efree(tmp);
2591 						return 1 == ret;
2592 					}
2593 
2594 					case TIMELIB_ZONETYPE_ID: {
2595 						int ret;
2596 						convert_to_string(*z_timezone);
2597 
2598 						tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC);
2599 
2600 						ALLOC_INIT_ZVAL(tmp_obj);
2601 						tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC);
2602 						tzobj->type = TIMELIB_ZONETYPE_ID;
2603 						tzobj->tzi.tz = tzi;
2604 						tzobj->initialized = 1;
2605 
2606 						ret = php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC);
2607 						zval_ptr_dtor(&tmp_obj);
2608 						return 1 == ret;
2609 					}
2610 				}
2611 			}
2612 		}
2613 	}
2614 	return 0;
2615 }
2616 
2617 /* {{{ proto DateTime::__set_state()
2618 */
PHP_METHOD(DateTime,__set_state)2619 PHP_METHOD(DateTime, __set_state)
2620 {
2621 	php_date_obj     *dateobj;
2622 	zval             *array;
2623 	HashTable        *myht;
2624 
2625 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
2626 		RETURN_FALSE;
2627 	}
2628 
2629 	myht = HASH_OF(array);
2630 
2631 	php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
2632 	dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
2633 	if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
2634 		php_error(E_ERROR, "Invalid serialization data for DateTime object");
2635 	}
2636 }
2637 /* }}} */
2638 
2639 /* {{{ proto DateTime::__wakeup()
2640 */
PHP_METHOD(DateTime,__wakeup)2641 PHP_METHOD(DateTime, __wakeup)
2642 {
2643 	zval             *object = getThis();
2644 	php_date_obj     *dateobj;
2645 	HashTable        *myht;
2646 
2647 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2648 
2649 	myht = Z_OBJPROP_P(object);
2650 
2651 	if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
2652 		php_error(E_ERROR, "Invalid serialization data for DateTime object");
2653 	}
2654 }
2655 /* }}} */
2656 
2657 /* Helper function used to add an associative array of warnings and errors to a zval */
zval_from_error_container(zval * z,timelib_error_container * error)2658 static void zval_from_error_container(zval *z, timelib_error_container *error)
2659 {
2660 	int   i;
2661 	zval *element;
2662 
2663 	add_assoc_long(z, "warning_count", error->warning_count);
2664 	MAKE_STD_ZVAL(element);
2665 	array_init(element);
2666 	for (i = 0; i < error->warning_count; i++) {
2667 		add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
2668 	}
2669 	add_assoc_zval(z, "warnings", element);
2670 
2671 	add_assoc_long(z, "error_count", error->error_count);
2672 	MAKE_STD_ZVAL(element);
2673 	array_init(element);
2674 	for (i = 0; i < error->error_count; i++) {
2675 		add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
2676 	}
2677 	add_assoc_zval(z, "errors", element);
2678 }
2679 
2680 /* {{{ proto array date_get_last_errors()
2681    Returns the warnings and errors found while parsing a date/time string.
2682 */
PHP_FUNCTION(date_get_last_errors)2683 PHP_FUNCTION(date_get_last_errors)
2684 {
2685 	if (DATEG(last_errors)) {
2686 		array_init(return_value);
2687 		zval_from_error_container(return_value, DATEG(last_errors));
2688 	} else {
2689 		RETURN_FALSE;
2690 	}
2691 }
2692 /* }}} */
2693 
php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS,timelib_time * parsed_time,struct timelib_error_container * error)2694 void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, struct timelib_error_container *error)
2695 {
2696 	zval *element;
2697 
2698 	array_init(return_value);
2699 #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
2700 	if (parsed_time->elem == -99999) {               \
2701 		add_assoc_bool(return_value, #name, 0); \
2702 	} else {                                       \
2703 		add_assoc_long(return_value, #name, parsed_time->elem); \
2704 	}
2705 	PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year,      y);
2706 	PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month,     m);
2707 	PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day,       d);
2708 	PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour,      h);
2709 	PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute,    i);
2710 	PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second,    s);
2711 
2712 	if (parsed_time->f == -99999) {
2713 		add_assoc_bool(return_value, "fraction", 0);
2714 	} else {
2715 		add_assoc_double(return_value, "fraction", parsed_time->f);
2716 	}
2717 
2718 	zval_from_error_container(return_value, error);
2719 
2720 	timelib_error_container_dtor(error);
2721 
2722 	add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
2723 
2724 	if (parsed_time->is_localtime) {
2725 		PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
2726 		switch (parsed_time->zone_type) {
2727 			case TIMELIB_ZONETYPE_OFFSET:
2728 				PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
2729 				add_assoc_bool(return_value, "is_dst", parsed_time->dst);
2730 				break;
2731 			case TIMELIB_ZONETYPE_ID:
2732 				if (parsed_time->tz_abbr) {
2733 					add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
2734 				}
2735 				if (parsed_time->tz_info) {
2736 					add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
2737 				}
2738 				break;
2739 			case TIMELIB_ZONETYPE_ABBR:
2740 				PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
2741 				add_assoc_bool(return_value, "is_dst", parsed_time->dst);
2742 				add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
2743 				break;
2744 		}
2745 	}
2746 	if (parsed_time->have_relative) {
2747 		MAKE_STD_ZVAL(element);
2748 		array_init(element);
2749 		add_assoc_long(element, "year",   parsed_time->relative.y);
2750 		add_assoc_long(element, "month",  parsed_time->relative.m);
2751 		add_assoc_long(element, "day",    parsed_time->relative.d);
2752 		add_assoc_long(element, "hour",   parsed_time->relative.h);
2753 		add_assoc_long(element, "minute", parsed_time->relative.i);
2754 		add_assoc_long(element, "second", parsed_time->relative.s);
2755 		if (parsed_time->relative.have_weekday_relative) {
2756 			add_assoc_long(element, "weekday", parsed_time->relative.weekday);
2757 		}
2758 		if (parsed_time->relative.have_special_relative && (parsed_time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY)) {
2759 			add_assoc_long(element, "weekdays", parsed_time->relative.special.amount);
2760 		}
2761 		if (parsed_time->relative.first_last_day_of) {
2762 			add_assoc_bool(element, parsed_time->relative.first_last_day_of == 1 ? "first_day_of_month" : "last_day_of_month", 1);
2763 		}
2764 		add_assoc_zval(return_value, "relative", element);
2765 	}
2766 	timelib_time_dtor(parsed_time);
2767 }
2768 
2769 /* {{{ proto array date_parse(string date)
2770    Returns associative array with detailed info about given date
2771 */
PHP_FUNCTION(date_parse)2772 PHP_FUNCTION(date_parse)
2773 {
2774 	char                           *date;
2775 	int                             date_len;
2776 	struct timelib_error_container *error;
2777 	timelib_time                   *parsed_time;
2778 
2779 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
2780 		RETURN_FALSE;
2781 	}
2782 
2783 	parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
2784 	php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
2785 }
2786 /* }}} */
2787 
2788 /* {{{ proto array date_parse_from_format(string format, string date)
2789    Returns associative array with detailed info about given date
2790 */
PHP_FUNCTION(date_parse_from_format)2791 PHP_FUNCTION(date_parse_from_format)
2792 {
2793 	char                           *date, *format;
2794 	int                             date_len, format_len;
2795 	struct timelib_error_container *error;
2796 	timelib_time                   *parsed_time;
2797 
2798 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, &format_len, &date, &date_len) == FAILURE) {
2799 		RETURN_FALSE;
2800 	}
2801 
2802 	parsed_time = timelib_parse_from_format(format, date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
2803 	php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
2804 }
2805 /* }}} */
2806 
2807 /* {{{ proto string date_format(DateTime object, string format)
2808    Returns date formatted according to given format
2809 */
PHP_FUNCTION(date_format)2810 PHP_FUNCTION(date_format)
2811 {
2812 	zval         *object;
2813 	php_date_obj *dateobj;
2814 	char         *format;
2815 	int           format_len;
2816 
2817 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
2818 		RETURN_FALSE;
2819 	}
2820 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2821 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2822 	RETURN_STRING(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime), 0);
2823 }
2824 /* }}} */
2825 
2826 /* {{{ proto DateTime date_modify(DateTime object, string modify)
2827    Alters the timestamp.
2828 */
PHP_FUNCTION(date_modify)2829 PHP_FUNCTION(date_modify)
2830 {
2831 	zval         *object;
2832 	php_date_obj *dateobj;
2833 	char         *modify;
2834 	int           modify_len;
2835 	timelib_time *tmp_time;
2836 	timelib_error_container *err = NULL;
2837 
2838 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
2839 		RETURN_FALSE;
2840 	}
2841 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2842 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2843 
2844 	tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
2845 
2846 	/* update last errors and warnings */
2847 	update_errors_warnings(err TSRMLS_CC);
2848 	if (err && err->error_count) {
2849 		/* spit out the first library error message, at least */
2850 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify,
2851 			err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
2852 		timelib_time_dtor(tmp_time);
2853 		RETURN_FALSE;
2854 	}
2855 
2856 	memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
2857 	dateobj->time->have_relative = tmp_time->have_relative;
2858 	dateobj->time->sse_uptodate = 0;
2859 
2860 	if (tmp_time->y != -99999) {
2861 		dateobj->time->y = tmp_time->y;
2862 	}
2863 	if (tmp_time->m != -99999) {
2864 		dateobj->time->m = tmp_time->m;
2865 	}
2866 	if (tmp_time->d != -99999) {
2867 		dateobj->time->d = tmp_time->d;
2868 	}
2869 
2870 	if (tmp_time->h != -99999) {
2871 		dateobj->time->h = tmp_time->h;
2872 		if (tmp_time->i != -99999) {
2873 			dateobj->time->i = tmp_time->i;
2874 			if (tmp_time->s != -99999) {
2875 				dateobj->time->s = tmp_time->s;
2876 			} else {
2877 				dateobj->time->s = 0;
2878 			}
2879 		} else {
2880 			dateobj->time->i = 0;
2881 			dateobj->time->s = 0;
2882 		}
2883 	}
2884 	timelib_time_dtor(tmp_time);
2885 
2886 	timelib_update_ts(dateobj->time, NULL);
2887 	timelib_update_from_sse(dateobj->time);
2888 	dateobj->time->have_relative = 0;
2889 
2890 	RETURN_ZVAL(object, 1, 0);
2891 }
2892 /* }}} */
2893 
2894 /* {{{ proto DateTime date_add(DateTime object, DateInterval interval)
2895    Adds an interval to the current date in object.
2896 */
PHP_FUNCTION(date_add)2897 PHP_FUNCTION(date_add)
2898 {
2899 	zval         *object, *interval;
2900 	php_date_obj *dateobj;
2901 	php_interval_obj *intobj;
2902 	int               bias = 1;
2903 
2904 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
2905 		RETURN_FALSE;
2906 	}
2907 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2908 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2909 	intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
2910 	DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
2911 
2912 
2913 	if (intobj->diff->have_weekday_relative || intobj->diff->have_special_relative) {
2914 		memcpy(&dateobj->time->relative, intobj->diff, sizeof(struct timelib_rel_time));
2915 	} else {
2916 		if (intobj->diff->invert) {
2917 			bias = -1;
2918 		}
2919 		memset(&dateobj->time->relative, 0, sizeof(struct timelib_rel_time));
2920 		dateobj->time->relative.y = intobj->diff->y * bias;
2921 		dateobj->time->relative.m = intobj->diff->m * bias;
2922 		dateobj->time->relative.d = intobj->diff->d * bias;
2923 		dateobj->time->relative.h = intobj->diff->h * bias;
2924 		dateobj->time->relative.i = intobj->diff->i * bias;
2925 		dateobj->time->relative.s = intobj->diff->s * bias;
2926 	}
2927 	dateobj->time->have_relative = 1;
2928 	dateobj->time->sse_uptodate = 0;
2929 
2930 	timelib_update_ts(dateobj->time, NULL);
2931 	timelib_update_from_sse(dateobj->time);
2932 	dateobj->time->have_relative = 0;
2933 
2934 	RETURN_ZVAL(object, 1, 0);
2935 }
2936 /* }}} */
2937 
2938 /* {{{ proto DateTime date_sub(DateTime object, DateInterval interval)
2939    Subtracts an interval to the current date in object.
2940 */
PHP_FUNCTION(date_sub)2941 PHP_FUNCTION(date_sub)
2942 {
2943 	zval         *object, *interval;
2944 	php_date_obj *dateobj;
2945 	php_interval_obj *intobj;
2946 	int               bias = 1;
2947 
2948 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
2949 		RETURN_FALSE;
2950 	}
2951 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2952 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2953 	intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
2954 	DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
2955 
2956 	if (intobj->diff->have_special_relative) {
2957 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only non-special relative time specifications are supported for subtraction");
2958 		return;
2959 	}
2960 
2961 	if (intobj->diff->invert) {
2962 		bias = -1;
2963 	}
2964 
2965 	memset(&dateobj->time->relative, 0, sizeof(struct timelib_rel_time));
2966 	dateobj->time->relative.y = 0 - (intobj->diff->y * bias);
2967 	dateobj->time->relative.m = 0 - (intobj->diff->m * bias);
2968 	dateobj->time->relative.d = 0 - (intobj->diff->d * bias);
2969 	dateobj->time->relative.h = 0 - (intobj->diff->h * bias);
2970 	dateobj->time->relative.i = 0 - (intobj->diff->i * bias);
2971 	dateobj->time->relative.s = 0 - (intobj->diff->s * bias);
2972 	dateobj->time->have_relative = 1;
2973 	dateobj->time->sse_uptodate = 0;
2974 
2975 	timelib_update_ts(dateobj->time, NULL);
2976 	timelib_update_from_sse(dateobj->time);
2977 
2978 	dateobj->time->have_relative = 0;
2979 
2980 	RETURN_ZVAL(object, 1, 0);
2981 }
2982 /* }}} */
2983 
2984 /* {{{ proto DateTimeZone date_timezone_get(DateTime object)
2985    Return new DateTimeZone object relative to give DateTime
2986 */
PHP_FUNCTION(date_timezone_get)2987 PHP_FUNCTION(date_timezone_get)
2988 {
2989 	zval             *object;
2990 	php_date_obj     *dateobj;
2991 	php_timezone_obj *tzobj;
2992 
2993 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
2994 		RETURN_FALSE;
2995 	}
2996 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2997 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2998 	if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
2999 		php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
3000 		tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
3001 		tzobj->initialized = 1;
3002 		tzobj->type = dateobj->time->zone_type;
3003 		switch (dateobj->time->zone_type) {
3004 			case TIMELIB_ZONETYPE_ID:
3005 				tzobj->tzi.tz = dateobj->time->tz_info;
3006 				break;
3007 			case TIMELIB_ZONETYPE_OFFSET:
3008 				tzobj->tzi.utc_offset = dateobj->time->z;
3009 				break;
3010 			case TIMELIB_ZONETYPE_ABBR:
3011 				tzobj->tzi.z.utc_offset = dateobj->time->z;
3012 				tzobj->tzi.z.dst = dateobj->time->dst;
3013 				tzobj->tzi.z.abbr = strdup(dateobj->time->tz_abbr);
3014 				break;
3015 		}
3016 	} else {
3017 		RETURN_FALSE;
3018 	}
3019 }
3020 /* }}} */
3021 
3022 /* {{{ proto DateTime date_timezone_set(DateTime object, DateTimeZone object)
3023    Sets the timezone for the DateTime object.
3024 */
PHP_FUNCTION(date_timezone_set)3025 PHP_FUNCTION(date_timezone_set)
3026 {
3027 	zval             *object;
3028 	zval             *timezone_object;
3029 	php_date_obj     *dateobj;
3030 	php_timezone_obj *tzobj;
3031 
3032 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
3033 		RETURN_FALSE;
3034 	}
3035 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3036 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3037 	tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
3038 	if (tzobj->type != TIMELIB_ZONETYPE_ID) {
3039 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now");
3040 		return;
3041 	}
3042 	timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
3043 	timelib_unixtime2local(dateobj->time, dateobj->time->sse);
3044 
3045 	RETURN_ZVAL(object, 1, 0);
3046 }
3047 /* }}} */
3048 
3049 /* {{{ proto long date_offset_get(DateTime object)
3050    Returns the DST offset.
3051 */
PHP_FUNCTION(date_offset_get)3052 PHP_FUNCTION(date_offset_get)
3053 {
3054 	zval                *object;
3055 	php_date_obj        *dateobj;
3056 	timelib_time_offset *offset;
3057 
3058 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
3059 		RETURN_FALSE;
3060 	}
3061 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3062 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3063 	if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
3064 		switch (dateobj->time->zone_type) {
3065 			case TIMELIB_ZONETYPE_ID:
3066 				offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
3067 				RETVAL_LONG(offset->offset);
3068 				timelib_time_offset_dtor(offset);
3069 				break;
3070 			case TIMELIB_ZONETYPE_OFFSET:
3071 				RETVAL_LONG(dateobj->time->z * -60);
3072 				break;
3073 			case TIMELIB_ZONETYPE_ABBR:
3074 				RETVAL_LONG((dateobj->time->z - (60 * dateobj->time->dst)) * -60);
3075 				break;
3076 		}
3077 		return;
3078 	} else {
3079 		RETURN_LONG(0);
3080 	}
3081 }
3082 /* }}} */
3083 
3084 /* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second])
3085    Sets the time.
3086 */
PHP_FUNCTION(date_time_set)3087 PHP_FUNCTION(date_time_set)
3088 {
3089 	zval         *object;
3090 	php_date_obj *dateobj;
3091 	long          h, i, s = 0;
3092 
3093 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
3094 		RETURN_FALSE;
3095 	}
3096 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3097 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3098 	dateobj->time->h = h;
3099 	dateobj->time->i = i;
3100 	dateobj->time->s = s;
3101 	timelib_update_ts(dateobj->time, NULL);
3102 
3103 	RETURN_ZVAL(object, 1, 0);
3104 }
3105 /* }}} */
3106 
3107 /* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day)
3108    Sets the date.
3109 */
PHP_FUNCTION(date_date_set)3110 PHP_FUNCTION(date_date_set)
3111 {
3112 	zval         *object;
3113 	php_date_obj *dateobj;
3114 	long          y, m, d;
3115 
3116 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
3117 		RETURN_FALSE;
3118 	}
3119 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3120 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3121 	dateobj->time->y = y;
3122 	dateobj->time->m = m;
3123 	dateobj->time->d = d;
3124 	timelib_update_ts(dateobj->time, NULL);
3125 
3126 	RETURN_ZVAL(object, 1, 0);
3127 }
3128 /* }}} */
3129 
3130 /* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day])
3131    Sets the ISO date.
3132 */
PHP_FUNCTION(date_isodate_set)3133 PHP_FUNCTION(date_isodate_set)
3134 {
3135 	zval         *object;
3136 	php_date_obj *dateobj;
3137 	long          y, w, d = 1;
3138 
3139 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
3140 		RETURN_FALSE;
3141 	}
3142 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3143 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3144 	dateobj->time->y = y;
3145 	dateobj->time->m = 1;
3146 	dateobj->time->d = 1;
3147 	memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative));
3148 	dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
3149 	dateobj->time->have_relative = 1;
3150 
3151 	timelib_update_ts(dateobj->time, NULL);
3152 
3153 	RETURN_ZVAL(object, 1, 0);
3154 }
3155 /* }}} */
3156 
3157 /* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp)
3158    Sets the date and time based on an Unix timestamp.
3159 */
PHP_FUNCTION(date_timestamp_set)3160 PHP_FUNCTION(date_timestamp_set)
3161 {
3162 	zval         *object;
3163 	php_date_obj *dateobj;
3164 	long          timestamp;
3165 
3166 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, &timestamp) == FAILURE) {
3167 		RETURN_FALSE;
3168 	}
3169 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3170 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3171 	timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp);
3172 	timelib_update_ts(dateobj->time, NULL);
3173 
3174 	RETURN_ZVAL(object, 1, 0);
3175 }
3176 /* }}} */
3177 
3178 /* {{{ proto long date_timestamp_get(DateTime object)
3179    Gets the Unix timestamp.
3180 */
PHP_FUNCTION(date_timestamp_get)3181 PHP_FUNCTION(date_timestamp_get)
3182 {
3183 	zval         *object;
3184 	php_date_obj *dateobj;
3185 	long          timestamp;
3186 	int           error;
3187 
3188 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
3189 		RETURN_FALSE;
3190 	}
3191 	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
3192 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3193 	timelib_update_ts(dateobj->time, NULL);
3194 
3195 	timestamp = timelib_date_to_int(dateobj->time, &error);
3196 	if (error) {
3197 		RETURN_FALSE;
3198 	} else {
3199 		RETVAL_LONG(timestamp);
3200 	}
3201 }
3202 /* }}} */
3203 
3204 /* {{{ proto DateInterval date_diff(DateTime object [, bool absolute])
3205    Returns the difference between two DateTime objects.
3206 */
PHP_FUNCTION(date_diff)3207 PHP_FUNCTION(date_diff)
3208 {
3209 	zval         *object1, *object2;
3210 	php_date_obj *dateobj1, *dateobj2;
3211 	php_interval_obj *interval;
3212 	long          absolute = 0;
3213 
3214 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &object1, date_ce_date, &object2, date_ce_date, &absolute) == FAILURE) {
3215 		RETURN_FALSE;
3216 	}
3217 	dateobj1 = (php_date_obj *) zend_object_store_get_object(object1 TSRMLS_CC);
3218 	dateobj2 = (php_date_obj *) zend_object_store_get_object(object2 TSRMLS_CC);
3219 	DATE_CHECK_INITIALIZED(dateobj1->time, DateTime);
3220 	DATE_CHECK_INITIALIZED(dateobj2->time, DateTime);
3221 	timelib_update_ts(dateobj1->time, NULL);
3222 	timelib_update_ts(dateobj2->time, NULL);
3223 
3224 	php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
3225 	interval = zend_object_store_get_object(return_value TSRMLS_CC);
3226 	interval->diff = timelib_diff(dateobj1->time, dateobj2->time);
3227 	if (absolute) {
3228 		interval->diff->invert = 0;
3229 	}
3230 	interval->initialized = 1;
3231 }
3232 /* }}} */
3233 
timezone_initialize(timelib_tzinfo ** tzi,char * tz TSRMLS_DC)3234 static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC)
3235 {
3236 	char *tzid;
3237 
3238 	*tzi = NULL;
3239 
3240 	if ((tzid = timelib_timezone_id_from_abbr(tz, -1, 0))) {
3241 		*tzi = php_date_parse_tzfile(tzid, DATE_TIMEZONEDB TSRMLS_CC);
3242 	} else {
3243 		*tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
3244 	}
3245 
3246 	if (*tzi) {
3247 		return SUCCESS;
3248 	} else {
3249 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", tz);
3250 		return FAILURE;
3251 	}
3252 }
3253 
3254 /* {{{ proto DateTimeZone timezone_open(string timezone)
3255    Returns new DateTimeZone object
3256 */
PHP_FUNCTION(timezone_open)3257 PHP_FUNCTION(timezone_open)
3258 {
3259 	char *tz;
3260 	int   tz_len;
3261 	timelib_tzinfo *tzi = NULL;
3262 	php_timezone_obj *tzobj;
3263 
3264 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) {
3265 		RETURN_FALSE;
3266 	}
3267 	if (SUCCESS != timezone_initialize(&tzi, tz TSRMLS_CC)) {
3268 		RETURN_FALSE;
3269 	}
3270 	tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC) TSRMLS_CC);
3271 	tzobj->type = TIMELIB_ZONETYPE_ID;
3272 	tzobj->tzi.tz = tzi;
3273 	tzobj->initialized = 1;
3274 }
3275 /* }}} */
3276 
3277 /* {{{ proto DateTimeZone::__construct(string timezone)
3278    Creates new DateTimeZone object.
3279 */
PHP_METHOD(DateTimeZone,__construct)3280 PHP_METHOD(DateTimeZone, __construct)
3281 {
3282 	char *tz;
3283 	int tz_len;
3284 	timelib_tzinfo *tzi = NULL;
3285 	php_timezone_obj *tzobj;
3286 	zend_error_handling error_handling;
3287 
3288 	zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
3289 	if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
3290 		if (SUCCESS == timezone_initialize(&tzi, tz TSRMLS_CC)) {
3291 			tzobj = zend_object_store_get_object(getThis() TSRMLS_CC);
3292 			tzobj->type = TIMELIB_ZONETYPE_ID;
3293 			tzobj->tzi.tz = tzi;
3294 			tzobj->initialized = 1;
3295 		} else {
3296 			ZVAL_NULL(getThis());
3297 		}
3298 	}
3299 	zend_restore_error_handling(&error_handling TSRMLS_CC);
3300 }
3301 /* }}} */
3302 
3303 /* {{{ proto string timezone_name_get(DateTimeZone object)
3304    Returns the name of the timezone.
3305 */
PHP_FUNCTION(timezone_name_get)3306 PHP_FUNCTION(timezone_name_get)
3307 {
3308 	zval             *object;
3309 	php_timezone_obj *tzobj;
3310 
3311 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
3312 		RETURN_FALSE;
3313 	}
3314 	tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3315 	DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3316 
3317 	switch (tzobj->type) {
3318 		case TIMELIB_ZONETYPE_ID:
3319 			RETURN_STRING(tzobj->tzi.tz->name, 1);
3320 			break;
3321 		case TIMELIB_ZONETYPE_OFFSET: {
3322 			char *tmpstr = emalloc(sizeof("UTC+05:00"));
3323 			timelib_sll utc_offset = tzobj->tzi.utc_offset;
3324 
3325 			snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
3326 				utc_offset > 0 ? '-' : '+',
3327 				abs(utc_offset / 60),
3328 				abs((utc_offset % 60)));
3329 
3330 			RETURN_STRING(tmpstr, 0);
3331 			}
3332 			break;
3333 		case TIMELIB_ZONETYPE_ABBR:
3334 			RETURN_STRING(tzobj->tzi.z.abbr, 1);
3335 			break;
3336 	}
3337 }
3338 /* }}} */
3339 
3340 /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]])
3341    Returns the timezone name from abbrevation
3342 */
PHP_FUNCTION(timezone_name_from_abbr)3343 PHP_FUNCTION(timezone_name_from_abbr)
3344 {
3345 	char    *abbr;
3346 	char    *tzid;
3347 	int      abbr_len;
3348 	long     gmtoffset = -1;
3349 	long     isdst = -1;
3350 
3351 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
3352 		RETURN_FALSE;
3353 	}
3354 	tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
3355 
3356 	if (tzid) {
3357 		RETURN_STRING(tzid, 1);
3358 	} else {
3359 		RETURN_FALSE;
3360 	}
3361 }
3362 /* }}} */
3363 
3364 /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTime object)
3365    Returns the timezone offset.
3366 */
PHP_FUNCTION(timezone_offset_get)3367 PHP_FUNCTION(timezone_offset_get)
3368 {
3369 	zval                *object, *dateobject;
3370 	php_timezone_obj    *tzobj;
3371 	php_date_obj        *dateobj;
3372 	timelib_time_offset *offset;
3373 
3374 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_date) == FAILURE) {
3375 		RETURN_FALSE;
3376 	}
3377 	tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3378 	DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3379 	dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
3380 	DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
3381 
3382 	switch (tzobj->type) {
3383 		case TIMELIB_ZONETYPE_ID:
3384 			offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
3385 			RETVAL_LONG(offset->offset);
3386 			timelib_time_offset_dtor(offset);
3387 			break;
3388 		case TIMELIB_ZONETYPE_OFFSET:
3389 			RETURN_LONG(tzobj->tzi.utc_offset * -60);
3390 			break;
3391 		case TIMELIB_ZONETYPE_ABBR:
3392 			RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
3393 			break;
3394 	}
3395 }
3396 /* }}} */
3397 
3398 /* {{{ proto array timezone_transitions_get(DateTimeZone object [, long timestamp_begin [, long timestamp_end ]])
3399    Returns numerically indexed array containing associative array for all transitions in the specified range for the timezone.
3400 */
PHP_FUNCTION(timezone_transitions_get)3401 PHP_FUNCTION(timezone_transitions_get)
3402 {
3403 	zval                *object, *element;
3404 	php_timezone_obj    *tzobj;
3405 	unsigned int         i, begin = 0, found;
3406 	long                 timestamp_begin = LONG_MIN, timestamp_end = LONG_MAX;
3407 
3408 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
3409 		RETURN_FALSE;
3410 	}
3411 	tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3412 	DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3413 	if (tzobj->type != TIMELIB_ZONETYPE_ID) {
3414 		RETURN_FALSE;
3415 	}
3416 
3417 #define add_nominal() \
3418 		MAKE_STD_ZVAL(element); \
3419 		array_init(element); \
3420 		add_assoc_long(element, "ts",     timestamp_begin); \
3421 		add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, timestamp_begin, 0 TSRMLS_CC), 0); \
3422 		add_assoc_long(element, "offset", tzobj->tzi.tz->type[0].offset); \
3423 		add_assoc_bool(element, "isdst",  tzobj->tzi.tz->type[0].isdst); \
3424 		add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx], 1); \
3425 		add_next_index_zval(return_value, element);
3426 
3427 #define add(i,ts) \
3428 		MAKE_STD_ZVAL(element); \
3429 		array_init(element); \
3430 		add_assoc_long(element, "ts",     ts); \
3431 		add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0 TSRMLS_CC), 0); \
3432 		add_assoc_long(element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
3433 		add_assoc_bool(element, "isdst",  tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
3434 		add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx], 1); \
3435 		add_next_index_zval(return_value, element);
3436 
3437 #define add_last() add(tzobj->tzi.tz->timecnt - 1, timestamp_begin)
3438 
3439 	array_init(return_value);
3440 
3441 	if (timestamp_begin == LONG_MIN) {
3442 		add_nominal();
3443 		begin = 0;
3444 		found = 1;
3445 	} else {
3446 		begin = 0;
3447 		found = 0;
3448 		if (tzobj->tzi.tz->timecnt > 0) {
3449 			do {
3450 				if (tzobj->tzi.tz->trans[begin] > timestamp_begin) {
3451 					if (begin > 0) {
3452 						add(begin - 1, timestamp_begin);
3453 					} else {
3454 						add_nominal();
3455 					}
3456 					found = 1;
3457 					break;
3458 				}
3459 				begin++;
3460 			} while (begin < tzobj->tzi.tz->timecnt);
3461 		}
3462 	}
3463 
3464 	if (!found) {
3465 		if (tzobj->tzi.tz->timecnt > 0) {
3466 			add_last();
3467 		} else {
3468 			add_nominal();
3469 		}
3470 	} else {
3471 		for (i = begin; i < tzobj->tzi.tz->timecnt; ++i) {
3472 			if (tzobj->tzi.tz->trans[i] < timestamp_end) {
3473 				add(i, tzobj->tzi.tz->trans[i]);
3474 			}
3475 		}
3476 	}
3477 }
3478 /* }}} */
3479 
3480 /* {{{ proto array timezone_location_get()
3481    Returns location information for a timezone, including country code, latitude/longitude and comments
3482 */
PHP_FUNCTION(timezone_location_get)3483 PHP_FUNCTION(timezone_location_get)
3484 {
3485 	zval                *object;
3486 	php_timezone_obj    *tzobj;
3487 
3488 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
3489 		RETURN_FALSE;
3490 	}
3491 	tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
3492 	DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
3493 	if (tzobj->type != TIMELIB_ZONETYPE_ID) {
3494 		RETURN_FALSE;
3495 	}
3496 
3497 	array_init(return_value);
3498 	add_assoc_string(return_value, "country_code", tzobj->tzi.tz->location.country_code, 1);
3499 	add_assoc_double(return_value, "latitude", tzobj->tzi.tz->location.latitude);
3500 	add_assoc_double(return_value, "longitude", tzobj->tzi.tz->location.longitude);
3501 	add_assoc_string(return_value, "comments", tzobj->tzi.tz->location.comments, 1);
3502 }
3503 /* }}} */
3504 
date_interval_initialize(timelib_rel_time ** rt,char * format,int format_length TSRMLS_DC)3505 static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
3506 {
3507 	timelib_time     *b = NULL, *e = NULL;
3508 	timelib_rel_time *p = NULL;
3509 	int               r = 0;
3510 	int               retval = 0;
3511 	struct timelib_error_container *errors;
3512 
3513 	timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
3514 
3515 	if (errors->error_count > 0) {
3516 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
3517 		retval = FAILURE;
3518 	} else {
3519 		if(p) {
3520 			*rt = p;
3521 			retval = SUCCESS;
3522 		} else {
3523 			if(b && e) {
3524 				timelib_update_ts(b, NULL);
3525 				timelib_update_ts(e, NULL);
3526 				*rt = timelib_diff(b, e);
3527 				retval = SUCCESS;
3528 			} else {
3529 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse interval (%s)", format);
3530 				retval = FAILURE;
3531 			}
3532 		}
3533 	}
3534 	timelib_error_container_dtor(errors);
3535 	return retval;
3536 }
3537 
3538 /* {{{ date_interval_read_property */
date_interval_read_property(zval * object,zval * member,int type TSRMLS_DC)3539 zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC)
3540 {
3541 	php_interval_obj *obj;
3542 	zval *retval;
3543 	zval tmp_member;
3544 	timelib_sll value = -1;
3545 
3546  	if (member->type != IS_STRING) {
3547 		tmp_member = *member;
3548 		zval_copy_ctor(&tmp_member);
3549 		convert_to_string(&tmp_member);
3550 		member = &tmp_member;
3551 	}
3552 
3553 	obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
3554 
3555 	if (!obj->initialized) {
3556 		retval = (zend_get_std_object_handlers())->read_property(object, member, type TSRMLS_CC);
3557 		if (member == &tmp_member) {
3558 			zval_dtor(member);
3559 		}
3560 		return retval;
3561 	}
3562 
3563 #define GET_VALUE_FROM_STRUCT(n,m)            \
3564 	if (strcmp(Z_STRVAL_P(member), m) == 0) { \
3565 		value = obj->diff->n;                 \
3566 		break;								  \
3567 	}
3568 	do {
3569 		GET_VALUE_FROM_STRUCT(y, "y");
3570 		GET_VALUE_FROM_STRUCT(m, "m");
3571 		GET_VALUE_FROM_STRUCT(d, "d");
3572 		GET_VALUE_FROM_STRUCT(h, "h");
3573 		GET_VALUE_FROM_STRUCT(i, "i");
3574 		GET_VALUE_FROM_STRUCT(s, "s");
3575 		GET_VALUE_FROM_STRUCT(invert, "invert");
3576 		GET_VALUE_FROM_STRUCT(days, "days");
3577 		/* didn't find any */
3578 		retval = (zend_get_std_object_handlers())->read_property(object, member, type TSRMLS_CC);
3579 
3580 		if (member == &tmp_member) {
3581 			zval_dtor(member);
3582 		}
3583 
3584 		return retval;
3585 	} while(0);
3586 
3587 	ALLOC_INIT_ZVAL(retval);
3588 	Z_SET_REFCOUNT_P(retval, 0);
3589 
3590 	ZVAL_LONG(retval, value);
3591 
3592 	if (member == &tmp_member) {
3593 		zval_dtor(member);
3594 	}
3595 
3596 	return retval;
3597 }
3598 /* }}} */
3599 
3600 /* {{{ date_interval_write_property */
date_interval_write_property(zval * object,zval * member,zval * value TSRMLS_DC)3601 void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
3602 {
3603 	php_interval_obj *obj;
3604 	zval tmp_member, tmp_value;
3605 
3606  	if (member->type != IS_STRING) {
3607 		tmp_member = *member;
3608 		zval_copy_ctor(&tmp_member);
3609 		convert_to_string(&tmp_member);
3610 		member = &tmp_member;
3611 	}
3612 
3613 	obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
3614 
3615 	if (!obj->initialized) {
3616 		(zend_get_std_object_handlers())->write_property(object, member, value TSRMLS_CC);
3617 		if (member == &tmp_member) {
3618 			zval_dtor(member);
3619 		}
3620 		return;
3621 	}
3622 
3623 #define SET_VALUE_FROM_STRUCT(n,m)            \
3624 	if (strcmp(Z_STRVAL_P(member), m) == 0) { \
3625 		if (value->type != IS_LONG) {         \
3626 			tmp_value = *value;               \
3627 			zval_copy_ctor(&tmp_value);       \
3628 			convert_to_long(&tmp_value);      \
3629 			value = &tmp_value;               \
3630 		}                                     \
3631 		obj->diff->n = Z_LVAL_P(value);       \
3632 		if (value == &tmp_value) {            \
3633 			zval_dtor(value);                 \
3634 		}                                     \
3635 		break;								  \
3636 	}
3637 
3638 	do {
3639 		SET_VALUE_FROM_STRUCT(y, "y");
3640 		SET_VALUE_FROM_STRUCT(m, "m");
3641 		SET_VALUE_FROM_STRUCT(d, "d");
3642 		SET_VALUE_FROM_STRUCT(h, "h");
3643 		SET_VALUE_FROM_STRUCT(i, "i");
3644 		SET_VALUE_FROM_STRUCT(s, "s");
3645 		SET_VALUE_FROM_STRUCT(invert, "invert");
3646 		/* didn't find any */
3647 		(zend_get_std_object_handlers())->write_property(object, member, value TSRMLS_CC);
3648 	} while(0);
3649 
3650 	if (member == &tmp_member) {
3651 		zval_dtor(member);
3652 	}
3653 }
3654 /* }}} */
3655 
3656 
3657 /* {{{ proto DateInterval::__construct([string interval_spec])
3658    Creates new DateInterval object.
3659 */
PHP_METHOD(DateInterval,__construct)3660 PHP_METHOD(DateInterval, __construct)
3661 {
3662 	char *interval_string = NULL;
3663 	int   interval_string_length;
3664 	php_interval_obj *diobj;
3665 	timelib_rel_time *reltime;
3666 	zend_error_handling error_handling;
3667 
3668 	zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
3669 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &interval_string, &interval_string_length) == SUCCESS) {
3670 		if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
3671 			diobj = zend_object_store_get_object(getThis() TSRMLS_CC);
3672 			diobj->diff = reltime;
3673 			diobj->initialized = 1;
3674 		} else {
3675 			ZVAL_NULL(getThis());
3676 		}
3677 	}
3678 	zend_restore_error_handling(&error_handling TSRMLS_CC);
3679 }
3680 /* }}} */
3681 
3682 
php_date_interval_initialize_from_hash(zval ** return_value,php_interval_obj ** intobj,HashTable * myht TSRMLS_DC)3683 static int php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht TSRMLS_DC)
3684 {
3685 	(*intobj)->diff = timelib_rel_time_ctor();
3686 
3687 #define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \
3688 	do { \
3689 		zval **z_arg = NULL; \
3690 		if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
3691 			convert_to_long(*z_arg); \
3692 			(*intobj)->diff->member = (itype)Z_LVAL_PP(z_arg); \
3693 		} else { \
3694 			(*intobj)->diff->member = (itype)def; \
3695 		} \
3696 	} while (0);
3697 
3698 #define PHP_DATE_INTERVAL_READ_PROPERTY_I64(element, member) \
3699 	do { \
3700 		zval **z_arg = NULL; \
3701 		if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
3702 			convert_to_string(*z_arg); \
3703 			DATE_A64I((*intobj)->diff->member, Z_STRVAL_PP(z_arg)); \
3704 		} else { \
3705 			(*intobj)->diff->member = -1LL; \
3706 		} \
3707 	} while (0);
3708 
3709 	PHP_DATE_INTERVAL_READ_PROPERTY("y", y, timelib_sll, -1)
3710 	PHP_DATE_INTERVAL_READ_PROPERTY("m", m, timelib_sll, -1)
3711 	PHP_DATE_INTERVAL_READ_PROPERTY("d", d, timelib_sll, -1)
3712 	PHP_DATE_INTERVAL_READ_PROPERTY("h", h, timelib_sll, -1)
3713 	PHP_DATE_INTERVAL_READ_PROPERTY("i", i, timelib_sll, -1)
3714 	PHP_DATE_INTERVAL_READ_PROPERTY("s", s, timelib_sll, -1)
3715 	PHP_DATE_INTERVAL_READ_PROPERTY("weekday", weekday, int, -1)
3716 	PHP_DATE_INTERVAL_READ_PROPERTY("weekday_behavior", weekday_behavior, int, -1)
3717 	PHP_DATE_INTERVAL_READ_PROPERTY("first_last_day_of", first_last_day_of, int, -1)
3718 	PHP_DATE_INTERVAL_READ_PROPERTY("invert", invert, int, 0);
3719 	PHP_DATE_INTERVAL_READ_PROPERTY_I64("days", days);
3720 	PHP_DATE_INTERVAL_READ_PROPERTY("special_type", special.type, unsigned int, 0);
3721 	PHP_DATE_INTERVAL_READ_PROPERTY_I64("special_amount", special.amount);
3722 	PHP_DATE_INTERVAL_READ_PROPERTY("have_weekday_relative", have_weekday_relative, unsigned int, 0);
3723 	PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0);
3724 	(*intobj)->initialized = 1;
3725 
3726 	return 0;
3727 }
3728 
3729 /* {{{ proto DateInterval::__set_state()
3730 */
PHP_METHOD(DateInterval,__set_state)3731 PHP_METHOD(DateInterval, __set_state)
3732 {
3733 	php_interval_obj *intobj;
3734 	zval             *array;
3735 	HashTable        *myht;
3736 
3737 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
3738 		RETURN_FALSE;
3739 	}
3740 
3741 	myht = HASH_OF(array);
3742 
3743 	php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
3744 	intobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
3745 	php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC);
3746 }
3747 /* }}} */
3748 
3749 /* {{{ proto DateInterval::__wakeup()
3750 */
PHP_METHOD(DateInterval,__wakeup)3751 PHP_METHOD(DateInterval, __wakeup)
3752 {
3753 	zval             *object = getThis();
3754 	php_interval_obj *intobj;
3755 	HashTable        *myht;
3756 
3757 	intobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
3758 
3759 	myht = Z_OBJPROP_P(object);
3760 
3761 	php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC);
3762 }
3763 /* }}} */
3764 /* {{{ proto DateInterval date_interval_create_from_date_string(string time)
3765    Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string
3766 */
PHP_FUNCTION(date_interval_create_from_date_string)3767 PHP_FUNCTION(date_interval_create_from_date_string)
3768 {
3769 	char           *time_str = NULL;
3770 	int             time_str_len = 0;
3771 	timelib_time   *time;
3772 	timelib_error_container *err = NULL;
3773 	php_interval_obj *diobj;
3774 
3775 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &time_str, &time_str_len) == FAILURE) {
3776 		RETURN_FALSE;
3777 	}
3778 
3779 	php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
3780 
3781 	time = timelib_strtotime(time_str, time_str_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
3782 	diobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
3783 	diobj->diff = timelib_rel_time_clone(&time->relative);
3784 	diobj->initialized = 1;
3785 	timelib_time_dtor(time);
3786 	timelib_error_container_dtor(err);
3787 }
3788 /* }}} */
3789 
3790 /* {{{ date_interval_format -  */
date_interval_format(char * format,int format_len,timelib_rel_time * t)3791 static char *date_interval_format(char *format, int format_len, timelib_rel_time *t)
3792 {
3793 	smart_str            string = {0};
3794 	int                  i, length, have_format_spec = 0;
3795 	char                 buffer[33];
3796 
3797 	if (!format_len) {
3798 		return estrdup("");
3799 	}
3800 
3801 	for (i = 0; i < format_len; i++) {
3802 		if (have_format_spec) {
3803 			switch (format[i]) {
3804 				case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break;
3805 				case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break;
3806 
3807 				case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
3808 				case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break;
3809 
3810 				case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
3811 				case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break;
3812 
3813 				case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
3814 				case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break;
3815 
3816 				case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
3817 				case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break;
3818 
3819 				case 'S': length = slprintf(buffer, 32, "%02ld", (long) t->s); break;
3820 				case 's': length = slprintf(buffer, 32, "%ld", (long) t->s); break;
3821 
3822 				case 'a': {
3823 					if ((int) t->days != -99999) {
3824 						length = slprintf(buffer, 32, "%d", (int) t->days);
3825 					} else {
3826 						length = slprintf(buffer, 32, "(unknown)");
3827 					}
3828 				} break;
3829 				case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break;
3830 				case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break;
3831 
3832 				case '%': length = slprintf(buffer, 32, "%%"); break;
3833 				default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
3834 			}
3835 			smart_str_appendl(&string, buffer, length);
3836 			have_format_spec = 0;
3837 		} else {
3838 			if (format[i] == '%') {
3839 				have_format_spec = 1;
3840 			} else {
3841 				smart_str_appendc(&string, format[i]);
3842 			}
3843 		}
3844 	}
3845 
3846 	smart_str_0(&string);
3847 
3848 	return string.c;
3849 }
3850 /* }}} */
3851 
3852 /* {{{ proto string date_interval_format(DateInterval object, string format)
3853    Formats the interval.
3854 */
PHP_FUNCTION(date_interval_format)3855 PHP_FUNCTION(date_interval_format)
3856 {
3857 	zval             *object;
3858 	php_interval_obj *diobj;
3859 	char             *format;
3860 	int               format_len;
3861 
3862 	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) {
3863 		RETURN_FALSE;
3864 	}
3865 	diobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
3866 	DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval);
3867 
3868 	RETURN_STRING(date_interval_format(format, format_len, diobj->diff), 0);
3869 }
3870 /* }}} */
3871 
date_period_initialize(timelib_time ** st,timelib_time ** et,timelib_rel_time ** d,long * recurrences,char * format,int format_length TSRMLS_DC)3872 static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, long *recurrences, /*const*/ char *format, int format_length TSRMLS_DC)
3873 {
3874 	timelib_time     *b = NULL, *e = NULL;
3875 	timelib_rel_time *p = NULL;
3876 	int               r = 0;
3877 	int               retval = 0;
3878 	struct timelib_error_container *errors;
3879 
3880 	timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
3881 
3882 	if (errors->error_count > 0) {
3883 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
3884 		retval = FAILURE;
3885 	} else {
3886 		*st = b;
3887 		*et = e;
3888 		*d  = p;
3889 		*recurrences = r;
3890 		retval = SUCCESS;
3891 	}
3892 	timelib_error_container_dtor(errors);
3893 	return retval;
3894 }
3895 
3896 /* {{{ proto DatePeriod::__construct(DateTime $start, DateInterval $interval, int recurrences|DateTime $end)
3897    Creates new DatePeriod object.
3898 */
PHP_METHOD(DatePeriod,__construct)3899 PHP_METHOD(DatePeriod, __construct)
3900 {
3901 	php_period_obj   *dpobj;
3902 	php_date_obj     *dateobj;
3903 	php_interval_obj *intobj;
3904 	zval *start, *end = NULL, *interval;
3905 	long  recurrences = 0, options = 0;
3906 	char *isostr = NULL;
3907 	int   isostr_len = 0;
3908 	timelib_time *clone;
3909 	zend_error_handling error_handling;
3910 
3911 	zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
3912 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_date, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
3913 		if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_date, &interval, date_ce_interval, &end, date_ce_date, &options) == FAILURE) {
3914 			if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &isostr, &isostr_len, &options) == FAILURE) {
3915 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTime, DateInterval, int) OR (DateTime, DateInterval, DateTime) OR (string) as arguments.");
3916 				zend_restore_error_handling(&error_handling TSRMLS_CC);
3917 				return;
3918 			}
3919 		}
3920 	}
3921 
3922 	dpobj = zend_object_store_get_object(getThis() TSRMLS_CC);
3923 	dpobj->current = NULL;
3924 
3925 	if (isostr) {
3926 		date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len TSRMLS_CC);
3927 		if (dpobj->start == NULL) {
3928 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
3929 		}
3930 		if (dpobj->interval == NULL) {
3931 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
3932 		}
3933 		if (dpobj->end == NULL && recurrences == 0) {
3934 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
3935 		}
3936 
3937 		if (dpobj->start) {
3938 			timelib_update_ts(dpobj->start, NULL);
3939 		}
3940 		if (dpobj->end) {
3941 			timelib_update_ts(dpobj->end, NULL);
3942 		}
3943 	} else {
3944 		/* init */
3945 		intobj  = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
3946 
3947 		/* start date */
3948 		dateobj = (php_date_obj *) zend_object_store_get_object(start TSRMLS_CC);
3949 		clone = timelib_time_ctor();
3950 		memcpy(clone, dateobj->time, sizeof(timelib_time));
3951 		if (dateobj->time->tz_abbr) {
3952 			clone->tz_abbr = strdup(dateobj->time->tz_abbr);
3953 		}
3954 		if (dateobj->time->tz_info) {
3955 			clone->tz_info = dateobj->time->tz_info;
3956 		}
3957 		dpobj->start = clone;
3958 
3959 		/* interval */
3960 		dpobj->interval = timelib_rel_time_clone(intobj->diff);
3961 
3962 		/* end date */
3963 		if (end) {
3964 			dateobj = (php_date_obj *) zend_object_store_get_object(end TSRMLS_CC);
3965 			clone = timelib_time_clone(dateobj->time);
3966 			dpobj->end = clone;
3967 		}
3968 	}
3969 
3970 	/* options */
3971 	dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
3972 
3973 	/* recurrrences */
3974 	dpobj->recurrences = recurrences + dpobj->include_start_date;
3975 
3976 	dpobj->initialized = 1;
3977 
3978 	zend_restore_error_handling(&error_handling TSRMLS_CC);
3979 }
3980 /* }}} */
3981 
check_id_allowed(char * id,long what)3982 static int check_id_allowed(char *id, long what)
3983 {
3984 	if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA     && strncasecmp(id, "Africa/",      7) == 0) return 1;
3985 	if (what & PHP_DATE_TIMEZONE_GROUP_AMERICA    && strncasecmp(id, "America/",     8) == 0) return 1;
3986 	if (what & PHP_DATE_TIMEZONE_GROUP_ANTARCTICA && strncasecmp(id, "Antarctica/", 11) == 0) return 1;
3987 	if (what & PHP_DATE_TIMEZONE_GROUP_ARCTIC     && strncasecmp(id, "Arctic/",      7) == 0) return 1;
3988 	if (what & PHP_DATE_TIMEZONE_GROUP_ASIA       && strncasecmp(id, "Asia/",        5) == 0) return 1;
3989 	if (what & PHP_DATE_TIMEZONE_GROUP_ATLANTIC   && strncasecmp(id, "Atlantic/",    9) == 0) return 1;
3990 	if (what & PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  && strncasecmp(id, "Australia/",  10) == 0) return 1;
3991 	if (what & PHP_DATE_TIMEZONE_GROUP_EUROPE     && strncasecmp(id, "Europe/",      7) == 0) return 1;
3992 	if (what & PHP_DATE_TIMEZONE_GROUP_INDIAN     && strncasecmp(id, "Indian/",      7) == 0) return 1;
3993 	if (what & PHP_DATE_TIMEZONE_GROUP_PACIFIC    && strncasecmp(id, "Pacific/",     8) == 0) return 1;
3994 	if (what & PHP_DATE_TIMEZONE_GROUP_UTC        && strncasecmp(id, "UTC",          3) == 0) return 1;
3995 	return 0;
3996 }
3997 
3998 /* {{{ proto array timezone_identifiers_list([long what[, string country]])
3999    Returns numerically index array with all timezone identifiers.
4000 */
PHP_FUNCTION(timezone_identifiers_list)4001 PHP_FUNCTION(timezone_identifiers_list)
4002 {
4003 	const timelib_tzdb             *tzdb;
4004 	const timelib_tzdb_index_entry *table;
4005 	int                             i, item_count;
4006 	long                            what = PHP_DATE_TIMEZONE_GROUP_ALL;
4007 	char                           *option = NULL;
4008 	int                             option_len = 0;
4009 
4010 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &what, &option, &option_len) == FAILURE) {
4011 		RETURN_FALSE;
4012 	}
4013 
4014 	/* Extra validation */
4015 	if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
4016 		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
4017 		RETURN_FALSE;
4018 	}
4019 
4020 	tzdb = DATE_TIMEZONEDB;
4021 	item_count = tzdb->index_size;
4022 	table = tzdb->index;
4023 
4024 	array_init(return_value);
4025 
4026 	for (i = 0; i < item_count; ++i) {
4027 		if (what == PHP_DATE_TIMEZONE_PER_COUNTRY) {
4028 			if (tzdb->data[table[i].pos + 5] == option[0] && tzdb->data[table[i].pos + 6] == option[1]) {
4029 				add_next_index_string(return_value, table[i].id, 1);
4030 			}
4031 		} else if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || (check_id_allowed(table[i].id, what) && (tzdb->data[table[i].pos + 4] == '\1'))) {
4032 			add_next_index_string(return_value, table[i].id, 1);
4033 		}
4034 	};
4035 }
4036 /* }}} */
4037 
4038 /* {{{ proto array timezone_version_get()
4039    Returns the Olson database version number.
4040 */
PHP_FUNCTION(timezone_version_get)4041 PHP_FUNCTION(timezone_version_get)
4042 {
4043 	const timelib_tzdb *tzdb;
4044 
4045 	tzdb = DATE_TIMEZONEDB;
4046 	RETURN_STRING(tzdb->version, 1);
4047 }
4048 /* }}} */
4049 
4050 /* {{{ proto array timezone_abbreviations_list()
4051    Returns associative array containing dst, offset and the timezone name
4052 */
PHP_FUNCTION(timezone_abbreviations_list)4053 PHP_FUNCTION(timezone_abbreviations_list)
4054 {
4055 	const timelib_tz_lookup_table *table, *entry;
4056 	zval                          *element, **abbr_array_pp, *abbr_array;
4057 
4058 	table = timelib_timezone_abbreviations_list();
4059 	array_init(return_value);
4060 	entry = table;
4061 
4062 	do {
4063 		MAKE_STD_ZVAL(element);
4064 		array_init(element);
4065 		add_assoc_bool(element, "dst", entry->type);
4066 		add_assoc_long(element, "offset", entry->gmtoffset);
4067 		if (entry->full_tz_name) {
4068 			add_assoc_string(element, "timezone_id", entry->full_tz_name, 1);
4069 		} else {
4070 			add_assoc_null(element, "timezone_id");
4071 		}
4072 
4073 		if (zend_hash_find(HASH_OF(return_value), entry->name, strlen(entry->name) + 1, (void **) &abbr_array_pp) == FAILURE) {
4074 			MAKE_STD_ZVAL(abbr_array);
4075 			array_init(abbr_array);
4076 			add_assoc_zval(return_value, entry->name, abbr_array);
4077 		} else {
4078 			abbr_array = *abbr_array_pp;
4079 		}
4080 		add_next_index_zval(abbr_array, element);
4081 		entry++;
4082 	} while (entry->name);
4083 }
4084 /* }}} */
4085 
4086 /* {{{ proto bool date_default_timezone_set(string timezone_identifier)
4087    Sets the default timezone used by all date/time functions in a script */
PHP_FUNCTION(date_default_timezone_set)4088 PHP_FUNCTION(date_default_timezone_set)
4089 {
4090 	char *zone;
4091 	int   zone_len;
4092 
4093 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
4094 		RETURN_FALSE;
4095 	}
4096 	if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
4097 		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
4098 		RETURN_FALSE;
4099 	}
4100 	if (DATEG(timezone)) {
4101 		efree(DATEG(timezone));
4102 		DATEG(timezone) = NULL;
4103 	}
4104 	DATEG(timezone) = estrndup(zone, zone_len);
4105 	RETURN_TRUE;
4106 }
4107 /* }}} */
4108 
4109 /* {{{ proto string date_default_timezone_get()
4110    Gets the default timezone used by all date/time functions in a script */
PHP_FUNCTION(date_default_timezone_get)4111 PHP_FUNCTION(date_default_timezone_get)
4112 {
4113 	timelib_tzinfo *default_tz;
4114 
4115 	default_tz = get_timezone_info(TSRMLS_C);
4116 	RETVAL_STRING(default_tz->name, 1);
4117 }
4118 /* }}} */
4119 
4120 /* {{{ php_do_date_sunrise_sunset
4121  *  Common for date_sunrise() and date_sunset() functions
4122  */
php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS,int calc_sunset)4123 static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
4124 {
4125 	double latitude = 0.0, longitude = 0.0, zenith = 0.0, gmt_offset = 0, altitude;
4126 	double h_rise, h_set, N;
4127 	timelib_sll rise, set, transit;
4128 	long time, retformat = 0;
4129 	int             rs;
4130 	timelib_time   *t;
4131 	timelib_tzinfo *tzi;
4132 	char           *retstr;
4133 
4134 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
4135 		RETURN_FALSE;
4136 	}
4137 
4138 	switch (ZEND_NUM_ARGS()) {
4139 		case 1:
4140 			retformat = SUNFUNCS_RET_STRING;
4141 		case 2:
4142 			latitude = INI_FLT("date.default_latitude");
4143 		case 3:
4144 			longitude = INI_FLT("date.default_longitude");
4145 		case 4:
4146 			if (calc_sunset) {
4147 				zenith = INI_FLT("date.sunset_zenith");
4148 			} else {
4149 				zenith = INI_FLT("date.sunrise_zenith");
4150 			}
4151 		case 5:
4152 		case 6:
4153 			break;
4154 		default:
4155 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid format");
4156 			RETURN_FALSE;
4157 			break;
4158 	}
4159 	if (retformat != SUNFUNCS_RET_TIMESTAMP &&
4160 		retformat != SUNFUNCS_RET_STRING &&
4161 		retformat != SUNFUNCS_RET_DOUBLE)
4162 	{
4163 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong return format given, pick one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING or SUNFUNCS_RET_DOUBLE");
4164 		RETURN_FALSE;
4165 	}
4166 	altitude = 90 - zenith;
4167 
4168 	/* Initialize time struct */
4169 	t = timelib_time_ctor();
4170 	tzi = get_timezone_info(TSRMLS_C);
4171 	t->tz_info = tzi;
4172 	t->zone_type = TIMELIB_ZONETYPE_ID;
4173 
4174 	if (ZEND_NUM_ARGS() <= 5) {
4175 		gmt_offset = timelib_get_current_offset(t) / 3600;
4176 	}
4177 
4178 	timelib_unixtime2local(t, time);
4179 	rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
4180 	timelib_time_dtor(t);
4181 
4182 	if (rs != 0) {
4183 		RETURN_FALSE;
4184 	}
4185 
4186 	if (retformat == SUNFUNCS_RET_TIMESTAMP) {
4187 		RETURN_LONG(calc_sunset ? set : rise);
4188 	}
4189 	N = (calc_sunset ? h_set : h_rise) + gmt_offset;
4190 
4191 	if (N > 24 || N < 0) {
4192 		N -= floor(N / 24) * 24;
4193 	}
4194 
4195 	switch (retformat) {
4196 		case SUNFUNCS_RET_STRING:
4197 			spprintf(&retstr, 0, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
4198 			RETURN_STRINGL(retstr, 5, 0);
4199 			break;
4200 		case SUNFUNCS_RET_DOUBLE:
4201 			RETURN_DOUBLE(N);
4202 			break;
4203 	}
4204 }
4205 /* }}} */
4206 
4207 /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
4208    Returns time of sunrise for a given day and location */
PHP_FUNCTION(date_sunrise)4209 PHP_FUNCTION(date_sunrise)
4210 {
4211 	php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4212 }
4213 /* }}} */
4214 
4215 /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
4216    Returns time of sunset for a given day and location */
PHP_FUNCTION(date_sunset)4217 PHP_FUNCTION(date_sunset)
4218 {
4219 	php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4220 }
4221 /* }}} */
4222 
4223 /* {{{ proto array date_sun_info(long time, float latitude, float longitude)
4224    Returns an array with information about sun set/rise and twilight begin/end */
PHP_FUNCTION(date_sun_info)4225 PHP_FUNCTION(date_sun_info)
4226 {
4227 	long            time;
4228 	double          latitude, longitude;
4229 	timelib_time   *t, *t2;
4230 	timelib_tzinfo *tzi;
4231 	int             rs;
4232 	timelib_sll     rise, set, transit;
4233 	int             dummy;
4234 	double          ddummy;
4235 
4236 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
4237 		RETURN_FALSE;
4238 	}
4239 	/* Initialize time struct */
4240 	t = timelib_time_ctor();
4241 	tzi = get_timezone_info(TSRMLS_C);
4242 	t->tz_info = tzi;
4243 	t->zone_type = TIMELIB_ZONETYPE_ID;
4244 	timelib_unixtime2local(t, time);
4245 
4246 	/* Setup */
4247 	t2 = timelib_time_ctor();
4248 	array_init(return_value);
4249 
4250 	/* Get sun up/down and transit */
4251 	rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
4252 	switch (rs) {
4253 		case -1: /* always below */
4254 			add_assoc_bool(return_value, "sunrise", 0);
4255 			add_assoc_bool(return_value, "sunset", 0);
4256 			break;
4257 		case 1: /* always above */
4258 			add_assoc_bool(return_value, "sunrise", 1);
4259 			add_assoc_bool(return_value, "sunset", 1);
4260 			break;
4261 		default:
4262 			t2->sse = rise;
4263 			add_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
4264 			t2->sse = set;
4265 			add_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
4266 	}
4267 	t2->sse = transit;
4268 	add_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
4269 
4270 	/* Get civil twilight */
4271 	rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
4272 	switch (rs) {
4273 		case -1: /* always below */
4274 			add_assoc_bool(return_value, "civil_twilight_begin", 0);
4275 			add_assoc_bool(return_value, "civil_twilight_end", 0);
4276 			break;
4277 		case 1: /* always above */
4278 			add_assoc_bool(return_value, "civil_twilight_begin", 1);
4279 			add_assoc_bool(return_value, "civil_twilight_end", 1);
4280 			break;
4281 		default:
4282 			t2->sse = rise;
4283 			add_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
4284 			t2->sse = set;
4285 			add_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
4286 	}
4287 
4288 	/* Get nautical twilight */
4289 	rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
4290 	switch (rs) {
4291 		case -1: /* always below */
4292 			add_assoc_bool(return_value, "nautical_twilight_begin", 0);
4293 			add_assoc_bool(return_value, "nautical_twilight_end", 0);
4294 			break;
4295 		case 1: /* always above */
4296 			add_assoc_bool(return_value, "nautical_twilight_begin", 1);
4297 			add_assoc_bool(return_value, "nautical_twilight_end", 1);
4298 			break;
4299 		default:
4300 			t2->sse = rise;
4301 			add_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
4302 			t2->sse = set;
4303 			add_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
4304 	}
4305 
4306 	/* Get astronomical twilight */
4307 	rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
4308 	switch (rs) {
4309 		case -1: /* always below */
4310 			add_assoc_bool(return_value, "astronomical_twilight_begin", 0);
4311 			add_assoc_bool(return_value, "astronomical_twilight_end", 0);
4312 			break;
4313 		case 1: /* always above */
4314 			add_assoc_bool(return_value, "astronomical_twilight_begin", 1);
4315 			add_assoc_bool(return_value, "astronomical_twilight_end", 1);
4316 			break;
4317 		default:
4318 			t2->sse = rise;
4319 			add_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
4320 			t2->sse = set;
4321 			add_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
4322 	}
4323 	timelib_time_dtor(t);
4324 	timelib_time_dtor(t2);
4325 }
4326 /* }}} */
4327 
4328 
date_object_get_properties_period(zval * object TSRMLS_DC)4329 static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC)
4330 {
4331 	HashTable		*props;
4332 	zval			*zv;
4333 	php_period_obj	*period_obj;
4334 
4335 	period_obj = zend_object_store_get_object(object TSRMLS_CC);
4336 
4337 	props = zend_std_get_properties(object TSRMLS_CC);
4338 
4339 	if (!period_obj->start) {
4340 		return props;
4341 	}
4342 
4343 	MAKE_STD_ZVAL(zv);
4344 	if (period_obj->start) {
4345 		php_date_obj *date_obj;
4346 		object_init_ex(zv, date_ce_date);
4347 		date_obj = zend_object_store_get_object(zv TSRMLS_CC);
4348 		date_obj->time = timelib_time_clone(period_obj->start);
4349 	} else {
4350 		ZVAL_NULL(zv);
4351 	}
4352 	zend_hash_update(props, "start", sizeof("start"), &zv, sizeof(zv), NULL);
4353 
4354 	MAKE_STD_ZVAL(zv);
4355 	if (period_obj->current) {
4356 		php_date_obj *date_obj;
4357 		object_init_ex(zv, date_ce_date);
4358 		date_obj = zend_object_store_get_object(zv TSRMLS_CC);
4359 		date_obj->time = timelib_time_clone(period_obj->current);
4360 	} else {
4361 		ZVAL_NULL(zv);
4362 	}
4363 	zend_hash_update(props, "current", sizeof("current"), &zv, sizeof(zv), NULL);
4364 
4365 	MAKE_STD_ZVAL(zv);
4366 	if (period_obj->end) {
4367 		php_date_obj *date_obj;
4368 		object_init_ex(zv, date_ce_date);
4369 		date_obj = zend_object_store_get_object(zv TSRMLS_CC);
4370 		date_obj->time = timelib_time_clone(period_obj->end);
4371 	} else {
4372 		ZVAL_NULL(zv);
4373 	}
4374 	zend_hash_update(props, "end", sizeof("end"), &zv, sizeof(zv), NULL);
4375 
4376 	MAKE_STD_ZVAL(zv);
4377 	if (period_obj->interval) {
4378 		php_interval_obj *interval_obj;
4379 		object_init_ex(zv, date_ce_interval);
4380 		interval_obj = zend_object_store_get_object(zv TSRMLS_CC);
4381 		interval_obj->diff = timelib_rel_time_clone(period_obj->interval);
4382 		interval_obj->initialized = 1;
4383 	} else {
4384 		ZVAL_NULL(zv);
4385 	}
4386 	zend_hash_update(props, "interval", sizeof("interval"), &zv, sizeof(zv), NULL);
4387 
4388 	/* converted to larger type (int->long); must check when unserializing */
4389 	MAKE_STD_ZVAL(zv);
4390 	ZVAL_LONG(zv, (long) period_obj->recurrences);
4391 	zend_hash_update(props, "recurrences", sizeof("recurrences"), &zv, sizeof(zv), NULL);
4392 
4393 	MAKE_STD_ZVAL(zv);
4394 	ZVAL_BOOL(zv, period_obj->include_start_date);
4395 	zend_hash_update(props, "include_start_date", sizeof("include_start_date"), &zv, sizeof(zv), NULL);
4396 
4397 	return props;
4398 }
4399 
php_date_period_initialize_from_hash(php_period_obj * period_obj,HashTable * myht TSRMLS_DC)4400 static int php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht TSRMLS_DC)
4401 {
4402 	zval **ht_entry;
4403 
4404 	/* this function does no rollback on error */
4405 
4406 	if (zend_hash_find(myht, "start", sizeof("start"), (void**) &ht_entry) == SUCCESS) {
4407 		if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
4408 			php_date_obj *date_obj;
4409 			date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
4410 			period_obj->start = timelib_time_clone(date_obj->time);
4411 		} else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
4412 			return 0;
4413 		}
4414 	} else {
4415 		return 0;
4416 	}
4417 
4418 	if (zend_hash_find(myht, "end", sizeof("end"), (void**) &ht_entry) == SUCCESS) {
4419 		if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
4420 			php_date_obj *date_obj;
4421 			date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
4422 			period_obj->end = timelib_time_clone(date_obj->time);
4423 		} else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
4424 			return 0;
4425 		}
4426 	} else {
4427 		return 0;
4428 	}
4429 
4430 	if (zend_hash_find(myht, "current", sizeof("current"), (void**) &ht_entry) == SUCCESS) {
4431 		if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
4432 			php_date_obj *date_obj;
4433 			date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
4434 			period_obj->current = timelib_time_clone(date_obj->time);
4435 		} else if (Z_TYPE_PP(ht_entry) != IS_NULL)  {
4436 			return 0;
4437 		}
4438 	} else {
4439 		return 0;
4440 	}
4441 
4442 	if (zend_hash_find(myht, "interval", sizeof("interval"), (void**) &ht_entry) == SUCCESS) {
4443 		if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_interval) {
4444 			php_interval_obj *interval_obj;
4445 			interval_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
4446 			period_obj->interval = timelib_rel_time_clone(interval_obj->diff);
4447 		} else { /* interval is required */
4448 			return 0;
4449 		}
4450 	} else {
4451 		return 0;
4452 	}
4453 
4454 	if (zend_hash_find(myht, "recurrences", sizeof("recurrences"), (void**) &ht_entry) == SUCCESS &&
4455 			Z_TYPE_PP(ht_entry) == IS_LONG && Z_LVAL_PP(ht_entry) >= 0 && Z_LVAL_PP(ht_entry) <= INT_MAX) {
4456 		period_obj->recurrences = Z_LVAL_PP(ht_entry);
4457 	} else {
4458 		return 0;
4459 	}
4460 
4461 	if (zend_hash_find(myht, "include_start_date", sizeof("include_start_date"), (void**) &ht_entry) == SUCCESS &&
4462 			Z_TYPE_PP(ht_entry) == IS_BOOL) {
4463 		period_obj->include_start_date = Z_BVAL_PP(ht_entry);
4464 	} else {
4465 		return 0;
4466 	}
4467 
4468 	period_obj->initialized = 1;
4469 
4470 	return 1;
4471 }
4472 
4473 /* {{{ proto DatePeriod::__set_state()
4474 */
PHP_METHOD(DatePeriod,__set_state)4475 PHP_METHOD(DatePeriod, __set_state)
4476 {
4477 	php_period_obj   *period_obj;
4478 	zval             *array;
4479 	HashTable        *myht;
4480 
4481 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
4482 		RETURN_FALSE;
4483 	}
4484 
4485 	myht = Z_ARRVAL_P(array);
4486 
4487 	object_init_ex(return_value, date_ce_period);
4488 	period_obj = zend_object_store_get_object(return_value TSRMLS_CC);
4489 	if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
4490 		php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
4491 	}
4492 }
4493 /* }}} */
4494 
4495 /* {{{ proto DatePeriod::__wakeup()
4496 */
PHP_METHOD(DatePeriod,__wakeup)4497 PHP_METHOD(DatePeriod, __wakeup)
4498 {
4499 	zval             *object = getThis();
4500 	php_period_obj   *period_obj;
4501 	HashTable        *myht;
4502 
4503 	period_obj = zend_object_store_get_object(object TSRMLS_CC);
4504 
4505 	myht = Z_OBJPROP_P(object);
4506 
4507 	if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
4508 		php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
4509 	}
4510 }
4511 /* }}} */
4512 
4513 /* {{{ date_period_read_property */
date_period_read_property(zval * object,zval * member,int type TSRMLS_DC)4514 static zval *date_period_read_property(zval *object, zval *member, int type TSRMLS_DC)
4515 {
4516 	zval *zv;
4517 	if (type != BP_VAR_IS && type != BP_VAR_R) {
4518 		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Retrieval of DatePeriod properties for modification is unsupported");
4519 	}
4520 
4521 	Z_OBJPROP_P(object); /* build properties hash table */
4522 
4523 	zv = std_object_handlers.read_property(object, member, type TSRMLS_CC);
4524 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJ_HANDLER_P(zv, clone_obj)) {
4525 		/* defensive copy */
4526 		zend_object_value zov = Z_OBJ_HANDLER_P(zv, clone_obj)(zv TSRMLS_CC);
4527 		MAKE_STD_ZVAL(zv);
4528 		Z_TYPE_P(zv) = IS_OBJECT;
4529 		Z_OBJVAL_P(zv) = zov;
4530 	}
4531 
4532 	return zv;
4533 }
4534 /* }}} */
4535 
4536 /* {{{ date_period_write_property */
date_period_write_property(zval * object,zval * member,zval * value TSRMLS_DC)4537 static void date_period_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
4538 {
4539 	php_error_docref(NULL TSRMLS_CC, E_ERROR, "Writing to DatePeriod properties is unsupported");
4540 }
4541 /* }}} */
4542 
4543 
4544 /*
4545  * Local variables:
4546  * tab-width: 4
4547  * c-basic-offset: 4
4548  * End:
4549  * vim600: fdm=marker
4550  * vim: noet sw=4 ts=4
4551  */
4552