diff --git a/php_timecop.h b/php_timecop.h index 4040bf3..5996bd3 100644 --- a/php_timecop.h +++ b/php_timecop.h @@ -49,6 +49,8 @@ PHP_FUNCTION(timecop_freeze); PHP_FUNCTION(timecop_travel); PHP_FUNCTION(timecop_return); PHP_FUNCTION(timecop_time); +PHP_FUNCTION(timecop_mktime); +PHP_FUNCTION(timecop_gmmktime); PHP_FUNCTION(timecop_date); PHP_FUNCTION(timecop_gmdate); PHP_FUNCTION(timecop_idate); diff --git a/tests/004.phpt b/tests/004.phpt new file mode 100644 index 0000000..bd269ed --- /dev/null +++ b/tests/004.phpt @@ -0,0 +1,24 @@ +--TEST-- +Check for timecop_mktime +--SKIPIF-- + +--INI-- +date.timezone=America/Los_Angeles +--FILE-- + +--FILE-- +param_count = num_args; + fci->params = safe_emalloc(num_args, sizeof(zval**), 0); + args = safe_emalloc(num_args, sizeof(zval *), 0); + for (i = 0; i < num_args; i++) { + MAKE_STD_ZVAL(args[i]); + fci->params[i] = &args[i]; + } + fci->no_separation = 0; + return 1; +} + +static int init_timecop_date_fcall_info(zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc TSRMLS_DC) +{ + int ret; + ret = init_fcall_info(callable, fci, fcc, 2); + if (ret) { + ZVAL_LONG(*fci->params[1], _timecop_current_timestamp()); + } + return ret; +} + +static zval *timecop_date_fcall(const char *format, zend_fcall_info * fci, zend_fcall_info_cache * fcc TSRMLS_DC) +{ + zval *zvalue; + MAKE_STD_ZVAL(zvalue); + ZVAL_STRING(*fci->params[0], format, 1); + if (zend_call_function(fci, fcc TSRMLS_CC) == SUCCESS && + fci->retval_ptr_ptr && *fci->retval_ptr_ptr) { + COPY_PZVAL_TO_ZVAL(*zvalue, *fci->retval_ptr_ptr); + } + return zvalue; +} + +static zval ***alloc_fcall_params(int num_args) +{ + int i; + zval ***params, **args; + params = safe_emalloc(num_args, sizeof(zval**), 0); + args = safe_emalloc(num_args, sizeof(zval *), 0); + for (i = 0; i < num_args; i++) { + MAKE_STD_ZVAL(args[i]); + params[i] = &args[i]; + } + return params; +} + +static void dtor_fcall_params(zval ***params, int num_args) +{ + int i; + for (i = 0; i < num_args; i++) { + zval_ptr_dtor(params[i]); + } + efree(*params); + efree(params); +} + +static void copy_fcall_params(zval ***src, zval ***dst, int num_args) +{ + int i; + for (i = 0; i < num_args; i++) { + ZVAL_ZVAL(*dst[i], *src[i], 1, 0) + } +} + +static int fill_mktime_params(zval ***params, zval *date_callable, int from) +{ + zval *zp, *date_retval_ptr = NULL; + zend_fcall_info date_fci; + zend_fcall_info_cache date_fci_cache; + char *formats[] = {"H", "i", "s", "n", "j", "Y"}; + int i, max_params = 6; + + if (!init_timecop_date_fcall_info(date_callable, &date_fci, &date_fci_cache)) { + return from; + } + date_fci.retval_ptr_ptr = &date_retval_ptr; + + for (i = from; i < max_params; i++) { + zp = timecop_date_fcall(formats[i], &date_fci, &date_fci_cache TSRMLS_CC); + ZVAL_ZVAL(*params[i], zp, 1, 1); + } + return max_params; +} + +/* {{{ php_timecop_mktime - timecop_(gm)mktime helper */ +PHPAPI void php_timecop_mktime(INTERNAL_FUNCTION_PARAMETERS, zval *mktime_callable, zval *date_callable) +{ + zval *retval_ptr = NULL; + zend_fcall_info fci; + zend_fcall_info_cache fci_cache; + char *is_callable_error = NULL; + int old_param_count; + int i; + int argc = 0; + zval ***args = NULL; + + zend_fcall_info_init(mktime_callable, 0, &fci, &fci_cache, NULL, &is_callable_error TSRMLS_CC); + fci.retval_ptr_ptr = &retval_ptr; + fci.no_separation = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &args, &argc) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() >= 6) { + fci.params = args; + fci.param_count = argc; + } else { + fci.params = alloc_fcall_params(6); + copy_fcall_params(args, fci.params, argc); + if (args) { + efree(args); + } + fci.param_count = fill_mktime_params(fci.params, date_callable, argc); + } + + if (ZEND_NUM_ARGS() == 0) { + php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead"); + } + + if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && fci.retval_ptr_ptr && *fci.retval_ptr_ptr) { + COPY_PZVAL_TO_ZVAL(*return_value, *fci.retval_ptr_ptr); + } + + if (fci.params) { + if (ZEND_NUM_ARGS() >= 6) { + efree(fci.params); + } else { + dtor_fcall_params(fci.params, 6); + } + } +} + +/* {{{ proto int timecop_mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]]) + Get UNIX timestamp for a date */ +PHP_FUNCTION(timecop_mktime) +{ + zval mktime_callable, date_callable; + if (TIMECOP_G(func_overload)){ + ZVAL_STRING(&mktime_callable, "timecop_orig_mktime", 1); + ZVAL_STRING(&date_callable, "timecop_orig_date", 1); + } else { + ZVAL_STRING(&mktime_callable, "mktime", 1); + ZVAL_STRING(&date_callable, "date", 1); + } + php_timecop_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, &mktime_callable, &date_callable); +} +/* }}} */ + +/* {{{ proto int timecop_gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]]) + Get UNIX timestamp for a GMT date */ +PHP_FUNCTION(timecop_gmmktime) +{ + zval mktime_callable, date_callable; + if (TIMECOP_G(func_overload)){ + ZVAL_STRING(&mktime_callable, "timecop_orig_gmmktime", 1); + ZVAL_STRING(&date_callable, "timecop_orig_gmdate", 1); + } else { + ZVAL_STRING(&mktime_callable, "gmmktime", 1); + ZVAL_STRING(&date_callable, "gmdate", 1); + } + php_timecop_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, &mktime_callable, &date_callable); +} +/* }}} */ + /* {{{ proto string timecop_date(string format [, long timestamp]) Format a local date/time */ PHP_FUNCTION(timecop_date)