Google Ad

CakePHP File Upload Plugin

Date: Sat, Aug 29th 2009, 10:47 Author: nick Views: 139787 Comments share

CakePHP File Upload Plugin

Get it:
  • Download Now
  • git clone git:// file_upload
The popular FileUploadComponent is now a plugin.

Version 4.0 brings a new behavior to the plugin to round out all your file uploading needs.

Version 6.0 Security Release. Read more about it here:

Legacy Version: Due to the new settings class and required API changes in 4.0, I've created a legacy zip of the File Upload Plugin version 3.6.3 (the most recent version before the API changes). Those of you looking for the old file upload plugin here is version 3.6.3:


copy the file_upload directory into your app/plugins/ directory

CHANGELOG: 6.1.1: Allow users to change the uploadDir outside of WEB_ROOT by changing setting forceWebroot to false in the configuration. Default is still webroot/files. Updated typos in the README.txt
6.0.0: Change the way file uploads types are checked. Now checking extension along with filetypes.
: ****** Please read migration guide. migration_guide_5_0_x_to_6_0_x.txt ******
5.0.1: Fixed a bug that would continue a file upload if the fileName returned false after a filename callback.
5.0.0: Major release tag
4.4.0: Added new fileName manipulation callbacks and settings
4.3.0: Added a new 'maxFileSize' validation key.
4.2.0: Added a new 'required' key in Behavior settings that would produce a validation error if a file wasn't uploaded.
4.1.2: Fixed a regression, passing in custom settings to the helper now changes those settings.
4.1.1: Bug fix displaying correct image path for Windows Servers.
4.1.0: Added validation errors for the behavior. If an error is accurded durring an upload a validation error is thrown and presented to the user.
4.0.4: Bug fix, Undefined index notice within same controller on different form without an upload at all.
4.0.3: Bug fix, using wrong option in removeFile method.
4.0.2: Bug fix, uploading non-model files now returns proper array of files to be uploaded.
4.0.1: Bug fix, setting false values into the global settings now works again, errors in uploader translate to component errors.
4.0: Massive update, refactoring, new behavior, new configuration file.
3.6.3 Bug fix; assigning multiple columns to upload model key, doesn't test to make sure it's a file (regression fixed).
3.6.2 Bug fixes, multiple fileupload issue with finalFiles
3.6.1 Bug fixes (for non model users)
3.6: Added massSave associative array save support.
3.5: Added multi file support. (API changes: $uploadId now depreciated, use $uploadIds[0] instead. $finalFile now depreciated, use $finalFiles[0] instead.)
3.0: Converted Component and Helper into a plugin for easy management between projects
2.0.1: Bug Fixes
2.0: Release of FileUploadHelper
1.7: Added detailed errors to FileUploadComponent
1.6: Bug Fixes
1.5: Bug Fixes
1.4: Added toggle to allow for auto processFile or not.
1.3: Bug Fixes
1.2: Bug Fixes
1.1: Converted to cakePHP naming conventions and standards
1.0: Initial Release


There are three ways to setup the this plugin.

One) Behavior + Helper method (recommended). By attaching the FileUpload.FileUpload behavior to a model of your choice any file uploaded while saving that
model will move the file to its specified area (webroot/files). All the file uploading will happen for you
automatically, including multiple file uploads and associations.

Two) Component + Model + Helper (not recommended, legacy). You'll setup a basic model and the component will handle the save for you in a number of ways.

Three) Component + Helper (Non-model users only). If all you need to do is setup an easy way to upload files to your webserver and don't care about keeping track of them then you can use the Component + Helper to easily handle all your file uploading needs. Model not required.

The fastest and most flexible way to setup file upload plugin is with the behavior method.

Behavior Configuration *NEW* v4.+ (RECOMMENDED)

To use the behavior method of the plugin simply attach the FileUpload.FileUpload to the model of your choice.

  1. class Upload extends AppModel {
  2.   var $name = 'Upload';
  3.   var $actsAs = array('FileUpload.FileUpload');
  4. }

That's enough to get you going with the default settings. The default settings are in (config/file_upload_settings.php). File you upload will be saved to the app/webroot/files directory and will not overwrite eachother.

