Skip to content

Commit

Permalink
Wrong create_from_format (#7)
Browse files Browse the repository at this point in the history
 more instead method for create_from_format
  • Loading branch information
zeriyoshi authored Sep 11, 2024
1 parent d531254 commit 7bbcf85
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 23 deletions.
127 changes: 104 additions & 23 deletions ext/hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
| Author: Go Kudo <[email protected]> |
+----------------------------------------------------------------------+
*/

#include "hook.h"

#include "php.h"
Expand All @@ -32,9 +31,82 @@
# include <sys/time.h>
#endif

typedef struct _format_flags_t {
bool y, m, d, h, i, s, us;
} format_flags_t;

static inline void parse_format(char *format, format_flags_t *flags) {
memset(flags, 0, sizeof(format_flags_t));
bool skip_next = false;

for (char *c = format; *c != '\0'; c++) {
if (skip_next) {
skip_next = false;
continue;
}
switch (*c) {
case '\\':
skip_next = true;
continue;
case 'X':
case 'x':
case 'Y':
case 'y':
flags->y = true;
continue;
case 'F':
case 'M':
case 'm':
case 'n':
flags->m = true;
continue;
case 'd':
case 'j':
case 'D':
/* case 'l': */
/* case 'S': */
case 'z':
flags->d = true;
continue;
/* case 'a': */
/* case 'A': */
case 'g':
case 'h':
case 'G':
case 'H':
flags->h = true;
continue;
case 'i':
flags->i = true;
continue;
case 's':
flags->s = true;
continue;
case 'v':
case 'u':
flags->us = true;
continue;
case '!':
case '|':
case 'U':
flags->y = true;
flags->m = true;
flags->d = true;
flags->h = true;
flags->i = true;
flags->s = true;
flags->us = true;
continue;
default:
continue;
}
}
}

static inline void apply_interval(timelib_time **time, timelib_rel_time *interval)
{
timelib_time *new_time = timelib_sub(*time, interval);
timelib_update_ts(new_time, NULL);
timelib_time_dtor(*time);
*time = new_time;
}
Expand Down Expand Up @@ -107,37 +179,46 @@ 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; \
\
zend_object *object; \
php_date_obj *object_date; \
timelib_rel_time interval; \
zend_string *format, *_datetime; \
zval *_timezone_object; \
format_flags_t flags; \
\
CALL_ORIGINAL_FUNCTION(name); \
\
if (EG(exception) || Z_TYPE_P(return_value) == IS_FALSE) { \
RETURN_FALSE; \
if (!return_value || Z_TYPE_P(return_value) == IS_FALSE || !Z_PHPDATE_P(return_value)->time) { \
return; \
} \
\
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); \
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 2, 3); \
Z_PARAM_STR(format) \
Z_PARAM_STR(_datetime) \
Z_PARAM_OPTIONAL \
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(_timezone_object, php_date_get_timezone_ce()) \
ZEND_PARSE_PARAMETERS_END(); \
\
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; \
} \
parse_format(ZSTR_VAL(format), &flags); \
\
timelib_time temp; \
timelib_rel_time interval; \
get_shift_interval(&interval); \
memcpy(&temp, Z_PHPDATE_P(return_value)->time, sizeof(timelib_time)); \
\
apply_interval(&Z_PHPDATE_P(return_value)->time, &interval); \
if (flags.h || flags.i || flags.s || flags.us) { \
Z_PHPDATE_P(return_value)->time->h = 0; \
Z_PHPDATE_P(return_value)->time->i = 0; \
Z_PHPDATE_P(return_value)->time->s = 0; \
Z_PHPDATE_P(return_value)->time->us = 0; \
} \
if (flags.y) { Z_PHPDATE_P(return_value)->time->y = temp.y; } \
if (flags.m) { Z_PHPDATE_P(return_value)->time->m = temp.m; } \
if (flags.d) { Z_PHPDATE_P(return_value)->time->d = temp.d; } \
if (flags.h) { Z_PHPDATE_P(return_value)->time->h = temp.h; } \
if (flags.i) { Z_PHPDATE_P(return_value)->time->i = temp.i; } \
if (flags.s) { Z_PHPDATE_P(return_value)->time->s = temp.s; } \
if (flags.us) { Z_PHPDATE_P(return_value)->time->us = temp.us; } \
\
timelib_update_ts(Z_PHPDATE_P(return_value)->time, NULL); \
}

#define DEFINE_CREATE_FROM_FORMAT(name) \
Expand Down
File renamed without changes.
83 changes: 83 additions & 0 deletions ext/tests/gh7.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
--TEST--
Check GitHub PR - #7 (wrong createFromFormat)
--EXTENSIONS--
colopl_timeshifter
--FILE--
<?php

$first = date_create_from_format('Ymd', '19941026');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('PT1H'));
$second = date_create_from_format('Ymd', '19941026');
/* Sometimes delay */
if ($first->diff($second)->format('%h%i%s') !== '100' && $first->diff($second)->format('%h%i%s') !== '05959') {
die('fail: ' . $first->diff($second)->format('%h%i%s'));
}
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('i', '30');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1MT30S'));
$second = date_create_from_format('i', '30');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('YmdHisu', '19941026112233444444');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('PT30M'));
$second = date_create_from_format('YmdHisu', '19941026112233444444');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('!Hisu', '112233444444');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('PT30M'));
$second = date_create_from_format('!Hisu', '112233444444');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('dm|', '2610');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1D'));
$second = date_create_from_format('dm|', '2610');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('P', 'Asia/Tokyo');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('PT30M'));
$second = date_create_from_format('P', 'Asia/Tokyo');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('Ym\\d', '199410d');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1M'));
$second = date_create_from_format('Ym\\d', '199410d');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('u\\Y\\m\\d', '123456Ymd');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1M'));
$second = date_create_from_format('u\\Y\\m\\d', '123456Ymd');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('YmdP', '19941026Asia/Tokyo');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1M'));
$second = date_create_from_format('YmdP', '19941026Asia/Tokyo');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

$first = date_create_from_format('uYmdP', '12345619941026Asia/Tokyo');
\Colopl\ColoplTimeShifter\register_hook(new DateInterval('P1M'));
$second = date_create_from_format('uYmdP', '12345619941026Asia/Tokyo');
echo $first->diff($second)->format('%y-%m-%d %h:%i:%s.%F'), \PHP_EOL;
\Colopl\ColoplTimeShifter\unregister_hook();

?>
--EXPECTF--
0-0-0 %d:%d:%d.000000
0-1-0 0:0:0.000000
0-0-0 0:0:0.000000
0-0-0 0:0:0.000000
0-0-0 0:0:0.000000
0-0-0 0:%d:%d.%d
0-0-0 0:0:0.000000
0-1-0 0:0:0.000000
0-0-0 0:0:0.000000
0-0-0 0:0:0.000000

0 comments on commit 7bbcf85

Please sign in to comment.