Posts Tagged ‘PHP’

Generating an execution trace for a PHP script with Dtrace

August 12th, 2010

Here is a small Dtrace script I used to generate the execution trace of a PHP script running in a terminal :
(executiontrace.d)

#! /usr/bin/dtrace -s
#pragma D option quiet
#pragma D option switchrate=10

BEGIN
{
    printf("TRACE START [%Y]\n", walltimestamp);
    self->depth      = 0;
    self->time_last  = 0;
}

/**
 * program begins, so {main}
 */
php*:::function-entry
/copyinstr(arg0) == ""/
{
    printf(
        "%d\t -> {main}() %s:%d\n",
        /* well, just zero :-)  */
        0,
        /* source file, you can use basename(copyinstr(arg1)) if needed */
        copyinstr(arg1),
        /* line number*/
        arg2
    );

    self->time_last = timestamp;
}

/**
 * start any other function that is not {main}
 */
php*:::function-entry
/copyinstr(arg0) != ""/
{
    self->depth += 2;

    printf(
        /* string format */
        "%d\t %*s %s%s%s() %s:%d\n",
        /* time delta (microseconds)*/
        (timestamp - self->time_last) / 1000,
        /* indentation   */
        self->depth, "->",
        /* class name, if available */
        copyinstr(arg3),
        /* scope operator, if available */
        copyinstr(arg4),
        /* function name, always available */
        copyinstr(arg0),
        /* source file, you can use basename(copyinstr(arg1)) if needed */
        copyinstr(arg1),
        /* line number*/
        arg2
    );

    self->time_last = timestamp;
}

/**
 * end of any other function that is not {main}
 */
php*:::function-return
/copyinstr(arg0) != ""/
{
    self->depth -= 2;
}

END
{
    self->depth = 0;
    printf("TRACE END [%Y]", walltimestamp);
}

It looks like an Xdebug trace (without the memory usage / delta) but since Dtrace and Xdebug do not operate at the same level the results are quite different.

If you want to test this script you can use for example the following (nestedfunctions.php) :

<?php
function parent()
{
 new DirectoryIterator( __DIR__ );
 child();
}
function child()
{
 sleep( 1 );
}
function launch()
{
 parent( );
}
function foo(){}
launch(  );
foo();
sleep( 2 );
foo();
launch();
foo();
?>

And by running the following command :

sudo dtrace -s executiontrace.d -c "php nestedfunctions.php"

You should get a result like this (do not forget to hit <Ctrl-c> in order to exit from Dtrace).

TRACE START [2010 Aug 12 10:44:27]
0     -> {main}() [...]/testnestedfunctions.php:0
669     -> launch() [...]/testnestedfunctions.php:21
24       -> parent() [...]/testnestedfunctions.php:16
37         -> DirectoryIterator::__construct() [...]/testnestedfunctions.php:5
286         -> child() [...]/testnestedfunctions.php:6
21           -> sleep() [...]/testnestedfunctions.php:11
1000158     -> foo() [...]/testnestedfunctions.php:22
32     -> sleep() [...]/testnestedfunctions.php:23
2000097     -> foo() [...]/testnestedfunctions.php:24
32     -> launch() [...]/testnestedfunctions.php:25
21       -> parent() [...]/testnestedfunctions.php:16
32         -> DirectoryIterator::__construct() [...]/testnestedfunctions.php:5
141         -> child() [...]/testnestedfunctions.php:6
20           -> sleep() [...]/testnestedfunctions.php:11
1000111     -> foo() [...]/testnestedfunctions.php:26
^C
TRACE END [2010 Aug 12 10:44:34]

I tried to add as much comments as possible in order to make the script clearer.

Please note that if you run this script on production you will get a lot of output because the script does not filter on any pid so Dtrace will aggregate results across multilple Apache processes. It is up to you to use the correct predicate to filter on the PID you want in order to limit the result set.

Hope that helps :)

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Finding syscalls generated by PHP functions with Dtrace

August 4th, 2010

I wanted to check a list of syscalls that are generated by PHP for a bunch of functions. Dtrace saved the day again, in 10 minutes I had all I needed.

Here is a PHP script you can use for testing (syscalls.php) :

<?php
file_exists( __FILE__ );
file_get_contents( __FILE__ );
chdir( __DIR__ );
dir( __DIR__ );
getcwd();
opendir( __DIR__ );
scandir( __DIR__ );
new DirectoryIterator( __DIR__ );
stat( __DIR__ );
is_readable( __DIR__ );
is_writable( __DIR__ );
file_put_contents('/tmp/foo.txt', 'foo');
?>

And the small Dtrace (syscalls.d) script I used:#!/usr/sbin/dtrace -s

#pragma D option quiet