If you want to alter the default settings like the uploadDir (the upload directory) simply pass it in as a key=>value pair when attaching the behavior like so:
  1. class Upload extends AppModel {
  2.   var $name = 'Upload';
  3.   var $actsAs = array(
  4.         'FileUpload.FileUpload' => array(
  5.           'uploadDir' => 'uploads',
  6.           'forceWebroot' => true, //if false, uploads will be saved to
  7.                                            //the uploadDir as a direct path.
  8.                                            //default: true
  9.           'fields' => array(
  10.             'name' => 'file_name',
  11.             'type' => 'file_type',
  12.             'size' => 'file_size'
  13.           ),
  14.           'allowedTypes' => array(
  15.             'pdf' => array('application/pdf')
  16.           ),
  17.           'maxFileSize' => '10000', //in bytes
  18.           'unique' => false, //uploaded files will overwrite existing files
  19.           'fileNameFunction' => 'sha1', //execute sha1 on fileName
  20.         )
  21.       );
  22. }

You'll notice the upload directory is now app/webroot/uploads (make sure it exists). And the file_specific column names are changed from name, type and size to file_name, file_type, and file_size. We are now also ONLY allowing .pdf files to be uploaded, only allowing files less than 10KB, files with the same name will be overwritten, and the Sha1 function will be executed on the filename before saving, nothing more (by default all web image types are allowed and there are no file restrictions -- other than those specified in php.ini).

Now with your model set, you'll be able to upload files and save the results to your database even though associated models

Example -- Assuming an Application->hasMany->Uploads you could do the following in /views/applications/add.ctp
  1. echo $form->create('Application', array('type' => 'file'));
  2. echo $form->input('');
  3. echo $form->input('Upload.0.file', array('type' => 'file'));
  4. echo $form->input('Upload.1.file', array('type' => 'file'));
  5. echo $form->end('Save Application and Two Uploads');

With this you'll created two new upload record along with their files put into the uploadDir directory, and associate it directly with your new application record.

NOTE: Please review file_upload/config/file_upload_settings.php for details on each setting.

Component Configuration (NOT RECOMMENDED)

This is the legacy way of handling file upload tasks and as such is not recommended. However, if you do not need to use a database or keep track of your uploads the component option has a non-model user option and is extremely easy to configure.

You'll need to add the FileUpload.FileUpload in both the components and helpers array

  1. <?php
  2. var $helpers = array('Html', 'Form', 'FileUpload.FileUpload');
  3. var $components = array('FileUpload.FileUpload');
  4. ?>

Upon submitting a file the FileUpload Component will automatically search for your uploaded file, verify its of the proper type set by $this->FileUpload->allowedTypes():
  1. <?php
  2. function beforeFilter(){
  3.   parent::beforeFilter();
  4.   /* defaults to:
  5.   'jpg' => array('image/jpeg', 'image/pjpeg'),
  6.   'jpeg' => array('image/jpeg', 'image/pjpeg'),
  7.   'gif' => array('image/gif'),
  8.   'png' => array('image/png','image/x-png'),*/
  10.   $this->FileUpload->allowedTypes(array(
  11.     'jpg' => array('image/jpeg','image/pjpeg'),
  12.     'txt',
  13.     'gif',
  14.     'pdf' => array('application/pdf')
  15.   ));
  16. }
  17. ?>

Then it will attempt to copy the file to your uploads directory set by $this->FileUpload->uploadDir():
  1. <?php
  2. function beforeFilter(){
  3.   parent::beforeFilter();
  4.   //defaults to 'files', will be webroot/files, make sure webroot/files exists and is chmod 777
  5.   $this->FileUpload->uploadDir('files');
  6. }
  7. ?>


You can use this Component with or without a model. It defaults to use the Upload model:

  1. <?php
  2. //app/models/upload.php
  3. class Upload extends AppModel{
  4.   var $name = 'Upload';
  5. }
  6. ?>


If you're using a Model, you'll need to have at least 3 fields to hold the uploaded data (name, type, size)
Example SQL Table:
-- Table structure for table `uploads`

`id` int(11) unsigned NOT NULL auto_increment,
`name` varchar(200) NOT NULL,
`type` varchar(200) NOT NULL,
`size` int(11) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,

Or you can use the built in cake schema command:
  1. cake schema run create -path plugins/file_upload/config/sql -name upload

Default fields are name, type, and size; but you can change that at anytime using the $this->FileUpload->fields();
  1. <?php
  2. function beforeFilter(){
  3.   parent::beforeFilter();
  4.   //fill with associated array of name, type, size to the corresponding column name
  5.   $this->FileUpload->fields(array('name'=> 'file_name', 'type' => 'file_type', 'size' => 'file_size'));
  6. }
  7. ?>


Example view WITH Model WITH Helper:
  1. <?= $fileUpload->input(); ?>

