1 /*
2    +----------------------------------------------------------------------+
3    | This source file is subject to version 3.01 of the PHP license,      |
4    | that is bundled with this package in the file LICENSE, and is        |
5    | available through the world-wide-web at the following url:           |
6    | https://www.php.net/license/3_01.txt                                 |
7    | If you did not receive a copy of the PHP license and are unable to   |
8    | obtain it through the world-wide-web, please send a note to          |
9    | license@php.net so we can mail you a copy immediately.               |
10    +----------------------------------------------------------------------+
11    | Authors: Gustavo Lopes <cataphract@php.net>                          |
12    +----------------------------------------------------------------------+
13 */
14 
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 
19 #include "../intl_cppshims.h"
20 
21 #include <unicode/locid.h>
22 #include <unicode/timezone.h>
23 #include <unicode/ustring.h>
24 #include <unicode/calendar.h>
25 #include "intl_convertcpp.h"
26 
27 #include "../common/common_date.h"
28 
29 extern "C" {
30 #include "../php_intl.h"
31 #define USE_TIMEZONE_POINTER 1
32 #include "timezone_class.h"
33 #include "intl_convert.h"
34 #include <zend_exceptions.h>
35 #include <ext/date/php_date.h>
36 }
37 #include "common/common_enum.h"
38 
39 using icu::Locale;
40 using icu::Calendar;
41 
PHP_METHOD(IntlTimeZone,__construct)42 U_CFUNC PHP_METHOD(IntlTimeZone, __construct)
43 {
44 	zend_throw_exception( NULL,
45 		"An object of this type cannot be created with the new operator",
46 		0 );
47 }
48 
PHP_FUNCTION(intltz_create_time_zone)49 U_CFUNC PHP_FUNCTION(intltz_create_time_zone)
50 {
51 	char	*str_id;
52 	size_t	 str_id_len;
53 	intl_error_reset(NULL);
54 
55 	ZEND_PARSE_PARAMETERS_START(1, 1)
56 		Z_PARAM_STRING(str_id, str_id_len)
57 	ZEND_PARSE_PARAMETERS_END();
58 
59 	UErrorCode status = UErrorCode();
60 	UnicodeString id = UnicodeString();
61 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
62 		intl_error_set(NULL, status,
63 			"could not convert time zone id to UTF-16", 0);
64 		RETURN_NULL();
65 	}
66 
67 	//guaranteed non-null; GMT if timezone cannot be understood
68 	TimeZone *tz = TimeZone::createTimeZone(id);
69 	timezone_object_construct(tz, return_value, 1);
70 }
71 
PHP_FUNCTION(intltz_from_date_time_zone)72 U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone)
73 {
74 	zval				*zv_timezone;
75 	TimeZone			*tz;
76 	php_timezone_obj	*tzobj;
77 	intl_error_reset(NULL);
78 
79 	ZEND_PARSE_PARAMETERS_START(1, 1)
80 		Z_PARAM_OBJECT_OF_CLASS(zv_timezone, php_date_get_timezone_ce())
81 	ZEND_PARSE_PARAMETERS_END();
82 
83 	tzobj = Z_PHPTIMEZONE_P(zv_timezone);
84 	if (!tzobj->initialized) {
85 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
86 			"DateTimeZone object is unconstructed",
87 			0);
88 		RETURN_NULL();
89 	}
90 
91 	tz = timezone_convert_datetimezone(tzobj->type, tzobj, false, NULL,
92 		"intltz_from_date_time_zone");
93 	if (tz == NULL) {
94 		RETURN_NULL();
95 	}
96 
97 	timezone_object_construct(tz, return_value, 1);
98 }
99 
PHP_FUNCTION(intltz_create_default)100 U_CFUNC PHP_FUNCTION(intltz_create_default)
101 {
102 	intl_error_reset(NULL);
103 
104 	ZEND_PARSE_PARAMETERS_NONE();
105 
106 	TimeZone *tz = TimeZone::createDefault();
107 	timezone_object_construct(tz, return_value, 1);
108 }
109 
PHP_FUNCTION(intltz_get_gmt)110 U_CFUNC PHP_FUNCTION(intltz_get_gmt)
111 {
112 	intl_error_reset(NULL);
113 
114 	ZEND_PARSE_PARAMETERS_NONE();
115 
116 	timezone_object_construct(TimeZone::getGMT(), return_value, 0);
117 }
118 
PHP_FUNCTION(intltz_get_unknown)119 U_CFUNC PHP_FUNCTION(intltz_get_unknown)
120 {
121 	intl_error_reset(NULL);
122 
123 	ZEND_PARSE_PARAMETERS_NONE();
124 
125 	timezone_object_construct(&TimeZone::getUnknown(), return_value, 0);
126 }
127 
PHP_FUNCTION(intltz_create_enumeration)128 U_CFUNC PHP_FUNCTION(intltz_create_enumeration)
129 {
130 	zval				*arg = NULL;
131 	StringEnumeration	*se	  = NULL;
132 	intl_error_reset(NULL);
133 
134 	/* double indirection to have the zend engine destroy the new zval that
135 	 * results from separation */
136 	ZEND_PARSE_PARAMETERS_START(0, 1)
137 		Z_PARAM_OPTIONAL
138 		Z_PARAM_ZVAL(arg)
139 	ZEND_PARSE_PARAMETERS_END();
140 
141 	if (arg == NULL || Z_TYPE_P(arg) == IS_NULL) {
142 		se = TimeZone::createEnumeration();
143 	} else if (Z_TYPE_P(arg) == IS_LONG) {
144 int_offset:
145 		if (UNEXPECTED(Z_LVAL_P(arg) < (zend_long)INT32_MIN ||
146 				Z_LVAL_P(arg) > (zend_long)INT32_MAX)) {
147 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
148 				"value is out of range", 0);
149 			RETURN_FALSE;
150 		} else {
151 			se = TimeZone::createEnumeration((int32_t) Z_LVAL_P(arg));
152 		}
153 	} else if (Z_TYPE_P(arg) == IS_DOUBLE) {
154 double_offset:
155 		convert_to_long(arg);
156 		goto int_offset;
157 	} else if (Z_TYPE_P(arg) == IS_OBJECT || Z_TYPE_P(arg) == IS_STRING) {
158 		zend_long lval;
159 		double dval;
160 		if (!try_convert_to_string(arg)) {
161 			RETURN_THROWS();
162 		}
163 		switch (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &lval, &dval, 0)) {
164 		case IS_DOUBLE:
165 			zval_ptr_dtor(arg);
166 			ZVAL_DOUBLE(arg, dval);
167 			goto double_offset;
168 		case IS_LONG:
169 			zval_ptr_dtor(arg);
170 			ZVAL_LONG(arg, lval);
171 			goto int_offset;
172 		}
173 		/* else call string version */
174 		se = TimeZone::createEnumeration(Z_STRVAL_P(arg));
175 	} else {
176 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
177 			"invalid argument type", 0);
178 		RETURN_FALSE;
179 	}
180 
181 	if (se) {
182 		IntlIterator_from_StringEnumeration(se, return_value);
183 	} else {
184 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
185 			"error obtaining enumeration", 0);
186 		RETVAL_FALSE;
187 	}
188 }
189 
PHP_FUNCTION(intltz_count_equivalent_ids)190 U_CFUNC PHP_FUNCTION(intltz_count_equivalent_ids)
191 {
192 	char	*str_id;
193 	size_t	 str_id_len;
194 	intl_error_reset(NULL);
195 
196 	ZEND_PARSE_PARAMETERS_START(1, 1)
197 		Z_PARAM_STRING(str_id, str_id_len)
198 	ZEND_PARSE_PARAMETERS_END();
199 
200 	UErrorCode status = UErrorCode();
201 	UnicodeString id = UnicodeString();
202 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
203 		intl_error_set(NULL, status,
204 			"could not convert time zone id to UTF-16", 0);
205 		RETURN_FALSE;
206 	}
207 
208 	int32_t result = TimeZone::countEquivalentIDs(id);
209 	RETURN_LONG((zend_long)result);
210 }
211 
PHP_FUNCTION(intltz_create_time_zone_id_enumeration)212 U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)
213 {
214 	zend_long zoneType,
215 			  offset_arg;
216 	char	 *region		= NULL;
217 	size_t    region_len = 0;
218 	int32_t	  offset,
219 			 *offsetp	= NULL;
220 	bool arg3isnull = 1;
221 
222 	intl_error_reset(NULL);
223 
224 	ZEND_PARSE_PARAMETERS_START(1, 3)
225 		Z_PARAM_LONG(zoneType)
226 		Z_PARAM_OPTIONAL
227 		Z_PARAM_STRING_OR_NULL(region, region_len)
228 		Z_PARAM_LONG_OR_NULL(offset_arg, arg3isnull)
229 	ZEND_PARSE_PARAMETERS_END();
230 
231 	if (zoneType != UCAL_ZONE_TYPE_ANY && zoneType != UCAL_ZONE_TYPE_CANONICAL
232 			&& zoneType != UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
233 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
234 			"bad zone type", 0);
235 		RETURN_FALSE;
236 	}
237 
238 	if (!arg3isnull) {
239 		if (UNEXPECTED(offset_arg < (zend_long)INT32_MIN || offset_arg > (zend_long)INT32_MAX)) {
240 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
241 				"offset out of bounds", 0);
242 			RETURN_FALSE;
243 		}
244 		offset = (int32_t)offset_arg;
245 		offsetp = &offset;
246 	} //else leave offsetp NULL
247 
248 	StringEnumeration *se;
249 	UErrorCode uec = UErrorCode();
250 	se = TimeZone::createTimeZoneIDEnumeration((USystemTimeZoneType)zoneType,
251 		region, offsetp, uec);
252 	INTL_CHECK_STATUS(uec, "error obtaining time zone id enumeration")
253 
254 	IntlIterator_from_StringEnumeration(se, return_value);
255 }
256 
PHP_FUNCTION(intltz_get_canonical_id)257 U_CFUNC PHP_FUNCTION(intltz_get_canonical_id)
258 {
259 	char	*str_id;
260 	size_t	 str_id_len;
261 	zval	*is_systemid = NULL;
262 	intl_error_reset(NULL);
263 
264 	ZEND_PARSE_PARAMETERS_START(1, 2)
265 		Z_PARAM_STRING(str_id, str_id_len)
266 		Z_PARAM_OPTIONAL
267 		Z_PARAM_ZVAL(is_systemid)
268 	ZEND_PARSE_PARAMETERS_END();
269 
270 	UErrorCode status = UErrorCode();
271 	UnicodeString id;
272 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
273 		intl_error_set(NULL, status,
274 			"could not convert time zone id to UTF-16", 0);
275 		RETURN_FALSE;
276 	}
277 
278 	UnicodeString result;
279 	UBool isSystemID;
280 	TimeZone::getCanonicalID(id, result, isSystemID, status);
281 	INTL_CHECK_STATUS(status, "error obtaining canonical ID");
282 
283 	zend_string *u8str =intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), &status);
284 	INTL_CHECK_STATUS(status,
285 		"could not convert time zone id to UTF-16");
286 	RETVAL_NEW_STR(u8str);
287 
288 	if (is_systemid) { /* by-ref argument passed */
289 		ZVAL_DEREF(is_systemid);
290 		zval_ptr_dtor(is_systemid);
291 		ZVAL_BOOL(is_systemid, isSystemID);
292 	}
293 }
294 
PHP_FUNCTION(intltz_get_region)295 U_CFUNC PHP_FUNCTION(intltz_get_region)
296 {
297 	char	*str_id;
298 	size_t	 str_id_len;
299 	char	 outbuf[3];
300 	intl_error_reset(NULL);
301 
302 	ZEND_PARSE_PARAMETERS_START(1, 1)
303 		Z_PARAM_STRING(str_id, str_id_len)
304 	ZEND_PARSE_PARAMETERS_END();
305 
306 	UErrorCode status = UErrorCode();
307 	UnicodeString id;
308 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
309 		intl_error_set(NULL, status,
310 			"could not convert time zone id to UTF-16", 0);
311 		RETURN_FALSE;
312 	}
313 
314 	int32_t region_len = TimeZone::getRegion(id, outbuf, sizeof(outbuf), status);
315 	INTL_CHECK_STATUS(status, "error obtaining region");
316 
317 	RETURN_STRINGL(outbuf, region_len);
318 }
319 
PHP_FUNCTION(intltz_get_tz_data_version)320 U_CFUNC PHP_FUNCTION(intltz_get_tz_data_version)
321 {
322 	intl_error_reset(NULL);
323 
324 	ZEND_PARSE_PARAMETERS_NONE();
325 
326 	UErrorCode status = UErrorCode();
327 	const char *res = TimeZone::getTZDataVersion(status);
328 	INTL_CHECK_STATUS(status, "error obtaining time zone data version");
329 
330 	RETURN_STRING(res);
331 }
332 
PHP_FUNCTION(intltz_get_equivalent_id)333 U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id)
334 {
335 	char	   *str_id;
336 	size_t		str_id_len;
337 	zend_long	index;
338 	intl_error_reset(NULL);
339 
340 	ZEND_PARSE_PARAMETERS_START(2, 2)
341 		Z_PARAM_STRING(str_id, str_id_len)
342 		Z_PARAM_LONG(index)
343 	ZEND_PARSE_PARAMETERS_END();
344 
345 	if (UNEXPECTED(index < (zend_long)INT32_MIN || index > (zend_long)INT32_MAX)) {
346 		RETURN_FALSE;
347 	}
348 
349 	UErrorCode status = UErrorCode();
350 	UnicodeString id;
351 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
352 		intl_error_set(NULL, status,
353 			"could not convert time zone id to UTF-16", 0);
354 		RETURN_FALSE;
355 	}
356 
357 	const UnicodeString result = TimeZone::getEquivalentID(id, (int32_t)index);
358 	zend_string *u8str;
359 
360 	u8str = intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), &status);
361 	INTL_CHECK_STATUS(status, "could not convert resulting time zone id to UTF-16");
362 	RETVAL_NEW_STR(u8str);
363 }
364 
365 #if U_ICU_VERSION_MAJOR_NUM >= 74
PHP_FUNCTION(intltz_get_iana_id)366 U_CFUNC PHP_FUNCTION(intltz_get_iana_id)
367 {
368 	char	*str_id;
369 	size_t	 str_id_len;
370 	intl_error_reset(NULL);
371 
372 	ZEND_PARSE_PARAMETERS_START(1, 1)
373 		Z_PARAM_STRING(str_id, str_id_len)
374 	ZEND_PARSE_PARAMETERS_END();
375 
376 	UErrorCode status = UErrorCode();
377 	UnicodeString id;
378 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
379 		intl_error_set(NULL, status,
380 			"could not convert time zone id to UTF-16", 0);
381 		RETURN_FALSE;
382 	}
383 
384 	UnicodeString result;
385 	TimeZone::getIanaID(id, result, status);
386 	INTL_CHECK_STATUS(status, "error obtaining IANA ID");
387 
388 	zend_string *u8str = intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), &status);
389 	INTL_CHECK_STATUS(status,
390 		"could not convert time zone id to UTF-16");
391 	RETVAL_NEW_STR(u8str);
392 }
393 #endif
394 
PHP_FUNCTION(intltz_get_id)395 U_CFUNC PHP_FUNCTION(intltz_get_id)
396 {
397 	TIMEZONE_METHOD_INIT_VARS;
398 
399 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
400 			&object, TimeZone_ce_ptr) == FAILURE) {
401 		RETURN_THROWS();
402 	}
403 
404 	TIMEZONE_METHOD_FETCH_OBJECT;
405 
406 	UnicodeString id_us;
407 	to->utimezone->getID(id_us);
408 
409 	zend_string *u8str;
410 
411 	u8str = intl_convert_utf16_to_utf8(
412 		id_us.getBuffer(), id_us.length(), TIMEZONE_ERROR_CODE_P(to));
413 	INTL_METHOD_CHECK_STATUS(to, "could not convert id to UTF-8");
414 
415 	RETVAL_NEW_STR(u8str);
416 }
417 
PHP_FUNCTION(intltz_use_daylight_time)418 U_CFUNC PHP_FUNCTION(intltz_use_daylight_time)
419 {
420 	TIMEZONE_METHOD_INIT_VARS;
421 
422 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
423 			&object, TimeZone_ce_ptr) == FAILURE) {
424 		RETURN_THROWS();
425 	}
426 
427 	TIMEZONE_METHOD_FETCH_OBJECT;
428 
429 	RETURN_BOOL(to->utimezone->useDaylightTime());
430 }
431 
PHP_FUNCTION(intltz_get_offset)432 U_CFUNC PHP_FUNCTION(intltz_get_offset)
433 {
434 	double		date;
435 	bool	local;
436 	zval		*rawOffsetArg,
437 				*dstOffsetArg;
438 	int32_t		rawOffset,
439 				dstOffset;
440 	TIMEZONE_METHOD_INIT_VARS;
441 
442 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
443 			"Odbz/z/", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg,
444 			&dstOffsetArg) == FAILURE) {
445 		RETURN_THROWS();
446 	}
447 
448 	TIMEZONE_METHOD_FETCH_OBJECT;
449 
450 	to->utimezone->getOffset((UDate) date, (UBool) local, rawOffset, dstOffset,
451 		TIMEZONE_ERROR_CODE(to));
452 
453 	INTL_METHOD_CHECK_STATUS(to, "error obtaining offset");
454 
455 	zval_ptr_dtor(rawOffsetArg);
456 	ZVAL_LONG(rawOffsetArg, rawOffset);
457 	zval_ptr_dtor(dstOffsetArg);
458 	ZVAL_LONG(dstOffsetArg, dstOffset);
459 
460 	RETURN_TRUE;
461 }
462 
PHP_FUNCTION(intltz_get_raw_offset)463 U_CFUNC PHP_FUNCTION(intltz_get_raw_offset)
464 {
465 	TIMEZONE_METHOD_INIT_VARS;
466 
467 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
468 			"O", &object, TimeZone_ce_ptr) == FAILURE) {
469 		RETURN_THROWS();
470 	}
471 
472 	TIMEZONE_METHOD_FETCH_OBJECT;
473 
474 	RETURN_LONG(to->utimezone->getRawOffset());
475 }
476 
PHP_FUNCTION(intltz_has_same_rules)477 U_CFUNC PHP_FUNCTION(intltz_has_same_rules)
478 {
479 	zval			*other_object;
480 	TimeZone_object	*other_to;
481 	TIMEZONE_METHOD_INIT_VARS;
482 
483 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
484 			"OO", &object, TimeZone_ce_ptr, &other_object, TimeZone_ce_ptr)
485 			== FAILURE) {
486 		RETURN_THROWS();
487 	}
488 	TIMEZONE_METHOD_FETCH_OBJECT;
489 	other_to = Z_INTL_TIMEZONE_P(other_object);
490 	if (other_to->utimezone == NULL) {
491 		intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR,
492 			"The second IntlTimeZone is unconstructed", 0);
493 		RETURN_FALSE;
494 	}
495 
496 	RETURN_BOOL(to->utimezone->hasSameRules(*other_to->utimezone));
497 }
498 
499 static constexpr TimeZone::EDisplayType display_types[] = {
500 	TimeZone::SHORT,				TimeZone::LONG,
501 	TimeZone::SHORT_GENERIC,		TimeZone::LONG_GENERIC,
502 	TimeZone::SHORT_GMT,			TimeZone::LONG_GMT,
503 	TimeZone::SHORT_COMMONLY_USED,	TimeZone::GENERIC_LOCATION
504 };
505 
PHP_FUNCTION(intltz_get_display_name)506 U_CFUNC PHP_FUNCTION(intltz_get_display_name)
507 {
508 	bool	daylight		= 0;
509 	zend_long	display_type	= TimeZone::LONG;
510 	const char *locale_str		= NULL;
511 	size_t		dummy			= 0;
512 	TIMEZONE_METHOD_INIT_VARS;
513 
514 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
515 			"O|bls!", &object, TimeZone_ce_ptr, &daylight, &display_type,
516 			&locale_str, &dummy) == FAILURE) {
517 		RETURN_THROWS();
518 	}
519 
520 	bool found = false;
521 	for (int i = 0; !found && i < sizeof(display_types)/sizeof(*display_types); i++) {
522 		if (display_types[i] == display_type)
523 			found = true;
524 	}
525 	if (!found) {
526 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
527 			"wrong display type", 0);
528 		RETURN_FALSE;
529 	}
530 
531 	if (!locale_str) {
532 		locale_str = intl_locale_get_default();
533 	}
534 
535 	TIMEZONE_METHOD_FETCH_OBJECT;
536 
537 	UnicodeString result;
538 	to->utimezone->getDisplayName((UBool)daylight, (TimeZone::EDisplayType)display_type,
539 		Locale::createFromName(locale_str), result);
540 
541 	zend_string *u8str = intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), TIMEZONE_ERROR_CODE_P(to));
542 	INTL_METHOD_CHECK_STATUS(to, "could not convert resulting time zone id to UTF-16");
543 
544 	RETVAL_NEW_STR(u8str);
545 }
546 
PHP_FUNCTION(intltz_get_dst_savings)547 U_CFUNC PHP_FUNCTION(intltz_get_dst_savings)
548 {
549 	TIMEZONE_METHOD_INIT_VARS;
550 
551 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
552 			"O", &object, TimeZone_ce_ptr) == FAILURE) {
553 		RETURN_THROWS();
554 	}
555 
556 	TIMEZONE_METHOD_FETCH_OBJECT;
557 
558 	RETURN_LONG((zend_long)to->utimezone->getDSTSavings());
559 }
560 
PHP_FUNCTION(intltz_to_date_time_zone)561 U_CFUNC PHP_FUNCTION(intltz_to_date_time_zone)
562 {
563 	zval tmp;
564 	TIMEZONE_METHOD_INIT_VARS;
565 
566 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
567 			"O", &object, TimeZone_ce_ptr) == FAILURE) {
568 		RETURN_THROWS();
569 	}
570 
571 	TIMEZONE_METHOD_FETCH_OBJECT;
572 
573 	zval *ret = timezone_convert_to_datetimezone(to->utimezone,
574 		&TIMEZONE_ERROR(to), "intltz_to_date_time_zone", &tmp);
575 
576 	if (ret) {
577 		ZVAL_COPY_VALUE(return_value, ret);
578 	} else {
579 		RETURN_FALSE;
580 	}
581 }
582 
PHP_FUNCTION(intltz_get_error_code)583 U_CFUNC PHP_FUNCTION(intltz_get_error_code)
584 {
585 	TIMEZONE_METHOD_INIT_VARS
586 
587 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
588 			&object, TimeZone_ce_ptr) == FAILURE) {
589 		RETURN_THROWS();
590 	}
591 
592 	/* Fetch the object (without resetting its last error code ). */
593 	to = Z_INTL_TIMEZONE_P(object);
594 	if (to == NULL)
595 		RETURN_FALSE;
596 
597 	RETURN_LONG((zend_long)TIMEZONE_ERROR_CODE(to));
598 }
599 
PHP_FUNCTION(intltz_get_error_message)600 U_CFUNC PHP_FUNCTION(intltz_get_error_message)
601 {
602 	zend_string* message = NULL;
603 	TIMEZONE_METHOD_INIT_VARS
604 
605 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
606 			&object, TimeZone_ce_ptr) == FAILURE) {
607 		RETURN_THROWS();
608 	}
609 
610 
611 	/* Fetch the object (without resetting its last error code ). */
612 	to = Z_INTL_TIMEZONE_P(object);
613 	if (to == NULL)
614 		RETURN_FALSE;
615 
616 	/* Return last error message. */
617 	message = intl_error_get_message(TIMEZONE_ERROR_P(to));
618 	RETURN_STR(message);
619 }
620 
621 #if U_ICU_VERSION_MAJOR_NUM >= 52
622 /* {{{ Translate a system timezone (e.g. "America/Los_Angeles" into a
623 Windows Timezone (e.g. "Pacific Standard Time")
624  */
PHP_FUNCTION(intltz_get_windows_id)625 U_CFUNC PHP_FUNCTION(intltz_get_windows_id)
626 {
627 	zend_string *id, *winID;
628 	UnicodeString uID, uWinID;
629 	UErrorCode error;
630 
631 	ZEND_PARSE_PARAMETERS_START(1, 1)
632 		Z_PARAM_STR(id)
633 	ZEND_PARSE_PARAMETERS_END();
634 
635 	error = U_ZERO_ERROR;
636 	if (intl_stringFromChar(uID, id->val, id->len, &error) == FAILURE) {
637 		intl_error_set(NULL, error,
638 		               "could not convert time zone id to UTF-16", 0);
639 		RETURN_FALSE;
640 	}
641 
642 	error = U_ZERO_ERROR;
643 	TimeZone::getWindowsID(uID, uWinID, error);
644 	INTL_CHECK_STATUS(error, "intltz_get_windows_id: Unable to get timezone from windows ID");
645 	if (uWinID.length() == 0) {
646 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
647 		               "unknown system timezone", 0);
648 		RETURN_FALSE;
649 	}
650 
651 	error = U_ZERO_ERROR;
652 	winID = intl_convert_utf16_to_utf8(uWinID.getBuffer(), uWinID.length(), &error);
653 	INTL_CHECK_STATUS(error, "could not convert time zone id to UTF-8");
654 	RETURN_STR(winID);
655 }
656 /* }}} */
657 
658 /* {{{ Translate a windows timezone (e.g. "Pacific Time Zone" into a
659 System Timezone (e.g. "America/Los_Angeles")
660  */
PHP_FUNCTION(intltz_get_id_for_windows_id)661 U_CFUNC PHP_FUNCTION(intltz_get_id_for_windows_id)
662 {
663 	zend_string *winID, *region = NULL, *id;
664 	UnicodeString uWinID, uID;
665 	UErrorCode error;
666 
667 	ZEND_PARSE_PARAMETERS_START(1, 2)
668 		Z_PARAM_STR(winID)
669 		Z_PARAM_OPTIONAL
670 		Z_PARAM_STR_OR_NULL(region)
671 	ZEND_PARSE_PARAMETERS_END();
672 
673 	error = U_ZERO_ERROR;
674 	if (intl_stringFromChar(uWinID, winID->val, winID->len, &error) == FAILURE) {
675 		intl_error_set(NULL, error,
676 		               "could not convert time zone id to UTF-16", 0);
677 		RETURN_FALSE;
678 	}
679 
680 	error = U_ZERO_ERROR;
681 	TimeZone::getIDForWindowsID(uWinID, region ? region->val : NULL, uID, error);
682 	INTL_CHECK_STATUS(error, "unable to get windows ID for timezone");
683 	if (uID.length() == 0) {
684 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
685 		               "unknown windows timezone", 0);
686 		RETURN_FALSE;
687 	}
688 
689 	error = U_ZERO_ERROR;
690 	id = intl_convert_utf16_to_utf8(uID.getBuffer(), uID.length(), &error);
691 	INTL_CHECK_STATUS(error, "could not convert time zone id to UTF-8");
692 	RETURN_STR(id);
693 }
694 /* }}} */
695 #endif
696