php*:::function-entry
/pid == $target && arg0/
{
 printf( "%s%s%s\n", copyinstr(arg3), copyinstr(arg4), copyinstr(arg0) );
 self->follow++;
}

syscall:::entry
/self->follow > 0/
{
 printf("  ->%s\n", probefunc);
}

php*:::function-return
/pid == $target && arg0/
{
 self->follow -= self->follow == 0 ? 0 : 1;
 printf("\n");
}

You can test the script by running :

sudo dtrace -s syscalls.d -c "php syscalls.php"

And you should get a list like this (at least on Mac Os X)

file_exists
 ->access

file_get_contents
 ->lstat
 ->lstat
 ->open
 ->fstat
 ->lseek
 ->fstat
 ->read
 ->read
 ->read
 ->close

chdir
 ->chdir

dir
 ->open_nocancel
 ->fcntl_nocancel
 ->__sysctl
 ->fstatfs

getcwd
 ->open_nocancel
 ->fstat64
 ->fcntl_nocancel
 ->close_nocancel
 ->stat64

opendir
 ->open_nocancel
 ->fcntl_nocancel
 ->fstatfs
 ->close_nocancel

scandir
 ->open_nocancel
 ->fcntl_nocancel
 ->fstatfs
 ->getdirentries
 ->getdirentries
 ->close_nocancel

DirectoryIterator::__construct
 ->open_nocancel
 ->fcntl_nocancel
 ->fstatfs
 ->getdirentries

 ->close_nocancel
stat
 ->stat

is_readable
 ->access

is_writable
 ->access

file_put_contents
 ->lstat
 ->lstat
 ->readlink
 ->lstat
 ->lstat
 ->open
 ->fstat
 ->lseek
 ->write
 ->close

If I have time I’ll post more Dtrace scripts useful for analysing what PHP does.

‘Hope that helps :)

Edit :

I fixed a small bug for the DirectoryOperator class.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Avoiding warnings about autoconf 2.13 when building PHP

June 9th, 2010

If you want to build PHP from the SVN repository, you have to run buildconf [--force].

But depending on the version of autoconf you have on your machine you can get the very annoying warning message :

[...]
buildconf: Your version of autoconf likely contains buggy cache code.
Running vcsclean for you.
To avoid this, install autoconf-2.13.
[...]

If you do not have autoconf 2.13 installed, then you have to install it first.

On RedHat running sudo yum install autoconf213 should work. On Debian, the autoconf2.13 package is available.

Once autoconf2.13 install, you can instruct buildconf to use this new version of autoconf by runing :

export PHP_AUTOCONF=`which autoconf-2.13`

You can check the value is correct by running :

echo $PHP_AUTOCONF

Which should give you something like (depending on your system)

/usr/bin/autoconf-2.13

Now retry to run ./buildconf –force. The annoying message is gone, joy :)

‘Hope that helps.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Fetching headers sent by PHP from the command line

March 25th, 2010

I needed a way to unit test some code that sends HTTP headers via the header function.

However when doing this from the command line :

php -r "header('Foo : Bar'); print_r(headers_list());"

The only result you get is an empty array, which makes sense of course but for unit testing from the command line that is annoying.

XDebug saves the day again by providing the xdebug_get_headers function.

Let’s try the same code, but with XDebug this time :

php -r "header('Foo:Bar'); print_r(xdebug_get_headers());"

Returns

Array
(
 [0] => Foo:Bar
)

Joy :)

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Backporting ReflectionMethod::setAccessible in PHP 5.3.1

December 9th, 2009

I needed the ReflectionMethod::setAccessible method for one of my script.

But after reading the CHANGELOG I realized that it is available for PHP 5.3.2 only.

Since PHP 5.3.2 is not released yet I was blocked :/ So I decided to add ReflectionMethod::setAccessible in my version of PHP so I can use it in my scripts.

The backport is available here : reflection.diff.gz

You can install it by following the method below:

1. download the patch above

2. download the PHP 5.3.1 tarball and extract it

3. apply the patch :

patch -p0 --verbose < ./reflection.diff

4. run the standard ./configure [...] && make && make test && sudo make install commands.

Alternatively, if you only want to test the Reflection extension you can do the following, after running “make” :

export TEST_PHP_EXECUTABLE="./sapi/cli/php" && php ./run-tests.php ext/reflection/tests

or

export TEST_PHP_EXECUTABLE="./sapi/cli/php" && php ./run-tests.php ext/reflection/tests/ReflectionMethod_setAccessible.phpt

But in any case, you should get :

==========================================
Number of tests :  267               267
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    :  267 (100.0%) (100.0%)
------------------------------------------
Time taken      :    9 seconds
==========================================

All Reflection tests must pass.

‘Hope that helps

:)

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Back from the PHP conference in Paris

November 14th, 2009