Example View WITH Model WITHOUT Helper:
  1. <?= $form->create('Upload', array('type'=>'file')); ?>
  2. <?= $form->input('file', array('type'=>'file')); ?>
  3. <?= $form->end('Submit')); ?>

Model Association Saves (version 3.6.+)

With version 3.6 and above users now have the ability to save associated data along with thier upload via the plugin by simply following the associations rules in cakephp. By default this feature is turned off, so you'll need to switch it by setting $this->FileUpload->massSave = true; in a beforefilter.
  1. function beforeFilter(){
  2.   parent::beforeFilter();
  3.   $this->FileUpload->massSave(true);
  4. }

By setting massSave to true, the plugin will execute a saveAll on the data it was passed per upload given. This allows you to construct your form much more naturally and all the file upload magic will happen for you automatically. Take this form for an example:
  1. echo $form->create('Picture', array('action'=>'add', 'type' => 'file'));
  2. echo $form->input('Picture.title');
  3. echo $form->input('Picture.user_id');
  4. echo $form->input('Picture.description');
  5. echo $fileUpload->input();
  6. echo $form->end('Add');

With massSave on, your file will be uploaded for you and saved to your Upload model and then associated to the Picture model you've just created all automatically done by the plugin. Following this example your add() action might look like this:
  1. function add(){
  2.   if(!empty($this->data)){
  3.     if($this->FileUpload->success){
  4.       $this->Session->setFlash('Save Successfull!');
  5.     }
  6.     else {   $this->Session->setFlash($this->FileUpload->showErrors());
  7.     }
  8.   }
  9. }


If you wish to NOT use a model simply set $this->FileUpload->fileModel(null); in a beforeFilter.
  1. <?php
  2.   //in a controller
  3.   function beforeFilter(){
  4.     parent::beforeFilter();
  5.     $this->FileUpload->fileModel(null);  //Upload by default.
  6.   }
  7. ?>


Example View WITHOUT a Model:

Example view WITHOUT Model WITH Helper:
  1. <?= $fileUpload->input(array('var' => 'file', 'model' => false)); ?>


If a fileModel is given, it will attempt to save the record of the uploaded file to the database for later use. Upon success the FileComponent sets $this->FileUpload->success to TRUE; You can use this variable to test in your controller like so:

  1. <?php
  2. class UploadsController extends AppController {
  4.   var $name = 'Uploads';
  5.   var $helpers = array('Html', 'Form', 'FileUpload.FileUpload');
  6.   var $components = array('FileUpload.FileUpload');
  8.   function admin_add() {
  9.     if(!empty($this->data)){
  10.       if($this->FileUpload->success){
  11.         $this->set('photo', $this->FileUpload->finalFile);
  12.       }else{
  13.         $this->Session->setFlash($this->FileUpload->showErrors());
  14.       }
  15.     }
  16.   }
  17. }
  18. ?>

At any time you can remove a file by using the $this->FileUpload->removeFile($name); function. An example of that being used might be in a controller:
  1. <?php
  2. class UploadsController extends AppController {
  4.   var $name = 'Uploads';
  5.   var $helpers = array('Html', 'Form', 'FileUpload.FileUpload');
  6.   var $components = array('FileUpload.FileUpload');
  8.   function admin_delete($id = null) {
  9.     $upload = $this->Upload->findById($id);
  10.     if($this->FileUpload->removeFile($upload['Upload']['name'])){
  11.       if($this->Upload->del($id)){
  12.         $this->Session->setFlash('Upload deleted');
  13.         $this->redirect(array('action'=>'index'));
  14.       }
  15.     }
  16.   }
  17. }
  18. ?>


To View the photo variable you might type something like
  1. <?= $html->image("/files/$photo"); ?>

Example with FileUploadHelper:
  1. <?= $fileUpload->image($photo); ?>

Simple as that. Automagic File Uploading. I hope you enjoy it. If you read through the documentation I've written in the actual FileUpload Component it will give you detailed examples and explanations of each variable/function. Comments are appreciated.

Multiple File Uploads *NEW*

In version 3.5, I've worked hard to get multiple file uploading as easy as possible for both
model configurations and non-model configurations. Look above for fileUploadHelper examples.



@Elmer 2/9/2009 (
"As long as the automatic var is true (default), the component works as always. But if it is set to false, processAllFiles() is no longer called automatically. From my controller I can now set an upload folder and call processAllFiles() when I'm ready."

  1. if ($this->FileUpload->hasFile) {
  2.     $this->FileUpload->uploadDir('files/sub/dir/1/2/3');
  3.     $this->FileUpload->processAllFiles();
  4. }