Today I learned about the php_ini_loaded_file function. It returns the path to the php.ini file if one is loaded. This function is implemented in JavaScript at jsphp.co, but the implementation isn’t very interesting.
Daily Archives: 2012-01-10 [Tuesday]
Profiling a PHP script
Note: if you’re a web developer you might be interested in registering to become a ProgClub member. ProgClub is a free international club for computer programmers and we run some mailing lists you might like to hang out on to chat about software development, life, etc.
Warning: this article is long and detailed and contains a fair number of notes about experimental modifications. If you’re going to try applying the ideas in this file I strong encourage you to read the whole article first, and especially the comments which include important notes about how to patch the software properly (rather than just commenting stuff out which I do initially). You have been warned!
Update: this article is over three years old. It’s helped a number of people, which is nice, but it’s time to move on. The APD component is ancient and unmaintained. If you want a PHP profiler I strongly recommend Xdebug. Seriously: use Xdebug. Oh, and be careful!
Let me take you on a fabulous adventure.
I was working on a new web app I’m doing and the app felt a little sluggish. I wanted to know what was causing the sluggishness. Was it database access? Encryption? Compression? Something else?
So I did a search for profiling a php script and turned up this article (Simplest way to profile a PHP script) at StackOverflow. I read this answer which suggested the PECL APD extension so I figured I’d check it out.
I found the documentation for APD (APD stands for Advanced PHP Debugger) and I read the installation instructions, but there didn’t seem to be anything there. Admittedly I was just looking for the Ubuntu package to install with apt-get. Now that I’m writing this up I realise I should have read Installation of PECL extensions first, but I missed that at the time.
I started throwing commands at my terminal:
# apt-cache search apd # apt-cache search apd php # apt-cache search apd | grep php # apt-cache search apd | grep PHP # cd /usr # find -name "apd.so" # apt-cache search pecl # apt-get install dh-make-php
The dh-make-php package was the closest thing I could find, so I thought maybe I would try that. It said “dh-make-php – Creates Debian source packages for PHP PEAR and PECL extensions”, sounded pretty close. Maybe. Anyway, before I confirmed the installation of of dh-make-php I thought I’d do some more research.
I searched for installing pecl apd ubuntu but that didn’t seem to turn up much. The first result was in French, and it only seemed to be an unanswered question about an error during compilation.
I searched for apd.so ubuntu (because the installation instructions that I read said I needed apd.so) and I turned up How to install apd in debian php5 at ServerFault. The answer said to install php-pear and then run “pecl install apd”. So I did “apt-get install php-pear” and that worked well enough. Then I ran pecl:
root@sixsigma:~# pecl install apd downloading apd-1.0.1.tgz ... Starting to download apd-1.0.1.tgz (36,643 bytes) ..........done: 36,643 bytes 15 source files, building running: phpize sh: phpize: not found ERROR: `phpize' failed
I searched for sh: phpize: not found ERROR: `phpize’ failed and found phpize: command not found which said I needed to apt-get install php5-dev, which I did. Then I tried again:
root@sixsigma:~# pecl install apd downloading apd-1.0.1.tgz ... Starting to download apd-1.0.1.tgz (36,643 bytes) ..........done: 36,643 bytes 15 source files, building running: phpize Cannot find config.m4. Make sure that you run '/usr/bin/phpize' in the top level source directory of the module ERROR: `phpize' failed
I searched for the error message running: phpize Cannot find config.m4. and found Cannot find config.m4 + phpize +Resolved which just said like the error message said that I needed to run from the top level source directory. Whatever that was supposed to mean.
I searched for the downloaded file apd-1.0.1.tgz and found it in /build/buildd/php5-5.3.2/pear-build-download/. So I tried the following:
root@sixsigma:~# cd /build/buildd/php5-5.3.2/pear-build-download/ root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download# tar xvf apd-1.0.1.tgz package.xml apd-1.0.1/LICENSE apd-1.0.1/Makefile.in apd-1.0.1/README apd-1.0.1/apd.dsp apd-1.0.1/apd_array.c apd-1.0.1/apd_array.h apd-1.0.1/apd_lib.c apd-1.0.1/apd_lib.h apd-1.0.1/apd_summary.c apd-1.0.1/build apd-1.0.1/build/CVS apd-1.0.1/build/CVS/Entries apd-1.0.1/build/CVS/Repository apd-1.0.1/build/CVS/Root apd-1.0.1/build/mkdep.awk apd-1.0.1/build/scan_makefile_in.awk apd-1.0.1/build/shtool apd-1.0.1/config.m4 apd-1.0.1/php_apd.c apd-1.0.1/php_apd.h apd-1.0.1/php_sockets.h apd-1.0.1/php_sockets_win.h apd-1.0.1/pprofp apd-1.0.1/pprof2calltree apd-1.0.1/win32compat.c apd-1.0.1/win32compat.h root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download# cd apd-1.0.1 root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ls apd_array.c apd_lib.h LICENSE php_sockets.h README apd_array.h apd_summary.c Makefile.in php_sockets_win.h win32compat.c apd.dsp build php_apd.c pprof2calltree win32compat.h apd_lib.c config.m4 php_apd.h pprofp
It wasn’t clear what to do next. There was no configure script or Makefile in the directory.
I searched for the full error message Starting to download apd-1.0.1.tgz (36,643 bytes) ……….done: 36,643 bytes 15 source files, building running: phpize Cannot find config.m4. and found this which seemed to suggest I needed to run “pear channel-update pear.php.net” which I did, but nothing exciting happened:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# pear channel-update pear.php.net Updating channel "pear.php.net" Channel "pear.php.net" is up to date root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# pecl install apd downloading apd-1.0.1.tgz ... Starting to download apd-1.0.1.tgz (36,643 bytes) ..........done: 36,643 bytes 15 source files, building running: phpize Cannot find config.m4. Make sure that you run '/usr/bin/phpize' in the top level source directory of the module ERROR: `phpize' failed
The error message had said something about “phpize” so I figured I’d give that a go.
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# phpize Configuring for: PHP Api Version: 20090626 Zend Module Api No: 20090626 Zend Extension Api No: 220090626 root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ls acinclude.m4 apd_summary.c configure missing pprofp aclocal.m4 autom4te.cache configure.in mkinstalldirs README apd_array.c build install-sh php_apd.c run-tests.php apd_array.h config.guess LICENSE php_apd.h win32compat.c apd.dsp config.h.in ltmain.sh php_sockets.h win32compat.h apd_lib.c config.m4 Makefile.global php_sockets_win.h apd_lib.h config.sub Makefile.in pprof2calltree
And there you go! The “phpize” command built me a configure script. So…
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ./configure checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for a sed that does not truncate output... /bin/sed checking for cc... cc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether cc accepts -g... yes checking for cc option to accept ISO C89... none needed checking how to run the C preprocessor... cc -E checking for icc... no checking for suncc... no checking whether cc understands -c and -o together... yes checking for system library directory... lib checking if compiler supports -R... no checking if compiler supports -Wl,-rpath,... yes checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu checking target system type... x86_64-unknown-linux-gnu checking for PHP prefix... /usr checking for PHP includes... -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib checking for PHP extension directory... /usr/lib/php5/20090626 checking for PHP installed headers prefix... /usr/include/php5 checking if debug is enabled... no checking if zts is enabled... no checking for re2c... re2c checking for re2c version... 0.13.5 (ok) checking for gawk... no checking for nawk... nawk checking if nawk is broken... no checking whether to enable apd support... yes, shared checking for a sed that does not truncate output... (cached) /bin/sed checking for fgrep... /bin/grep -F checking for ld used by cc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1572864 checking whether the shell understands some XSI constructs... yes checking whether the shell understands "+="... yes checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for ar... ar checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from cc object... ok checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if cc supports -fno-rtti -fno-exceptions... no checking for cc option to produce PIC... -fPIC -DPIC checking if cc PIC flag -fPIC -DPIC works... yes checking if cc static flag -static works... yes checking if cc supports -c -o file.o... yes checking if cc supports -c -o file.o... (cached) yes checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... no configure: creating ./config.status config.status: creating config.h config.status: executing libtool commands root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# make /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=compile cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c -o php_apd.lo libtool: compile: cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c -fPIC -DPIC -o .libs/php_apd.o /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_dump_fprintfâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:182: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_pprof_fprintfâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:205: warning: format not a string literal and no format arguments /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_interactiveâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:241: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_override_functionâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:615: warning: âzend_get_parameters_exâ is deprecated (declared at /usr/include/php5/Zend/zend_API.h:222) /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_rename_functionâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:669: warning: âzend_get_parameters_exâ is deprecated (declared at /usr/include/php5/Zend/zend_API.h:222) /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_apd_set_pprof_traceâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:792: warning: âzend_get_parameters_exâ is deprecated (declared at /usr/include/php5/Zend/zend_API.h:222) /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_apd_echoâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:934: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:935: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_zend_startupâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:967: error: âstruct _zend_compiler_globalsâ has no member named âextended_infoâ make: *** [php_apd.lo] Error 1
I searched for building pecl apd but didn’t turn up anything useful. I had a look at the code in php_apd.c on line 967:
int apd_zend_startup(zend_extension *extension) { TSRMLS_FETCH(); CG(extended_info) = 1; /* XXX: this is ridiculous */ return zend_startup_module(&apd_module_entry); }
The problem line was the line saying “this is ridiculous”. I wonder what they meant?
I decided to figure out where CG was defined so I could figure out what was going on. I grepped for CG:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# grep -R "define CG" * root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1#
No dice. I had a look in the Makefile and found phpincludedir = /usr/include/php5.
jj5@sixsigma:~$ cd /usr/include/php5 jj5@sixsigma:/usr/include/php5$ ls ext main TSRM Zend jj5@sixsigma:/usr/include/php5$ grep -R "define CG" * Zend/zend_globals_macros.h:# define CG(v) TSRMG(compiler_globals_id, zend_compiler_globals *, v) Zend/zend_globals_macros.h:# define CG(v) (compiler_globals.v)
The code in question was:
/* Compiler */ #ifdef ZTS # define CG(v) TSRMG(compiler_globals_id, zend_compiler_globals *, v) int zendparse(void *compiler_globals); #else # define CG(v) (compiler_globals.v) extern ZEND_API struct _zend_compiler_globals compiler_globals; int zendparse(void); #endif
I wasn’t sure if ZTS was defined or not, but in any event the problem seemed to be related to *zend_compiler_globals.
root@sixsigma:/usr/include/php5# grep -R compiler_global * Zend/zend_globals_macros.h:typedef struct _zend_compiler_globals zend_compiler_globals; Zend/zend_globals_macros.h:# define CG(v) TSRMG(compiler_globals_id, zend_compiler_globals *, v) Zend/zend_globals_macros.h:int zendparse(void *compiler_globals); Zend/zend_globals_macros.h:# define CG(v) (compiler_globals.v) Zend/zend_globals_macros.h:extern ZEND_API struct _zend_compiler_globals compiler_globals; Zend/zend_globals.h:ZEND_API extern int compiler_globals_id; Zend/zend_globals.h:struct _zend_compiler_globals {
I found the struct definition in Zend/zend_globals.h. I had a look at the source. It was a huge file. I searched for “extend” (because the error message was about missing member “extended_info”) and all I found was:
/* for extended information support */ zend_bool no_extensions;
Maybe I had an older version of the header file and it had been refactored from “no_extensions” to “extended_info”? That might explain why the comment was complaining about something being ridiculous. Maybe they rename their interface all the time? I tried changing php_apd.c to use “no_extensions” instead of “extended_info” but that didn’t compile either. Not knowing what else to do I commented out the line wtih the syntax error:
int apd_zend_startup(zend_extension *extension) { TSRMLS_FETCH(); /* CG(extended_info) = 1; /* XXX: this is ridiculous */ return zend_startup_module(&apd_module_entry); }
Then I ran make again:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# make /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=compile cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c -o php_apd.lo libtool: compile: cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c -fPIC -DPIC -o .libs/php_apd.o /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_dump_fprintfâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:182: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_pprof_fprintfâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:205: warning: format not a string literal and no format arguments /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âapd_interactiveâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:241: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_override_functionâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:615: warning: âzend_get_parameters_exâ is deprecated (declared at /usr/include/php5/Zend/zend_API.h:222) /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_rename_functionâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:669: warning: âzend_get_parameters_exâ is deprecated (declared at /usr/include/php5/Zend/zend_API.h:222) /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_apd_set_pprof_traceâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:792: warning: âzend_get_parameters_exâ is deprecated (declared at /usr/include/php5/Zend/zend_API.h:222) /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c: In function âzif_apd_echoâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:934: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/php_apd.c:935: warning: ignoring return value of âwriteâ, declared with attribute warn_unused_result /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=compile cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_lib.c -o apd_lib.lo libtool: compile: cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_lib.c -fPIC -DPIC -o .libs/apd_lib.o /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=compile cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_array.c -o apd_array.lo libtool: compile: cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_array.c -fPIC -DPIC -o .libs/apd_array.o /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=compile cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_summary.c -o apd_summary.lo libtool: compile: cc -I. -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_summary.c -fPIC -DPIC -o .libs/apd_summary.o /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_summary.c: In function âapd_summary_output_footerâ: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_summary.c:278: warning: unknown conversion type character â"â in format /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/apd_summary.c:294: warning: passing argument 6 of âphp_basenameâ from incompatible pointer type /usr/include/php5/ext/standard/php_string.h:128: note: expected âsize_t *â but argument is of type âint *â /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=link cc -DPHP_ATOM_INC -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/include -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/main -I/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 -I/usr/include/php5 -I/usr/include/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include/php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -g -O2 -o apd.la -export-dynamic -avoid-version -prefer-pic -module -rpath /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules php_apd.lo apd_lib.lo apd_array.lo apd_summary.lo libtool: link: cc -shared .libs/php_apd.o .libs/apd_lib.o .libs/apd_array.o .libs/apd_summary.o -Wl,-soname -Wl,apd.so -o .libs/apd.so libtool: link: ( cd ".libs" && rm -f "apd.la" && ln -s "../apd.la" "apd.la" ) /bin/bash /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/libtool --mode=install cp ./apd.la /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules libtool: install: cp ./.libs/apd.so /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules/apd.so libtool: install: cp ./.libs/apd.lai /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules/apd.la libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin:/usr/lib/surfraw:/sbin" ldconfig -n /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules ---------------------------------------------------------------------- Libraries have been installed in: /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution - add LIBDIR to the `LD_RUN_PATH' environment variable during linking - use the `-Wl,-rpath -Wl,LIBDIR' linker flag - have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages. ---------------------------------------------------------------------- Build complete. Don't forget to run 'make test'.
Success!
The build script said to run make test, so:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# make test Build complete. Don't forget to run 'make test'. PHP Warning: PHP Startup: Invalid library (maybe not a PHP library) 'apd.so' in Unknown on line 0 Warning: PHP Startup: Invalid library (maybe not a PHP library) 'apd.so' in Unknown on line 0 PHP Warning: PHP Startup: Invalid library (maybe not a PHP library) 'apd.so' in Unknown on line 0 Warning: PHP Startup: Invalid library (maybe not a PHP library) 'apd.so' in Unknown on line 0 ===================================================================== PHP : /usr/bin/php PHP_SAPI : cli PHP_VERSION : 5.3.2-1ubuntu4.11 ZEND_VERSION: 2.3.0 PHP_OS : Linux - Linux sixsigma.blackbrick.com 2.6.33.5-rscloud #2 SMP Thu Jun 10 15:26:23 UTC 2010 x86_64 INI actual : /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini More .INIs : CWD : /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 Extra dirs : VALGRIND : Not used ===================================================================== TIME START 2012-01-10 04:13:08 ===================================================================== No tests were run.
That didn’t look good. There was complaints about an invalid apd.so library and no tests were run. What next?
I had a look in the Makefile for the “test: all” target:
test: all -@if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \ INI_FILE=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r 'echo php_ini_loaded_file();' 2> /dev/null`; \ if test "$$INI_FILE"; then \ $(EGREP) -h -v $(PHP_DEPRECATED_DIRECTIVES_REGEX) "$$INI_FILE" > $(top_builddir)/tmp-php.ini; \ else \ echo > $(top_builddir)/tmp-php.ini; \ fi; \ INI_SCANNED_PATH=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r '$$a = explode(",\n", trim(php_ini_scanned_files())); echo $$a[0];' 2> /dev/null`; \ if test "$$INI_SCANNED_PATH"; then \ INI_SCANNED_PATH=`$(top_srcdir)/build/shtool path -d $$INI_SCANNED_PATH`; \ $(EGREP) -h -v $(PHP_DEPRECATED_DIRECTIVES_REGEX) "$$INI_SCANNED_PATH"/*.ini >> $(top_builddir)/tmp-php.ini; \ fi; \ TEST_PHP_EXECUTABLE=$(PHP_EXECUTABLE) \ TEST_PHP_SRCDIR=$(top_srcdir) \ CC="$(CC)" \ $(PHP_EXECUTABLE) -n -c $(top_builddir)/tmp-php.ini $(PHP_TEST_SETTINGS) $(top_srcdir)/run-tests.php -n -c $(top_builddir)/tmp-php.ini -d extension_dir=$(top_builddir)/modules/ $(PHP_TEST_SHARED_EXTENSIONS) $(TESTS); \ else \ echo "ERROR: Cannot run tests without CLI sapi."; \ fi
A little bit of tinkering and I was able to determine that the test script was running:
/usr/bin/php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d open_basedir= -d output_buffering=0 -d memory_limit=-1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d extension_dir=/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules/ -d extension=apd.so
I wasn’t quite sure where to begin with that, so I searched for the error message PHP Warning: PHP Startup: Invalid library (maybe not a PHP library) ‘apd.so’ in Unknown on line 0 which rendered Re: Problems Compiling (lots of) extensions with
php 5.1-beta3 – msg#00192 which suggested the problem was that APD was a Zend extension not a normal extension:
Aren’t tzhose Zend Extensions? So you would need to load them with
zend_extension = [full path] instead of extension = [filename].
I remembered way back in the original installation instructions something about configuring zend_extension… so I edited /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini and added the following:
zend_extension = /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/modules/apd.so apd.dumpdir = /build/trace apd.statement_tracing = 0
Since I was using the zend_extension I edited the command line to remove all references to “extension” arguments:
/usr/bin/php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d open_basedir= -d output_buffering=0 -d memory_limit=-1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# /usr/bin/php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d open_basedir= -d output_buffering=0 -d memory_limit=-1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini ERROR: environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!
So I set that variable:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# TEST_PHP_EXECUTABLE=/usr/bin/php root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# /usr/bin/php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d open_basedir= -d output_buffering=0 -d memory_limit=-1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini ERROR: environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable! root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# export TEST_PHP_EXECUTABLE root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# /usr/bin/php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d open_basedir= -d output_buffering=0 -d memory_limit=-1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini ===================================================================== PHP : /usr/bin/php PHP_SAPI : cli PHP_VERSION : 5.3.2-1ubuntu4.11 ZEND_VERSION: 2.3.0 PHP_OS : Linux - Linux sixsigma.blackbrick.com 2.6.33.5-rscloud #2 SMP Thu Jun 10 15:26:23 UTC 2010 x86_64 INI actual : /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini More .INIs : CWD : /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 Extra dirs : VALGRIND : Not used ===================================================================== TIME START 2012-01-10 04:43:34 ===================================================================== No tests were run.
Still no tests running. I had a read, a nice long read, of the /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php file. It seems to load an run *.phpt files. So I searched for pecl apd phpt files and found Patching a bug in a pecl extension which describes the *.phpt file format. So I created a test.phpt file:
--TEST-- Just testing. --FILE-- <?php apd_set_pprof_trace(); function a() { echo "a"; } function b() { a(); echo "b"; } a(); b(); a(); --EXPECT-- aaba
I ran the run-tests.php script again and checked the /build/trace directory for messages from APD, but there was nothing there. The tests hadn’t run.
I couldn’t be bothered figuring out the correct syntax for run-tests.php so I edited the file and changed line 824 from:
$test_dirs = array();
To:
$test_dirs = array( '.' );
Then I ran the tests again:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# /usr/bin/php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini -d open_basedir= -d output_buffering=0 -d memory_limit=-1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/run-tests.php -n -c /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini ===================================================================== PHP : /usr/bin/php PHP_SAPI : cli PHP_VERSION : 5.3.2-1ubuntu4.11 ZEND_VERSION: 2.3.0 PHP_OS : Linux - Linux sixsigma.blackbrick.com 2.6.33.5-rscloud #2 SMP Thu Jun 10 15:26:23 UTC 2010 x86_64 INI actual : /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/tmp-php.ini More .INIs : CWD : /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1 Extra dirs : VALGRIND : Not used ===================================================================== TIME START 2012-01-10 05:05:06 ===================================================================== PASS Just testing. [test.phpt] ===================================================================== TIME END 2012-01-10 05:05:06 ===================================================================== TEST RESULT SUMMARY --------------------------------------------------------------------- Exts skipped : 0 Exts tested : 45 --------------------------------------------------------------------- Number of tests : 1 1 Tests skipped : 0 ( 0.0%) -------- Tests warned : 0 ( 0.0%) ( 0.0%) Tests failed : 0 ( 0.0%) ( 0.0%) Expected fail : 0 ( 0.0%) ( 0.0%) Tests passed : 1 (100.0%) (100.0%) --------------------------------------------------------------------- Time taken : 0 seconds ===================================================================== We would like to send this report automatically to the PHP QA team, to give us a better understanding of how the test cases are doing. If you don't want to send it immediately, you can choose "s" to save the report to a file that you can send us later. Do you want to send this report now? [Yns]: n
And they ran!
I checked the /build/trace directory, and there was a file there! The trace had worked!
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# cd /build/trace root@sixsigma:/build/trace# ls pprof.15345.0 root@sixsigma:/build/trace# head pprof.15345.0 #Pprof [APD] v1.0.1 caller=/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/test.php END_HEADER ! 1 /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/test.php & 1 main 2 + 1 1 2 & 2 apd_set_pprof_trace 2 + 2 1 2 @ 0 2 0 0 489
It took me a little while to find it, but eventually I found the pprofp script in the file /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/pprofp. So I ran it:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ./pprofp -r /build/trace/pprof.15345.0 bash: ./pprofp: /usr/local/bin/php: bad interpreter: No such file or directory
I needed to fix the registered interpreter. I changed it to /usr/bin/php.
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ./pprofp -r /build/trace/pprof.15345.0 PHP: syntax error, unexpected '=' in Unknown on line 7 Trace for /build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1/test.php Total Elapsed Time = 0.00 Total System Time = 0.00 Total User Time = 0.00 Real User System secs/ cumm %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name -------------------------------------------------------------------------------------- 84.9 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0005 0.0005 0 apd_set_pprof_trace 12.8 0.00 0.00 0.00 0.00 0.00 0.00 3 0.0000 0.0000 0 a 1.4 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0000 0.0000 0 b 0.9 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0000 0.0006 0 main
It works!
So then all I had to do was configure my application under development to run apd, which I did. Then I ran the report on the trace file it generated:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ./pprofp -r /build/trace/pprof.15650.1 PHP: syntax error, unexpected '=' in Unknown on line 7 Trace for /home/jj5/proj/aman/src/web/aman/config.php Total Elapsed Time = 2.62 Total System Time = 0.37 Total User Time = 1.23 Real User System secs/ cumm %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name -------------------------------------------------------------------------------------- 36.2 0.95 0.95 0.03 0.03 0.00 0.00 2 0.4737 0.4773 0 ob_end_flush 15.0 0.39 0.39 0.21 0.21 0.07 0.07 52388 0.0000 0.0000 0 sgen_word_xor 9.3 0.24 0.24 0.21 0.21 0.02 0.02 33504 0.0000 0.0000 0 sgen_word_add 6.0 0.16 0.16 0.18 0.18 0.06 0.06 16756 0.0000 0.0000 0 sgen_word_a 4.5 0.12 0.12 0.04 0.04 0.02 0.02 16756 0.0000 0.0000 0 sgen_word_b 4.3 0.11 0.11 0.10 0.10 0.01 0.01 16756 0.0000 0.0000 0 sgen_word_c 4.3 0.11 0.11 0.11 0.11 0.05 0.05 16756 0.0000 0.0000 0 sgen_word_d 3.4 0.09 0.09 0.07 0.07 0.04 0.04 34 0.0026 0.0026 0 mysqli->query 3.2 0.08 1.20 0.10 0.90 0.04 0.27 16752 0.0000 0.0001 0 SgenBlowfishCipher->do_round 2.2 0.06 0.06 0.07 0.07 0.00 0.00 175 0.0003 0.0003 0 dirname 1.3 0.04 0.04 0.03 0.03 0.00 0.00 4477 0.0000 0.0000 0 substr 1.1 0.03 0.03 0.03 0.03 0.01 0.01 4168 0.0000 0.0000 0 hexdec
And ob_end_flush had a massive 36% of the processing time! Not sure what to do, I tried changing my php.ini file setting output_buffering to 200,000:
#output_buffering = 4096 output_buffering = 200000
Then I ran my code again and examined the next trace:
root@sixsigma:/build/buildd/php5-5.3.2/pear-build-download/apd-1.0.1# ./pprofp -r /build/trace/pprof.15948.0 PHP: syntax error, unexpected '=' in Unknown on line 7 Trace for /home/jj5/proj/aman/src/web/aman/config.php Total Elapsed Time = 2.01 Total System Time = 0.57 Total User Time = 1.37 Real User System secs/ cumm %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name -------------------------------------------------------------------------------------- 20.8 0.42 0.42 0.30 0.30 0.07 0.07 52388 0.0000 0.0000 0 sgen_word_xor 14.7 0.30 0.30 0.22 0.22 0.07 0.07 33504 0.0000 0.0000 0 sgen_word_add 9.2 0.18 0.18 0.15 0.15 0.05 0.05 16756 0.0000 0.0000 0 sgen_word_a 6.9 0.14 0.14 0.10 0.10 0.04 0.04 16756 0.0000 0.0000 0 sgen_word_c 6.5 0.13 0.13 0.07 0.07 0.03 0.03 16756 0.0000 0.0000 0 sgen_word_b 6.3 0.13 0.13 0.10 0.10 0.04 0.04 16756 0.0000 0.0000 0 sgen_word_d 4.6 0.09 0.09 0.04 0.04 0.05 0.05 175 0.0005 0.0005 0 dirname 4.4 0.09 1.35 0.07 0.98 0.07 0.36 16752 0.0000 0.0001 0 SgenBlowfishCipher->do_round 3.5 0.07 0.07 0.03 0.03 0.02 0.02 2 0.0348 0.0348 0 mysqli_connect 2.8 0.06 0.06 0.03 0.03 0.01 0.01 819 0.0001 0.0001 0 preg_replace 1.7 0.03 0.03 0.01 0.01 0.01 0.01 4477 0.0000 0.0000 0 substr 1.6 0.03 0.03 0.02 0.02 0.01 0.01 139 0.0002 0.0002 0 gettype 1.4 0.03 0.03 0.01 0.01 0.01 0.01 4168 0.0000 0.0000 0 hexdec 1.3 0.03 0.03 0.05 0.05 0.02 0.02 34 0.0008 0.0008 0 mysqli->query 1.1 0.02 0.03 0.01 0.01 0.01 0.01 2 0.0114 0.0153 0 ob_end_flush
So that configuration change seemed to have fixed that problem! Or maybe it was just an aberration?
In any event, I’ve found the reason for my sluggish site. It’s because I’ve been lazy and haven’t refactored pccipher yet. When I was doing the development work it was easiest to write the algorithm once and then define an interface for both the 32-bit and 64-bit versions of the code to implement. This meant that I had to do my math with functions rather than with operators, which is slooooow. Anyway, I knew that. I guess now that I can’t hide from it I’ll have to get around to fixing up that implementation and improving its performance.
I’m glad that was easy…
What is the size of an IP packet?
I searched for what is the size of an ip packet? and it turned up that the maximum IP packet length is 65535 bytes. I’ll have to do more reading to learn about what size packets are commonly used and supported.
Inline Small CSS
Page Speed is telling me to Inline Small CSS. I knew it!
Page Speed – Browser Caching
Page Speed is telling me to leverage browser caching.
Apache Caching Guide
Reading the Apache Caching Guide is on my list of things to do.
Closure Compiler
Been checking out the source code for closure-compiler. It’s a JavaScript compiler written in Java.
Compressing JavaScript in PHP (no comments or whitespace)
Note: if you’re a web developer you might be interested in registering to become a ProgClub member. ProgClub is a free international club for computer programmers and we run some mailing lists you might like to hang out on to chat about software development, life, etc.
Given that I’ve been working on compressing CSS and compressing HTML in PHP, it’s only natural that I’m interested in JavaScript compression too. I haven’t done much research on the topic — I’m sure there are better tools out there than the one I’ve cobbled together — but for the sake of it here’s my first take on JavaScript compression in PHP:
function slib_compress_script( $buffer ) { // JavaScript compressor by John Elliot <jj5@jj5.net> $replace = array( '#\'([^\n\']*?)/\*([^\n\']*)\'#' => "'\1/'+\'\'+'*\2'", // remove comments from ' strings '#\"([^\n\"]*?)/\*([^\n\"]*)\"#' => '"\1/"+\'\'+"*\2"', // remove comments from " strings '#/\*.*?\*/#s' => "", // strip C style comments '#[\r\n]+#' => "\n", // remove blank lines and \r's '#\n([ \t]*//.*?\n)*#s' => "\n", // strip line comments (whole line only) '#([^\\])//([^\'"\n]*)\n#s' => "\\1\n", // strip line comments // (that aren't possibly in strings or regex's) '#\n\s+#' => "\n", // strip excess whitespace '#\s+\n#' => "\n", // strip excess whitespace '#(//[^\n]*\n)#s' => "\\1\n", // extra line feed after any comments left // (important given later replacements) '#/([\'"])\+\'\'\+([\'"])\*#' => "/*" // restore comments in strings ); $search = array_keys( $replace ); $script = preg_replace( $search, $replace, $buffer ); $replace = array( "&&\n" => "&&", "||\n" => "||", "(\n" => "(", ")\n" => ")", "[\n" => "[", "]\n" => "]", "+\n" => "+", ",\n" => ",", "?\n" => "?", ":\n" => ":", ";\n" => ";", "{\n" => "{", // "}\n" => "}", (because I forget to put semicolons after function assignments) "\n]" => "]", "\n)" => ")", "\n}" => "}", "\n\n" => "\n" ); $search = array_keys( $replace ); $script = str_replace( $search, $replace, $script ); return trim( $script ); }
It’s funny, but jQuery actually choked on my original function because it contains a few strings like “*/*”. To fix the problem I had to patch jQuery with “*/”+”*”, but then I decided to handle that case in my code. Of course jQuery comes pre-minified by tools much more sophisticated than mine. My tool compresses the 230 KB jQuery file to 150 KB, whereas the tool jQuery uses compresses the file to 90 KB. So I think I have my work cut out for me! It was a fun hack though.
Compressing HTML in PHP (no comments or whitespace)
Note: if you’re a web developer you might be interested in registering to become a ProgClub member. ProgClub is a free international club for computer programmers and we run some mailing lists you might like to hang out on to chat about software development, life, etc.
In addition to compressing CSS in PHP I’ve been compressing HTML. My HTML compressor is a bit of a hack. It doesn’t handle CDATA sections for instance. But it should generally work OK. Here it is:
function slib_compress_html( $buffer ) { $replace = array( "#<!--.*?-->#s" => "", // strip comments "#>\s+<#" => ">\n<", // strip excess whitespace "#\n\s+<#" => "\n<" // strip excess whitespace ); $search = array_keys( $replace ); $html = preg_replace( $search, $replace, $buffer ); return trim( $html ); }
I use this function to compress HTML generated by my PHP scripts by putting ob_start( ‘slib_compress_html’ ) at the beginning of my script (after the ob_gzhandler) and ob_end_flush() at the end. My HTML compression code looks like this:
if ( extension_loaded( 'zlib' ) ) { ob_start( 'ob_gzhandler' ); } ob_start( 'slib_compress_html' ); run_app( $app_factory ); ob_end_flush(); if ( extension_loaded( 'zlib' ) ) { ob_end_flush(); }
Compressing CSS in PHP (no comments or whitespace)
Note: if you’re a web developer you might be interested in registering to become a ProgClub member. ProgClub is a free international club for computer programmers and we run some mailing lists you might like to hang out on to chat about software development, life, etc.
I was searching for methods to remove comments and whitespace from CSS files in PHP and I found this article (3 ways to compress CSS files using PHP).
The article suggests this code by Reinhold Weber, which I thought was a pretty good place to start:
<?php header('Content-type: text/css'); ob_start("compress"); function compress($buffer) { /* remove comments */ $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer); /* remove tabs, spaces, newlines, etc. */ $buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer); return $buffer; } /* your css files */ include('master.css'); include('typography.css'); include('grid.css'); include('print.css'); include('handheld.css'); ob_end_flush(); ?>
Later I found css_strip_whitespace by nyctimus in the documentation for the PHP method strip_whitespace. It looks like this:
function css_strip_whitespace($css) { $replace = array( "#/\*.*?\*/#s" => "", // Strip C style comments. "#\s\s+#" => " ", // Strip excess whitespace. ); $search = array_keys($replace); $css = preg_replace($search, $replace, $css); $replace = array( ": " => ":", "; " => ";", " {" => "{", " }" => "}", ", " => ",", "{ " => "{", ";}" => "}", // Strip optional semicolons. ",\n" => ",", // Don't wrap multiple selectors. "\n}" => "}", // Don't wrap closing braces. "} " => "}\n", // Put each rule on it's own line. ); $search = array_keys($replace); $css = str_replace($search, $replace, $css); return trim($css); }
The latter function is the one that I used, and I’m quite happy with it. I’ve been working on HTML and JavaScript compressors too, and those are much more difficult file formats to deal with than CSS.