I am trying to help a friend moving a web-site from one web-hotel to another.
The old place is already closed, I have only a flat tar file of what was in it.
The web site contained HTML docs and one could download a little Java application (to be loaded on mobile phone) to send data to the web site.
The mobile Java application sent a string to URL=<HOST>/php/register.php. This php script included another php script (../inc/db_login.php), which connected to a SQL DB using $link=mysql_connect(). Another file, register.php, did the SQL insert for putting the new sent data in the DB.
My question is basicaly, where I should put this 2 PHP files on the new website and what permissions the directories and files should have?
The old web server obviously had a /php and /inc directories. None of these exists on the new webserver. Should I create them? What permission should they have? I guess the reason for having the password in a separate PHP file was security. The /php and /inc directory probably had different permissions.
The new server has directories:
/httpdos
/httpsdos
/cgi-bin
/conf (and some others probably irrelevant)
My questions
Does the file-extension (.php) mean something to the server: as PHP scripts are "included" in HTML code (between <?...?>, does the server need to look at the file suffix or is it irrelevant? (I understand that the server reacts on the <?...?>, of course)
should the public file (register.php in my case) be placed in the httpdocs/ directory or does the server (apache I think) reacts on something and fetches it in another directory?
Should the PHP script have permission R-X (read and execute), --X (execute) or R-- (read)? From a OS perspective I guess apache is just reading this files, meaning that they should be R--, but this would mean that if PHP service is "stopped" the client would get all the PHP code in his browser(?). I would prefer it being --X but as this is neither a binary nor has a #!, I guess it must be --R?
If the public PHP script can be placed in another dir (e.g /php instead of /httpdocs) what should /php (and the script) have for permission?. I guess the server has to know about this /php directory (or are there usual defaults?)
The PHP script included (../inc/db_login.php, containing SQL password) should not be under /httpdocs I guess. This means that my register.php is including a file which is not under the /httpdocs subtree. Does this work? Does the server need to know?
I understand you may need to know the server configuration. Just assume the default in your answer (and you can tell where it is changed if it is).
Directories must have execute permissions to be usable. Usually this is 0755. PHP scripts run via mod_php are not executed but rather read; 0644 will suffice for this. Directories that must be written to need to be owned by the user the web server is running as. There may be additional concerns regarding permissions, e.g. SELinux, but the above will get you through the basics.
Documents that must not be accessed by other users or external clients should be 0600, owned by the web server user, and located outside the DocumentRoot. Note that running mod_php in Safe Mode will prevent scripts from ever including anything outside the DocumentRoot; a lamentable flaw.
Set php files to 640
For maximum security you should set minimum permissions, which
is 640.
The owner 6 would be the one uploading the files.
The group 4 would be the one serving the file. Make apache a group member.
The nobody 0 means no other users can read this file. It's important since php scripts sometimes have passwords and other sensitive data.
Never allow php scripts to be read by everyone.
Useful commands:
chmod 640 file.php
chown user:group file.php
usermod -a -G group apache
What these commands are doing:
Change ownership of file.php so user can read and write, group read.
Change ownership of file.php, to chosen user name and group name.
Add apache to the group, so that apache can serve the file. Otherwise 640 will not work.
1) Files that end with a .php extension are handed off to the PHP compiler by Apache. If the proper configuration is not set up to do so, PHP files get served up as text files by the server. The Apache configuration line "AddHandler php5-script php" in the httpd.conf file is the PHP5 method of setting this up.
2) register.php needs to be accessible at http://www.example.com/php/register.php, as the java app is looking for it, so in the Apache htdocs folder, there needs to be a "php" folder with the register.php file in it.
3) PHP files need read access by the user that's running the Apache service. Using PHP as an Apache module has no 'service' to speak of that's separate for PHP. Instead the Apache service, when it gets a request for a PHP file, makes a shell call to the PHP binary to parse the file and hand the Apache service the result, which it serves to the client. Only if you were using PHP from the command line (CLI setup) would the scripts need execute permission, and start with a #!/path/to/php-bin line.
4) The requested file (register.php) needs to be in htdocs in order to be served by Apache. If PHP is running with "Safe Mode" disabled, register.php could include a file that was outside the htdocs folder.
5) The path "../inc/db_login.php" is relative to the PHP script that was originally fetched (register.php), so, since register.php is in htdocs/php/register.php, that would put db_login.php at htdocs/inc/db_login.php.
I've coded a function to address the permissions issues in both of PHP / SuPHP and similar:
function realChmod($path, $chmod = null)
{
if (file_exists($path) === true)
{
if (is_null($chmod) === true)
{
$chmod = (is_file($path) === true) ? 644 : 755;
if (in_array(get_current_user(), array('apache', 'httpd', 'nobody', 'system', 'webdaemon', 'www', 'www-data')) === true)
{
$chmod += 22;
}
}
return chmod($path, octdec(intval($chmod)));
}
return false;
}
Maybe it's useful for you.
All the PHP files which are intended to be addressed directly via URLs can happily reside in the same directories as the static content (this is the usual practice).
It is good practice to have at least one directory outside those visible from the webserver to hold include files, but the PHP include path should still include '.'.
I'd recommend not putting lots of non-standard directories in your root filesystem - the default webroot varies by distribution, but I usually go with something like:
/var/www/htdocs - as the document root
/usr/local/php - for include files
Obviously if you intend running your webserver chrrot, these should be mapped accordingly.
All files must be readable by the uid under which the webserver runs, however if you can restrict what is writeable by this uid as much as possible then you close off a potential attack vector.
I usually go with setting up my dirs as drwxrwSr-x owned by a member of a webdev group with the group ownership as the webdev team, (the httpd uid is not in the webdev group) and files are therefore -rw-rw-r-- So anyone in the webdex group can change files, and the httpd uid can only read files.
1) does the files-extension (.php) means something to the server:
Yes - go read the PHP installation guide.
C.
Assuming your SFTP/FTP user is johndoe and web server group is www-data. johndoe only read, write the files but not execute the files (in my case never). The web server software usually Apache/Nginx from the group www-data can read/write/execute the files. Other users? what are they doing here???
So, I used to set 0670 (rw-rwx---) and works for me always :)
Set file permission to 0644 and folder permission to 0755.
I have coded a library for that.
Example of usage:
<?php
use MathiasReker\FilePerm;
require __DIR__ . '/vendor/autoload.php';
(new FilePerm([__DIR__])) // <-- root directory
->setDefaultModeFile(0644) // <-- file permission
->setDefaultModeFolder(0755) // <-- folder permission
->scan()
->fix();
Full documentation: https://github.com/MathiasReker/php-file-permissions
Related
In PHP scripts, whether calling include(), require(), fopen(), or their derivatives such as include_once, require_once, or even, move_uploaded_file(), one often runs into an error or warning:
Failed to open stream : No such file or directory.
What is a good process to quickly find the root cause of the problem?
There are many reasons why one might run into this error and thus a good checklist of what to check first helps considerably.
Let's consider that we are troubleshooting the following line:
require "/path/to/file"
Checklist
1. Check the file path for typos
either check manually (by visually checking the path)
or move whatever is called by require* or include* to its own variable, echo it, copy it, and try accessing it from a terminal:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Then, in a terminal:
cat <file path pasted>
2. Check that the file path is correct regarding relative vs absolute path considerations
if it is starting by a forward slash "/" then it is not referring to the root of your website's folder (the document root), but to the root of your server.
for example, your website's directory might be /users/tony/htdocs
if it is not starting by a forward slash then it is either relying on the include path (see below) or the path is relative. If it is relative, then PHP will calculate relatively to the path of the current working directory.
thus, not relative to the path of your web site's root, or to the file where you are typing
for that reason, always use absolute file paths
Best practices :
In order to make your script robust in case you move things around, while still generating an absolute path at runtime, you have 2 options :
use require __DIR__ . "/relative/path/from/current/file". The __DIR__ magic constant returns the directory of the current file.
define a SITE_ROOT constant yourself :
at the root of your web site's directory, create a file, e.g. config.php
in config.php, write
define('SITE_ROOT', __DIR__);
in every file where you want to reference the site root folder, include config.php, and then use the SITE_ROOT constant wherever you like :
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
These 2 practices also make your application more portable because it does not rely on ini settings like the include path.
3. Check your include path
Another way to include files, neither relatively nor purely absolutely, is to rely on the include path. This is often the case for libraries or frameworks such as the Zend framework.
Such an inclusion will look like this :
include "Zend/Mail/Protocol/Imap.php"
In that case, you will want to make sure that the folder where "Zend" is, is part of the include path.
You can check the include path with :
echo get_include_path();
You can add a folder to it with :
set_include_path(get_include_path().":"."/path/to/new/folder");
4. Check that your server has access to that file
It might be that all together, the user running the server process (Apache or PHP) simply doesn't have permission to read from or write to that file.
To check under what user the server is running you can use posix_getpwuid :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
To find out the permissions on the file, type the following command in the terminal:
ls -l <path/to/file>
and look at permission symbolic notation
5. Check PHP settings
If none of the above worked, then the issue is probably that some PHP settings forbid it to access that file.
Three settings could be relevant :
open_basedir
If this is set PHP won't be able to access any file outside of the specified directory (not even through a symbolic link).
However, the default behavior is for it not to be set in which case there is no restriction
This can be checked by either calling phpinfo() or by using ini_get("open_basedir")
You can change the setting either by editing your php.ini file or your httpd.conf file
safe mode
if this is turned on restrictions might apply. However, this has been removed in PHP 5.4. If you are still on a version that supports safe mode upgrade to a PHP version that is still being supported.
allow_url_fopen and allow_url_include
this applies only to including or opening files through a network process such as http:// not when trying to include files on the local file system
this can be checked with ini_get("allow_url_include") and set with ini_set("allow_url_include", "1")
Corner cases
If none of the above enabled to diagnose the problem, here are some special situations that could happen :
1. The inclusion of library relying on the include path
It can happen that you include a library, for example, the Zend framework, using a relative or absolute path. For example :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
But then you still get the same kind of error.
This could happen because the file that you have (successfully) included, has itself an include statement for another file, and that second include statement assumes that you have added the path of that library to the include path.
For example, the Zend framework file mentioned before could have the following include :
include "Zend/Mail/Protocol/Exception.php"
which is neither an inclusion by relative path, nor by absolute path. It is assuming that the Zend framework directory has been added to the include path.
In such a case, the only practical solution is to add the directory to your include path.
2. SELinux
If you are running Security-Enhanced Linux, then it might be the reason for the problem, by denying access to the file from the server.
To check whether SELinux is enabled on your system, run the sestatus command in a terminal. If the command does not exist, then SELinux is not on your system. If it does exist, then it should tell you whether it is enforced or not.
To check whether SELinux policies are the reason for the problem, you can try turning it off temporarily. However be CAREFUL, since this will disable protection entirely. Do not do this on your production server.
setenforce 0
If you no longer have the problem with SELinux turned off, then this is the root cause.
To solve it, you will have to configure SELinux accordingly.
The following context types will be necessary :
httpd_sys_content_t for files that you want your server to be able to read
httpd_sys_rw_content_t for files on which you want read and write access
httpd_log_t for log files
httpd_cache_t for the cache directory
For example, to assign the httpd_sys_content_t context type to your website root directory, run :
semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
If your file is in a home directory, you will also need to turn on the httpd_enable_homedirs boolean :
setsebool -P httpd_enable_homedirs 1
In any case, there could be a variety of reasons why SELinux would deny access to a file, depending on your policies. So you will need to enquire into that. Here is a tutorial specifically on configuring SELinux for a web server.
3. Symfony
If you are using Symfony, and experiencing this error when uploading to a server, then it can be that the app's cache hasn't been reset, either because app/cache has been uploaded, or that cache hasn't been cleared.
You can test and fix this by running the following console command:
cache:clear
4. Non ACSII characters inside Zip file
Apparently, this error can happen also upon calling zip->close() when some files inside the zip have non-ASCII characters in their filename, such as "é".
A potential solution is to wrap the file name in utf8_decode() before creating the target file.
Credits to Fran Cano for identifying and suggesting a solution to this issue
To add to the (really good) existing answer
Shared Hosting Software
open_basedir is one that can stump you because it can be specified in a web server configuration. While this is easily remedied if you run your own dedicated server, there are some shared hosting software packages out there (like Plesk, cPanel, etc) that will configure a configuration directive on a per-domain basis. Because the software builds the configuration file (i.e. httpd.conf) you cannot change that file directly because the hosting software will just overwrite it when it restarts.
With Plesk, they provide a place to override the provided httpd.conf called vhost.conf. Only the server admin can write this file. The configuration for Apache looks something like this
<Directory /var/www/vhosts/domain.com>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode off
php_admin_value open_basedir "/var/www/vhosts/domain.com:/tmp:/usr/share/pear:/local/PEAR"
</IfModule>
</Directory>
Have your server admin consult the manual for the hosting and web server software they use.
File Permissions
It's important to note that executing a file through your web server is very different from a command line or cron job execution. The big difference is that your web server has its own user and permissions. For security reasons that user is pretty restricted. Apache, for instance, is often apache, www-data or httpd (depending on your server). A cron job or CLI execution has whatever permissions that the user running it has (i.e. running a PHP script as root will execute with permissions of root).
A lot of times people will solve a permissions problem by doing the following (Linux example)
chmod 777 /path/to/file
This is not a smart idea, because the file or directory is now world writable. If you own the server and are the only user then this isn't such a big deal, but if you're on a shared hosting environment you've just given everyone on your server access.
What you need to do is determine the user(s) that need access and give only those them access. Once you know which users need access you'll want to make sure that
That user owns the file and possibly the parent directory (especially the parent directory if you want to write files). In most shared hosting environments this won't be an issue, because your user should own all the files underneath your root. A Linux example is shown below
chown apache:apache /path/to/file
The user, and only that user, has access. In Linux, a good practice would be chmod 600 (only owner can read and write) or chmod 644 (owner can write but everyone can read)
You can read a more extended discussion of Linux/Unix permissions and users here
Look at the exact error
My code worked fine on all machines but only on this one started giving problem (which used to work find I guess). Used echo "document_root" path to debug and also looked closely at the error, found this
Warning:
include(D:/MyProjects/testproject//functions/connections.php):
failed to open stream:
You can easily see where the problems are. The problems are // before functions
$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');
So simply remove the lading / from include and it should work fine. What is interesting is this behaviors is different on different versions. I run the same code on Laptop, Macbook Pro and this PC, all worked fine untill. Hope this helps someone.
Copy past the file location in the browser to make sure file exists. Sometimes files get deleted unexpectedly (happened with me) and it was also the issue in my case.
Samba Shares
If you have a Linux test server and you work from a Windows Client, the Samba share interferes with the chmod command. So, even if you use:
chmod -R 777 myfolder
on the Linux side it is fully possible that the Unix Group\www-data still doesn't have write access. One working solution if your share is set up that Windows admins are mapped to root: From Windows, open the Permissions, disable Inheritance for your folder with copy, and then grant full access for www-data.
Add script with query parameters
That was my case. It actually links to question #4485874, but I'm going to explain it here shortly.
When you try to require path/to/script.php?parameter=value, PHP looks for file named script.php?parameter=value, because UNIX allows you to have paths like this.
If you are really need to pass some data to included script, just declare it as $variable=... or $GLOBALS[]=... or other way you like.
Aside from the other excellent answers, one thing I overlooked on Windows while writing a simple script: This error will be shown when trying to open a file with characters that Windows does not support in file names.
For example:
$file = fopen(date('Y-m-d_H:i:s'), 'w+');
Will give:
fopen(2022-06-01_22:53:03): Failed to open stream: No such file or directory in ...
Windows does not like : in file names, as well as a number of other characters.
The following PHP settings in php.ini if set to non-existent directory can also raise
PHP Warning: Unknown: failed to open stream: Permission denied in
Unknown on line 0
sys_temp_dir
upload_tmp_dir
session.save_path
PHP - Failed to open stream : No such file or directory in mac
For example I will upload a picture. But I am getting this error. First thing i will do right click on the image and get info.
$thePathOfMyPicture = "/Users/misstugba/Desktop/";
use with function
if(move_uploaded_file($_FILES["file"]["tmp_name"],$thePathOfMyPicture.$_FILES["file"]["name"])){
echo "image uploaded successfully";
}
For me I got this error because I was trying to read a file which required HTTP auth, with a username and password. Hope that helps others. Might be another corner case.
Edit
You can check if this type of authentication is present by inspecting the headers:
$file_headers = get_headers($url);
if (!$file_headers) echo 'File headers missing';
else if (strpos($file_headers[0], '401 Unauthorized') > -1) echo '401 Unauthorized';
In PHP, start Apache then write you DB name and password if exist in your environment(.env).
In PHP scripts, whether calling include(), require(), fopen(), or their derivatives such as include_once, require_once, or even, move_uploaded_file(), one often runs into an error or warning:
Failed to open stream : No such file or directory.
What is a good process to quickly find the root cause of the problem?
There are many reasons why one might run into this error and thus a good checklist of what to check first helps considerably.
Let's consider that we are troubleshooting the following line:
require "/path/to/file"
Checklist
1. Check the file path for typos
either check manually (by visually checking the path)
or move whatever is called by require* or include* to its own variable, echo it, copy it, and try accessing it from a terminal:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Then, in a terminal:
cat <file path pasted>
2. Check that the file path is correct regarding relative vs absolute path considerations
if it is starting by a forward slash "/" then it is not referring to the root of your website's folder (the document root), but to the root of your server.
for example, your website's directory might be /users/tony/htdocs
if it is not starting by a forward slash then it is either relying on the include path (see below) or the path is relative. If it is relative, then PHP will calculate relatively to the path of the current working directory.
thus, not relative to the path of your web site's root, or to the file where you are typing
for that reason, always use absolute file paths
Best practices :
In order to make your script robust in case you move things around, while still generating an absolute path at runtime, you have 2 options :
use require __DIR__ . "/relative/path/from/current/file". The __DIR__ magic constant returns the directory of the current file.
define a SITE_ROOT constant yourself :
at the root of your web site's directory, create a file, e.g. config.php
in config.php, write
define('SITE_ROOT', __DIR__);
in every file where you want to reference the site root folder, include config.php, and then use the SITE_ROOT constant wherever you like :
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
These 2 practices also make your application more portable because it does not rely on ini settings like the include path.
3. Check your include path
Another way to include files, neither relatively nor purely absolutely, is to rely on the include path. This is often the case for libraries or frameworks such as the Zend framework.
Such an inclusion will look like this :
include "Zend/Mail/Protocol/Imap.php"
In that case, you will want to make sure that the folder where "Zend" is, is part of the include path.
You can check the include path with :
echo get_include_path();
You can add a folder to it with :
set_include_path(get_include_path().":"."/path/to/new/folder");
4. Check that your server has access to that file
It might be that all together, the user running the server process (Apache or PHP) simply doesn't have permission to read from or write to that file.
To check under what user the server is running you can use posix_getpwuid :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
To find out the permissions on the file, type the following command in the terminal:
ls -l <path/to/file>
and look at permission symbolic notation
5. Check PHP settings
If none of the above worked, then the issue is probably that some PHP settings forbid it to access that file.
Three settings could be relevant :
open_basedir
If this is set PHP won't be able to access any file outside of the specified directory (not even through a symbolic link).
However, the default behavior is for it not to be set in which case there is no restriction
This can be checked by either calling phpinfo() or by using ini_get("open_basedir")
You can change the setting either by editing your php.ini file or your httpd.conf file
safe mode
if this is turned on restrictions might apply. However, this has been removed in PHP 5.4. If you are still on a version that supports safe mode upgrade to a PHP version that is still being supported.
allow_url_fopen and allow_url_include
this applies only to including or opening files through a network process such as http:// not when trying to include files on the local file system
this can be checked with ini_get("allow_url_include") and set with ini_set("allow_url_include", "1")
Corner cases
If none of the above enabled to diagnose the problem, here are some special situations that could happen :
1. The inclusion of library relying on the include path
It can happen that you include a library, for example, the Zend framework, using a relative or absolute path. For example :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
But then you still get the same kind of error.
This could happen because the file that you have (successfully) included, has itself an include statement for another file, and that second include statement assumes that you have added the path of that library to the include path.
For example, the Zend framework file mentioned before could have the following include :
include "Zend/Mail/Protocol/Exception.php"
which is neither an inclusion by relative path, nor by absolute path. It is assuming that the Zend framework directory has been added to the include path.
In such a case, the only practical solution is to add the directory to your include path.
2. SELinux
If you are running Security-Enhanced Linux, then it might be the reason for the problem, by denying access to the file from the server.
To check whether SELinux is enabled on your system, run the sestatus command in a terminal. If the command does not exist, then SELinux is not on your system. If it does exist, then it should tell you whether it is enforced or not.
To check whether SELinux policies are the reason for the problem, you can try turning it off temporarily. However be CAREFUL, since this will disable protection entirely. Do not do this on your production server.
setenforce 0
If you no longer have the problem with SELinux turned off, then this is the root cause.
To solve it, you will have to configure SELinux accordingly.
The following context types will be necessary :
httpd_sys_content_t for files that you want your server to be able to read
httpd_sys_rw_content_t for files on which you want read and write access
httpd_log_t for log files
httpd_cache_t for the cache directory
For example, to assign the httpd_sys_content_t context type to your website root directory, run :
semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
If your file is in a home directory, you will also need to turn on the httpd_enable_homedirs boolean :
setsebool -P httpd_enable_homedirs 1
In any case, there could be a variety of reasons why SELinux would deny access to a file, depending on your policies. So you will need to enquire into that. Here is a tutorial specifically on configuring SELinux for a web server.
3. Symfony
If you are using Symfony, and experiencing this error when uploading to a server, then it can be that the app's cache hasn't been reset, either because app/cache has been uploaded, or that cache hasn't been cleared.
You can test and fix this by running the following console command:
cache:clear
4. Non ACSII characters inside Zip file
Apparently, this error can happen also upon calling zip->close() when some files inside the zip have non-ASCII characters in their filename, such as "é".
A potential solution is to wrap the file name in utf8_decode() before creating the target file.
Credits to Fran Cano for identifying and suggesting a solution to this issue
To add to the (really good) existing answer
Shared Hosting Software
open_basedir is one that can stump you because it can be specified in a web server configuration. While this is easily remedied if you run your own dedicated server, there are some shared hosting software packages out there (like Plesk, cPanel, etc) that will configure a configuration directive on a per-domain basis. Because the software builds the configuration file (i.e. httpd.conf) you cannot change that file directly because the hosting software will just overwrite it when it restarts.
With Plesk, they provide a place to override the provided httpd.conf called vhost.conf. Only the server admin can write this file. The configuration for Apache looks something like this
<Directory /var/www/vhosts/domain.com>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode off
php_admin_value open_basedir "/var/www/vhosts/domain.com:/tmp:/usr/share/pear:/local/PEAR"
</IfModule>
</Directory>
Have your server admin consult the manual for the hosting and web server software they use.
File Permissions
It's important to note that executing a file through your web server is very different from a command line or cron job execution. The big difference is that your web server has its own user and permissions. For security reasons that user is pretty restricted. Apache, for instance, is often apache, www-data or httpd (depending on your server). A cron job or CLI execution has whatever permissions that the user running it has (i.e. running a PHP script as root will execute with permissions of root).
A lot of times people will solve a permissions problem by doing the following (Linux example)
chmod 777 /path/to/file
This is not a smart idea, because the file or directory is now world writable. If you own the server and are the only user then this isn't such a big deal, but if you're on a shared hosting environment you've just given everyone on your server access.
What you need to do is determine the user(s) that need access and give only those them access. Once you know which users need access you'll want to make sure that
That user owns the file and possibly the parent directory (especially the parent directory if you want to write files). In most shared hosting environments this won't be an issue, because your user should own all the files underneath your root. A Linux example is shown below
chown apache:apache /path/to/file
The user, and only that user, has access. In Linux, a good practice would be chmod 600 (only owner can read and write) or chmod 644 (owner can write but everyone can read)
You can read a more extended discussion of Linux/Unix permissions and users here
Look at the exact error
My code worked fine on all machines but only on this one started giving problem (which used to work find I guess). Used echo "document_root" path to debug and also looked closely at the error, found this
Warning:
include(D:/MyProjects/testproject//functions/connections.php):
failed to open stream:
You can easily see where the problems are. The problems are // before functions
$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');
So simply remove the lading / from include and it should work fine. What is interesting is this behaviors is different on different versions. I run the same code on Laptop, Macbook Pro and this PC, all worked fine untill. Hope this helps someone.
Copy past the file location in the browser to make sure file exists. Sometimes files get deleted unexpectedly (happened with me) and it was also the issue in my case.
Samba Shares
If you have a Linux test server and you work from a Windows Client, the Samba share interferes with the chmod command. So, even if you use:
chmod -R 777 myfolder
on the Linux side it is fully possible that the Unix Group\www-data still doesn't have write access. One working solution if your share is set up that Windows admins are mapped to root: From Windows, open the Permissions, disable Inheritance for your folder with copy, and then grant full access for www-data.
Add script with query parameters
That was my case. It actually links to question #4485874, but I'm going to explain it here shortly.
When you try to require path/to/script.php?parameter=value, PHP looks for file named script.php?parameter=value, because UNIX allows you to have paths like this.
If you are really need to pass some data to included script, just declare it as $variable=... or $GLOBALS[]=... or other way you like.
Aside from the other excellent answers, one thing I overlooked on Windows while writing a simple script: This error will be shown when trying to open a file with characters that Windows does not support in file names.
For example:
$file = fopen(date('Y-m-d_H:i:s'), 'w+');
Will give:
fopen(2022-06-01_22:53:03): Failed to open stream: No such file or directory in ...
Windows does not like : in file names, as well as a number of other characters.
The following PHP settings in php.ini if set to non-existent directory can also raise
PHP Warning: Unknown: failed to open stream: Permission denied in
Unknown on line 0
sys_temp_dir
upload_tmp_dir
session.save_path
PHP - Failed to open stream : No such file or directory in mac
For example I will upload a picture. But I am getting this error. First thing i will do right click on the image and get info.
$thePathOfMyPicture = "/Users/misstugba/Desktop/";
use with function
if(move_uploaded_file($_FILES["file"]["tmp_name"],$thePathOfMyPicture.$_FILES["file"]["name"])){
echo "image uploaded successfully";
}
For me I got this error because I was trying to read a file which required HTTP auth, with a username and password. Hope that helps others. Might be another corner case.
Edit
You can check if this type of authentication is present by inspecting the headers:
$file_headers = get_headers($url);
if (!$file_headers) echo 'File headers missing';
else if (strpos($file_headers[0], '401 Unauthorized') > -1) echo '401 Unauthorized';
In PHP, start Apache then write you DB name and password if exist in your environment(.env).
THE SITUATION
I have multiple folders in my /var/www/ directory.
Users are created that have control over a specific directory... /var/www/app1 belongs to app1:app1 (www-data is a member of the app1 group).
This works fine for what I want.
THE PROBLEM
If the app1 user uploads a PHP script that changes the file/folder permissions for something in app2s directory structure, the Apache process (as there's only one installed on the server) will be more than happy to run it, as it has the necessary permissions to access both /var/www/app1 and /var/www/app2 folders and files.
EDIT:
To the best of my knowledge, something like, /var/www/app1/includes/hack.php:
<?php
chmod("/var/www/app2", 777);
?>
The Apache process (owned by www-data) will run this, as it has permissions to change both /var/www/app1 and /var/www/app2 directories. The user app1 will then be able to cd /var/www/app2, rm -rf /var/www/app2, etc., which is obviously not good.
THE QUESTION
How can I avoid this cross-contamination of the Apache process? Can I instruct Apache to only run PHP scripts that affect the files/folders that reside within the relevant vHost root directory and below?
While open_basedir would help, there are several ways of bypassing this constraint. While you could break a lot of functionality in php to close off all the backdoors, a better solution would be to stop executing the php as a user whom has access to all the files. To do that, you need to use php-fpm with a separate process pool/uid/gid for each vhost.
You should still have a separate uid for the php execution from the uid owning the files with a common group allowing a default read only access to the files.
You also need to have separate storage directories for session data.
A more elaborate mechanism would be to use something like Apache traffic server in front of a container-per owner with each site running on its own instance of Apache - much better isolation, but technically demanding and somewhat more resource intensive.
Bear in mind, if you are using mariadb or similar, that the DBMS can also read and write arbitrary files (SELECT INTO OUTFILE.../LOAD DATA INFILE)
UPDATE
Rather than the effort of maintaining separate containers, better isolation could be achieved with less effort by setting the home directory of the php-fpm uid appX to the base directory of the vhost (which should contain, not be, the document_root - see below) and use apparmor to constrain access to the common files (e.g .so libs) and #{HOME}. Hence each /var/www/appX might contain:
.htaccess
.user.ini
data/ (writeable by fpm-appX)
html/ (the document root)
include/
sessions/ (writeable by fpm-appX)
You should add an open_basedir directive to each site's vhost file. The open_basedir directive limits the directories that a site can access.
You can read more about open_basedir here.
This question is related to another question I wrote:
Trouble using DOTNET from PHP.
Where I was using the DOTNET() function in PHP to call a DLL I had written.
I was able to get it working fine by running php.exe example.php from the command line (with the DLL's still in the PHP folder).
I moved the php file to an IIS 7 webserver folder on the same machine (leaving the DLLs in the same php folder), but I keep getting a 500 internal service error.
I've checked the server logs (in c:\inetput\logs\ and in c:\windows\temp\php53errors) but there doesn't seem to be any relevant information about what caused the error. I even tried to change the php.ini settings to get more error feedback, but that doesn't seem to help.
I can only guess that the issue may be related to:
that php file not having the proper permissions (my dll does some file reading/writing)
php can't find the DLLs
The actual error I get is:
The FastCGI process exited unexpectedly.
Any idea on how to debug this problem?
The problem here is almost certainly related to file permissions.
When you run php.exe from the command line you run as your own logged-in user. When running a PHP script from IIS, in response to an http request, php.exe runs as a different user. Depending on your version of Windows it could be
IUSR_machine - on IIS6 and prior
IUSR on IIS7 and later
These users need permissions on the php file to be executed.
Read more about it
On IIS7 and later I use a command-line tool called icacls.exe to set the permissions on directories or files that need to be read by IIS and the processes it starts (like php.exe). This security stuff applies to all IIS applications: PHP, ASPNET, ASP-classic, Python, and so on.
IIS also needs to be able to read static files, like .htm, .js, .css, .jpog, .png files and so on. You can set the same permissions for all of them: Read and Execute.
You can grant permissions directly to the user, like this:
icacls.exe YOUR-FILE-GOES-HERE /grant "NT AUTHORITY\IUSR:(RX)"
You can also grant permissions to the group, to which IUSR belongs, like this:
icacls.exe YOUR-FILE-HERE /grant "BUILTIN\IIS_IUSRS:(RX)"
In either case you may need to stop and restart IIS after setting file-level permissions.
If your .php script reads and writes other files or directories, then the same user needs pernissions on those other files and directories. If you need the .php script to be able to delete files, then you might want
icacls.exe YOUR-FILE-HERE /grant "BUILTIN\IIS_IUSRS:(F)"
...which grants full rights to the file.
You can grant permissions on an entire directory, too, specifying that all files created in that directory in the future will inherit the file-specific permissions set on the directory. For example, set the file perms for the directory, then copy a bunch of files into it, and all the files get the permissions from the parent. Do this with the OI and CI flags (those initials stand for "object-inherit" and "container-inherit").
icacls.exe DIRECTORY /grant "BUILTIN\IIS_IUSRS:(OI)(CI)(RX)"
copy FILE1 DIRECTORY
copy FILE2 DIRECTORY
...
When I want to create a new vdir in IIS, to allow running PHP scripts, or ASPX or .JS (yes, ASP Classic) or Python or whatever, I do these steps:
appcmd.exe add app /site.name:"Default Web Site" /path:/vdirpath /physicalPath:c:\docroot
icacls.exe DIRECTORY /grant "BUILTIN\IIS_IUSRS:(OI)(CI)(RX)"
Then I drop files into the directory, and they get the proper permissions.
Setting the ACL (access control list) on the directory will not change the ACL for the files that already exist in the directory. If you want to set permissions on the files that are already in the directory, you need to use icacls.exe on the particular files. icacls accepts wildcards, and it also has a /t switch that recurses.
In my project, I have to upload some video files to a folder which lies outside the root folder. I am using simple php function move_uploaded_file to upload the file. I have tried with the code below.
$source = $_FILES['Filedata']['tmp_name'];
$targetFile = '/usr/local/WowzaMediaServer-3.1.1/content/video.mp4'
move_uploaded_file($source,$targetFile);
But it is not working. Can we done it through move_uploaded_file. if not, suggest a better option to do this.
I have seen some similar question but nothing helps. So any help would be appreciated..
Are you sure you're not in a chroot jail?
If so, your "absolute" path name could be pointing to the wrong place-- somewhere that doesn't exist.
If so, change the path to point to somewhere within the jail.
It may be necessary to mount --bind the directory you want this to go in into some location within the jail. (Note that a symbolic link will not work for getting out of jail.)
More than likely this is a simple permissions issue and quite easy to solve.
Find the user that apache uses. To do this open up your httpd.conf file and look for something like:
User apache
Group apache
Change the ownership of the folder that you're trying to upload to.
chown -R apache.apache /usr/local/WowzaMediaServer-3.1.1/content/
Change the permissions of the folder
chmod -R 775 /usr/local/WowzaMediaServer-3.1.1/content/
And that should be that.
I'm going to assume you're using Apache for the purposes of this answer.
First off, is the file being uploaded ok? One possible reason you might have trouble is that the tmp directory isn't writable by the webserver, or readable come to that. Assuming that's ok then move_uploaded_file should work fine.
Create a folder next to your DOCUMENT_ROOT, let's call it "filestore". Make sure it's writable by www-data or whichever user runs apache. Now, you should be able to move the files into that folder. Note they will be owned by www-data:www-data typically - or whatever user and group your server is set up to run as. The reason I put the "filestore" folder next to the DOCUMENT_ROOT folder is that you can be sure the webserver can read the file path up to DOCUMENT_ROOT. Otherwise you run the risk of a folder part way up the path not being readable, and that'll stop you dead. e.g. if you have /usr/local/media as your target folder and /usr/local isn't readable (and executable) by the webserver, you're toast.
If all this works and you absolutely must have you media elsewhere, you can have the "filestore" folder anywhere so long as the whole path to it is read/executable by the webserver. Check each directory in the path.
If these uploaded files are being downloaded by other users via the web then the "filestore" folder only needs to have permissions of 700 since it's always going to be the web server's user which reads them. If other users need access, typically because other software running as a different user needs to use them then you might need permissions to be 750 to allow group members to read (and execute) the directory. You'll also need to add that other user to the www-data group.
For downloads you will need to write a simple script which dumps the file to the browser after doing some authentication checks. That way, you avoid having the media accessible just via http without having any authentication done first - which could make your service into an attractive place for illegal files (copyright violations being the least concern here).
This is a dangerous approach as it gives root privileges to the apache user, so use with caution.
Add the apache user to the list of sudoers - which will let you execute commands as root in php via system('sudo the_command'). Then move the uploaded file to a temporary location that the apache user can write do (eg. create a 'tmp' directory in the doc root). Then use system("sudo mv \"$source\" \"$destination\""); to move the temporary file to it's final location.
You can find the apache user by executing <?php echo exec('whoami'); ?>. Then add the following entry to sudoers the-apache-user ALL=(ALL) NOPASSWD: ALL. Use visudo to add the sudoer entry.
Example:
$source = $_FILES['Filedata']['tmp_name'];
$targetFile = '/usr/local/WowzaMediaServer-3.1.1/content/video.mp4'
$tempLocation = 'tmp/temp-file.mp4';
move_uploaded_file($source, $tempLocation);
system('sudo mv "' . $tempLocation . '" "' . $targetFile . '"');
Edit: Related question - How to run PHP exec() as root?
Always you face a problem with your code, look at the server log or easier turn on errors display. That said, your problem could be related to upload_tmp_dir setting. Check what a phpinfo() tells about that or look at your php.inifile.
A better solution would be to write the file somewhere where you can write (i.e. under the webroot) and then create a symlink from the media directory to be to where you wrote it.
For example:
Web Root is /var/www/html
You want it at /usr/local/WowzaMediaServer-3.1.1/content/
Create directory /var/www/html/mediaserver/content/
Make permissions on /var/www/html/mediaserver/content/ 777 (so apache can write to it)
Copy files from /usr/local/WowzaMediaServer-3.1.1/content/ to /var/www/html/mediaserver/content/
Delete /usr/local/WowzaMediaServer-3.1.1/content/ (just the "content" directory)
Create symlink from /usr/local/WowzaMediaServer-3.1.1/content/ to /var/www/html/mediaserver/content/
Then you have permissions to read/write, and the media server should too. Only issue would be if the media server is trained not to read symlinks - but you can find that out quickly enough.