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).
Related
In the manual I can see it says something about security reasons, but I didn't quite understand what is the problematic situation.
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 makes sure it was uploaded via PHP, but if it will not check that, what could happen? what information could be revealed, and how?
Can someone explain this? An example will be great.
A PHP script will likely move files around whose name is determined at runtime (the name of a temporary file that has just been uploaded). The check is meant to ensure that poorly-written scripts don't expose system files, or files containing authentication secrets.
Suppose I write a script that lets you upload an image to my server, enhance it by embedding some super-cute cat gifs that I provide, and download it again. To keep track of which image you are working on, I embed the file name in the request URLs for my edit buttons:
http://example.com/add-kitty.php?img=ato3508.png&add=kitty31.gif
Or maybe I embed the same information in a cookie or POST data, wrongly thinking that this makes it more secure. Then some moderately enterprising script kiddie comes by and tries this (or the POST/cookie equivalent):
http://example.com/add-kitty.php?img=$2Fetc%2Fpasswd&add=kitty31.gif
See it? That's the path /etc/passwd, url-encoded. Oops! You may have just made your /etc/passwd file available for download, with a little kitty noise in the middle.
Obviously this is not a full working exploit for anything, but I trust you get the idea: The move_uploaded_file function makes the extra check to protect you from attacks that will inject an unintended filename into your code.
The security issue in this case is the upload directory will be visible to public.
To avoid this case, you need to configure your web server such as Apache to make the directory forbidden to public.
Also, whenever you upload file through PHP script, rename files with mixed characters.
For example, you could use encrypted timestamps combined with actual file name.
It seems to be conventional to handle file uploads. You could stick with this way to handle file uploads securely.
EDITED:
This answer is edited as per your question in the comment.
You need to have an existing file within any of your www directory to rename it with rename($existing_old_file_name, $new_file_name) function.
move_uploaded_file($tmp_uploaded_file_name, $new_file_name) function moves the uploaded file from the tmp directory to the destination you specify as a second parameter in the function.
I want to upload file in laravel, I am using only local server and but not any cloud storage.
From doc,I found two methods related with file upload,
Normal method (Request::file('file')->move(dest,filename))
Using File system
But I could not understand actual difference between these methods?
If I am using normal method,
$file->move('path', $fileName);
Here where should be path located,storage/app or public/uploads(new)?
How can I upload files using File System ?
The "normal" method allows you to save the uploaded file only in the local filesystem in any place you choose, as long as PHP has write access to that location. This method can only be used for "save" operation and only for uploaded files.
The "filesystem" method is more flexible as it adds a layer of abstraction over the place you write to. Filesystem configuration is stored in a separate config and is transparent to your code. You can easily change the underlying storage (e.g. from local to cloud) or change paths without any changes to the code. The filesystem also gives you a lot of additional helper methods to operate on files it store, like list all files, checking existence, removing. Additional advantage is that it can be used to any files, not only the ones uploaded by the user during current request.
Answering your second question: you decide where to store files in both normal and filesystem method. In the normal method you pass the path, in filesystem you configure the paths using filesystems.php config.
And how to upload the file using File systems? You don't use the filesystem to upload the file, you use it to save the uploaded file. The upload process is the same, but instead of calling $uploadedFile->move() you do:
Storage::put('file key', file_get_contents(Request::file('file')->getRealPath()));
the difference between these two methods is about usage.
You use the "File System" service to work on your local/cloud file system, like creating, moving or deleting file. You could use the Storage::put() method to store the uploaded file, of course, but you would have to get the file from the request either way. So you normally just use the $request->file('photo')->move($destinationPath); method as specified in http://laravel.com/docs/5.1/requests#files to move the file where you want it to be. The File system service is not meant to handle uploads itself. That is what the Request is for.
The question about where you put the files is one you have to answer yourself. The default path for storing files is storage/app. You can put them to public/uploads but it is discouraged as anyone knowing the URL can download the files. It really depends on what the file is meant to. If it is a say profile picture then it can be put in public/uploads. Is the file private then is should not be put there but instead in storage/app.
I need to allow a small subset of users on my GAE-hosted PHP site to upload files (tarballs of python scripts, typically ~25k in size). Given the tiny footprint of each file and relative infrequency of access to this particular table, I just want to store the files in my CloudSQL DB as a varbinary or mediumblob. It also makes cleaning up old files a lot easier.
I can find a lot of docs discussing the use of cloud storage buckets, but nothing on storage into a SQL DB. var_dump ($_POST) returns the rest of the form fields (as expected) but var_dump ($_FILES) returns undefined - I suppose because this is dependent on a filesystem write for the temporary version of the uploaded file, and GAEPHP doesn't allow filesystem writes.
Any way to make this work or am I doomed to using a CloudStorage bucket and keeping the path in the table? Could I use javascript to convert the tarball to a binary stream client side and POST as text or something in a hidden field?
Appreciate any ideas!
Edit with a secondary issue: phpinfo lists file_uploads = 'Off'. I've tried setting it in php.ini as = 1 and = '1' and neither seems to take effect. Other settings changes in php.ini are taking effect. Wondering if this was listed as a configurable param in error?
You should try direct file uploads in this case: https://gae-php-tips.appspot.com/2015/03/09/direct-file-uploads-for-php-5-5/
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..
Is it possible in PHP to configure it to somehow not save files to disk at all? As a matter of fact, the best thing would be to get the script going before even reading the entire POST body. (Keeping my hopes high ;))
You can turn off file uploads via a configuration setting in PHP.
http://php.net/manual/en/ini.core.php#ini.file-uploads
PHP needs a place to temporarily store the files content for you to be able to interact with it through PHP - although, you don't have to do anything else other then access the temporary file to get the data:
$content = file_get_contents($_FILES["user_file"]["tmp_name"]);
From here on you can manipulate with the files content without having to move the uploaded file to another location before accessing it.
You can use HTTP PUT requests to directly upload a file. PHP will not handle the upload directly (e.g. set it up in $_FILES). Instead, you have to read the raw bytes from the php://input pseudo-url and from there can do whatever you want.
There's some details and examples here.