Recent Thoughts

Downloads

Contact Us

Email:
Topic:
Message:

Google Ad

FileUploadPlugin v5.0 released!

Date: Fri, Apr 16th 2010, 22:52 Author: nick Views: 1613 Comments: 25 share

CakePHP File Upload Plugin

Info:
Get it:
  • Download Now
  • svn co http://svn.github.com/webtechnick/CakePHP-FileUpload-Plugin file_upload
I'm excited to announce the newest v5.0 release of the popular File Upload Plugin. There have been a lot of new features since the last major release and I'll discuss each one in depth.

New Features


At a glance:

- Validation, and file upload errors now display back to the view
- new 'required' key setting
- new 'maxFileSize' key setting
- new 'unique' key setting
- new 'fileNameFunction' key setting.

Validation errors


Any errors that occur during a file upload will now be presented back to user just like any other standard model validation error. If more than one error occurs, each subsequent error will be added to the model's validation errors. This means no more guess work for the developer or user over what went wrong during the upload (ie file was too large, file type not allowed, etc...).

Required setting


This is a behavior specific new feature. By setting the key 'required' to true you will require an upload to be made if the Model key is present in the saveAll function. This setting is false by default.

  1. var $actsAs = array('FileUpload.FileUpload' => array(
  2.   'required' => true
  3. ));


Now anywhere in your app if you attempt to preform a $this->saveAll($data, array('validate' => 'first')); with the file model set as an associative key, an uploaded file will be required as well. If no file is detected during that saveAll the entire save is exited and a validation error occurs.

maxfilesize setting


maxFileSize is a new key setting that allows a developer to limit the size of an upload (note: this does *not* overwrite the limit set in php.ini). This is useful, to tone down the size of uploaded files allowed. The setting takes an int and corresponds to the byte size allowed. If set to false, no file size restrictions (other than those set in php.ini) are enforced on the uploaded file. maxFileSize is false by default.

Example:
  1. var $actsAs = array('FileUpload.FileUpload' => array(
  2.   'maxFileSize' => 102400, //in bytes (~100KB)
  3. ));


unique setting


Until now, the File Upload Plugin made sure never to overwrite any previously uploaded file. That is still the default behavior, but now you can turn that feature off if you wish.

  1. var $actsAs = array('FileUpload.FileUpload' => array(
  2.   'unique' => false
  3. ));


When unique is set to false, uploaded files will overwrite files on the server with the same name. This setting is true by default.

fileNameFunction setting


We saved the best for last. A much requested feature was the ability to manipulate the resulting filename in a number of ways. Until now, the only way a user could manipulate the file was in a beforeSave(), but that still required the developer to manually rename the file on the server. Some suggested using a sha1 hash, others a md5 hash, and the rest wanted the ability to define their own function to handle the resulting filename. I've decided to make you all happy!

Enter fileNameFunction setting. With this setting you can define your own filename filtering function, or use any built in PHP hashing function.

Examples:
  1. var $actsAs = array('FileUpload.FileUpload' => array(
  2.   'fileNameFunction' => 'sha1'
  3. ));


Defining fileNameFunction as sha1, the resulting filename will first be passed into sha1() and then moved to the server and saved to the database. You can use *ANY* PHP function you wish, including functions you define either in bootstrap.php or within your Model.

Bootstrap.php Example:
  1. //config/bootstrap.php
  2. function prefix_string($str){
  3.   return 'prefix_' . $str;
  4. }
  5.  
  6. //models/upload.php
  7. var $actsAs = array('FileUpload.FileUpload' => array(
  8.   'fileNameFunction' => 'prefix_string'
  9. ));


You can also define it within the same Model:
  1. //models/upload.php
  2. var $actsAs = array('FileUpload.FileUpload' => array(
  3.   'fileNameFunction' => 'sanitizeFileName'
  4. ));
  5.  
  6. function sanitizeFileName($fileName){
  7.   //whatever filename logic you need
  8.   return $fileName;
  9. }



NOTE: The function you choose must return a string. If the resulting hash function does *not* return a string, the save will be halted and a validation error will occur.

Enjoy v5.0


I hope you enjoy the new features. As always, comments are appreciated. If you enjoy the plugin and wish to help keep it supported, please consider a donation (or click an ad a few times. :) ).

Enjoy,
Nick

