In this post I will describe how to upload and store a file in the database. Yes, you read correct, I will describe how to store a file in the database. I know, a lot of people do not recommend storing files in a database due to performance reasons. Of course, this is an important point you have to consider when you design your application. The reasons why I store files often in the database are:
- all data are stored in one place: the database
- it is easier to test
- it is easier to develop as I do not have to keep database and file system in sync
Enough of bla-bla, let us dive in the code. First the table definition for MySQL:
CREATE TABLE my_files ( id INT(11) NOT NULL AUTO_INCREMENT, name VARCHAR(75) NOT NULL, type VARCHAR(255) NOT NULL, size INT(11) NOT NULL, data MEDIUMBLOB NOT NULL, created DATETIME, modified DATETIME, PRIMARY KEY (id) );
Note: Use MEDIUMBLOB or LONGBLOB as data type unless you know for sure that the file size of the uploaded files is never bigger than 64kB.
The model is straight-forward:
// app/models/my_file.php class MyFile extends AppModel { var $name = 'MyFile'; }
We omit the controller for the moment and create directly the view:
// app/views/my_files/add.ctp (Cake 1.2) <?php echo $form->create('MyFile', array('action' => 'add', 'type' => 'file')); echo $form->file('File'); echo $form->submit('Upload'); echo $form->end(); ?> // app/views/my_files/add.thtml (Cake 1.1) <form action="/my_files/add" enctype="multipart/form-data" method="post"> <?php echo $html->file('File'); ?> <?php echo $html->submit('Upload'); ?> </form>
So, now we are ready to build the controller and to implement the add() function:
// app/controllers/my_files_controller.php (Cake 1.2) class MyFilesController extends AppController { function add() { if (!empty($this->data) && is_uploaded_file($this->data['MyFile']['File']['tmp_name'])) { $fileData = fread(fopen($this->data['MyFile']['File']['tmp_name'], "r"), $this->data['MyFile']['File']['size']); $this->data['MyFile']['name'] = $this->data['MyFile']['File']['name']; $this->data['MyFile']['type'] = $this->data['MyFile']['File']['type']; $this->data['MyFile']['size'] = $this->data['MyFile']['File']['size']; $this->data['MyFile']['data'] = $fileData; $this->MyFile->save($this->data); $this->redirect('somecontroller/someaction'); } } } // app/controllers/my_files_controller.php (Cake 1.1) class MyFilesController extends AppController { function add() { if (!empty($this->params['form']) && is_uploaded_file($this->params['form']['File']['tmp_name'])) { $fileData = fread(fopen($this->params['form']['File']['tmp_name'], "r"), $this->params['form']['File']['size']); $this->params['form']['File']['data'] = $fileData; $this->MyFile->save($this->params['form']['File']); $this->redirect('somecontroller/someaction'); } } }
Easy, isn’t it? Up to now we have stored the file in the database. To retrieve the file from the database, we need a download() action which we add to our controller:
function download($id) { Configure::write('debug', 0); $file = $this->MyFile->findById($id); header('Content-type: ' . $file['MyFile']['type']); header('Content-length: ' . $file['MyFile']['size']); // some people reported problems with this line (see the comments), commenting out this line helped in those cases header('Content-Disposition: attachment; filename="'.$file['MyFile']['name'].'"'); echo $file['MyFile']['data']; exit(); }
Well, I know that this action is probably not very cake-like, the proper way would be to use a layout and a view, but this way I have less to write ;-)
So, that’s it. We have finished our very simple upload/download application.
Update (2006-08-05): Fixed a security hole in the code above, see also “Be careful with file uploads”. Thanks to Lamby.
Update (2007-06-09): Fixed a small bug in the download function. Thanks to Wilhelm Raab!
Update (2007-10-15): The name “File” led to problems with the core class with the same name, hence I renamed table name, model name, etc. Thanks to “fyi” for the hint!
Update (2007-12-11): Updated for CakePHP 1.2.
Update (2009-02-20): Adding comment to the header(‘Content-length’) statement in the download method
[…] Re: Newbie file upload question Posted by News On February 1st, 2011 / No Comments Hi there This should be helpful: [link] […]
Thanks for the tutorial!
@H-man: I had the whitespace on the start of the output as well. I checked my custom App_Controller.php which had an empty space on it’s end. (after the })
@SitePunk: You are welcome :)
Hi,
After modifying selenium-api.js file, i have created selenium-server.jar file by following command.
jar -cvf selenium-sevrer.jar selenium-server
But when I am trying to start selenium server, I am getting following error.
D:\krajendr\Desktop\debug>java -jar seleniumserver.jar
Failed to load Main-Class manifest attribute from
seleniumserver.jar
D:\krajendr\Desktop\debug>
please let me know the solution, if anyone knows.
hi I try to validate file type is doesn’t work
var $validate = array(
‘type’ => array(
‘checktypeedit’ =>array(
‘rule’ => array(‘checkType’,false),
‘message’ => ‘Invalid File type’,
)
)
);
function checkType($data, $required = false){
$data = array_shift($data);
if(!$required && $data[‘error’] == 4){
return true;
}
$allowedMime = array(‘application/x-bittorrent’);
if(!in_array($data[‘type’], $allowedMime)){
return false;
}
return true;
}
it’ doesn’t work what is the right way
@taqman: Hm, is the checkType() method called? If the method is not called, then the $data array you pass to the save() method probably has the wrong structure. As you can see in the add() method in the article, I have to convert the form data to the structure expected by CakePHP’s save() method.
Hope this helps!
@cakebaker thank for answer but your code is useful but the UI
doesn’t friendly I try to apply to
http://pixelcone.com/tutorial/ajax-file-upload-using-jquery-and-cakephp-media-plugin/
I don’t want media plugin and try to insert you code separate in controller this code http://bin.cakephp.org/view/1830824100
but when I upload always failed although match in validate
can you help me to fix it
@taqman: As I mentioned in my previous comment, I would first check whether your checkType() method gets called. If it is called, I would then check the content of the $data variable, especially the call of array_shift() looks a bit suspicious to me.
Hope this brings you one step further.
hi again cakebaker
I have apply your download function
I have question how to fix it to work and I need counter download
thank
@taqman: Hm, what doesn’t work with the snippet you posted?
To count the downloads you have to use something like:
Hope this helps!
The code to upload file in PHP is very simple, but we need to understand the flow which is a below.
1. Browse the file from a local system
2. Upload to server
3. Server keeps it on a temporary path
5. Copy from temporary to permanent path
Create a file upload form
Filename:
Note:
* An enctype attribute of the tag has been specified.
* This attribute specifies which content-type to use when submitting the form
* We have used “multipart/form-data†to upload binary data, like the contents of a file, to be uploaded
* If proper enctype is not provided, upload will not work.
* File upload is a huge security risk so you must check what type of files are being uploade
Create a file upload script (upload-file.php)
This will upload the file to the specified path.
Note:
* The default file upload size using a browser is usually 2MB so files larger than this size may not upload. You will have to alter the file upload setting on the server.
* You need to set write permission to the folder where file needs to be upload.
* In our case, the “uploads†folder needs to have a 777 permission on a linux/unix server.
Source:
http://phphelp.co/2012/05/18/how-to-upload-a-file-in-php/
@Aneeq: Thanks for your comment!
[…] http://cakebaker.42dh.com/2006/04/15/file-upload-with-cakephp/ Above one use database, I don’t wanna use database to store files. And it use cakephp 1.x which cannot run in 2.x. […]
please i need a code that enable me upload and output image(like passport photograph) from Database to the browser i have stalled up 2 project because of this
Good afternoon, I’m newbie with cakephp and the version I have is 1.3, you have the code for that version? thanks
I used this in a cake 2.5.5 project. I had problems using download function for images. I got an extra character in the beginning of the body. It had nothing to do with the addslashes suggestions, but it had to do with flushing the output buffer. i used this to solve the problem: