1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 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: php_date.c,v 1.43.2.45.2.43 2007/03/05 14:10:18 mike Exp $ */
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 "php_date.h"
29 : #include "lib/timelib.h"
30 : #include <time.h>
31 :
32 : /* {{{ arginfo */
33 : static
34 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
35 : ZEND_ARG_INFO(0, format)
36 : ZEND_ARG_INFO(0, timestamp)
37 : ZEND_END_ARG_INFO()
38 :
39 : static
40 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
41 : ZEND_ARG_INFO(0, format)
42 : ZEND_ARG_INFO(0, timestamp)
43 : ZEND_END_ARG_INFO()
44 :
45 : static
46 : ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
47 : ZEND_ARG_INFO(0, format)
48 : ZEND_ARG_INFO(0, timestamp)
49 : ZEND_END_ARG_INFO()
50 :
51 : static
52 : ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
53 : ZEND_ARG_INFO(0, time)
54 : ZEND_ARG_INFO(0, now)
55 : ZEND_END_ARG_INFO()
56 :
57 : static
58 : ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
59 : ZEND_ARG_INFO(0, hour)
60 : ZEND_ARG_INFO(0, min)
61 : ZEND_ARG_INFO(0, sec)
62 : ZEND_ARG_INFO(0, mon)
63 : ZEND_ARG_INFO(0, day)
64 : ZEND_ARG_INFO(0, year)
65 : ZEND_END_ARG_INFO()
66 :
67 : static
68 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 0, 0, 0)
69 : ZEND_ARG_INFO(0, hour)
70 : ZEND_ARG_INFO(0, min)
71 : ZEND_ARG_INFO(0, sec)
72 : ZEND_ARG_INFO(0, mon)
73 : ZEND_ARG_INFO(0, day)
74 : ZEND_ARG_INFO(0, year)
75 : ZEND_END_ARG_INFO()
76 :
77 : static
78 : ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
79 : ZEND_ARG_INFO(0, month)
80 : ZEND_ARG_INFO(0, day)
81 : ZEND_ARG_INFO(0, year)
82 : ZEND_END_ARG_INFO()
83 :
84 : static
85 : ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
86 : ZEND_ARG_INFO(0, format)
87 : ZEND_ARG_INFO(0, timestamp)
88 : ZEND_END_ARG_INFO()
89 :
90 : static
91 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
92 : ZEND_ARG_INFO(0, format)
93 : ZEND_ARG_INFO(0, timestamp)
94 : ZEND_END_ARG_INFO()
95 :
96 : static
97 : ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
98 : ZEND_END_ARG_INFO()
99 :
100 : static
101 : ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
102 : ZEND_ARG_INFO(0, timestamp)
103 : ZEND_ARG_INFO(0, associative_array)
104 : ZEND_END_ARG_INFO()
105 :
106 : static
107 : ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
108 : ZEND_ARG_INFO(0, timestamp)
109 : ZEND_END_ARG_INFO()
110 :
111 : static
112 : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
113 : ZEND_ARG_INFO(0, timezone_identifier)
114 : ZEND_END_ARG_INFO()
115 :
116 : static
117 : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
118 : ZEND_END_ARG_INFO()
119 :
120 : static
121 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
122 : ZEND_ARG_INFO(0, time)
123 : ZEND_ARG_INFO(0, format)
124 : ZEND_ARG_INFO(0, latitude)
125 : ZEND_ARG_INFO(0, longitude)
126 : ZEND_ARG_INFO(0, zenith)
127 : ZEND_ARG_INFO(0, gmt_offset)
128 : ZEND_END_ARG_INFO()
129 :
130 : static
131 : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
132 : ZEND_ARG_INFO(0, time)
133 : ZEND_ARG_INFO(0, format)
134 : ZEND_ARG_INFO(0, latitude)
135 : ZEND_ARG_INFO(0, longitude)
136 : ZEND_ARG_INFO(0, zenith)
137 : ZEND_ARG_INFO(0, gmt_offset)
138 : ZEND_END_ARG_INFO()
139 :
140 : static
141 : ZEND_BEGIN_ARG_INFO(arginfo_date_sun_info, 0)
142 : ZEND_ARG_INFO(0, time)
143 : ZEND_ARG_INFO(0, latitude)
144 : ZEND_ARG_INFO(0, longitude)
145 : ZEND_END_ARG_INFO()
146 :
147 : /* }}} */
148 :
149 : /* {{{ Function table */
150 : zend_function_entry date_functions[] = {
151 : PHP_FE(strtotime, arginfo_strtotime)
152 : PHP_FE(date, arginfo_date)
153 : PHP_FE(idate, arginfo_idate)
154 : PHP_FE(gmdate, arginfo_gmdate)
155 : PHP_FE(mktime, arginfo_mktime)
156 : PHP_FE(gmmktime, arginfo_gmmktime)
157 : PHP_FE(checkdate, arginfo_checkdate)
158 :
159 : #ifdef HAVE_STRFTIME
160 : PHP_FE(strftime, arginfo_strftime)
161 : PHP_FE(gmstrftime, arginfo_gmstrftime)
162 : #endif
163 :
164 : PHP_FE(time, arginfo_time)
165 : PHP_FE(localtime, arginfo_localtime)
166 : PHP_FE(getdate, arginfo_getdate)
167 :
168 : /* Advanced Interface */
169 : PHP_FE(date_create, NULL)
170 : PHP_FE(date_parse, NULL)
171 : PHP_FE(date_format, NULL)
172 : PHP_FE(date_modify, NULL)
173 : PHP_FE(date_timezone_get, NULL)
174 : PHP_FE(date_timezone_set, NULL)
175 : PHP_FE(date_offset_get, NULL)
176 :
177 : PHP_FE(date_time_set, NULL)
178 : PHP_FE(date_date_set, NULL)
179 : PHP_FE(date_isodate_set, NULL)
180 :
181 : PHP_FE(timezone_open, NULL)
182 : PHP_FE(timezone_name_get, NULL)
183 : PHP_FE(timezone_name_from_abbr, NULL)
184 : PHP_FE(timezone_offset_get, NULL)
185 : PHP_FE(timezone_transitions_get, NULL)
186 : PHP_FE(timezone_identifiers_list, NULL)
187 : PHP_FE(timezone_abbreviations_list, NULL)
188 :
189 : /* Options and Configuration */
190 : PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
191 : PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
192 :
193 : /* Astronomical functions */
194 : PHP_FE(date_sunrise, arginfo_date_sunrise)
195 : PHP_FE(date_sunset, arginfo_date_sunset)
196 : PHP_FE(date_sun_info, arginfo_date_sun_info)
197 : {NULL, NULL, NULL}
198 : };
199 :
200 : zend_function_entry date_funcs_date[] = {
201 : PHP_ME(DateTime, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
202 : PHP_ME_MAPPING(format, date_format, NULL, 0)
203 : PHP_ME_MAPPING(modify, date_modify, NULL, 0)
204 : PHP_ME_MAPPING(getTimezone, date_timezone_get, NULL, 0)
205 : PHP_ME_MAPPING(setTimezone, date_timezone_set, NULL, 0)
206 : PHP_ME_MAPPING(getOffset, date_offset_get, NULL, 0)
207 : PHP_ME_MAPPING(setTime, date_time_set, NULL, 0)
208 : PHP_ME_MAPPING(setDate, date_date_set, NULL, 0)
209 : PHP_ME_MAPPING(setISODate, date_isodate_set, NULL, 0)
210 : {NULL, NULL, NULL}
211 : };
212 :
213 : zend_function_entry date_funcs_timezone[] = {
214 : PHP_ME(DateTimeZone, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
215 : PHP_ME_MAPPING(getName, timezone_name_get, NULL, 0)
216 : PHP_ME_MAPPING(getOffset, timezone_offset_get, NULL, 0)
217 : PHP_ME_MAPPING(getTransitions, timezone_transitions_get, NULL, 0)
218 : PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
219 : PHP_ME_MAPPING(listIdentifiers, timezone_identifiers_list, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
220 : {NULL, NULL, NULL}
221 : };
222 :
223 : static void date_register_classes(TSRMLS_D);
224 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
225 : /* }}} */
226 :
227 : ZEND_DECLARE_MODULE_GLOBALS(date)
228 : static PHP_GINIT_FUNCTION(date);
229 :
230 : /* True global */
231 : timelib_tzdb *php_date_global_timezone_db;
232 : int php_date_global_timezone_db_enabled;
233 :
234 : #define DATE_DEFAULT_LATITUDE "31.7667"
235 : #define DATE_DEFAULT_LONGITUDE "35.2333"
236 :
237 : /* on 90'35; common sunset declaration (start of sun body appear) */
238 : #define DATE_SUNSET_ZENITH "90.583333"
239 :
240 : /* on 90'35; common sunrise declaration (sun body disappeared) */
241 : #define DATE_SUNRISE_ZENITH "90.583333"
242 :
243 : /* {{{ INI Settings */
244 : PHP_INI_BEGIN()
245 : STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdateString, default_timezone, zend_date_globals, date_globals)
246 : PHP_INI_ENTRY("date.default_latitude", DATE_DEFAULT_LATITUDE, PHP_INI_ALL, NULL)
247 : PHP_INI_ENTRY("date.default_longitude", DATE_DEFAULT_LONGITUDE, PHP_INI_ALL, NULL)
248 : PHP_INI_ENTRY("date.sunset_zenith", DATE_SUNSET_ZENITH, PHP_INI_ALL, NULL)
249 : PHP_INI_ENTRY("date.sunrise_zenith", DATE_SUNRISE_ZENITH, PHP_INI_ALL, NULL)
250 : PHP_INI_END()
251 : /* }}} */
252 :
253 : zend_class_entry *date_ce_date, *date_ce_timezone;
254 :
255 : static zend_object_handlers date_object_handlers_date;
256 : static zend_object_handlers date_object_handlers_timezone;
257 :
258 : typedef struct _php_date_obj php_date_obj;
259 : typedef struct _php_timezone_obj php_timezone_obj;
260 :
261 : struct _php_date_obj {
262 : zend_object std;
263 : timelib_time *time;
264 : };
265 :
266 : struct _php_timezone_obj {
267 : zend_object std;
268 : timelib_tzinfo *tz;
269 : };
270 :
271 : #define DATE_SET_CONTEXT \
272 : zval *object; \
273 : object = getThis(); \
274 :
275 : #define DATE_FETCH_OBJECT \
276 : php_date_obj *obj; \
277 : DATE_SET_CONTEXT; \
278 : if (object) { \
279 : if (ZEND_NUM_ARGS()) { \
280 : WRONG_PARAM_COUNT; \
281 : } \
282 : } else { \
283 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, date_ce_date) == FAILURE) { \
284 : RETURN_FALSE; \
285 : } \
286 : } \
287 : obj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); \
288 :
289 : #define DATE_CHECK_INITIALIZED(member, class_name) \
290 : if (!(member)) { \
291 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
292 : RETURN_FALSE; \
293 : }
294 :
295 : static void date_object_free_storage_date(void *object TSRMLS_DC);
296 : static void date_object_free_storage_timezone(void *object TSRMLS_DC);
297 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
298 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
299 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
300 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
301 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
302 :
303 : /* This is need to ensure that session extension request shutdown occurs 1st, because it uses the date extension */
304 : static zend_module_dep date_deps[] = {
305 : ZEND_MOD_OPTIONAL("session")
306 : {NULL, NULL, NULL}
307 : };
308 :
309 : /* {{{ Module struct */
310 : zend_module_entry date_module_entry = {
311 : STANDARD_MODULE_HEADER_EX,
312 : NULL,
313 : date_deps,
314 : "date", /* extension name */
315 : date_functions, /* function list */
316 : PHP_MINIT(date), /* process startup */
317 : PHP_MSHUTDOWN(date), /* process shutdown */
318 : PHP_RINIT(date), /* request startup */
319 : PHP_RSHUTDOWN(date), /* request shutdown */
320 : PHP_MINFO(date), /* extension info */
321 : PHP_VERSION, /* extension version */
322 : PHP_MODULE_GLOBALS(date), /* globals descriptor */
323 : PHP_GINIT(date), /* globals ctor */
324 : NULL, /* globals dtor */
325 : NULL, /* post deactivate */
326 : STANDARD_MODULE_PROPERTIES_EX
327 : };
328 : /* }}} */
329 :
330 :
331 : /* {{{ PHP_GINIT_FUNCTION */
332 : static PHP_GINIT_FUNCTION(date)
333 220 : {
334 220 : date_globals->default_timezone = NULL;
335 220 : date_globals->timezone = NULL;
336 220 : }
337 : /* }}} */
338 :
339 :
340 : static void _php_date_tzinfo_dtor(void *tzinfo)
341 2 : {
342 2 : timelib_tzinfo **tzi = (timelib_tzinfo **)tzinfo;
343 :
344 2 : timelib_tzinfo_dtor(*tzi);
345 2 : }
346 :
347 : /* {{{ PHP_RINIT_FUNCTION */
348 : PHP_RINIT_FUNCTION(date)
349 219 : {
350 219 : if (DATEG(timezone)) {
351 0 : efree(DATEG(timezone));
352 : }
353 219 : DATEG(timezone) = NULL;
354 219 : zend_hash_init(&DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
355 :
356 219 : return SUCCESS;
357 : }
358 : /* }}} */
359 :
360 : /* {{{ PHP_RSHUTDOWN_FUNCTION */
361 : PHP_RSHUTDOWN_FUNCTION(date)
362 219 : {
363 219 : if (DATEG(timezone)) {
364 0 : efree(DATEG(timezone));
365 : }
366 219 : DATEG(timezone) = NULL;
367 219 : zend_hash_destroy(&DATEG(tzcache));
368 :
369 219 : return SUCCESS;
370 : }
371 : /* }}} */
372 :
373 : #define DATE_TIMEZONEDB php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
374 :
375 : /*
376 : * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
377 : * date-time = [ day "," ] date time ; dd mm yy hh:mm:ss zzz
378 : * day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
379 : * date = 1*2DIGIT month 2DIGIT ; day month year e.g. 20 Jun 82
380 : * month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
381 : * time = hour zone ; ANSI and Military
382 : * hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
383 : * zone = "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" / "MST" / "MDT" / "PST" / "PDT" / 1ALPHA / ( ("+" / "-") 4DIGIT )
384 : */
385 : #define DATE_FORMAT_RFC822 "D, d M y H:i:s O"
386 :
387 : /*
388 : * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
389 : * Format must be acceptable both to the ARPANET and to the getdate routine.
390 : * One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
391 : * TIMEZONE can be any timezone name (3 or more letters)
392 : */
393 : #define DATE_FORMAT_RFC850 "l, d-M-y H:i:s T"
394 :
395 : /*
396 : * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
397 : * Its format must be acceptable both in RFC-822 and to the getdate(3)
398 : * Wdy, DD Mon YY HH:MM:SS TIMEZONE
399 : * There is no hope of having a complete list of timezones. Universal
400 : * Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
401 : * CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
402 : */
403 : #define DATE_FORMAT_RFC1036 "D, d M y H:i:s O"
404 :
405 : /*
406 : * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
407 : * RFC-822 Date and Time Specification: RFC-822 Section 5
408 : * The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
409 : */
410 : #define DATE_FORMAT_RFC1123 "D, d M Y H:i:s O"
411 :
412 : /*
413 : * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
414 : * FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
415 : * CFWS = *([FWS] comment) (([FWS] comment) / FWS)
416 : *
417 : * date-time = [ day-of-week "," ] date FWS time [CFWS]
418 : * day-of-week = ([FWS] day-name)
419 : * day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
420 : * date = day month year
421 : * year = 4*DIGIT
422 : * month = (FWS month-name FWS)
423 : * month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
424 : * day = ([FWS] 1*2DIGIT)
425 : * time = time-of-day FWS zone
426 : * time-of-day = hour ":" minute [ ":" second ]
427 : * hour = 2DIGIT
428 : * minute = 2DIGIT
429 : * second = 2DIGIT
430 : * zone = (( "+" / "-" ) 4DIGIT)
431 : */
432 : #define DATE_FORMAT_RFC2822 "D, d M Y H:i:s O"
433 : /*
434 : * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
435 : * date-fullyear = 4DIGIT
436 : * date-month = 2DIGIT ; 01-12
437 : * date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
438 : *
439 : * time-hour = 2DIGIT ; 00-23
440 : * time-minute = 2DIGIT ; 00-59
441 : * time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
442 : *
443 : * time-secfrac = "." 1*DIGIT
444 : * time-numoffset = ("+" / "-") time-hour ":" time-minute
445 : * time-offset = "Z" / time-numoffset
446 : *
447 : * partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
448 : * full-date = date-fullyear "-" date-month "-" date-mday
449 : * full-time = partial-time time-offset
450 : *
451 : * date-time = full-date "T" full-time
452 : */
453 : #define DATE_FORMAT_RFC3339 "Y-m-d\\TH:i:sP"
454 :
455 : #define DATE_FORMAT_ISO8601 "Y-m-d\\TH:i:sO"
456 :
457 : #define DATE_TZ_ERRMSG \
458 : "It is not safe to rely on the system's timezone settings. Please use " \
459 : "the date.timezone setting, the TZ environment variable or the " \
460 : "date_default_timezone_set() function. In case you used any of those " \
461 : "methods and you are still getting this warning, you most likely " \
462 : "misspelled the timezone identifier. "
463 :
464 : #define SUNFUNCS_RET_TIMESTAMP 0
465 : #define SUNFUNCS_RET_STRING 1
466 : #define SUNFUNCS_RET_DOUBLE 2
467 :
468 :
469 : /* {{{ PHP_MINIT_FUNCTION */
470 : PHP_MINIT_FUNCTION(date)
471 220 : {
472 220 : REGISTER_INI_ENTRIES();
473 220 : date_register_classes(TSRMLS_C);
474 : /*
475 : * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
476 : * A Date construct is an element whose content MUST conform to the
477 : * "date-time" production in [RFC3339]. In addition, an uppercase "T"
478 : * character MUST be used to separate date and time, and an uppercase
479 : * "Z" character MUST be present in the absence of a numeric time zone offset.
480 : */
481 220 : REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
482 : /*
483 : * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
484 : * "This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123,
485 : * with the variations that the only legal time zone is GMT
486 : * and the separators between the elements of the date must be dashes."
487 : */
488 220 : REGISTER_STRING_CONSTANT("DATE_COOKIE", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
489 220 : REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
490 220 : REGISTER_STRING_CONSTANT("DATE_RFC822", DATE_FORMAT_RFC822, CONST_CS | CONST_PERSISTENT);
491 220 : REGISTER_STRING_CONSTANT("DATE_RFC850", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
492 220 : REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
493 220 : REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
494 220 : REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
495 220 : REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
496 : /*
497 : * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
498 : * "All date-times in RSS conform to the Date and Time Specification of RFC 822,
499 : * with the exception that the year may be expressed with two characters or four characters (four preferred)"
500 : */
501 220 : REGISTER_STRING_CONSTANT("DATE_RSS", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
502 220 : REGISTER_STRING_CONSTANT("DATE_W3C", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
503 :
504 220 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
505 220 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
506 220 : REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
507 :
508 220 : php_date_global_timezone_db = NULL;
509 220 : php_date_global_timezone_db_enabled = 0;
510 :
511 220 : return SUCCESS;
512 : }
513 : /* }}} */
514 :
515 : /* {{{ PHP_MSHUTDOWN_FUNCTION */
516 : PHP_MSHUTDOWN_FUNCTION(date)
517 219 : {
518 219 : UNREGISTER_INI_ENTRIES();
519 :
520 219 : return SUCCESS;
521 : }
522 : /* }}} */
523 :
524 : /* {{{ PHP_MINFO_FUNCTION */
525 : PHP_MINFO_FUNCTION(date)
526 0 : {
527 0 : const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
528 :
529 0 : php_info_print_table_start();
530 0 : php_info_print_table_row(2, "date/time support", "enabled");
531 0 : php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
532 0 : php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
533 0 : php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb TSRMLS_CC));
534 0 : php_info_print_table_end();
535 :
536 0 : DISPLAY_INI_ENTRIES();
537 0 : }
538 : /* }}} */
539 :
540 : /* {{{ Timezone Cache functions */
541 : static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb TSRMLS_DC)
542 2 : {
543 : timelib_tzinfo *tzi, **ptzi;
544 :
545 2 : if (zend_hash_find(&DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void **) &ptzi) == SUCCESS) {
546 0 : return *ptzi;
547 : }
548 :
549 2 : tzi = timelib_parse_tzfile(formal_tzname, tzdb);
550 2 : if (tzi) {
551 2 : zend_hash_add(&DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void *) &tzi, sizeof(timelib_tzinfo*), NULL);
552 : }
553 2 : return tzi;
554 : }
555 : /* }}} */
556 :
557 : /* {{{ Helper functions */
558 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
559 2 : {
560 : char *env;
561 :
562 : /* Checking configure timezone */
563 2 : if (DATEG(timezone) && (strlen(DATEG(timezone)) > 0)) {
564 0 : return DATEG(timezone);
565 : }
566 : /* Check environment variable */
567 2 : env = getenv("TZ");
568 2 : if (env && *env && timelib_timezone_id_is_valid(env, tzdb)) {
569 0 : return env;
570 : }
571 : /* Check config setting for default timezone */
572 2 : if (DATEG(default_timezone) && (strlen(DATEG(default_timezone)) > 0) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
573 1 : return DATEG(default_timezone);
574 : }
575 : #if HAVE_TM_ZONE
576 : /* Try to guess timezone from system information */
577 : {
578 : struct tm *ta, tmbuf;
579 : time_t the_time;
580 : char *tzid;
581 :
582 1 : the_time = time(NULL);
583 1 : ta = php_localtime_r(&the_time, &tmbuf);
584 1 : tzid = timelib_timezone_id_from_abbr(ta->tm_zone, ta->tm_gmtoff, ta->tm_isdst);
585 1 : if (! tzid) {
586 0 : tzid = "UTC";
587 : }
588 :
589 1 : php_error_docref(NULL TSRMLS_CC, E_STRICT, DATE_TZ_ERRMSG "We selected '%s' for '%s/%.1f/%s' instead", tzid, ta->tm_zone, (float) (ta->tm_gmtoff / 3600), ta->tm_isdst ? "DST" : "no DST");
590 1 : return tzid;
591 : }
592 : #endif
593 : #ifdef PHP_WIN32
594 : {
595 : char *tzid;
596 : TIME_ZONE_INFORMATION tzi;
597 :
598 : switch (GetTimeZoneInformation(&tzi))
599 : {
600 : /* no DST or not in effect */
601 : case TIME_ZONE_ID_UNKNOWN:
602 : case TIME_ZONE_ID_STANDARD:
603 : php_win_std_time:
604 : tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.StandardBias) * -60, 0);
605 : if (! tzid) {
606 : tzid = "UTC";
607 : }
608 : php_error_docref(NULL TSRMLS_CC, E_STRICT, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/no DST' instead", tzid, ((tzi.Bias + tzi.StandardBias) / -60.0));
609 : break;
610 :
611 : /* DST in effect */
612 : case TIME_ZONE_ID_DAYLIGHT:
613 : /* If user has disabled DST in the control panel, Windows returns 0 here */
614 : if (tzi.DaylightBias == 0) {
615 : goto php_win_std_time;
616 : }
617 :
618 : tzid = timelib_timezone_id_from_abbr("", (tzi.Bias + tzi.DaylightBias) * -60, 1);
619 : if (! tzid) {
620 : tzid = "UTC";
621 : }
622 : php_error_docref(NULL TSRMLS_CC, E_STRICT, DATE_TZ_ERRMSG "We selected '%s' for '%.1f/DST' instead", tzid, ((tzi.Bias + tzi.DaylightBias) / -60.0));
623 : break;
624 : }
625 : return tzid;
626 : }
627 : #elif defined(NETWARE)
628 : /* Try to guess timezone from system information */
629 : {
630 : char *tzid = timelib_timezone_id_from_abbr("", ((_timezone * -1) + (daylightOffset * daylightOnOff)), daylightOnOff);
631 : if (tzid) {
632 : return tzid;
633 : }
634 : }
635 : #endif
636 : /* Fallback to UTC */
637 : 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");
638 : return "UTC";
639 : }
640 :
641 : PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
642 2 : {
643 : char *tz;
644 : timelib_tzinfo *tzi;
645 :
646 2 : tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
647 2 : tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
648 2 : if (! tzi) {
649 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
650 : }
651 2 : return tzi;
652 : }
653 : /* }}} */
654 :
655 :
656 : /* {{{ date() and gmdate() data */
657 : #include "ext/standard/php_smart_str.h"
658 :
659 : static char *mon_full_names[] = {
660 : "January", "February", "March", "April",
661 : "May", "June", "July", "August",
662 : "September", "October", "November", "December"
663 : };
664 :
665 : static char *mon_short_names[] = {
666 : "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
667 : };
668 :
669 : static char *day_full_names[] = {
670 : "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
671 : };
672 :
673 : static char *day_short_names[] = {
674 : "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
675 : };
676 :
677 : static char *english_suffix(timelib_sll number)
678 0 : {
679 0 : if (number >= 10 && number <= 19) {
680 0 : return "th";
681 : } else {
682 0 : switch (number % 10) {
683 0 : case 1: return "st";
684 0 : case 2: return "nd";
685 0 : case 3: return "rd";
686 : }
687 : }
688 0 : return "th";
689 : }
690 : /* }}} */
691 :
692 : /* {{{ day of week helpers */
693 : char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
694 0 : {
695 0 : timelib_sll day_of_week = timelib_day_of_week(y, m, d);
696 0 : if (day_of_week < 0) {
697 0 : return "Unknown";
698 : }
699 0 : return day_full_names[day_of_week];
700 : }
701 :
702 : char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
703 0 : {
704 0 : timelib_sll day_of_week = timelib_day_of_week(y, m, d);
705 0 : if (day_of_week < 0) {
706 0 : return "Unknown";
707 : }
708 0 : return day_short_names[day_of_week];
709 : }
710 : /* }}} */
711 :
712 : /* {{{ date_format - (gm)date helper */
713 : static char *date_format(char *format, int format_len, timelib_time *t, int localtime)
714 1 : {
715 1 : smart_str string = {0};
716 : int i, length;
717 : char buffer[33];
718 1 : timelib_time_offset *offset = NULL;
719 : timelib_sll isoweek, isoyear;
720 1 : int rfc_colon = 0;
721 :
722 1 : if (!format_len) {
723 0 : return estrdup("");
724 : }
725 :
726 1 : if (localtime) {
727 1 : if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
728 0 : offset = timelib_time_offset_ctor();
729 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
730 0 : offset->leap_secs = 0;
731 0 : offset->is_dst = t->dst;
732 0 : offset->abbr = strdup(t->tz_abbr);
733 1 : } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
734 0 : offset = timelib_time_offset_ctor();
735 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
736 0 : offset->leap_secs = 0;
737 0 : offset->is_dst = t->dst;
738 0 : offset->abbr = malloc(9); /* GMT±xxxx\0 */
739 0 : snprintf(offset->abbr, 9, "GMT%c%02d%02d",
740 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
741 : localtime ? abs(offset->offset / 3600) : 0,
742 : localtime ? abs((offset->offset % 3600) / 60) : 0 );
743 : } else {
744 1 : offset = timelib_get_time_zone_info(t->sse, t->tz_info);
745 : }
746 : }
747 1 : timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
748 :
749 7 : for (i = 0; i < format_len; i++) {
750 6 : switch (format[i]) {
751 : /* day */
752 1 : case 'd': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
753 0 : case 'D': length = slprintf(buffer, 32, "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
754 0 : case 'j': length = slprintf(buffer, 32, "%d", (int) t->d); break;
755 0 : case 'l': length = slprintf(buffer, 32, "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
756 0 : case 'S': length = slprintf(buffer, 32, "%s", english_suffix(t->d)); break;
757 0 : case 'w': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
758 0 : case 'N': length = slprintf(buffer, 32, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
759 0 : case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
760 :
761 : /* week */
762 0 : case 'W': length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */
763 0 : case 'o': length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */
764 :
765 : /* month */
766 0 : case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break;
767 1 : case 'm': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
768 0 : case 'M': length = slprintf(buffer, 32, "%s", mon_short_names[t->m - 1]); break;
769 0 : case 'n': length = slprintf(buffer, 32, "%d", (int) t->m); break;
770 0 : case 't': length = slprintf(buffer, 32, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
771 :
772 : /* year */
773 0 : case 'L': length = slprintf(buffer, 32, "%d", timelib_is_leap((int) t->y)); break;
774 0 : case 'y': length = slprintf(buffer, 32, "%02d", (int) t->y % 100); break;
775 1 : case 'Y': length = slprintf(buffer, 32, "%04d", (int) t->y); break;
776 :
777 : /* time */
778 0 : case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
779 0 : case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
780 : case 'B': {
781 0 : int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
782 0 : while (retval < 0) {
783 0 : retval += 1000;
784 : }
785 0 : retval = retval % 1000;
786 0 : length = slprintf(buffer, 32, "%03d", retval);
787 0 : break;
788 : }
789 0 : case 'g': length = slprintf(buffer, 32, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
790 0 : case 'G': length = slprintf(buffer, 32, "%d", (int) t->h); break;
791 0 : case 'h': length = slprintf(buffer, 32, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
792 1 : case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
793 1 : case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
794 0 : case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
795 :
796 : /* timezone */
797 0 : case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
798 0 : case 'P': rfc_colon = 1; /* break intentionally missing */
799 0 : case 'O': length = slprintf(buffer, 32, "%c%02d%s%02d",
800 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
801 : localtime ? abs(offset->offset / 3600) : 0,
802 : rfc_colon ? ":" : "",
803 : localtime ? abs((offset->offset % 3600) / 60) : 0
804 : );
805 0 : break;
806 0 : case 'T': length = slprintf(buffer, 32, "%s", localtime ? offset->abbr : "GMT"); break;
807 0 : case 'e': length = slprintf(buffer, 32, "%s", localtime ? t->tz_info->name : "UTC"); break;
808 0 : case 'Z': length = slprintf(buffer, 32, "%d", localtime ? offset->offset : 0); break;
809 :
810 : /* full date/time */
811 0 : case 'c': length = slprintf(buffer, 32, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
812 : (int) t->y, (int) t->m, (int) t->d,
813 : (int) t->h, (int) t->i, (int) t->s,
814 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
815 : localtime ? abs(offset->offset / 3600) : 0,
816 : localtime ? abs((offset->offset % 3600) / 60) : 0
817 : );
818 0 : break;
819 0 : case 'r': length = slprintf(buffer, 32, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
820 : php_date_short_day_name(t->y, t->m, t->d),
821 : (int) t->d, mon_short_names[t->m - 1],
822 : (int) t->y, (int) t->h, (int) t->i, (int) t->s,
823 : localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
824 : localtime ? abs(offset->offset / 3600) : 0,
825 : localtime ? abs((offset->offset % 3600) / 60) : 0
826 : );
827 0 : break;
828 0 : case 'U': length = slprintf(buffer, 32, "%lld", (timelib_sll) t->sse); break;
829 :
830 0 : case '\\': if (i < format_len) i++; /* break intentionally missing */
831 :
832 1 : default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
833 : }
834 6 : smart_str_appendl(&string, buffer, length);
835 : }
836 :
837 1 : smart_str_0(&string);
838 :
839 1 : if (localtime) {
840 1 : timelib_time_offset_dtor(offset);
841 : }
842 :
843 1 : return string.c;
844 : }
845 :
846 : static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
847 1 : {
848 : char *format;
849 : int format_len;
850 : long ts;
851 : char *string;
852 :
853 1 : if (ZEND_NUM_ARGS() == 1) {
854 1 : ts = time(NULL);
855 : }
856 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
857 0 : RETURN_FALSE;
858 : }
859 :
860 1 : string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
861 :
862 1 : RETVAL_STRING(string, 0);
863 : }
864 : /* }}} */
865 :
866 : PHPAPI char *php_format_date(char *format, int format_len, time_t ts, int localtime TSRMLS_DC) /* {{{ */
867 1 : {
868 : timelib_time *t;
869 : timelib_tzinfo *tzi;
870 : char *string;
871 :
872 1 : t = timelib_time_ctor();
873 :
874 1 : if (localtime) {
875 1 : tzi = get_timezone_info(TSRMLS_C);
876 1 : t->tz_info = tzi;
877 1 : t->zone_type = TIMELIB_ZONETYPE_ID;
878 1 : timelib_unixtime2local(t, ts);
879 : } else {
880 0 : tzi = NULL;
881 0 : timelib_unixtime2gmt(t, ts);
882 : }
883 :
884 1 : string = date_format(format, format_len, t, localtime);
885 :
886 1 : timelib_time_dtor(t);
887 1 : return string;
888 : }
889 : /* }}} */
890 :
891 : /* {{{ php_idate
892 : */
893 : PHPAPI int php_idate(char format, time_t ts, int localtime)
894 0 : {
895 : timelib_time *t;
896 : timelib_tzinfo *tzi;
897 0 : int retval = -1;
898 0 : timelib_time_offset *offset = NULL;
899 : timelib_sll isoweek, isoyear;
900 :
901 0 : t = timelib_time_ctor();
902 :
903 0 : if (!localtime) {
904 : TSRMLS_FETCH();
905 0 : tzi = get_timezone_info(TSRMLS_C);
906 0 : t->tz_info = tzi;
907 0 : t->zone_type = TIMELIB_ZONETYPE_ID;
908 0 : timelib_unixtime2local(t, ts);
909 : } else {
910 0 : tzi = NULL;
911 0 : timelib_unixtime2gmt(t, ts);
912 : }
913 :
914 0 : if (!localtime) {
915 0 : if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
916 0 : offset = timelib_time_offset_ctor();
917 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
918 0 : offset->leap_secs = 0;
919 0 : offset->is_dst = t->dst;
920 0 : offset->abbr = strdup(t->tz_abbr);
921 0 : } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
922 0 : offset = timelib_time_offset_ctor();
923 0 : offset->offset = (t->z - (t->dst * 60)) * -60;
924 0 : offset->leap_secs = 0;
925 0 : offset->is_dst = t->dst;
926 0 : offset->abbr = malloc(9); /* GMT±xxxx\0 */
927 0 : snprintf(offset->abbr, 9, "GMT%c%02d%02d",
928 : !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
929 : !localtime ? abs(offset->offset / 3600) : 0,
930 : !localtime ? abs((offset->offset % 3600) / 60) : 0 );
931 : } else {
932 0 : offset = timelib_get_time_zone_info(t->sse, t->tz_info);
933 : }
934 : }
935 :
936 0 : timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
937 :
938 0 : switch (format) {
939 : /* day */
940 0 : case 'd': case 'j': retval = (int) t->d; break;
941 :
942 0 : case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
943 0 : case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
944 :
945 : /* week */
946 0 : case 'W': retval = (int) isoweek; break; /* iso weeknr */
947 :
948 : /* month */
949 0 : case 'm': case 'n': retval = (int) t->m; break;
950 0 : case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
951 :
952 : /* year */
953 0 : case 'L': retval = (int) timelib_is_leap((int) t->y); break;
954 0 : case 'y': retval = (int) (t->y % 100); break;
955 0 : case 'Y': retval = (int) t->y; break;
956 :
957 : /* Swatch Beat a.k.a. Internet Time */
958 : case 'B':
959 0 : retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
960 0 : while (retval < 0) {
961 0 : retval += 1000;
962 : }
963 0 : retval = retval % 1000;
964 0 : break;
965 :
966 : /* time */
967 0 : case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
968 0 : case 'H': case 'G': retval = (int) t->h; break;
969 0 : case 'i': retval = (int) t->i; break;
970 0 : case 's': retval = (int) t->s; break;
971 :
972 : /* timezone */
973 0 : case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
974 0 : case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
975 :
976 0 : case 'U': retval = (int) t->sse; break;
977 : }
978 :
979 0 : if (!localtime) {
980 0 : timelib_time_offset_dtor(offset);
981 : }
982 0 : timelib_time_dtor(t);
983 :
984 0 : return retval;
985 : }
986 : /* }}} */
987 :
988 : /* {{{ proto string date(string format [, long timestamp])
989 : Format a local date/time */
990 : PHP_FUNCTION(date)
991 1 : {
992 1 : php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
993 1 : }
994 : /* }}} */
995 :
996 : /* {{{ proto string gmdate(string format [, long timestamp])
997 : Format a GMT date/time */
998 : PHP_FUNCTION(gmdate)
999 0 : {
1000 0 : php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1001 0 : }
1002 : /* }}} */
1003 :
1004 : /* {{{ proto int idate(string format [, int timestamp])
1005 : Format a local time/date as integer */
1006 : PHP_FUNCTION(idate)
1007 0 : {
1008 : char *format;
1009 : int format_len;
1010 : long ts;
1011 : int ret;
1012 :
1013 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
1014 0 : RETURN_FALSE;
1015 : }
1016 :
1017 0 : if (format_len != 1) {
1018 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
1019 0 : RETURN_FALSE;
1020 : }
1021 :
1022 0 : if (ZEND_NUM_ARGS() == 1) {
1023 0 : ts = time(NULL);
1024 : }
1025 :
1026 0 : ret = php_idate(format[0], ts, 0);
1027 0 : if (ret == -1) {
1028 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized date format token.");
1029 0 : RETURN_FALSE;
1030 : }
1031 0 : RETURN_LONG(ret);
1032 : }
1033 : /* }}} */
1034 :
1035 : /* {{{ php_date_set_tzdb - NOT THREADSAFE */
1036 : PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
1037 0 : {
1038 0 : const timelib_tzdb *builtin = timelib_builtin_db();
1039 :
1040 0 : if (php_version_compare(tzdb->version, builtin->version) > 0) {
1041 0 : php_date_global_timezone_db = tzdb;
1042 0 : php_date_global_timezone_db_enabled = 1;
1043 : }
1044 0 : }
1045 : /* }}} */
1046 :
1047 : /* {{{ php_parse_date: Backwards compability function */
1048 : PHPAPI signed long php_parse_date(char *string, signed long *now)
1049 0 : {
1050 : timelib_time *parsed_time;
1051 : int error2;
1052 : signed long retval;
1053 :
1054 0 : parsed_time = timelib_strtotime(string, strlen(string), NULL, DATE_TIMEZONEDB);
1055 0 : timelib_update_ts(parsed_time, NULL);
1056 0 : retval = timelib_date_to_int(parsed_time, &error2);
1057 0 : timelib_time_dtor(parsed_time);
1058 0 : if (error2) {
1059 0 : return -1;
1060 : }
1061 0 : return retval;
1062 : }
1063 : /* }}} */
1064 :
1065 :
1066 : /* {{{ proto int strtotime(string time [, int now ])
1067 : Convert string representation of date and time to a timestamp */
1068 : PHP_FUNCTION(strtotime)
1069 1 : {
1070 : char *times, *initial_ts;
1071 : int time_len, error1, error2;
1072 : struct timelib_error_container *error;
1073 : long preset_ts, ts;
1074 :
1075 : timelib_time *t, *now;
1076 : timelib_tzinfo *tzi;
1077 :
1078 1 : tzi = get_timezone_info(TSRMLS_C);
1079 :
1080 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sl", ×, &time_len, &preset_ts) != FAILURE) {
1081 : /* We have an initial timestamp */
1082 0 : now = timelib_time_ctor();
1083 :
1084 0 : initial_ts = emalloc(25);
1085 0 : snprintf(initial_ts, 24, "@%ld", preset_ts);
1086 0 : t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB); /* we ignore the error here, as this should never fail */
1087 0 : timelib_update_ts(t, tzi);
1088 0 : now->tz_info = tzi;
1089 0 : now->zone_type = TIMELIB_ZONETYPE_ID;
1090 0 : timelib_unixtime2local(now, t->sse);
1091 0 : timelib_time_dtor(t);
1092 0 : efree(initial_ts);
1093 1 : } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", ×, &time_len, &preset_ts) != FAILURE) {
1094 : /* We have no initial timestamp */
1095 1 : now = timelib_time_ctor();
1096 1 : now->tz_info = tzi;
1097 1 : now->zone_type = TIMELIB_ZONETYPE_ID;
1098 1 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1099 : } else {
1100 0 : RETURN_FALSE;
1101 : }
1102 :
1103 1 : if (!time_len) {
1104 0 : timelib_time_dtor(now);
1105 0 : RETURN_FALSE;
1106 : }
1107 :
1108 1 : t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB);
1109 1 : error1 = error->error_count;
1110 1 : timelib_error_container_dtor(error);
1111 1 : timelib_fill_holes(t, now, 0);
1112 1 : timelib_update_ts(t, tzi);
1113 1 : ts = timelib_date_to_int(t, &error2);
1114 :
1115 : /* if tz_info is not a copy, avoid double free */
1116 1 : if (now->tz_info != tzi && now->tz_info) {
1117 0 : timelib_tzinfo_dtor(now->tz_info);
1118 : }
1119 1 : if (t->tz_info != tzi) {
1120 1 : timelib_tzinfo_dtor(t->tz_info);
1121 : }
1122 :
1123 1 : timelib_time_dtor(now);
1124 1 : timelib_time_dtor(t);
1125 :
1126 1 : if (error1 || error2) {
1127 0 : RETURN_FALSE;
1128 : } else {
1129 1 : RETURN_LONG(ts);
1130 : }
1131 : }
1132 : /* }}} */
1133 :
1134 :
1135 : /* {{{ php_mktime - (gm)mktime helper */
1136 : PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1137 0 : {
1138 0 : long hou, min, sec, mon, day, yea, dst = -1;
1139 : timelib_time *now;
1140 0 : timelib_tzinfo *tzi = NULL;
1141 0 : long ts, adjust_seconds = 0;
1142 : int error;
1143 :
1144 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
1145 0 : RETURN_FALSE;
1146 : }
1147 : /* Initialize structure with current time */
1148 0 : now = timelib_time_ctor();
1149 0 : if (gmt) {
1150 0 : timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
1151 : } else {
1152 0 : tzi = get_timezone_info(TSRMLS_C);
1153 0 : now->tz_info = tzi;
1154 0 : now->zone_type = TIMELIB_ZONETYPE_ID;
1155 0 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1156 : }
1157 : /* Fill in the new data */
1158 0 : switch (ZEND_NUM_ARGS()) {
1159 : case 7:
1160 : /* break intentionally missing */
1161 : case 6:
1162 0 : if (yea >= 0 && yea < 70) {
1163 0 : yea += 2000;
1164 0 : } else if (yea >= 70 && yea <= 110) {
1165 0 : yea += 1900;
1166 : }
1167 0 : now->y = yea;
1168 : /* break intentionally missing again */
1169 : case 5:
1170 0 : now->d = day;
1171 : /* break missing intentionally here too */
1172 : case 4:
1173 0 : now->m = mon;
1174 : /* and here */
1175 : case 3:
1176 0 : now->s = sec;
1177 : /* yup, this break isn't here on purpose too */
1178 : case 2:
1179 0 : now->i = min;
1180 : /* last intentionally missing break */
1181 : case 1:
1182 0 : now->h = hou;
1183 0 : break;
1184 : default:
1185 0 : php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead");
1186 : }
1187 : /* Update the timestamp */
1188 0 : if (gmt) {
1189 0 : timelib_update_ts(now, NULL);
1190 : } else {
1191 0 : timelib_update_ts(now, tzi);
1192 : }
1193 : /* Support for the deprecated is_dst parameter */
1194 0 : if (dst != -1) {
1195 0 : php_error_docref(NULL TSRMLS_CC, E_STRICT, "The is_dst parameter is deprecated");
1196 0 : if (gmt) {
1197 : /* GMT never uses DST */
1198 0 : if (dst == 1) {
1199 0 : adjust_seconds = -3600;
1200 : }
1201 : } else {
1202 : /* Figure out is_dst for current TS */
1203 : timelib_time_offset *tmp_offset;
1204 0 : tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
1205 0 : if (dst == 1 && tmp_offset->is_dst == 0) {
1206 0 : adjust_seconds = -3600;
1207 : }
1208 0 : if (dst == 0 && tmp_offset->is_dst == 1) {
1209 0 : adjust_seconds = +3600;
1210 : }
1211 0 : timelib_time_offset_dtor(tmp_offset);
1212 : }
1213 : }
1214 : /* Clean up and return */
1215 0 : ts = timelib_date_to_int(now, &error);
1216 0 : ts += adjust_seconds;
1217 0 : timelib_time_dtor(now);
1218 :
1219 0 : if (error) {
1220 0 : RETURN_FALSE;
1221 : } else {
1222 0 : RETURN_LONG(ts);
1223 : }
1224 : }
1225 : /* }}} */
1226 :
1227 : /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
1228 : Get UNIX timestamp for a date */
1229 : PHP_FUNCTION(mktime)
1230 0 : {
1231 0 : php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1232 0 : }
1233 : /* }}} */
1234 :
1235 : /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
1236 : Get UNIX timestamp for a GMT date */
1237 : PHP_FUNCTION(gmmktime)
1238 0 : {
1239 0 : php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1240 0 : }
1241 : /* }}} */
1242 :
1243 :
1244 : /* {{{ proto bool checkdate(int month, int day, int year)
1245 : Returns true(1) if it is a valid date in gregorian calendar */
1246 : PHP_FUNCTION(checkdate)
1247 0 : {
1248 : long m, d, y;
1249 :
1250 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
1251 0 : RETURN_FALSE;
1252 : }
1253 :
1254 0 : if (y < 1 || y > 32767 || m < 1 || m > 12 || d < 1 || d > timelib_days_in_month(y, m)) {
1255 0 : RETURN_FALSE;
1256 : }
1257 0 : RETURN_TRUE; /* True : This month, day, year arguments are valid */
1258 : }
1259 : /* }}} */
1260 :
1261 : #ifdef HAVE_STRFTIME
1262 : /* {{{ php_strftime - (gm)strftime helper */
1263 : PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1264 0 : {
1265 : char *format, *buf;
1266 : int format_len;
1267 : long timestamp;
1268 : struct tm ta;
1269 0 : int max_reallocs = 5;
1270 0 : size_t buf_len = 64, real_len;
1271 : timelib_time *ts;
1272 : timelib_tzinfo *tzi;
1273 0 : timelib_time_offset *offset = NULL;
1274 :
1275 0 : timestamp = (long) time(NULL);
1276 :
1277 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, ×tamp) == FAILURE) {
1278 0 : RETURN_FALSE;
1279 : }
1280 :
1281 0 : if (format_len == 0) {
1282 0 : RETURN_FALSE;
1283 : }
1284 :
1285 0 : ts = timelib_time_ctor();
1286 0 : if (gmt) {
1287 0 : tzi = NULL;
1288 0 : timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
1289 : } else {
1290 0 : tzi = get_timezone_info(TSRMLS_C);
1291 0 : ts->tz_info = tzi;
1292 0 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1293 0 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1294 : }
1295 0 : ta.tm_sec = ts->s;
1296 0 : ta.tm_min = ts->i;
1297 0 : ta.tm_hour = ts->h;
1298 0 : ta.tm_mday = ts->d;
1299 0 : ta.tm_mon = ts->m - 1;
1300 0 : ta.tm_year = ts->y - 1900;
1301 0 : ta.tm_wday = timelib_day_of_week(ts->y, ts->m, ts->d);
1302 0 : ta.tm_yday = timelib_day_of_year(ts->y, ts->m, ts->d);
1303 0 : if (gmt) {
1304 0 : ta.tm_isdst = 0;
1305 : #if HAVE_TM_GMTOFF
1306 0 : ta.tm_gmtoff = 0;
1307 : #endif
1308 : #if HAVE_TM_ZONE
1309 0 : ta.tm_zone = "GMT";
1310 : #endif
1311 : } else {
1312 0 : offset = timelib_get_time_zone_info(timestamp, tzi);
1313 :
1314 0 : ta.tm_isdst = offset->is_dst;
1315 : #if HAVE_TM_GMTOFF
1316 0 : ta.tm_gmtoff = offset->offset;
1317 : #endif
1318 : #if HAVE_TM_ZONE
1319 0 : ta.tm_zone = offset->abbr;
1320 : #endif
1321 : }
1322 :
1323 0 : buf = (char *) emalloc(buf_len);
1324 0 : while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) {
1325 0 : buf_len *= 2;
1326 0 : buf = (char *) erealloc(buf, buf_len);
1327 0 : if (!--max_reallocs) {
1328 0 : break;
1329 : }
1330 : }
1331 :
1332 0 : timelib_time_dtor(ts);
1333 0 : if (!gmt) {
1334 0 : timelib_time_offset_dtor(offset);
1335 : }
1336 :
1337 0 : if (real_len && real_len != buf_len) {
1338 0 : buf = (char *) erealloc(buf, real_len + 1);
1339 0 : RETURN_STRINGL(buf, real_len, 0);
1340 : }
1341 0 : efree(buf);
1342 0 : RETURN_FALSE;
1343 : }
1344 : /* }}} */
1345 :
1346 : /* {{{ proto string strftime(string format [, int timestamp])
1347 : Format a local time/date according to locale settings */
1348 : PHP_FUNCTION(strftime)
1349 0 : {
1350 0 : php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1351 0 : }
1352 : /* }}} */
1353 :
1354 : /* {{{ proto string gmstrftime(string format [, int timestamp])
1355 : Format a GMT/UCT time/date according to locale settings */
1356 : PHP_FUNCTION(gmstrftime)
1357 0 : {
1358 0 : php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1359 0 : }
1360 : /* }}} */
1361 : #endif
1362 :
1363 : /* {{{ proto int time(void)
1364 : Return current UNIX timestamp */
1365 : PHP_FUNCTION(time)
1366 3 : {
1367 3 : RETURN_LONG((long)time(NULL));
1368 : }
1369 : /* }}} */
1370 :
1371 : /* {{{ proto array localtime([int timestamp [, bool associative_array]])
1372 : 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 */
1373 : PHP_FUNCTION(localtime)
1374 0 : {
1375 0 : long timestamp = (long)time(NULL);
1376 0 : zend_bool associative = 0;
1377 : timelib_tzinfo *tzi;
1378 : timelib_time *ts;
1379 :
1380 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", ×tamp, &associative) == FAILURE) {
1381 0 : RETURN_FALSE;
1382 : }
1383 :
1384 0 : tzi = get_timezone_info(TSRMLS_C);
1385 0 : ts = timelib_time_ctor();
1386 0 : ts->tz_info = tzi;
1387 0 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1388 0 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1389 :
1390 0 : array_init(return_value);
1391 :
1392 0 : if (associative) {
1393 0 : add_assoc_long(return_value, "tm_sec", ts->s);
1394 0 : add_assoc_long(return_value, "tm_min", ts->i);
1395 0 : add_assoc_long(return_value, "tm_hour", ts->h);
1396 0 : add_assoc_long(return_value, "tm_mday", ts->d);
1397 0 : add_assoc_long(return_value, "tm_mon", ts->m - 1);
1398 0 : add_assoc_long(return_value, "tm_year", ts->y - 1900);
1399 0 : add_assoc_long(return_value, "tm_wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1400 0 : add_assoc_long(return_value, "tm_yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1401 0 : add_assoc_long(return_value, "tm_isdst", ts->dst);
1402 : } else {
1403 0 : add_next_index_long(return_value, ts->s);
1404 0 : add_next_index_long(return_value, ts->i);
1405 0 : add_next_index_long(return_value, ts->h);
1406 0 : add_next_index_long(return_value, ts->d);
1407 0 : add_next_index_long(return_value, ts->m - 1);
1408 0 : add_next_index_long(return_value, ts->y- 1900);
1409 0 : add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
1410 0 : add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
1411 0 : add_next_index_long(return_value, ts->dst);
1412 : }
1413 :
1414 0 : timelib_time_dtor(ts);
1415 : }
1416 : /* }}} */
1417 :
1418 : /* {{{ proto array getdate([int timestamp])
1419 : Get date/time information */
1420 : PHP_FUNCTION(getdate)
1421 0 : {
1422 0 : long timestamp = (long)time(NULL);
1423 : timelib_tzinfo *tzi;
1424 : timelib_time *ts;
1425 :
1426 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", ×tamp) == FAILURE) {
1427 0 : RETURN_FALSE;
1428 : }
1429 :
1430 0 : tzi = get_timezone_info(TSRMLS_C);
1431 0 : ts = timelib_time_ctor();
1432 0 : ts->tz_info = tzi;
1433 0 : ts->zone_type = TIMELIB_ZONETYPE_ID;
1434 0 : timelib_unixtime2local(ts, (timelib_sll) timestamp);
1435 :
1436 0 : array_init(return_value);
1437 :
1438 0 : add_assoc_long(return_value, "seconds", ts->s);
1439 0 : add_assoc_long(return_value, "minutes", ts->i);
1440 0 : add_assoc_long(return_value, "hours", ts->h);
1441 0 : add_assoc_long(return_value, "mday", ts->d);
1442 0 : add_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
1443 0 : add_assoc_long(return_value, "mon", ts->m);
1444 0 : add_assoc_long(return_value, "year", ts->y);
1445 0 : add_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
1446 0 : add_assoc_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d), 1);
1447 0 : add_assoc_string(return_value, "month", mon_full_names[ts->m - 1], 1);
1448 0 : add_index_long(return_value, 0, timestamp);
1449 :
1450 0 : timelib_time_dtor(ts);
1451 : }
1452 : /* }}} */
1453 :
1454 : static void date_register_classes(TSRMLS_D)
1455 220 : {
1456 : zend_class_entry ce_date, ce_timezone;
1457 :
1458 220 : INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
1459 220 : ce_date.create_object = date_object_new_date;
1460 220 : date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC);
1461 220 : memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1462 220 : date_object_handlers_date.clone_obj = date_object_clone_date;
1463 220 : date_object_handlers_date.compare_objects = date_object_compare_date;
1464 :
1465 : #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
1466 : zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
1467 :
1468 220 : REGISTER_DATE_CLASS_CONST_STRING("ATOM", DATE_FORMAT_RFC3339);
1469 220 : REGISTER_DATE_CLASS_CONST_STRING("COOKIE", DATE_FORMAT_RFC850);
1470 220 : REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
1471 220 : REGISTER_DATE_CLASS_CONST_STRING("RFC822", DATE_FORMAT_RFC822);
1472 220 : REGISTER_DATE_CLASS_CONST_STRING("RFC850", DATE_FORMAT_RFC850);
1473 220 : REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
1474 220 : REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
1475 220 : REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
1476 220 : REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
1477 220 : REGISTER_DATE_CLASS_CONST_STRING("RSS", DATE_FORMAT_RFC1123);
1478 220 : REGISTER_DATE_CLASS_CONST_STRING("W3C", DATE_FORMAT_RFC3339);
1479 :
1480 :
1481 220 : INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
1482 220 : ce_timezone.create_object = date_object_new_timezone;
1483 220 : date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC);
1484 220 : memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1485 220 : date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
1486 220 : }
1487 :
1488 : static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
1489 0 : {
1490 : php_date_obj *intern;
1491 : zend_object_value retval;
1492 : zval *tmp;
1493 :
1494 0 : intern = emalloc(sizeof(php_date_obj));
1495 0 : memset(intern, 0, sizeof(php_date_obj));
1496 0 : if (ptr) {
1497 0 : *ptr = intern;
1498 : }
1499 :
1500 0 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1501 0 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
1502 :
1503 0 : 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);
1504 0 : retval.handlers = &date_object_handlers_date;
1505 :
1506 0 : return retval;
1507 : }
1508 :
1509 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC)
1510 0 : {
1511 0 : return date_object_new_date_ex(class_type, NULL TSRMLS_CC);
1512 : }
1513 :
1514 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
1515 0 : {
1516 0 : php_date_obj *new_obj = NULL;
1517 0 : php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
1518 0 : zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
1519 :
1520 0 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
1521 :
1522 : /* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
1523 0 : new_obj->time = timelib_time_ctor();
1524 0 : *new_obj->time = *old_obj->time;
1525 0 : if (old_obj->time->tz_abbr) {
1526 0 : new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
1527 : }
1528 0 : if (old_obj->time->tz_info) {
1529 0 : new_obj->time->tz_info = timelib_tzinfo_clone(old_obj->time->tz_info);
1530 : }
1531 :
1532 0 : return new_ov;
1533 : }
1534 :
1535 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC)
1536 0 : {
1537 0 : if (Z_TYPE_P(d1) == IS_OBJECT && Z_TYPE_P(d2) == IS_OBJECT &&
1538 : instanceof_function(Z_OBJCE_P(d1), date_ce_date TSRMLS_CC) &&
1539 : instanceof_function(Z_OBJCE_P(d2), date_ce_date TSRMLS_CC)) {
1540 0 : php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC);
1541 0 : php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC);
1542 :
1543 0 : if (!o1->time->sse_uptodate) {
1544 0 : timelib_update_ts(o1->time, o1->time->tz_info);
1545 : }
1546 0 : if (!o2->time->sse_uptodate) {
1547 0 : timelib_update_ts(o2->time, o2->time->tz_info);
1548 : }
1549 :
1550 0 : return (o1->time->sse == o2->time->sse) ? 0 : ((o1->time->sse < o2->time->sse) ? -1 : 1);
1551 : }
1552 :
1553 0 : return 1;
1554 : }
1555 :
1556 : static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC)
1557 0 : {
1558 : php_timezone_obj *intern;
1559 : zend_object_value retval;
1560 : zval *tmp;
1561 :
1562 0 : intern = emalloc(sizeof(php_timezone_obj));
1563 0 : memset(intern, 0, sizeof(php_timezone_obj));
1564 0 : if (ptr) {
1565 0 : *ptr = intern;
1566 : }
1567 :
1568 0 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1569 0 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
1570 :
1571 0 : 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);
1572 0 : retval.handlers = &date_object_handlers_timezone;
1573 :
1574 0 : return retval;
1575 : }
1576 :
1577 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC)
1578 0 : {
1579 0 : return date_object_new_timezone_ex(class_type, NULL TSRMLS_CC);
1580 : }
1581 :
1582 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
1583 0 : {
1584 0 : php_timezone_obj *new_obj = NULL;
1585 0 : php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
1586 0 : zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
1587 :
1588 0 : zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
1589 0 : new_obj->tz = old_obj->tz;
1590 :
1591 0 : return new_ov;
1592 : }
1593 :
1594 : static void date_object_free_storage_date(void *object TSRMLS_DC)
1595 0 : {
1596 0 : php_date_obj *intern = (php_date_obj *)object;
1597 :
1598 0 : if (intern->time) {
1599 0 : if (intern->time->tz_info) {
1600 0 : timelib_tzinfo_dtor(intern->time->tz_info);
1601 : }
1602 0 : timelib_time_dtor(intern->time);
1603 : }
1604 :
1605 0 : zend_object_std_dtor(&intern->std TSRMLS_CC);
1606 0 : efree(object);
1607 0 : }
1608 :
1609 : static void date_object_free_storage_timezone(void *object TSRMLS_DC)
1610 0 : {
1611 0 : php_timezone_obj *intern = (php_timezone_obj *)object;
1612 :
1613 0 : zend_object_std_dtor(&intern->std TSRMLS_CC);
1614 0 : efree(object);
1615 0 : }
1616 :
1617 : /* Advanced Interface */
1618 : static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
1619 0 : {
1620 0 : if (!object) {
1621 0 : ALLOC_ZVAL(object);
1622 : }
1623 :
1624 0 : Z_TYPE_P(object) = IS_OBJECT;
1625 0 : object_init_ex(object, pce);
1626 0 : object->refcount = 1;
1627 0 : object->is_ref = 0;
1628 0 : return object;
1629 : }
1630 :
1631 : static void date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, zval *timezone_object TSRMLS_DC)
1632 0 : {
1633 : timelib_time *now;
1634 : timelib_tzinfo *tzi;
1635 0 : timelib_error_container *err = NULL;
1636 0 : int free_tzi = 0;
1637 :
1638 0 : if (dateobj->time) {
1639 0 : if (dateobj->time->tz_info) {
1640 0 : timelib_tzinfo_dtor(dateobj->time->tz_info);
1641 : }
1642 0 : timelib_time_dtor(dateobj->time);
1643 : }
1644 0 : dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB);
1645 0 : if (err) {
1646 0 : if (err->error_count) {
1647 : /* spit out the first library error message, at least */
1648 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
1649 : err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
1650 : }
1651 0 : timelib_error_container_dtor(err);
1652 : }
1653 :
1654 0 : if (timezone_object) {
1655 : php_timezone_obj *tzobj;
1656 :
1657 0 : tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
1658 0 : tzi = timelib_tzinfo_clone(tzobj->tz);
1659 0 : free_tzi = 1;
1660 0 : } else if (dateobj->time->tz_info) {
1661 0 : tzi = timelib_tzinfo_clone(dateobj->time->tz_info);
1662 0 : free_tzi = 1;
1663 : } else {
1664 0 : tzi = get_timezone_info(TSRMLS_C);
1665 : }
1666 :
1667 0 : now = timelib_time_ctor();
1668 0 : now->tz_info = tzi;
1669 0 : now->zone_type = TIMELIB_ZONETYPE_ID;
1670 0 : timelib_unixtime2local(now, (timelib_sll) time(NULL));
1671 :
1672 0 : timelib_fill_holes(dateobj->time, now, 0);
1673 0 : timelib_update_ts(dateobj->time, tzi);
1674 :
1675 0 : dateobj->time->have_weekday_relative = dateobj->time->have_relative = 0;
1676 :
1677 0 : if (now->tz_info != tzi) {
1678 0 : timelib_tzinfo_dtor(now->tz_info);
1679 : }
1680 0 : if (free_tzi) {
1681 0 : timelib_tzinfo_dtor(tzi);
1682 : }
1683 0 : timelib_time_dtor(now);
1684 0 : }
1685 :
1686 : /* {{{ proto DateTime date_create([string time[, DateTimeZone object]])
1687 : Returns new DateTime object
1688 : */
1689 : PHP_FUNCTION(date_create)
1690 0 : {
1691 0 : zval *timezone_object = NULL;
1692 0 : char *time_str = NULL;
1693 0 : int time_str_len = 0;
1694 :
1695 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
1696 0 : RETURN_FALSE;
1697 : }
1698 :
1699 0 : date_instantiate(date_ce_date, return_value TSRMLS_CC);
1700 0 : date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, timezone_object TSRMLS_CC);
1701 : }
1702 : /* }}} */
1703 :
1704 : /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
1705 : Creates new DateTime object
1706 : */
1707 : PHP_METHOD(DateTime, __construct)
1708 0 : {
1709 0 : zval *timezone_object = NULL;
1710 0 : char *time_str = NULL;
1711 0 : int time_str_len = 0;
1712 :
1713 0 : php_set_error_handling(EH_THROW, NULL TSRMLS_CC);
1714 0 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
1715 0 : date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, timezone_object TSRMLS_CC);
1716 : }
1717 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
1718 0 : }
1719 : /* }}} */
1720 :
1721 : /* {{{ proto array date_parse(string date)
1722 : Returns associative array with detailed info about given date
1723 : */
1724 : PHP_FUNCTION(date_parse)
1725 0 : {
1726 : char *date;
1727 : int date_len, i;
1728 : struct timelib_error_container *error;
1729 : timelib_time *parsed_time;
1730 : zval *element;
1731 :
1732 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
1733 0 : RETURN_FALSE;
1734 : }
1735 :
1736 0 : parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB);
1737 0 : array_init(return_value);
1738 : #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
1739 : if (parsed_time->elem == -1) { \
1740 : add_assoc_bool(return_value, #name, 0); \
1741 : } else { \
1742 : add_assoc_long(return_value, #name, parsed_time->elem); \
1743 : }
1744 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year, y);
1745 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month, m);
1746 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day, d);
1747 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour, h);
1748 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute, i);
1749 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second, s);
1750 :
1751 0 : if (parsed_time->f == -1) {
1752 0 : add_assoc_bool(return_value, "fraction", 0);
1753 : } else {
1754 0 : add_assoc_double(return_value, "fraction", parsed_time->f);
1755 : }
1756 :
1757 0 : add_assoc_long(return_value, "warning_count", error->warning_count);
1758 0 : MAKE_STD_ZVAL(element);
1759 0 : array_init(element);
1760 0 : for (i = 0; i < error->warning_count; i++) {
1761 0 : add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
1762 : }
1763 0 : add_assoc_zval(return_value, "warnings", element);
1764 :
1765 0 : add_assoc_long(return_value, "error_count", error->error_count);
1766 0 : MAKE_STD_ZVAL(element);
1767 0 : array_init(element);
1768 0 : for (i = 0; i < error->error_count; i++) {
1769 0 : add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
1770 : }
1771 0 : add_assoc_zval(return_value, "errors", element);
1772 0 : timelib_error_container_dtor(error);
1773 :
1774 0 : add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
1775 :
1776 0 : if (parsed_time->is_localtime) {
1777 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
1778 0 : switch (parsed_time->zone_type) {
1779 : case TIMELIB_ZONETYPE_OFFSET:
1780 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
1781 0 : add_assoc_bool(return_value, "is_dst", parsed_time->dst);
1782 0 : break;
1783 : case TIMELIB_ZONETYPE_ID:
1784 0 : if (parsed_time->tz_abbr) {
1785 0 : add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
1786 : }
1787 0 : if (parsed_time->tz_info) {
1788 0 : add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
1789 : }
1790 0 : break;
1791 : case TIMELIB_ZONETYPE_ABBR:
1792 0 : PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
1793 0 : add_assoc_bool(return_value, "is_dst", parsed_time->dst);
1794 0 : add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
1795 : break;
1796 : }
1797 : }
1798 0 : if (parsed_time->have_relative || parsed_time->have_weekday_relative) {
1799 0 : MAKE_STD_ZVAL(element);
1800 0 : array_init(element);
1801 : }
1802 0 : if (parsed_time->have_relative) {
1803 0 : add_assoc_long(element, "year", parsed_time->relative.y);
1804 0 : add_assoc_long(element, "month", parsed_time->relative.m);
1805 0 : add_assoc_long(element, "day", parsed_time->relative.d);
1806 0 : add_assoc_long(element, "hour", parsed_time->relative.h);
1807 0 : add_assoc_long(element, "minute", parsed_time->relative.i);
1808 0 : add_assoc_long(element, "second", parsed_time->relative.s);
1809 : }
1810 0 : if (parsed_time->have_weekday_relative) {
1811 0 : add_assoc_long(element, "weekday", parsed_time->relative.weekday);
1812 : }
1813 0 : if (parsed_time->have_relative || parsed_time->have_weekday_relative) {
1814 0 : add_assoc_zval(return_value, "relative", element);
1815 : }
1816 0 : timelib_time_dtor(parsed_time);
1817 : }
1818 : /* }}} */
1819 :
1820 : /* {{{ proto string date_format(DateTime object, string format)
1821 : Returns date formatted according to given format
1822 : */
1823 : PHP_FUNCTION(date_format)
1824 0 : {
1825 : zval *object;
1826 : php_date_obj *dateobj;
1827 : char *format;
1828 : int format_len;
1829 :
1830 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &format, &format_len) == FAILURE) {
1831 0 : RETURN_FALSE;
1832 : }
1833 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1834 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1835 0 : RETURN_STRING(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime), 0);
1836 : }
1837 : /* }}} */
1838 :
1839 : /* {{{ proto void date_modify(DateTime object, string modify)
1840 : Alters the timestamp.
1841 : */
1842 : PHP_FUNCTION(date_modify)
1843 0 : {
1844 : zval *object;
1845 : php_date_obj *dateobj;
1846 : char *modify;
1847 : int modify_len;
1848 : timelib_time *tmp_time;
1849 :
1850 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
1851 0 : RETURN_FALSE;
1852 : }
1853 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1854 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1855 :
1856 0 : tmp_time = timelib_strtotime(modify, modify_len, NULL, DATE_TIMEZONEDB);
1857 0 : dateobj->time->relative.y = tmp_time->relative.y;
1858 0 : dateobj->time->relative.m = tmp_time->relative.m;
1859 0 : dateobj->time->relative.d = tmp_time->relative.d;
1860 0 : dateobj->time->relative.h = tmp_time->relative.h;
1861 0 : dateobj->time->relative.i = tmp_time->relative.i;
1862 0 : dateobj->time->relative.s = tmp_time->relative.s;
1863 0 : dateobj->time->relative.weekday = tmp_time->relative.weekday;
1864 0 : dateobj->time->have_relative = tmp_time->have_relative;
1865 0 : dateobj->time->have_weekday_relative = tmp_time->have_weekday_relative;
1866 0 : dateobj->time->sse_uptodate = 0;
1867 0 : timelib_time_dtor(tmp_time);
1868 :
1869 0 : timelib_update_ts(dateobj->time, NULL);
1870 0 : timelib_update_from_sse(dateobj->time);
1871 : }
1872 : /* }}} */
1873 :
1874 : /* {{{ proto DateTimeZone date_timezone_get(DateTime object)
1875 : Return new DateTimeZone object relative to give DateTime
1876 : */
1877 : PHP_FUNCTION(date_timezone_get)
1878 0 : {
1879 : zval *object;
1880 : php_date_obj *dateobj;
1881 : php_timezone_obj *tzobj;
1882 :
1883 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
1884 0 : RETURN_FALSE;
1885 : }
1886 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1887 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1888 0 : if (dateobj->time->is_localtime && dateobj->time->tz_info) {
1889 0 : date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
1890 0 : tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
1891 0 : tzobj->tz = timelib_tzinfo_clone(dateobj->time->tz_info);
1892 : } else {
1893 0 : RETURN_FALSE;
1894 : }
1895 : }
1896 : /* }}} */
1897 :
1898 : /* {{{ proto void date_timezone_set(DateTime object, DateTimeZone object)
1899 : Sets the timezone for the DateTime object.
1900 : */
1901 : PHP_FUNCTION(date_timezone_set)
1902 0 : {
1903 : zval *object;
1904 : zval *timezone_object;
1905 : php_date_obj *dateobj;
1906 : php_timezone_obj *tzobj;
1907 :
1908 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
1909 0 : RETURN_FALSE;
1910 : }
1911 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1912 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1913 0 : tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
1914 0 : if (dateobj->time->tz_info) {
1915 0 : timelib_tzinfo_dtor(dateobj->time->tz_info);
1916 : }
1917 0 : timelib_set_timezone(dateobj->time, timelib_tzinfo_clone(tzobj->tz));
1918 0 : timelib_unixtime2local(dateobj->time, dateobj->time->sse);
1919 : }
1920 : /* }}} */
1921 :
1922 : /* {{{ proto long date_offset_get(DateTime object)
1923 : Returns the DST offset.
1924 : */
1925 : PHP_FUNCTION(date_offset_get)
1926 0 : {
1927 : zval *object;
1928 : php_date_obj *dateobj;
1929 : timelib_time_offset *offset;
1930 :
1931 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_date) == FAILURE) {
1932 0 : RETURN_FALSE;
1933 : }
1934 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1935 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1936 0 : if (dateobj->time->is_localtime && dateobj->time->tz_info) {
1937 0 : offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
1938 0 : RETVAL_LONG(offset->offset);
1939 0 : timelib_time_offset_dtor(offset);
1940 0 : return;
1941 : } else {
1942 0 : RETURN_LONG(0);
1943 : }
1944 : }
1945 : /* }}} */
1946 :
1947 : /* {{{ proto void date_time_set(DateTime object, long hour, long minute[, long second])
1948 : Sets the time.
1949 : */
1950 : PHP_FUNCTION(date_time_set)
1951 0 : {
1952 : zval *object;
1953 : php_date_obj *dateobj;
1954 0 : long h, i, s = 0;
1955 :
1956 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
1957 0 : RETURN_FALSE;
1958 : }
1959 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1960 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1961 0 : dateobj->time->h = h;
1962 0 : dateobj->time->i = i;
1963 0 : dateobj->time->s = s;
1964 0 : timelib_update_ts(dateobj->time, NULL);
1965 : }
1966 : /* }}} */
1967 :
1968 : /* {{{ proto void date_date_set(DateTime object, long year, long month, long day)
1969 : Sets the date.
1970 : */
1971 : PHP_FUNCTION(date_date_set)
1972 0 : {
1973 : zval *object;
1974 : php_date_obj *dateobj;
1975 : long y, m, d;
1976 :
1977 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
1978 0 : RETURN_FALSE;
1979 : }
1980 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
1981 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
1982 0 : dateobj->time->y = y;
1983 0 : dateobj->time->m = m;
1984 0 : dateobj->time->d = d;
1985 0 : timelib_update_ts(dateobj->time, NULL);
1986 : }
1987 : /* }}} */
1988 :
1989 : /* {{{ proto void date_isodate_set(DateTime object, long year, long week[, long day])
1990 : Sets the ISO date.
1991 : */
1992 : PHP_FUNCTION(date_isodate_set)
1993 0 : {
1994 : zval *object;
1995 : php_date_obj *dateobj;
1996 0 : long y, w, d = 1;
1997 :
1998 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
1999 0 : RETURN_FALSE;
2000 : }
2001 0 : dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
2002 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2003 0 : dateobj->time->y = y;
2004 0 : dateobj->time->m = 1;
2005 0 : dateobj->time->d = 1;
2006 0 : dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
2007 0 : dateobj->time->have_relative = 1;
2008 :
2009 0 : timelib_update_ts(dateobj->time, NULL);
2010 : }
2011 : /* }}} */
2012 :
2013 : static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC)
2014 0 : {
2015 : char *tzid;
2016 :
2017 0 : *tzi = NULL;
2018 :
2019 0 : if ((tzid = timelib_timezone_id_from_abbr(tz, -1, 0))) {
2020 0 : *tzi = php_date_parse_tzfile(tzid, DATE_TIMEZONEDB TSRMLS_CC);
2021 : } else {
2022 0 : *tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
2023 : }
2024 :
2025 0 : if (*tzi) {
2026 0 : return SUCCESS;
2027 : } else {
2028 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", tz);
2029 0 : return FAILURE;
2030 : }
2031 : }
2032 :
2033 : /* {{{ proto DateTimeZone timezone_open(string timezone)
2034 : Returns new DateTimeZone object
2035 : */
2036 : PHP_FUNCTION(timezone_open)
2037 0 : {
2038 : char *tz;
2039 : int tz_len;
2040 0 : timelib_tzinfo *tzi = NULL;
2041 :
2042 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) {
2043 0 : RETURN_FALSE;
2044 : }
2045 0 : if (SUCCESS != timezone_initialize(&tzi, tz TSRMLS_CC)) {
2046 0 : RETURN_FALSE;
2047 : }
2048 0 : ((php_timezone_obj *) zend_object_store_get_object(date_instantiate(date_ce_timezone, return_value TSRMLS_CC) TSRMLS_CC))->tz = tzi;
2049 : }
2050 : /* }}} */
2051 :
2052 : /* {{{ proto DateTimeZone::__construct(string timezone)
2053 : Creates new DateTimeZone object.
2054 : */
2055 : PHP_METHOD(DateTimeZone, __construct)
2056 0 : {
2057 : char *tz;
2058 : int tz_len;
2059 0 : timelib_tzinfo *tzi = NULL;
2060 :
2061 0 : php_set_error_handling(EH_THROW, NULL TSRMLS_CC);
2062 0 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
2063 0 : if (SUCCESS == timezone_initialize(&tzi, tz TSRMLS_CC)) {
2064 0 : ((php_timezone_obj *) zend_object_store_get_object(getThis() TSRMLS_CC))->tz = tzi;
2065 : }
2066 : }
2067 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
2068 0 : }
2069 : /* }}} */
2070 :
2071 : /* {{{ proto string timezone_name_get(DateTimeZone object)
2072 : Returns the name of the timezone.
2073 : */
2074 : PHP_FUNCTION(timezone_name_get)
2075 0 : {
2076 : zval *object;
2077 : php_timezone_obj *tzobj;
2078 :
2079 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
2080 0 : RETURN_FALSE;
2081 : }
2082 0 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
2083 0 : DATE_CHECK_INITIALIZED(tzobj->tz, DateTimeZone);
2084 :
2085 0 : RETURN_STRING(tzobj->tz->name, 1);
2086 : }
2087 : /* }}} */
2088 :
2089 : /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]])
2090 : Returns the timezone name from abbrevation
2091 : */
2092 : PHP_FUNCTION(timezone_name_from_abbr)
2093 0 : {
2094 : char *abbr;
2095 : char *tzid;
2096 : int abbr_len;
2097 0 : long gmtoffset = -1;
2098 0 : long isdst = -1;
2099 :
2100 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
2101 0 : RETURN_FALSE;
2102 : }
2103 0 : tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
2104 :
2105 0 : if (tzid) {
2106 0 : RETURN_STRING(tzid, 1);
2107 : } else {
2108 0 : RETURN_FALSE;
2109 : }
2110 : }
2111 : /* }}} */
2112 :
2113 : /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTime object)
2114 : Returns the timezone offset.
2115 : */
2116 : PHP_FUNCTION(timezone_offset_get)
2117 0 : {
2118 : zval *object, *dateobject;
2119 : php_timezone_obj *tzobj;
2120 : php_date_obj *dateobj;
2121 : timelib_time_offset *offset;
2122 :
2123 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_date) == FAILURE) {
2124 0 : RETURN_FALSE;
2125 : }
2126 0 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
2127 0 : DATE_CHECK_INITIALIZED(tzobj->tz, DateTimeZone);
2128 0 : dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
2129 0 : DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
2130 :
2131 0 : offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tz);
2132 0 : RETVAL_LONG(offset->offset);
2133 0 : timelib_time_offset_dtor(offset);
2134 : }
2135 : /* }}} */
2136 :
2137 : /* {{{ proto array timezone_transitions_get(DateTimeZone object)
2138 : Returns numeracilly indexed array containing associative array for all transitions for the timezone.
2139 : */
2140 : PHP_FUNCTION(timezone_transitions_get)
2141 0 : {
2142 : zval *object, *element;
2143 : php_timezone_obj *tzobj;
2144 : int i;
2145 :
2146 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
2147 0 : RETURN_FALSE;
2148 : }
2149 0 : tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
2150 0 : DATE_CHECK_INITIALIZED(tzobj->tz, DateTimeZone);
2151 :
2152 0 : array_init(return_value);
2153 0 : for (i = 0; i < tzobj->tz->timecnt; ++i) {
2154 0 : MAKE_STD_ZVAL(element);
2155 0 : array_init(element);
2156 0 : add_assoc_long(element, "ts", tzobj->tz->trans[i]);
2157 0 : add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, tzobj->tz->trans[i], 0 TSRMLS_CC), 0);
2158 0 : add_assoc_long(element, "offset", tzobj->tz->type[tzobj->tz->trans_idx[i]].offset);
2159 0 : add_assoc_bool(element, "isdst", tzobj->tz->type[tzobj->tz->trans_idx[i]].isdst);
2160 0 : add_assoc_string(element, "abbr", &tzobj->tz->timezone_abbr[tzobj->tz->type[tzobj->tz->trans_idx[i]].abbr_idx], 1);
2161 :
2162 0 : add_next_index_zval(return_value, element);
2163 : }
2164 : }
2165 : /* }}} */
2166 :
2167 : /* {{{ proto array timezone_identifiers_list()
2168 : Returns numerically index array with all timezone identifiers.
2169 : */
2170 : PHP_FUNCTION(timezone_identifiers_list)
2171 0 : {
2172 : const timelib_tzdb *tzdb;
2173 : const timelib_tzdb_index_entry *table;
2174 : int i, item_count;
2175 :
2176 0 : tzdb = DATE_TIMEZONEDB;
2177 0 : item_count = tzdb->index_size;
2178 0 : table = tzdb->index;
2179 :
2180 0 : array_init(return_value);
2181 :
2182 0 : for (i = 0; i < item_count; ++i) {
2183 0 : add_next_index_string(return_value, table[i].id, 1);
2184 : };
2185 0 : }
2186 : /* }}} */
2187 :
2188 : /* {{{ proto array timezone_abbreviations_list()
2189 : Returns associative array containing dst, offset and the timezone name
2190 : */
2191 : PHP_FUNCTION(timezone_abbreviations_list)
2192 0 : {
2193 : const timelib_tz_lookup_table *table, *entry;
2194 : zval *element, **abbr_array_pp, *abbr_array;
2195 :
2196 0 : table = timelib_timezone_abbreviations_list();
2197 0 : array_init(return_value);
2198 0 : entry = table;
2199 :
2200 : do {
2201 0 : MAKE_STD_ZVAL(element);
2202 0 : array_init(element);
2203 0 : add_assoc_bool(element, "dst", entry->type);
2204 0 : add_assoc_long(element, "offset", entry->gmtoffset);
2205 0 : if (entry->full_tz_name) {
2206 0 : add_assoc_string(element, "timezone_id", entry->full_tz_name, 1);
2207 : } else {
2208 0 : add_assoc_null(element, "timezone_id");
2209 : }
2210 :
2211 0 : if (zend_hash_find(HASH_OF(return_value), entry->name, strlen(entry->name) + 1, (void **) &abbr_array_pp) == FAILURE) {
2212 0 : MAKE_STD_ZVAL(abbr_array);
2213 0 : array_init(abbr_array);
2214 0 : add_assoc_zval(return_value, entry->name, abbr_array);
2215 : } else {
2216 0 : abbr_array = *abbr_array_pp;
2217 : }
2218 0 : add_next_index_zval(abbr_array, element);
2219 0 : entry++;
2220 0 : } while (entry->name);
2221 0 : }
2222 : /* }}} */
2223 :
2224 : /* {{{ proto bool date_default_timezone_set(string timezone_identifier)
2225 : Sets the default timezone used by all date/time functions in a script */
2226 : PHP_FUNCTION(date_default_timezone_set)
2227 0 : {
2228 : char *zone;
2229 : int zone_len;
2230 :
2231 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
2232 0 : RETURN_FALSE;
2233 : }
2234 0 : if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
2235 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
2236 0 : RETURN_FALSE;
2237 : }
2238 0 : if (DATEG(timezone)) {
2239 0 : efree(DATEG(timezone));
2240 0 : DATEG(timezone) = NULL;
2241 : }
2242 0 : DATEG(timezone) = estrndup(zone, zone_len);
2243 0 : RETURN_TRUE;
2244 : }
2245 : /* }}} */
2246 :
2247 : /* {{{ proto string date_default_timezone_get()
2248 : Gets the default timezone used by all date/time functions in a script */
2249 : PHP_FUNCTION(date_default_timezone_get)
2250 0 : {
2251 : timelib_tzinfo *default_tz;
2252 :
2253 0 : default_tz = get_timezone_info(TSRMLS_C);
2254 0 : RETVAL_STRING(default_tz->name, 1);
2255 0 : }
2256 : /* }}} */
2257 :
2258 : /* {{{ php_do_date_sunrise_sunset
2259 : * Common for date_sunrise() and date_sunset() functions
2260 : */
2261 : static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
2262 0 : {
2263 0 : double latitude, longitude, zenith, gmt_offset = 0, altitude;
2264 : double h_rise, h_set, N;
2265 : timelib_sll rise, set, transit;
2266 : long time, retformat;
2267 : int rs;
2268 : timelib_time *t;
2269 : timelib_tzinfo *tzi;
2270 : char *retstr;
2271 :
2272 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
2273 0 : RETURN_FALSE;
2274 : }
2275 :
2276 0 : switch (ZEND_NUM_ARGS()) {
2277 : case 1:
2278 0 : retformat = SUNFUNCS_RET_STRING;
2279 : case 2:
2280 0 : latitude = INI_FLT("date.default_latitude");
2281 : case 3:
2282 0 : longitude = INI_FLT("date.default_longitude");
2283 : case 4:
2284 0 : if (calc_sunset) {
2285 0 : zenith = INI_FLT("date.sunset_zenith");
2286 : } else {
2287 0 : zenith = INI_FLT("date.sunrise_zenith");
2288 : }
2289 : case 5:
2290 : case 6:
2291 : break;
2292 : default:
2293 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid format");
2294 0 : RETURN_FALSE;
2295 : break;
2296 : }
2297 0 : if (retformat != SUNFUNCS_RET_TIMESTAMP &&
2298 : retformat != SUNFUNCS_RET_STRING &&
2299 : retformat != SUNFUNCS_RET_DOUBLE)
2300 : {
2301 0 : 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");
2302 0 : RETURN_FALSE;
2303 : }
2304 0 : altitude = 90 - zenith;
2305 :
2306 : /* Initialize time struct */
2307 0 : t = timelib_time_ctor();
2308 0 : tzi = get_timezone_info(TSRMLS_C);
2309 0 : t->tz_info = tzi;
2310 0 : t->zone_type = TIMELIB_ZONETYPE_ID;
2311 :
2312 0 : if (ZEND_NUM_ARGS() <= 5) {
2313 0 : gmt_offset = timelib_get_current_offset(t) / 3600;
2314 : }
2315 :
2316 0 : timelib_unixtime2local(t, time);
2317 0 : rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, altitude > -1 ? 1 : 0, &h_rise, &h_set, &rise, &set, &transit);
2318 0 : timelib_time_dtor(t);
2319 :
2320 0 : if (rs != 0) {
2321 0 : RETURN_FALSE;
2322 : }
2323 :
2324 0 : if (retformat == SUNFUNCS_RET_TIMESTAMP) {
2325 0 : RETURN_LONG(calc_sunset ? set : rise);
2326 : }
2327 0 : N = (calc_sunset ? h_set : h_rise) + gmt_offset;
2328 0 : while (N > 24) {
2329 0 : N -= 24;
2330 : }
2331 0 : while (N < 0) {
2332 0 : N += 24;
2333 : }
2334 0 : switch (retformat) {
2335 : case SUNFUNCS_RET_STRING:
2336 0 : spprintf(&retstr, 0, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
2337 0 : RETURN_STRINGL(retstr, 5, 0);
2338 : break;
2339 : case SUNFUNCS_RET_DOUBLE:
2340 0 : RETURN_DOUBLE(N);
2341 : break;
2342 : }
2343 : }
2344 : /* }}} */
2345 :
2346 : /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
2347 : Returns time of sunrise for a given day and location */
2348 : PHP_FUNCTION(date_sunrise)
2349 0 : {
2350 0 : php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2351 0 : }
2352 : /* }}} */
2353 :
2354 : /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
2355 : Returns time of sunset for a given day and location */
2356 : PHP_FUNCTION(date_sunset)
2357 0 : {
2358 0 : php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2359 0 : }
2360 : /* }}} */
2361 :
2362 : /* {{{ proto array date_sun_info(long time, float latitude, float longitude)
2363 : Returns an array with information about sun set/rise and twilight begin/end */
2364 : PHP_FUNCTION(date_sun_info)
2365 0 : {
2366 : long time;
2367 : double latitude, longitude;
2368 : timelib_time *t, *t2;
2369 : timelib_tzinfo *tzi;
2370 : int rs;
2371 : timelib_sll rise, set, transit;
2372 : int dummy;
2373 : double ddummy;
2374 :
2375 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
2376 0 : RETURN_FALSE;
2377 : }
2378 : /* Initialize time struct */
2379 0 : t = timelib_time_ctor();
2380 0 : tzi = get_timezone_info(TSRMLS_C);
2381 0 : t->tz_info = tzi;
2382 0 : t->zone_type = TIMELIB_ZONETYPE_ID;
2383 0 : timelib_unixtime2local(t, time);
2384 :
2385 : /* Setup */
2386 0 : t2 = timelib_time_ctor();
2387 0 : array_init(return_value);
2388 :
2389 : /* Get sun up/down and transit */
2390 0 : rs = timelib_astro_rise_set_altitude(t, latitude, longitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
2391 0 : switch (rs) {
2392 : case -1: /* always below */
2393 0 : add_assoc_bool(return_value, "sunrise", 0);
2394 0 : add_assoc_bool(return_value, "sunset", 0);
2395 0 : break;
2396 : case 1: /* always above */
2397 0 : add_assoc_bool(return_value, "sunrise", 1);
2398 0 : add_assoc_bool(return_value, "sunset", 1);
2399 0 : break;
2400 : default:
2401 0 : t2->sse = rise;
2402 0 : add_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
2403 0 : t2->sse = set;
2404 0 : add_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
2405 : }
2406 0 : t2->sse = transit;
2407 0 : add_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
2408 :
2409 : /* Get civil twilight */
2410 0 : rs = timelib_astro_rise_set_altitude(t, latitude, longitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
2411 0 : switch (rs) {
2412 : case -1: /* always below */
2413 0 : add_assoc_bool(return_value, "civil_twilight_begin", 0);
2414 0 : add_assoc_bool(return_value, "civil_twilight_end", 0);
2415 0 : break;
2416 : case 1: /* always above */
2417 0 : add_assoc_bool(return_value, "civil_twilight_begin", 1);
2418 0 : add_assoc_bool(return_value, "civil_twilight_end", 1);
2419 0 : break;
2420 : default:
2421 0 : t2->sse = rise;
2422 0 : add_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
2423 0 : t2->sse = set;
2424 0 : add_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
2425 : }
2426 :
2427 : /* Get nautical twilight */
2428 0 : rs = timelib_astro_rise_set_altitude(t, latitude, longitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
2429 0 : switch (rs) {
2430 : case -1: /* always below */
2431 0 : add_assoc_bool(return_value, "nautical_twilight_begin", 0);
2432 0 : add_assoc_bool(return_value, "nautical_twilight_end", 0);
2433 0 : break;
2434 : case 1: /* always above */
2435 0 : add_assoc_bool(return_value, "nautical_twilight_begin", 1);
2436 0 : add_assoc_bool(return_value, "nautical_twilight_end", 1);
2437 0 : break;
2438 : default:
2439 0 : t2->sse = rise;
2440 0 : add_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
2441 0 : t2->sse = set;
2442 0 : add_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
2443 : }
2444 :
2445 : /* Get astronomical twilight */
2446 0 : rs = timelib_astro_rise_set_altitude(t, latitude, longitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
2447 0 : switch (rs) {
2448 : case -1: /* always below */
2449 0 : add_assoc_bool(return_value, "astronomical_twilight_begin", 0);
2450 0 : add_assoc_bool(return_value, "astronomical_twilight_end", 0);
2451 0 : break;
2452 : case 1: /* always above */
2453 0 : add_assoc_bool(return_value, "astronomical_twilight_begin", 1);
2454 0 : add_assoc_bool(return_value, "astronomical_twilight_end", 1);
2455 0 : break;
2456 : default:
2457 0 : t2->sse = rise;
2458 0 : add_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
2459 0 : t2->sse = set;
2460 0 : add_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
2461 : }
2462 0 : timelib_time_dtor(t);
2463 0 : timelib_time_dtor(t2);
2464 : }
2465 : /* }}} */
2466 : /*
2467 : * Local variables:
2468 : * tab-width: 4
2469 : * c-basic-offset: 4
2470 : * End:
2471 : * vim600: fdm=marker
2472 : * vim: noet sw=4 ts=4
2473 : */
|