Skip to content

Commit

Permalink
Merge pull request #6 from colopl/fix_create_from_format
Browse files Browse the repository at this point in the history
Fix DateTime::createFromFormat
  • Loading branch information
zeriyoshi authored Sep 10, 2024
2 parents 8872ce5 + 5fae76a commit 7031efc
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 57 deletions.
79 changes: 26 additions & 53 deletions ext/hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,60 +107,37 @@ static inline void apply_interval(timelib_time **time, timelib_rel_time *interva
#define DEFINE_CREATE_FROM_FORMAT_EX(fname, name) \
static void hook_##fname(INTERNAL_FUNCTION_PARAMETERS) { \
CHECK_STATE(name); \
timelib_time orig; \
\
php_date_obj *date; \
timelib_time *time = NULL; \
zval *params, orig_return_value; \
uint32_t param_count = 0; \
timelib_time *current_time = get_current_timelib_time(); \
timelib_time *shifted_time = get_shifted_timelib_time(); \
zend_object *object; \
php_date_obj *object_date; \
timelib_rel_time interval; \
\
CALL_ORIGINAL_FUNCTION(name); \
\
if (EG(exception) || Z_TYPE_P(return_value) == IS_FALSE) { \
RETURN_FALSE; \
} \
\
date = Z_PHPDATE_P(return_value); \
time = date->time; \
\
zend_parse_parameters(ZEND_NUM_ARGS(), "+", &params, &param_count); \
memcpy(&orig, Z_PHPDATE_P(return_value)->time, sizeof(timelib_time)); \
/* Note: createFromFormat does not handle microseconds, so a wait in seconds is necessary */ \
usleep(((uint32_t) COLOPL_TS_G(usleep_sec)) > 0 ? ((uint32_t) COLOPL_TS_G(usleep_sec) * 1000000) : 1000000); \
zval_ptr_dtor(return_value); \
CALL_ORIGINAL_FUNCTION(name); \
\
if (memchr(Z_STRVAL(params[0]), '!', Z_STRLEN(params[0])) != NULL) { \
/* fixed (unix epoch) */ \
if (Z_PHPDATE_P(return_value)->time->y == orig.y && \
Z_PHPDATE_P(return_value)->time->m == orig.m && \
Z_PHPDATE_P(return_value)->time->d == orig.d && \
Z_PHPDATE_P(return_value)->time->h == orig.h && \
Z_PHPDATE_P(return_value)->time->i == orig.i && \
Z_PHPDATE_P(return_value)->time->s == orig.s && \
Z_PHPDATE_P(return_value)->time->us == orig.us \
) { \
return; \
} \
\
/* Fixed check */ \
if (current_time->y == time->y) { \
time->y = shifted_time->y; \
} \
if (current_time->m == time->m) { \
time->m = shifted_time->m; \
} \
if (current_time->d == time->d) { \
time->d = shifted_time->d; \
} \
if (current_time->h == time->h) { \
time->h = shifted_time->h; \
} \
if (current_time->i == time->i) { \
time->i = shifted_time->i; \
} \
/* Maybe sometimes mistake, but not bothered. */ \
if (llabs(current_time->s - time->s) <= 3) { \
time->s = shifted_time->s; \
} \
if (llabs(current_time->us - time->us) <= 10) { \
time->us = shifted_time->us; \
} \
\
/* Apply changes */ \
timelib_update_ts(time, NULL); \
\
/* Clean up */ \
timelib_time_dtor(current_time); \
timelib_time_dtor(shifted_time); \
get_shift_interval(&interval); \
apply_interval(&Z_PHPDATE_P(return_value)->time, &interval); \
}

#define DEFINE_CREATE_FROM_FORMAT(name) \
Expand Down Expand Up @@ -224,17 +201,13 @@ static inline bool is_fixed_time_str(zend_string *datetime, zval *timezone)
before = Z_PHPDATE_P(&before_zv);
php_date_initialize(before, ZSTR_VAL(datetime), ZSTR_LEN(datetime), NULL, timezone, 0);

/*
* Check format is absolute.
* FIXME: Need more instead method.
*/
usleep(((uint32_t) COLOPL_TS_G(usleep_sec)) > 0 ? (uint32_t) COLOPL_TS_G(usleep_sec) : 1);

php_date_instantiate(ce, &after_zv);
after = Z_PHPDATE_P(&after_zv);
php_date_initialize(after, ZSTR_VAL(datetime), ZSTR_LEN(datetime), NULL, timezone, 0);

is_fixed_time_str = before->time->y == after->time->y
is_fixed_time_str = before->time->y == after->time->y
&& before->time->m == after->time->m
&& before->time->d == after->time->d
&& before->time->h == after->time->h
Expand All @@ -254,7 +227,7 @@ static inline timelib_time *get_current_timelib_time()
timelib_time *t = timelib_time_ctor();

timelib_unixtime2gmt(t, php_time());

return t;
}

