In short, the following code is meant to create a directory structure like:
>Attachments
>Lot
>Layer
The Attachments directory is fixed. The Lot comes out with 0777 permissions. The Layer directory does not. I added the chmod lines after concern that perhaps umask was at fault, but it didn't change anything.
// Create directory for this entry's attachments if needed.
$attachment_dir = $config_ini['OOCDB_defaults']['attachment_dir'];
$attachment_lot_dir = $attachment_dir.$txtLotID."/";
$attachment_lot_layer_dir = $attachment_lot_dir . $txtLayer."/";
if(!is_dir($attachment_lot_dir)){
mkdir($attachment_lot_dir , 0777);
}
if(!is_dir($attachment_lot_layer_dir )){
mkdir($attachment_lot_layer_dir , 0777);
}
chmod($attachment_lot_dir ,0777);
chmod($attachment_lot_layer ,0777);
$sleuthFile = $attachment_lot_layer_dir . "makeSleuthImg.txt";
$fp = fopen($sleuthFile,"w") or die("unable to open File! <br>");
//Write the string to the file and close it.
You have a typographical error:
$attachment_lot_layer_dir = $attachment_lot_dir . $txtLayer."/";
...
chmod($attachment_lot_layer ,0777);
That variable does not exist, so yes that will never work. PHP's mkdir respects umask in Linux (assuming you're on Linux otherwise this wouldn't be happening), so your directories are not being created at 0777 mask as requested; however chmod does not respect umask, so your first call to chmod is in fact changing this directory's mask to 0777. The second call is failing due to the bad variable name. Hence the behavior you're seeing.
FWIW, mkdir has a second optional, boolean parameter that will allow you to recursively create a directory structure in a single call by passing it the full directory path (see here). You should also look at this question to understand what to do with umask before calling mkdir if you want to avoid the subsequent calls to chmod entirely.
Related
I'm trying to create a directory on my server using PHP with the command:
mkdir("test", 0777);
But it doesn't give full permissions, only these:
rwxr-xr-x
The mode is modified by your current umask, which is 022 in this case.
The way the umask works is a subtractive one. You take the initial permission given to mkdir and subtract the umask to get the actual permission:
0777
- 0022
======
0755 = rwxr-xr-x.
If you don't want this to happen, you need to set your umask temporarily to zero so it has no effect. You can do this with the following snippet:
$oldmask = umask(0);
mkdir("test", 0777);
umask($oldmask);
The first line changes the umask to zero while storing the previous one into $oldmask. The second line makes the directory using the desired permissions and (now irrelevant) umask. The third line restores the umask to what it was originally.
See the PHP doco for umask and mkdir for more details.
The creation of files and directories is affected by the setting of umask. You can create files with a particular set of permissions by manipulating umask as follows :-
$old = umask(0);
mkdir("test", 0777);
umask($old);
Avoid using this function in multithreaded webservers. It is better to change the file permissions with chmod() after creating the file.
Example:
$dir = "test";
$permit = 0777;
mkdir($dir);
chmod($dir, $permit);
For those who tried
mkdir('path', 777);
and it did not work.
It is because, apparently, the 0 preceding the file mode is very important which tells chmod to interpret the passed number as an Octal instead of a decimal.
Reference
Ps. This is not a solution to the question but only an add-on to the accepted anwser
Probably, your umask is set to exclude those
In my case, I have to use the following way for centos7, which solved the problem
$oldmask = umask(000);//it will set the new umask and returns the old one
mkdir("test", 0777);
umask($oldmask);//reset the old umask
More details can be found at
https://www.php.net/manual/en/function.umask.php
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 can't understand why I have to use chmod to get the correct permissions..
The file is created succesfully but with 0755 and not 0775 that I specify in mkdir .
( http://php.net/manual/en/function.mkdir.php )
I have to do chmod after mkdir to set the correct permissions.
Safe mode is off in php.ini and the folder belongs to php's group and owner (www-data)
This doesn't work:
if(!is_dir("/var/www/customers/$username/$project_name"))
{
mkdir("/var/www/customers/$username/$project_name",0775);
}
But this does:
if(!is_dir("/var/www/customers/$username/$project_name"))
{
mkdir("/var/www/customers/$username/$project_name");
chmod("/var/www/customers/$username/$project_name",0775);
}
Yes, it's because of umask...
from comments of docs: http://php.net/manual/en/function.mkdir.php
You might notice that when you create
a new directory using this code:
mkdir($dir, 0777);
The created folder actually has
permissions of 0755, instead of the
specified
0777. Why is this you ask? Because of umask(): http://php.net/manual/en/function.umask.php
The default value of umask, at least
on my setup, is 18. Which is 22 octal,
or
0022. This means that when you use mkdir() to CHMOD the created folder to
0777, PHP takes 0777 and substracts
the current value of umask, in our
case 0022, so the result is 0755 -
which is not what you wanted,
probably.
The "fix" for this is simple, include
this line:
$old_umask = umask(0);
Right before creating a folder with
mkdir() to have the actual value you
put be used as the CHMOD. If you would
like to return umask to its original
value when you're done, use this:
umask($old_umask);
I think you may have to modify your umask.
As noted on the mkdir manpage:
The mode is also modified by the current umask, which you can change using umask().
Now, looking at the umask() manpage, one of the comment listed confirms my inner thought:
"It is better to change the file permissions with chmod() after creating the file."
In other words, I believe the way you are doing it is more secure:
Set your umask so that files are created private to your user, then use chmod to open them up.
Try calling this function before you make your directory: clearstatcache(); Also, maybe you should check if you can do it using just mkdir if you siwtch to another user.
Figured PHP's rename would be my best bet. I didn't see many examples on how to use relative URLs in it though, so I kind of compromised. Either way, this give me permission denied:
I want to do this:
$file = "../data.csv";
rename("$file", "../history/newname.csv");
Where ../ of course would go back 1 directory from where the script is being ran. I couldn't figure out a way...so I did this instead:
$file = "data.csv";
$path = dirname(realpath("../".$file));
rename("$path/$file", "$path/history/newname.csv");
However I am getting permission denied (yes the history folder is owned by www-data, and yes data.csv is owned by www-data). I thought it was weird so I tried a simple test:
rename( 'tempfile.txt', 'tempfile2.txt' );
and I made sure www-data had full control over tempfile.txt...still got permission denied. Why? does the file your renaming it to have to exist? can you not rename like linux's mv? So I instead just copy() and unlink()?
In order to move a file from "../" to "../history/", a process needs write permission to both "../" and "../history/".
In your example, you're obviously lacking write permission to "../". Permissions for the file being moved are not relevant, by the way.
Not only ownership plays a role, but also file permissions. Make sure that the permissions are set up correctly on the source file and destination directory (e.g. chmod 644 data.csv).
Is www-data the same user as Apache?
Edit: Take care to provide existing, absolute paths to realpath(). Also beware of the following:
$path = dirname(realpath("../".$file));
This might yield nothing, because the file ../data.csv might not exist. I.e., the result of realpath() on a non-existent file is false.
Here's some code that might work better for you:
$file = "data.csv";
$path1 = realpath($file);
$path2 = realpath(dirname($file).'/..').'/history/newname.csv';
rename($path1, $path2);
You should be extremely careful that $file cannot be edited by the visitor, because he could change a request manipulate which file is renamed to where.
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.