PHP File Permissions... getting it "write"? - php

I am trying to write an install script for a system I have been working on. The script copies some default files from one location to another, and creates various folders for them. I have this bit working a treat, but the only problem is that when I login via FTP, I can't edit, or delete the files that PHP has moved for me.
If I login via terminal I can happily "sudo chmod -R 777 [dir]" and the problem goes away, so the question is:
What am I missing on the PHP end?
my permissions function is as follows:
function set_permissions($file)
{
if (file_exists($file)):
chmod($file,0777);
endif;
}
I understand it's not 100% ideal to set the permissions to 777, but I am simply trying to achieve the result of being able to edit the files via FTP, after PHP has moved them for me.
Hope I've been clear enough. This is puzzling me now so any help is appreciated :)
Tom
edit:
The whole process is as follows:
mkdir($root_dir, 0777);
mkdir($images_dir, 0777);
if (!copy($orig_logo, $new_logo))
{
echo "failed to copy $orig_logo...";
}
// see function above for details on set_permissions...
$this->set_permissions($new_logo);
}
(All the paths are correct too)
edit:
The file before I login via terminal has the following permissions:
-rwxrwxrwx 1 www-data www-data 2739 2009-08-26 01:45 base.css
The file after I login and change it has:
-rwxrwxrwx 1 www-data www-data 2739 2009-08-26 01:45 base.css
The system is a content management system that allows you to edit and delete files through the admin area, and strangely enough, this works well. It seems like the files are somehow locked out from anybody else other than Apache... but the file info suggests otherwise. It's odd...

Sounds like your directory needs the write permissions as well.

Are you sure the file exists or the path is correct?

If you can chmod -R 777 via terminal to fix the problem, then what were the permissions set to by PHP before you ran chmod??? Obviously not 777. My guess is that your PHP code is not actually changing the permissions.
Lookat at your code, your permission-changing function could be failing silently if the file doesn't exist - e.g., you're giving it invalid file names (wrong folder? wrong relative path?) but you can't tell because your set_permissions() function is too scared of warning you. You should rewrite it as follows:
function set_permissions($file)
{
if (!file_exists($file))
throw new Exception(__FUNCTION__ . "() file doesn't exist! '$file'");
chmod($file,0777);
error_log("chmod 777 $file"); // debug
}
This allows you to see what's happening, and you'll certainly notice if you haven't got your file names correct.

Related

I am having issues with permissions of the apache user www-data on raspberry pi [duplicate]

