My (mostly technical) blog

Archive for the ‘cakephp’ Category

I have never been more in need of a proper PHP debugger in my whole life. I have been stuck with a very mysterious behavior with CakePHP for the past 4 hours.

I was editing a model, then saving it. For some reason, my form action was changing from

/controller/edit/1
to
/controller/add

it was making me go crazy!

After seaching around (finally) I found this: https://trac.cakephp.org/ticket/5871
I came to realize that I have actually omitted the

<?= form->input('id'); ?>

from my edit view because I thought “why the hell do I need to edit the primary key?”

As it turns out, CakePHP needs a field (hidden or not) with the name ID or else it will revert to the ADD form.

Luckily though, it is smart enough to render it as a hidden field.

Google is your friend.

Advertisements
Tags: ,
UPDATE 2: Dear all, the code is now released under MIT license and is version controlled on github thanks to TuteC!

7/7/2009.

UPDATE: Please check this comment for a more updated example.

Component code updated on 30/4/2009, check the posted code or the download links.

I revisited the code I used to develop the old image resize component because I found a bug in the resize code. I used the resize function from the PImageComponent by Wendy and ended up with the current version I’m using at my websites:
Code download at the bottom of the post.

<?php
/*
 File: /app/controllers/components/image.php
*/
class ImageComponent extends Object
{
	/*
	*	Uploads an image and its thumbnail into $folderName/big and $folderName/small respectivley.
	* 	Also uploads a zoom cropped image into $folderName/home. You could easily modify it to suit your needs!
	
	* 	Directions:
	*	In view where you upload the image, make sure your form creation is similar to the following
	*	<?= $form->create('ControllerName',array('type' => 'file')); ?>
	

	*	In view where you upload the image, make sure that you have a file input similar to the following
	*	<?= $form->file('Image/image1'); ?>
	
	
	*	In the controller, add the component to your components array
	*	var $components = array("Image");
	

	*	In your controller action (the parameters are expained below)
	*	$image_path = $this->Image->upload_image_and_thumbnail($this->data,"name1", 573,380,80,80, "sets");
	*	this returns the file name of the result image.  You can  store this file name in the database
	*
	*	Note that your image will be stored in 3 locations:
	*	Image: /webroot/img/$folderName/big/$image_path 
	*	Thumbnail:  /webroot/img/$folderName/small/$image_path 
	*	Homepage:  /webroot/img/$folderName/home/$image_path  
	*
	*	You could easily add more locations or remove locations you don't need


	*	Finally in the view where you want to see the images
	*	<?= $html->image('sets/big/'.$furnitureSet['FurnitureSet']['image_path']);
	* 	where "sets" is the folder name we saved our pictures in, and $furnitureSet['FurnitureSet']['image_path'] is the file name we stored in the database
	

	*	Parameters:
	*	$data: the image data array from the form
	*	$maxw: the maximum width that you want your picture to be resized to
	*	$maxh: the maximum width that you want your picture to be resized to
	*	$thumbscalew: the maximum width hat you want your thumbnail to be resized to
	*	$thumbscaleh: the maximum height that you want your thumbnail to be resized to
	*	$folderName: the name of the parent folder of the images. The images will be stored to /webroot/img/$folderName/big/ and  /webroot/img/$folderName/small/
	*/	
	function upload_image_and_thumbnail($data, $maxw, $maxh, $thumbscalew, $thumbscaleh, $folderName) {
		if (strlen($data['name'])>4){ 
					$error = 0;
					$tempuploaddir = "img/temp"; // the /temp/ directory, should delete the image after we upload
					$homeuploaddir = "img/".$folderName."/home"; // the /home/ directory
					$biguploaddir = "img/".$folderName."/big"; // the /big/ directory
					$smalluploaddir = "img/".$folderName."/small"; // the /small/ directory for thumbnails
					
					// Make sure the required directories exist, and create them if necessary
					if(!is_dir($tempuploaddir)) mkdir($tempuploaddir,0755,true);
					if(!is_dir($homeuploaddir)) mkdir($homeuploaddir,0755,true);
					if(!is_dir($biguploaddir)) mkdir($biguploaddir,0755,true);
					if(!is_dir($smalluploaddir)) mkdir($smalluploaddir,0755,true);
					
					$filetype = $this->getFileExtension($data['name']);
					$filetype = strtolower($filetype);
 
					if (($filetype != "jpeg")  && ($filetype != "jpg") && ($filetype != "gif") && ($filetype != "png"))
					{
						// verify the extension
						return;
					}
					else
					{
						// Get the image size
						$imgsize = GetImageSize($data['tmp_name']);
					}

					// Generate a unique name for the image (from the timestamp)
					//$id_unic = str_replace(".", "", strtotime ("now"));
					$id_unic = $uuid = String::uuid();
					$filename = $id_unic;
					  
					settype($filename,"string");
					$filename.= ".";
					$filename.=$filetype;
					$tempfile = $tempuploaddir . "/$filename";
					$homefile = $homeuploaddir . "/$filename";
					$resizedfile = $biguploaddir . "/$filename";
					$croppedfile = $smalluploaddir . "/$filename";
					
					
					if (is_uploaded_file($data['tmp_name']))
                    {                    
						// Copy the image into the temporary directory
                        if (!copy($data['tmp_name'],"$tempfile"))
                        {
                            //print "Error Uploading File!.";
							unset($filename);
							unlink($tempfile);
                            exit(); 
                        }
						else {				
							/*
							 *	Generate the home page version of the image center cropped
							 */
							$this->resizeImage('resizeCrop', $tempuploaddir, $filename, $homeuploaddir, $filename, 886, 473, 85);
							/*
							 *	Generate the big version of the image with max of $imgscale in either directions
							 */
							$this->resizeImage('resize', $tempuploaddir, $filename, $biguploaddir, $filename, $maxw, $maxh, 85);							

							/*
							 *	Generate the small thumbnail version of the image with scale of $thumbscalew and $thumbscaleh
							 */
							$this->resizeImage('resizeCrop', $tempuploaddir, $filename, $smalluploaddir, $filename, $thumbscalew, $thumbscaleh, 75);
													
							// Delete the temporary image
							unlink($tempfile);
						}
                    }
 
                     // Image uploaded, return the file name
					 return $filename;   
		}
	}
	
