MeioUpload Behavior – An improved File Upload Behavior for CakePHP

MeioUpload Behavior is an improved File Upload Behavior for the CakePHP framework. It’s based on the Digital Spaghetti’s Upload Behavior.

Juan Basso created a project hosted at github. I am unable to keep working on this behavior an he is making some updates to the code. I think github is a great tool because you can simply fork the project and make your own changes. Go check his work: http://github.com/jrbasso/MeioUpload/tree/master

Download

MeioUploadBehavior version 1.0.1

Related Articles

Features

  • Can be used for any kind of files;
  • Accepts custom directory for files to be uploaded;
  • Validates the file extension and mime-type due to the behavior configuration;
  • Validates the max file size;
  • Allow custom validation rules;
  • Allow as many thumbnails formats as you want;
  • Allow more then one field to be uploadable, with custom options per field;
  • Stores the directory, filesize, and mime-type in the database if the table has these fields. Also allows to customize these fields names;
  • Allow the use of default files and deleting files without deleting the entire record;
  • Delete files when the record is deleted or updated with a new file;
  • Also works in the $model->saveAll method.

Usage

  1. Place the meio_upload.php file in your app/models/behaviors folder;
  2. If you want to use thumbnails, download Nate’s phpThumb Component and place it in your app/controllers/components folder;
  3. Insert in your model table a character varying field:
    CREATE TABLE `products` (
    `id` int(8) unsigned NOT NULL auto_increment,
    `name` varchar(255) default NULL,
    `description` text default NULL,
    `price` double default NULL,
    `picture` varchar(255) default NULL,
    `dir` varchar(255) default NULL,
    `mimetype` varchar(255) NULL,
    `filesize` int(11) unsigned default NULL,
    `created` datetime default NULL,
    `modified` datetime default NULL,
    PRIMARY KEY  (`id`) ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
    
  4. Add the MeioUpload in the $actsAs of your model:
    var $actsAs = array(
        'MeioUpload' => array(
            'picture' => array(
                'dir' => 'img{DS}{model}{DS}{field}',
                'create_directory' => true,
                'allowed_mime' => array('image/jpeg', 'image/pjpeg', 'image/png'),
                'allowed_ext' => array('.jpg', '.jpeg', '.png'),
                'thumbsizes' => array(
                    'normal' => array('width'=>200, 'height'=>200),
                ),
                'default' => 'default.jpg',
            )
        )
    );
    
  5. Use a form file input to the field:
    echo $form->input('picture', array('type' => 'file'));
    
  6. Make sure your form has multipart/form-data enctype:
    echo $form->create('Product',array('type' => 'file'));
    
  7. Make sure the PHP has permission to write in the folder yous specified and the php.ini allow the MAX_FILE_SIZE you specified.

Options

When you apply the MeioUpload Behavior to a Model, you pass an array with your options. Here are the options you can change and it’s defaults.

  1. dir

    The folder where the uploaded files will be saved. It must be inside the app/webroot directory and defaults to an empty string, what means that it will be the app/webroot itself. If you specify some path, then it will be app/webroot/the_path_you/specified. In this option you may use the {DS} pattern, what will be converted to ‘/’ in UNIX systems and to ‘\’ in Windows systems.
  2. allowed_mime

    This option specifies the allowed mime-types for the files. It defaults to an empty array. What means that every mime-type will be accepted. But if you specify an array with the mime-types allowed, only files of these mime-types will be accepted.
    var $actsAs = array(
        'picture' => array(
            'allowed_mime' => array('image/jpeg', 'image/pjpeg', 'image/png')
        )
    );
    
    The code above says that the picture field will be a file uploaded, and it allows ‘image/jpeg’, ‘image/pjpeg’ and ‘image/png’ mime-types.
  3. allowed_ext

    This option specifies the allowed file extensions. It defaults to an empty array. What means that every extension will be accepted. But if you specify an array with the extensions allowed, only files with these extensions will be accepted.
    var $actsAs = array(
        'picture' => array(
            'allowed_ext' => array('.jpg', '.jpeg', '.png')
        )
    );
    
    The code above says that the picture field will be a file uploaded, and it allows ‘.jpg’, ‘.jpeg’ and ‘.png’ extensions.
  4. create_directory

    If you want to create the directory specified in the dir option if it don’t exists, then set this option to true. It already defaults to true, but you can set it to false.
  5. max_size

    The max file size allowed in the upload. Be sure it’s lower then the php.ini configuration. You can set a numeric value of bytes, or set it in other unit like ‘8 Kb’, only ‘kb’, ‘mb’, ‘gb’ and ‘tb’ units are allowed and it’s not case-sensitive. It defaults to 2 Mb.
    var $actsAs = array(
        'picture' => array(
            'max_size' => '4 Mb'
        )
    );
    
  6. default

    If you have a file that you want to use if the field is left blank, like a default picture for users who don’t have one, set this option to the name of this file. Make sure it is inside the folder specified in the ‘dir’ option.
    var $actsAs = array(
        'picture' => array(
            'default' => 'default.jpg'
        )
    );
    
  7. fields

    With this option you can customize the field inside your model table, where the data will be saved. The filename is the key of the options array, and you can setup fields to store the filesize, mime-type and directory. It defaults to ‘filesize’, ‘mimetype’ and ‘dir’ respectively, but you can customize with an array:
    var $actsAs = array(
        'picture' => array(
            'fields' => array(
                'filesize' => 'picture_filesize',
                'mimetype' => '{field}_mimetype',
                'dir' => 'pictures_folder'
            )
        )
    );
    
    The code above says that your filesize, mimetype and dir fields will be ‘picture_filesize’, ‘picture_mimetype’ and ‘picture_folder’ respectively. And the filename field will be pictures. You may notice that in mimetype case, i used the constant {field} that will be replaced with the field name(picture in this case).

Validations

The behavior automatically include some validations to your field. Here they are:

  1. FieldName Checks if the field has been setup to be and uploadable.
  2. Dir Checks if the directory exists or if it can be created. This validation depends on the option ‘create_directory’.
  3. Empty Checks if the filename is not empty. It defaults to be used only on create.
  4. UploadError Checks if ocurred erros in the upload.
  5. MaxSize Checks if the file isn’t bigger then the max file size option.
  6. InvalidMime Checks if the file is of an allowed mime-type.
  7. InvalidExt Checks if the file has an allowed extension.

You can overwrite any of the parameters of these default validation rules. Directly in the model $validate var:

var $validate = array(
    'picture' => array(
        'Empty' => array(
            'check' => false
        ),
        'InvalidExt => array(
            'message' => 'This file extension isn't allowed.'
        )
    )
);
In the code above, i changed the message for the ‘InvalidExt’ default validation. You can also disable any of the default validations by setting the ‘check’ atribute fo false as is shown in the example above for the ‘Empty’ default validation. You can change any of the other parameters of the built-in cake validation:
var $validate = array(
    'picture' => array(
        'Empty' => array(
            'rule' => array('YourDefaultValidation'),
            'on' => 'update',
            'required' => true
        ),
    )
);
You can also change the validation rule for one you have created. But use this functionality carefully.