Thanks to my friend Arnaud I have been able to come to Paris in order to attend the last day of the PHP conference.

That was great and the talks were interesting.

I had a interesting discussion with Johannes Schlüter about DTrace (I was happy to meet another Dtrace addict :) ) and he gave me the solution to run Skype on Open Solaris so I’ll test it and if that works then I’ll switch to Open Solaris fully and get rid of Mac OS X.

We also had an interesting dicussion on PHP6, and it seems we have the same concers.

I also met a lot of people in the community I had not met for a while: Julien, Jean-Marc, Perrick, Damien (sorry I did not test the Snickers pie yet), FreshDaz, Cyril… I was really happy to meet you all.

I also had the chance (and the honnor) to discuss with Monty along with my colleague Patrick. And I have to say that he really opened my mind to something I was secretely looking for.

Thanks a lot to all the team in charge of the organisation, I am sure you sweated a lot, but that was really worth it.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Displaying the byte sequence of a string in PHP

August 26th, 2009

Since I am never able to remember this, I decided to write it down here.

The code is the following :

function showByteSequence( $string )
{
 for ( $i = 0; $i < strlen( $string ); $i++ )
 {
 echo '0x', dechex( ord( $string[ $i ] ) ), ' ';
 }

 echo "\n";
}

For example writing

showByteSequence( 'foo-bar' );

should display

0x66 0x6f 0x6f 0x2d 0x62 0x61 0x72
Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Compiling PHP 5.3 on Mac OS X

July 18th, 2009

A few people find it hard to compile PHP on Mac OS X and prefer using tools like Mamp or MacPorts.

Even though MacPorts is useful I prefer compiling PHP by myself, here is a step by step tutorial.

Note 1: this tutorial has been written for Mac OS X 10.4 but I am sure it is the same for more recent versions.

Note 2 : with the configuration directives described below PHP is compiled in CGI/FastCGI mode if you want to use it as an Apache module this only thing you have is to do is to use the following extra argument :

--with-apxs2=/path/to/apache2/apxs

1. Downloading PHP 5.3

wget http://fr3.php.net/get/php-5.3.0.tar.gz/from/fr.php.net/mirror

2. Extracting the tarball

tar zxvf php-5.3.0.tar.gz

3. Configuring PHP


cd php-5.3.0

./configure \
–prefix=/opt/php5 \
–enable-exif \
–with-gd=/opt/local \
–with-freetype-dir=/opt/local \
–with-jpeg-dir=/opt/local \
–enable-gd-native-ttf \
–with-png-dir=/opt/local \
–with-t1lib=/opt/local \
–with-zlib=/opt/local \
–with-mysql=/usr/local/mysql \
–with-mysqli \
–with-ldap \
–enable-mbstring \
–with-mcrypt=/opt/local \
–with-bz2=/usr/bin \
–enable-ctype \
–enable-dom \
–enable-libxml \
–with-iconv \
–enable-pdo \
–with-pdo-sqlite \
–enable-posix \
–enable-simplexml \
–enable-xml \
–with-zlib \
–with-curl \
–enable-filter \
–with-pdo-mysql=/usr/local/mysql \
–with-openssl \
–with-xmlrpc \
–with-xsl \
–enable-soap \
–enable-ftp \
–enable-pcntl \
–enable-shmop

4. Compiling and installing

make && sudo make install

You can go to the kitchen and get a tea or a coffe while it is compiling.

If you do not like tea or coffee you can also try other fun activities like the following :

Source : http://xkcd.com/303/

Back from the kitchen, you are done. PHP 5.3 is now compiled and installed on your machine.

You can of course use a few extra CFLAGS or options to the configure script if you want to, but the most basic steps are here and you now know the required steps

Now a small tip, let us say I want to compile with the --with-mysql=/path/to/wrong/mysql/directory argument but unfortunately the configure script fails with such an error message :

configure: error: Cannot find MySQL header files under /path/to/wrong/directory.
Note that the MySQL client library is not bundled anymore!

How to find the correct path and fix the problem ?

1. I know that the mysql extension is available in the ext/mysql directory

2. the configuration related to this module is in config.m4

By opening ext/mysql/config.m4 I discover (line 77) that the mysql.h header is required and it is searched in the following directories (still on line 77) :

- /usr/local

- /usr/

The only thing I have to do is searching for mysql.h. Since I use the official MySQL binary I know it is installed in /usr/local/mysql/ so if I look in /usr/local/mysql/include/ I find the required mysql.h file. The config.m4 file searches for /include/mysql.h (line 81) so the only thing I have to do is to correct my –with-mysql argument and use --with-mysql=/usr/local/mysql. By relaunching the configure script it worked and we have been able to compile PHP with MySQL successfully :)

Since you now have compiled PHP by yourself the only limit for you now is your imagination :)

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)