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.
Related
I have recently been struggling with removal of symlinked folders with content on windows in PHP.
The process I am doing is:
1. symlink files/folders from location A to location B (all good)
2. unlink all files/folders from location B
Now this is where things get tricky.
My code:
echo("\n unlinking: ".$pre.$folder.'/'.$elem);
if(file_exists($pre.$folder.'/'.$elem)){
if(isWindows()){
if(is_dir($pre.$folder.'/'.$elem)){
rmdir($pre.$folder.'/'.$elem);
} else {
unlink($pre.$folder.'/'.$elem);
}
} else {
unlink($pre.$folder.'/'.$elem);
}
} else {
echo("\n -> Not there. \n");
}
Everything works properly if the target is a file or an empty folder. When the symlinked folder has contents however, I get a warning that I can't remove a non-empty folder and the folder is not removed.
Warning: rmdir(dirname): Directory not empty
Which means that a symlinked folder with contents on windows is non-removable when using rmdir(the recommended operation).
I can remove that folder manually in windows explorer and that works properly(removes a symlink only).
Would appreciate help,
Sivael.
When deleting a symlink, you need to treat it as a file, not a directory. So, you need to use unlink, rather than rmdir!
HTH :)
Found out what was going on.
It turns out that it was not PHP related after all - those folders were under version control in TortoiseSVN and NetBeans, which happened to mess with the symlinks somehow.
Can't replicate the behaviour now.
Thanks:)
so I am writing this bit of code that needs to create a folder in a specified directory.
public function createFolder () {
opendir("images/u");
mkdir("/nick", 0755, true);
if (false){
echo "the directry could not be made";
}//end if
}//end createFolder
The problem is that Apache lacks the necessary permissions to perform the mkdir function. Now, there has been at least one other question similar to this that has been answered, but I do not find the answer satisfactory. I would like to know how I give Apache permissions without opening my directory up to everyone (i.e. chmod 0777).
Your opendir call does nothing, since you're not saving the result anywhere.
You're trying to create the directory /nick. I.e. in the root folder. You should certainly not be giving Apache permissions for the root folder. More likely your path is simply wrong. You either mean ./nick as relative to the current working directory, or __DIR__ . '/nick' as relative to the file's path or some other directory. But simply: you're using the wrong path to create your directory.
I have a working drupal batch process. In it I want to copy image files (JPGs) from a source directory into a target directory with PHP copy function. Both the directories exist. The source file does exist, too. But the copy does not succeed.
I checked for the file permissions of the source directory (0755) and the source file (0744) and the target directory (0755). The owner and group are that of the script.
I debugged by putting the success of the copy into watchdog. It says it was successfull. But the file is not there.
This is the code where the copy takes place
$copy_from = $_SERVER["DOCUMENT_ROOT"]."/".$file->filepath;
$copy_to = $_SERVER["DOCUMENT_ROOT"]."/".$path_new;
$success = false;
if (file_exists($copy_from)) {
$success = copy($copy_from, $copy_to);
watchdog('catalog_copy2', ($success ? 'yes' : 'no')
. ' | ' . "copy('{$copy_from}', '{$copy_to}')");
}
If I copy the watchdog output and edit it slightly to end up in an shell copy order
cp path/to/file dest_path
The file is copied with no fuzz at all. So no typos and no case sensitive issues are in order.
I'm clearly nearly out of my mind, because I do not understand why I cannot copy the files with PHP.
Strange thing though is, some of the files are copied with my batch and some are not.
I'd be grateful for any hint where to look for to find a solution.
edit
I've worked around the problem by using the shell cp command using php's exec command. I'm not happy with this, but I had to make it work.
edit
I circumvented the problem by using the API function from the file_field module
the problem was not solved, but I managed to use the API functions from the file_field modules which works perfectly
i was using this basic script:
$folderPath = "../path/to/$folder/";
mkdir("$folderPath");
i create this directory and then upload photos to it. I've been doing this for a good 4-5 months now and suddenly i start getting 'FORBIDDEN' errors when I attempt to view the contents of the folder via web browser
The directory is being created the same and the photos are still uploading without a problem, but I cannot access the photos
I tried rewriting the script and using chmod to change the permissions but I'm having no luck at all
All the older folders were being created with: -w- rwx r-x r-x
and I can't get this recreated
I've tried adding a chmod line into my script:
$folderPath = "../sales/inventory/$folder/";
mkdir("$folderPath");
chmod("$folderPath", 0755);
but I can't recreate the same permissions, I'm trying to understand how chmod works, but I can't figure out how to get this very basic function working properly again
Try looking out for a HTAccess file, where the "Options -Indexes" option will be mentioned, as this is mostly used for not showing the contents of a folder in a web browser. The file needs to be searched in the following manner:-
In the folder "root_folder/sales/inventory/$folder/", where "$folder" is as mentioned in your code.
If not found, try in the folder "root_folder/sales/inventory/".
If not found, try in the folder "root_folder/sales/".
If not found, try in the folder "root_folder/".
When you get the code of "Options -Indexes" written in the HTAccess file, you can remove / comment that line of code from there, or you can also write another HTAccess file in your required folder of "$folder", where the code will be "Options Indexes".
Also in the PHP page, the logic must be like this:-
<?php
$folderPath = "../sales/inventory/$folder/";
mkdir("$folderPath");
chmod("$folderPath", 0755);
// Use of "copy()" / "move_uploaded_file()" function here, using some "$targetFile" variable.
chmod($targetFile, 0755);
?>
This will help you when you will be unlinking / deleting the uploaded files from the "$folder" folder.
Hope it helps.
If your $folder variable includes some sub-directories your parent directories are maybe not being chmoded to the right permissions. This was the problem I was having on a hired OVH Gentoo server.
Imagine that $folder = '/store1/ally23/shelf42'; so your final directory structure is
../sales/inventory/store1/ally23/shelf42, and you want 0777 permisions.
You do:
mkdir($folderPath, 0777, true) || chmod($folderPath, 0777);
Only the final directory shelf42 is chmoded to 0777. The intermediary directories are created with default permissions (in my case 0744).
There is no recursive option in PHP's chmod command, so you have to loop over the intermediary directories and chmod them individually.
If you're in a shared environment, you may also want to chown after upload, to be on the safe side. Especially if you're running your web server under a user other than your virtual host has permission to access (EG: "nobody" vs "mysite".) This is common with cPanel servers, FWIW.
Simply umask means the default permissions for new files/directories:
<?php
umask(022);
?>
This sets the default permissions for user, groups, and others respectively:
0 - read, write and execute
1 - read and write
2 - read and execute
3 - read only
4 - write and execute
5 - write only
6 - execute only
7 - no permissions
I'm writing a PHP function that will delete all the files in the directory that's passed to it (and eventually, possibly expand it to a recursive delete). To be safe, I want to make sure that, through a bug or something, I don't try to delete anything if the directory passed in is the root directory.
File permissions should protect me to a large extent, but just in case, and especially if I expand it to a recursive delete I just want to take that extra step.
As a complicating factor, this code may be run in a windows machine or a linux machine, so the root directory may look like 'C:\' or '/'. I assume there are other ways that really refer to the root as well, possibly 'c:\temp..'
So, is there a reliable way in PHP to recognize that a dir spec resolves to the root of the file system?
Elaboration...
I'm writing PHPUnit tests for a web app and I'm trying to create a framework where the state of the app is backed up before the tests are run and restored afterwards. The app allows users to upload files. Depending on what the file is it is copied to one of several possible directories.
To save and restore the state of the app those directories need to be copied somewhere, the tests run, then the directories need to have their files deleted and retreived from the backup.
The location of these directories can vary from one machine to another and I know that some people put them outside of the web app. There is a configuration file that can be read by the test that gives the location of those directories for the given machine.
If I don't restrict all these directories to a specific dir tree it's difficult to do the jailing. If I do restrict these directories to a specific dir tree then some people will have to reconfigure their machines.
You should have a defined root folder, which you never go above, a.k.a. jailing. The root folder is not the only folder where severe damage can be done.
Edit.
Although I still advocate using some sort of jailing, I suppose you could recognize the root folder by stripping out any drive-letters and translating \ to /. The root folder would then always be a single /.
function isRootFolder($dirpath) {
list($drive, $path) = explode(':', str_replace('\\', '/', $dirpath), 2);
return $path == '/';
}
Try, this function:
function is_root_dir($path)
{
$clean_path = realpath($path);
if($clean_path == '/' || preg_match('/[a-z]:\\/i', $clean_path))
{
return true;
}
else
{
return false;
}
}
It's not tested, I just wrote it in the editor here. realpath() resolves the path, folowing simbolic links and resolving stuff like: c:\temp.. == c:\
Edit: In the end you should folow the advice that nikc gave you, define a list of directories that are safe to delete.
I use this:
if (dirname($target)==$target) { // you're at the root dir
(is portable between Microsoft and everything else)
C.