<?php
/*  ****************************************************************
                    :: _image :: 
                    Image upload and manipulation class
                    
                    Copyright MJDIGITAL ©2008
                    Written by Mark Jackson
                    All rights reserved 
    
*  ****************************************************************/

class _image {
    
// available properties (variables)    REDEFINE IN PAGE AS NEEDED
    
    // GENERIC - as in used by upload and resize functions
    
public $newName         '';                // new image name (without file extension)
    
public $returnType        'array';             // specify return type - fullPath | array | bool (you can also use 'file' ro the resize function)
    
public $safeRename        'true';            // rename the new file to remove unsafe characters and spaces
    
public $duplicates        'u';                 // u = make unique / o = overwrite / e = error / a = abort
    
    // UPLOAD FUNCTION
    
public $uploadTo        'uploaded/';        // folder to upload to (relative to calling document)
    
    // RESIZE FUNCTION
    
public $source_file     '';                // source file to resize
    
public $newWidth         '';                // new image width - e.g. '200' = 200 pixels
    
public $newHeight         '';                // new image height - e.g. '200' = 200 pixels
    
public $namePrefix         '';                // prefix the resized file
    
public $newPath         '';                // path to save the new resized file
    
public $aspectRatio     'true';            // keep the aspect ratio - true | false
    
public $padToFit         'true';            // pad the image with the pad colour to fit the new image dimensions - true | false
    
public $upscale         'false';            // enlarge smaller images or not - true | false
    
public $setPosition        'cc';                // set position of image within its canvas - e.g. 'cc' = center x center y OR 'tr' = top right
    
public $padColour         '';                // set background padding colour - '#XXXXXX' or 'transparent' (defaults to transparent or black from jpgs)
    
public $padTransparent    'true';             // if uploading a GIF or PNG then set background as transparent - this overrides $padColour
    
public $newImgType        '';                 // force resized image to be jpg | gif | png | wbmp - leave blank to match source type
    
public $imgQuality        '80';                // image quality 1-100 (%) - defaults to 80
    
    
    
    // array of all generated error messages
    
public $errors = array(
        
'no-image'         => '<strong>Error:</strong> Please specify a source image - declare: $mj_Image->source_file = "path_to_your_image_here.jpg";',
        
'no-width'         => '<strong>Error:</strong> Please specify a width for the new image - declare: $mj_Image->newWidth = 100;',
        
'no-height'     => '<strong>Error:</strong> Please specify a height for the new image - declare: $mj_Image->newheight = 100;',
        
'no-dir'        => '<strong>Error:</strong> The destination directory directory is missing and could not be created',
        
'image-exists'     => '<strong>Error:</strong> The image you specified already exists',
        
'upl-no-array'    => '<strong>Error:</strong> It appears the form did not submit a valid file - please try again.',
        
'upl-ini-max'    => '<strong>Error:</strong> The file uploaded exceeds the filesize limit set on this server',
        
'upl-maxsize'    => '<strong>Error:</strong> The file uploaded exceeds the filesize limit set for this form',
        
'upl-partial'    => '<strong>Error:</strong> The file was only partially uploaded - please try again',
        
'upl-no-file'    => '<strong>Error:</strong> No file was submitted for upload',
        
'upl-no-tmpDir'    => '<strong>Error:</strong> The temporary upload directory is missing',
        
'upl-cant-write'=> '<strong>Error:</strong> Failed to write to the temporary folder - please check the permissions',
        
'upl-ext'        => '<strong>Error:</strong> The upload was stopped due to an invalid file extension',
        
'rsz-ext'        => '<strong>Error:</strong> The image resizing was stopped due to an invalid file extension',
        
'upl-no-size'    => '<strong>Error:</strong> The file submitted for upload had a filesize of zero or was corrupt',
        
'upl-failed'    => '<strong>Error:</strong> The upload failed - the file could not be moved to the target location - please check the permissions'
    
);
    
    
#################################################
    #                     METHODS                    #
    #################################################

    // This function runs when this class is instantiated
    
public function __construct() {
        
//echo 'newImage Constructed';
        // set default values
        
$this->padColour = ($this->padColour=='') ? 'transparent' $this->padColour;
    }

    private function 
hex2dec($_hex) {
        
$_color str_replace('#'''$_hex);
        
$_ret = array(
            
'r' => hexdec(substr($_color02)),
            
'g' => hexdec(substr($_color22)),
            
'b' => hexdec(substr($_color42))
        );
        return 
$_ret;
    }
    
