Use case: User uploads image to the web server. Image should be resized and cropped. Image saved to the database. Show successfully uploaded image on the web page.


Let’s start from the database end. The first thing I found about saving images in to the database was this. Analogously here is my SQL to create table:

CREATE TABLE `mymodels` (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `photo_data` blob,
  `photo_type` varchar(32) collate utf8_unicode_ci NOT NULL,
  `photo_size` int(10) UNSIGNED NOT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY  (`id`)
);

We want to allow save in to the database jpg images greater then 10kb; therefore we add validation to our model /app/models/mymodel.php

		'photo_size' => array('limit' => array('rule' => array('comparison', '<=', 10240))), //10kb
		'photo_type' => array('type' => array('rule' => array('comparison', '==', 'image/jpeg'))),

Additionally in controller we will invalidate files larger then 512kb. So, there are two levels of file size validation. You can remove any validation if necessary.
To show upload file element, current image and valiation error messages we add this line to our view:

echo $html->image('/mymodels/photo/'.$form->value('id'));
echo $form->input('photo', 	array(
	'size' => '40', 'type'=>'file',
	'label' => __('-models-mymodel-photo', true), 
	'error' => array( 
			'size' => sprintf(__('-models-mymodel-photo-error-size', true))
		)
	));
echo $form->error('photo_size', sprintf(__('-models-mymodel-photo-error-size', true)));
echo $form->error('photo_type', sprintf(__('-models-mymodel-photo-error-type', true)));

Note the field name is ‘photo’, this means the uploaded image data will be pased to the controller as array with name ‘photo’. On the other side our model expects photo_data, photo_type and photo_size. Therefore we add data transformation lines in the controller before model is saved:

			//parse photo data
			$personal = &$this->data['Personal'];
			$file = &$personal['photo']['tmp_name'];
			if (is_uploaded_file($file)) {
				if ($personal['photo']['size'] > 512*1024) { //max 256kb to upload
					$this->Personal->invalidate('photo_size');
				}
				else {
					//read image from stream and resize image
					$this->Thumbinal->output($file, $file, 
						array('width'  => 3*50, 'height' => 4*50, 
						'method' => $this->Thumbinal->THUMBNAIL_METHOD_SCALE_MIN,
						'align' => $this->Thumbinal->THUMBNAIL_ALIGN_CENTER,
						'type' => IMAGETYPE_JPEG));
					$personal['photo_type'] = $personal['photo']['type'];
					$personal['photo_data'] = fread(fopen($file, 'r'), filesize($file));
					$personal['photo_size'] = strlen($personal['photo_data']);
				}
			}
			unset($personal['photo']);

As you can see to resize uploaded image ThumbinalComponent is used. Nice code library to resize images I’ve borrowed from here. Unfortunatly it was not in the CakePHP component format, so I’ve spend some time to fit it. Here is the result /app/controllers/components/thumbinal.php

And the last peace of code will we add to controller will find record by id and write image to the response stream:

/*
 * Returns stream with photo image
 */
function photo($id) {
 
	//disable output that can corrupt image (for that action only)
	Configure::write('debug', '0');
	$this->autoRender=false;
	$this->Personal->cacheQueries=false;
 
	$rec = $this->Personal->findById($id, array('id', 'photo_data', 'photo_type', 'photo_size', 'modified'));
	$timestamp = strtotime($rec['Personal']['modified']);
 
	header('Last-Modified: '.gmdate('D, d M Y H:i:s', $timestamp).' GMT', true, 200);
	header('Expires: '.gmdate('D, d M Y H:i:s',  $timestamp + 60*60*48).' GMT', true, 200); // Set expiration time +48 hours
	header('Pragma: public');
	header('Content-type: '.$rec['Personal']['photo_type']);
	header('Content-length: '.$rec['Personal']['photo_size']);
	//uncomment this if you want user to download image
	//header('Content-Disposition: attachment; filename='.$rec['Personal']['id']);
 
	echo $rec['Personal']['photo_data'];
	exit();
}

That’s all. Happy coding. ;)

References:
http://cakebaker.wordpress.com/2006/04/15/file-upload-with-cakephp/
http://debugger.ru/articles/thumbnails
http://www.anyexample.com/programming/php/php_mysql_example__image_gallery_(blob_storage).xml

Posted by Rostislav Palivoda, filed under PHP. Date: April 8, 2008, 2:23 pm |

2 Responses

  1. ildar Says:

    Hi Rostislav,

    Good adaptation of the foreign code.
    Thanks for usage of my code.

  2. Rostislav Palivoda Says:

    Ildar, I found very useful not only the code but also the publication about thumbnails theory. Many thanks!

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.