Am I enforced in some way to use move_uploaded_file() and/or delete the temporary file?
My application needs only to load the file contents in memory (eg. via file_get_contents()). Do I need to move it to another directory before? Otherwise, am I required to delete it at the end of the script?
If you don't want to save the uploaded file somewhere, you don't need to use move_uploaded_file(). Read from the file however you like; it'll be deleted automatically by PHP at the end of the request.
Yes, in cases when open_basedir or safe mode (hopefully safe_mode will go out of style eventually) otherwise prevent you to read from the location the uploaded file was saved to. The move_uploaded_file() is aware of those restrictions but only enforce them to the second parameter, so you can move files out of lets say /tmp/ while otherwise you couldn't read that directory.
Related
When uploading a file through PHP - The default behavior of the interpreter is to save the file in a temporary folder, with temporary name.
Then we will have to use the function move_uploaded_file() in order to save it permanently.
If I have access to the php code- is there a way to skip the move_uploaded_file() phase ?
Yes and no. You can specify which directory to put the temporary files in, but not decide on the temporary name yourself.
From the docs:
Files will, by default be stored in the server's default temporary directory, unless another location has been given with the upload_tmp_dir directive in php.ini.
So you can set upload_tmp_dir:
The temporary directory used for storing files when doing file upload. Must be writable by whatever user PHP is running as. If not specified PHP will use the system's default.
If the directory specified here is not writable, PHP falls back to the system default temporary directory. If open_basedir is on, then the system default directory must be allowed for an upload to succeed.
However, this merely decides the directory but not the filename itself.
I think there is pretty solid reasoning why you can't do that:
Concurrency: How would you know if multiple users / multiple processes are trying to write to the same filename that your application logic decides on? This would cause a lot of race conditions if handled differently.
Depending on your operating system and filename escaping, it could also be a huge security risk to have the file named based on user input or application logic. For example, one could try to overwrite the password file /etc/shadow on a Linux-based system and hook into system access.
Furthermore, I personally don't really see any reason why using the process with move_uploaded_file() would be bothersome.
Was wondering if its ok & possible to use rename function isntead of move_uploaded_file. Are there any security issues?
The reason is I am building a File class that will handle all file uploads and file objects. I want to be able to move files between directories when not uploading and I want to have a 1 function called move that does this and I was debating whether I should use move_uploading_file or rename within that function.
I don't believe there are any security differences between the two functions; if security is your primary concern, the main thing to keep in mind is that you verify your allowable size, allowable characters, name length, allowable extensions, etc.
move_uploaded_file() is probably the more specific function for what you want to do, but if you're making a "move" function that extends beyond uploaded files, I would use rename().
What I was trying to say with my comment before was you should do something like this:
function move($frompath, $topath, $isupload)
{
if( $isupload )
{
//frompath should only be filename
move_uploaded_file($frompath, $topath);
}
else
{
//frompath must be fullpath
rename($frompath, $topath);
}
}
If for no other reason than not having to bother with passing in the temp path. But also there is a security concern. From the docs:
move_uploaded_file() is both safe mode and open_basedir aware.
However, restrictions are placed only on the destination path as to
allow the moving of uploaded files in which filename may conflict with
such restrictions. move_uploaded_file() ensures the safety of this
operation by allowing only those files uploaded through PHP to be
moved.
I don't know what all destination paths PHP has blacklisted, but I know it would be a bad idea to be moving Windows dlls to c:\windows\system32. You probably would not be doing that with rename() either, but what if you were, and someone uploaded a dll, and you called rename() instead of move_uploaded_file()? Unlikely, but might as well do things right just in case.
The main difference is that move_uploaded_file() works only for uploaded files.
Quoting the docs:
This function checks to ensure that the file designated by filename
is a valid upload file (meaning that it was uploaded via PHP's HTTP
POST upload mechanism). If the file is valid, it will be moved to the
filename given by destination.
This sort of check is especially important if there is any chance that
anything done with uploaded files could reveal their contents to the
user, or even to other users on the same system.
So, it's a security check, to make sure someone won't try to read your mysql.php file or some other fishy trick.
As for functionality, they're equivalent - except move_uploaded_file() is designed for it's purpose, and so it does some extra security checks.
However, you can not use move_uploaded_file() for other than uploaded files, it will refuse to work.
We are using Zend_Form inside a PHP application for building an input file html element. We can set the 'destination' of this element, and when calling receive() the file will be saved to the specified location.
We want to be able not to save the file to disc at all, but grab the file as a byte array and do something else with it.
Is this possible? If it is not possible with Zend_Form(), can it be done any other way?
EDIT: The reason why we cannot write to disc is because the application runs on Azure, and it seems that it does not have write access rights anywhere, not even in the temp folder. We get an exception from Zend saying that 'The given destination is not writeable'.
The only thing that seems viable would be to save the file using the php://memory protocol.
I've never had reason to implement but it looks a simple as setting the save location of the file to php://memory here is the link to the manual page PHP I/O Wrappers.
All PHP uploads are written to the file system regardless of using Zend or not (see upload_tmp_dir and POST method uploads).
Files will, by default be stored in the server's default temporary
directory, unless another location has been given with the
upload_tmp_dir directive in php.ini.
Instead of using receive to process the upload, try accessing it directly using the $_FILES array which would let you read the file into a string using file_get_contents() or similar functions. You can however, still use Zend_Form to create and handle the form in general.
You could set up shared memory upload_tmp_dir to map a filesystem to memory where uploaded files are held. Be cautious with this as if someone attempts to upload a very large file, it will go into memory which could affect performance or your cost of service.
Ultimately, Zend_File_Transfer_Adapter_Http::receive() calls move_uploaded_file() to move the file from its temporary location to the permanent location. In addition it makes sure the upload is valid and filters it, and marks it as received so it cannot be moved again (as that would fail).
As far as I know, PHP stores all uploaded files in upload_tmp_dir (or the systems default tmp dir, if upload_tmp_dir is not set in the php.ini file).
Then the usual method is to move that file to another place using move_uploaded_file
My question is: Is there a way to to retrieve the file in a variable? So it does not need to be stored on the file system at any time?
Reasons are, that I don't have to clean up the files afterwards and don't have to care about file system permissions.
$contents = file_get_contents($_FILES['name']['tmp_name']);
It is generally safe to leave the temporary file as it is, PHP will take care to delete it at the end of the request (unless PHP crashes hard during your script).
You can probably read the temporary file, convert it to Base64 (for example) and store it on a variable..
I'm uploading files via JS and storing the temp path in the session.
Than i use the following code to move the files.
if(move_uploaded_file($_SESSION['temp_img'][$key]['path'], $dest.$bigimg)){
$dest and $bigimg are defined earlier in the script with the id from the database.
Any Ideas or alternatives ?
MANCHUCK's answer was close but not quite there. You must call move_uploaded_file within the script where the file was uploaded. You cannot do what you're doing, that is, "storing temp path in the session" because that path is only valid for one request.
From the PHP manual:
The file will be deleted from the
temporary directory at the end of the
request if it has not been moved away
or renamed.
(Emphasis mine)
move_uploaded_file checks that a file has been uploaded to that page. You are actually uploading the file to a different PHP script then storing in a session. Instead of using move_upload_file use rename.
What is the output of $_SESSION['temp_img'][$key]['path'], also do you have permission to write to the web directory your placing the files. You may need to set it to 777 for some hosts to allow the webserver to write there.