	/*
	*	Deletes the image and its associated thumbnail
	*	Example in controller action:	$this->Image->delete_image("1210632285.jpg","sets");
	*
	*	Parameters:
	*	$filename: The file name of the image
	*	$folderName: the name of the parent folder of the images. The images will be stored to /webroot/img/$folderName/big/ and  /webroot/img/$folderName/small/
	*/
	function delete_image($filename,$folderName) {
		if(is_file("img/".$folderName."/home/".$filename))
			unlink("img/".$folderName."/home/".$filename);
		if(is_file("img/".$folderName."/big/".$filename))
			unlink("img/".$folderName."/big/".$filename);
		if(is_file("img/".$folderName."/small/".$filename))
			unlink("img/".$folderName."/small/".$filename);
	}
 
    function getFileExtension($str) {
 
        $i = strrpos($str,".");
        if (!$i) { return ""; }
        $l = strlen($str) - $i;
        $ext = substr($str,$i+1,$l);
        return $ext;
    }

	/*
	 * @param $cType - the conversion type: resize (default), resizeCrop (square), crop (from center) 
	 * @param $id - image filename
	 * @param $imgFolder  - the folder where the image is
	 * @param $newName - include extension (if desired)
	 * @param $newWidth - the  max width or crop width
	 * @param $newHeight - the max height or crop height
	 * @param $quality - the quality of the image
	 * @param $bgcolor - this was from a previous option that was removed, but required for backward compatibility
	 */
	function resizeImage($cType = 'resize', $srcfolder, $srcname, $dstfolder, $dstname = false, $newWidth=false, $newHeight=false, $quality = 75)
	{
		$srcimg = $srcfolder.DS.$srcname;
		list($oldWidth, $oldHeight, $type) = getimagesize($srcimg); 
		$ext = $this->image_type_to_extension($type);
		
		//check to make sure that the file is writeable, if so, create destination image (temp image)
		if (is_writeable($dstfolder))
		{
			$dstimg = $dstfolder.DS.$dstname;
		}
		else
		{
			//if not let developer know
			debug("You must allow proper permissions for image processing. And the folder has to be writable.");
			debug("Run \"chmod 777 on '$dstfolder' folder\"");
			exit();
		}
		
		//check to make sure that something is requested, otherwise there is nothing to resize.
		//although, could create option for quality only
		if ($newWidth OR $newHeight)
		{
			/*
			 * check to make sure temp file doesn't exist from a mistake or system hang up.
			 * If so delete.
			 */
			if(file_exists($dstimg))
			{
				unlink($dstimg);
			}
			else
			{
				switch ($cType){
					default:
					case 'resize':
						# Maintains the aspect ration of the image and makes sure that it fits
						# within the maxW(newWidth) and maxH(newHeight) (thus some side will be smaller)
						$widthScale = 2;
						$heightScale = 2;
						
						// Check to see that we are not over resizing, otherwise, set the new scale
						if($newWidth) {
							if($newWidth > $oldWidth) $newWidth = $oldWidth;
							$widthScale = 	$newWidth / $oldWidth;
						}
						if($newHeight) {
							if($newHeight > $oldHeight) $newHeight = $oldHeight;
							$heightScale = $newHeight / $oldHeight;
						}
						//debug("W: $widthScale  H: $heightScale<br>");
						if($widthScale < $heightScale) {
							$maxWidth = $newWidth;
							$maxHeight = false;							
						} elseif ($widthScale > $heightScale ) {
							$maxHeight = $newHeight;
							$maxWidth = false;
						} else {
							$maxHeight = $newHeight;
							$maxWidth = $newWidth;
						}
						
						if($maxWidth > $maxHeight){
							$applyWidth = $maxWidth;
							$applyHeight = ($oldHeight*$applyWidth)/$oldWidth;
						} elseif ($maxHeight > $maxWidth) {
							$applyHeight = $maxHeight;
							$applyWidth = ($applyHeight*$oldWidth)/$oldHeight;
						} else {
							$applyWidth = $maxWidth; 
								$applyHeight = $maxHeight;
						}
						$startX = 0;
						$startY = 0;
						break;
					case 'resizeCrop':
					
						// Check to see that we are not over resizing, otherwise, set the new scale						
						// -- resize to max, then crop to center
						if($newWidth > $oldWidth) $newWidth = $oldWidth;	
							$ratioX = $newWidth / $oldWidth;
						
						if($newHeight > $oldHeight) $newHeight = $oldHeight;
							$ratioY = $newHeight / $oldHeight;									
	
						if ($ratioX < $ratioY) { 
							$startX = round(($oldWidth - ($newWidth / $ratioY))/2);
							$startY = 0;
							$oldWidth = round($newWidth / $ratioY);
							$oldHeight = $oldHeight;
						} else { 
							$startX = 0;
							$startY = round(($oldHeight - ($newHeight / $ratioX))/2);
							$oldWidth = $oldWidth;
							$oldHeight = round($newHeight / $ratioX);
						}
						$applyWidth = $newWidth;
						$applyHeight = $newHeight;
						break;
					case 'crop':
						// -- a straight centered crop
						$startY = ($oldHeight - $newHeight)/2;
						$startX = ($oldWidth - $newWidth)/2;
						$oldHeight = $newHeight;
						$applyHeight = $newHeight;
						$oldWidth = $newWidth; 
						$applyWidth = $newWidth;
						break;
				}
				
				switch($ext)
				{
					case 'gif' :
						$oldImage = imagecreatefromgif($srcimg);
						break;
					case 'png' :
						$oldImage = imagecreatefrompng($srcimg);
						break;
					case 'jpg' :
					case 'jpeg' :
						$oldImage = imagecreatefromjpeg($srcimg);
						break;
					default :
						//image type is not a possible option
						return false;
						break;
				}
				
				//create new image
				$newImage = imagecreatetruecolor($applyWidth, $applyHeight);
								
				//put old image on top of new image
				imagecopyresampled($newImage, $oldImage, 0,0 , $startX, $startY, $applyWidth, $applyHeight, $oldWidth, $oldHeight);
				
					switch($ext)
					{
						case 'gif' :
							imagegif($newImage, $dstimg, $quality);
							break;
						case 'png' :
							imagepng($newImage, $dstimg, $quality);
							break;
						case 'jpg' :
						case 'jpeg' :
							imagejpeg($newImage, $dstimg, $quality);
							break;
						default :
							return false;
							break;
					}
				
				imagedestroy($newImage);
				imagedestroy($oldImage);
								
				return true;
			}

		} else {
			return false;
		}
		

	}