Setting up file removing

If you send a form data with as field named data[Model][field][remove] not empty, then the behavior will automatically delete the file associated with the record and set it’s value to the default, if it is set, or to empty. To achieve this you can add a checkbox to your form:

echo $form->input('Product.picture.remove', array('type' => 'checkbox'));

138 Responses to “MeioUpload Behavior – An improved File Upload Behavior for CakePHP”

Pages: « 1 2 3 4 [5] 6 7 8 9 10 11 … 14 » Show All

  1. 41
    John Says:

    Hi – I sorted the problem. I was just being a muppet and it all works beautifully. I changed the relationship from HABTM to Product has Many Images (which is fine as I plan to use the polymorphic behaviour to attach multiple models).

    I also changed the controller from: $this->Product->save($this->data) to $this->Product->saveAll($this->data)

    Thanks.

  2. 42
    gabriel Says:

    Hi,

    I have problem with validation : preg_match() expects parameter 2 to be string, array given [/homez.40/.../cakephp/cake/libs/validation.php, line 877]

    See you

    Gabriel

  3. 43
    gabriel Says:

    I have solved the problem with validation : you have to use PHP5 and I used PHP4

  4. 44
    Noel Says:

    Hello !

    I’d like to say that this project helped me a lot in my own. But I’m facing a small problem now : I can’t delete the files I uploaded via the checkbox. When I put the file to delete in the input, check the box, a new entry is inserted in my DB.

    Can anyone tell me what’s the problem ?

    Thanks in advance.

  5. 45
    John Says:

    Hi Vinicius. I’ve been playing around trying to upload multiple files at the same time – i.e. Product has many ProductImages – in order to save the images I’m using the following in my controler: function admin_add() { if (!empty($this->data)) { $this->Product->create();

            if ($this->Product->save($this->data)) {
    
                $product_id = $this->Product->getLastInsertId();
    
                    // this is multiple images          
                    foreach($this->data['ProductImage'] as $ProductImage => $value){              
    
                        $this->Product->ProductImage->create();
                        $value['product_id'] = $product_id;
                        $this->Product->ProductImage->save($value);
                    }
    
                $this->Session->setFlash(__('The Product has been saved', true));         
                $this->redirect(array('action'=>'index'));            
    
            } else {
                $this->Session->setFlash(__('The Product could not be saved. Please, try again.', true));
            }
        }
    }
    

    The $this->data array would look like this:

    Array ( [Product] => Array ( [name] => Product 0 [live] => 1 )

    [ProductImage] => Array
        (
            [0] => Array
                (
                    [filename] => Array
                        (
                            [name] => doves.jpg
                            [type] => image/jpeg
                            [tmp_name] => E:\xampp\tmp\php7A.tmp
                            [error] => 0
                            [size] => 21024
                        )
    
                )
    
            [1] => Array
                (
                    [filename] => Array
                        (
                            [name] => 2960-medium.jpg
                            [type] => image/jpeg
                            [tmp_name] => E:\xampp\tmp\php7B.tmp
                            [error] => 0
                            [size] => 134256
                        )
    
                )
    
        )
    

    )

    But I was wondering if there was a better way of dealing with this? You mentioned in one of the comments above that you were planning to put up an example of uploading multiple files.

    What I’ve done it above is fine but it would be so much more elegant to push it into the behaviour.

    Cheers

  6. 46
    唯枫志 - CakePHP中使用MeioUpload Behavior上传图片 Says:

    [...] 这款MeioUpload Behavior真是帮我解决了大问题,感谢作者和阿辉,另外CakePHP的app/models/behaviors目录是专门用来存放相关行为处理文件的,大家如果想省事儿,可以到http://bakery.cakephp.org/来先找找有没有人事先写好的代码,记录下图片上传先。 我的文章表里有两个字段:thumbnailimg 和 largeimg ,分别代表小图和大图,文章添加时上传的两张图片到webroot/files/images下,并把路径和文件名分别保存到这两个字段,实现过程如下: [...]

  7. 47
    wkeeper Says:

    Hi, Thank you for this nice behavior!

    I have a small problem. When I’m trying to leave the upload field empty (for example, I want to update other field of the object), behavior replaces filename in database record to the “default.jpg”.

    Does anybody know any solution?

  8. 48
    CorneyWalls Says:

    First of all thnx for such a nice piece of code, its working perfectly in my case expect the thumbnails part, (i copied the phpthumb files to “app\vendors\phpThumb\”, and copied the thumb component to “app\controllers\components\” direcotry ) the model controller and views in my code are as follows.

    ///////////////////////////////////////// data)){ $this->Image->save($this->data); } }
    ?>

    ////////////////////////////////////////////////////// create(“images”,array(“acction”=>”add”,’type’ => ‘file’)); echo $form->input(‘Image.name’, array(‘type’ => ‘file’)); echo $form->end(“Upload”); ?>

    ///////////////////////////////////////////////////// array( ‘name’ => array( ‘dir’ => ‘users_files{DS}posts{DS}images’,
    ‘create_directory’ => true, ‘allowed_mime’ => array(‘image/jpeg’, ‘image/pjpeg’, ‘image/png’), ‘allowed_ext’ => array(‘.jpg’, ‘.jpeg’, ‘.png’), ‘thumbsizes’ => array(‘normal’ => array(‘width’=>200, ‘height’=>200)) ) ) );

    }

    ?> /////////////////////////////////////////

    is there any idea about why the thumbnails are not being created

    thanks

  9. 49
    CorneyWalls Says:

    First of all thnx for such a nice piece of code, its working perfectly in my case expect the thumbnails part, (i copied the phpthumb files to “app\vendors\phpThumb\”, and copied the thumb component to “app\controllers\components\” direcotry )

    i have uploaded the code files here http://www.weborbs.com/files.zip

    is there any idea about why the thumbnails are not being created

    thanks

  10. 50
    Meshach Says:

    faemino,

    Your problem is what I was seeing too, but the solution you offered doesn’t work. Namely, it doesn’t delete images when you edit to override them. Instead of adding a redundant “else” statement, simply remove the “!” on line 623, and it’ll work. The problem appears to have simply been a typo. Here’s what my line 623 of the meio_upload.php looked like before:

    if(!empty($model->data[$model->name][$model->primaryKey])){ $this->setFileToRemove($fieldName); }

    Which I changed to: if(empty($model->data[$model->name][$model->primaryKey])){ $this->setFileToRemove($fieldName); }

    Seems to be working fine now.

    Great work, vin.

Pages: « 1 2 3 4 [5] 6 7 8 9 10 11 … 14 » Show All

Leave a Reply