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