├── .appveyor.yml ├── .gitignore ├── .travis.yml ├── CREDITS ├── EXPERIMENTAL ├── LICENSE ├── README.md ├── circle.yml ├── config.m4 ├── config.w32 ├── package.xml ├── php-timecop.spec ├── php_timecop.h ├── stubs └── Timecop.php ├── tc_timeval.c ├── tc_timeval.h ├── tests ├── core_001.phpt ├── core_002.phpt ├── core_003.phpt ├── core_004.phpt ├── core_005.phpt ├── core_006.phpt ├── core_007.phpt ├── core_008.phpt ├── core_009.phpt ├── core_010.phpt ├── core_011.phpt ├── core_012.phpt ├── core_013.phpt ├── date_001.phpt ├── date_002.phpt ├── date_003.phpt ├── date_004.phpt ├── date_005.phpt ├── date_006.phpt ├── date_007.phpt ├── date_008.phpt ├── date_override_001.phpt ├── date_override_002.phpt ├── date_override_003.phpt ├── date_override_006.phpt ├── date_override_007.phpt ├── date_override_008.phpt ├── func_001.phpt ├── func_002.phpt ├── func_003.phpt ├── func_004.phpt ├── func_005.phpt ├── func_006.phpt ├── func_007.phpt ├── func_008.phpt ├── func_009.phpt ├── func_010.phpt ├── func_011.phpt ├── func_012.phpt ├── func_013.phpt ├── func_014.phpt ├── func_override_001.phpt ├── func_override_002.phpt ├── func_override_003.phpt ├── func_override_004.phpt ├── func_override_005.phpt ├── func_override_006.phpt ├── func_override_007.phpt ├── func_override_008.phpt ├── func_override_009.phpt ├── func_override_010.phpt ├── func_override_011.phpt ├── func_override_012.phpt ├── func_override_013.phpt ├── func_override_014.phpt ├── immutable_001.phpt ├── immutable_002.phpt ├── immutable_003.phpt ├── immutable_004.phpt ├── immutable_005.phpt ├── immutable_006.phpt ├── immutable_007.phpt ├── immutable_008.phpt ├── immutable_override_001.phpt ├── immutable_override_006.phpt ├── immutable_override_007.phpt ├── immutable_override_008.phpt ├── issue_009.phpt ├── issue_010.phpt ├── issue_013.phpt ├── issue_014.phpt └── tests-skipcheck.inc.php ├── timecop.php ├── timecop_php5.c ├── timecop_php7.c └── wercker.yml /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{branch}.{build}' 2 | 3 | environment: 4 | PROJECT_NAME: php-timecop 5 | REPORT_EXIT_STATUS: 1 6 | NO_INTERACTION: 1 7 | PHP_SDK_DIR: 'C:\projects\php-sdk' 8 | matrix: 9 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 10 | PHP_PACKAGE_URL: 'https://secure.php.net/distributions/php-5.4.45.tar.bz2' 11 | PHP_SDK_TOOLS_URL: 'http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip' 12 | PHP_SDK_DEPS_URL: 'http://windows.php.net/downloads/php-sdk/archives/deps-5.4-vc9-x86_2015-05.7z' 13 | VCVARS32_PATH: 'C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat' 14 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 15 | PHP_PACKAGE_URL: 'https://secure.php.net/distributions/php-5.6.29.tar.bz2' 16 | PHP_SDK_TOOLS_URL: 'http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip' 17 | PHP_SDK_DEPS_URL: 'http://windows.php.net/downloads/php-sdk/archives/deps-5.6-vc11-x86.7z' 18 | VCVARS32_PATH: 'C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\vcvars32.bat' 19 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 20 | PHP_PACKAGE_URL: 'https://secure.php.net/distributions/php-7.1.7.tar.bz2' 21 | PHP_SDK_TOOLS_URL: 'http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip' 22 | PHP_SDK_DEPS_URL: 'http://windows.php.net/downloads/php-sdk/archives/deps-7.1-vc14-x86.7z' 23 | VCVARS32_PATH: 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat' 24 | # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 25 | # PHP_PACKAGE_URL: 'https://downloads.php.net/~pollita/php-7.2.0beta1.tar.bz2' 26 | # PHP_SDK_TOOLS_URL: 'https://github.com/OSTC/php-sdk-binary-tools/archive/php-sdk-2.0.7.zip' 27 | # PHP_SDK_DEPS_URL: 'http://windows.php.net/downloads/php-sdk/deps-master-vc15-x86.7z' 28 | # VCVARS32_PATH: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat' 29 | 30 | install: 31 | - cmd: >- 32 | set PROJECT_DIR=C:\projects\%PROJECT_NAME% 33 | 34 | set TEST_PHP_EXECUTABLE=%PROJECT_DIR%\bin\php.exe 35 | 36 | for /f %%F in ("%PHP_PACKAGE_URL%") do set PHP_PACKAGE_FILENAME=%%~nxF 37 | 38 | set PHP_SRC_DIR=C:\projects\%PHP_PACKAGE_FILENAME:.tar.bz2=% 39 | 40 | for /f %%F in ("%PHP_SDK_TOOLS_URL%") do set PHP_SDK_TOOLS_FILENAME=%%~nxF 41 | 42 | set PHP_SDK_TOOLS_SUBDIR=php-sdk-binary-tools-%PHP_SDK_TOOLS_FILENAME:.zip=% 43 | 44 | for /f %%F in ("%PHP_SDK_DEPS_URL%") do set PHP_SDK_DEPS_FILENAME=%%~nxF 45 | 46 | set TEST_PHP_EXECUTABLE=%PROJECT_DIR%\bin\php.exe 47 | 48 | choco feature enable -n=allowGlobalConfirmation 49 | 50 | cinst wget 51 | 52 | mkdir %PROJECT_DIR%\bin 53 | 54 | build_script: 55 | - cmd: >- 56 | echo %APPVEYOR_BUILD_WORKER_IMAGE% 57 | 58 | echo %PROJECT_DIR% 59 | 60 | echo %TEST_PHP_EXECUTABLE% 61 | 62 | "%VCVARS32_PATH%" 63 | 64 | wget --no-check-certificate %PHP_PACKAGE_URL% 65 | 66 | 7z x -so %PHP_PACKAGE_FILENAME% | 7z x -si -ttar -oC:\projects\ 67 | 68 | wget --no-check-certificate %PHP_SDK_TOOLS_URL% 69 | 70 | 7z x -y %PHP_SDK_TOOLS_FILENAME% -o%PHP_SDK_DIR% 71 | 72 | if exist %PHP_SDK_DIR%\%PHP_SDK_TOOLS_SUBDIR% ( cd %PHP_SDK_DIR%\%PHP_SDK_TOOLS_SUBDIR% ) else ( cd %PHP_SDK_DIR% ) 73 | 74 | dir 75 | 76 | bin\phpsdk_setvars.bat 77 | 78 | mkdir %PHP_SRC_DIR%\ext\%PROJECT_NAME% 79 | 80 | xcopy %PROJECT_DIR% %PHP_SRC_DIR%\ext\%PROJECT_NAME% /s /e /y 81 | 82 | wget --no-check-certificate %PHP_SDK_DEPS_URL% 83 | 84 | 7z x -y %PHP_SDK_DEPS_FILENAME% -o%PHP_SRC_DIR% 85 | 86 | cd %PHP_SRC_DIR% 87 | 88 | buildconf.bat 89 | 90 | rem "Build failed with '--enable-zip' on PHP 7.2.0 beta1" 91 | 92 | configure.bat --disable-all --enable-phar --enable-json --enable-hash --enable-ctype --enable-filter --enable-tokenizer --with-iconv --with-openssl --with-dom --with-libxml --enable-zip --enable-timecop=shared --enable-cli --enable-zts --with-config-file-scan-dir=%PROJECT_DIR%\bin\modules.d --with-prefix=%PROJECT_DIR%\bin --with-php-build=deps 93 | 94 | nmake 95 | 96 | nmake install 97 | 98 | copy php.ini-development %PROJECT_DIR%\bin\php.ini 99 | 100 | mkdir %PROJECT_DIR%\bin\modules.d 101 | 102 | echo extension=php_timecop.dll >> %PROJECT_DIR%\bin\modules.d\php.ini 103 | 104 | test_script: 105 | - cmd: >- 106 | echo %PROJECT_DIR% 107 | 108 | echo %TEST_PHP_EXECUTABLE% 109 | 110 | cd %PROJECT_DIR% 111 | 112 | if exist bin dir bin 113 | 114 | if exist bin\ext dir bin\ext 115 | 116 | if exist bin\modules.d dir bin\modules.d 117 | 118 | "%TEST_PHP_EXECUTABLE%" %PHP_SRC_DIR%\run-tests.php --show-diff 119 | 120 | exit /b %errorlevel% 121 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore automatically created files in building PHP extensions 2 | .deps 3 | .libs 4 | Makefile 5 | Makefile.fragments 6 | Makefile.global 7 | Makefile.objects 8 | acinclude.m4 9 | aclocal.m4 10 | autom4te.cache 11 | build 12 | config.guess 13 | config.h 14 | config.h.in 15 | config.log 16 | config.nice 17 | config.status 18 | config.sub 19 | configure 20 | configure.in 21 | install-sh 22 | libtool 23 | ltmain.sh 24 | ltmain.sh.backup 25 | missing 26 | mkinstalldirs 27 | modules 28 | run-tests.php 29 | 30 | # Ignore generated tarball 31 | timecop-*.tgz 32 | 33 | # Ignore test-related temporary files 34 | tmp-php.ini 35 | tests/*.diff 36 | tests/*.exp 37 | tests/*.log 38 | tests/*.php 39 | tests/*.sh 40 | tests/*.out 41 | 42 | # Ignore C-related temporary files 43 | *.o 44 | *.lo 45 | *.la 46 | 47 | # Ignore other temporary files 48 | #*# 49 | .*.rej 50 | *.rej 51 | .*~ 52 | *~ 53 | .#* 54 | .DS_Store 55 | Thumbs.db 56 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: php 3 | dist: xenial 4 | 5 | matrix: 6 | include: 7 | - dist: trusty 8 | php: 5.4 9 | - dist: trusty 10 | php: 5.5 11 | allow_failures: 12 | - php: master 13 | 14 | branches: 15 | except: 16 | - gh-pages 17 | - /^circleci-.*$/ 18 | - /^wercker-.*$/ 19 | 20 | php: 21 | - 5.6 22 | - 7.0 23 | - 7.1 24 | - 7.2 25 | - 7.3 26 | - master 27 | 28 | before_script: 29 | - phpize && ./configure && make 30 | 31 | script: 32 | - make test REPORT_EXIT_STATUS=1 NO_INTERACTION=1 TESTS="--show-all" | tee tests-output.txt && if grep -q 'TEST SUMMARY$' tests-output.txt ; then exit 1 ; fi 33 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | timecop 2 | -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hnw/php-timecop/3efe135ba5c34f22f2c08a7874e922b8173ccbb1/EXPERIMENTAL -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2017 Yoshio HANAWA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-timecop [![Travis CI build status](https://travis-ci.org/hnw/php-timecop.svg?branch=master)](https://travis-ci.org/hnw/php-timecop) [![CircleCI build status](https://circleci.com/gh/hnw/php-timecop.svg?style=shield)](https://circleci.com/gh/hnw/php-timecop) [![Wercker build status](https://app.wercker.com/status/bb9856dda9b2ced0bbfa44d50d7fc034/s/master "wercker status")](https://app.wercker.com/project/bykey/bb9856dda9b2ced0bbfa44d50d7fc034)[![Build status](https://ci.appveyor.com/api/projects/status/1q7c9bwera4cmv5g/branch/master?svg=true)](https://ci.appveyor.com/project/hnw/php-timecop/branch/master) 2 | 3 | ## DESCRIPTION 4 | 5 | A PHP extension providing "time travel" and "time freezing" capabilities, inspired by [ruby timecop gem](https://github.com/travisjeffery/timecop). 6 | 7 | ## INSTALL (with package manager) 8 | 9 | If you are using macOS, you can install php-timecop with [Homebrew](https://brew.sh/) . 10 | 11 | ``` 12 | brew install homebrew/php/php71-timecop 13 | ``` 14 | 15 | In Fedora, you can install php-timecop from official repository as php-pecl-timecop 16 | ``` 17 | sudo dnf install php-pecl-timecop 18 | ``` 19 | 20 | In RHEL/CentOS, you can install php-timecop from [Remi's RPM repository](https://rpms.remirepo.net/). 21 | 22 | ``` 23 | sudo yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm 24 | sudo yum install yum-utils 25 | sudo yum-config-manager --enable remi-php71 26 | sudo yum install php-pecl-timecop 27 | ``` 28 | 29 | Otherwise, you can use pecl command to install php-timecop. 30 | 31 | ``` 32 | pecl install timecop-beta 33 | ``` 34 | 35 | ## INSTALL (with phpize) 36 | 37 | ``` 38 | git clone https://github.com/hnw/php-timecop.git 39 | cd php-timecop 40 | phpize 41 | ./configure 42 | make 43 | make install 44 | ``` 45 | 46 | After install, add these lines to your `php.ini` . 47 | 48 | ```ini 49 | extension=timecop.so 50 | ``` 51 | 52 | ## INSTALL (on Windows, experimental) 53 | 54 | You can download the extension DLL from [PECL :: Package :: timecop](https://pecl.php.net/package/timecop) 55 | 56 | To install the extension, extract zip and copy `php_timecop.dll` to the extension directory. 57 | 58 | After install, add these lines to your `php.ini` . 59 | 60 | ```ini 61 | extension=php_timecop.dll 62 | ``` 63 | 64 | ## SYSTEM REQUIREMENTS 65 | 66 | - OS: Windows(experimental), Linux, macOS 67 | - PHP: 5.3.1 - 7.2.x (might work on 5.2.x and 5.3.0, but not tested enough) 68 | - SAPI: Apache, CLI 69 | - Other SAPIs are not tested, but there is no SAPI-dependent code. 70 | - non-ZTS(recommended), ZTS 71 | 72 | ## FEATURES 73 | 74 | - Freeze time to a specific point. 75 | - Travel back to a specific point in time, but allow time to continue moving forward from there. 76 | - Scale time by a given scaling factor that will cause time to move at an accelerated pace. 77 | - Override the following PHP stock functions and methods, which supports freezing or traveling time. 78 | - `time()` 79 | - `mktime()` 80 | - `gmmktime()` 81 | - `date()` 82 | - `gmdate()` 83 | - `idate()` 84 | - `getdate()` 85 | - `localtime()` 86 | - `strtotime()` 87 | - `strftime()` 88 | - `gmstrftime()` 89 | - `microtime()` 90 | - `gettimeofday()` 91 | - `unixtojd()` 92 | - `DateTime::_construct()` 93 | - `DateTime::createFromFormat()` (PHP >= 5.3.0) 94 | - `DateTimeImmutable::_construct()` (PHP >= 5.5.0) 95 | - `DateTimeImmutable::createFromFormat()` (PHP >= 5.5.0) 96 | - `date_create()` 97 | - `date_create_from_format()` (PHP >= 5.3.0) 98 | - `date_create_immutable()` (PHP >= 5.5.0) 99 | - `date_create_immutable_from_format()` (PHP >= 5.5.0) 100 | - Rewrite value of the following global variables when the time has been moved. 101 | - `$_SERVER['REQUEST_TIME']` 102 | 103 | ## USAGE 104 | 105 | ```php 106 | format("c")); // string(25) "2017-01-01T00:00:05+00:00" 141 | ``` 142 | 143 | ## CHANGELOG 144 | 145 | ### version 1.2.10(beta), 2017/11/23 146 | 147 | - Fix "double free" bug on PHP 7.2.0 ([#32](https://github.com/hnw/php-timecop/issues/32)) 148 | 149 | ### version 1.2.8(beta), 2017/7/7 150 | 151 | - Publish on PECL 152 | - Support Windows (experimental) 153 | 154 | ### version 1.2.6(beta), 2017/7/4 155 | 156 | - Bug fixed: Calling timecop_freeze() on a fast machine sometimes fails to stop the microsecond part of current time. 157 | - Support PHP 7.2.0+ 158 | 159 | ### version 1.2.4(beta), 2017/6/8 160 | 161 | - Fix [#18](https://github.com/hnw/php-timecop/issues/18) (Fix date_create_from_format when using `|` char) 162 | - Fix `timecop_date_create()`: The previous version of `timecop_date_create("@[unix timestamp]")` returns +1 hour time on PHP 5.3.9 - 5.4.7 only during the DST. 163 | 164 | ### version 1.2.3(beta), 2017/1/8 165 | - Fix `timecop_date_create_from_format()`: support time travelling 166 | - Now portions of the generated time not provided in `format` will be set to the travelled time 167 | - The previous version is completely same behavior as `date_create_from_format()`. 168 | - Remove `TimecopDateTime::getTimestamp()`, `TimecopDateTime::setTimestamp()` on PHP 5.2.x 169 | 170 | ### version 1.2.2(alpha), 2017/1/4 171 | - Implement `TimecopDateTimeImmutable` class and `timecop_date_create_immutable()`, `timecop_date_create_immutable_from_format()` functions. 172 | - Now `timecop_date_create_from_format()` returns `DateTime` instance 173 | 174 | ### version 1.2.0(alpha), 2016/12/30 175 | - Big internal change (without BC break): handle microseconds accurately in time traveling. 176 | - Now `timecop_freeze()` and `timecop_travel()` accepts either `DateTimeInterface` or `int`. 177 | - With `DateTimeInterface` argument, freezed/traveled time would have fraction of second. 178 | - Implement `timecop_scale()`: Make time go faster. 179 | - Implement `Timecop::***()` as alias of `timecop_***()`. (For `freeze`, `travel`, `return`, `scale`) 180 | 181 | ### version 1.1.3, 2016/12/27 182 | - Fix crash when non-object passed as 2nd argument of TimecopDateTime::__construct() (Fix [#9](https://github.com/hnw/php-timecop/issues/9))' 183 | - Add CI environment (CentOS, Ubuntu 32-bit, PHP 7.1) 184 | 185 | ### version 1.1.2(alpha), 2016/04/23 186 | - Fix for stock PHP on Ubuntu 187 | 188 | ### version 1.1.0(alpha), 2016/04/18 189 | - Support PHP 7.0.x 190 | - Now `new DateTime()` always returns `DateTime` instance 191 | - The previous version returns `TimecopDateTime` instance when `timecop.func_override=1`. 192 | - Implement `timecop_gettimeofday()` and `timecop_microtime()` 193 | 194 | ### version 1.0.6, 2016/04/15 195 | - Fix #10 (Timecop segfaults when set_error_handler throws an exception) 196 | 197 | ### version 1.0.5, 2013/11/26 198 | - Fix `TimecopDateTime::createFromFormat()` to reutrn `TimecopDateTime` instance on PHP >= 5.3.4 199 | - The previous version returns `DateTime` instance 200 | - Implement identical function `timecop_date_create_from_format()` 201 | - BUG: not supporting "relative formats" for this method currently. 202 | - Fix behavior of `TimecopDateTime::_construct()` when its 2nd argument is specified. 203 | 204 | ### version 1.0.4, 2013/03/11 205 | - Fix SIGSEGV in `TimecopDateTime::__construct()` called with NULL as 1st argument 206 | 207 | ### version 1.0.3, 2013/03/09 208 | 209 | - Fix the time traveling implementation for `TimecopDateTime::__construct()` 210 | - Fix `timecop_date_create()` to return `TimecopDateTime` instance 211 | - The previous version returns `DateTime` instance 212 | - Add `TimecopDateTime::getTimestamp()`, `TimecopDateTime::setTimestamp()` only for PHP 5.2.x 213 | 214 | ### version 1.0.2, 2013/03/06 215 | 216 | - Implement `timecop_date_create()` 217 | 218 | ### Version 1.0.1, 2013/03/04 219 | 220 | - Implement time traveling feature for `TimecopDateTime::__construct()` with 1 or 2 arguments 221 | - The previous version works correctly only for no arguments calling: "new TimecopDateTime()" 222 | 223 | ### version 1.0.0, 2012/11/21 224 | 225 | - Fix memory leak 226 | 227 | ### version 0.0.1, 2012/06/19 228 | 229 | - Initial Release 230 | 231 | ## LICENSE 232 | # 233 | The MIT License 234 | 235 | Copyright (c) 2012-2017 Yoshio HANAWA 236 | 237 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 238 | 239 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 240 | 241 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 242 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | general: 2 | branches: 3 | ignore: 4 | - gh-pages 5 | - /^travisci-.*$/ 6 | - /^wercker-.*$/ 7 | 8 | dependencies: 9 | pre: 10 | - case $CIRCLE_NODE_INDEX in 0) sudo apt-get update; sudo apt-get install php5-dev; phpenv global system ;; 1) phpenv global 5.6.22 ;; 2) phpenv global 7.0.11 ;; 3) phpenv global 7.1.9 ;; esac 11 | - phpenv versions 12 | - phpize && ./configure && make 13 | 14 | test: 15 | override: 16 | - make test REPORT_EXIT_STATUS=1 NO_INTERACTION=1 TESTS="--show-all" | tee tests-output.txt && if grep -q 'TEST SUMMARY$' tests-output.txt ; then exit 1 ; fi: 17 | parallel: true 18 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension timecop 3 | 4 | dnl Comments in this file start with the string 'dnl'. 5 | dnl Remove where necessary. This file will not work 6 | dnl without editing. 7 | 8 | dnl If your extension references something external, use with: 9 | 10 | dnl PHP_ARG_WITH(timecop, for timecop support, 11 | dnl Make sure that the comment is aligned: 12 | dnl [ --with-timecop Include timecop support]) 13 | 14 | dnl Otherwise use enable: 15 | 16 | PHP_ARG_ENABLE(timecop, whether to enable timecop support, 17 | [ --enable-timecop Enable timecop support]) 18 | 19 | if test "$PHP_TIMECOP" != "no"; then 20 | 21 | dnl Check PHP version: 22 | AC_MSG_CHECKING(PHP version) 23 | if test ! -z "$phpincludedir"; then 24 | PHP_VERSION=`grep 'PHP_VERSION ' $phpincludedir/main/php_version.h | sed -e 's/.*"\([[0-9]]*\.[[0-9]]*\.[[0-9]]*.*\)".*/\1/g' 2>/dev/null` 25 | elif test ! -z "$PHP_CONFIG"; then 26 | PHP_VERSION=`$PHP_CONFIG --version 2>/dev/null` 27 | fi 28 | 29 | if test x"$PHP_VERSION" = "x"; then 30 | AC_MSG_WARN([not found]) 31 | else 32 | PHP_MAJOR_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/g' 2>/dev/null` 33 | PHP_MINOR_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/g' 2>/dev/null` 34 | PHP_RELEASE_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/g' 2>/dev/null` 35 | AC_MSG_RESULT([$PHP_VERSION]) 36 | fi 37 | 38 | if test "$PHP_MAJOR_VERSION" -eq 5; then 39 | PHP_NEW_EXTENSION(timecop, timecop_php5.c tc_timeval.c, $ext_shared) 40 | else 41 | PHP_NEW_EXTENSION(timecop, timecop_php7.c tc_timeval.c, $ext_shared) 42 | fi 43 | fi 44 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | ARG_ENABLE("timecop", "enable timecop support", "no"); 5 | 6 | if (PHP_TIMECOP != "no") { 7 | if (PHP_VERSION <= 5) { 8 | EXTENSION("timecop", "timecop_php5.c tc_timeval.c"); 9 | } else { 10 | EXTENSION("timecop", "timecop_php7.c tc_timeval.c"); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | timecop 4 | pecl.php.net 5 | 6 | A PHP extension providing "time travel" capabilities. 7 | 8 | 9 | A PHP extension providing "time travel" and "time freezing" capabilities, inspired by ruby timecop gem. 10 | 11 | 12 | Yoshio HANAWA 13 | hnw 14 | y@hnw.jp 15 | yes 16 | 17 | 2017-11-23 18 | 19 | 1.2.10 20 | 1.2.10 21 | 22 | 23 | beta 24 | beta 25 | 26 | MIT License 27 | Fix "double free" bug on PHP 7.2.0 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 5.3.1 122 | 123 | 124 | 1.4.8 125 | 126 | 127 | 128 | timecop 129 | 130 | 131 | -------------------------------------------------------------------------------- /php-timecop.spec: -------------------------------------------------------------------------------- 1 | %define __ext_name timecop 2 | Name: php-%{__ext_name} 3 | Version: 1.2.7 4 | Release: 1%{?dist} 5 | Summary: php-timecop module 6 | 7 | Group: Development/Languages 8 | License: MIT 9 | URL: https://github.com/hnw/php-timecop 10 | Source0: https://github.com/hnw/php-timecop/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz 11 | BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) 12 | 13 | BuildRequires: php, php-devel 14 | Requires: php 15 | Requires: php(api) = %{php_core_api} 16 | 17 | %description 18 | A PHP extension providing "time travel" and "time freezing" capabilities, 19 | inspired by ruby timecop gem(https://github.com/travisjeffery/timecop). 20 | 21 | %prep 22 | %setup -q 23 | cat > %{__ext_name}.ini << 'EOF' 24 | ; Enable %{__ext_name} extension module 25 | extension = %{__ext_name}.so 26 | 27 | EOF 28 | 29 | %build 30 | phpize 31 | %configure 32 | make %{?_smp_mflags} 33 | make test REPORT_EXIT_STATUS=1 NO_INTERACTION=1 TESTS="--show-all" | tee tests-output.txt && if grep -q 'TEST SUMMARY$' tests-output.txt ; then exit 1 ; fi 34 | 35 | %install 36 | rm -rf %{buildroot} 37 | make install INSTALL_ROOT=%{buildroot} 38 | install -D -m 644 %{__ext_name}.ini %{buildroot}%{_sysconfdir}/php.d/%{__ext_name}.ini 39 | 40 | 41 | %clean 42 | rm -rf %{buildroot} 43 | 44 | 45 | %files 46 | %defattr(-,root,root,-) 47 | %config(noreplace) %{_sysconfdir}/php.d/%{__ext_name}.ini 48 | %{php_extdir}/%{__ext_name}.so 49 | 50 | 51 | 52 | 53 | %changelog 54 | * Wed Jun 11 2014 withgod 55 | - created 56 | -------------------------------------------------------------------------------- /php_timecop.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2012-2017 Yoshio HANAWA 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef PHP_TIMECOP_H 26 | #define PHP_TIMECOP_H 27 | 28 | #define PHP_TIMECOP_VERSION "1.2.10" 29 | 30 | extern zend_module_entry timecop_module_entry; 31 | #define phpext_timecop_ptr &timecop_module_entry 32 | 33 | #ifdef PHP_WIN32 34 | # define PHP_TIMECOP_API __declspec(dllexport) 35 | #elif defined(__GNUC__) && __GNUC__ >= 4 36 | # define PHP_TIMECOP_API __attribute__ ((visibility("default"))) 37 | #else 38 | # define PHP_TIMECOP_API 39 | #endif 40 | 41 | #ifdef ZTS 42 | #include "TSRM.h" 43 | #endif 44 | 45 | #ifndef PHP_WIN32 46 | #include 47 | #else 48 | #include "win32/time.h" 49 | #endif 50 | 51 | #include "Zend/zend_interfaces.h" 52 | #include "tc_timeval.h" 53 | 54 | PHP_MINIT_FUNCTION(timecop); 55 | PHP_MSHUTDOWN_FUNCTION(timecop); 56 | PHP_RINIT_FUNCTION(timecop); 57 | PHP_RSHUTDOWN_FUNCTION(timecop); 58 | PHP_MINFO_FUNCTION(timecop); 59 | 60 | PHP_FUNCTION(timecop_freeze); 61 | PHP_FUNCTION(timecop_travel); 62 | PHP_FUNCTION(timecop_scale); 63 | PHP_FUNCTION(timecop_return); 64 | PHP_FUNCTION(timecop_time); 65 | PHP_FUNCTION(timecop_mktime); 66 | PHP_FUNCTION(timecop_gmmktime); 67 | PHP_FUNCTION(timecop_date); 68 | PHP_FUNCTION(timecop_gmdate); 69 | PHP_FUNCTION(timecop_idate); 70 | PHP_FUNCTION(timecop_getdate); 71 | PHP_FUNCTION(timecop_localtime); 72 | PHP_FUNCTION(timecop_strtotime); 73 | PHP_FUNCTION(timecop_strftime); 74 | PHP_FUNCTION(timecop_gmstrftime); 75 | #ifdef HAVE_GETTIMEOFDAY 76 | PHP_FUNCTION(timecop_microtime); 77 | PHP_FUNCTION(timecop_gettimeofday); 78 | #endif 79 | PHP_FUNCTION(timecop_unixtojd); 80 | PHP_FUNCTION(timecop_date_create); 81 | PHP_FUNCTION(timecop_date_create_from_format); 82 | #if PHP_VERSION_ID >= 50500 83 | PHP_FUNCTION(timecop_date_create_immutable); 84 | PHP_FUNCTION(timecop_date_create_immutable_from_format); 85 | #endif 86 | #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300 87 | PHP_FUNCTION(date_timestamp_set); 88 | PHP_FUNCTION(date_timestamp_get); 89 | #endif 90 | 91 | PHP_METHOD(TimecopDateTime, __construct); 92 | PHP_METHOD(TimecopOrigDateTime, __construct); 93 | 94 | #if PHP_VERSION_ID >= 50500 95 | PHP_METHOD(TimecopDateTimeImmutable, __construct); 96 | PHP_METHOD(TimecopOrigDateTimeImmutable, __construct); 97 | #endif 98 | 99 | PHP_METHOD(Timecop, freeze); 100 | PHP_METHOD(Timecop, travel); 101 | 102 | typedef enum timecop_mode_t { 103 | TIMECOP_MODE_REALTIME, 104 | TIMECOP_MODE_FREEZE, 105 | TIMECOP_MODE_TRAVEL 106 | } timecop_mode_t; 107 | 108 | ZEND_BEGIN_MODULE_GLOBALS(timecop) 109 | long func_override; 110 | long sync_request_time; 111 | #if PHP_VERSION_ID >= 70000 112 | zval orig_request_time; 113 | #else 114 | zval *orig_request_time; 115 | #endif 116 | timecop_mode_t timecop_mode; 117 | tc_timeval freezed_time; 118 | tc_timeval travel_origin; 119 | tc_timeval travel_offset; 120 | #if PHP_VERSION_ID >= 70000 121 | zend_long scaling_factor; 122 | #else 123 | long scaling_factor; 124 | #endif 125 | zend_class_entry *ce_DateTimeZone; 126 | zend_class_entry *ce_DateTimeInterface; 127 | zend_class_entry *ce_DateTime; 128 | zend_class_entry *ce_TimecopDateTime; 129 | zend_class_entry *ce_DateTimeImmutable; 130 | zend_class_entry *ce_TimecopDateTimeImmutable; 131 | ZEND_END_MODULE_GLOBALS(timecop) 132 | 133 | #if ZEND_DEBUG 134 | # define TIMECOP_ASSERT(c) assert(c) 135 | #else 136 | # define TIMECOP_ASSERT(c) 137 | #endif /* ZEND_DEBUG */ 138 | 139 | #define SAVE_FUNC_PREFIX "timecop_orig_" 140 | #define OVRD_FUNC_PREFIX "timecop_" 141 | 142 | #define OVRD_CLASS_PREFIX "timecop" 143 | 144 | #define ORIG_FUNC_NAME(fname) \ 145 | (TIMECOP_G(func_override) ? (SAVE_FUNC_PREFIX fname) : fname) 146 | 147 | #define TIMECOP_OFE(fname) {fname, OVRD_FUNC_PREFIX fname, SAVE_FUNC_PREFIX fname} 148 | #define TIMECOP_OCE(cname, mname) \ 149 | {cname, mname, OVRD_CLASS_PREFIX cname, SAVE_FUNC_PREFIX mname} 150 | 151 | /* 152 | * Trick for guarding the multi-referenced internal function from function destructor on PHP 7.2.0+ 153 | * See: https://github.com/hnw/php-timecop/issues/29#issuecomment-332171527 154 | */ 155 | #define GUARD_FUNCTION_ARG_INFO_BEGIN(zend_func) { \ 156 | zend_arg_info *orig_arg_info; \ 157 | zend_function *zf = zend_func; \ 158 | if (zf->type == ZEND_INTERNAL_FUNCTION) { \ 159 | orig_arg_info = zf->common.arg_info; \ 160 | zf->common.arg_info = NULL; \ 161 | } 162 | 163 | #define GUARD_FUNCTION_ARG_INFO_END() \ 164 | if (zf->type == ZEND_INTERNAL_FUNCTION) { \ 165 | zf->common.arg_info = orig_arg_info; \ 166 | } \ 167 | } 168 | 169 | struct timecop_override_func_entry { 170 | char *orig_func; 171 | char *ovrd_func; 172 | char *save_func; 173 | }; 174 | 175 | struct timecop_override_class_entry { 176 | char *orig_class; 177 | char *orig_method; 178 | char *ovrd_class; 179 | char *save_method; 180 | }; 181 | 182 | #define call_php_method_with_0_params(obj, ce, method_name, retval) \ 183 | _call_php_method_with_0_params(obj, ce, method_name, retval TSRMLS_CC) 184 | 185 | #define call_php_method_with_1_params(obj, ce, method_name, retval, arg1) \ 186 | _call_php_method_with_1_params(obj, ce, method_name, retval, arg1 TSRMLS_CC) 187 | 188 | #define call_php_method_with_2_params(obj, ce, method_name, retval, arg1, arg2) \ 189 | _call_php_method_with_2_params(obj, ce, method_name, retval, arg1, arg2 TSRMLS_CC) 190 | 191 | #define call_php_function_with_0_params(function_name, retval) \ 192 | _call_php_function_with_0_params(function_name, retval TSRMLS_CC) 193 | 194 | #define call_php_function_with_1_params(function_name, retval, arg1) \ 195 | _call_php_function_with_1_params(function_name, retval, arg1 TSRMLS_CC) 196 | 197 | #define call_php_function_with_2_params(function_name, retval, arg1, arg2) \ 198 | _call_php_function_with_2_params(function_name, retval, arg1, arg2 TSRMLS_CC) 199 | 200 | #define call_php_function_with_3_params(function_name, retval, arg1, arg2, arg3) \ 201 | _call_php_function_with_3_params(function_name, retval, arg1, arg2, arg3 TSRMLS_CC) 202 | 203 | #define call_php_function_with_params(function_name, retval, param_count, params) \ 204 | _call_php_function_with_params(function_name, retval, param_count, params TSRMLS_CC) 205 | 206 | /* In every utility function you add that needs to use variables 207 | in php_timecop_globals, call TSRMLS_FETCH(); after declaring other 208 | variables used by that function, or better yet, pass in TSRMLS_CC 209 | after the last function argument and declare your utility function 210 | with TSRMLS_DC after the last declared argument. Always refer to 211 | the globals in your function as TIMECOP_G(variable). You are 212 | encouraged to rename these macros something shorter, see 213 | examples in any other php module directory. 214 | */ 215 | 216 | #if PHP_VERSION_ID >= 70000 217 | # define TIMECOP_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(timecop, v) 218 | # if defined(ZTS) && defined(COMPILE_DL_TIMECOP) 219 | ZEND_TSRMLS_CACHE_EXTERN(); 220 | # endif 221 | #else 222 | # ifdef ZTS 223 | # define TIMECOP_G(v) TSRMG(timecop_globals_id, zend_timecop_globals *, v) 224 | # else 225 | # define TIMECOP_G(v) (timecop_globals.v) 226 | # endif 227 | #endif 228 | 229 | #endif /* PHP_TIMECOP_H */ 230 | 231 | /* 232 | * Local variables: 233 | * tab-width: 4 234 | * c-basic-offset: 4 235 | * End: 236 | * vim600: noet sw=4 ts=4 fdm=marker 237 | * vim<600: noet sw=4 ts=4 238 | */ 239 | -------------------------------------------------------------------------------- /stubs/Timecop.php: -------------------------------------------------------------------------------- 1 | = 7 30 | zend_long sec, usec; 31 | #else 32 | long sec, usec; 33 | #endif 34 | usec = arg1->usec + arg2->usec; 35 | sec = arg1->sec + arg2->sec; 36 | if (usec < 0) { 37 | sec -= ((-usec) / USEC_PER_SEC + 1); 38 | usec = USEC_PER_SEC - ((-usec) % USEC_PER_SEC); 39 | if (usec == USEC_PER_SEC) { 40 | sec++; 41 | usec = 0; 42 | } 43 | } else if (usec >= USEC_PER_SEC) { 44 | sec += usec / USEC_PER_SEC; 45 | usec = usec % USEC_PER_SEC; 46 | } 47 | ret->sec = sec; 48 | ret->usec = usec; 49 | 50 | return 0; 51 | } 52 | int tc_timeval_sub(tc_timeval *ret, const tc_timeval *arg1, const tc_timeval *arg2) 53 | { 54 | #if PHP_MAJOR_VERSION >= 7 55 | zend_long sec, usec; 56 | #else 57 | long sec, usec; 58 | #endif 59 | usec = arg1->usec - arg2->usec; 60 | sec = arg1->sec - arg2->sec; 61 | if (usec < 0) { 62 | sec -= ((-usec) / USEC_PER_SEC + 1); 63 | usec = USEC_PER_SEC - ((-usec) % USEC_PER_SEC); 64 | if (usec == USEC_PER_SEC) { 65 | sec++; 66 | usec = 0; 67 | } 68 | } else if (usec >= USEC_PER_SEC) { 69 | sec += usec / USEC_PER_SEC; 70 | usec = usec % USEC_PER_SEC; 71 | } 72 | ret->sec = sec; 73 | ret->usec = usec; 74 | 75 | return 0; 76 | } 77 | 78 | #if PHP_MAJOR_VERSION >= 7 79 | int tc_timeval_mul(tc_timeval *ret, const tc_timeval *arg1, const zend_long arg2) 80 | #else 81 | int tc_timeval_mul(tc_timeval *ret, const tc_timeval *arg1, const long arg2) 82 | #endif 83 | { 84 | #if PHP_MAJOR_VERSION >= 7 85 | zend_long sec, usec; 86 | #else 87 | long sec, usec; 88 | #endif 89 | usec = arg1->usec * arg2; 90 | sec = arg1->sec * arg2; 91 | if (usec < 0) { 92 | sec -= ((-usec) / USEC_PER_SEC + 1); 93 | usec = USEC_PER_SEC - ((-usec) % USEC_PER_SEC); 94 | if (usec == USEC_PER_SEC) { 95 | sec++; 96 | usec = 0; 97 | } 98 | } else if (usec >= USEC_PER_SEC) { 99 | sec += usec / USEC_PER_SEC; 100 | usec = usec % USEC_PER_SEC; 101 | } 102 | ret->sec = sec; 103 | ret->usec = usec; 104 | 105 | return 0; 106 | } 107 | 108 | /* 109 | * Local variables: 110 | * tab-width: 4 111 | * c-basic-offset: 4 112 | * End: 113 | * vim600: noet sw=4 ts=4 fdm=marker 114 | * vim<600: noet sw=4 ts=4 115 | */ 116 | -------------------------------------------------------------------------------- /tc_timeval.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2012-2017 Yoshio HANAWA 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef TC_TIMEVAL_H 26 | #define TC_TIMEVAL_H 27 | 28 | #ifndef USEC_PER_SEC 29 | # define USEC_PER_SEC 1000000 30 | #endif 31 | 32 | typedef struct _tc_timeval { 33 | #if PHP_MAJOR_VERSION >= 7 34 | zend_long sec; 35 | zend_long usec; 36 | #else 37 | long sec; 38 | long usec; 39 | #endif 40 | } tc_timeval; 41 | 42 | 43 | int tc_timeval_add(tc_timeval *ret, const tc_timeval *arg1, const tc_timeval *arg2); 44 | int tc_timeval_sub(tc_timeval *ret, const tc_timeval *arg1, const tc_timeval *arg2); 45 | #if PHP_MAJOR_VERSION >= 7 46 | int tc_timeval_mul(tc_timeval *ret, const tc_timeval *arg1, const zend_long arg2); 47 | #else 48 | int tc_timeval_mul(tc_timeval *ret, const tc_timeval *arg1, const long arg2); 49 | #endif 50 | 51 | #endif /* TC_TIMEVAL_H */ 52 | 53 | /* 54 | * Local variables: 55 | * tab-width: 4 56 | * c-basic-offset: 4 57 | * End: 58 | * vim600: noet sw=4 ts=4 fdm=marker 59 | * vim<600: noet sw=4 ts=4 60 | */ 61 | -------------------------------------------------------------------------------- /tests/core_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for timecop_freeze() 3 | --SKIPIF-- 4 | setTimeZone(new DateTimeZone("America/Los_Angeles")); 35 | } 36 | 37 | timecop_freeze(1); 38 | $dt7 =new TimecopDateTime(); 39 | 40 | var_dump($dt2->format("Y-m-d H:i:s.uP")); 41 | var_dump($dt4->format("Y-m-d H:i:s.uP")); 42 | var_dump($dt6->format("Y-m-d H:i:s.uP")); 43 | var_dump($dt1 == $dt2); 44 | var_dump($dt3 == $dt4); 45 | var_dump($dt5 == $dt6); 46 | var_dump($dt7->format("Y-m-d H:i:s.uP")); 47 | --EXPECT-- 48 | string(32) "1969-12-31 16:00:00.000000-08:00" 49 | string(32) "1970-01-01 01:00:00.000000-08:00" 50 | string(32) "2039-12-31 16:00:00.000000-08:00" 51 | bool(true) 52 | bool(true) 53 | bool(true) 54 | string(32) "1969-12-31 16:00:01.000000-08:00" 55 | -------------------------------------------------------------------------------- /tests/core_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for timecop_travel() 3 | --SKIPIF-- 4 | modify("+1second"); 38 | $dt6->setTimeZone(new DateTimeZone("America/Los_Angeles")); 39 | } 40 | 41 | timecop_travel(1); 42 | sleep(1); 43 | $dt7 =new TimecopDateTime(); 44 | 45 | var_dump($dt2->format("Y-m-d H:i:s")); 46 | var_dump($dt4->format("Y-m-d H:i:s")); 47 | var_dump($dt6->format("Y-m-d H:i:s")); 48 | var_dump($dt1 < $dt2); 49 | var_dump($dt3 < $dt4); 50 | var_dump($dt5 < $dt6); 51 | var_dump($dt7->format("Y-m-d H:i:s")); 52 | --EXPECT-- 53 | string(19) "1969-12-31 16:00:01" 54 | string(19) "1970-01-01 01:00:01" 55 | string(19) "2039-12-31 16:00:01" 56 | bool(true) 57 | bool(true) 58 | bool(true) 59 | string(19) "1969-12-31 16:00:02" 60 | -------------------------------------------------------------------------------- /tests/core_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for timecop_scale() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s")); 25 | var_dump($dt3->format("Y-m-d H:i:s")); 26 | --EXPECT-- 27 | string(19) "1969-12-31 16:00:02" 28 | string(19) "1969-12-31 16:00:04" 29 | -------------------------------------------------------------------------------- /tests/core_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for timecop_return() 3 | --SKIPIF-- 4 | $dt3); 22 | --EXPECT-- 23 | bool(false) 24 | bool(false) 25 | bool(true) 26 | -------------------------------------------------------------------------------- /tests/core_005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for Timecop::freeze() 3 | --SKIPIF-- 4 | setTimeZone(new DateTimeZone("Pacific/Honolulu")); 36 | } 37 | 38 | Timecop::freeze(7); 39 | $dt7 =new TimecopDateTime(); 40 | 41 | var_dump($dt2->format("Y-m-d H:i:s.u")); 42 | var_dump($dt4->format("Y-m-d H:i:s.u")); 43 | var_dump($dt6->format("Y-m-d H:i:s.u")); 44 | var_dump($dt1 == $dt2); 45 | var_dump($dt3 == $dt4); 46 | var_dump($dt5 == $dt6); 47 | var_dump($dt7->format("Y-m-d H:i:s.u")); 48 | --EXPECT-- 49 | string(26) "1969-12-31 14:00:00.000000" 50 | string(26) "1970-01-01 01:00:00.000000" 51 | string(26) "2039-12-31 14:00:05.000000" 52 | bool(true) 53 | bool(true) 54 | bool(true) 55 | string(26) "1969-12-31 14:00:07.000000" 56 | -------------------------------------------------------------------------------- /tests/core_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for Timecop::travel() 3 | --SKIPIF-- 4 | modify("+1second"); 37 | $dt6->setTimeZone(new DateTimeZone("America/Los_Angeles")); 38 | } 39 | 40 | Timecop::travel(1); 41 | sleep(1); 42 | $dt7 =new TimecopDateTime(); 43 | 44 | var_dump($dt2->format("Y-m-d H:i:s")); 45 | var_dump($dt4->format("Y-m-d H:i:s")); 46 | var_dump($dt6->format("Y-m-d H:i:s")); 47 | var_dump($dt1 < $dt2); 48 | var_dump($dt3 < $dt4); 49 | var_dump($dt5 < $dt6); 50 | var_dump($dt7->format("Y-m-d H:i:s")); 51 | --EXPECT-- 52 | string(19) "1969-12-31 16:00:01" 53 | string(19) "1970-01-01 01:00:01" 54 | string(19) "2039-12-31 16:00:01" 55 | bool(true) 56 | bool(true) 57 | bool(true) 58 | string(19) "1969-12-31 16:00:02" 59 | -------------------------------------------------------------------------------- /tests/core_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for Timecop::scale() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s")); 24 | var_dump($dt3->format("Y-m-d H:i:s")); 25 | --EXPECT-- 26 | string(19) "1969-12-31 16:00:02" 27 | string(19) "1969-12-31 16:00:04" 28 | -------------------------------------------------------------------------------- /tests/core_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for Timecop::return() 3 | --SKIPIF-- 4 | $dt3); 21 | --EXPECT-- 22 | bool(false) 23 | bool(false) 24 | bool(true) 25 | -------------------------------------------------------------------------------- /tests/core_009.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for date_timestamp_get() on PHP 5.2 3 | --SKIPIF-- 4 | = 0) { 6 | die("skip this test is for PHP 5.2.x"); 7 | } 8 | $required_class = array("timecopdatetime"); 9 | include(__DIR__."/tests-skipcheck.inc.php"); 10 | --INI-- 11 | date.timezone=America/Los_Angeles 12 | --FILE-- 13 | = 0) { 6 | die("skip this test is for PHP 5.2.x"); 7 | } 8 | $required_class = array("timecopdatetime"); 9 | include(__DIR__."/tests-skipcheck.inc.php"); 10 | --INI-- 11 | date.timezone=America/Los_Angeles 12 | --FILE-- 13 | format("U")); 17 | --EXPECT-- 18 | string(4) "2000" 19 | -------------------------------------------------------------------------------- /tests/core_011.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for $_SERVER['REQUEST_TIME'] when timecop.sync_request_time=1 3 | --SKIPIF-- 4 | enabled 17 | Version => \d+\.\d+\.\d+ 18 | 19 | Directive => Local Value => Master Value 20 | timecop\.func_override => 1 => 1 21 | timecop\.sync_request_time => 1 => 1 22 | .* 23 | -------------------------------------------------------------------------------- /tests/date_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for DateTime/TimecopDateTime/TimecopOrigDateTime inheritance 3 | --SKIPIF-- 4 | = 0) { 30 | var_dump($dt1 instanceof DateTimeInterface); 31 | var_dump($dt2 instanceof DateTimeInterface); 32 | var_dump($dt3 instanceof DateTimeInterface); 33 | } else { 34 | // force pass if PHP < 5.5.0 35 | var_dump(true); 36 | var_dump(true); 37 | var_dump(true); 38 | } 39 | echo "===\n"; 40 | var_dump($dt1->format("c") === $freezed_time); 41 | var_dump($dt2->format("c") === $freezed_time); 42 | var_dump($dt3->format("c") === $freezed_time); 43 | --EXPECT-- 44 | string(8) "DateTime" 45 | string(15) "TimecopDateTime" 46 | string(19) "TimecopOrigDateTime" 47 | bool(true) 48 | bool(true) 49 | bool(false) 50 | bool(false) 51 | bool(false) 52 | bool(false) 53 | === 54 | bool(true) 55 | bool(true) 56 | bool(true) 57 | === 58 | bool(false) 59 | bool(true) 60 | bool(false) 61 | -------------------------------------------------------------------------------- /tests/date_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for TimecopDateTime::__construct 3 | --SKIPIF-- 4 | getmessage() !== $e2->getmessage()) { 44 | printf("Exception message is differ for str=%s: %s !== %s\n", 45 | $str, $e1->getmessage(), $e2->getmessage()); 46 | } 47 | } 48 | if ($dt1 && $dt2) { 49 | if ($dt1->format("c") !== $dt2->format("c")) { 50 | printf("TimecopDatetime::format is differ from Datetime::format for str=%s: %s !== %s\n", 51 | $str, $dt1->format("c"), $dt2->format("c")); 52 | } 53 | if (version_compare(PHP_VERSION, '5.3.0') >= 0) { 54 | if ($dt1->format("U") != $dt2->getTimestamp()) { 55 | printf("TimecopDatetime::getTimestamp is differ from Datetime::getTimestamp for str=%s: %s !== %s\n", 56 | $str, $dt1->format("U"), $dt2->getTimestamp()); 57 | } 58 | } 59 | } 60 | } 61 | --EXPECT-- 62 | -------------------------------------------------------------------------------- /tests/date_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for serialize/unserialize TimecopDateTime instance 3 | --SKIPIF-- 4 | format("c")); 17 | var_dump($dt2->format("c")); 18 | --EXPECT-- 19 | string(25) "2012-01-01T12:00:00+00:00" 20 | string(25) "2012-01-01T12:00:00+00:00" 21 | -------------------------------------------------------------------------------- /tests/date_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for compareing TimecopDateTime instance 3 | --SKIPIF-- 4 | format("c")); 15 | --EXPECT-- 16 | string(25) "2012-01-01T12:00:00+00:00" 17 | -------------------------------------------------------------------------------- /tests/date_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for timecop_date_create 3 | --SKIPIF-- 4 | format("c")); 46 | } 47 | 48 | --EXPECT-- 49 | string(8) "DateTime" 50 | string(25) "2012-02-29T01:23:45-08:00" 51 | string(25) "2012-02-29T01:23:45-08:00" 52 | string(25) "2012-02-29T01:23:45-08:00" 53 | string(25) "2012-03-31T12:34:56-07:00" 54 | string(25) "2012-03-03T01:23:45-08:00" 55 | string(25) "1970-01-01T19:00:00-05:00" 56 | string(25) "1970-01-02T00:00:00+00:00" 57 | string(25) "2012-02-29T18:23:45+09:00" 58 | -------------------------------------------------------------------------------- /tests/date_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for timecop_date_create_from_format() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 32 | foreach ($tests_args as $args) { 33 | timecop_freeze($dt0); 34 | $dt1 = call_user_func_array("timecop_date_create_from_format", $args); 35 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 36 | while (true) { 37 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 38 | $start_time = time(); 39 | timecop_freeze(new DateTime()); 40 | $dt2 = call_user_func_array("timecop_date_create_from_format", $args); 41 | $dt3 = call_user_func_array("date_create_from_format", $args); 42 | if ($start_time === time()) { 43 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 44 | printf("timecop_date_create_from_format('%s', '%s') is differ from date_create_from_format() : %s !== %s\n", 45 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 46 | } 47 | break; 48 | } 49 | } 50 | } 51 | --EXPECTREGEX-- 52 | string\(8\) "DateTime" 53 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 54 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 55 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 56 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 57 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 58 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 59 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 60 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 61 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 62 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 63 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 64 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 65 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 66 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 67 | -------------------------------------------------------------------------------- /tests/date_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for TimecopDateTime::createFromFormat() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 33 | foreach ($tests_args as $args) { 34 | timecop_freeze($dt0); 35 | $dt1 = call_user_func_array(array("TimecopDateTime","createFromFormat"), $args); 36 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 37 | while (true) { 38 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 39 | $start_time = time(); 40 | timecop_freeze(new DateTime()); 41 | $dt2 = call_user_func_array(array("TimecopDateTime","createFromFormat"), $args); 42 | $dt3 = call_user_func_array(array("DateTime","createFromFormat"), $args); 43 | if ($start_time === time()) { 44 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 45 | printf("TimecopDateTime::createFromFormat('%s', '%s') is differ from DateTime::createFromFormat() : %s !== %s\n", 46 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 47 | } 48 | break; 49 | } 50 | } 51 | } 52 | --EXPECTREGEX-- 53 | string\(8\) "DateTime" 54 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 55 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 56 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 57 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 58 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 59 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 60 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 61 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 62 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 63 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 64 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 65 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 66 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 67 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 68 | -------------------------------------------------------------------------------- /tests/date_override_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for DateTime/TimecopDateTime/TimecopOrigDateTime inheritance when function override is enabled 3 | --SKIPIF-- 4 | = 0) { 30 | var_dump($dt1 instanceof DateTimeInterface); 31 | var_dump($dt2 instanceof DateTimeInterface); 32 | var_dump($dt3 instanceof DateTimeInterface); 33 | } else { 34 | // force pass if PHP < 5.5.0 35 | var_dump(true); 36 | var_dump(true); 37 | var_dump(true); 38 | } 39 | echo "===\n"; 40 | var_dump($dt1->format("c") === $freezed_time); 41 | var_dump($dt2->format("c") === $freezed_time); 42 | var_dump($dt3->format("c") === $freezed_time); 43 | --EXPECT-- 44 | string(8) "DateTime" 45 | string(15) "TimecopDateTime" 46 | string(19) "TimecopOrigDateTime" 47 | bool(true) 48 | bool(true) 49 | bool(false) 50 | bool(false) 51 | bool(false) 52 | bool(false) 53 | === 54 | bool(true) 55 | bool(true) 56 | bool(true) 57 | === 58 | bool(true) 59 | bool(true) 60 | bool(false) 61 | -------------------------------------------------------------------------------- /tests/date_override_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Method overrideing test for DateTime::__construct 3 | --SKIPIF-- 4 | format("c")); 64 | } 65 | 66 | --EXPECT-- 67 | string(8) "DateTime" 68 | string(25) "2012-02-29T01:23:45-08:00" 69 | string(25) "2012-02-29T01:23:45-08:00" 70 | string(25) "2012-02-29T01:23:45-08:00" 71 | string(25) "2012-02-29T01:23:45-08:00" 72 | string(25) "2012-03-31T00:00:00-07:00" 73 | string(25) "2013-03-01T00:00:00-08:00" 74 | string(25) "2013-03-31T00:00:00-07:00" 75 | string(25) "2013-03-31T12:34:56-07:00" 76 | string(25) "2012-02-29T12:34:56-08:00" 77 | string(25) "2012-02-29T12:34:00-08:00" 78 | string(25) "2012-03-03T01:23:45-08:00" 79 | string(25) "1970-01-01T19:00:00-05:00" 80 | string(25) "1970-01-02T00:00:00+00:00" 81 | string(25) "2012-02-29T18:23:45+09:00" 82 | -------------------------------------------------------------------------------- /tests/date_override_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for serialize/unserialize overridden DateTime instance 3 | --SKIPIF-- 4 | format("c")); 16 | var_dump($dt2->format("c")); 17 | --EXPECT-- 18 | string(25) "2012-01-01T12:00:00+00:00" 19 | string(25) "2012-01-01T12:00:00+00:00" 20 | -------------------------------------------------------------------------------- /tests/date_override_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Function overrideing test for date_create 3 | --SKIPIF-- 4 | format("c")); 46 | } 47 | 48 | --EXPECT-- 49 | string(8) "DateTime" 50 | string(25) "2012-02-29T01:23:45-08:00" 51 | string(25) "2012-02-29T01:23:45-08:00" 52 | string(25) "2012-02-29T01:23:45-08:00" 53 | string(25) "2012-03-31T12:34:56-07:00" 54 | string(25) "2012-03-03T01:23:45-08:00" 55 | string(25) "1970-01-01T19:00:00-05:00" 56 | string(25) "1970-01-02T00:00:00+00:00" 57 | string(25) "2012-02-29T18:23:45+09:00" 58 | -------------------------------------------------------------------------------- /tests/date_override_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Function overrideing test for date_create_from_format() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 34 | foreach ($tests_args as $args) { 35 | timecop_freeze($dt0); 36 | $dt1 = call_user_func_array("date_create_from_format", $args); 37 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 38 | while (true) { 39 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 40 | $start_time = time(); 41 | timecop_freeze(new TimecopOrigDateTime()); 42 | $dt2 = call_user_func_array("date_create_from_format", $args); 43 | $dt3 = call_user_func_array("timecop_orig_date_create_from_format", $args); 44 | if ($start_time === time()) { 45 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 46 | printf("date_create_from_format('%s', '%s') is differ from timecop_orig_date_create_from_format() : %s !== %s\n", 47 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 48 | } 49 | break; 50 | } 51 | } 52 | } 53 | --EXPECTREGEX-- 54 | string\(8\) "DateTime" 55 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 56 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 57 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 58 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 59 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 60 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 61 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 62 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 63 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 64 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 65 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 66 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 67 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 68 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 69 | string\(32\) "1970-03-31 00:00:00\.000000\-08:00" 70 | -------------------------------------------------------------------------------- /tests/date_override_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Method overrideing test for DateTime::createFromFormat() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 35 | foreach ($tests_args as $args) { 36 | timecop_freeze($dt0); 37 | $dt1 = call_user_func_array(array("DateTime","createFromFormat"), $args); 38 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 39 | while (true) { 40 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 41 | $start_time = time(); 42 | timecop_freeze(new TimecopOrigDateTime()); 43 | $dt2 = call_user_func_array(array("DateTime","createFromFormat"), $args); 44 | $dt3 = call_user_func_array(array("TimecopOrigDateTime","createFromFormat"), $args); 45 | if ($start_time === time()) { 46 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 47 | printf("DateTime::createFromFormat('%s', '%s') is differ from TimecopOrigDateTime::createFromFormat() : %s !== %s\n", 48 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 49 | } 50 | break; 51 | } 52 | } 53 | } 54 | --EXPECTREGEX-- 55 | string\(8\) "DateTime" 56 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 57 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 58 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 59 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 60 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 61 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 62 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 63 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 64 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 65 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 66 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 67 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 68 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 69 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 70 | string\(32\) "1970-03-31 00:00:00\.000000\-08:00" 71 | -------------------------------------------------------------------------------- /tests/func_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for timecop_time 3 | --SKIPIF-- 4 | = 0) { 31 | var_dump($dt1 instanceof DateTimeInterface); 32 | var_dump($dt2 instanceof DateTimeInterface); 33 | var_dump($dt3 instanceof DateTimeInterface); 34 | } else { 35 | // force pass if PHP < 5.5.0 36 | var_dump(true); 37 | var_dump(true); 38 | var_dump(true); 39 | } 40 | echo "===\n"; 41 | var_dump($dt1->format("c") === $dt0->format("c")); 42 | var_dump($dt2->format("c") === $dt0->format("c")); 43 | var_dump($dt3->format("c") === $dt0->format("c")); 44 | --EXPECT-- 45 | string(17) "DateTimeImmutable" 46 | string(24) "TimecopDateTimeImmutable" 47 | string(28) "TimecopOrigDateTimeImmutable" 48 | bool(true) 49 | bool(true) 50 | bool(false) 51 | bool(false) 52 | bool(false) 53 | bool(false) 54 | === 55 | bool(true) 56 | bool(true) 57 | bool(true) 58 | === 59 | bool(false) 60 | bool(true) 61 | bool(false) 62 | -------------------------------------------------------------------------------- /tests/immutable_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for TimecopDateTimeImmutable::__construct 3 | --SKIPIF-- 4 | getmessage() !== $e2->getmessage()) { 44 | printf("Exception message is differ for str=%s: %s !== %s\n", 45 | $str, $e1->getmessage(), $e2->getmessage()); 46 | } 47 | } 48 | if ($dt1 && $dt2) { 49 | if ($dt1->format("c") !== $dt2->format("c")) { 50 | printf("TimecopDatetimeImmutable::format is differ from DatetimeImmutable::format for str=%s: %s !== %s\n", 51 | $str, $dt1->format("c"), $dt2->format("c")); 52 | } 53 | if ($dt1->format("U") != $dt2->format("U")) { 54 | printf("TimecopDatetimeImmutable::getTimestamp is differ from DatetimeImmutable::getTimestamp for str=%s: %s !== %s\n", 55 | $str, $dt1->format("U"), $dt2->formmat("U")); 56 | } 57 | } 58 | } 59 | --EXPECT-- 60 | -------------------------------------------------------------------------------- /tests/immutable_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for serialize/unserialize TimecopDateTimeImmutable instance 3 | --SKIPIF-- 4 | format("c")); 16 | var_dump($dt2->format("c")); 17 | --EXPECT-- 18 | string(25) "2012-01-01T12:00:00+00:00" 19 | string(25) "2012-01-01T12:00:00+00:00" 20 | -------------------------------------------------------------------------------- /tests/immutable_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for compareing TimecopDateTimeImmutable instance 3 | --SKIPIF-- 4 | format("c")); 16 | --EXPECT-- 17 | string(25) "2012-01-01T12:00:00+00:00" 18 | -------------------------------------------------------------------------------- /tests/immutable_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for timecop_date_create_immutable 3 | --SKIPIF-- 4 | format("c")); 47 | } 48 | 49 | --EXPECT-- 50 | string(17) "DateTimeImmutable" 51 | string(25) "2012-02-29T01:23:45-08:00" 52 | string(25) "2012-02-29T01:23:45-08:00" 53 | string(25) "2012-02-29T01:23:45-08:00" 54 | string(25) "2012-03-31T12:34:56-07:00" 55 | string(25) "2012-03-03T01:23:45-08:00" 56 | string(25) "1970-01-01T19:00:00-05:00" 57 | string(25) "1970-01-02T00:00:00+00:00" 58 | string(25) "2012-02-29T18:23:45+09:00" 59 | -------------------------------------------------------------------------------- /tests/immutable_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for timecop_date_create_immutable_from_format() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 32 | foreach ($tests_args as $args) { 33 | timecop_freeze($dt0); 34 | $dt1 = call_user_func_array("timecop_date_create_immutable_from_format", $args); 35 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 36 | while (true) { 37 | /* test for equality between timecop_date_create_immutable_from_format() and date_create_immutale_from_format() */ 38 | $start_time = time(); 39 | timecop_freeze(new DateTime()); 40 | $dt2 = call_user_func_array("timecop_date_create_immutable_from_format", $args); 41 | $dt3 = call_user_func_array("date_create_immutable_from_format", $args); 42 | if ($start_time === time()) { 43 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 44 | printf("timecop_date_create_immutable_from_format('%s', '%s') is differ from date_create_immutable_from_format() : %s !== %s\n", 45 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 46 | } 47 | break; 48 | } 49 | } 50 | } 51 | --EXPECTREGEX-- 52 | string\(17\) "DateTimeImmutable" 53 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 54 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 55 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 56 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 57 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 58 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 59 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 60 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 61 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 62 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 63 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 64 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 65 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 66 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 67 | -------------------------------------------------------------------------------- /tests/immutable_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for TimecopDateTimeImmutable::createFromFormat() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 33 | foreach ($tests_args as $args) { 34 | timecop_freeze($dt0); 35 | $dt1 = call_user_func_array(array("TimecopDateTimeImmutable","createFromFormat"), $args); 36 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 37 | while (true) { 38 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 39 | $start_time = time(); 40 | timecop_freeze(new DateTime()); 41 | $dt2 = call_user_func_array(array("TimecopDateTimeImmutable","createFromFormat"), $args); 42 | $dt3 = call_user_func_array(array("DateTimeImmutable","createFromFormat"), $args); 43 | if ($start_time === time()) { 44 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 45 | printf("TimecopDateTimeImmutable::createFromFormat('%s', '%s') is differ from DateTimeImmutable::createFromFormat() : %s !== %s\n", 46 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 47 | } 48 | break; 49 | } 50 | } 51 | } 52 | --EXPECTREGEX-- 53 | string\(17\) "DateTimeImmutable" 54 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 55 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 56 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 57 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 58 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 59 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 60 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 61 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 62 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 63 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 64 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 65 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 66 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 67 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 68 | -------------------------------------------------------------------------------- /tests/immutable_override_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Test for DateTimeImmutable/TimecopDateTimeImmutable/TimecopOrigDateTimeImmutable inheritance when function override is enabled 3 | --SKIPIF-- 4 | = 0) { 31 | var_dump($dt1 instanceof DateTimeInterface); 32 | var_dump($dt2 instanceof DateTimeInterface); 33 | var_dump($dt3 instanceof DateTimeInterface); 34 | } else { 35 | // force pass if PHP < 5.5.0 36 | var_dump(true); 37 | var_dump(true); 38 | var_dump(true); 39 | } 40 | echo "===\n"; 41 | var_dump($dt1->format("c") === $dt0->format("c")); 42 | var_dump($dt2->format("c") === $dt0->format("c")); 43 | var_dump($dt3->format("c") === $dt0->format("c")); 44 | --EXPECT-- 45 | string(17) "DateTimeImmutable" 46 | string(24) "TimecopDateTimeImmutable" 47 | string(28) "TimecopOrigDateTimeImmutable" 48 | bool(true) 49 | bool(true) 50 | bool(false) 51 | bool(false) 52 | bool(false) 53 | bool(false) 54 | === 55 | bool(true) 56 | bool(true) 57 | bool(true) 58 | === 59 | bool(true) 60 | bool(true) 61 | bool(false) 62 | -------------------------------------------------------------------------------- /tests/immutable_override_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Function overrideing test for date_create_immutable 3 | --SKIPIF-- 4 | format("c")); 47 | } 48 | 49 | --EXPECT-- 50 | string(17) "DateTimeImmutable" 51 | string(25) "2012-02-29T01:23:45-08:00" 52 | string(25) "2012-02-29T01:23:45-08:00" 53 | string(25) "2012-02-29T01:23:45-08:00" 54 | string(25) "2012-03-31T12:34:56-07:00" 55 | string(25) "2012-03-03T01:23:45-08:00" 56 | string(25) "1970-01-01T19:00:00-05:00" 57 | string(25) "1970-01-02T00:00:00+00:00" 58 | string(25) "2012-02-29T18:23:45+09:00" 59 | -------------------------------------------------------------------------------- /tests/immutable_override_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Function overrideing test for date_create_immutable_from_format() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 34 | foreach ($tests_args as $args) { 35 | timecop_freeze($dt0); 36 | $dt1 = call_user_func_array("date_create_immutable_from_format", $args); 37 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 38 | while (true) { 39 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 40 | $start_time = time(); 41 | timecop_freeze(new TimecopOrigDateTime()); 42 | $dt2 = call_user_func_array("date_create_immutable_from_format", $args); 43 | $dt3 = call_user_func_array("timecop_orig_date_create_immutable_from_format", $args); 44 | if ($start_time === time()) { 45 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 46 | printf("date_create_immutable_from_format('%s', '%s') is differ from timecop_orig_date_create_immutable_from_format() : %s !== %s\n", 47 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 48 | } 49 | break; 50 | } 51 | } 52 | } 53 | --EXPECTREGEX-- 54 | string\(17\) "DateTimeImmutable" 55 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 56 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 57 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 58 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 59 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 60 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 61 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 62 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 63 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 64 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 65 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 66 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 67 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 68 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 69 | string\(32\) "1970-03-31 00:00:00\.000000\-08:00" 70 | -------------------------------------------------------------------------------- /tests/immutable_override_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Method overrideing test for DateTimeImmutable::createFromFormat() 3 | --SKIPIF-- 4 | format("Y-m-d H:i:s.uP")); 35 | foreach ($tests_args as $args) { 36 | timecop_freeze($dt0); 37 | $dt1 = call_user_func_array(array("DateTimeImmutable","createFromFormat"), $args); 38 | if (!$dt1 instanceof DateTimeImmutable) { 39 | // TODO: output an appropriate message 40 | echo get_class($dt1), "\n"; 41 | } 42 | 43 | var_dump($dt1->format("Y-m-d H:i:s.uP")); 44 | while (true) { 45 | /* test for equality between timecop_date_create_from_format() and date_create_from_format() */ 46 | $start_time = time(); 47 | timecop_freeze(new TimecopOrigDateTime()); 48 | $dt2 = call_user_func_array(array("DateTimeImmutable","createFromFormat"), $args); 49 | $dt3 = call_user_func_array(array("TimecopOrigDateTimeImmutable","createFromFormat"), $args); 50 | if ($start_time === time()) { 51 | if ($dt2 && $dt3 && ($dt2->format("c") !== $dt3->format("c"))) { 52 | printf("DateTimeImmutable::createFromFormat('%s', '%s') is differ from TimecopOrigDateTimeImmutable::createFromFormat() : %s !== %s\n", 53 | $args[0], $args[1], $dt2->format("c"), $dt3->format("c")); 54 | } 55 | break; 56 | } 57 | } 58 | } 59 | --EXPECTREGEX-- 60 | string\(17\) "DateTimeImmutable" 61 | string\(32\) "2010-01-02 03:04:05\.678000-08:00" 62 | string\(32\) "2010-01-02 03:04:05\.(000|678)000-08:00" 63 | string\(32\) "2010-01-02 03:04:05\.(\1)000-08:00" 64 | string\(32\) "1990-01-02 03:04:05\.000000-08:00" 65 | string\(32\) "2010-09-02 03:04:05\.000000-07:00" 66 | string\(32\) "2010-12-24 03:04:05\.000000-08:00" 67 | string\(32\) "2010-01-02 05:00:00\.000000\+09:00" 68 | string\(32\) "2010-01-02 00:00:59\.000000-08:00" 69 | string\(32\) "2010-01-02 (00:00:00|03:04:05)\.654321-08:00" 70 | string\(32\) "2012-03-31 12:34:56\.000000-07:00" 71 | string\(32\) "1970-01-01 12:34:56\.000000-08:00" 72 | string\(32\) "1970-01-01 19:00:00\.000000-05:00" 73 | string\(32\) "1970-01-02 00:00:00\.000000\+00:00" 74 | string\(32\) "2012-04-01 00:00:00\.000000\+09:00" 75 | string\(32\) "1970-03-31 00:00:00\.000000\-08:00" 76 | -------------------------------------------------------------------------------- /tests/issue_009.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for issue #9 (Issue with using timecop constructor) 3 | --SKIPIF-- 4 | setTime(0, 0, 0); 20 | } 21 | 22 | public function __toString() { 23 | return $this->format('Y-m-d'); 24 | } 25 | } 26 | timecop_freeze(strtotime("2010-01-01")); 27 | $dt1 = new Date(); 28 | echo $dt1, "\n"; 29 | $dt2 = new Date("2020-12-31"); 30 | echo $dt2, "\n"; 31 | $dt3 = new Date("2030-06-15", new \DateTimeZone("UTC")); 32 | echo $dt3, "\n"; 33 | --EXPECT-- 34 | 2010-01-01 35 | 2020-12-31 36 | 2030-06-15 37 | -------------------------------------------------------------------------------- /tests/issue_010.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for issue #10 (Timecop segfaults when set_error_handler throws an exception) 3 | --SKIPIF-- 4 | format("c")); 13 | --EXPECT-- 14 | string(25) "2044-06-18T00:00:00+00:00" 15 | -------------------------------------------------------------------------------- /tests/issue_014.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for issue #14 (All PHPUnit assertions involving DateTime comparison fail with PHP 7.1) 3 | --SKIPIF-- 4 | voidDate = new \DateTime(); 19 | } 20 | public function getvoidDate() 21 | { 22 | return $this->voidDate; 23 | } 24 | } 25 | function test_invoice_void() 26 | { 27 | $now = new \DateTime(); 28 | timecop_freeze($now); 29 | 30 | $invoice = new CustomerInvoice(); 31 | $invoice->void(); 32 | 33 | var_dump($now == $invoice->getVoidDate()); 34 | } 35 | test_invoice_void(); 36 | --EXPECT-- 37 | bool(true) 38 | -------------------------------------------------------------------------------- /tests/tests-skipcheck.inc.php: -------------------------------------------------------------------------------- 1 | "; 3 | 4 | if(!extension_loaded('timecop')) { 5 | dl('timecop.' . PHP_SHLIB_SUFFIX); 6 | } 7 | $module = 'timecop'; 8 | $functions = get_extension_funcs($module); 9 | echo "Functions available in the test extension:$br\n"; 10 | foreach($functions as $func) { 11 | echo $func."$br\n"; 12 | } 13 | echo "$br\n"; 14 | $function = 'timecop_time'; 15 | if (extension_loaded($module)) { 16 | echo timecop_time()."$br\n"; 17 | $_SERVER['REQUEST_TIME'] = PHP_INT_MAX; 18 | echo timecop_time()."$br\n"; 19 | } else { 20 | echo "Module $module is not compiled into PHP"; 21 | } 22 | 23 | ?> 24 | -------------------------------------------------------------------------------- /timecop_php7.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2012-2017 Yoshio HANAWA 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include "config.h" 27 | #endif 28 | 29 | #include "php.h" 30 | #include "php_ini.h" 31 | #include "ext/standard/info.h" 32 | 33 | #include "php_timecop.h" 34 | 35 | #ifdef ZFS 36 | #include "TSRM.h" 37 | #endif 38 | 39 | ZEND_DECLARE_MODULE_GLOBALS(timecop) 40 | 41 | static void timecop_globals_ctor(zend_timecop_globals *globals) { 42 | /* Initialize your global struct */ 43 | globals->func_override = 1; 44 | globals->sync_request_time = 1; 45 | ZVAL_NULL(&globals->orig_request_time); 46 | globals->timecop_mode = TIMECOP_MODE_REALTIME; 47 | globals->freezed_time.sec = 0; 48 | globals->freezed_time.usec = 0; 49 | globals->travel_origin.sec = 0; 50 | globals->travel_origin.usec = 0; 51 | globals->travel_offset.sec = 0; 52 | globals->travel_offset.usec = 0; 53 | globals->scaling_factor = 1; 54 | globals->ce_DateTimeZone = NULL; 55 | globals->ce_DateTimeInterface = NULL; 56 | globals->ce_DateTime = NULL; 57 | globals->ce_TimecopDateTime = NULL; 58 | globals->ce_DateTimeImmutable = NULL; 59 | globals->ce_TimecopDateTimeImmutable = NULL; 60 | } 61 | 62 | static const struct timecop_override_func_entry timecop_override_func_table[] = { 63 | TIMECOP_OFE("time"), 64 | TIMECOP_OFE("mktime"), 65 | TIMECOP_OFE("gmmktime"), 66 | TIMECOP_OFE("date"), 67 | TIMECOP_OFE("gmdate"), 68 | TIMECOP_OFE("idate"), 69 | TIMECOP_OFE("getdate"), 70 | TIMECOP_OFE("localtime"), 71 | TIMECOP_OFE("strtotime"), 72 | TIMECOP_OFE("strftime"), 73 | TIMECOP_OFE("gmstrftime"), 74 | #ifdef HAVE_GETTIMEOFDAY 75 | TIMECOP_OFE("microtime"), 76 | TIMECOP_OFE("gettimeofday"), 77 | #endif 78 | TIMECOP_OFE("unixtojd"), 79 | TIMECOP_OFE("date_create"), 80 | TIMECOP_OFE("date_create_from_format"), 81 | TIMECOP_OFE("date_create_immutable"), 82 | TIMECOP_OFE("date_create_immutable_from_format"), 83 | {NULL, NULL, NULL} 84 | }; 85 | 86 | static const struct timecop_override_class_entry timecop_override_class_table[] = { 87 | TIMECOP_OCE("datetime", "__construct"), 88 | TIMECOP_OCE("datetime", "createfromformat"), 89 | TIMECOP_OCE("datetimeimmutable", "__construct"), 90 | TIMECOP_OCE("datetimeimmutable", "createfromformat"), 91 | {NULL, NULL, NULL, NULL} 92 | }; 93 | 94 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_freeze, 0, 0, 1) 95 | ZEND_ARG_INFO(0, timestamp) 96 | ZEND_END_ARG_INFO() 97 | 98 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_travel, 0, 0, 1) 99 | ZEND_ARG_INFO(0, timestamp) 100 | ZEND_END_ARG_INFO() 101 | 102 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_scale, 0, 0, 1) 103 | ZEND_ARG_INFO(0, scale) 104 | ZEND_END_ARG_INFO() 105 | 106 | ZEND_BEGIN_ARG_INFO(arginfo_timecop_return, 0) 107 | ZEND_END_ARG_INFO() 108 | 109 | ZEND_BEGIN_ARG_INFO(arginfo_timecop_time, 0) 110 | ZEND_END_ARG_INFO() 111 | 112 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_mktime, 0, 0, 0) 113 | ZEND_ARG_INFO(0, hour) 114 | ZEND_ARG_INFO(0, min) 115 | ZEND_ARG_INFO(0, sec) 116 | ZEND_ARG_INFO(0, mon) 117 | ZEND_ARG_INFO(0, day) 118 | ZEND_ARG_INFO(0, year) 119 | ZEND_END_ARG_INFO() 120 | 121 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_gmmktime, 0, 0, 0) 122 | ZEND_ARG_INFO(0, hour) 123 | ZEND_ARG_INFO(0, min) 124 | ZEND_ARG_INFO(0, sec) 125 | ZEND_ARG_INFO(0, mon) 126 | ZEND_ARG_INFO(0, day) 127 | ZEND_ARG_INFO(0, year) 128 | ZEND_END_ARG_INFO() 129 | 130 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_date, 0, 0, 1) 131 | ZEND_ARG_INFO(0, format) 132 | ZEND_ARG_INFO(0, timestamp) 133 | ZEND_END_ARG_INFO() 134 | 135 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_gmdate, 0, 0, 1) 136 | ZEND_ARG_INFO(0, format) 137 | ZEND_ARG_INFO(0, timestamp) 138 | ZEND_END_ARG_INFO() 139 | 140 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_idate, 0, 0, 1) 141 | ZEND_ARG_INFO(0, format) 142 | ZEND_ARG_INFO(0, timestamp) 143 | ZEND_END_ARG_INFO() 144 | 145 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_getdate, 0, 0, 0) 146 | ZEND_ARG_INFO(0, timestamp) 147 | ZEND_END_ARG_INFO() 148 | 149 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_localtime, 0, 0, 0) 150 | ZEND_ARG_INFO(0, timestamp) 151 | ZEND_ARG_INFO(0, associative_array) 152 | ZEND_END_ARG_INFO() 153 | 154 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_strtotime, 0, 0, 1) 155 | ZEND_ARG_INFO(0, time) 156 | ZEND_ARG_INFO(0, now) 157 | ZEND_END_ARG_INFO() 158 | 159 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_strftime, 0, 0, 1) 160 | ZEND_ARG_INFO(0, format) 161 | ZEND_ARG_INFO(0, timestamp) 162 | ZEND_END_ARG_INFO() 163 | 164 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_gmstrftime, 0, 0, 1) 165 | ZEND_ARG_INFO(0, format) 166 | ZEND_ARG_INFO(0, timestamp) 167 | ZEND_END_ARG_INFO() 168 | 169 | #ifdef HAVE_GETTIMEOFDAY 170 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_microtime, 0, 0, 0) 171 | ZEND_ARG_INFO(0, get_as_float) 172 | ZEND_END_ARG_INFO() 173 | 174 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_gettimeofday, 0, 0, 0) 175 | ZEND_ARG_INFO(0, get_as_float) 176 | ZEND_END_ARG_INFO() 177 | #endif 178 | 179 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_unixtojd, 0, 0, 0) 180 | ZEND_ARG_INFO(0, timestamp) 181 | ZEND_END_ARG_INFO() 182 | 183 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_date_create, 0, 0, 0) 184 | ZEND_ARG_INFO(0, time) 185 | ZEND_ARG_INFO(0, object) 186 | ZEND_END_ARG_INFO() 187 | 188 | ZEND_BEGIN_ARG_INFO_EX(arginfo_timecop_date_create_from_format, 0, 0, 2) 189 | ZEND_ARG_INFO(0, format) 190 | ZEND_ARG_INFO(0, time) 191 | #if PHP_VERSION_ID >= 70200 192 | ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 1) 193 | #else 194 | ZEND_ARG_INFO(0, object) 195 | #endif 196 | ZEND_END_ARG_INFO() 197 | 198 | /* {{{ timecop_functions[] */ 199 | const zend_function_entry timecop_functions[] = { 200 | PHP_FE(timecop_freeze, arginfo_timecop_freeze) 201 | PHP_FE(timecop_travel, arginfo_timecop_travel) 202 | PHP_FE(timecop_scale, arginfo_timecop_scale) 203 | PHP_FE(timecop_return, arginfo_timecop_return) 204 | PHP_FE(timecop_time, arginfo_timecop_time) 205 | PHP_FE(timecop_mktime, arginfo_timecop_mktime) 206 | PHP_FE(timecop_gmmktime, arginfo_timecop_gmmktime) 207 | PHP_FE(timecop_date, arginfo_timecop_date) 208 | PHP_FE(timecop_gmdate, arginfo_timecop_gmdate) 209 | PHP_FE(timecop_idate, arginfo_timecop_idate) 210 | PHP_FE(timecop_getdate, arginfo_timecop_getdate) 211 | PHP_FE(timecop_localtime, arginfo_timecop_localtime) 212 | PHP_FE(timecop_strtotime, arginfo_timecop_strtotime) 213 | PHP_FE(timecop_strftime, arginfo_timecop_strftime) 214 | PHP_FE(timecop_gmstrftime, arginfo_timecop_gmstrftime) 215 | #ifdef HAVE_GETTIMEOFDAY 216 | PHP_FE(timecop_microtime, arginfo_timecop_microtime) 217 | PHP_FE(timecop_gettimeofday, arginfo_timecop_gettimeofday) 218 | #endif 219 | PHP_FE(timecop_unixtojd, arginfo_timecop_unixtojd) 220 | PHP_FE(timecop_date_create, arginfo_timecop_date_create) 221 | PHP_FE(timecop_date_create_from_format, arginfo_timecop_date_create_from_format) 222 | PHP_FE(timecop_date_create_immutable, arginfo_timecop_date_create) 223 | PHP_FE(timecop_date_create_immutable_from_format, arginfo_timecop_date_create_from_format) 224 | {NULL, NULL, NULL} 225 | }; 226 | /* }}} */ 227 | 228 | /* declare method parameters, */ 229 | 230 | /* each method can have its own parameters and visibility */ 231 | static zend_function_entry timecop_funcs_timecop[] = { 232 | PHP_ME_MAPPING(freeze, timecop_freeze, arginfo_timecop_travel, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 233 | PHP_ME_MAPPING(travel, timecop_travel, arginfo_timecop_travel, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 234 | PHP_ME_MAPPING(scale, timecop_scale, arginfo_timecop_scale, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 235 | PHP_ME_MAPPING(return, timecop_return, arginfo_timecop_return, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 236 | {NULL, NULL, NULL} 237 | }; 238 | 239 | static zend_function_entry timecop_funcs_date[] = { 240 | PHP_ME(TimecopDateTime, __construct, arginfo_timecop_date_create, 241 | ZEND_ACC_CTOR | ZEND_ACC_PUBLIC) 242 | PHP_ME_MAPPING(createFromFormat, timecop_date_create_from_format, arginfo_timecop_date_create_from_format, 243 | ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 244 | {NULL, NULL, NULL} 245 | }; 246 | 247 | static zend_function_entry timecop_funcs_orig_date[] = { 248 | PHP_ME(TimecopOrigDateTime, __construct, arginfo_timecop_date_create, 249 | ZEND_ACC_CTOR | ZEND_ACC_PUBLIC) 250 | {NULL, NULL, NULL} 251 | }; 252 | 253 | static zend_function_entry timecop_funcs_immutable[] = { 254 | PHP_ME(TimecopDateTimeImmutable, __construct, arginfo_timecop_date_create, 255 | ZEND_ACC_CTOR | ZEND_ACC_PUBLIC) 256 | PHP_ME_MAPPING(createFromFormat, timecop_date_create_immutable_from_format, arginfo_timecop_date_create_from_format, 257 | ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 258 | {NULL, NULL, NULL} 259 | }; 260 | 261 | static zend_function_entry timecop_funcs_orig_immutable[] = { 262 | PHP_ME(TimecopOrigDateTimeImmutable, __construct, arginfo_timecop_date_create, 263 | ZEND_ACC_CTOR | ZEND_ACC_PUBLIC) 264 | {NULL, NULL, NULL} 265 | }; 266 | 267 | #define MKTIME_NUM_ARGS 6 268 | 269 | #define TIMECOP_CALL_FUNCTION(func_name, index_to_fill_timestamp) \ 270 | _timecop_call_function(INTERNAL_FUNCTION_PARAM_PASSTHRU, ORIG_FUNC_NAME(func_name), index_to_fill_timestamp); 271 | 272 | #define TIMECOP_CALL_MKTIME(mktime_func_name, date_func_name) \ 273 | _timecop_call_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, ORIG_FUNC_NAME(mktime_func_name), ORIG_FUNC_NAME(date_func_name)); 274 | 275 | static void timecop_globals_ctor(zend_timecop_globals *globals); 276 | 277 | static int register_timecop_classes(); 278 | static int timecop_func_override(); 279 | static int timecop_class_override(); 280 | static int timecop_func_override_clear(); 281 | static int timecop_class_override_clear(); 282 | 283 | static int update_request_time(zend_long unixtime); 284 | static int restore_request_time(); 285 | 286 | static int fill_mktime_params(zval *fill_params, const char *date_function_name, int from); 287 | static int get_formatted_mock_time(zval *time, zval *timezone_obj, zval *retval_time, zval *retval_timezone); 288 | static long get_mock_fraction(zval *time, zval *timezone_obj); 289 | 290 | static void _timecop_call_function(INTERNAL_FUNCTION_PARAMETERS, const char *function_name, int index_to_fill_timestamp); 291 | static void _timecop_call_mktime(INTERNAL_FUNCTION_PARAMETERS, const char *mktime_function_name, const char *date_function_name); 292 | 293 | static int get_mock_timeval(tc_timeval *fixed, const tc_timeval *now); 294 | static inline zend_long mock_timestamp(); 295 | 296 | static int get_timeval_from_datetime(tc_timeval *tp, zval *dt); 297 | static int get_current_time(tc_timeval *now); 298 | 299 | static void _timecop_orig_datetime_constructor(INTERNAL_FUNCTION_PARAMETERS, int immutable); 300 | static inline void _timecop_date_create(INTERNAL_FUNCTION_PARAMETERS, int immutable); 301 | static inline void _timecop_datetime_constructor(INTERNAL_FUNCTION_PARAMETERS, int immutable); 302 | static void _timecop_datetime_constructor_ex(INTERNAL_FUNCTION_PARAMETERS, zval *obj, int immutable); 303 | 304 | static inline zval* _call_php_method_with_0_params(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr); 305 | static inline zval* _call_php_method_with_1_params(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr, zval *arg1); 306 | static inline zval* _call_php_method_with_2_params(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr, zval *arg1, zval *arg2); 307 | static inline zval* _call_php_method(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr, int param_count, zval* arg1, zval* arg2); 308 | static inline void _call_php_function_with_0_params(const char *function_name, zval *retval_ptr); 309 | static inline void _call_php_function_with_1_params(const char *function_name, zval *retval_ptr, zval *arg1); 310 | static inline void _call_php_function_with_2_params(const char *function_name, zval *retval_ptr, zval *arg1, zval *arg2); 311 | static void _call_php_function_with_3_params(const char *function_name, zval *retval_ptr, zval *arg1, zval *arg2, zval *arg3); 312 | static inline void _call_php_function_with_params(const char *function_name, zval *retval_ptr, uint32_t param_count, zval params[]); 313 | 314 | /* {{{ timecop_module_entry 315 | */ 316 | zend_module_entry timecop_module_entry = { 317 | #if ZEND_MODULE_API_NO >= 20010901 318 | STANDARD_MODULE_HEADER, 319 | #endif 320 | "timecop", 321 | timecop_functions, 322 | PHP_MINIT(timecop), 323 | PHP_MSHUTDOWN(timecop), 324 | PHP_RINIT(timecop), 325 | PHP_RSHUTDOWN(timecop), 326 | PHP_MINFO(timecop), 327 | #if ZEND_MODULE_API_NO >= 20010901 328 | PHP_TIMECOP_VERSION, 329 | #endif 330 | STANDARD_MODULE_PROPERTIES 331 | }; 332 | /* }}} */ 333 | 334 | #ifdef COMPILE_DL_TIMECOP 335 | # ifdef ZTS 336 | ZEND_TSRMLS_CACHE_DEFINE(); 337 | # endif 338 | ZEND_GET_MODULE(timecop) 339 | #endif 340 | 341 | /* {{{ PHP_INI 342 | */ 343 | PHP_INI_BEGIN() 344 | STD_PHP_INI_ENTRY("timecop.func_override", "1", 345 | PHP_INI_SYSTEM, OnUpdateLong, func_override, zend_timecop_globals, timecop_globals) 346 | STD_PHP_INI_ENTRY("timecop.sync_request_time", "1", 347 | PHP_INI_SYSTEM, OnUpdateLong, sync_request_time, zend_timecop_globals, timecop_globals) 348 | PHP_INI_END() 349 | /* }}} */ 350 | 351 | /* {{{ PHP_MINIT_FUNCTION 352 | */ 353 | PHP_MINIT_FUNCTION(timecop) 354 | { 355 | ZEND_INIT_MODULE_GLOBALS(timecop, timecop_globals_ctor, NULL); 356 | REGISTER_INI_ENTRIES(); 357 | register_timecop_classes(); 358 | return SUCCESS; 359 | } 360 | /* }}} */ 361 | 362 | /* {{{ PHP_MSHUTDOWN_FUNCTION 363 | */ 364 | PHP_MSHUTDOWN_FUNCTION(timecop) 365 | { 366 | UNREGISTER_INI_ENTRIES(); 367 | return SUCCESS; 368 | } 369 | /* }}} */ 370 | 371 | /* {{{ PHP_RINIT_FUNCTION(timecop) */ 372 | PHP_RINIT_FUNCTION(timecop) 373 | { 374 | #if defined(COMPILE_DL_TIMECOP) && defined(ZTS) 375 | ZEND_TSRMLS_CACHE_UPDATE(); 376 | #endif 377 | 378 | if (TIMECOP_G(func_override)) { 379 | if (SUCCESS != timecop_func_override() || 380 | SUCCESS != timecop_class_override()) { 381 | return FAILURE; 382 | } 383 | } 384 | 385 | return SUCCESS; 386 | } 387 | /* }}} */ 388 | 389 | /* {{{ PHP_RSHUTDOWN_FUNCTION(timecop) */ 390 | PHP_RSHUTDOWN_FUNCTION(timecop) 391 | { 392 | if (TIMECOP_G(func_override)) { 393 | timecop_func_override_clear(); 394 | timecop_class_override_clear(); 395 | } 396 | 397 | if (Z_TYPE(TIMECOP_G(orig_request_time)) == IS_NULL) { 398 | restore_request_time(); 399 | } 400 | 401 | TIMECOP_G(timecop_mode) = TIMECOP_MODE_REALTIME; 402 | TIMECOP_G(scaling_factor) = 1; 403 | 404 | return SUCCESS; 405 | } 406 | /* }}} */ 407 | 408 | 409 | /* {{{ PHP_MINFO_FUNCTION 410 | */ 411 | PHP_MINFO_FUNCTION(timecop) 412 | { 413 | php_info_print_table_start(); 414 | php_info_print_table_header(2, "timecop", "enabled"); 415 | php_info_print_table_row(2, "Version", PHP_TIMECOP_VERSION); 416 | php_info_print_table_end(); 417 | 418 | DISPLAY_INI_ENTRIES(); 419 | } 420 | /* }}} */ 421 | 422 | static int register_timecop_classes() 423 | { 424 | zend_class_entry ce; 425 | zend_class_entry *tmp, *date_ce, *timezone_ce, *immutable_ce, *interface_ce; 426 | 427 | date_ce = zend_hash_str_find_ptr(CG(class_table), "datetime", sizeof("datetime")-1); 428 | if (date_ce == NULL) { 429 | /* DateTime must be initialized before */ 430 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 431 | "timecop couldn't find class %s.", "DateTime"); 432 | return SUCCESS; 433 | } 434 | 435 | timezone_ce = zend_hash_str_find_ptr(CG(class_table), "datetimezone", sizeof("datetimezone")-1); 436 | if (timezone_ce == NULL) { 437 | /* DateTime must be initialized before */ 438 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 439 | "timecop couldn't find class %s.", "DateTimeZone"); 440 | return SUCCESS; 441 | } 442 | 443 | immutable_ce = zend_hash_str_find_ptr(CG(class_table), "datetimeimmutable", sizeof("datetimeimmutable")-1); 444 | if (immutable_ce == NULL) { 445 | /* DateTimeImmutable must be initialized before */ 446 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 447 | "timecop couldn't find class %s.", "DateTimeImmutable"); 448 | return SUCCESS; 449 | } 450 | 451 | interface_ce = zend_hash_str_find_ptr(CG(class_table), "datetimeinterface", sizeof("datetimeinterface")-1); 452 | if (interface_ce == NULL) { 453 | /* DateTimeInterface must be initialized before */ 454 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 455 | "timecop couldn't find interface %s.", "DateTimeInterface"); 456 | return SUCCESS; 457 | } 458 | 459 | INIT_CLASS_ENTRY(ce, "Timecop", timecop_funcs_timecop); 460 | zend_register_internal_class(&ce); 461 | 462 | TIMECOP_G(ce_DateTimeZone) = timezone_ce; 463 | TIMECOP_G(ce_DateTimeInterface) = interface_ce; 464 | 465 | /* replace DateTime */ 466 | INIT_CLASS_ENTRY(ce, "TimecopDateTime", timecop_funcs_date); 467 | tmp = zend_register_internal_class_ex(&ce, date_ce); 468 | tmp->create_object = date_ce->create_object; 469 | 470 | TIMECOP_G(ce_DateTime) = date_ce; 471 | TIMECOP_G(ce_TimecopDateTime) = tmp; 472 | 473 | INIT_CLASS_ENTRY(ce, "TimecopOrigDateTime", timecop_funcs_orig_date); 474 | tmp = zend_register_internal_class_ex(&ce, date_ce); 475 | tmp->create_object = date_ce->create_object; 476 | 477 | /* replace DateTimeImmutable */ 478 | INIT_CLASS_ENTRY(ce, "TimecopDateTimeImmutable", timecop_funcs_immutable); 479 | tmp = zend_register_internal_class_ex(&ce, immutable_ce); 480 | tmp->create_object = immutable_ce->create_object; 481 | 482 | TIMECOP_G(ce_DateTimeImmutable) = immutable_ce; 483 | TIMECOP_G(ce_TimecopDateTimeImmutable) = tmp; 484 | 485 | INIT_CLASS_ENTRY(ce, "TimecopOrigDateTimeImmutable", timecop_funcs_orig_immutable); 486 | tmp = zend_register_internal_class_ex(&ce, immutable_ce); 487 | tmp->create_object = immutable_ce->create_object; 488 | 489 | return SUCCESS; 490 | } 491 | 492 | static int timecop_func_override() 493 | { 494 | const struct timecop_override_func_entry *p; 495 | zend_function *zf_orig, *zf_ovrd, *zf_save; 496 | 497 | p = &(timecop_override_func_table[0]); 498 | while (p->orig_func != NULL) { 499 | zf_orig = zend_hash_str_find_ptr(EG(function_table), p->orig_func, strlen(p->orig_func)); 500 | if (zf_orig == NULL) { 501 | /* Do nothing. Because some functions are introduced by optional extensions. */ 502 | p++; 503 | continue; 504 | } 505 | 506 | zf_ovrd = zend_hash_str_find_ptr(EG(function_table), p->ovrd_func, strlen(p->ovrd_func)); 507 | if (zf_ovrd == NULL) { 508 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 509 | "timecop couldn't find function %s.", p->ovrd_func); 510 | p++; 511 | continue; 512 | } 513 | 514 | zf_save = zend_hash_str_find_ptr(EG(function_table), p->save_func, strlen(p->save_func)); 515 | if (zf_save != NULL) { 516 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 517 | "timecop couldn't create function %s because already exists.", 518 | p->save_func); 519 | p++; 520 | continue; 521 | } 522 | 523 | TIMECOP_ASSERT(zf_orig->type == ZEND_INTERNAL_FUNCTION); 524 | TIMECOP_ASSERT(zf_ovrd->type == ZEND_INTERNAL_FUNCTION); 525 | 526 | zend_hash_str_add_mem(EG(function_table), p->save_func, strlen(p->save_func), 527 | zf_orig, sizeof(zend_internal_function)); 528 | function_add_ref(zf_orig); 529 | 530 | GUARD_FUNCTION_ARG_INFO_BEGIN(zf_orig); 531 | zend_hash_str_update_mem(EG(function_table), p->orig_func, strlen(p->orig_func), 532 | zf_ovrd, sizeof(zend_internal_function)); 533 | GUARD_FUNCTION_ARG_INFO_END(); 534 | function_add_ref(zf_ovrd); 535 | 536 | p++; 537 | } 538 | return SUCCESS; 539 | } 540 | 541 | static int timecop_class_override() 542 | { 543 | const struct timecop_override_class_entry *p; 544 | zend_class_entry *ce_orig, *ce_ovrd; 545 | zend_function *zf_orig, *zf_ovrd, *zf_save, *zf_new; 546 | 547 | p = &(timecop_override_class_table[0]); 548 | while (p->orig_class != NULL) { 549 | ce_orig = zend_hash_str_find_ptr(EG(class_table), p->orig_class, strlen(p->orig_class)); 550 | if (ce_orig == NULL) { 551 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 552 | "timecop couldn't find class %s.", p->orig_class); 553 | p++; 554 | continue; 555 | } 556 | 557 | ce_ovrd = zend_hash_str_find_ptr(EG(class_table), p->ovrd_class, strlen(p->ovrd_class)); 558 | if (ce_ovrd == NULL) { 559 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 560 | "timecop couldn't find class %s.", p->ovrd_class); 561 | p++; 562 | continue; 563 | } 564 | 565 | zf_orig = zend_hash_str_find_ptr(&ce_orig->function_table, 566 | p->orig_method, strlen(p->orig_method)); 567 | if (zf_orig == NULL) { 568 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 569 | "timecop couldn't find method %s::%s.", 570 | p->orig_class, p->orig_method); 571 | p++; 572 | continue; 573 | } 574 | 575 | zf_ovrd = zend_hash_str_find_ptr(&ce_ovrd->function_table, 576 | p->orig_method, strlen(p->orig_method)); 577 | if (zf_ovrd == NULL) { 578 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 579 | "timecop couldn't find method %s::%s.", 580 | p->ovrd_class, p->orig_method); 581 | p++; 582 | continue; 583 | } 584 | 585 | zf_save = zend_hash_str_find_ptr(&ce_orig->function_table, 586 | p->save_method, strlen(p->save_method)); 587 | if (zf_save != NULL) { 588 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 589 | "timecop couldn't create method %s::%s because already exists.", 590 | p->orig_class, p->save_method); 591 | p++; 592 | continue; 593 | } 594 | 595 | TIMECOP_ASSERT(zf_orig->type == ZEND_INTERNAL_FUNCTION); 596 | TIMECOP_ASSERT(ce_orig->type & ZEND_INTERNAL_CLASS); 597 | TIMECOP_ASSERT(zf_ovrd->type == ZEND_INTERNAL_FUNCTION); 598 | TIMECOP_ASSERT(ce_ovrd->type & ZEND_INTERNAL_CLASS); 599 | 600 | zend_hash_str_add_mem(&ce_orig->function_table, 601 | p->save_method, strlen(p->save_method), 602 | zf_orig, sizeof(zend_internal_function)); 603 | function_add_ref(zf_orig); 604 | 605 | zf_new = zend_hash_str_update_mem(&ce_orig->function_table, 606 | p->orig_method, strlen(p->orig_method), 607 | zf_ovrd, sizeof(zend_internal_function)); 608 | function_add_ref(zf_ovrd); 609 | 610 | TIMECOP_ASSERT(zf_new != NULL); 611 | TIMECOP_ASSERT(zf_new != zf_orig); 612 | 613 | if (strcmp(p->orig_method, "__construct") == 0) { 614 | ce_orig->constructor = zf_new; 615 | } 616 | p++; 617 | } 618 | return SUCCESS; 619 | } 620 | 621 | /* clear function overriding. */ 622 | static int timecop_func_override_clear() 623 | { 624 | const struct timecop_override_func_entry *p; 625 | zend_function *zf_orig, *zf_ovld; 626 | 627 | p = &(timecop_override_func_table[0]); 628 | while (p->orig_func != NULL) { 629 | zf_orig = zend_hash_str_find_ptr(EG(function_table), 630 | p->save_func, strlen(p->save_func)); 631 | zf_ovld = zend_hash_str_find_ptr(EG(function_table), 632 | p->orig_func, strlen(p->orig_func)); 633 | if (zf_orig == NULL || zf_ovld == NULL) { 634 | p++; 635 | continue; 636 | } 637 | 638 | GUARD_FUNCTION_ARG_INFO_BEGIN(zf_ovld); 639 | zend_hash_str_update_mem(EG(function_table), p->orig_func, strlen(p->orig_func), 640 | zf_orig, sizeof(zend_internal_function)); 641 | GUARD_FUNCTION_ARG_INFO_END(); 642 | function_add_ref(zf_orig); 643 | 644 | GUARD_FUNCTION_ARG_INFO_BEGIN(zf_orig); 645 | zend_hash_str_del(EG(function_table), p->save_func, strlen(p->save_func)); 646 | GUARD_FUNCTION_ARG_INFO_END(); 647 | 648 | p++; 649 | } 650 | return SUCCESS; 651 | } 652 | 653 | static int timecop_class_override_clear() 654 | { 655 | const struct timecop_override_class_entry *p; 656 | zend_class_entry *ce_orig; 657 | zend_function *zf_orig; 658 | 659 | p = &(timecop_override_class_table[0]); 660 | while (p->orig_class != NULL) { 661 | ce_orig = zend_hash_str_find_ptr(EG(class_table), 662 | p->orig_class, strlen(p->orig_class)); 663 | if (ce_orig == NULL) { 664 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 665 | "timecop couldn't find class %s.", p->orig_class); 666 | p++; 667 | continue; 668 | } 669 | 670 | zf_orig = zend_hash_str_find_ptr(&ce_orig->function_table, 671 | p->save_method, strlen(p->save_method)); 672 | if (zf_orig == NULL) { 673 | php_error_docref("https://github.com/hnw/php-timecop", E_WARNING, 674 | "timecop couldn't find method %s::%s.", 675 | p->orig_class, p->save_method); 676 | p++; 677 | continue; 678 | } 679 | 680 | zend_hash_str_update_mem(&ce_orig->function_table, p->orig_method, strlen(p->orig_method), 681 | zf_orig, sizeof(zend_internal_function)); 682 | function_add_ref(zf_orig); 683 | 684 | zend_hash_str_del(&ce_orig->function_table, p->save_method, strlen(p->save_method)); 685 | 686 | if (strcmp(p->orig_method, "__construct") == 0) { 687 | ce_orig->constructor = zf_orig; 688 | } 689 | p++; 690 | } 691 | return SUCCESS; 692 | } 693 | 694 | static int update_request_time(zend_long unixtime) 695 | { 696 | zval *server_vars, *request_time, tmp; 697 | 698 | server_vars = zend_hash_str_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER")-1); 699 | if (server_vars != NULL && Z_TYPE_P(server_vars) == IS_ARRAY) { 700 | request_time = zend_hash_str_find(Z_ARRVAL_P(server_vars), "REQUEST_TIME", sizeof("REQUEST_TIME")-1); 701 | if (request_time != NULL) { 702 | if (Z_TYPE(TIMECOP_G(orig_request_time)) == IS_NULL) { 703 | ZVAL_COPY_VALUE(&TIMECOP_G(orig_request_time), request_time); 704 | } 705 | } 706 | ZVAL_LONG(&tmp, unixtime); 707 | zend_hash_str_update(Z_ARRVAL_P(server_vars), 708 | "REQUEST_TIME", sizeof("REQUEST_TIME")-1, 709 | &tmp); 710 | } 711 | 712 | return SUCCESS; 713 | } 714 | 715 | static int restore_request_time() 716 | { 717 | zval *server_vars; 718 | 719 | server_vars = zend_hash_str_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER")-1); 720 | if (Z_TYPE(TIMECOP_G(orig_request_time)) != IS_NULL && 721 | server_vars != NULL && Z_TYPE_P(server_vars) == IS_ARRAY) { 722 | zend_hash_str_update(Z_ARRVAL_P(server_vars), 723 | "REQUEST_TIME", sizeof("REQUEST_TIME")-1, 724 | &TIMECOP_G(orig_request_time)); 725 | ZVAL_NULL(&TIMECOP_G(orig_request_time)); 726 | } 727 | 728 | return SUCCESS; 729 | } 730 | 731 | static int fill_mktime_params(zval *fill_params, const char *date_function_name, int from) 732 | { 733 | char *formats[MKTIME_NUM_ARGS] = {"H", "i", "s", "n", "j", "Y"}; 734 | zval format, timestamp; 735 | int i; 736 | 737 | ZVAL_LONG(×tamp, mock_timestamp()); 738 | 739 | for (i = from; i < MKTIME_NUM_ARGS; i++) { 740 | ZVAL_STRING(&format, formats[i]); 741 | call_php_function_with_2_params(date_function_name, &fill_params[i], &format, ×tamp); 742 | zval_ptr_dtor(&format); 743 | } 744 | 745 | return MKTIME_NUM_ARGS; 746 | } 747 | 748 | /* 749 | * get_formatted_mock_time() : return formatted mock time like "2000-12-30 01:02:03.456000" 750 | * 751 | * pseudo code: 752 | * 753 | * function get_formatted_mock_time($time, $timezone_obj) { 754 | * if ($time === null || $time === false || $time === "") { 755 | * $time = "now"; 756 | * } 757 | * $now = get_mock_timeval(); 758 | * if ($timezone_obj) { 759 | * // save default timezone 760 | * $zonename = $timezone_obj->getName() 761 | * $orig_zonename = date_default_timezone_get(); 762 | * date_default_timezone_set($zonename); 763 | * } 764 | * $fixed_sec = strtotime($time, $now->sec); 765 | * if ($timezone_obj && $orig_zonename) { 766 | * // restore default timezone 767 | * date_default_timezone_set($orig_zonename); 768 | * } 769 | * if ($fixed_sec === FALSE) { 770 | * return false; 771 | * } 772 | * $fixed_usec = get_mock_fraction($time, $timezone_obj); 773 | * if ($fixed_usec === -1) { 774 | * $fixed_usec = $now->usec; 775 | * } 776 | * $dt = date_create($time, $timezone_obj); 777 | * $dt->setTimestamp($fixed_sec); 778 | * $format = sprintf("Y-m-d H:i:s.%06d", $fixed_usec); 779 | * $formatted_time = $dt->format($format); 780 | * return $formatted_time; 781 | * } 782 | */ 783 | static int get_formatted_mock_time(zval *time, zval *timezone_obj, zval *retval_time, zval *retval_timezone) 784 | { 785 | zval fixed_sec, orig_zonename; 786 | zval now_timestamp, str_now; 787 | tc_timeval now; 788 | zend_long fixed_usec; 789 | 790 | if (TIMECOP_G(timecop_mode) == TIMECOP_MODE_REALTIME) { 791 | ZVAL_FALSE(retval_time); 792 | ZVAL_NULL(retval_timezone); 793 | return -1; 794 | } 795 | 796 | if (time == NULL || Z_TYPE_P(time) == IS_NULL || 797 | Z_TYPE_P(time) == IS_FALSE || 798 | (Z_TYPE_P(time) == IS_STRING && Z_STRLEN_P(time) == 0)) { 799 | ZVAL_STRING(&str_now, "now"); 800 | time = &str_now; 801 | } 802 | 803 | get_mock_timeval(&now, NULL); 804 | 805 | if (timezone_obj && Z_TYPE_P(timezone_obj) == IS_OBJECT) { 806 | zval zonename; 807 | call_php_method_with_0_params(timezone_obj, Z_OBJCE_P(timezone_obj), "getname", &zonename); 808 | call_php_function_with_0_params("date_default_timezone_get", &orig_zonename); 809 | call_php_function_with_1_params("date_default_timezone_set", NULL, &zonename); 810 | zval_ptr_dtor(&zonename); 811 | } 812 | 813 | ZVAL_LONG(&now_timestamp, now.sec); 814 | call_php_function_with_2_params(ORIG_FUNC_NAME("strtotime"), &fixed_sec, time, &now_timestamp); 815 | 816 | if (timezone_obj && Z_TYPE_P(timezone_obj) == IS_OBJECT) { 817 | call_php_function_with_1_params("date_default_timezone_set", NULL, &orig_zonename); 818 | zval_ptr_dtor(&orig_zonename); 819 | } 820 | 821 | if (Z_TYPE(fixed_sec) == IS_FALSE) { 822 | ZVAL_FALSE(retval_time); 823 | ZVAL_NULL(retval_timezone); 824 | return -1; 825 | } 826 | 827 | fixed_usec = get_mock_fraction(time, timezone_obj); 828 | if (fixed_usec == -1) { 829 | fixed_usec = now.usec; 830 | } 831 | 832 | { 833 | zval dt; 834 | zval format_str; 835 | 836 | char buf[64]; 837 | 838 | call_php_function_with_2_params(ORIG_FUNC_NAME("date_create"), &dt, time, timezone_obj); 839 | if (Z_TYPE(dt) == IS_FALSE) { 840 | ZVAL_FALSE(retval_time); 841 | ZVAL_NULL(retval_timezone); 842 | return -1; 843 | } 844 | sprintf(buf, "Y-m-d H:i:s.%06ld", fixed_usec); 845 | ZVAL_STRING(&format_str, buf); 846 | call_php_method_with_1_params(&dt, TIMECOP_G(ce_DateTime), "settimestamp", NULL, &fixed_sec); 847 | call_php_method_with_0_params(&dt, TIMECOP_G(ce_DateTime), "gettimezone", retval_timezone); 848 | call_php_method_with_1_params(&dt, TIMECOP_G(ce_DateTime), "format", retval_time, &format_str); 849 | zval_ptr_dtor(&fixed_sec); 850 | zval_ptr_dtor(&format_str); 851 | zval_ptr_dtor(&dt); 852 | } 853 | 854 | if (time == &str_now) { 855 | zval_ptr_dtor(&str_now); 856 | } 857 | return 0; 858 | } 859 | 860 | /* 861 | * get_mock_fraction() 862 | * 863 | * pseudo code: 864 | * 865 | * function get_mock_fraction($time, $timezone_obj) { 866 | * $dt1 = date_create($time, $timezone_obj); 867 | * usleep(1); 868 | * $dt2 = date_create($time, $timezone_obj); 869 | * $usec1 = $dt1->format("u"); 870 | * $usec2 = $dt2->format("u"); 871 | * if ($usec1 === $usec2) { 872 | * $fixed_usec = $usec1; 873 | * } else { 874 | * $fixed_usec = -1; 875 | * } 876 | * return $fixed_usec; 877 | * } 878 | */ 879 | static long get_mock_fraction(zval *time, zval *timezone_obj TSRMLS_DC) 880 | { 881 | zval dt1, dt2, usec1, usec2; 882 | zend_long fixed_usec; 883 | zval u_str, sleep_usec; 884 | 885 | call_php_function_with_2_params(ORIG_FUNC_NAME("date_create"), &dt1, time, timezone_obj); 886 | if (Z_TYPE(dt1) == IS_FALSE) { 887 | return -1; 888 | } 889 | 890 | ZVAL_LONG(&sleep_usec, 1); 891 | call_php_function_with_1_params("usleep", NULL, &sleep_usec); 892 | 893 | call_php_function_with_2_params(ORIG_FUNC_NAME("date_create"), &dt2, time, timezone_obj); 894 | if (Z_TYPE(dt2) == IS_FALSE) { 895 | zval_ptr_dtor(&dt1); 896 | return -1; 897 | } 898 | ZVAL_STRING(&u_str, "u"); 899 | call_php_method_with_1_params(&dt1, TIMECOP_G(ce_DateTime), "format", &usec1, &u_str); 900 | call_php_method_with_1_params(&dt2, TIMECOP_G(ce_DateTime), "format", &usec2, &u_str); 901 | convert_to_long(&usec1); 902 | convert_to_long(&usec2); 903 | 904 | if (Z_LVAL(usec1) == Z_LVAL(usec2)) { 905 | fixed_usec = Z_LVAL(usec1); 906 | } else { 907 | fixed_usec = -1; 908 | } 909 | zval_ptr_dtor(&dt1); 910 | zval_ptr_dtor(&dt2); 911 | zval_ptr_dtor(&u_str); 912 | 913 | return fixed_usec; 914 | } 915 | 916 | 917 | static void _timecop_call_function(INTERNAL_FUNCTION_PARAMETERS, const char *function_name, int index_to_fill_timestamp) 918 | { 919 | zval *params; 920 | uint32_t param_count; 921 | 922 | param_count = MAX(ZEND_NUM_ARGS(), index_to_fill_timestamp+1); 923 | params = (zval *)safe_emalloc(param_count, sizeof(zval), 0); 924 | 925 | if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), params) == FAILURE) { 926 | efree(params); 927 | return; 928 | } 929 | 930 | param_count = ZEND_NUM_ARGS(); 931 | if (param_count == index_to_fill_timestamp) { 932 | ZVAL_LONG(¶ms[param_count], mock_timestamp()); 933 | param_count++; 934 | } 935 | 936 | call_php_function_with_params(function_name, return_value, param_count, params); 937 | 938 | efree(params); 939 | } 940 | 941 | /* {{{ _timecop_call_mktime - timecop_(gm)mktime helper */ 942 | static void _timecop_call_mktime(INTERNAL_FUNCTION_PARAMETERS, const char *mktime_function_name, const char *date_function_name) 943 | { 944 | zval *params; 945 | uint32_t param_count; 946 | 947 | int i; 948 | 949 | param_count = MAX(ZEND_NUM_ARGS(), MKTIME_NUM_ARGS); 950 | params = (zval *)safe_emalloc(param_count, sizeof(zval), 0); 951 | 952 | if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), params) == FAILURE) { 953 | efree(params); 954 | zend_throw_error(NULL, "Cannot get arguments for calling"); 955 | return; 956 | } 957 | 958 | param_count = ZEND_NUM_ARGS(); 959 | if (param_count < MKTIME_NUM_ARGS) { 960 | fill_mktime_params(params, date_function_name, param_count); 961 | param_count = MKTIME_NUM_ARGS; 962 | } 963 | 964 | if (ZEND_NUM_ARGS() == 0) { 965 | php_error_docref(NULL, E_DEPRECATED, "You should be using the time() function instead"); 966 | } 967 | 968 | call_php_function_with_params(mktime_function_name, return_value, param_count, params); 969 | 970 | for (i = ZEND_NUM_ARGS(); i < MKTIME_NUM_ARGS; i++) { 971 | zval_ptr_dtor(¶ms[i]); 972 | } 973 | efree(params); 974 | } 975 | /* }}} */ 976 | 977 | /* {{{ proto int timecop_freeze(long timestamp) 978 | Time travel to specified timestamp and freeze */ 979 | PHP_FUNCTION(timecop_freeze) 980 | { 981 | zval *dt; 982 | zend_long timestamp; 983 | tc_timeval freezed_tv; 984 | 985 | if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &dt, TIMECOP_G(ce_DateTimeInterface)) != FAILURE) { 986 | get_timeval_from_datetime(&freezed_tv, dt); 987 | } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "l", ×tamp) != FAILURE) { 988 | freezed_tv.sec = timestamp; 989 | freezed_tv.usec = 0; 990 | } else { 991 | php_error_docref(NULL, E_WARNING, "This function accepts either (DateTimeInterface) OR (int) as arguments."); 992 | RETURN_FALSE; 993 | } 994 | 995 | TIMECOP_G(timecop_mode) = TIMECOP_MODE_FREEZE; 996 | TIMECOP_G(freezed_time) = freezed_tv; 997 | 998 | if (TIMECOP_G(sync_request_time)){ 999 | update_request_time(freezed_tv.sec); 1000 | } 1001 | 1002 | RETURN_TRUE; 1003 | } 1004 | /* }}} */ 1005 | 1006 | /* {{{ proto int timecop_travel(long timestamp) 1007 | Time travel to specified timestamp */ 1008 | PHP_FUNCTION(timecop_travel) 1009 | { 1010 | zval *dt; 1011 | zend_long timestamp; 1012 | tc_timeval now, mock_tv; 1013 | 1014 | if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &dt, TIMECOP_G(ce_DateTimeInterface)) != FAILURE) { 1015 | get_timeval_from_datetime(&mock_tv, dt); 1016 | } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "l", ×tamp) != FAILURE) { 1017 | mock_tv.sec = timestamp; 1018 | mock_tv.usec = 0; 1019 | } else { 1020 | php_error_docref(NULL, E_WARNING, "This function accepts either (DateTimeInterface) OR (int) as arguments."); 1021 | RETURN_FALSE; 1022 | } 1023 | 1024 | TIMECOP_G(timecop_mode) = TIMECOP_MODE_TRAVEL; 1025 | get_current_time(&now); 1026 | tc_timeval_sub(&TIMECOP_G(travel_offset), &mock_tv, &now); 1027 | TIMECOP_G(travel_origin) = now; 1028 | 1029 | if (TIMECOP_G(sync_request_time)){ 1030 | update_request_time(mock_tv.sec); 1031 | } 1032 | 1033 | RETURN_TRUE; 1034 | } 1035 | /* }}} */ 1036 | 1037 | /* {{{ proto int timecop_scale(long scale) 1038 | Accelerate time with specified scale */ 1039 | PHP_FUNCTION(timecop_scale) 1040 | { 1041 | zend_long scale; 1042 | tc_timeval now, mock_time; 1043 | 1044 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &scale) == FAILURE) { 1045 | RETURN_FALSE; 1046 | } 1047 | if (scale < 0) { 1048 | RETURN_FALSE; 1049 | } 1050 | get_current_time(&now); 1051 | get_mock_timeval(&mock_time, &now); 1052 | TIMECOP_G(timecop_mode) = TIMECOP_MODE_TRAVEL; 1053 | TIMECOP_G(travel_origin) = now; 1054 | tc_timeval_sub(&TIMECOP_G(travel_offset), &mock_time, &now); 1055 | TIMECOP_G(scaling_factor) = scale; 1056 | 1057 | if (TIMECOP_G(sync_request_time)){ 1058 | update_request_time(mock_time.sec); 1059 | } 1060 | 1061 | RETURN_TRUE; 1062 | } 1063 | /* }}} */ 1064 | 1065 | /* {{{ proto int timecop_return(void) 1066 | Return to Time travel to specified timestamp */ 1067 | PHP_FUNCTION(timecop_return) 1068 | { 1069 | TIMECOP_G(timecop_mode) = TIMECOP_MODE_REALTIME; 1070 | 1071 | if (TIMECOP_G(sync_request_time)){ 1072 | restore_request_time(); 1073 | } 1074 | 1075 | RETURN_TRUE; 1076 | } 1077 | /* }}} */ 1078 | 1079 | /* {{{ proto int timecop_time(void) 1080 | Return virtual timestamp */ 1081 | PHP_FUNCTION(timecop_time) 1082 | { 1083 | RETURN_LONG(mock_timestamp()); 1084 | } 1085 | /* }}} */ 1086 | 1087 | /* {{{ proto int timecop_mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]]) 1088 | Get UNIX timestamp for a date */ 1089 | PHP_FUNCTION(timecop_mktime) 1090 | { 1091 | TIMECOP_CALL_MKTIME("mktime", "date"); 1092 | } 1093 | /* }}} */ 1094 | 1095 | /* {{{ proto int timecop_gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]]) 1096 | Get UNIX timestamp for a GMT date */ 1097 | PHP_FUNCTION(timecop_gmmktime) 1098 | { 1099 | TIMECOP_CALL_MKTIME("gmmktime", "gmdate"); 1100 | } 1101 | /* }}} */ 1102 | 1103 | /* {{{ proto string timecop_date(string format [, long timestamp]) 1104 | Format a local date/time */ 1105 | PHP_FUNCTION(timecop_date) 1106 | { 1107 | TIMECOP_CALL_FUNCTION("date", 1); 1108 | } 1109 | /* }}} */ 1110 | 1111 | /* {{{ proto string timecop_gmdate(string format [, long timestamp]) 1112 | Format a GMT date/time */ 1113 | PHP_FUNCTION(timecop_gmdate) 1114 | { 1115 | TIMECOP_CALL_FUNCTION("gmdate", 1); 1116 | } 1117 | /* }}} */ 1118 | 1119 | /* {{{ proto int timecop_idate(string format [, int timestamp]) 1120 | Format a local time/date as integer */ 1121 | PHP_FUNCTION(timecop_idate) 1122 | { 1123 | TIMECOP_CALL_FUNCTION("idate", 1); 1124 | } 1125 | /* }}} */ 1126 | 1127 | /* {{{ proto array timecop_getdate([int timestamp]) 1128 | Get date/time information */ 1129 | PHP_FUNCTION(timecop_getdate) 1130 | { 1131 | TIMECOP_CALL_FUNCTION("getdate", 0); 1132 | } 1133 | /* }}} */ 1134 | 1135 | /* {{{ proto array timecop_localtime([int timestamp [, bool associative_array]]) 1136 | Returns the results of the C system call localtime as an associative array if 1137 | the associative_array argument is set to 1 other wise it is a regular array */ 1138 | PHP_FUNCTION(timecop_localtime) 1139 | { 1140 | TIMECOP_CALL_FUNCTION("localtime", 0); 1141 | } 1142 | /* }}} */ 1143 | 1144 | /* {{{ proto int timecop_strtotime(string time [, int now ]) 1145 | Convert string representation of date and time to a timestamp */ 1146 | PHP_FUNCTION(timecop_strtotime) 1147 | { 1148 | TIMECOP_CALL_FUNCTION("strtotime", 1); 1149 | } 1150 | /* }}} */ 1151 | 1152 | /* {{{ proto string timecop_strftime(string format [, int timestamp]) 1153 | Format a local time/date according to locale settings */ 1154 | PHP_FUNCTION(timecop_strftime) 1155 | { 1156 | TIMECOP_CALL_FUNCTION("strftime", 1); 1157 | } 1158 | /* }}} */ 1159 | 1160 | /* {{{ proto string timecop_gmstrftime(string format [, int timestamp]) 1161 | Format a GMT/UCT time/date according to locale settings */ 1162 | PHP_FUNCTION(timecop_gmstrftime) 1163 | { 1164 | TIMECOP_CALL_FUNCTION("gmstrftime", 1); 1165 | } 1166 | /* }}} */ 1167 | 1168 | /* 1169 | * get_mock_timeval(fixed, now) 1170 | * 1171 | * 1172 | * delta 1173 | * |<----------------------->| 1174 | * travel_offset delta * scaling_factor 1175 | * |<------------->|<------------------------------------------------->| 1176 | * ==@===============@=========@=========================================@== 1177 | * ^ ^ ^ 1178 | * | | | 1179 | * travel_origin orig_time traveled_time 1180 | * 1181 | * 1182 | * delta = orig_time - travel_origin 1183 | * traveled_time = travel_origin + travel_offset + delta * scaling_factor 1184 | */ 1185 | static int get_mock_timeval(tc_timeval *fixed, const tc_timeval *now) 1186 | { 1187 | if (TIMECOP_G(timecop_mode) == TIMECOP_MODE_FREEZE) { 1188 | *fixed = TIMECOP_G(freezed_time); 1189 | } else if (TIMECOP_G(timecop_mode) == TIMECOP_MODE_TRAVEL) { 1190 | tc_timeval delta, origin = TIMECOP_G(travel_origin); 1191 | zend_long scale = TIMECOP_G(scaling_factor); 1192 | if (now == NULL) { 1193 | get_current_time(&delta); 1194 | } else { 1195 | delta = *now; 1196 | } 1197 | tc_timeval_sub(&delta, &delta, &origin); 1198 | tc_timeval_mul(&delta, &delta, scale); 1199 | tc_timeval_add(fixed, &origin, &TIMECOP_G(travel_offset)); 1200 | tc_timeval_add(fixed, fixed, &delta); 1201 | } else { 1202 | if (now == NULL) { 1203 | get_current_time(fixed); 1204 | } else { 1205 | *fixed = *now; 1206 | } 1207 | } 1208 | return 0; 1209 | } 1210 | 1211 | static zend_long mock_timestamp() 1212 | { 1213 | tc_timeval tv; 1214 | get_mock_timeval(&tv, NULL); 1215 | return tv.sec; 1216 | } 1217 | 1218 | static int get_timeval_from_datetime(tc_timeval *tp, zval *dt) 1219 | { 1220 | zval sec, usec; 1221 | zval u_str; 1222 | 1223 | call_php_method_with_0_params(dt, Z_OBJCE_P(dt), "gettimestamp", &sec); 1224 | ZVAL_STRING(&u_str, "u"); 1225 | call_php_method_with_1_params(dt, Z_OBJCE_P(dt), "format", &usec, &u_str); 1226 | zval_ptr_dtor(&u_str); 1227 | convert_to_long(&usec); 1228 | 1229 | tp->sec = Z_LVAL(sec); 1230 | tp->usec = Z_LVAL(usec); 1231 | 1232 | return 0; 1233 | } 1234 | 1235 | static int get_current_time(tc_timeval *now) 1236 | { 1237 | int ret = 0; 1238 | #if HAVE_GETTIMEOFDAY 1239 | struct timeval tv; 1240 | ret = gettimeofday(&tv, NULL); 1241 | if (ret == 0) { 1242 | now->sec = (zend_long)tv.tv_sec; 1243 | now->usec = (zend_long)tv.tv_usec; 1244 | } 1245 | #else 1246 | time_t ts = time(NULL); 1247 | if (ts == -1) { 1248 | ret = -1; 1249 | } else { 1250 | now->sec = (zend_long)ts; 1251 | now->usec = 0; 1252 | } 1253 | #endif 1254 | return ret; 1255 | } 1256 | 1257 | #ifdef HAVE_GETTIMEOFDAY 1258 | 1259 | #define MICRO_IN_SEC 1000000.00 1260 | #define SEC_IN_MIN 60 1261 | 1262 | static void _timecop_gettimeofday(INTERNAL_FUNCTION_PARAMETERS, int mode) 1263 | { 1264 | zend_bool get_as_float = 0; 1265 | tc_timeval fixed; 1266 | 1267 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &get_as_float) == FAILURE) { 1268 | RETURN_FALSE; 1269 | } 1270 | 1271 | if (get_mock_timeval(&fixed, NULL)) { 1272 | RETURN_FALSE; 1273 | } 1274 | 1275 | if (get_as_float) { 1276 | RETURN_DOUBLE((double)(fixed.sec + fixed.usec / MICRO_IN_SEC)); 1277 | } 1278 | if (mode) { 1279 | zval zv_offset, zv_dst, format, timestamp; 1280 | zend_long offset = 0, is_dst = 0; 1281 | 1282 | ZVAL_LONG(×tamp, fixed.sec); 1283 | 1284 | /* offset */ 1285 | ZVAL_STRING(&format, "Z"); 1286 | call_php_function_with_2_params(ORIG_FUNC_NAME("date"), &zv_offset, &format, ×tamp); 1287 | convert_to_long(&zv_offset); 1288 | offset = Z_LVAL(zv_offset); 1289 | zval_ptr_dtor(&zv_offset); 1290 | zval_ptr_dtor(&format); 1291 | 1292 | /* is_dst */ 1293 | ZVAL_STRING(&format, "I"); 1294 | call_php_function_with_2_params(ORIG_FUNC_NAME("date"), &zv_dst, &format, ×tamp); 1295 | convert_to_long(&zv_dst); 1296 | is_dst = Z_LVAL(zv_dst); 1297 | zval_ptr_dtor(&zv_dst); 1298 | zval_ptr_dtor(&format); 1299 | 1300 | array_init(return_value); 1301 | add_assoc_long(return_value, "sec", fixed.sec); 1302 | add_assoc_long(return_value, "usec", fixed.usec); 1303 | add_assoc_long(return_value, "minuteswest", -offset / SEC_IN_MIN); 1304 | add_assoc_long(return_value, "dsttime", is_dst); 1305 | } else { 1306 | char ret[100]; 1307 | snprintf(ret, 100, "%.8F %ld", fixed.usec / MICRO_IN_SEC, fixed.sec); 1308 | RETURN_STRING(ret); 1309 | } 1310 | } 1311 | 1312 | /* {{{ proto mixed microtime([bool get_as_float]) 1313 | Returns either a string or a float containing the current time in seconds and microseconds */ 1314 | PHP_FUNCTION(timecop_microtime) 1315 | { 1316 | _timecop_gettimeofday(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1317 | } 1318 | /* }}} */ 1319 | 1320 | /* {{{ proto array gettimeofday([bool get_as_float]) 1321 | Returns the current time as array */ 1322 | PHP_FUNCTION(timecop_gettimeofday) 1323 | { 1324 | _timecop_gettimeofday(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1325 | } 1326 | /* }}} */ 1327 | #endif 1328 | 1329 | /* {{{ proto int timecop_unixtojd([int timestamp]) 1330 | Convert UNIX timestamp to Julian Day */ 1331 | PHP_FUNCTION(timecop_unixtojd) 1332 | { 1333 | TIMECOP_CALL_FUNCTION("unixtojd", 0); 1334 | } 1335 | /* }}} */ 1336 | 1337 | static void _timecop_orig_datetime_constructor(INTERNAL_FUNCTION_PARAMETERS, int immutable) 1338 | { 1339 | zval *arg1 = NULL, *arg2 = NULL; 1340 | zend_class_entry *real_ce; 1341 | 1342 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|zz", &arg1, &arg2) == FAILURE) { 1343 | RETURN_FALSE; 1344 | } 1345 | 1346 | if (immutable) { 1347 | real_ce = TIMECOP_G(ce_DateTimeImmutable); 1348 | } else { 1349 | real_ce = TIMECOP_G(ce_DateTime); 1350 | } 1351 | 1352 | call_php_method_with_2_params(getThis(), real_ce, ORIG_FUNC_NAME("__construct"), NULL, arg1, arg2); 1353 | } 1354 | 1355 | static inline void _timecop_datetime_constructor(INTERNAL_FUNCTION_PARAMETERS, int immutable) 1356 | { 1357 | _timecop_datetime_constructor_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, getThis(), immutable); 1358 | } 1359 | 1360 | static inline void _timecop_date_create(INTERNAL_FUNCTION_PARAMETERS, int immutable) 1361 | { 1362 | _timecop_datetime_constructor_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, NULL, immutable); 1363 | } 1364 | 1365 | static void _timecop_datetime_constructor_ex(INTERNAL_FUNCTION_PARAMETERS, zval *obj, int immutable) 1366 | { 1367 | zval orig_time, *orig_timezone = NULL; 1368 | zval fixed_time, fixed_timezone, *arg1, *arg2; 1369 | char *orig_time_str = NULL; 1370 | size_t orig_time_len = 0; 1371 | const char *real_func; 1372 | zend_class_entry *real_ce; 1373 | 1374 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &orig_time_str, &orig_time_len, &orig_timezone, TIMECOP_G(ce_DateTimeZone)) == FAILURE) { 1375 | RETURN_FALSE; 1376 | } 1377 | 1378 | if (orig_time_str == NULL) { 1379 | ZVAL_NULL(&orig_time); 1380 | } else { 1381 | ZVAL_STRINGL(&orig_time, orig_time_str, orig_time_len); 1382 | } 1383 | if (immutable) { 1384 | real_func = ORIG_FUNC_NAME("date_create_immutable"); 1385 | real_ce = TIMECOP_G(ce_DateTimeImmutable); 1386 | } else { 1387 | real_func = ORIG_FUNC_NAME("date_create"); 1388 | real_ce = TIMECOP_G(ce_DateTime); 1389 | } 1390 | 1391 | if (get_formatted_mock_time(&orig_time, orig_timezone, &fixed_time, &fixed_timezone TSRMLS_CC) == 0) { 1392 | arg1 = &fixed_time; 1393 | arg2 = &fixed_timezone; 1394 | } else { 1395 | arg1 = &orig_time; 1396 | arg2 = orig_timezone; 1397 | } 1398 | if (obj == NULL) { 1399 | call_php_function_with_2_params(real_func, return_value, arg1, arg2); 1400 | } else { 1401 | call_php_method_with_2_params(obj, real_ce, ORIG_FUNC_NAME("__construct"), NULL, arg1, arg2); 1402 | } 1403 | zval_ptr_dtor(&orig_time); 1404 | zval_ptr_dtor(&fixed_time); 1405 | zval_ptr_dtor(&fixed_timezone); 1406 | } 1407 | 1408 | /* {{{ proto DateTime timecop_date_create([string time[, DateTimeZone object]]) 1409 | Returns new DateTime object initialized with traveled time */ 1410 | PHP_FUNCTION(timecop_date_create) 1411 | { 1412 | _timecop_date_create(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1413 | } 1414 | /* }}} */ 1415 | 1416 | static void _timecop_date_create_from_format(INTERNAL_FUNCTION_PARAMETERS, int immutable) 1417 | { 1418 | zval *orig_timezone = NULL; 1419 | zval orig_format, orig_time, fixed_format, fixed_time, new_format, new_time; 1420 | zval dt, dti, now_timestamp, tmp; 1421 | char *orig_format_str, *orig_time_str; 1422 | size_t orig_format_len, orig_time_len; 1423 | tc_timeval now; 1424 | char buf[64]; 1425 | const char *real_func; 1426 | 1427 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|O!", &orig_format_str, &orig_format_len, &orig_time_str, &orig_time_len, &orig_timezone, TIMECOP_G(ce_DateTimeZone)) == FAILURE) { 1428 | RETURN_FALSE; 1429 | } 1430 | 1431 | ZVAL_STRINGL(&orig_format, orig_format_str, orig_format_len); 1432 | ZVAL_STRINGL(&orig_time, orig_time_str, orig_time_len); 1433 | 1434 | call_php_function_with_3_params(ORIG_FUNC_NAME("date_create_from_format"), &dt, &orig_format, &orig_time, orig_timezone); 1435 | if (Z_TYPE(dt) == IS_FALSE) { 1436 | zval_ptr_dtor(&orig_format); 1437 | zval_ptr_dtor(&orig_time); 1438 | RETURN_FALSE; 1439 | } 1440 | 1441 | if (memchr(orig_format_str, '!', orig_format_len) || 1442 | memchr(orig_format_str, '|', orig_format_len)) { 1443 | zval_ptr_dtor(&orig_format); 1444 | zval_ptr_dtor(&orig_time); 1445 | 1446 | if (immutable) { 1447 | call_php_method_with_1_params(NULL, TIMECOP_G(ce_DateTimeImmutable), "createfrommutable", &dti, &dt); 1448 | zval_ptr_dtor(&dt); 1449 | RETURN_ZVAL(&dti, 1, 1); 1450 | } 1451 | 1452 | RETURN_ZVAL(&dt, 1, 1); 1453 | } 1454 | 1455 | get_mock_timeval(&now, NULL); 1456 | 1457 | ZVAL_LONG(&now_timestamp, now.sec); 1458 | call_php_method_with_1_params(&dt, TIMECOP_G(ce_DateTime), "settimestamp", NULL, &now_timestamp); 1459 | sprintf(buf, "Y-m-d H:i:s.%06ld ", now.usec); 1460 | ZVAL_STRING(&tmp, buf); 1461 | call_php_method_with_1_params(&dt, TIMECOP_G(ce_DateTime), "format", &fixed_time, &tmp); 1462 | zval_ptr_dtor(&tmp); 1463 | 1464 | if ( 1465 | #if PHP_VERSION_ID >= 70300 1466 | memchr(orig_format_str, 'u', orig_format_len) || 1467 | #endif 1468 | memchr(orig_format_str, 'g', orig_format_len) || 1469 | memchr(orig_format_str, 'h', orig_format_len) || 1470 | memchr(orig_format_str, 'G', orig_format_len) || 1471 | memchr(orig_format_str, 'H', orig_format_len) || 1472 | memchr(orig_format_str, 'i', orig_format_len) || 1473 | memchr(orig_format_str, 's', orig_format_len) 1474 | ) { 1475 | ZVAL_STRING(&fixed_format, "Y-m-d ??:??:??.??????"); 1476 | } else if (memchr(orig_format_str, 'Y', orig_format_len) || 1477 | memchr(orig_format_str, 'y', orig_format_len) || 1478 | memchr(orig_format_str, 'F', orig_format_len) || 1479 | memchr(orig_format_str, 'M', orig_format_len) || 1480 | memchr(orig_format_str, 'm', orig_format_len) || 1481 | memchr(orig_format_str, 'n', orig_format_len) || 1482 | memchr(orig_format_str, 'd', orig_format_len) || 1483 | memchr(orig_format_str, 'j', orig_format_len) || 1484 | memchr(orig_format_str, 'D', orig_format_len) || 1485 | memchr(orig_format_str, 'l', orig_format_len) || 1486 | memchr(orig_format_str, 'U', orig_format_len)) { 1487 | ZVAL_STRING(&fixed_format, "Y-m-d H:i:s.??????"); 1488 | } else { 1489 | #if PHP_VERSION_ID >= 70100 1490 | ZVAL_STRING(&fixed_format, "Y-m-d H:i:s.u"); 1491 | #else 1492 | ZVAL_STRING(&fixed_format, "Y-m-d H:i:s.??????"); 1493 | #endif 1494 | } 1495 | 1496 | ZVAL_STRING(&tmp, "%s %s"); 1497 | call_php_function_with_3_params("sprintf", &new_format, &tmp, &fixed_format, &orig_format); 1498 | call_php_function_with_3_params("sprintf", &new_time, &tmp, &fixed_time, &orig_time); 1499 | zval_ptr_dtor(&tmp); 1500 | 1501 | if (immutable) { 1502 | real_func = ORIG_FUNC_NAME("date_create_immutable_from_format"); 1503 | } else { 1504 | real_func = ORIG_FUNC_NAME("date_create_from_format"); 1505 | } 1506 | call_php_function_with_3_params(real_func, return_value, &new_format, &new_time, orig_timezone); 1507 | 1508 | zval_ptr_dtor(&dt); 1509 | zval_ptr_dtor(&orig_format); 1510 | zval_ptr_dtor(&orig_time); 1511 | zval_ptr_dtor(&fixed_format); 1512 | zval_ptr_dtor(&fixed_time); 1513 | zval_ptr_dtor(&new_format); 1514 | zval_ptr_dtor(&new_time); 1515 | } 1516 | 1517 | /* {{{ proto DateTime timecop_date_create_from_format(string format, string time[, DateTimeZone object]) 1518 | Returns new DateTime object initialized with traveled time */ 1519 | PHP_FUNCTION(timecop_date_create_from_format) 1520 | { 1521 | _timecop_date_create_from_format(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1522 | } 1523 | /* }}} */ 1524 | 1525 | /* {{{ proto DateTimeImmutable timecop_date_create_immutable([string time[, DateTimeZone object]]) 1526 | Returns new DateTimeImmutable object initialized with traveled time */ 1527 | PHP_FUNCTION(timecop_date_create_immutable) 1528 | { 1529 | _timecop_date_create(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1530 | } 1531 | /* }}} */ 1532 | 1533 | /* {{{ proto DateTimeImmutable timecop_date_create_immutable_from_format(string format, string time[, DateTimeZone object]) 1534 | Returns new DateTimeImmutable object initialized with traveled time */ 1535 | PHP_FUNCTION(timecop_date_create_immutable_from_format) 1536 | { 1537 | _timecop_date_create_from_format(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1538 | } 1539 | /* }}} */ 1540 | 1541 | /* {{{ proto TimecopDateTime::__construct([string time[, DateTimeZone object]]) 1542 | Creates new TimecopDateTime object */ 1543 | PHP_METHOD(TimecopDateTime, __construct) 1544 | { 1545 | _timecop_datetime_constructor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1546 | } 1547 | /* }}} */ 1548 | 1549 | /* {{{ proto TimecopOrigDateTime::__construct([string time[, DateTimeZone object]]) 1550 | Creates new TimecopOrigDateTime object */ 1551 | PHP_METHOD(TimecopOrigDateTime, __construct) 1552 | { 1553 | _timecop_orig_datetime_constructor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1554 | } 1555 | /* }}} */ 1556 | 1557 | /* {{{ proto TimecopDateTimeImmutable::__construct([string time[, DateTimeZone object]]) 1558 | Creates new TimecopDateTimeImmutable object */ 1559 | PHP_METHOD(TimecopDateTimeImmutable, __construct) 1560 | { 1561 | _timecop_datetime_constructor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1562 | } 1563 | /* }}} */ 1564 | 1565 | /* {{{ proto TimecopOrigDateTimeImmutable::__construct([string time[, DateTimeZone object]]) 1566 | Creates new TimecopOrigDateTimeImmutable object */ 1567 | PHP_METHOD(TimecopOrigDateTimeImmutable, __construct) 1568 | { 1569 | _timecop_orig_datetime_constructor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1570 | } 1571 | /* }}} */ 1572 | 1573 | static inline zval* _call_php_method_with_0_params(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr) 1574 | { 1575 | return _call_php_method(object_pp, obj_ce, method_name, retval_ptr, 0, NULL, NULL); 1576 | } 1577 | 1578 | static inline zval* _call_php_method_with_1_params(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr, zval *arg1) 1579 | { 1580 | int nparams = 1; 1581 | if (arg1 == NULL) { 1582 | nparams = 0; 1583 | } 1584 | return _call_php_method(object_pp, obj_ce, method_name, retval_ptr, nparams, arg1, NULL); 1585 | } 1586 | 1587 | static inline zval* _call_php_method_with_2_params(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr, zval *arg1, zval *arg2) 1588 | { 1589 | int nparams = 2; 1590 | if (arg1 == NULL) { 1591 | nparams = 0; 1592 | } else if (arg2 == NULL) { 1593 | nparams = 1; 1594 | } 1595 | return _call_php_method(object_pp, obj_ce, method_name, retval_ptr, nparams, arg1, arg2); 1596 | } 1597 | 1598 | static inline zval* _call_php_method(zval *object_pp, zend_class_entry *obj_ce, const char *method_name, zval *retval_ptr, int param_count, zval* arg1, zval* arg2) 1599 | { 1600 | return zend_call_method(object_pp, obj_ce, NULL, method_name, strlen(method_name), retval_ptr, param_count, arg1, arg2); 1601 | } 1602 | 1603 | static inline void _call_php_function_with_0_params(const char *function_name, zval *retval_ptr) 1604 | { 1605 | _call_php_method_with_0_params(NULL, NULL, function_name, retval_ptr); 1606 | } 1607 | 1608 | static inline void _call_php_function_with_1_params(const char *function_name, zval *retval_ptr, zval *arg1) 1609 | { 1610 | _call_php_method_with_1_params(NULL, NULL, function_name, retval_ptr, arg1); 1611 | } 1612 | 1613 | static inline void _call_php_function_with_2_params(const char *function_name, zval *retval_ptr, zval *arg1, zval *arg2) 1614 | { 1615 | _call_php_method_with_2_params(NULL, NULL, function_name, retval_ptr, arg1, arg2); 1616 | } 1617 | 1618 | static inline void _call_php_function_with_3_params(const char *function_name, zval *retval_ptr, zval *arg1, zval *arg2, zval *arg3) 1619 | { 1620 | if (arg3 == NULL) { 1621 | _call_php_function_with_2_params(function_name, retval_ptr, arg1, arg2); 1622 | } else { 1623 | zval params[3]; 1624 | ZVAL_COPY(¶ms[0], arg1); 1625 | ZVAL_COPY(¶ms[1], arg2); 1626 | ZVAL_COPY(¶ms[2], arg3); 1627 | call_php_function_with_params(function_name, retval_ptr, 3, params); 1628 | zval_ptr_dtor(¶ms[0]); 1629 | zval_ptr_dtor(¶ms[1]); 1630 | zval_ptr_dtor(¶ms[2]); 1631 | } 1632 | } 1633 | 1634 | static inline void _call_php_function_with_params(const char *function_name, zval *retval_ptr, uint32_t param_count, zval *params) 1635 | { 1636 | zval callable; 1637 | ZVAL_STRING(&callable, function_name); 1638 | 1639 | call_user_function_ex(EG(function_table), NULL, &callable, retval_ptr, param_count, params, 1, NULL); 1640 | 1641 | zval_ptr_dtor(&callable); 1642 | } 1643 | 1644 | /* 1645 | * Local variables: 1646 | * tab-width: 4 1647 | * c-basic-offset: 4 1648 | * End: 1649 | * vim600: noet sw=4 ts=4 fdm=marker 1650 | * vim<600: noet sw=4 ts=4 1651 | */ 1652 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | centos: 2 | box: library/centos 3 | steps: 4 | - script: 5 | name: yum -y install gcc make php php-devel rpm-build 6 | code: |- 7 | yum -y install gcc make php php-devel rpm-build 8 | - script: 9 | name: setenv TIMECOP_VER 10 | code: |- 11 | export TIMECOP_VER=$(grep '^Version' php-timecop.spec | sed 's/^.*[^0-9.]\([0-9.]*\)$/\1/') 12 | echo TIMECOP_VER=${TIMECOP_VER} 13 | - script: 14 | name: rpmbuild 15 | code: |- 16 | TIMECOP_TMP="$(dirname $(mktemp --dry-run 2>/dev/null || echo "/var/tmp/tmp_dir"))/php-timecop" 17 | echo TIMECOP_TMP=${TIMECOP_TMP} 18 | mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} 19 | mkdir -p ${TIMECOP_TMP}/php-timecop-${TIMECOP_VER}/ 20 | cp -R ./ ${TIMECOP_TMP}/php-timecop-${TIMECOP_VER}/ 21 | tar cvzf ~/rpmbuild/SOURCES/php-timecop-${TIMECOP_VER}.tar.gz -C ${TIMECOP_TMP} php-timecop-${TIMECOP_VER}/ 22 | rpmbuild -bb php-timecop.spec 23 | ubuntu-32bit: 24 | box: 32bit/ubuntu:16.04 25 | steps: 26 | - script: 27 | name: Install required software 28 | code: |- 29 | apt-get -y update 30 | DEBIAN_FRONTEND=noninteractive apt-get -y upgrade build-essential php-dev --no-install-recommends 31 | - script: 32 | name: Build test targets 33 | code: |- 34 | phpize && ./configure && make 35 | - script: 36 | name: Run test 37 | code: |- 38 | make test REPORT_EXIT_STATUS=1 NO_INTERACTION=1 TESTS="--show-all" | tee tests-output.txt && if grep -q 'TEST SUMMARY$' tests-output.txt ; then exit 1 ; fi 39 | --------------------------------------------------------------------------------