/upload

CakePHP plugin to handle file uploading sans ridiculous automagic

Primary LanguagePHP

Upload Plugin

The Upload Plugin is an attempt to sanely upload files using techniques garnered packages such as MeioUpload , UploadPack and PHP documentation.

A Note on Pull Requests

I will not accept any feature pull requests. They are sometimes of dubious quality and ensuring everything useful gets into the core is difficult at best. Please create a ticket for the functionality you desire and I will either extend this plugin or build it into the core.

If it is a bug-fix, feel free to issue a pull request, but be aware that reviewing your submission will take time and it may not be accepted as-is.

That said, I appreciate any and all feedback, especially on untested code such as this :)

Requirements

  • CakePHP 1.2/1.3
  • Imagick/GD PHP Extension (for Thumbnail Creation)
  • PHP5 (Not really, but I’m more likely to be able to fix a PHP5 issue than a PHP4 issue)
  • Patience

Installation

[Manual]

  1. Download this: http://github.com/josegonzalez/upload/zipball/master
  2. Unzip that download.
  3. Copy the resulting folder to app/plugins
  4. Rename the folder you just copied to upload

[GIT Submodule]

In your app directory type:

git submodule add git://github.com/josegonzalez/upload.git plugins/upload
git submodule init
git submodule update

[GIT Clone]

In your plugin directory type

git clone git://github.com/josegonzalez/upload.git upload

Usage

CREATE table users (
	id int(10) unsigned NOT NULL auto_increment,
	username varchar(20) NOT NULL,
	photo varchar(255)
);
<?php
class User extends AppModel {
	var $name = 'User';
	var $actsAs = array(
		'Upload.Upload' => array(
			'photo'
		)
	);
}
?>
<?php echo $this->Form->create('User', array('type' => 'file')); ?>
	<?php echo $this->Form->input('User.username'); ?>
	<?php echo $this->Form->input('User.photo', array('type' => 'file')); ?>
<?php echo $this->Form->end(); ?>

Using the above setup, uploaded files cannot be deleted. To do so, a field must be added to store the directory of the file as follows:

CREATE table users (
	`id` int(10) unsigned NOT NULL auto_increment,
	`username` varchar(20) NOT NULL,
	`photo` varchar(255) DEFAULT NULL,
	`photo_dir` varchar(255) DEFAULT NULL,
	PRIMARY KEY (`id`)
);
<?php
class User extends AppModel {
	var $name = 'User';
	var $actsAs = array(
		'Upload.Upload' => array(
			'photo' => array(
				'fields' => array(
					'dir' => 'photo_dir'
				)
			)
		)
	);
}
?>
<?php echo $this->Form->create('User', array('type' => 'file')); ?>
	<?php echo $this->Form->input('User.username'); ?>
	<?php echo $this->Form->input('User.photo', array('type' => 'file')); ?>
	<?php echo $this->Form->input('User.photo_dir', array('type' => 'hidden')); ?>
<?php echo $this->Form->end(); ?>

Thumbnails are not automatically created. To do so, thumbnail sizes must be defined:

<?php
class User extends AppModel {
	var $name = 'User';
	var $actsAs = array(
		'Upload.Upload' => array(
			'photo' => array(
				'fields' => array(
					'dir' => 'photo_dir'
				),
				'thumbsizes' => array(
					'xvga' => '1024x768',
					'vga' => '640x480',
					'thumb' => '80x80'
				)
			)
		)
	);
}
?>

Multiple files can also be attached to a single record:

<?php
class User extends AppModel {
	var $name = 'User';
	var $actsAs = array(
		'Upload.Upload' => array(
			'resume',
			'photo' => array(
				'fields' => array(
					'dir' => 'profile_dir'
				),
				'thumbsizes' => array(
					'xvga' => '1024x768',
					'vga' => '640x480',
					'thumb' => '80x80'
				)
			)
		)
	);
}
?>

Please read about the Behavior options for more details as to how to configure this plugin.

Behavior options:

  • pathMethod: The method to use for file paths. This is appended to the path option below
    • Default: (string) primaryKey
    • Options:
      • flat: Does not create a path for each record. Files are moved to the value of the ‘path’ option
      • primaryKey: Path based upon the record’s primaryKey is generated. Persists across a record
      • random: Random path is generated for each file upload. Does not persist across a record.
  • path: A path relative to the APP_PATH
    • Default: (string) 'webroot{DS}files{DS}{model}{DS}{field}{DS}'
    • Tokens:
      • {DS}: Replaced by a DIRECTORY_SEPARATOR
      • {model}: Replaced by the Model Alias
      • {field}: Replaced by the field name
  • fields: An array of fields to use when uploading files
    • Default: (array) array('dir' => 'dir', 'type' => 'type', 'size' => 'size')
    • Options:
      • dir: Field to use for storing the directory
      • type: Field to use for storing the filetype
      • size: Field to use for storing the filesize
  • mimetypes: Array of mimetypes to use for validation
    • Default: (array) empty
  • extensions: Array of extensions to use for validation
    • Default: (array) empty
  • maxSize: Max filesize in bytes for validation
    • Default: (int) 2097152
  • minSize: Minimum filesize in bytes for validation
    • Default: (int) 8
  • maxHeight: Maximum image height for validation
    • Default: (int) 0
  • minHeight: Minimum image height for validation
    • Default: (int) 0
  • maxWidth: Maximum image width for validation
    • Default: (int) 0
  • minWidth: Minimum image width for validation
    • Default: (int) 0
  • deleteOnUpdate: Whether to delete files when uploading new versions (potentially dangerous due to naming conflicts)
    • Default: (boolean) false
  • prefixStyle: Whether to prefix or suffix the style onto thumbnails
    • Default: (boolean) true
  • thumbnails: Whether to create thumbnails or not
    • Default: (boolean) true
  • thumbsizes: Array of thumbnail sizes, with the style-name mapping to a geometry
    • Default: (array) empty
  • thumbnailQuality: Quality of thumbnails that will be generated, on a scale of 0-100
    • Default: (int) 75
  • thumbnailMethod: The method to use for resizing thumbnails
    • Default: (string) imagick
    • Options:
      • imagick: Uses the PHP imagick extension to generate thumbnails
      • php: Uses the built-in PHP methods to generate thumbnails