Expand Down Expand Up @@ -328,7 +301,7 @@ static void hook_pdo_con(INTERNAL_FUNCTION_PARAMETERS)

CALL_ORIGINAL_FUNCTION(pdo_con);

if (!dbh->driver ||
if (!dbh->driver ||
strncmp(dbh->driver->driver_name, "mysql", 5) == 0 ||
dbh->methods != &COLOPL_TS_G(hooked_mysql_driver_methods)
) {
Expand Down Expand Up @@ -437,10 +410,10 @@ static inline void date_create_common(INTERNAL_FUNCTION_PARAMETERS, zend_class_e
php_date_instantiate(ce, return_value);
if (!php_date_initialize(
Z_PHPDATE_P(return_value),
(!time_str ? NULL : ZSTR_VAL(time_str)),
(!time_str ? NULL : ZSTR_VAL(time_str)),
(!time_str ? 0 : ZSTR_LEN(time_str)),
NULL,
timezone_object,
NULL,
timezone_object,
0
)) {
zval_ptr_dtor(return_value);
Expand Down Expand Up @@ -778,7 +751,7 @@ void apply_request_time_hook()
globals_server = zend_hash_str_find(&EG(symbol_table), "_SERVER", strlen("_SERVER"));

if (!globals_server || Z_TYPE_P(globals_server) != IS_ARRAY) {
/* $_SERVER not defined */
/* $_SERVER not defined */
return;
}

Expand Down
2 changes: 1 addition & 1 deletion ext/tests/classes/datetime_create_from_format.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (!$before_now instanceof \DateTime || !$before_static instanceof \DateTime ||
die('failed');
}

if ($after_now != $before_now && $interval->y === 3 && $interval->invert === 0) {
if ($after_now != $before_now && $interval->y >= 2 && $interval->invert === 0) {
die('success');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (!$before_now instanceof \DateTimeImmutable || !$before_static instanceof \Da
die('failed');
}

if ($after_now != $before_now && $interval->y === 3 && $interval->invert === 0) {
if ($after_now != $before_now && $interval->y >= 2 && $interval->invert === 0) {
die('success');
}

Expand Down
29 changes: 29 additions & 0 deletions ext/tests/classes/gh5.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Check GitHub Issue - #5 (createFromFormat returns incorrect result during hook)
--EXTENSIONS--
colopl_timeshifter
--FILE--
<?php

$interval = @unserialize('O:12:"DateInterval":16:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:1;s:1:"h";i:1;s:1:"i";i:2;s:1:"s";i:1;s:1:"f";d:0;s:7:"weekday";i:0;s:16:"weekday_behavior";i:0;s:17:"first_last_day_of";i:0;s:6:"invert";i:1;s:4:"days";i:1;s:12:"special_type";i:0;s:14:"special_amount";i:0;s:21:"have_weekday_relative";i:0;s:21:"have_special_relative";i:0;}');

echo DateTime::createFromFormat('YmdHi', 202211091600)->format('Y-m-d H:i:s'), \PHP_EOL;

\Colopl\ColoplTimeShifter\register_hook($interval);

echo DateTime::createFromFormat('YmdHi', 202211091600)->format('Y-m-d H:i:s'), \PHP_EOL;

\Colopl\ColoplTimeShifter\unregister_hook();

echo DateTime::createFromFormat('YmdHi', 202211091600)->format('Y-m-d H:i:s'), \PHP_EOL;

\Colopl\ColoplTimeShifter\register_hook($interval);

echo DateTime::createFromFormat('YmdHi', 202211091600)->format('Y-m-d H:i:s'), \PHP_EOL;

?>
--EXPECT--
2022-11-09 16:00:00
2022-11-09 16:00:00
2022-11-09 16:00:00
2022-11-09 16:00:00
2 changes: 1 addition & 1 deletion ext/tests/functions/date_create_from_format.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (!$before_now instanceof \DateTime || !$before_static instanceof \DateTime ||
die('failed');
}

if ($after_now != $before_now && $interval->y === 3 && $interval->invert === 0) {
if ($after_now != $before_now && $interval->y >= 2 && $interval->invert === 0) {
die('success');
}

Expand Down
2 changes: 1 addition & 1 deletion ext/tests/functions/date_create_immutable_from_format.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (!$before_now instanceof \DateTimeImmutable || !$before_static instanceof \Da
die('failed');
}

if ($after_now != $before_now && $interval->y === 3 && $interval->invert === 0) {
if ($after_now != $before_now && $interval->y >= 2 && $interval->invert === 0) {
die('success');
}

Expand Down

0 comments on commit 7031efc

Please sign in to comment.