Your SlideShare is downloading. ×
Time tested php with libtimemachine
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Time tested php with libtimemachine

1,116
views

Published on

Dynamically adjust system time used by PHP with libtimemachine for advanced testing.

Dynamically adjust system time used by PHP with libtimemachine for advanced testing.

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,116
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
13
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript

    • 1. Time Tested PHPAdvanced testing techniques with libTimeMachine Nick Galbreath nickg@client9.com @ngalbreath Vince Tse vtonehundred@gmail.com @vtonehundred 2012-07-19
    • 2. Follow along or get the latest version at:http://slidesha.re/ NDc5mK
    • 3. Time HappensWhile it should be avoided as much as possible, sometimes"time happens" and applications need testing based onsimulated time.• Financial applications (e.g. simulating ad spending and budgeting)• Security features (what happens when the cookie or auth token expires?)• System testing (what happens on leap year? day light savings time? 2038?)• Anything that runs periodically ("on the hour")
    • 4. PHP Time Sources• $_SERVER[REQUEST_TIME]• time()• microtime()• gettimeofday()• Single argument of date(fmt) (equivalent to date(fmt, time())
    • 5. Using $_SERVER[REQUEST_TIME]• Available in all SAPI contexts (mod_php, CLI, CGI, FPM...)• Created once at time of request• "Lowest Cost" -- array lookup• Easy to spoof in unit tests• Cant spoof for functional tests• Cant use it for timing
    • 6. Passing as Argument• Dont call time() et al directly in a function but instead pass current time in.• Allows unit testing• Follows dependency injection best-practice
    • 7. But what if your code isnt or cant bestructured that way?
    • 8. Time Travel with libtimemachine!https://github.com/vtonehundred/libtimemachine Changes the system calls that PHP uses to get the current time • time (defined in <time.h>) • gettimeofday (defined in <sys/time.h>) • clock_gettime (defined in <time.h>) and allows you to change them backwards or forward, relative or absolute.
    • 9. LibTimeMachine• Use some secret loader sexiness to change the underlying system calls. (see man ld-linux for details)• Works on Linux systems• Works on Mac OS X (only tested on 10.7.4)• Sorry Windows• (not sure about FreeBSD)
    • 10. Plug and Playgit clone git://github.com/vtonehundred/libtimemachine.gitcd libtimemachinemakesudo cp libtimemachine.so [ /lib64 or /lib ]sudo ldconfig
    • 11. To use!• libtimemachine reads /tmp/libtimemachine.conf (or whatever file you want using the LIBTIMEMACHINE_CONF environment variable)• Single number controls how to adjust time• If starts with "-" or "+" then current time will be adjusted by a relative amount.• If "just numbers" then the time is fixed with this value• If "0" or missing, then use current time
    • 12. PHP CLIJust add LD_PRELOAD=libtimemachine.sobefore php on the command line$ php -r echo date("rn");Mon, 28 May 2012 23:03:38 -0400$ # go back one year$ echo "-31536000" > /tmp/libtimemachine.conf$ LD_PRELOAD=libtimemachine.so php -r echo date("rn");Sun, 29 May 2011 23:03:49 -0400$ #winning
    • 13. PHP 5.4 Built-In WebServer This is the easiest way to go!$ dateMon May 28 23:27:19 2012$ echo "31536000" > /tmp/libtimemachine.conf$ LD_PRELOAD=/lib64/libtimemachine.so ./php -t ~/root -S 127.0.0.1:80PHP 5.4.3 Development Server started at Tue May 28 23:29:19 2013Listening on 127.0.0.1:80Document root is ~/rootPress Ctrl-C to quit.[Tue May 28 23:29:22 2013] 127.0.0.1:34913 [200]: ~/time.php Command line CGI works similarly
    • 14. Apache mod_php Debian / Ubuntu• Install libtimemachine.so in /lib64 or / lib depending on your OS.• (for good measure also do "sudo ldconfig")• /etc/apache2/envvars controls the apache and workers environment. Add export LD_PRELOAD=libtimemachine.so• sudo /etc/init.d/apache2 restart
    • 15. <?phpheader(Content-Type: text/plain);date_default_timezone_set(UTC); //if you need itprintf("REQUEST_TIME : %sn", date("r",$_SERVER[REQUEST_TIME]));printf("time() : %sn", date("r", time()));printf("microtime() : %sn", date("r", microtime(TRUE)));printf("date(r) : %sn", date("r"));printf("gettimeofday() : %sn", date("r", gettimeofday(TRUE)));//print_r($_SERVER);
    • 16. Back One Day!$ dateSun, 27 May 2012 19:35:41 +0000$ echo "-86400" > /tmp/libtimemachine.conf$ curl http://127.0.0.1/phptime.phpREQUEST_TIME : Sat, 26 May 2012 19:35:54 +0000time() : Sat, 26 May 2012 19:35:54 +0000microtime() : Sat, 26 May 2012 19:35:54 +0000date(r) : Sat, 26 May 2012 19:35:54 +0000gettimeofday() : Sat, 26 May 2012 19:35:54 +0000
    • 17. apache mod_php RedHat/CentOS• Disable SELinux: in /etc/selinux/config set SELINUX=disabled• put libtimemachine.so in /lib64 or /lib depending on your OS.• (for good measure also do "sudo ldconfig")• add to /etc/sysconfig/httpd export LD_PRELOAD=libtimemachine.so• And then...
    • 18. Fail on Apache +mod_php + CentOS 6.2• SELinux removes LD_PRELOAD• Even though we disabled SELinux, it appears the linker isnt getting LD_PRELOAD• mod_php is an shared library that loads shared libraries. hmmm• I suspect a bug in the OS? Or maybe mod_php is compiled differently.• Use PHP 5.4s built-in web server instead for testing.
    • 19. Future Work• Apache + PHP CGI (does anyone do this?)• nginx + PHP FPM (the new hotness)• Figuring out what is going on with CentOS• Testing on mysql server.• Packaging
    • 20. Detecting libtimemachine• Look for existence of /tmp/libtimemachine.conf• Shell out and use "date +%s" and compare to time()• Use Apache mod_env and add PassEnv LD_PRELOAD to let PHP see the environment variable
    • 21. Evil• Can this technique be used for evil?• Oh yeah.• type "LD_PRELOAD rootkit" in your favorite search engine for details
    • 22. Mac OS X Notes• Only tested on 10.7.4• Mac OS X uses dyld for linking and works different than gnu ld. See man dyld for details.• Instead of LD_PRELOAD, use: DYLD_INSERT_LIBRARIES=./libtimemachine.dylib• If that doesnt work, add DYLD_FORCE_FLAT_NAMESPACE=1
    • 23. Gotchas• if you globally set LD_PRELOAD, export LD_PRELOAD=libtimemachine.so then everything you do might be time shifted (to undo unset LD_PRELOAD)• Your application might run a bit slower since every time lookup requires reading /tmp/libtimemachine.conf
    • 24. Thanks!https://github.com/vtonehundred/libtimemachine Nick Galbreath nickg@client9.com @ngalbreath Vince Tse vtonehundred@gmail.com @vtonehundred