Thumbnail Sizes and Styles

Styles are the definition of thumbnails that will be generated for original image. You can define as many as you want.

<?php
class User extends AppModel {
	var $name = 'User';
	var $actsAs = array(
		'Upload.Upload' => array(
			'photo' => array(
				'thumbsizes' => array(
					'big' => '200x200',
					'small' => '120x120'
					'thumb' => '80x80'
				)
			)
		)
	);
?>

Styles only apply to images of the following types:

  • image/bmp
  • image/gif
  • image/jpeg
  • image/pjpeg
  • image/png
  • image/vnd.microsoft.icon
  • image/x-icon

You can specify any of the following resize modes for your styles:

  • 100×80 – resize for best fit into these dimensions, with overlapping edges trimmed if original aspect ratio differs
  • [100×80] – resize to fit these dimensions, with white banding if original aspect ratio differs
  • 100w – maintain original aspect ratio, resize to 100 pixels wide
  • 80h – maintain original aspect ratio, resize to 80 pixels high
  • 80l – maintain original aspect ratio, resize so that longest side is 80 pixels

Validation rules

By default, no validation rules are attached to the model. One must explicitly attach each rule if needed. Rules not referring to PHP upload errors are configurable but fallback to the behavior configuration.

isUnderPhpSizeLimit

Check that the file does not exceed the max file size specified by PHP

var $validate = array(
	'photo' => array(
		'rule' => 'isUnderPhpSizeLimit',
		'message' => 'File exceeds upload filesize limit'
	)
);

isUnderFormSizeLimit

Check that the file does not exceed the max file size specified in the HTML Form

var $validate = array(
	'photo' => array(
		'rule' => 'isUnderFormSizeLimit',
		'message' => 'File exceeds form upload filesize limit'
	)
);

isCompletedUpload

Check that the file was completely uploaded

var $validate = array(
	'photo' => array(
		'rule' => 'isCompletedUpload',
		'message' => 'File was not successfully uploaded'
	)
);

isFileUpload

Check that a file was uploaded

var $validate = array(
	'photo' => array(
		'rule' => 'isFileUpload',
		'message' => 'File was missing from submission'
	)
);

tempDirExists

Check that the PHP temporary directory is missing

var $validate = array(
	'photo' => array(
		'rule' => 'tempDirExists',
		'message' => 'The system temporary directory is missing'
	)
);

isSuccessfulWrite

Check that the file was successfully written to the server

var $validate = array(
	'photo' => array(
		'rule' => 'isSuccessfulWrite',
		'message' => 'File was unsuccessfully written to the server'
	)
);

noPhpExtensionErrors

Check that a PHP extension did not cause an error

var $validate = array(
	'photo' => array(
		'rule' => 'noPhpExtensionErrors',
		'message' => 'File was not uploaded because of a faulty PHP extension'
	)
);

isValidMimeType

Check that the file is of a valid mimetype

var $validate = array(
	'photo' => array(
		'rule' => array('isValidMimeType', array('valid/mimetypes', 'array/here')),
		'message' => 'File is of an invalid mimetype'
	)
);

isWritable

Check that the upload directory is writable

var $validate = array(
	'photo' => array(
		'rule' => 'isWritable',
		'message' => 'File upload directory was not writable'
	)
);

isValidDir

Check that the upload directory exists

var $validate = array(
	'photo' => array(
		'rule' => 'isValidDir',
		'message' => 'File upload directory does not exist'
	)
);

isBelowMaxSize

Check that the file is below the maximum file upload size (checked in bytes)

var $validate = array(
	'photo' => array(
		'rule' => array('isBelowMaxSize', 1024),
		'message' => 'File is larger than the maximum filesize'
	)
);

isAboveMinSize

Check that the file is above the minimum file upload size (checked in bytes)

var $validate = array(
	'photo' => array(
		'rule' => array('isAboveMinSize', 1024),
		'message' => 'File is below the mimimum filesize'
	)
);

isValidExtension

Check that the file has a valid extension

var $validate = array(
	'photo' => array(
		'rule' => array('isValidExtension', array('ext', 'array', 'here')),
		'message' => 'File has an invalid extension'
	)
);

isAboveMinHeight

Check that the file is above the minimum height requirement (checked in pixels)

var $validate = array(
	'photo' => array(
		'rule' => array('isAboveMinHeight' 150),
		'message' => 'File is below the minimum height'
	)
);

isBelowMaxHeight

Check that the file is below the maximum height requirement (checked in pixels)

var $validate = array(
	'photo' => array(
		'rule' => array('isBelowMaxHeight', 150),
		'message' => 'File is above the maximum height'
	)
);

isAboveMinWidth

Check that the file is above the minimum width requirement (checked in pixels)

var $validate = array(
	'photo' => array(
		'rule' => array('isAboveMinWidth', 150),
		'message' => 'File is below the minimum width'
	)
);

isBelowMaxWidth

Check that the file is below the maximum width requirement (checked in pixels)

var $validate = array(
	'photo' => array(
		'rule' => array('isBelowMaxWidth', 150),
		'message' => 'File is above the maximum width'
	)
);