I'm trying to use PHP to create a file, but it isn't working. I am assuming this is because it doesn't have write access (it's always been the problem before). I tried to test if this was the problem by making the folder chmod 0777, but that just ended up making every script in that directory return a 500 error message until I changed it back.
How do I give PHP write access to my file system so it can a create a file?
Edit: It is hosted on Hostgator shared hosting using Apache.
Edit 2: Someone asked for the code:
The code is a GD image script. I know the rest of it works as previously I was creating the image every ime it was called. Now I am trying to create them when new text is added and save them to a folder. The write line I have is:
imagejpeg(null,$file,85);
I also created a test file to check if it was just a broken script (mainly copied from tizag):
http://gearboxshow.info/rkr/lesig.jpg/testfile.txt (I don't know if/how to post the code here properly. Here is the contents of the PHP script, minus PHP tags.)
It returns 13,13,1 (separate lines), so it looks as if it thinks it wrote something, but the testfile.txt is blank (I uploaded a blank one), or non-existent (if I delete it).
Edit 3: The server runs CentOS.
An easy way is to let PHP create the directory itself in the first place.
<?php
$dir = 'myDir';
// create new directory with 744 permissions if it does not exist yet
// owner will be the user/group the PHP script is run under
if ( !file_exists($dir) ) {
mkdir ($dir, 0744);
}
file_put_contents ($dir.'/test.txt', 'Hello File');
This saves you the hassle with permissions.
Simple 3-Step Solution
Abstract: You need to set the owner of the directory to the user that PHP uses (web server user).
Step 1: Determine PHP User
Create a PHP file containing the following:
<?php echo `whoami`; ?>
Upload it to your web server. The output should be similar to the following:
www-data
Therefore, the PHP user is www-data.
Step 2: Determine Owner of Directory
Next, check the details of the web directory via the command line:
ls -dl /var/www/example.com/public_html/example-folder
The result should be similar to the following:
drwxrwxr-x 2 exampleuser1 exampleuser2 4096 Mar 29 16:34 example-folder
Therefore, the owner of the directory is exampleuser1.
Step 3: Change Directory Owner to PHP User
Afterwards, change the owner of the web directory to the PHP user:
sudo chown -R www-data /var/www/example.com/public_html/example-folder
Verify that the owner of the web directory has been changed:
ls -dl /var/www/example.com/public_html/example-folder
The result should be similar to the following:
drwxrwxr-x 2 www-data exampleuser2 4096 Mar 29 16:34 example-folder
Therefore, the owner of example-folder has successfully been changed to the PHP user: www-data.
Done! PHP should now be able to write to the directory.
Set the owner of the directory to the user running apache. Often nobody on linux
chown nobody:nobody <dirname>
This way your folder will not be world writable, but still writable for apache :)
1st Figure out which user is owning httpd process using the following command
ps aux | grep httpd
you will get a several line response like this:
phpuser 17121 0.0 0.2 414060 7928 ? SN 03:49 0:00 /usr/sbin/httpd
Here 1st column shows the user name. So now you know the user who is trying to write files, which is in this case phpuser
You can now go ahead and set the permission for directory where your php script is trying to write something:
sudo chown phpuser:phpuser PhpCanWriteHere
sudo chmod 755 PhpCanWriteHere
You can change the permissions of a folder with PHP's chmod(). More information on how to use the command is here: http://php.net/manual/en/function.chmod.php
If you get a 500 Error when setting the permissions to 777 (world writable), then it means your server is setup to prevent executing such files. This is done for security reasons. In that case, you will want to use 755 as the highest permissions on a file.
If there is an error_log file that is generated in the folder where you are executing the PHP document, you will want to view the last few entries. This will give you an idea where the script is failing.
For help with PHP file manipulation, I use http://www.tizag.com/phpT/filewrite.php as a resource.
I found out that with HostGator you have to set files to CMOD 644 and Folders to 755. Since I did this based on their tech support it works with HostGator
I had the same problem:
As I was reluctant to give 0777 to my php directory, I create a tmp directory with rights 0777, where I create the files I need to write to.
My php directory continue to be protected. If somebody hackes the tmp directory, the site continue to work as usual.
You can set selinux to permissive in order to analyze.
# setenforce 0
Selinux will log but permit acesses. So you can check the /var/log/audit/audit.log for details. Maybe you will need change selinux context. Fot this, you will use chcon command. If you need, show us your audit.log to more detailed answer.
Don't forget to enable selinux after you solved the problem. It better keep selinux enforced.
# setenforce 1
Best way in giving write access to a directory..
$dst = "path/to/directory";
mkdir($dst);
chown($dst, "ownername");
chgrp($dst, "groupname");
exec ("find ".$dst." -type d -exec chmod 0777 {} +");
chmod does not allow you to set ownership of a file. To set the ownership of the file you must use the chown command.
I'm running Ubuntu, and as said above nobody:nobody does not work on Ubuntu. You get the error:
chown: invalid group: 'nobody:nobody'
Instead you should use the 'nogroup', like:
chown nobody:nogroup <dirname>
Tiny little hint!
echo whoami;
make sure you use BACK QUOTES
NOT
single quotes ' '
!
(of course now the back quotes don't show up in this editor! oh well, I tried!)

Write to tmp folder

EDIT 1
This question involves the user of the MANGOPAY API. My problem is that I cannot get the API to write to the tmp folder.
I have succeeded in getting the API to write to http://fakedomain.com/apifolder/blank.txt and getting the appropriate output.
I then ran the script http://fake.com/apifolder/demos/iswrite.php on http://fakedomain.com/apifolder/blank.txt to have minimal working code I could test on the tmp folder. Here is the code in the script:
<?php
$filename = 'blank.txt';
echo "<br>";
file_exists($filename);
echo "<br>";
if (file_exists($filename)) {
echo "The file $filename exists";
} else {
echo "The file $filename does not exist";
}
echo "<br>";
if (is_writable($filename)) {
echo 'The file is writable';
} else {
echo 'The file is not writable';
}
?>
It gives me the output
The file blank.txt exists
The file is writable
so all good there. I created the following file with the following permissions using Filezilla:
In the script http://fake.com/apifolder/demos/iswrite.php I have changed the filename variable to $filename = 'http://fake.com/tmp/creative/blank.txt';. It gives me the following output:
The file http://fake.com/tmp/creative/blank.txt does not exist
The file is not writable
Also, allow_url_fopen is on.
I don't fully understand URL structures, so maybe the problem lies there? The tmp folder I am trying to access is on the same level as my public_html folder. Maybe I am writing my URLs wrong?
Put in another way, does the tmp folder have to be outside the public_html folder? Would there be any purpose to this? Or can I have create my own tmp folder within public_html where it is already working?
ORIGINAL QUESTION
The original question was poorly written. Please see EDIT 1
I am playing with the sandbox of an API (MangoPay). I have included my ClientId and ClientPassword which seems to work.
The API also says...
You also need to set a folder path in $api->Config->TemporaryFolder
that SDK needs to store temporary files. This path should be outside
your www folder. It could be /tmp/ or /var/tmp/ or any other location
that PHP can write to.
I have created one at:
ftp://fakedomain#fakedomain/tmp/fakefoldername
I am running the php script from my desktop using Terminal. The output it is giving me is
Cannot create or write to file
ftp://fakedomain#fakedomain/tmp/fakefoldername
even though I have set permissions to 777.
Any idea of why I am getting this error?
I am guessing the library in question is this one, and the error you are getting is this exception:
if (!is_writable($this->GetPathToTemporaryFolder()))
throw new \MangoPay\Libraries\Exception('Cannot create or write to file ' . $this->GetPathToTemporaryFolder());
So basically we seem to be debugging a call to is_writable().
make sure allow_url_fopen is on
if applicable, make sure the URL includes the FTP password
make sure the folder exists and the FTP account has write permissions (777 should suffice...)
Generally speaking a temp dir is supposed to be located on the same machine as your code. Using FTP is less than ideal. Are you not able to use a local directory?
You'll notice in the MangoPay documentation it shows a local dir:
https://github.com/Mangopay/mangopay2-php-sdk
$api->Config->TemporaryFolder = '/some/path/';
You should probably stick to that, instead of using a remote server via FTP.
An out-of-the-box Linux machine running Ubuntu 14.04 has the following user and permission settings
drwxrwxrwt 13 root root 4096 nov 9 00:56 tmp//
And the dummy directory
drwxrwxr-x 2 eric eric 4,0K nov 9 00:49 fakefoldername/
In case of switching to 777 permission set (as you said, you have already done this), that would be
drwxrwxrwx 2 eric eric 4,0K nov 9 00:49 fakefoldername/
The point to notice here is that if you used chmod 777 fakefoldername it changes the permission set only to the directory without touching any of the files/directories in fakefoldername (use chmod -R 777 fakefoldername). Another point to remember is that directories leading to the fakefoldername also need to have sufficient perms. For this particular case, check if /tmp folder has them, fix if necessary
sudo chmod 1777 tmp/
Also, as stated above, I would try to make another directory in /var directory and see how things are going then (an nice answer why to or not to choose /var/tmp over /tmp here).
For others: the SDK that is used is probably https://github.com/Mangopay/mangopay2-php-sdk
There might be some hints in the somewhat similar answers below:
http://forum.odin.com/threads/error-message-cant-create-write-to-file-tmp-after-overflow-tmp.296376/
https://unix.stackexchange.com/questions/39466/vsftpd-553-could-not-create-file-permissions
Most likely, your apache dont have permissions to write that folder, you have to be sure that you are creating that directory with same user (in your case, apache) and also chmod.

file_put_contents not creating txt file

I currently have a php script that is running when a browser browser browses to the webpage. What I'm trying to do is write a text file when the script runs that stores a variable. The owner of the folder is apache, but everyone has read write, strictly for testing purposes. (I thought it might be a permissions issue) SELINUX is enabled on the server, and when I run the script from console it creates the text file just fine, and in the right directory.
file_put_contents("My working file location", $myString);
I'm using this line to try to write and create the text file, I know that my file location works becaus I can run it and create it in offline mode, I.E. running it through console. The problem is that the variable I'm trying to write is populated through HTTP Post, and when I run the script through the browser, or when apache runs the script, it does not write or create the file. What do I need to do to allow access to write/change syntax wise to get this script to write this text file?
Your problem is likely due to apache not having permissions to write to the file location you specified. Go to that directory and check the permissions and group ownership with the ls command:
cd "My working file location"
ls -l .
There are three columns in the output that show the permissions, owner, and group for the directory. Most likely they are owned by root and don't have permissions for apache to write to the directory.
If this is the case, then you will see an error appear in your apache log when it tries to create the file. Try tailing your logs while running the script in your browser:
tail -f /var/log/apache2/error.log
I had the same trouble recently and stumbled upon this question. Unfortunately choppyfireballs the OP said in a comment he found his own solution and just accepted an answer that wasn't helping any of us... Then after a search and a success to make file_put_contents work again I decided to share my solution.
The permissions of my files and directories were ok to accept any writing (make sure your directories are chmod 757 this will give the root and others the grant to write files in the location). If it still doesn't work like it didn't for me, that's because your system is probably SELinux (Security Enhanced Linux) system.
If you want to make sure write setenforce 0 this will turn selinux to permissive mode, run your script again, if it works then it means the problem is well described.
In that case turn selinux on back setenforce 1 and try ls -Zl in the directory where the directory of your project is. this will give you a line like
drwx---r-x. 9 root root system_u:object_r:httpd_sys_content_t:s0 4096 Dec 8 00:25 project
or something different but httpd_sys_content_t if you used chcon to transfer the context from one directory to this one. but if you don't have httpd_sys_content_t it's ok because we need to change the context of that directory anyways.
first you need to accept any public_content_rw_t contexts to write file. Type
setsebool -P httpd_anon_write on
This will set (P)ermanently SELinux boolean httpd_anon_write to true and any context dubbed as public_content_rw_t will have the rights to write any files in their own location.
Now you have to say SELinux that your project directory is public_content_rw_t or you'll still not be able to write files. Type :
semanage fcontext --add --type public_content_rw_t "/project(/.*)?"
and restorecon -RvF /project to tell selinux to apply the above specifications.
Now your directory is public_content_rw_t and you should be able to write files.
I ran into this problem too. In my case, I found that the ownership of the directory was wrong. For a typical Apache installation the directory should be owned by www-data:www-data, not root:root.
Something else to try, for people with a similar question. You might just be making a simple mistake that doesn't require you to mess around with the file permissions—and if you're making this mistake, fixing the file permissions might not help.
Be sure you're using a local, relative file path in file_put_contents().
For example, use:
file_put_contents('short_local_path/my_working_file.txt', $myString);
Not:
file_put_contents('http://example.com/remote_path/my_working_file.txt', $myString);
And not:
file_put_contents('/whole/root/file/path/to/my_working_file.txt', $myString);
Have you tried chmodding the directory to 777?
Try this:
if(file_put_contents('file.txt', 'text')){
die('yes');
} else {
die('no');
}
Might of misspelled something. ^

php file_exists is returning false even if file exist on my linux

This question has been asked many times, but none of the answers I found helped me.
I am trying to get php file_exists() to work. The only scenario when it works is when the php-file is in the same directory as the file to use file_exist() on and only using the file name (i.e. excluding the path). But it's not consequent behaviour, please see below.
Som information:
safe_mode=off
no symlinks for directory 28
no whitespace in the file name
All directories in /var/www/html/smic/upload/28/ has apache:apache 777 as permission.
Using php 5.3
PHP:
echo getcwd()
clearstatcache();
$file = 'file:///var/www/html/smic/upload/28/ul.txt';
//Also tried like this
//$file = '/var/www/html/smic/upload/28/ul.txt';
if(file_exists($file)){
echo $file." exists";
}
getcwd() prints /var/www/html/smic/modules/core/ticket
The permission of the php-script and the file to be checked is apache:apache 777.
Some details about the directory structure:
[root#localhost 28]# pwd
/var/www/html/smic/upload/28
[root#localhost 28]# ls -l ul.txt
-rw-r--r--. 1 apache apache 2 Feb 9 10:50 ul.txt
[root#localhost 28]# chmod 777 ul.txt
[root#localhost 28]# ls -l ul.txt
-rwxrwxrwx. 1 apache apache 2 Feb 9 10:50 ul.txt
The behaviour didn't change after changing the permission of the file. The directory /28 has drwxr-xr-x. for apache user and apache group
For test, I also moved the actual php-script to /28, gave it apache:apache 777 rigths. Changed the $file to "ul.txt" (i.e. $file = 'ul.txt';). That works, the ul.txt file is found.
getcwd() prints then /var/www/html/smic/upload/28
As another test I tried to find another file excluding the path in the "ticket" directory, the file wasn't recognized.
I'm banging my head...
Any advice is appreciated.
The permission of the file alone is not sufficient for php to assess file_exists. the process that runs php also needs permission to traverse all the parent directories of that file to get to it.
Check them one by one and verify that php can read and enter (r-x)
ls -ald /var
ls -ald /var/www
ls -ald /var/www/html
ls -ald /var/www/html/smic
ls -ald /var/www/html/smic/upload
ls -ald /var/www/html/smic/upload/28
Clutching at straws here...
Try su - apache (or whatever the user your webserver runs as.. apache2, www-data etc..) and then traversing the directory.
Are there any .htaccess files knocking about, or any other restrictions on your apache configuration?
Gee, this was a pretty tuff one. I always make sure when I copy anything from the web to first paste it into a normal texteditor in order to remove all strange/hidden characters, then copy the whatever again and paste it into my dev tool.
As I mentioned somewhere in a comment, I did pwd and copied the text form my virtual server to my osx. But what I didn't think about/know was that strange/hidden characters could follow if I did that from my linux server, hence I didn't make sure to copy everything via texteditor.
I remembered that I had problem quite some time ago when I copied from the web and figured this may be a similar kind of problem. I opened my script in an hex editor. And what did I find... '/var' looked lite this: '/var'. Removing the strange characters fixed the problem.
Thank you all for your comments above. Hope those can help someone else and perhaps it has helped me without even knowing it (since I did a lot of things based on your comments).
what's about the access rights to the folder?
the path $file = 'file:///var/www/html/smic/upload/28/ul.txt'; is incorrect.
Try the php script copy to folder upload and file='28/ul.txt';.
The folder must be readable.
Try to open the file using $file = '/upload/28/ul.txt';
From the php.net manual, "Upon failure, an E_WARNING is emitted." make sure error reporting is set to a level that will show warnings and try it.
Also, "This function returns FALSE for files inaccessible due to safe mode restrictions. However these files still can be included if they are located in safe_mode_include_dir.". You're not running in php safe mode are you? phpinfo() should tell you.
Where is your php file located? If within the "html" folder, then use a relative path like $file = "smic/upload/28/ul.txt";
Perhaps, in a name of the file there is a whitespace symbol. It's important.

How do I give PHP write access to a directory?

I'm trying to use PHP to create a file, but it isn't working. I am assuming this is because it doesn't have write access (it's always been the problem before). I tried to test if this was the problem by making the folder chmod 0777, but that just ended up making every script in that directory return a 500 error message until I changed it back.
How do I give PHP write access to my file system so it can a create a file?
Edit: It is hosted on Hostgator shared hosting using Apache.
Edit 2: Someone asked for the code:
The code is a GD image script. I know the rest of it works as previously I was creating the image every ime it was called. Now I am trying to create them when new text is added and save them to a folder. The write line I have is:
imagejpeg(null,$file,85);
I also created a test file to check if it was just a broken script (mainly copied from tizag):
http://gearboxshow.info/rkr/lesig.jpg/testfile.txt (I don't know if/how to post the code here properly. Here is the contents of the PHP script, minus PHP tags.)
It returns 13,13,1 (separate lines), so it looks as if it thinks it wrote something, but the testfile.txt is blank (I uploaded a blank one), or non-existent (if I delete it).
Edit 3: The server runs CentOS.
An easy way is to let PHP create the directory itself in the first place.
<?php
$dir = 'myDir';
// create new directory with 744 permissions if it does not exist yet
// owner will be the user/group the PHP script is run under
if ( !file_exists($dir) ) {
mkdir ($dir, 0744);
}
file_put_contents ($dir.'/test.txt', 'Hello File');
This saves you the hassle with permissions.
Simple 3-Step Solution
Abstract: You need to set the owner of the directory to the user that PHP uses (web server user).
Step 1: Determine PHP User
Create a PHP file containing the following:
<?php echo `whoami`; ?>
Upload it to your web server. The output should be similar to the following:
www-data
Therefore, the PHP user is www-data.
Step 2: Determine Owner of Directory
Next, check the details of the web directory via the command line:
ls -dl /var/www/example.com/public_html/example-folder
The result should be similar to the following:
drwxrwxr-x 2 exampleuser1 exampleuser2 4096 Mar 29 16:34 example-folder
Therefore, the owner of the directory is exampleuser1.
Step 3: Change Directory Owner to PHP User
Afterwards, change the owner of the web directory to the PHP user:
sudo chown -R www-data /var/www/example.com/public_html/example-folder
Verify that the owner of the web directory has been changed:
ls -dl /var/www/example.com/public_html/example-folder
The result should be similar to the following:
drwxrwxr-x 2 www-data exampleuser2 4096 Mar 29 16:34 example-folder
Therefore, the owner of example-folder has successfully been changed to the PHP user: www-data.
Done! PHP should now be able to write to the directory.
Set the owner of the directory to the user running apache. Often nobody on linux
chown nobody:nobody <dirname>
This way your folder will not be world writable, but still writable for apache :)
1st Figure out which user is owning httpd process using the following command
ps aux | grep httpd
you will get a several line response like this:
phpuser 17121 0.0 0.2 414060 7928 ? SN 03:49 0:00 /usr/sbin/httpd
Here 1st column shows the user name. So now you know the user who is trying to write files, which is in this case phpuser
You can now go ahead and set the permission for directory where your php script is trying to write something:
sudo chown phpuser:phpuser PhpCanWriteHere
sudo chmod 755 PhpCanWriteHere
You can change the permissions of a folder with PHP's chmod(). More information on how to use the command is here: http://php.net/manual/en/function.chmod.php
If you get a 500 Error when setting the permissions to 777 (world writable), then it means your server is setup to prevent executing such files. This is done for security reasons. In that case, you will want to use 755 as the highest permissions on a file.
If there is an error_log file that is generated in the folder where you are executing the PHP document, you will want to view the last few entries. This will give you an idea where the script is failing.
For help with PHP file manipulation, I use http://www.tizag.com/phpT/filewrite.php as a resource.
I found out that with HostGator you have to set files to CMOD 644 and Folders to 755. Since I did this based on their tech support it works with HostGator
I had the same problem:
As I was reluctant to give 0777 to my php directory, I create a tmp directory with rights 0777, where I create the files I need to write to.
My php directory continue to be protected. If somebody hackes the tmp directory, the site continue to work as usual.
You can set selinux to permissive in order to analyze.
# setenforce 0
Selinux will log but permit acesses. So you can check the /var/log/audit/audit.log for details. Maybe you will need change selinux context. Fot this, you will use chcon command. If you need, show us your audit.log to more detailed answer.
Don't forget to enable selinux after you solved the problem. It better keep selinux enforced.
# setenforce 1
Best way in giving write access to a directory..
$dst = "path/to/directory";
mkdir($dst);
chown($dst, "ownername");
chgrp($dst, "groupname");
exec ("find ".$dst." -type d -exec chmod 0777 {} +");
chmod does not allow you to set ownership of a file. To set the ownership of the file you must use the chown command.
I'm running Ubuntu, and as said above nobody:nobody does not work on Ubuntu. You get the error:
chown: invalid group: 'nobody:nobody'
Instead you should use the 'nogroup', like:
chown nobody:nogroup <dirname>
Tiny little hint!
echo whoami;
make sure you use BACK QUOTES
NOT
single quotes ' '
!
(of course now the back quotes don't show up in this editor! oh well, I tried!)

Categories