How to Solve “No input file specified” with PHP and Nginx
“No input file specified” or “Primary script unknown” in the error log is one of the most frequently encountered issues in nginx+PHP.
People on serverfault and in the #nginx IRC channel asks for help with this so often that this post is mostly to allow me to be lazy and not have to type up the same answer every time.
This is actually an error from PHP and due to display_errors being 0ff people will often just get a blank page with no output. In a typical setup PHP will then send the error to stderr or stdout and nginx will pick up on it and log it in the nginx error log file. Thus people spend a ton of time trying to figure out why nginx isn’t working.
The root cause of the error is that PHP cannot find the file nginx is telling it to look for, and there are a few common cases that causes this.
Wrong Path Sent to PHP
The most common reason at the time of writing happens because a user uses a horrible tutorial found via google instead of actually understanding nginx. Reading my nginx primer will equip you to actually solve this on your own but since this post is actually dedicated to the error I’ll cheat this once and allow you to be lazy by just giving you the full solution.
Nginx tells PHP about the file to execute via the SCRIPT_FILENAME fastcgi_param value. Most examples in the wiki should define this as $document_root$fastcgi_script_name. The horrible tutorials will often hard code the path value but this is not desirable as we don’t want to duplicate information and invite future screw ups. So you’ve gone with the $document_root$fastcgi_script_name option and suddenly it’s no longer working.
This happens because nginx has 3 levels of inheritance commonly referred to as blocks, these being http, server and location, each being a sub-block of the parent. Directives in nginx inherit downwards but never up or across, so if you define something in one location block it will never be applied in any other location block under any circumstance.
Typically users define their index and root directive in location / because a tutorial told them to. So when they then define SCRIPT_FILENAME using $document_root the root directive is not actually defined and thus the SCRIPT_FILENAME value becomes just the URI making PHP look at the root server dir.
The simple solution here is to just define the directive in your server block. (or http block even!) Generally the higher up your can define a directive the less duplicate directives you’ll need.
Incorrect File Permissions
Most people don’t really believe me when I tell them their file permissions are incorrect. They’re looking at the damn permissions and the PHP user can read the file just fine! Sadly, this shows a lack of understanding of Unix user permissions. Being able to read a file is not enough, a user must also be able to traverse to the file.
This effectively means that not only should the file have read permission, but the entire directory structure should have execute permission so that the PHP user can traverse the path. An example of this:
Say you have an index.php file in /var/www. /var/www/index.php must have read permission and both /var and /var/www must have execute permissions.
Using Alias and $document_root
It is fairly common to define SCRIPT_FILENAME as $document_root$fastcgi_script_filename; However, $document_root does not account for the alias directive and will thus result in an incorrect path being sent. It is preferable to define SCRIPT_FILENAME as such:
fastcgi_param SCRIPT_FILENAME $request_filename;
This accounts for alias and ensures proper path is sent. One note about this is that $request_filename does not account for fastcgi_index, but you only use this index if you send a request ending in / to PHP. If you use the standard PHP location ~ \.php$ then you will never use the fastcgi_index directive.
Chrooted Environment
If your PHP lives in a chrooted environment that nginx does not, then they basically have 2 different roots and the file path that nginx reports to PHP will not resolve to the actual file. A simple example to make this obvious:
Lets say you request phpinfo.php, nginx looks in your defined root and finds this file in: /home/user/public_html/phpinfo.php
The PHP process for user is chrooted to only have access to his directory for security reasons, so as far as PHP knows the root of the server is at /home/user. Therefore when nginx reports the file path PHP will look in: /home/user/home/user/public_html/phpinfo.php.
Either make sure both nginx and PHP has the same chroot or make sure you rewrite your internal URI before you fastcgi pass to PHP.
Open Basedir Restriction
PHP has the option to limit file access to certain directories defined in your php.ini. Some distributions might preconfigure this option for their packaging system.
SCRIPT_NAME Versus SCRIPT_FILENAME
Fastcgi has two parameters which are quite similiar in name, make sure that you’re not confusing the SCRIPT_NAME variable for the SCRIPT_FILENAME one. SCRIPT_FILENAME tells fastcgi the location of the script to execute while SCRIPT_NAME merely tells the name of the script.
How can I make my php.ini file recursive ?
. What this means is that they do not modify settings in any child folders (which are subdirectories of the current directory).
Still confused, here’s an example.
Let’s say you have a php.ini file in your public_html folder. That php.ini file has the PHP memory_limit set to 256M. Only scripts that run directly in your public_html folder will have the memory_limit set to 256M. If you have a folder named public_html/employees, that “employees” folder will not be affected by the public_html/php.ini file, it would only be affected by a php.ini file located in its own folder, public_html/employees
If you have many folders, creating a php.ini file for each folder would be quite tedious. What you can do is update your .htaccess file to tell the server that the public_html/php.ini file should apply not only to public_html, but to any folders within that folder (such as public_html/employees or public_html/about-us). This is the definition of making your php.ini file recursive.
Update your suPHP_ConfigPath in your .htaccess file
Making your php.ini file affect all child folders as well is referred to as making the file “recursive”. To make your public_html/php.ini file recursive, edit (or create the file if it doesn’t exist) your public_html/.htaccess file and add the following code:
This line you entered is specifying the directory where the php.ini is located that you want to make recursive. Be sure to replace username with your cPanel username.
This change is immediate, so you should see the update right away.
How to Test your changes
After saving the changes, be sure to create a phpinfo page in one of your subdirectories and test the results. When looking at your phpinfo page, the “Loaded Configuration File” should reflect the php.ini file that you wanted to make recursive.
Troubleshooting errors
Important! If you add the recursive path to your php.ini and you get an error like the following, it is because the PHP version is not being rendered correctly.
Fatal error: Uncaught exception 'Zend_Db_Adapter_Exception' with message 'The PDO extension is required for this adapter but the extension is not loaded' in /home/userna5/public_html/shop/engine/Library/Zend/Db/Adapter/Pdo/Abstract.php:342 Stack trace: #0 /home/userna5/public_html/shop/engine/Library/Zend/Db/Adapter/Abstract.php(247): Zend_Db_Adapter_Pdo_Abstract->setFetchMode(2) #1 /home/userna5/public_html/shop/engine/Library/Zend/Db.php(270): Zend_Db_Adapter_Abstract->__construct(Array) #2 /home/userna5/public_html/shop/engine/Library/Enlight/Components/Db.php(96): Zend_Db::factory('pdo_mysql', Array) #3 /home/userna5/public_html/shop/engine/Shopware/Bootstrap.php(154): Enlight_Components_Db::factory('pdo_mysql', Array) #4 [internal function]: Shopware_Bootstrap->initDb() #5 /home/userna5/public_html/shop/engine/Library/Enlight/Bootstrap.php(304): call_user_func(Array) #6 /home/userna5/public_html/shop/engine/Library/Enlight/Bootstrap.php(258): Enlight_Bootstrap->loadResource('Db') #7 /home/userna5/public_html/ in /home/userna5/public_html/shop/engine/Library/Zend/Db/Adapter/Pdo/Abstract.php on line 342
This is common with those who are using the PHP version switcher. To fix this error, check your .htaccess file in your home directory. Make sure the correct AddHandler is in the .htaccess and is not commented out. In the image to the right, the php 5.4 AddHandler is shown. If you are unable the fix this error please contact tech support and we can look at it for you.
Thoughts on “ How can I make my php.ini file recursive ? ”
If i did .htaccess in main directory, then i can copy same thing and change path and upload to sub directory. So second .htaccess can override first .htaccess. In second .htaccess, it make website use custom php.ini. Not the global php.ini from main directory. Please advise.
Yes, if you have a .htaccess file in a subfolder, you can override existing rules it is inheriting from the parent .htaccess file. Thank you,
John-Paul
If suPHP_ConfigPath already exists in the htaccess file in the public_html directory, can I add redirect code or an ErrorDocument line into the same htaccess file? I tried doing this using the Cpanel Redirect tool, but got an error. Maybe the suPHP_ConfigPath needs to be the last statement? Thanks in advance for any insights, Tessa
I would do likewise. Try re-ordering the code in the .htaccess manually. If that doesn’t work, you can always place a dedicated php.ini file in the directories they are required to affect. But I don’t expect you should have a problem.
hi, I received Internal Server Error message when I tried to add the code in my .htaccess file. What do you reckon is the problem? Thank.
Hello Tim, There are number of possible causes to this problem. Can you give us any specific information on the account? Also, exactly what code did you use? If we can look at the issue then we may be able to troubleshoot it. We also have an article that discusses Internal Server errors If you have any further questions or comments, please let us know. Regards,
Arnel C.
Hi christopherm, Thanks for the reply. My suPHP_ConfigPath is configured to the root(home/username/public_html), this is my where main site located. However, i have few directories set up for other website.
home/username/public_html/support – support.example.com (above is a support website, ticket system) home/username/public_html/forum – forum.example.com (above is a forum website) home/username/public_html/example2 – www.example2.com (above contains second website) Hence, i would like to to have different php setting for above directories. If i create three seperate php.ini where ‘suPUP_ConfigPath’ in each php is set to
-home/username/public_html/forum -home/username/public_html/support -home/username/public_html/example2 and put above php.ini(s) to the correspond directory, it will overwrite the php setting in home/username/public_htm The way I recommend is to make your php.ini file recursive and put a new php.ini file in the directories you want to exclude from the recursive path. My mains site is located at (home/username/public_htm/) and my other websites(where i want to have customized php setting) are located in the subdirectories. It is impossible to exclude these directories from the root.
Pardon me, I meant that the php.ini in the subdirectories should take priority over the recursive one.
Hi, Can i make php.ini recursive in selected directories?
For example
If suPHP_ConfigPath is configured to /home/username/public_html directory, can i create another customized php.ini in /home/username/public_html/manager to override the php value? (I still want /home/username/public_html/employee to use the php setting from the parent) I have tried to create a customized php.ini some choosen directories, however, they do not override the setting. In the phpinfo page, the “Loaded Configuration File” still point to /home/username/public_html/php.ini Doing following does the trick, but i am not sure whether it is a save/right thing to implement: 1)Create a htaccess file in the choosen directory(If file not exist). 2)Copy/Change the code to “suPHP_ConfigPath to /home/username/public_html/manager” in (1) Now, the phpinfo in will show the setting updated. Any correct/right way to make php.ini recursive in selected directories? Thank you.
The way I recommend is to make your php.ini file recursive and put a new php.ini file in the directories you want to exclude from the recursive path.
I dont know Jack about PHP, and your 2 tutorials have allowed me to configure parameters that not even Hostgator support could deal with! Huge Thank You!