Comments

04/17/2010 2:38 pm

V5.0 and fileNameFunction

Hi, I must be missing something as I can't get the fileNameFunction setting to work.
My Model is as follows:
class Technique extends AppModel {
var $name = 'Technique';

var $actsAs = array('FileUpload.FileUpload'=> array(
'uploadDir' => 'technique',
'allowedTypes' => array('application/pdf'),
'fileNameFunction' => 'sanitizeFileName'
)
);

function sanitizeFileName($fileName){
$sanitized = preg_replace('/[^a-zA-Z0-9-_\.]/','', $filename);
return $sanitized;
}
}

What am I doing wrong? I process the filename through a simple regex function to make sure I got it straight. Still, the uploaded file is left untouched.
Thanks for your help.
04/17/2010 3:20 pm

Ya, you're returning null.

You're taking in $fileName in the function but parsing $filename. Notice the "N" in Name is lowercase.

Try this:
  1. function sanitizeFileName($fileName){
  2.   $sanitized = preg_replace('/[^a-zA-Z0-9-_\.]/','', $fileName);
  3.   return $sanitized;
  4. }


Hope that helps,
Nick
04/17/2010 3:38 pm

Me->dumb!

Thanks, that was obvious. Sorry for taking your time for something so stupid. I guess I should take some time off...
04/17/2010 4:15 pm

LOL no worries.

An extra set of eyes never hurts. I'm glad I could help. :)

Nick
05/05/2010 10:32 am

Using no model and multiple files

Hi,

first things first, thanks for the plugin, it's saved me a lot of time. I am trying to use the plugin without model and I am having a few issues, maybe you can give me a hand. I am kinda new to cakephp and I am still learning.

I only need to save the URL of the uploaded files in my database so I think I don't need to use a model for that. I configured the controller like this:

var $helpers = array('Html','Form','FileUpload.FileUpload');
var $components = array('FileUpload.FileUpload');

function beforeFilter() {
$this->FileUpload->fileModel(null);
$this->FileUpload->uploadDir('images/uploads');
}

Then in my view, I have a form with 2 file fields where the user can upload one, two or none graphics files. This is my view code:

echo $form->create(null, array ('url' => array('controller' => 'contenidos', 'action' =>'edit'), 'type' => 'file' ));
echo $fileUpload->input(array('model' => false));
echo $fileUpload->input(array('model' => false));
echo $form->end();

The problem is that if I don't upload both images, after do submit, the controller drops this error:

Warning (512): FileUpload::processFile() - Unable to save temp file to file system. [APP/plugins/file_upload/controllers/components/file_upload.php, line 402]

Also another problem that I have, is how to know which file field the user has sent. The first file field in the view is for a big image and the second one is for a small image. I need to distinguish between both in order to do one action or another. I have to add a var in the helper but it didn't work. Any ideas?

Thanks in advance!
05/05/2010 1:38 pm

Make sure you have webroot/images/uploads chmod 777

Hi,
You're getting that warning if the component isn't able to move the uploaded file to the destination you wanted. As such, make sure webroot/images/uploads is created and is writable.

In regards to the second problem you're having, wanting to flag an image upload for a particular type, I can't think of a way off the top of my head that doesn't involve a database.

If you were storing your upload records within a database you could flag that image as "large" or "small" by passing in a hidden field within your form. If you were using the behavior/helper method you could do something like this in your view:

  1. $form->input('Upload.0.size_type', array('value'=>'big', 'type' => 'hidden'));
  2. $form->input('Upload.0.file', array('type' => 'file'));
  3.  
  4. $form->input('Upload.1.size_type', array('value'=>'small', 'type' => 'hidden'));
  5. $form->input('Upload.1.file', array('type' => 'file'));


Then when saved to a database, CakePHP would keep track of what was a large image and what was a small image. You could also do some fancy stuff with afterSave() in a model to check the actual image size and determine if its large enough for your "big" flag.

But without a database, I suppose you could just flag it however you wanted it via the form, and hope the user follows instructions. Knowing the order helps, you could count how many files were uploaded, and determine by order what file was what. /shrug That's the best solution I can come up with without using a model.

Hope that helps,
Nick
05/06/2010 2:49 am

still Unable to save temp file to file system.

Hi,