    public function 
cleanUp($str) {
        
$str stripslashes($str);
        
$str str_replace(' ','_',$str);
        
$str str_replace('.JPG','.jpg',$str);
        
$str str_replace('.PNG','.png',$str);
        
$str str_replace('.GIF','.gif',$str);
        
$str ereg_replace("[^A-Za-z0-9_\-\.]""",$str);
        return 
$str;
    }
    
    public function 
upload($ar) {
        
// ERROR CAPTURE
        
if(!isset($ar['name'])) { $this->doDie($this->errors['upl-no-array']); exit; } 
        if(
$ar['error']!=0) { 
            switch(
$ar['error']) {
                case 
1$this->doDie($this->errors['upl-ini-max']);     exit; break;
                case 
2$this->doDie($this->errors['upl-maxsize']);     exit; break;
                case 
3$this->doDie($this->errors['upl-partial']);     exit; break;
                case 
4$this->doDie($this->errors['upl-no-file']);     exit; break;
                case 
6$this->doDie($this->errors['upl-no-tmpDir']);     exit; break;
                case 
7$this->doDie($this->errors['upl-cant-write']);     exit; break;
                case 
8$this->doDie($this->errors['upl-ext']);         exit; break;
            }
        }
        if(
$ar['size']==0) { $this->doDie($this->errors['upl-no-size']); exit; } 

        
// create variables
        
$img_name         $ar['name'];
        
$img_type         $ar['type'];
        
$img_tmp_name     $ar['tmp_name'];
        
$img_error        $ar['error'];
        
$img_size        $ar['size'];
        
        
// rename file to safe filename
        
if($this->safeRename=='true') {
            
$imgName = ($this->newName!='') ? $this->newName $img_name;
            
$imgName $this->cleanUp(basename($img_name));
            
$imgPath str_replace(basename($img_name),"",$img_name);
            
$img_name $imgPath.$imgName;
        }
        
        
// set target path
        
$target_path $this->uploadTo basename($img_name);
        
        
// if path doesn't exist then create it and chmod to 0777
        
if(!file_exists($this->uploadTo)) { 
            @
mkdir($this->uploadTo0777);
            
// check it worked - if not then try creating with fopen
            
if(!file_exists($this->uploadTo)) {
                
$dir = @fopen($this->uploadTo"x+");
                
fclose($dir);
                
// check it worked - if not then throw error
                
if(!file_exists($this->uploadTo)) {
                    
$this->doDie($this->errors['no-dir']); exit;
                }
            }
        }
        
        
// Handle duplicates
        
if(file_exists($target_path)) {
            switch(
$this->duplicates) {
                case 
'o': break;
                case 
'e'$this->doDie($this->errors['image-exists']); exit;
                case 
'a': return false; break;
                default: 
// make unique
                    
$im = (strstr(basename($img_name),'.')) ? substr(basename($img_name),0,strrpos(basename($img_name),'.')) : basename($img_name);
                    
$ext str_replace($im,"",basename($img_name));
                    
$path $this->uploadTo;
                    
$i=1;
                    while(
file_exists($path.$im.$i.$ext)) {
                        
$i++;
                    }
                    
$imgName $im.$i.$ext;
                    
$imgPath str_replace(basename($img_name),"",$img_name);
                    
$img_name $imgPath.$imgName;
                    
$target_path $this->uploadTo $imgName;
            }
        }

        
// Do upload / move image to target path
        
if(move_uploaded_file($img_tmp_name$target_path)) {
            
// chmod file to 0777
            
if(file_exists($target_path)) {
                
chmod($target_path0777);
            }
            
            
// add uploaded file to $this->source_file for resize function quick access
            
$this->source_file $this->uploadTo.basename($img_name);
            
            
// Return image or array if required
            
if($this->returnType=='array') {
                
$_ar = array(
                    
'image'     => basename($img_name),
                    
'path'        => $this->uploadTo,
                    
'size'        => $img_size,
                    
'type'        => substr(basename($img_name),strrpos(basename($img_name),'.'))
                );
                return 
$_ar;
            } elseif(
$this->returnType=='fullPath') {
                return (
file_exists($target_path)) ? $target_path false;
            } else {
                return (
file_exists($target_path)) ? true false;
            }
        } else{
            
$this->doDie($this->errors['upl-failed']); exit;
        }
    }
    
