phpThumb Component
This is my first attempt at writing a component for CakePHP. If you have any suggestions please add them to the comments and I'll incorporate them.
download the latest copy of phpThumb from http://phpthumb.sourceforge.net and extract it into your vendors directory. Should end up like: /vendors/phpThumb/{files}.
Add this file into your components directory (/app/components/thumb.php).
And here's an example usage in your controller.
Add this file into your components directory (/app/components/thumb.php).
Component Class:
<?php
/**
* Thumbnail Generator for CakePHP that uses phpThumb (http://phpthumb.sourceforge.net/)
*
* @package default
* @author Nate Constant
**/
class ThumbComponent{
/**
* The mime types that are allowed for images
*/
var $allowed_mime_types = array('image/jpeg','image/pjpeg','image/gif','image/png');
/**
* File system location to save thumbnail to. ** Must be writable by webserver
*/
var $image_location = 'images';
/**
* Array of errors
*/
var $errors = array();
/**
* Default width if not set
*/
var $width = 100;
/**
* Default height if not set
*/
var $height = 100;
/**
* do we zoom crop the image?
*/
var $zoom_crop = 0;//do not zoom crop
/**
* The original image uploaded
* @access private
*/
var $file;
var $controller;
var $model;
function startup( &$controller ) {
$this->controller = &$controller;
}
/**
* This is the method that actually does the thumbnail generation by setting up
* the parameters and calling phpThumb
*
* @return bool Success?
* @author Nate Constant
**/
function generateThumb($filename,$model){
// Make sure we have the name of the uploaded file and that the Model is specified
if(empty($filename) || !$this->controller->data[$model][$filename]){
$this->addError('non-existant file'.$filename);
return false;
}
// save the file to the object
$this->file = $this->controller->data[$model][$filename];
// verify that the size is greater than 0 ( emtpy file uploaded )
if(!$this->file['size']){
$this->addError('File Size is 0');
return false;
}
// verify that our file is one of the valid mime types
if(!in_array($this->file['type'],$this->allowed_mime_types)){
$this->addError('Invalid File type: '.$this->file['type']);
return false;
}
// verify that the filesystem is writable, if not add an error to the object
// dont fail if not and let phpThumb try anyway
if(!is_writable(WWW_ROOT.DS.$this->image_location)){
$this->addError('directory: '.WWW_ROOT.DS.$this->image_location.' is not writable.');
}
// Load phpThumb
vendor('phpThumb'.DS.'phpthumb.class');
$phpThumb = new phpThumb();
$phpThumb->setSourceFilename($this->file['tmp_name']);
$phpThumb->setParameter('w',$this->width);
$phpThumb->setParameter('h',$this->height);
$phpThumb->setParameter('zc',$this->zoom_crop);
if($phpThumb->generateThumbnail()){
if(!$phpThumb->RenderToFile(WWW_ROOT.DS.$this->image_location.DS.$this->file['name'])){
$this->addError('Could not render file to: '.$this->image_location.DS.$this->file['name']);
}
} else {
$this->addError('could not generate thumbnail');
}
// if we have any errors, remove any thumbnail that was generated and return false
if(count($this->errors)>0){
if(file_exists(WWW_ROOT.DS.$this->image_location.DS.$this->file['name'])){
unlink(WWW_ROOT.DS.$this->image_location.DS.$this->file['name']);
}
return false;
} else return true;
}
function addError($msg){
$this->errors[] = $msg;
}
}
?>
And here's an example usage in your controller.
Controller Class:
<?php
class ImagesController extends AppController
{
var $name = 'Images';
var $components = array('Thumb');
var $uses = array('Image');
function add(){
if(!empty($this->data)){
if($this->data['Image']['thumbnail']['size']){
pr($this->data);
if(!$this->Thumb->generateThumb('thumbnail','Image')){
pr($this->Thumb->errors);
}
}
}
}
}
?>

