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 35static __inline __int64 php_date_llabs( __int64 i ) { return i >= 0? i: -i; } 36#elif defined(__GNUC__) && __GNUC__ < 3 37static __inline __int64_t php_date_llabs( __int64_t i ) { return i >= 0 ? i : -i; } 38#else 39static 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 */ 57ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1) 58 ZEND_ARG_INFO(0, format) 59 ZEND_ARG_INFO(0, timestamp) 60ZEND_END_ARG_INFO() 61 62ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1) 63 ZEND_ARG_INFO(0, format) 64 ZEND_ARG_INFO(0, timestamp) 65ZEND_END_ARG_INFO() 66 67ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1) 68 ZEND_ARG_INFO(0, format) 69 ZEND_ARG_INFO(0, timestamp) 70ZEND_END_ARG_INFO() 71 72ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1) 73 ZEND_ARG_INFO(0, time) 74 ZEND_ARG_INFO(0, now) 75ZEND_END_ARG_INFO() 76 77ZEND_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) 84ZEND_END_ARG_INFO() 85 86ZEND_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) 93ZEND_END_ARG_INFO() 94 95ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0) 96 ZEND_ARG_INFO(0, month) 97 ZEND_ARG_INFO(0, day) 98 ZEND_ARG_INFO(0, year) 99ZEND_END_ARG_INFO() 100 101ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1) 102 ZEND_ARG_INFO(0, format) 103 ZEND_ARG_INFO(0, timestamp) 104ZEND_END_ARG_INFO() 105 106ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1) 107 ZEND_ARG_INFO(0, format) 108 ZEND_ARG_INFO(0, timestamp) 109ZEND_END_ARG_INFO() 110 111ZEND_BEGIN_ARG_INFO(arginfo_time, 0) 112ZEND_END_ARG_INFO() 113 114ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0) 115 ZEND_ARG_INFO(0, timestamp) 116 ZEND_ARG_INFO(0, associative_array) 117ZEND_END_ARG_INFO() 118 119ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0) 120 ZEND_ARG_INFO(0, timestamp) 121ZEND_END_ARG_INFO() 122 123ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0) 124 ZEND_ARG_INFO(0, timezone_identifier) 125ZEND_END_ARG_INFO() 126 127ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0) 128ZEND_END_ARG_INFO() 129 130ZEND_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) 137ZEND_END_ARG_INFO() 138 139ZEND_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) 146ZEND_END_ARG_INFO() 147 148ZEND_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) 152ZEND_END_ARG_INFO() 153 154ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0) 155 ZEND_ARG_INFO(0, time) 156 ZEND_ARG_INFO(0, object) 157ZEND_END_ARG_INFO() 158 159ZEND_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) 163ZEND_END_ARG_INFO() 164 165ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse, 0, 0, 1) 166 ZEND_ARG_INFO(0, date) 167ZEND_END_ARG_INFO() 168 169ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse_from_format, 0, 0, 2) 170 ZEND_ARG_INFO(0, format) 171 ZEND_ARG_INFO(0, date) 172ZEND_END_ARG_INFO() 173 174ZEND_BEGIN_ARG_INFO(arginfo_date_get_last_errors, 0) 175ZEND_END_ARG_INFO() 176 177ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2) 178 ZEND_ARG_INFO(0, object) 179 ZEND_ARG_INFO(0, format) 180ZEND_END_ARG_INFO() 181 182ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_format, 0, 0, 1) 183 ZEND_ARG_INFO(0, format) 184ZEND_END_ARG_INFO() 185 186ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2) 187 ZEND_ARG_INFO(0, object) 188 ZEND_ARG_INFO(0, modify) 189ZEND_END_ARG_INFO() 190 191ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_modify, 0, 0, 1) 192 ZEND_ARG_INFO(0, modify) 193ZEND_END_ARG_INFO() 194 195ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2) 196 ZEND_ARG_INFO(0, object) 197 ZEND_ARG_INFO(0, interval) 198ZEND_END_ARG_INFO() 199 200ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_add, 0, 0, 1) 201 ZEND_ARG_INFO(0, interval) 202ZEND_END_ARG_INFO() 203 204ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sub, 0, 0, 2) 205 ZEND_ARG_INFO(0, object) 206 ZEND_ARG_INFO(0, interval) 207ZEND_END_ARG_INFO() 208 209ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_sub, 0, 0, 1) 210 ZEND_ARG_INFO(0, interval) 211ZEND_END_ARG_INFO() 212 213ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1) 214 ZEND_ARG_INFO(0, object) 215ZEND_END_ARG_INFO() 216 217ZEND_BEGIN_ARG_INFO(arginfo_date_method_timezone_get, 0) 218ZEND_END_ARG_INFO() 219 220ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2) 221 ZEND_ARG_INFO(0, object) 222 ZEND_ARG_INFO(0, timezone) 223ZEND_END_ARG_INFO() 224 225ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timezone_set, 0, 0, 1) 226 ZEND_ARG_INFO(0, timezone) 227ZEND_END_ARG_INFO() 228 229ZEND_BEGIN_ARG_INFO_EX(arginfo_date_offset_get, 0, 0, 1) 230 ZEND_ARG_INFO(0, object) 231ZEND_END_ARG_INFO() 232 233ZEND_BEGIN_ARG_INFO(arginfo_date_method_offset_get, 0) 234ZEND_END_ARG_INFO() 235 236ZEND_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) 240ZEND_END_ARG_INFO() 241 242ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_diff, 0, 0, 1) 243 ZEND_ARG_INFO(0, object) 244 ZEND_ARG_INFO(0, absolute) 245ZEND_END_ARG_INFO() 246 247ZEND_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) 252ZEND_END_ARG_INFO() 253 254ZEND_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) 258ZEND_END_ARG_INFO() 259 260ZEND_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) 265ZEND_END_ARG_INFO() 266 267ZEND_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) 271ZEND_END_ARG_INFO() 272 273ZEND_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) 278ZEND_END_ARG_INFO() 279 280ZEND_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) 284ZEND_END_ARG_INFO() 285 286ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2) 287 ZEND_ARG_INFO(0, object) 288 ZEND_ARG_INFO(0, unixtimestamp) 289ZEND_END_ARG_INFO() 290 291ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timestamp_set, 0, 0, 1) 292 ZEND_ARG_INFO(0, unixtimestamp) 293ZEND_END_ARG_INFO() 294 295ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_get, 0, 0, 1) 296 ZEND_ARG_INFO(0, object) 297ZEND_END_ARG_INFO() 298 299ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0) 300ZEND_END_ARG_INFO() 301 302ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1) 303 ZEND_ARG_INFO(0, timezone) 304ZEND_END_ARG_INFO() 305 306ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1) 307 ZEND_ARG_INFO(0, object) 308ZEND_END_ARG_INFO() 309 310ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_name_get, 0) 311ZEND_END_ARG_INFO() 312 313ZEND_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) 317ZEND_END_ARG_INFO() 318 319ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2) 320 ZEND_ARG_INFO(0, object) 321 ZEND_ARG_INFO(0, datetime) 322ZEND_END_ARG_INFO() 323 324ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_method_offset_get, 0, 0, 1) 325 ZEND_ARG_INFO(0, datetime) 326ZEND_END_ARG_INFO() 327 328ZEND_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) 332ZEND_END_ARG_INFO() 333 334ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0) 335 ZEND_ARG_INFO(0, timestamp_begin) 336 ZEND_ARG_INFO(0, timestamp_end) 337ZEND_END_ARG_INFO() 338 339ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1) 340 ZEND_ARG_INFO(0, object) 341ZEND_END_ARG_INFO() 342 343ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0) 344ZEND_END_ARG_INFO() 345 346ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0) 347 ZEND_ARG_INFO(0, what) 348 ZEND_ARG_INFO(0, country) 349ZEND_END_ARG_INFO() 350 351ZEND_BEGIN_ARG_INFO(arginfo_timezone_abbreviations_list, 0) 352ZEND_END_ARG_INFO() 353 354ZEND_BEGIN_ARG_INFO(arginfo_timezone_version_get, 0) 355ZEND_END_ARG_INFO() 356 357ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1) 358 ZEND_ARG_INFO(0, time) 359ZEND_END_ARG_INFO() 360 361ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2) 362 ZEND_ARG_INFO(0, object) 363 ZEND_ARG_INFO(0, format) 364ZEND_END_ARG_INFO() 365 366ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0) 367 ZEND_ARG_INFO(0, format) 368ZEND_END_ARG_INFO() 369 370ZEND_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) 374ZEND_END_ARG_INFO() 375 376ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0) 377 ZEND_ARG_INFO(0, interval_spec) 378ZEND_END_ARG_INFO() 379/* }}} */ 380 381/* {{{ Function table */ 382const 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 445const 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 467const 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 478const 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 487const 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 494static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC); 495static void date_register_classes(TSRMLS_D); 496/* }}} */ 497 498ZEND_DECLARE_MODULE_GLOBALS(date) 499static PHP_GINIT_FUNCTION(date); 500 501/* True global */ 502timelib_tzdb *php_date_global_timezone_db; 503int 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 */ 515PHP_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) 521PHP_INI_END() 522/* }}} */ 523 524zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period; 525 526 527PHPAPI zend_class_entry *php_date_get_date_ce(void) 528{ 529 return date_ce_date; 530} 531 532PHPAPI zend_class_entry *php_date_get_timezone_ce(void) 533{ 534 return date_ce_timezone; 535} 536 537static zend_object_handlers date_object_handlers_date; 538static zend_object_handlers date_object_handlers_timezone; 539static zend_object_handlers date_object_handlers_interval; 540static 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 566static void date_object_free_storage_date(void *object TSRMLS_DC); 567static void date_object_free_storage_timezone(void *object TSRMLS_DC); 568static void date_object_free_storage_interval(void *object TSRMLS_DC); 569static void date_object_free_storage_period(void *object TSRMLS_DC); 570 571static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC); 572static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC); 573static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC); 574static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC); 575 576static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC); 577static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC); 578static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC); 579static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC); 580 581static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC); 582static HashTable *date_object_get_properties(zval *object TSRMLS_DC); 583static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); 584static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC); 585 586zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC); 587void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC); 588static zval *date_period_read_property(zval *object, zval *member, int type TSRMLS_DC); 589static void date_period_write_property(zval *object, zval *member, zval *value TSRMLS_DC); 590 591/* {{{ Module struct */ 592zend_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 */ 614static 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 623static 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 */ 631PHP_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 */ 645PHP_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 */ 762PHP_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 */ 808PHP_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 */ 821PHP_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 */ 837static 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 857timelib_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 */ 865static 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: 937php_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 962PHPAPI 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 980static char *mon_full_names[] = { 981 "January", "February", "March", "April", 982 "May", "June", "July", "August", 983 "September", "October", "November", "December" 984}; 985 986static char *mon_short_names[] = { 987 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 988}; 989 990static char *day_full_names[] = { 991 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" 992}; 993 994static char *day_short_names[] = { 995 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 996}; 997 998static 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 */ 1014char *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 1023char *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 */ 1034static 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 1188static 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 1208PHPAPI 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 */ 1235PHPAPI 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 */ 1332PHP_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 */ 1340PHP_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 */ 1348PHP_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 */ 1378PHPAPI 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 */ 1390PHPAPI 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 */ 1416PHP_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 */ 1476PHPAPI 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 */ 1569PHP_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 */ 1577PHP_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 */ 1586PHP_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 */ 1603PHPAPI 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 */ 1688PHP_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 */ 1696PHP_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 */ 1705PHP_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 */ 1713PHP_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 */ 1760PHP_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 */ 1813typedef 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 */ 1822static 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 */ 1835static 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 */ 1849static 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 */ 1874static 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 */ 1900static 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 */ 1910static 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 */ 1921static 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 */ 1936zend_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 1948zend_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 1967static 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 2048static 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 2069static 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 2074static 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 2098static 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 2123static 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 2176static 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 2197static 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 2202static 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 2232static 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 2253static 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 2258static 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 2270static 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 2314static 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 2335static 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 2340static 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 2352static 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 2364static 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 2375static 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 2384static 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 */ 2406PHPAPI 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. */ 2418static 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 2427PHPAPI 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*/ 2512PHP_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*/ 2532PHP_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*/ 2552PHP_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 2567static 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*/ 2619PHP_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*/ 2641PHP_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 */ 2658static 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*/ 2683PHP_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 2694void 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*/ 2772PHP_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*/ 2791PHP_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*/ 2810PHP_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*/ 2829PHP_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*/ 2897PHP_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*/ 2941PHP_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*/ 2987PHP_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*/ 3025PHP_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*/ 3052PHP_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*/ 3087PHP_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*/ 3110PHP_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*/ 3133PHP_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*/ 3160PHP_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*/ 3181PHP_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*/ 3207PHP_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 3234static 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*/ 3257PHP_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*/ 3280PHP_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*/ 3306PHP_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*/ 3343PHP_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*/ 3367PHP_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*/ 3401PHP_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*/ 3483PHP_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 3505static 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 */ 3539zval *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 */ 3601void 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*/ 3660PHP_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 3683static 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*/ 3731PHP_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*/ 3751PHP_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*/ 3767PHP_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 - */ 3791static 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*/ 3855PHP_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 3872static 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*/ 3899PHP_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 3982static 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*/ 4001PHP_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*/ 4041PHP_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*/ 4053PHP_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 */ 4088PHP_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 */ 4111PHP_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 */ 4123static 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 */ 4209PHP_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 */ 4217PHP_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 */ 4225PHP_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 4329static 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 4400static 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*/ 4475PHP_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*/ 4497PHP_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 */ 4514static 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 */ 4537static 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