    public function 
resize() {
        
// ERROR CAPTURE
        
if($this->newWidth=='') {     $this->doDie($this->errors['no-width']); exit; }
        if(
$this->newHeight=='') {     $this->doDie($this->errors['no-height']); exit; }
        
$sImage = (($this->source_file!='')&&(file_exists($this->source_file))) ? $this->source_file $this->doDie($this->errors['no-image']);
        
        
// make sure the new dimentions are numbers
        
$this->newWidth = (!is_int($this->newWidth)) ? intval($this->newWidth) : $this->newWidth;
        
$this->newHeight = (!is_int($this->newHeight)) ? intval($this->newHeight) : $this->newHeight;
        
        
// get image details
        
$image_info getimagesize($sImage);
        
        
// select the filetype based on file MIME
        // set source as resource
        
switch ($image_info['mime']) {
            case 
'image/gif':
                if (
imagetypes() & IMG_GIF)  { // not the same as IMAGETYPE
                    
$src imagecreatefromgif($this->source_file);
                    
$this->imgType = ($this->newImgType!='') ? $this->newImgType 'gif';
                } else {
                    
$this->doDie($this->errors['rsz-ext'].' - GIF images are not supported');
                }
                break;
            case 
'image/jpeg':
                if (
imagetypes() & IMG_JPG)  {
                    
$src imagecreatefromjpeg($this->source_file) ;
                    
$this->imgType = ($this->newImgType!='') ? $this->newImgType 'jpg';
                } else {
                    
$this->doDie($this->errors['rsz-ext'].' - JPEG images are not supported');
                }
                break;
            case 
'image/png':
                if (
imagetypes() & IMG_PNG)  {
                    
$src imagecreatefrompng($this->source_file);
                    
$this->imgType = ($this->newImgType!='') ? $this->newImgType 'png';
                } else {
                    
$this->doDie($this->errors['rsz-ext'].' - PNG images are not supported');
                }
                break;
            case 
'image/wbmp':
                if (
imagetypes() & IMG_WBMP)  {
                    
$src imagecreatefromwbmp($this->source_file) ;
                    
$this->imgType = ($this->newImgType!='') ? $this->newImgType 'wbmp';
                } else {
                    
$this->doDie($this->errors['rsz-ext'].' - WBMP images are not supported');
                }
                break;
            default:
                
$this->doDie($this->errors['rsz-ext'].' - '.$image_info['mime'].' files are not supported');
                break;
        }
        
        
$srcPath = (strstr($sImage,'/')) ? substr($sImage,0,strrpos($sImage,'/')+1) : '';
        
$srcName str_replace($srcPath,'',$sImage);
        
        
$path = ($this->newPath!='') ? trim($this->newPath) : trim($srcPath);
        
$path = (substr($path,strlen($path)-1,strlen($path))!='/') ? $path.'/' $path;
        
$imgName = ($this->newName!='') ? $this->newName $srcName;
        
        
$imgName = (strstr($imgName,'.')) ? substr($imgName,0,strrpos($imgName,'.')).'.'.$this->imgType 
                                          
$imgName.'.'.$this->imgType// make sure it has the correct extension
        
        
$preFix = ($this->namePrefix!='') ? $this->namePrefix '';
        
        
// if path doesn't exist then create it and chmod to 0777
        
if(!file_exists($path)) { 
            @
mkdir($path0777);
            
// check it worked - if not then try creating with fopen
            
if(!file_exists($path)) {
                
$dir = @fopen($path"x+");
                
fclose($dir);
                
// check it worked - if not then throw error
                
if(!file_exists($path)) {
                    
$this->doDie($this->errors['no-dir']); exit;
                }
            }
        }
        
        
// rename file to safe filename
        
if($this->safeRename=='true') {
            
$imgName $this->cleanUp($imgName);
        }
        
        
// Handle duplicates
        
if(file_exists($path.$preFix.$imgName)) {
            switch(
$this->duplicates) {
                case 
'o': break;
                case 
'e'$this->doDie($this->errors['image-exists']); exit;
                case 
'a': return false; break;
                default: 
// make unique
                    
$im = (strstr($imgName,'.')) ? substr($imgName,0,strrpos($imgName,'.')) : $imgName;
                    
$i=1;
                    while(
file_exists($path.$im.$i.'.'.$this->imgType)) {
                        
$i++;
                    }
                    
$imgName $im.$i.'.'.$this->imgType;
            }
        }
        
        
// Source dimensions
        
$s_width imagesx($src);
        
$s_height imagesy($src);
        
        
// canvas dimensions
        
$c_width $this->newWidth;
        
$c_height $this->newHeight;
        
        
// maintain the aspect ratio
        
if($this->aspectRatio=='true') {
            if(
$s_width $s_height) { 
                
$resize_pc = ($this->newWidth/$s_width);
                
// make sure the new dimensions fit into defined space
                
if(round($s_height*$resize_pc)<=$this->newHeight) {
                    
$this->newHeight round($s_height*$resize_pc);
                } else {
                    
$resize_pc = ($this->newHeight/$s_height);
                    
$this->newWidth round($s_width*$resize_pc);
                }
            } else { 
                
$resize_pc = ($this->newHeight/$s_height);
                
// make sure the new dimensions fit into defined space
                
if(round($s_width*$resize_pc)<=$this->newWidth) {
                    
$this->newWidth round($s_width*$resize_pc);
                } else {
                    
$resize_pc = ($this->newWidth/$s_width);
                    
$this->newHeight round($s_height*$resize_pc);
                }
            } 
        }
        
        if(
$this->padToFit!='true') {
            
$c_width $this->newWidth;
            
$c_height $this->newHeight;
        } 
        
        if(
$this->upscale!='true'){
            
// do not upscale image
            
if(($s_width<=$this->newWidth)&&($s_height<=$this->newHeight)) {
                
$this->newWidth $s_width;
                
$this->newHeight $s_height;
            }
        }
        
        
// set the position of source in the canvas
        
if($this->padToFit=='true') {
            
// set positions
            
$top $left 0;
            
$right $c_width-$this->newWidth;
            
$cenX = ($c_width/2)-($this->newWidth/2);
            
$cenY = ($c_height/2)-($this->newHeight/2);
            
$bottom $c_height-$this->newHeight;
            switch(
$this->setPosition) {
                case 
'tl'// top left
                    
$toPos = array('dx'=>$left,'dy'=>$top,'sx'=>0,'sy'=>0); break;
                case 
'tr'// top right
                    
$toPos = array('dx'=>$right,'dy'=>$top,'sx'=>0,'sy'=>0); break;
                case 
'tc'// top centre
                    
$toPos = array('dx'=>$cenX,'dy'=>$top,'sx'=>0,'sy'=>0); break;
                case 
'bl'// bottom left
                    
$toPos = array('dx'=>$left,'dy'=>$bottom,'sx'=>0,'sy'=>0); break;
                case 
'br'// bottom right
                    
$toPos = array('dx'=>$right,'dy'=>$bottom,'sx'=>0,'sy'=>0); break;
                case 
'bc'// bottom centre
                    
$toPos = array('dx'=>$cenX,'dy'=>$bottom,'sx'=>0,'sy'=>0); break;
                case 
'cl'// centre left
                    
$toPos = array('dx'=>$left,'dy'=>$cenY,'sx'=>0,'sy'=>0); break;
                case 
'cr'// centre right
                    
$toPos = array('dx'=>$right,'dy'=>$cenY,'sx'=>0,'sy'=>0); break;
                default: 
// centred horz + vert
                    
$toPos = array('dx'=>$cenX,'dy'=>$cenY,'sx'=>0,'sy'=>0); break;
            }
        } else {
            
$toPos = array('dx'=>0,'dy'=>0,'sx'=>0,'sy'=>0);
        }

        
// Create target image
        
$canvas imagecreatetruecolor($c_width$c_height);
        
        
// colour the canvas
        
if(($this->padColour=='transparent')&&(($this->imgType=='gif')||($this->imgType=='png')))  {
            if(
$this->imgType=='gif') {
                
imagealphablending($canvasfalse);
                
imagesavealpha($canvas,true);
                
$trans_colour imagecolorallocatealpha($canvas000127);
                
imagefilledrectangle($canvas00$c_width$c_height$trans_colour);
                
imagecolortransparent($canvas$trans_colour);
            } else {
                
$imgName str_replace('.'.$this->imgType,'.png',$imgName);
                
$this->imgType 'png'// default to PNG
                
imagesavealpha($canvastrue);
                
$trans_colour imagecolorallocatealpha($canvas000127);
                
imagefill($canvas00$trans_colour);
            }
        } else {
            
$col $this->hex2dec($this->padColour);
            
$bgCol imagecolorallocate($canvas$col['r'], $col['g'], $col['b']);
            
imagefill($canvas00$bgCol);
        }

        
// Copy image
        
imagecopyresampled($canvas$src$toPos['dx'], $toPos['dy'], $toPos['sx'], $toPos['sy'], $this->newWidth$this->newHeight$s_width$s_height);
        
        
// output headers
        
if($this->returnType=='file') {
            switch(
$this->imgType) {
                case 
'gif'$mime 'image/gif'; break;
                case 
'png'$mime 'image/png'; break;
                case 
'wbmp'$mime 'image/vnd.wap.wbmp'; break;
                default: 
$mime 'image/jpeg'; break;
            }
            
$length strlen($imagedata);
            
header('Last-Modified: '.date('r'));
            
header('Accept-Ranges: bytes');
            
header('Content-Length: '.$length);
            
header('Cache-Control: private');
            
header("Content-Type: $mime");
        }
        
        
// Output file
        
if(($this->padColour=='transparent')&&(($this->imgType=='gif')||($this->imgType=='png'))) {
            switch(
$this->imgType) {
                case 
'gif'
                    
$newImg = ($this->returnType!='file') ? imagegif($canvas$path.$preFix.$imgName) : imagegif($canvas);
                    break;
                default:     
                    
$quality round(intval($this->imgQuality)/10);
                    
$newImg = ($this->returnType!='file') ? imagepng($canvas$path.$preFix.$imgName$quality) : imagepng($canvas);
                    break;
            }
        } else {
            switch(
$this->imgType) {
                case 
'gif'
                    
$newImg = ($this->returnType!='file') ? imagegif($canvas$path.$preFix.$imgName) : imagegif($canvas);
                    break;
                case 
'png':
                    
$quality round(intval($this->imgQuality)/10);
                    
$newImg = ($this->returnType!='file') ? imagepng($canvas$path.$preFix.$imgName,$quality) : imagepng($canvas);
                    break;
                case 
'wbmp':     
                    
$newImg = ($this->returnType!='file') ? imagewbmp($canvas$path.$preFix.$imgName) : imagewbmp($canvas);
                    break;
                default:         
                    
$newImg = ($this->returnType!='file') ? imagejpeg($canvas$path.$preFix.$imgName$this->imgQuality) : imagejpeg($canvas);
                    break;
            }
        }
        
        
// clean up
        
imagedestroy($src);
        
imagedestroy($canvas);
        
        
// Return image or array if required
        
if($this->returnType=='array') {
            
$_ar = array(
                
'image'     => $imgName,
                
'prefix'    => $preFix,
                
'path'        => $path,
                
'height'    => $c_height,
                
'width'        => $c_width,
                
'bgcolor'    => $this->padColour,
                
'type'        => $this->imgType
            
);
            return 
$_ar;
        } elseif(
$this->returnType=='fullPath') {
            return (
file_exists($path.$preFix.$imgName)) ? $path.$preFix.$imgName false;
        } elseif(
$this->returnType=='file') {
            
ob_start();
            print(
$newImg);
            
ob_end_flush();
            exit;
        } else {
            return (
file_exists($path.$preFix.$imgName)) ? true false;
        }
}

    public function 
doDie($msg,$file="",$line="") {                     // doDie - calls a die function with custom error
        
if (($file!='')&&($line!='')) {
        die(    
'<h4>Error:</h4>'.$msg.'<br/><br/>'.
                 
'<strong>File:</strong> '.$file.
                
' - <strong>on line:</strong> '.$line.
                
'</body></html>');
        } else {
        die(    
$msg);
        }
    }
// END OF CLASS






// TEST CODE - I would advise you delete the below and just include this class in other documents

if(isset($_FILES['image'])) {
$myImage = new _image;
$myImage->uploadTo 'testDir/';
$res $myImage->upload($_FILES['image']);
if(
$res) {
    
// RESIZE to 
    
$myImage->newWidth 400;
    
$myImage->newHeight 300;
    
$myImage->newImgType 'png'// force output to PNG
    
$i $myImage->resize();
    if(isset(
$i)) {
        echo 
'<pre>';
        
print_r($i);
        echo 
'</pre>';
    }
}
} else {
?>
<form action="" method="post" enctype="multipart/form-data" name="myForm" id="myForm">
    <p>
        <input type="file" name="image" id="image" />
    </p>
    <p>
        <input type="submit" name="button" id="button" value="Submit" />
    </p>
</form>
<?php }

?>