	function image_type_to_extension($imagetype)
	{
	if(empty($imagetype)) return false;
		switch($imagetype)
		{
			case IMAGETYPE_GIF    : return 'gif';
			case IMAGETYPE_JPEG    : return 'jpg';
			case IMAGETYPE_PNG    : return 'png';
			case IMAGETYPE_SWF    : return 'swf';
			case IMAGETYPE_PSD    : return 'psd';
			case IMAGETYPE_BMP    : return 'bmp';
			case IMAGETYPE_TIFF_II : return 'tiff';
			case IMAGETYPE_TIFF_MM : return 'tiff';
			case IMAGETYPE_JPC    : return 'jpc';
			case IMAGETYPE_JP2    : return 'jp2';
			case IMAGETYPE_JPX    : return 'jpf';
			case IMAGETYPE_JB2    : return 'jb2';
			case IMAGETYPE_SWC    : return 'swc';
			case IMAGETYPE_IFF    : return 'aiff';
			case IMAGETYPE_WBMP    : return 'wbmp';
			case IMAGETYPE_XBM    : return 'xbm';
			default                : return false;
		}
	}
	} 
?>

to use it in your controller,


<?php
class FurnitureSetsController extends AppController {

	var $name = 'FurnitureSets';
var $components = array("Image","RequestHandler");

function admin_add() {
 if (!empty($this->data)) { 
  $this->FurnitureSet->create();
   if ($this->FurnitureSet->save($this->data)) {
    // resize the image to 573x380 and create a square thumbnail 80x80
       $image_path = $this->Image->upload_image_and_thumbnail($this->data,"name1", 573,380,80,80, "sets");
    if(isset($image_path)) {
     $this->FurnitureSet->saveField('image_path',$image_path);
    }
    else {
     $this->Session->setFlash(__('The image for the set could not be saved. Please, try again.', true));
    }     

   }

 }
}

Note that you can modify the resize settings in the upload_image_and_thumbnail method.

The view..

<div class="furnitureSets form">
    <?php echo $form->create('FurnitureSet',array('type' => 'file'));?>
    <fieldset>
        <legend>
            <?php __('Add Furniture set');?>
        </legend>
        <?php
		echo $form->input('name');
		echo $form->input('country_id');
			?>
		<div class="input">
		<label for="Image/name1">Image</label>
		<?php
		echo $form->file('Image/name1', array('size' => '40'));
		?>
		</div>
		<?php
		echo $form->input('is_featured');
		echo $form->input('furniture_material_id');
		echo $form->input('furniture_category_id');
		echo $form->input('is_indoor');
		echo $form->input('is_outdoor');		
		echo $form->input('CustomerType');
	?>
    </fieldset>
    <?php echo $form->end('Submit');?>
</div>

Now as promised, the code!
30/4/2009: after modification from comments
17/7/2008: Old version

Again, thanks Wendy for your code!

Update:
Newer version

I needed to upload images to my CakePHP based website and at the same time, I needed to resize and create thumbnails of those images.

I found some different components on the Bakery and I found some code here, but I needed something more, I needed to have the ability to generate square zoomed thumbnails out of the uploaded images.

Since I was new to CakePHP and I wanted to improve my skills, I ended up taking code from several sources, writing some of my own, and integrating them in a component.

Big version resized using scale: 573

Small version resized using scale 110

Small version resized using scale 110 / square

You can download the code from here or here and you can take a look at it below.

<?php
/*
 File: /app/controllers/components/image.php
*/
class ImageComponent extends Object
{
    /*
    *    Uploads an image and its thumbnail into $folderName/big and $folderName/small respectivley.
    *     the  generated thumnail could either have the same aspect ratio as the uploaded image, or could
    *    be a zoomed and cropped version.

    *     Directions:
    *    In view where you upload the image, make sure your form creation is similar to the following
    *    <?= $form->create('FurnitureSet',array('type' => 'file')); ?>
    *
    *    In view where you upload the image, make sure that you have a file input similar to the following
    *    <?= $form->file('Image/name1'); ?>
    *
    *    In the controller, add the component to your components array
    *    var $components = array("Image");
    *
    *    In your controller action (the parameters are expained below)
    *    $image_path = $this->Image->upload_image_and_thumbnail($this->data,"name1",573,80,"sets",true);
    *    this returns the file name of the result image.  You can  store this file name in the database
    *
    *    Note that your image will be stored in 2 locations:
    *    Image: /webroot/img/$folderName/big/$image_path
    *    Thumbnail:  /webroot/img/$folderName/small/$image_path
    *
    *    Finally in the view where you want to see the images
    *    <?= $html->image('sets/big/'.$furnitureSet['FurnitureSet']['image_path']);
    *     where "sets" is the folder name we saved our pictures in, and $furnitureSet['FurnitureSet']['image_path'] is the file name we stored in the database

    *    Parameters:
    *    $data: CakePHP data array from the form
    *    $datakey: key in the $data array. If you used <?= $form->file('Image/name1'); ?> in your view, then $datakey = name1
    *    $imgscale: the maximum width or height that you want your picture to be resized to
    *    $thumbscale: the maximum width or height that you want your thumbnail to be resized to
    *    $folderName: the name of the parent folder of the images. The images will be stored to /webroot/img/$folderName/big/ and  /webroot/img/$folderName/small/
    *    $square: a boolean flag indicating whether you want square and zoom cropped thumbnails, or thumbnails with the same aspect ratio of the source image
    */
    function upload_image_and_thumbnail($data, $datakey, $imgscale, $thumbscale, $folderName, $square) {
        if (strlen($data['Image'][$datakey]['name'])>4){
                    $error = 0;
                    $tempuploaddir = "img/temp"; // the /temp/ directory, should delete the image after we upload
                    $biguploaddir = "img/".$folderName."/big"; // the /big/ directory
                    $smalluploaddir = "img/".$folderName."/small"; // the /small/ directory for thumbnails

                    // Make sure the required directories exist, and create them if necessary
                    if(!is_dir($tempuploaddir)) mkdir($tempuploaddir,true);
                    if(!is_dir($biguploaddir)) mkdir($biguploaddir,true);
                    if(!is_dir($smalluploaddir)) mkdir($smalluploaddir,true);

                    $filetype = $this->getFileExtension($data['Image'][$datakey]['name']);
                    $filetype = strtolower($filetype);

                    if (($filetype != "jpeg")  && ($filetype != "jpg") && ($filetype != "gif") && ($filetype != "png"))
                    {
                        // verify the extension
                        return;
                    }
                    else
                    {
                        // Get the image size
                        $imgsize = GetImageSize($data['Image'][$datakey]['tmp_name']);
                    }

                    // Generate a unique name for the image (from the timestamp)
                    $id_unic = str_replace(".", "", strtotime ("now"));
                    $filename = $id_unic;

                    settype($filename,"string");
                    $filename.= ".";
                    $filename.=$filetype;
                    $tempfile = $tempuploaddir . "/$filename";
                    $resizedfile = $biguploaddir . "/$filename";
                    $croppedfile = $smalluploaddir . "/$filename";

                    if (is_uploaded_file($data['Image'][$datakey]['tmp_name']))
                    {
                        // Copy the image into the temporary directory
                        if (!copy($data['Image'][$datakey]['tmp_name'],"$tempfile"))
                        {
                            print "Error Uploading File!.";
                            exit();
                        }
                        else {
                            /*
                             *    Generate the big version of the image with max of $imgscale in either directions
                             */
                            $this->resize_img($tempfile, $imgscale, $resizedfile);                            

                            if($square) {
                                /*
                                 *    Generate the small square version of the image with scale of $thumbscale
                                 */
                                $this->crop_img($tempfile, $thumbscale, $croppedfile);
                            }
                            else {
                                /*
                                 *    Generate the big version of the image with max of $imgscale in either directions
                                 */
                                $this->resize_img($tempfile, $thumbscale, $croppedfile);
                            }

                            // Delete the temporary image
                            unlink($tempfile);
                        }
                    }

                     // Image uploaded, return the file name
                     return $filename;
        }
    }

