We are using a linux dedicated server in our company.
Whenever we create a folder with php script, apache is owning the folder and each time I have to connect to server via root in order to change the owner to the user and the permissions
But I don't know which setting I should change in order to fix this.
I tried to switch the safe mode on/off but it didn't work.
I'd be glad if someone could help me
Thanks in advance
Have you tried using the chown PHP command and chmod PHP command?
There are 2 ways to do this:
chown() where you can change the file permissions via executing that function.
or if you are able to move files around using an FTP, you can drag the file outside of the document root (public_html/), and right click -> change file permissions on the file.
CHMODs are what you want to be looking at. 777 will give anyone and everything access to your file, which you can use as a test to make sure you have file permissions. I don't recommend keeping the permissions on 777 at all though.
This is a portability issue and depends on your server configuration (i.e. mod_php or FCGI with SuExec).
You can try using the chown function right after you created the file, but that will only work if you know who the actual owner should be (which is not always the case). To overcome this issue, I wrote a simple method that tries to find the best possible file mode that always assures reading and writing (as well as execution for directories) without giving excessive permissions:
function xChmod($path, $chmod = null) // adapted from phunction
{
if (file_exists($path) === true)
{
if (is_null($chmod) === true)
{
$chmod = (is_dir($path) === true) ? 777 : 666;
if (extension_loaded('posix') === true)
{
$user = posix_getpwuid(posix_getuid());
if (array_key_exists('name', $user) === true)
{
$chmod -= (in_array($user['name'], explode('|', 'apache|httpd|nobody|system|webdaemon|www|www-data')) === true) ? 0 : 22;
}
}
}
return chmod($path, octdec(intval($chmod)));
}
return false;
}
Basically, if you omit the second $chmod argument, it will use 0777 for folders and 0666 for files by default, however, if PHP is being run under a non-standard user, it will decrement the mode by 22, yielding 0755 for folders and 0644 for files. Bare in mind that this will only work for files that already exist, so if you're creating a directory you'll need to have additional precautions.
Related
For some reason all folders created dynamically using my PHP upload script get permission 1354 and then it's not possible to save files inside them.
if(!file_exists($options['uploadDir']) && !is_dir($options['uploadDir'])
&& mkdir($options['uploadDir'], 0750, true))
{
$this->data['hasWarnings'] = true;
$this->data['warnings'] = "A new directory was created in " .
realpath($options['uploadDir']);
}
if(!is_writable($options['uploadDir']))
#chmod($options['uploadDir'], 0750);
I don't know what am I doing wrong.
Check parameters of your http server especially the profile of the user running it and the default user profile of the system. There may be a "umask" set somewhere forcing another permission.
You can try to change the umask with a php command umask.
Also you can check the permission of the parent folders and also check the ownership of your folder.
The following works in windows:
mkdir('../my/folder/somewhere/on/the/server', 0777, true);
I am talking about PHP mkdir.
It works perfectly, and creates the subfolders recursively. However, if I run the same command on a linux server, the folders aren't created.
Previously I solved this by breaking up the path and creating each folder one by one. But I don't want to do that because it should work with the "resurive" flag set to true. Why isn't it working?
Sorry, but there must be some problem apart from the mkdir command itself.
This tiny example works as expected and recursively creates the directories for me when executed on Linux:
#!/usr/bin/php
<?php
mkdir ('testdir/testdir2/testdir3',0777,TRUE);
?>
This are the thing have discovered
Make sure the root path exists
Make sure the root path is writable
Don't use .. always use real path ...
Example
$fixedRoot = __DIR__;
$recusivePath = 'my/folder/somewhere/on/the/server';
if (is_writable($fixedRoot) && is_dir($fixedRoot)) {
mkdir($fixedRoot . DIRECTORY_SEPARATOR . $recusivePath, 0, true);
} else {
trigger_error("can write to that path");
}
Make sure that your PHP user (eg www-data) has permission to write to the parent folders of any folder it is trying to create. PHP needs to be able to write to the lowest one that already exists.
For example, in the case of ../my/folder/somewhere/on/the/server, if ../my already exists and PHP is able to write to .. but not to my, mkdir will fail.
If your user is www-data, you could use sudo chown -R www-data:www-data ../my to give write permission for my and all its subfolders.
I am having problems with functions that create files in the tmp directory such as tmpfile() and tempnam(). They all seem to fail to write to tmp and return false. upload_tmp_dir is set in php ini and file uploads work fine.
When debugging this error I found that sys_get_temp_dir() gets the location of the tmp directory unfortunately it's not supported in my PHP version (5.1.6). I also saw that using the following method replaces the functionality of sys_get_temp_dir():
if ( !function_exists('sys_get_temp_dir')) {
function sys_get_temp_dir() {
if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
$tempfile=tempnam(__FILE__,'');
if (file_exists($tempfile)) {
unlink($tempfile);
return realpath(dirname($tempfile));
}
return null;
}
}
But there is no reference to a tmp directory in the $_ENV array and tempnam() fails as I mentioned before.
Also open_basedir is not set which I've heard can cause similar problems
How can I find out where the tmp directory is or whether it is even set?
Is this a apache server configuration issue or a PHP one?
Thanks for your help
I am running Ubuntu 18.04 and I could create/modify files in the /tmp directory when I ran the PHP script from the CLI, but when I tried accessing the same script as a web page, I could never find the file that was being created. It turns out that Apache by default will create a private tmp directory. The following post provided some insight on the problem Odd Bits - Private /tmp directory. However, the /usr/lib/systemd directory mentioned in the post did not contain any services for http or apache2 on my machine. To help track down the problem I executed the following command:
sudo find / -mount -type f -exec grep -e "PrivateTmp" '{}' ';' -print
and found in /lib/systemd/system/apache2.service the PrivateTmp=true mentioned in the Odd Bits post. Copying the file from /lib/systemd/system to /etc/systemd/system/ and changing true to false and executing
systemctl daemon-restart
systemctl restart apache2
fixed the problem. A person wiser than me suggested copying the file to /etc instead of editing it in /lib was the correct course of action because /lib is 'owned' by the packages and local edits should be performed in /etc. systemd man page describes the systemd configuration processing in gory details.
you can set the upload temp dir in your php.ini -
something like that should work:
upload_tmp_dir=/your-www/tmp/
Also, in case you can't edit the php.ini or don't want to do it globally you can use this in the beginning of your script:
ini_set('upload_tmp_dir','/your-home-www/tmp/');
TMP, TEMP (and maybe TMPDIR) are valid on Windows only and usually pointing to C:\Windows\TEMP. On Linux default temp location is /tmp. To workaround this (works with tempnam() function) you can create a temp folder somewhere within your website space, specify appropriate access permissions and pass this as first parameter to the above function.
Not a great solution but better than nothing.
Probably not the cleanest but this works on my old 5.1.6 install:
function get_temp_path() {
static $path = null;
if ($path !== null) return $path;
$file = tmpfile();
$meta = stream_get_meta_data($file);
fclose($file);
$path = dirname($meta['uri']);
return $path;
}
I have the same problem and the solution is to change the apache configuration to expose the TEMP variable to PHP, see this post.
Tip for newbies like me: I THOUGHT that PHP couldn't move stuff from my temporary folder, but I was just confused because of the relative positions of folders. This may apply to someone else, so I'll explain, even though it's very tangentially related to this specific question (because this specific question is a likely search result for other people like me who are newbies).
My problem is that I was echoing an upload form FROM a functions.php file inside of /var/www/html/ TO a profile.php file in /var/www/html/user/ which CALLED an uploadphoto.php file in /var/www/html/. Uploaded files were ultimately intended to land in /var/www/html/uploads. This ultimately meant that most of my references to both uploadphoto.php AND uploads/ in functions.php were written "../uploadphoto.php" or "../uploads/[etc.jpg]", respectively, in order to step back into html/ from html/user/ (where the echoed code landed in html/user/profile.php). This led me to intuitively use the following command inside of uploadphoto.php without thinking it through:
move_uploaded_file($_FILES["file"]["tmp_name"][0], "../uploads/$filename")
See the problem? uploadphoto.php is in the same directory as uploads/, so I did not need the ../ here. For hours, I was sure I was messing up my folder permissions again, because I am new to image uploading. I had forgotten to check for more simple-minded errors. Hopefully this helps someone else.
I have an easy script to create and delete a folder, but when I try to delete a folder, it brings up and error.
The code:
<?php
if ($_POST['hidden']) {
$key = "../g_test/uploads";
$new_folder = $_POST['nazevS'];
$new_dir_path = $key."/".$new_folder;
$dir = mkdir($new_dir_path);
if($dir)
chmod ($new_dir_path, 0777);
}
if ($_POST['hiddenSS']) {
$key = "../g_test/uploads";
$new_folder = $_POST['nazevS'];
rmdir($key."/".$new_folder);
}
?>
The error msg:
Warning: rmdir(../g_test/uploads/) [function.rmdir]: Permission denied in /home/free/howto.cz/m/mousemys/root/www/g_test/upload.php on line 51
Does anyone know how to delete the folder (hopefuly with everything inside) ?
Also if you see any other improvments, the code could have, feel free to tell me. :-)
Thanks, Mike.
Generally speaking PHP scripts on Unix/Linux run as user "nobody", meaning they need the "all" privileges so it's a permissions problem with the directory. Also, to delete a file or directory in Linux/Unix you need write privileges on the parent directory. That might be your problem.
If you have problems with the files or directories you create, use chmod() on them to set the right permissions.
Also it might not be empty.
Also, it's worth mentioning that
$new_folder = $_POST['nazevS'];
$new_dir_path = $key."/".$new_folder;
is really bad from a security point of view. Sanitize that input.
For the purpose of this answer, I will put the security risks of allowing any and all uploads in a directory aside. I know it's not secure, but I feel this issue is outside the scope of the original question.
As everybody said, it can be a permission problem. But since you've created the directory in your code (which is most likely running as the same user when deleted). It doubt it is that.
To delete a directory, you need to make sure that:
You have proper permissions (as everyone pointed out).
All directory handles must be closed prior to deletion.
(leaving handles open can cause Permission denied errors)
The directory must be empty. rmdir() only deletes the directory, not the files inside. So it can't do its job if there is still stuff inside.
To fix number 2, it is extremely simple. If you are using something like this:
$hd = opendir($mydir);
Close your handle prior to deletion:
closedir($hd);
For number 3, what you want to do is called a recursive delete. You can use the following function to achieve this:
function force_rmdir($path) {
if (!file_exists($path)) return false;
if (is_file($path) || is_link($path)) {
return unlink($path);
}
if (is_dir($path)) {
$path = rtrim($path, DIR_SEPARATOR) . DIR_SEPARATOR;
$result = true;
$dir = new DirectoryIterator($path);
foreach ($dir as $file) {
if (!$file->isDot()) {
$result &= force_rmdir($path . $file->getFilename(), false, $sizeErased);
}
}
$result &= rmdir($path);
return $result;
}
}
It looks like you need access rights on the folder you're trying to edit.
To change this:
chmod ug+rw /home/free/howto.cz/m/mousemys/root/www/g_test/
or maybe you'll need to do
sudo chmod ug+rw /home/free/howto.cz/m/mousemys/root/www/g_test/
Make sure that this is what you want to do and that your application is secure. Don't give write rights to any application since it could lead to security issues.
The webserver requires write access to the folder you're trying to delete. You can provide this with:
chgrp -R www-data g_test/uploads
chmod g+w g_test/uploads
where www-data is the user that the webserver runs under (may be apache or some variation depending on your OS and server installation). After this you can run rmdir (or rm -r if the directory isn't empty).
Also, keep in mind that giving the web server the ability to write to a directory posses security problems. In certain situations, this could allow a malicious user to run arbitrary code (i.e. take over your machine), or modify your website (i.e. server spyware).
For these reasons, you should only give dirs write perms that:
absolutely need them
don't contain source code
are outside the dir containing scripts
owned by the server
In this setup on a production machine, you could set up a separate directory just for this type of file, that only Apache can write to. If you have to deploy files to this directory, use sudo or the root account to do so to limit the accounts that have access.
For a more complete description of what I mean, have a look at the security tips section in the Apache documentation.
I have set file permissions to 777 yet I cannot write to the file with PHP.
I can clearly see in my FTP client that the file has 0777 permissions and when I do:
echo (true === is_writable('file.txt')) ? 'yes' : 'no';
I get 'no';
I also tried:
echo (true === chmod('file.txt', 0777)) ? 'yes' : 'no';
With the same result.
The directory listing goes something like this:
public_html
public 0777
css 0755
js 0755
file.txt 0777
And I'm using .htaccess file to redirect all traffic to the public subfolder. Of course, I have excluded the file from rewriting (it is accessible from the browser I checked):
RewriteRule ^(file).* - [L]
Why is that?
I guess Apache runs as a different user/group than the user/group owning the file. In which case, the file itself needs to be 0777.
public only needs to be 0777 if you plan on adding files to the folder using PHP. Even if the folder itself is not 0777, if the file is and the folder has at least 5 for the user (read/execute), you should be able to write to the file.
In the end, your file tree should look like this:
public_html
public
file.txt 0777
Naturally, you won't be able to change those permissions using PHP, but you can do so from your FTP client.
If it still isn't working, PHP might be running in safe mode or you might be using an extension such as PHP Suhosin. You might get better result changing the owner of the file to the same user/group that is running the script.
To get the user/group id of the executing user, you may use the following:
<?php
echo getmyuid().':'.getmygid(); //ex:. 0:0
?>
Then, you may use chown (in the terminal) to change the owner of the file:
> chown 0:0 file.txt
In opencart i faced this error after installing vqmod and giving all necessary permissions.
after researching a bit, found it.
"MODS CACHE PATH NOT WRITEABLE" is actually refering to vqmod folder itself and not the cache folder.
sudo chmod -R 777 vqmod
in your root directory.....
You have to chmod the file right after you create it.
function Doo_Chmod($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;
}
Not strictly related to the above question, still, I will put it here for future visitors, as I came here reading the title.
From arch wiki:
File attributes
Apart from the file mode bits that control user and group read, write
and execute permissions, several file systems support file attributes
that enable further customization of allowable file operations. This
section describes some of these attributes and how to work with them.
Warning: By default, file attributes are not preserved by cp, rsync,
and other similar programs. chattr and lsattr
For ext2 and ext3 file systems, the e2fsprogs package contains the
programs lsattr and chattr that list and change a file's attributes,
respectively. Though some are not honored by all file systems, the
available attributes are:
a: append only
c: compressed
d: no dump
e: extent format
i: immutable
j: data journalling
s: secure deletion
t: no tail-merging
u: undeletable
A: no atime updates
C: no copy on write
D: synchronous directory updates
S: synchronous updates
T: top of directory hierarchy
For example, if you want to set the immutable bit on some file, use
the following command:
# chattr +i /path/to/file
To remove an attribute on a file just change + to -.
For a file, with no additional attributes, the lsattr looks like this:
$ lsattr /etc/hosts
-------------e- /etc/hosts