News Archive
PhpRiot Newsletter
Your Email Address:

More information

Using the PHP CLI Webserver to Identify and Test Memory Issues in PHP

Note: This article was originally published at Planet PHP on 15 August 2012.
Planet PHP

The PHP 5.4 CLI webserver is being used more and more to identify and resolve PHP bugs. Following on from the CLI webserver tests that Xinchen Hui (aka "laruence") instigated for the PHP 5.4 release, Anatoliy Belsky (aka "weltling") begain adding CLI webserver tests for the APC package, which is currently undergoing some much needed fixups for PHP 5.4.

Rasmus Lerdorf has also been running some of the PHP command line tests through the CLI web server to identify crashes and memory corruption issues that the existing one-test-per-process tests can't identify. Even today a fix for a session issue was merged by Laruence. The symptom would have been a random crash that would have been very hard to reproduce and explain to the PHP developers.

Rasmus mentioned on IRC how he ran the tests: simply renaming the ".phpt" test files as ".php", and invoking them through the CLI webserver. The SKIPIF sections get executed, but that doesn't affect the desired outcome of testing multiple HTTP requests with different input scripts.

Below are some quick shell scripts I put together to automate testing the OCI8 extension with valgrind.

There are three scripts. The first creates a copy of all OCI8 tests with names changed to ".php":

#!/bin/sh # NAME: # PURPOSE: Copy .phpt files as .php # Assumes a clean PHP-5.4 branch with no tests/*.diff filesSD=$HOME/php-5.4/ext/oci8/testscd /tmp && rm -rf tests && mkdir tests for F in $(echo $SD/*) do if [ "${F##*.}" = "phpt" ]; then # sym link with a .php file extension instead of .phpt N=$(basename $F .phpt).php else # sym link the unchanged filename N=$(basename $F) fi ln -s $F tests/$N done

The second script starts the PHP CLI webserver:

#!/bin/sh # NAME: # PURPOSE: Start the CLI webserver PHP="$HOME/phpbuild/php54/sapi/cli/php" PHPOPTS="-d max_execution_time=600 -d log_errors=Off" PORT=4444 VALGRIND=valgrind VALGRINDOPTS=" --tool=memcheck --suppressions=$HOME/.valgrind_supp" USE_ZEND_ALLOC=0 $VALGRIND $VALGRINDOPTS $PHP $PHPOPTS \ -t /tmp/tests -S localhost:$PORT

Here I'm running valgrind to check for memory issues. I set the execution time large, because several of the OCI8 tests take time, especially with valgrind.

The third script invokes all PHP tests sequentially:

#!/bin/sh # NAME: # PURPOSE: Load all .php scripts sequentiallyPORT=4444cd /tmp/tests for F in *.php do wget -O /tmp/L.php_cli_test http://localhost:$PORT/$F done

You can change this script to call subsets of your own scripts, or repeatedly call scripts to check memory usage and cleanup code.

To use the scripts, start the webserver and wait for it to initialize:

$ ./ ==14170== Memcheck, a memory error detector ==14170== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==14170== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info ==14170== Command: php -d max_execution_time=600 -d log_errors=Off -t /tmp/tests -S localhost:4444 ==14170== PHP 5.4.5-dev Development Server started at Tue Aug 14 14:53:34 2012 Listening on http://localhost:4444 Document root is /tmp/tests Press Ctrl-C to quit.

This sits, waiting to handle requests.

In a second terminal run to initiate requests:

$ ./ --2012-08-14 14:38:41-- http://localhost:4444/tests/array_bind_001.php Resolving localhost... Connecting to localhost||:4444... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [text/html] Saving to: `/tmp/L.php_cli_test'[ ] 707 --.-K/s in 0.003s 2012-08-14 14:38:44 (231 KB/s) - `/tmp/L.php_cli_test' saved [707] . . .

You could suppress this output by adding the option "-o /tmp/L.wg_output" to I didn't add it because, although I'm ignoring output, I like to see that the tests are really returning something.

The first terminal running the CLI web server shows each requested script:

[Tue Aug 14 14:35:06 2012] [200]: /tests/array_bind_001.php [Tue Aug 14 14:35:06 2012] [200]: /tests/array_bind_002.php [Tue Aug 14 14:35:07 2012] [200]: /tests/array_bind_003.php [Tue Aug 14 14:35:07 2012] [200]: /tests/array_bind_004.php [Tue Aug 14 14:35:07 2012] [200]: /tests/array_bind_005.php [Tue Aug 14 14:35:07 2012] [200]: /tests/array_bind_006.php [Tue Aug 14 14:35:07 2012]

Truncated by Planet PHP, read more at the original (another 930 bytes)