    /*
    *    Deletes the image and its associated thumbnail
    *    Example in controller action:    $this->Image->delete_image("1210632285.jpg","sets");
    *
    *    Parameters:
    *    $filename: The file name of the image
    *    $folderName: the name of the parent folder of the images. The images will be stored to /webroot/img/$folderName/big/ and  /webroot/img/$folderName/small/
    */
    function delete_image($filename,$folderName) {
        unlink("img/".$folderName."/big/".$filename);
        unlink("img/".$folderName."/small/".$filename);
    }

    function crop_img($imgname, $scale, $filename) {
        $filetype = $this->getFileExtension($imgname);
        $filetype = strtolower($filetype);

        switch($filetype){
            case "jpeg":
            case "jpg":
              $img_src = ImageCreateFromjpeg ($imgname);
             break;
             case "gif":
              $img_src = imagecreatefromgif ($imgname);
             break;
             case "png":
              $img_src = imagecreatefrompng ($imgname);
             break;
        }

        $width = imagesx($img_src);
        $height = imagesy($img_src);
        $ratiox = $width / $height * $scale;
        $ratioy = $height / $width * $scale;

        //-- Calculate resampling
        $newheight = ($width <= $height) ? $ratioy : $scale;
        $newwidth = ($width <= $height) ? $scale : $ratiox;

        //-- Calculate cropping (division by zero)
        $cropx = ($newwidth - $scale != 0) ? ($newwidth - $scale) / 2 : 0;
        $cropy = ($newheight - $scale != 0) ? ($newheight - $scale) / 2 : 0;

        //-- Setup Resample & Crop buffers
        $resampled = imagecreatetruecolor($newwidth, $newheight);
        $cropped = imagecreatetruecolor($scale, $scale);

        //-- Resample
        imagecopyresampled($resampled, $img_src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
        //-- Crop
        imagecopy($cropped, $resampled, 0, 0, $cropx, $cropy, $newwidth, $newheight);

        // Save the cropped image
        switch($filetype)
        {
            case "jpeg":
            case "jpg":
             imagejpeg($cropped,$filename,80);
             break;
             case "gif":
             imagegif($cropped,$filename,80);
             break;
             case "png":
             imagepng($cropped,$filename,80);
             break;
        }
    }

    function resize_img($imgname, $size, $filename)    {
        $filetype = $this->getFileExtension($imgname);
        $filetype = strtolower($filetype);

        switch($filetype) {
            case "jpeg":
            case "jpg":
            $img_src = ImageCreateFromjpeg ($imgname);
            break;
            case "gif":
            $img_src = imagecreatefromgif ($imgname);
            break;
            case "png":
            $img_src = imagecreatefrompng ($imgname);
            break;
        }

        $true_width = imagesx($img_src);
        $true_height = imagesy($img_src);

        if ($true_width>=$true_height)
        {
            $width=$size;
            $height = ($width/$true_width)*$true_height;
        }
        else
        {
            $width=$size;
            $height = ($width/$true_width)*$true_height;
        }
        $img_des = ImageCreateTrueColor($width,$height);
        imagecopyresampled ($img_des, $img_src, 0, 0, 0, 0, $width, $height, $true_width, $true_height);

        // Save the resized image
        switch($filetype)
        {
            case "jpeg":
            case "jpg":
             imagejpeg($img_des,$filename,80);
             break;
             case "gif":
             imagegif($img_des,$filename,80);
             break;
             case "png":
             imagepng($img_des,$filename,80);
             break;
        }
    }

    function getFileExtension($str) {

        $i = strrpos($str,".");
        if (!$i) { return ""; }
        $l = strlen($str) - $i;
        $ext = substr($str,$i+1,$l);
        return $ext;
    }
} ?>

Ahmed Sabbour's Facebook profile
November 2017
S M T W T F S
« Jul    
 1234
567891011
12131415161718
19202122232425
2627282930  

Tweets

Error: Twitter did not respond. Please wait a few minutes and refresh this page.

RSS StackOverflow

Recently bookmarked