06.14 php
digitalspaghetti
Note
Version 1.1 of my improved upload behaviour
  1. <?php
  2.  
  3. /**
  4. *  Improved Upload Behaviour
  5. *  This behaviour is based on Chris Partridge's upload behaviour (http://bin.cakephp.org/saved/17539)
  6. *  @author Tane Piper (digitalspaghetti@gmail.com)
  7. *  @link http://www.digitalspaghetti.me.uk
  8. *  @filesource http://bakery.cakephp.org/articles/view/improved-upload-behaviour-with-thumbnails-and-name-correction
  9. *  @version 1.1
  10. *  @modifiedby      $LastChangedBy:$
  11. *  @lastmodified    $Date:$
  12. *  @svn             $Id:$
  13. *
  14. *  Useage:
  15. *  1) Download this behaviour and place it in your models/behaviours/upload.php
  16. *  2) If you require thumbnails for image generation, download Nate's phpThumb Component (http://bakery.cakephp.org/articles/view/phpthumb-component)
  17. *  3) Insert the following SQL into your database.  This is a basic model you can expand on:
  18. *    CREATE TABLE `images` (
  19. *        `id` int(8) unsigned NOT NULL auto_increment,
  20. *     `filename` varchar(255) default NULL,
  21. *     `dir` varchar(255) default NULL,
  22. *     `mimetype` varchar(255) NULL,
  23. *     `filesize` int(11) unsigned default NULL,
  24. *     `created` datetime default NULL,
  25. *     `modified` datetime default NULL,
  26. *     PRIMARY KEY  (`id`) ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
  27. *  4) In your model that you want to have the upload behavior work, place the below code.  This example is for an Image model:
  28. *
  29. *  var $actsAs = array('Upload' => array(
  30. *        'filename' => array(
  31. *            'dir' => 'files/images',
  32. *            'overwrite_existing' => false,
  33. *            'create_directory' => false,
  34. *            'allowed_mime' => array('image/jpeg', 'image/pjpeg', 'image/gif', 'image/png'),
  35. *            'allowed_ext' => array('.jpg', '.jpeg', '.png', '.gif'),
  36. *            'thumbsizes' => array(
  37. *                   'small'  =>    array('width'=>100, 'height'=>100),
  38. *                    'medium'=>    array('width'=>220, 'height'=>220),
  39. *                    'large'   => array('width'=>800, 'height'=>600)
  40. *            )
  41. *        )
  42. *      )
  43. *  );
  44. *  The above code will save the uploaded file's name in the 'filename' field in database,
  45. *  it will not overwrite existing files, instead it will create a random filename if
  46. *  it already exists.
  47. *  Allowed Mimetypes and extentions should be pretty explanitory
  48. *  For thumbnails, when the file is uploaded, it will create 3 thumbnail sizes and prepend the name
  49. *  to the thumbfiles (i.e. image_001.jpg will produced thumb.small.image_001.jpg, thumb.medium.image_001.jpg, etc)
  50. *
  51. *  5) Create your upload view, make sure it's a multipart/form-data form, and the filename field is of type $form->file
  52. *  6) Make sure your directory is at least CHMOD 775, also check your php.ini MAX_FILE_SIZE is enough to support the filesizes you are uploading
  53. *
  54. *  Version Details
  55. *
  56. *  1.1
  57. *  + Improved Image scaling code
  58. *  + Fixed check to see if file exists and rename file to unique name
  59. *  + Improved model actsAs to allow more thumbnail sizes
  60. *
  61. *  1.0
  62. *  + Initial release with thumbnail code.
  63. */
  64.    
  65. uses('folder');
  66. uses('file');
  67.  
  68. class UploadBehavior extends ModelBehavior {
  69.    
  70.     var $default_options = array('dir' => '',
  71.                                  'allowed_mime' => array(),
  72.                                  'allowed_ext' => array(),
  73.                                  'overwrite_existing' => false,
  74.                                  'create_directory' => true,
  75.                                  'thumbsizes' => array()
  76.     );
  77.                                 
  78.     var $__fields = array();
  79.    
  80.     var $patterns = array(
  81.                             "/\s/", # Whitespace
  82.                             "/\&/", # Ampersand
  83.                             "/\+/"  # Plus
  84.                             );
  85.     var $replacements = array(
  86.                                 "_",   # Whitespace
  87.                                 "and", # Ampersand
  88.                                 "plus" # Plus
  89.                                 );
  90.  
  91.     function setup(&$model, $config=array()) {
  92.        
  93.         //$this->File = &new File;
  94.         $this->Folder = &new Folder;
  95.        
  96.         foreach($config as $field => $options) {
  97.            
  98.             // Check if given field exists
  99.             if(!$model->hasField($field)) {
  100.                 unset($config[$field]);
  101.                 unset($model->data[$model->name][$field]);
  102.             }
  103.            
  104.             // Merge given options with defaults
  105.             $options = array_merge($this->default_options, $options);
  106.            
  107.             // Generate temporary directory if none provided
  108.             if(empty($options['dir'])) {
  109.                 $options['dir'] = 'img' . DS . 'uploads' . DS . $model->name;
  110.             }
  111.            
  112.             // Check if directory exists and create it if required
  113.             if(!is_dir($options['dir'])) {
  114.                 if($options['create_directory'] && !$this->Folder->mkdirr($options['dir'])) {
  115.                     unset($config[$field]);
  116.                     unset($model->data[$model->name][$field]);
  117.                 }
  118.             }
  119.            
  120.             // Check if directory is writable
  121.             if(!is_writable($options['dir'])) {
  122.                 unset($config[$field]);
  123.                 unset($model->data[$model->name][$field]);
  124.             }
  125.            
  126.             // Check that the given directory does not have a DS on the end
  127.             if($options['dir'][strlen($options['dir'])-1] == DS) {
  128.                 $options['dir'] = substr($options['dir'],0,strlen($options['dir'])-2);
  129.             }
  130.                
  131.         }
  132.        
  133.         $this->__fields = $config
  134.     }
  135.    
  136.    
  137.     function beforeSave(&$model)
  138.     {
  139.        
  140.         $filtered_filename = '';
  141.         $random_filename = false;
  142.        
  143.         if(count($this->__fields) > 0) {
  144.             foreach($this->__fields as $field=>$options) {
  145.                
  146.                 // Check for upload
  147.                 if(isset($model->data) && !is_array($model->data[$model->name][$field])) {
  148.                     unset($model->data[$model->name][$field]);
  149.                     continue;
  150.                 }
  151.                    
  152.                 // Check error
  153.                 if($model->data[$model->name][$field]['error'] > 0) {
  154.                     unset($model->data[$model->name][$field]);
  155.                     continue;
  156.                 }
  157.                
  158.                 // Fix name
  159.                 $filename = preg_replace($this->patterns,$this->replacements,$model->data[$model->name][$field]['name']);
  160.                 for ($i=0;$i<strlen($filename);$i++) {
  161.                     $current_char = substr($filename,$i,1);
  162.                     if (ctype_alnum($current_char) == TRUE || $current_char == "_" || $current_char == ".") {
  163.                         $filtered_filename .= $current_char;
  164.                     }
  165.                 }
  166.                
  167.                 $model->data[$model->name][$field]['name'] = $filtered_filename;
  168.  
  169.                 // Check mime
  170.                 if(count($options['allowed_mime']) > 0 && !in_array($model->data[$model->name][$field]['type'], $options['allowed_mime'])) {
  171.                     unset($model->data[$model->name][$field]);
  172.                     continue;
  173.                 }
  174.                
  175.                 // Check extensions
  176.                 if(count($options['allowed_ext']) > 0) {
  177.                    
  178.                     $matches = 0;
  179.                     foreach($options['allowed_ext'] as $extension) {
  180.                         if(substr($model->data[$model->name][$field]['name'],-strlen($extension)) == $extension) {
  181.                             $matches++;
  182.                             $keepext = $extension;
  183.                         }
  184.                     }
  185.                    
  186.                     if($matches == 0) {
  187.                         unset($model->data[$model->name][$field]);
  188.                         continue;
  189.                     }
  190.                    
  191.                 }
  192.                
  193.                 // Create final save path
  194.                 $saveAs = $options['dir'] . DS . $model->data[$model->name][$field]['name'];
  195.                
  196.                 // Check if file exists
  197.                 if(file_exists($saveAs)) {
  198.                     if(!$options['overwrite_existing'] || !unlink($saveAs)) {
  199.                         $model->data[$model->name][$field]['name'] = uniqid("") . $keepext;
  200.                         $saveAs = $options['dir'] . DS . $model->data[$model->name][$field]['name'];
  201.                     }
  202.                 }
  203.                
  204.                 // Attempt to move uploaded file
  205.                 if(!move_uploaded_file($model->data[$model->name][$field]['tmp_name'], $saveAs)) {
  206.                     unset($model->data[$model->name][$field]);
  207.                     continue;
  208.                 }
  209.                
  210.                 // Create thumbnail of uploaded image
  211.                 // This is hard-coded to only support JPEG + PNG at this time
  212.                 // Code unable to handle other formats
  213.                 if (count($options['allowed_ext']) > 0 && in_array($model->data[$model->name][$field]['type'], array('image/jpeg', 'image/pjpeg', 'image/png')))
  214.                 {
  215.                     foreach ($options['thumbsizes'] as $key => $value) :
  216.                         $this->createthumb($saveAs, $options['dir'] . DS . 'thumb.' . $key . '.' . $model->data[$model->name][$field]['name'], $value['width'], $value['height']);
  217.                     endforeach;
  218.                 }
  219.                
  220.                 // Update model data
  221.                 $model->data[$model->name]['dir'] = $options['dir'];
  222.                 $model->data[$model->name]['mimetype']$model->data[$model->name][$field]['type'];            
  223.                 $model->data[$model->name]['filesize'] = $model->data[$model->name][$field]['size'];
  224.                 $model->data[$model->name][$field] = $model->data[$model->name][$field]['name'];
  225.             }
  226.         }
  227.     }
  228.    
  229.    
  230.     // FIXME: This currently does not delete images :(
  231.     function beforeDelete(&$model)
  232.     {
  233.         if(count($this->__fields) > 0)
  234.         {
  235.             $model->read(null, $model->id);
  236.             if (isset($model->data))
  237.             {
  238.                 foreach($this->__fields as $field=>$options)
  239.                 {
  240.                     $file = $model->data[$model->name][$field];
  241.                     if(is_file($file))
  242.                     {
  243.                         $dir=$options['dir'];
  244.                         $folder = &new Folder($dir);
  245.                         $files = $folder->find('[a-zA-Z0-9]+x[a-zA-Z0-9]+.'.basename($file));
  246.                         foreach($files as $f) unlink($dir.$f);
  247.                         if (!unlink($file))
  248.                             return false;
  249.                     }
  250.                 }
  251.             }
  252.         }
  253.         return true;
  254.     }
  255.    
  256.     // Function to create thumbnail image
  257.     // This requires Nate Constant's thumbnail generator for PHPThumb
  258.     // http://bakery.cakephp.org/articles/view/phpthumb-component
  259.     function createthumb($name, $filename, $new_w, $new_h)
  260.     {
  261.         loadComponent('thumb');
  262.         $system = explode(".", $name);
  263.        
  264.         if (preg_match("/jpg|jpeg/", $system[1]))
  265.         {
  266.             $src_img = imagecreatefromjpeg($name);
  267.         }
  268.          
  269.         if (preg_match("/png/", $system[1]))
  270.         {
  271.             $src_img = imagecreatefrompng($name);
  272.         }
  273.        
  274.         $old_x = imagesx($src_img);
  275.         $old_y = imagesy($src_img);
  276.        
  277.         if ($old_x >= $old_y)
  278.         {
  279.             $thumb_w = $new_w;
  280.             $ratio = $old_y / $old_x;
  281.             $thumb_h = $ratio * $new_w;
  282.         } else if ($old_x < $old_y) {
  283.             $thumb_h = $new_h;
  284.             $ratio = $old_x / $old_y;
  285.             $thumb_w = $ratio * $new_h;
  286.         }
  287.  
  288.         $dst_img = imagecreatetruecolor($thumb_w, $thumb_h);
  289.         imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $thumb_w, $thumb_h, $old_x, $old_y);
  290.        
  291.         if (preg_match("/png/", $system[1]))
  292.         {
  293.             imagepng($dst_img, $filename);
  294.         } else {
  295.             imagejpeg($dst_img, $filename);
  296.         }
  297.  
  298.         imagedestroy($dst_img);
  299.         imagedestroy($src_img);
  300.     }
  301. }
  302. ?>
Parsed in 0.426 seconds, using GeSHi 1.0.7.14

Modify this Paste