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