I have create related class, component, models, tables. but when i executed code it gives the following error.
Notice (8): Undefined index: Image [APP\controllers\images_controller.php, line 12]
I dont know whats wrong in my code.
Please help me!
Regards
(
[0] => could not generate thumbnail
)
Full solution here:
http://www.nabble.com/Re%3A-phpThumb-Component-p9689230.html
Short solution:
In the file phpthumb.class.php, change this:
$config_prefer_imagemagick = false;
$config_imagemagick_use_thumbnail = false;
and this:
$config_allow_src_above_docroot = true;
[end quote]
Could you please explain how to do this as I am having issues with my redirects now. Thanks
vendor('phpThumb'.DS.'phpthumb.class');
try
App::import('Vendor', 'PhpThumb', array('file' => 'phpThumb'.DS.'phpthumb.class.php'));
http://bin.cakephp.org/saved/21922
Watermarking would now be easy, look @ #6 and #7 on http://phpthumb.sourceforge.net/demo/demo/phpThumb.demo.demo.php
I changed one of the elements of the presets array in the component
from:
to:'fltr[]' => null,
'fltr' => null,
Then added two methods to the component that add and remove filters:
function addFilter($filter){
if($this->presets['fltr'] != null){
$this->presets['fltr'][]= $filter;
}else{
$this->presets['fltr']= array($filter);
}
}
function removeFilter($filter = true){
if($filter === true){
$this->presets['fltr']= null;
}else{
$offset= array_search($filter, $this->presets['fltr']);
if($offset !== false){
array_splice($this->presets['fltr'], $offset, 1);
}
}
}
Usage:
Let's say we want to have a red text placed on the center of the images:
$this->PhpThumb->addFilter('wmt|My Message|20|C|FF0000');
Check out http://phpthumb.sourceforge.net/demo/demo/phpThumb.demo.demo.php for more samples using filters.
However, it will require a bit of a re-write of the tutorial as it now has more functions and works in a different way.
I will understand if you don't want to do this, and i can just publish the code as it is as a snipit, Then write a full tutorial when i get the time.
The choice is yours :)
Drayen
Drayen
Component Class:
<?php
<?php
/* $Id$ */
/**
* PhpThumbComponent - A CakePHP Component to use with PhpThumb
* Copyright (C) 2007-2008 Alex McFadyen aka Drayen
*
* @license MIT
*/
/**
* PhpThumbComponent - A CakePHP Component to use with PhpThumb
* (http://phpthumb.sourceforge.net/)
*
* Based on CakePHP tutorial on : http://bakery.cakephp.org/articles/view/274
*
* This component will allow you to create/display thumbnails as well as have them
* auto generated and cached.
*
* Its set up to allow off site linking.
*
* @package PhpThumbComponent
* @subpackage controllers.components
*
* @author Alex McFadyen aka Drayen
*
* @version 0.1
**/
class PhpThumbComponent extends Component{
/**
* Array of errors
*/
var $errors = array();
/**
* The mime types that are allowed for images
*/
var $allowed_mime_types = array(IMAGETYPE_JPEG,IMAGETYPE_GIF,IMAGETYPE_PNG);
/**
* File system location to save thumbnails to.
*/
var $cache_location = null;
/**
* How old the cached image can be before its updated.
*/
var $max_cache_age = 7776000; #90 days in seconds
/**
* Default width if not set
*/
var $width = 100;
/**
* Default height if not set
*/
var $height = 100;
/**
* Jpeg quality
*/
var $quality = 100;
/**
* do we zoom crop the image?
*/
var $zoom_crop = 0;//do not zoom crop
/**
* keep a fixed aspect ratio?
*/
var $fixed_aspect_ratio = 1;//do not streach
/*
* When not zoom cropping, diffent aspect ratios causes space
* this is the fill colour
*/
var $background = 'FFFFFF';
var $controller;
var $model;
function startup( &$controller ) {
$this->controller = &$controller;
$this->cache_location = CACHE.'thumbs'.DS;
}
/**
* Will generate a thumbnail as defined by the presets (or by $_GET vars)
* and place it in the target. If display = true it will also output the
* thumbnail.
*
* @param string $source the location of the source image (may be relative or absolute)
* @param string $target the target directory and filename for the generated thumbnail
* @param bool $overwrite if the target should be overwritten
* @param bool $display if the image should be displayed
* @return bool Success?
* @author Alex McFadyen
*/
function generateThumbnail($source = null, $target = null, $overwrite = true, $display = false){
$target_dir = substr($target, 0, -(strpos(strrev($target),'/')));
if($source == null OR $target == null){//check correct params are set
$this->addError("Both source[$source] and target[$target] must be set");
return false;
}elseif(!is_file($source)){//check source is a file
$this->addError("Source[$source] is not a valid file");
return false;
}elseif(in_array($this->ImageTypeToMIMEtype($source), $this->allowed_mime_types)){//and is of allowed type
$this->addError("Source[$source] is not a valid file type");
return false;
}elseif(!is_writable($target_dir)){//check if target directory is writeable
$this->addError("Can not write to target directory [$target_dir]");
return false;
}elseif(is_file($target) AND !$overwrite){//check if target is a file already and not ok to be over written
$this->addError("Target[$target] exsists and overwrite is not true");
return false;
}elseif(is_file($target) AND !is_writable($target)){
$this->addError("Can not overwrite Target[$target]");
return false;
}
//load PhpThumb
vendor('phpThumb'.DS.'phpthumb.class');
$phpThumb = new phpThumb();
//set presets
$phpThumb->config_nohotlink_enabled = false;
$phpThumb->config_nooffsitelink_enabled = false;
$phpThumb->config_prefer_imagemagick = true;
$phpThumb->config_output_format = 'jpeg';
$phpThumb->config_error_die_on_error = true;
//load in source image
$phpThumb->setSourceFilename($source);
//load vars from $_GET if they are set
//width
if(!isset($_GET['w']))
$phpThumb->setParameter('w', $this->width);
else
$phpThumb->setParameter('w', $_GET['w']);
//height
if(!isset($_GET['h']))
$phpThumb->setParameter('h', $this->height);
else
$phpThumb->setParameter('h', $_GET['h']);
//zoom crop
if(!isset($_GET['zc']))
$phpThumb->setParameter('zc', $this->zoom_crop);
else
$phpThumb->setParameter('zc', $_GET['zc']);
//Fixed Aspect Ratio
if(!isset($_GET['far']))
$phpThumb->setParameter('far', $this->fixed_aspect_ratio);
else
$phpThumb->setParameter('far', $_GET['far']);
// background
if(!isset($_GET['bg']))
$phpThumb->setParameter('bg', $this->background);
else
$phpThumb->setParameter('bg', $_GET['bg']);
//quality
if(!isset($_GET['q']))
$phpThumb->setParameter('q', $this->quality);
else
$phpThumb->setParameter('q', $_GET['q']);
//create the thumbnail
if($phpThumb->generateThumbnail()){
if(!$phpThumb->RenderToFile($target)){
$this->addError('Could not render file to: '.$target);
}elseif($display==true){
$phpThumb->OutputThumbnail();
die();//not perfect, i know but it insures cake doenst add extra code after the image.
}
} else {
$this->addError('could not generate thumbnail');
}
// if we have any errors, remove any thumbnail that was generated and return false
if(count($this->errors)>0){
if(file_exists($target)){
unlink($target);
}
return false;
} else return true;
}
/**
* Display and/or generate a auto-named thumbnail, based on presets in $_GET.
*
* @param string $source the location of the source image (may be relative or absolute)
* @param bool $forceUpdate if the thumbnal should be refreashed
* @param bool $display if the image should be displayed
* @return bool Success?
* @author Alex McFadyen
*/
function displayThumbnail($source, $forceUpdate = false, $display = true){
if($source == null) $source = $_GET['src'];
$cache_filename = $this->cache_location . md5(env('REQUEST_URI')) . '_' . md5($source).'.jpg';
#check the cache'ed image exsists and its new enough and that it needs to be displayed
if(is_file($cache_filename) //file exsists
AND (time() < filectime($cache_filename) + $this->max_cache_age) //not too old
AND (is_file($source) ? ( filectime($cache_filename) > filectime($source) ) : true) //cached image is newer than source
AND ($display == true)
AND !($forceUpdate == true))
{
header('Content-Type: '.IMAGETYPE_JPEG);
@readfile($cache_filename);
exit();//not perfect, i know but it insures cake doenst add extra code after the image.
}else{
return $this->generateThumbnail($source, $cache_filename, true, $display);
}
}
/**
* Function borrowed form phpThumb libs
*/
function ImageTypeToMIMEtype($imagetype) {
if (function_exists('image_type_to_mime_type') && ($imagetype >= 1) && ($imagetype <= 16)) {
// PHP v4.3.0+
return image_type_to_mime_type($imagetype);
}
static $image_type_to_mime_type = array(
1 => 'image/gif', // IMAGETYPE_GIF
2 => 'image/jpeg', // IMAGETYPE_JPEG
3 => 'image/png', // IMAGETYPE_PNG
4 => 'application/x-shockwave-flash', // IMAGETYPE_SWF
5 => 'image/psd', // IMAGETYPE_PSD
6 => 'image/bmp', // IMAGETYPE_BMP
7 => 'image/tiff', // IMAGETYPE_TIFF_II (intel byte order)
8 => 'image/tiff', // IMAGETYPE_TIFF_MM (motorola byte order)
9 => 'application/octet-stream', // IMAGETYPE_JPC
10 => 'image/jp2', // IMAGETYPE_JP2
11 => 'application/octet-stream', // IMAGETYPE_JPX
12 => 'application/octet-stream', // IMAGETYPE_JB2
13 => 'application/x-shockwave-flash', // IMAGETYPE_SWC
14 => 'image/iff', // IMAGETYPE_IFF
15 => 'image/vnd.wap.wbmp', // IMAGETYPE_WBMP
16 => 'image/xbm', // IMAGETYPE_XBM
'gif' => 'image/gif', // IMAGETYPE_GIF
'jpg' => 'image/jpeg', // IMAGETYPE_JPEG
'jpeg' => 'image/jpeg', // IMAGETYPE_JPEG
'png' => 'image/png', // IMAGETYPE_PNG
'bmp' => 'image/bmp', // IMAGETYPE_BMP
'ico' => 'image/x-icon',
);
return (isset($image_type_to_mime_type[$imagetype]) ? $image_type_to_mime_type[$imagetype] : false);
}
function addError($msg){
$this->errors[] = $msg;
}
}
?>
?>
Nate
hey there, this is exactly what i need in my current project. has Drayen's code been published somewhere? thank you both for your work! :)
leo.
Hi Leo, there was talk of updating this code with mine, but both Nate and i seem to be very busy. I tried to publish my code but got rejected because this post exists ?!?! Here it is in the comments instead :)
Component Class:
<?php
<?php
/* $Id$ */
/**
* PhpThumbComponent - A CakePHP Component to use with PhpThumb
* Copyright (C) 2007-2008 Alex McFadyen aka Drayen
*
* @license MIT
*/
/**
* PhpThumbComponent - A CakePHP Component to use with PhpThumb
* (http://phpthumb.sourceforge.net/)
*
* Based on CakePHP tutorial on : http://bakery.cakephp.org/articles/view/274
*
* This component will allow you to create/display thumbnails as well as have them
* auto generated and cached.
*
* Its set up to allow off site linking.
*
* @package PhpThumbComponent
* @subpackage controllers.components
*
* @author Alex McFadyen aka Drayen
*
* @version 0.1
**/
class PhpThumbComponent extends Component{
/**
* Array of errors
*/
var $errors = array();
/**
* The mime types that are allowed for images
*/
var $allowed_mime_types = array(IMAGETYPE_JPEG,IMAGETYPE_GIF,IMAGETYPE_PNG);
/**
* File system location to save thumbnails to.
*/
var $cache_location = null;
/**
* How old the cached image can be before its updated.
*/
var $max_cache_age = 7776000; #90 days in seconds
/**
* Size in bytes that the cashe folder can reach before it over writes old images,
* comment out to disable
*/
var $max_cache_size = 10485760; //10 * 1024 * 1024;
/**
* Default width if not set
*/
var $width = 100;
/**
* Default height if not set
*/
var $height = 100;
/**
* Jpeg quality
*/
var $quality = 100;
/**
* do we zoom crop the image?
*/
var $zoom_crop = 0;//do not zoom crop
/**
* keep a fixed aspect ratio?
*/
var $fixed_aspect_ratio = 1;//do not streach
/*
* When not zoom cropping, diffent aspect ratios causes space
* this is the fill colour
*/
var $background = 'FFFFFF';
var $controller;
var $model;
function startup( &$controller ) {
$this->controller = &$controller;
$this->cache_location = CACHE.'thumbs'.DS;
}
/**
* Will generate a thumbnail as defined by the presets (or by $_GET vars)
* and place it in the target. If display = true it will also output the
* thumbnail.
*
* @param string $source the location of the source image (may be relative or absolute)
* @param string $target the target directory and filename for the generated thumbnail
* @param bool $overwrite if the target should be overwritten
* @param bool $display if the image should be displayed
* @return bool Success?
* @author Alex McFadyen
*/
function generateThumbnail($source = null, $target = null, $overwrite = true, $display = false){
$target_dir = substr($target, 0, -(strpos(strrev($target),'/')));
if($source == null OR $target == null){//check correct params are set
$this->addError("Both source[$source] and target[$target] must be set");
return false;/*
}elseif(!is_file($source)){//check source is a file
$this->addError("Source[$source] is not a valid file");
return false;*/
}elseif(in_array($this->ImageTypeToMIMEtype($source), $this->allowed_mime_types)){//and is of allowed type
$this->addError("Source[$source] is not a valid file type");
return false;
}elseif(!is_writable($target_dir)){//check if target directory is writeable
$this->addError("Can not write to target directory [$target_dir]");
return false;
}elseif(is_file($target) AND !$overwrite){//check if target is a file already and not ok to be over written
$this->addError("Target[$target] exsists and overwrite is not true");
return false;
}elseif(is_file($target) AND !is_writable($target)){
$this->addError("Can not overwrite Target[$target]");
return false;
}
//load PhpThumb
vendor('phpThumb'.DS.'phpthumb.class');
$phpThumb = new phpThumb();
//set presets
$phpThumb->config_nohotlink_enabled = false;
$phpThumb->config_nooffsitelink_enabled = false;
$phpThumb->config_prefer_imagemagick = true;
$phpThumb->config_output_format = 'jpeg';
$phpThumb->config_error_die_on_error = true;
$phpThumb->config_allow_src_above_docroot = true;
//optionals
if(isset($this->max_cache_size)) $phpThumb->config_cache_maxsize = $this->max_cache_size;
//load in source image
$phpThumb->setSourceFilename($source);
//load vars from $_GET if they are set
//width
if(!isset($_GET['w']))
$phpThumb->setParameter('w', $this->width);
else
$phpThumb->setParameter('w', $_GET['w']);
//height
if(!isset($_GET['h']))
$phpThumb->setParameter('h', $this->height);
else
$phpThumb->setParameter('h', $_GET['h']);
//zoom crop
if(!isset($_GET['zc']))
$phpThumb->setParameter('zc', $this->zoom_crop);
else
$phpThumb->setParameter('zc', $_GET['zc']);
//Fixed Aspect Ratio
if(!isset($_GET['far']))
$phpThumb->setParameter('far', $this->fixed_aspect_ratio);
else
$phpThumb->setParameter('far', $_GET['far']);
// background
if(!isset($_GET['bg']))
$phpThumb->setParameter('bg', $this->background);
else
$phpThumb->setParameter('bg', $_GET['bg']);
//quality
if(!isset($_GET['q']))
$phpThumb->setParameter('q', $this->quality);
else
$phpThumb->setParameter('q', $_GET['q']);
//create the thumbnail
if($phpThumb->generateThumbnail()){
if(!$phpThumb->RenderToFile($target)){
$this->addError('Could not render file to: '.$target);
}elseif($display==true){
$phpThumb->OutputThumbnail();
die();//not perfect, i know but it insures cake doenst add extra code after the image.
}
} else {
$this->addError('could not generate thumbnail');
}
// if we have any errors, remove any thumbnail that was generated and return false
if(count($this->errors)>0){
if(file_exists($target)){
unlink($target);
}
return false;
} else return true;
}
/**
* Display and/or generate a auto-named thumbnail, based on presets in $_GET.
*
* @param string $source the location of the source image (may be relative or absolute)
* @param bool $forceUpdate if the thumbnal should be refreashed
* @param bool $display if the image should be displayed
* @return bool Success?
* @author Alex McFadyen
*/
function displayThumbnail($source, $forceUpdate = false, $display = true){
if($source == null) $source = $_GET['src'];
$cache_filename = $this->cache_location . md5(env('REQUEST_URI')) . '_' . md5($source).'.jpg';
#check the cache'ed image exsists and its new enough and that it needs to be displayed
if(is_file($cache_filename) //file exsists
AND (time() < filectime($cache_filename) + $this->max_cache_age) //not too old
AND (is_file($source) ? ( filectime($cache_filename) > filectime($source) ) : true) //cached image is newer than source
AND ($display == true)
AND !($forceUpdate == true))
{
header('Content-Type: '.IMAGETYPE_JPEG);
@readfile($cache_filename);
exit();//not perfect, i know but it insures cake doenst add extra code after the image.
}else{
return $this->generateThumbnail($source, $cache_filename, true, $display);
}
}
/**
* Function borrowed form phpThumb libs
*/
function ImageTypeToMIMEtype($imagetype) {
if (function_exists('image_type_to_mime_type') && ($imagetype >= 1) && ($imagetype <= 16)) {
// PHP v4.3.0+
return image_type_to_mime_type($imagetype);
}
static $image_type_to_mime_type = array(
1 => 'image/gif', // IMAGETYPE_GIF
2 => 'image/jpeg', // IMAGETYPE_JPEG
3 => 'image/png', // IMAGETYPE_PNG
4 => 'application/x-shockwave-flash', // IMAGETYPE_SWF
5 => 'image/psd', // IMAGETYPE_PSD
6 => 'image/bmp', // IMAGETYPE_BMP
7 => 'image/tiff', // IMAGETYPE_TIFF_II (intel byte order)
8 => 'image/tiff', // IMAGETYPE_TIFF_MM (motorola byte order)
9 => 'application/octet-stream', // IMAGETYPE_JPC
10 => 'image/jp2', // IMAGETYPE_JP2
11 => 'application/octet-stream', // IMAGETYPE_JPX
12 => 'application/octet-stream', // IMAGETYPE_JB2
13 => 'application/x-shockwave-flash', // IMAGETYPE_SWC
14 => 'image/iff', // IMAGETYPE_IFF
15 => 'image/vnd.wap.wbmp', // IMAGETYPE_WBMP
16 => 'image/xbm', // IMAGETYPE_XBM
'gif' => 'image/gif', // IMAGETYPE_GIF
'jpg' => 'image/jpeg', // IMAGETYPE_JPEG
'jpeg' => 'image/jpeg', // IMAGETYPE_JPEG
'png' => 'image/png', // IMAGETYPE_PNG
'bmp' => 'image/bmp', // IMAGETYPE_BMP
'ico' => 'image/x-icon',
);
return (isset($image_type_to_mime_type[$imagetype]) ? $image_type_to_mime_type[$imagetype] : false);
}
/**
* Clears the current set cache directory of expired files (or all) images
*
* @param bool $clearAll if set, it will clear all the files in the cache directory
* @return bool true
* @author Alex McFadyen
*/
function clearCache($clearAll = false){
$files = glob($this->cache_location.'*.jpg');
foreach($files as $file)
if($clearAll OR time() < filectime($file))
unlink($file);
return true;
}
function addError($msg){
$this->errors[] = $msg;
}
}
?>
?>
Drayen
In the thumb.php component at line 99 add this code below the existing $this->addError() call:
$this->addError(implode('; ',$phpThumb->debugmessages));
This will tell you everything that phpThumb is doing and will help you track down the problem better.
Please, if you find common errors that I can add to the component that will give a better user experience, please add them in the comments here.
". ImageMagick is used wherever possible for speed. "
so I think you need to check in phpThumb somewhere :)
Thanks for the tutorial, but I am not able to run it.
I setup everything you detailed in your example.
However, it always says, unable to create thumb.
I know I don't have ImageMagick, but by definition of phpThumb, it should use GD library to create thumbs, but unfortunately, it's not.
When I go to the phpThumb/demos/phpThumb.demo.demo.php, I can see thumbnails getting created, which means that their code works, only there is a flag somewhere to use gd and not imagemagick?
Do you know of it?
-Mandy.