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