PHP lstat the full path many times before read the file is looking for. And this happens when in apache httpd configuration is specified PHP_ADMIN_VALUE open_basedir setting or if safe_mode is ON.
If I have a simple website with only phpinfo.php page and inside we have only "".
Consider we have latest version of httpd (2.2.15) and PHP (5.2.13 or 5.3.2).
If we specify safe_mode=on or PHP_ADMIN_VALUE open_basedir in Virtual host configuration:
<Directory "/usr/local/myspace/webspace/httpdocs"> PHP_ADMIN_VALUE open_basedir "/usr/local/myspace/webspace" </Directory> <VirtualHost *:80> ServerName damorealt.xoom.it DocumentRoot "/usr/local/myspace/webspace/httpdocs" CustomLog /var/log/httpd/damorealt/access_log combined ErrorLog /var/log/httpd/damorealt/error_log </VirtualHost >
Calling page http://damorealt.xoom.it/phpinfo.php we can reproduce following behavior:
First check
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
Second check
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
Third check (incomplete)
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
Fifth check.
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
Read the file!
25933 open("/usr/local/myspace/webspace/httpdocs/phpinfo.php", O_RDONLY) = 16 25933 fstat(16, {st_mode=S_IFREG|0644, st_size=16, ...}) = 0 25933 read(16, "\n", 8192) = 16 25933 read(16, "", 8192) = 0 25933 read(16, "", 8192) = 0 25933 close(16) = 0
If PHP_ADMIN_VALUE open_basedir "/usr/local/myspace/webspace" is removed ::
First check
26235 time(NULL) = 1278696735 26235 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
Read the file.
26235 open("/usr/local/myspace/webspace/httpdocs/phpinfo.php", O_RDONLY) = 16 26235 fstat(16, {st_mode=S_IFREG|0644, st_size=16, ...}) = 0 26235 read(16, "\n", 8192) = 16 26235 read(16, "", 8192) = 0 26235 read(16, "", 8192) = 0 26235 close(16) = 0 26235 uname({sys="Linux", node="svilpar4", ...}) = 0 26235 time(NULL) = 1278696735 26235 writev(15, [{"HTTP/1.1 200 OK\r\nDate: Fri, 09 J"..., 173},[...] 26235 chdir("/") = 0
Can someone explain me why PHP have such behavior?
Realpath cache is disabled if safe_mode or open_basedir are set. This dramatically reduce performance of PHP Engine and this behavior can bring a server to its knees. Especially because there is a lack of documentation!
Looking at source code main/main.c of PHP engine 5.2.13 you can see:
Please refer to: http://bugs.php.net/bug.php?id=52312
a workaround solution is described here: https://github.com/Whissi/realpath_turbo
with that extension you can use realpatch cache with openbasedir enabled