have checked that the webroot/images/uploads is created and is writable. images is 777 and owner www-data but still get the error "Unable to save temp file to file system". It is interesting that when I upload both file fields (big and small) I don't get the "Unable to save..." error, that only happens when I upload one image.

Thanks
05/09/2010 6:09 pm

Typo in view example

In views/helpers/file_upload.php lines 13-14, you show an example of displaying resized image:
$fileUpload->image('filename.jpg', array('width => 250'));
Should be:
$fileUpload->image('filename.jpg', array('width' => 250));

Cheers,
Dave
05/09/2010 6:37 pm

Thanks dave

Thanks for catching the documentation typo. I've corrected it and pushed the changes.

Hope all is well,
Nick
05/10/2010 8:14 pm

Having Trouble with 'Required' setting

Hi Nick,

I thought I had everything working but I realized the required=true validation rule is not working. I am able to save a product without selecting a file for upload. I've attached snippets from my controller,model, and view files in case you have a moment to take a look.

Thanks!
-Dave

Controller:
if (!empty($this->data)) {
$this->Product->create();
if ($this->Product->saveAll($this->data, array('validate' => 'first')))

Model:
var $actsAs = array(
'FileUpload.FileUpload' => array(
'fileNameFunction' => 'modifyFileName',
'required' => true
)
);

View:
echo $form->create('Product', array('type' => 'file'));
echo $form->input('Product.code');
echo $form->input('Upload.0.file', array('type' => 'file', 'label' => 'Image'));
echo $form->input('Product.price');
05/11/2010 8:27 pm

Thanks for the info

Hi, this is something that has been brought to my attention a few times, my local tests work just fine but I'll make sure I'm not missing a corner case of sorts. I'll try my best to recreate this issue and post a fix (if I find one).

Hope all is well,
Nick
05/19/2010 9:28 pm

Support on CakePHP 1.3?

I've tried to use this plugin in CakePHP 1.3. But it didn't work. Do you plan to upgrade to support CakePHP 1.3? Thanks
05/19/2010 10:23 pm

@File Upload Plugin supports CakePHP 1.x

Hi, this plugin works in both 1.2.x as well as 1.3 of CakePHP. I have personally tested and use this plugin in almost all my 1.3 applications.

What seems to be the problem?
05/19/2010 10:36 pm

I'm not so sure

Thanks for reply. I'm quite new to your plugin but I can make it works in my cake 1.2 app but I can't make it works in my cake 1.3 app I don't know why. It didn't show error and nothing happened. It would be great if you can create a very sample complete project of cake 1.3 with your plugin. I'm sorry for annoying but this plugin will save my life.. thanks.
05/19/2010 10:42 pm

Or may be creating a readme file for cake 1.3

Your readme file support for cake 1.2. So I guess I miss something that is specific for cake 1.3. May be a readme file instead of a sample project. I tried to change "form" function of cause but still not work.
05/20/2010 12:06 am

Different documentation isn't necessary.

There isn't a need for different documentation because the plugin has is really a set of utilities that are not reliant on a specific version change (ie 1.2 to 1.3). All my apps are 1.3 apps now, and I have the plugin running on each one with the same configuration it was running with 1.2.

I'm interested to know what's going on in your app but you haven't given me any clues as to what the issue is.

'not work' is pretty vague and unhelpful. Are you using the Behavior + Helper method, the Component+Helper? Are you configuring the plugin to use a model, no model? How did you configure it? What version are you running? What have you tried specifically to get it working?

I'd love to help, maybe you could email me your code and I can point you in the right direction.

Hope that helps,
Nick
05/20/2010 10:12 am

Well.. it works now..

Sorry for annoying but must thanks for you to convince me that it works on 1.3 so I just try again and now it works. My faults. But thanks again for great plugin!

I used model + component.
05/23/2010 1:28 pm

Any Help Appreciated.

I am using the plugin and it works... I have a problem..I want users to able to view the files(.doc & .pdf) of other users... but not download it without user's permission.. I have used scribd's javascript in my past projects.. but unlike previous implementations.. I dont want to share the location of the file..

Any help is appreciated.

Thanx.
05/28/2010 3:45 am

Problem with file type

I have a problem with file type. I can't get PDF or SWF file to be uploadable. I use model+component way to set up.

Here is my setting in my upload model.
var $actsAs = array(
'FileUpload.FileUpload' => array(
'uploadDir' => 'files',
'fields' => array('name' => 'name', 'type' => 'type', 'size' => 'size'),
'allowedTypes' => array(
'application/msword',
'application/pdf',
'image/jpeg',
'image/gif',
'image/png',
'image/x-png',
'application/x-shockwave-flash',
),
'required' => false, //default is false, if true a validation error would occur if a file wsan't uploaded.
'maxFileSize' => false, //bytes OR false to turn off maxFileSize (default false)
'unique' => true, //filenames will overwrite existing files of the same name. (default true)
'fileNameFunction' => false //execute the Sha1 function on a filename before saving it (default false)
));

I'm also use "beforeFilter" to change upload location in target model for upload.

function beforeFilter(){
parent::beforeFilter();
$this->FileUpload->uploadDir('files\pdf');
}

The upload works fine with JPEG, PNG as it is default type but I can't add another type.

Thanks in advance.
05/28/2010 3:58 am

Basic setup help

Hi Nick,
I have setup the plugin correctly as far as I can see but I am having one small problem.

I have the Upload table/model setup:
class Upload extends AppModel {
var $name = 'Upload';
var $actsAs = array('FileUpload.FileUpload');
}

And I have a table of offers where people can attach a file:
class Offer extends AppModel {
var $name = 'Offer';
var $displayField = 'name';

var $hasMany = array(
'Upload'
);
}

In my controller I have:
if(!empty($this->data)) {
$this->Offer->create();
$this->Offer->set($this->data);
$this->Offer->set('restaurant_id', $restaurant_id);

if($this->Offer->saveAll()) {
$this->Session->setFlash('Saved');
} else {
$this->Session->setFlash('Failed');
}
}

It saved the file to Upload and the Offer, but does not add the upload_id to the offers table.

This controller function is being used from another controller which 'uses' offer. Could this be the problem?

I would be very grateful for any help.

Many thanks!
Antony
05/28/2010 4:13 am

Previous comment

Hi Nick,
Please ignore my last comment! belongsTo not hasMany. Doh!

Fantastic plugin, thanks again!
05/28/2010 4:52 am

Model+Component is not a valid setup.

Hi, You're not able to upload swf, or pdf files because behavior+component is not a valid setup.

The three options are:

Behavior+Helper, Component+Helper (With Upload Model w/o behavior), or Component+Helper (no model).

You've setup the behavior correctly, as such, you don't need the component.

Hope that helps,
Nick
05/28/2010 1:47 pm

For Behavior+Helper with different setting

I found that Behavior+Helper is very easy.
But if I need different setting like Component+Helper that we can use "beforeFilter" to config some setting.

Can we do that? Because I need to upload file into different folder.

But if we can't it is fine I can use Component+Helper anyway...
06/14/2010 5:18 am

behavior does not seem to be "triggered"

hello Nick,
i have been trying to make the file_upload behavior to work for 2 days and it seems to not being 'called'.
No file uploaded, and i get a sql error because name, type and size are not populated.

Here is my conf :

in app/models/document.php
class Document extends AppModel{

var $name = 'Document';

var $actsAs = array(
'FileUpload.FileUpload' => array(
'uploadDir' => 'picts',
'allowedTypes' => array(
'jpg' => array('image/jpeg', 'image/pjpeg'),
'jpeg' => array('image/jpeg', 'image/pjpeg'),
'gif' => array('image/gif'),
'png' => array('image/png','image/x-png')),
'maxFileSize' => '10000', //bytes OR false to turn off maxFileSize (default false)
'required' => true
));

var $belongsTo = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'post_id'
)
);
in app/models/post.php

var $hasMany = array(
'Document' => array(
'className' => 'Document'
),
);
in app/controllers/posts_controller.php

if(!empty($this->data)){
$this->Post->saveAll($this->data, array('validate'=>'first'));
}

in this controller i checked the behaviors with :

$behaviors = Configure::listObjects('behavior');
pr($behaviors);
And only the default package behaviors are showing : Acl, Containable, Translate, Tree.
I'm quite new to cakephp so i don't know what to check to find out where my code is wrong.
Thank you for your help !
06/14/2010 6:16 am

error found !

folder name mismatch ...
Really annoying when it takes so much time to discover the one typo i made !

Add Comment

Please login or register to submit a comment.