Windows + Apache + PHP giving you random 403 errors? Avoid Symbolic Links!
This blog post is in English because I couldn't find the solution when Googling, and hope this shows up in the top results for this topic :)
In one of my latest consultancy projects, I was asked to measure, analyze and improve the performance and architecture of a PHP based web application. For various reasons, the application runs on a Windows Server, using PHP FastCGI in Apache.
The document root of the application was defined as
N:\TheApp, which was a Symbolic Link (a symlink, in Windows-speak) to a network share. All was running well, except when I started to increase the load in my JMeter test scripts. At random moments, I would get a
403 Access Denied error. When searching for the corresponding entry in the PHP error log at that time, there wasn't much, except this one line:
PHP Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0
This error normally indicates a permission error of some sort, but this wasn't the case, as this would occur randomly. When doing some more debugging, I even found it had nothing to do with server load. It seems to happen at random moments.
There was nothing else in the logs, nothing in the Event Viewer either, really strange. Google didn't help much, except for a small number of people running into the same issue. The only thing we all had in common besides Windows, was that we all did "something" with the filesystem: a symlink, a Union-mount-like thing or other filesystem trickery...
I decided to change the document root to bypass the symbolic by specifying the network UNC path as the document root in the Apache vhost config (
DocumentRoot //nfs-srv/path/to/docroot) and low and behold, three things happened.
Errors went away
The errors went away. From about 1% (over a sample of about 10000 JMeter requests) to 0.000000%. Gone. Never to reappear again. Ever.
The speed of the application (as measured by the JMeter test script) improved significantly! It seems that Windows requires an extra lookup when "resolving" the link and that this resolving takes some time.
Ugly side-effect: PHP exec() and co failed
However, as I was happy about the complete disappearance of any errors and the improved speed, I noticed certain parts of the application broke. When digging into the code, it appears those parts all invoked a command line command either using backticks or PHP's
exec() function calls.
The strange thing is that no errors were to be found. Even the (failing) exec() call returned true.
I quickly found PHP bug #71883 which explains what's happening. Short story: put an explicit
chdir("C:\") at the top of your application.
- Avoid Symbolic links and other filesystem "trickery" in a Windows/Apache/PHP setup
- UNC paths as the DocumentRoot works great and is faster
- Beware of PHP bug #71883 when using UNCs. Fix is a
chdir()before you use shell commands