06.05 php saved
adrien.gibrat
Tags add more
Upload, behavior and standard  
Note
An upload behavior that give standard methods to validate uploaded files and set mimetype & filesize automagic model fields.

Do just upload, but do it well.

Sorry but it's not well documented!
  1. <?php
  2. if (!defined('FILES')) {
  3.     define('FILES', WWW_ROOT . 'files' . DS);
  4. }
  5. class UploadBehavior extends ModelBehavior {
  6.    
  7.     var $options    = array(       
  8.         'dir'       => null,
  9.         'filename'  => null,
  10.         'overwrite' => null,
  11.         'cascade'   => null,
  12.         'messages'  => array(
  13.             'no_dir'        => 'The servers upload directory is missing.',
  14.             'no_write'      => 'Failed to write to the upload directory.',
  15.             'file_exists'   => 'The file %s already exists.',
  16.             'no_move'       => 'Failed to move file the upload directory.'
  17.         )
  18.     );
  19.  
  20.     var $fields     = array();
  21.  
  22.     function setup(&$model, $config = array()) {
  23.         if(!is_array($config)) {
  24.             $config = array($config);
  25.         }
  26.         foreach($config as $field => $options) {
  27.             if(is_numeric($field) && is_string($options) && $model->hasField($options)) {
  28.                 unset($config[$field]);
  29.                 $field = $options;
  30.                 $options = array();
  31.             } elseif(!$model->hasField($field)) {
  32.                 unset($config[$field]);
  33.                 continue;
  34.             }
  35.             $options = array_merge_recursive($this->options, $options);
  36.             if(empty($options['dir'])) {
  37.                 $options['dir'] = FILES . low(Inflector::pluralize($model->name) . DS . $field) . DS;
  38.             } elseif(substr($options['dir'], -1) != DS) {
  39.                 $options['dir'] .= DS;
  40.             }
  41.             $config[$field] = $options;
  42.         }
  43.         $this->fields = $config;
  44.     }
  45.  
  46.     function beforeSave(&$model) {
  47.         if(count($this->fields)) {
  48.             foreach($this->fields as $field => $options) {
  49.                 if (!empty($model->data[$model->name][$field]['tmp_name']) && file_exists($model->data[$model->name][$field]['tmp_name'])) {
  50.                     if(!is_dir($options['dir']) && !Folder::mkdirr($options['dir'])) {
  51.                         return $model->invalidate($field, $options['messages']['no_dir']) && false;
  52.                     }
  53.                     if(!is_writable($options['dir'])) {
  54.                         return $model->invalidate($field, $options['messages']['no_write']) && false;
  55.                     }
  56.                     if($options['filename'] === true) {
  57.                         $filename  = $model->data[$model->name][$field]['name'];
  58.                     } elseif(method_exists($model, $options['filename'])) {
  59.                         $filename  = call_user_func(array($model, $options['filename']), $model->data[$model->name][$field]['name']);
  60.                     } else {
  61.                         $filename  = md5(uniqid(time())) . '.' . pathinfo($model->data[$model->name][$field]['name'], PATHINFO_EXTENSION);
  62.                     }
  63.                     $file = $options['dir'] . $filename;
  64.                     if(empty($options['overwrite']) && file_exists($file)) {
  65.                         return $model->invalidate($field, sprintf($options['messages']['no_write'], $filename)) && false;
  66.                     }
  67.                     if(!move_uploaded_file(@$model->data[$model->name][$field]['tmp_name'], $file)) {
  68.                         return $model->invalidate($field, $options['messages']['no_move']) && false;
  69.                     }
  70.                     $model->data[$model->name][$field] = $filename;
  71.                     $model->data[$model->name]['mimetype'] = mime_content_type($file);
  72.                     $model->data[$model->name]['filesize'] = filesize($file);
  73.                 } else {
  74.                     //Not an uploaded file
  75.                 }
  76.             }
  77.         }
  78.     }
  79.  
  80.     function beforeDelete(&$model, $cascade) {
  81.         if(count($this->fields)) {
  82.             $model->read(null, $model->id);
  83.             if(isset($model->data)) {
  84.                 foreach($this->fields as $field => $options) {
  85.                     $file   = $options['dir'] . $model->data[$model->name][$field];
  86.                     if(is_file($file) && !unlink($file)) {
  87.                         return false;
  88.                     }
  89.                 }
  90.             }
  91.         }
  92.         return true;
  93.     }
  94.  
  95.     function afterDelete(&$model) {
  96.         if(count($this->fields)) {
  97.             foreach($this->fields as $field => $options) {
  98.                 $used  = $model->findAll("{$model->name}.$field = '{$model->data[$model->name][$field]}'");
  99.                 if(!empty($options['cascade']) && !empty($used)){
  100.                     foreach($used as $line) {
  101.                         $model->del($line[$model->name]['id']);
  102.                     }
  103.                 }
  104.             }
  105.         }
  106.     }
  107.  
  108.     /* check uploaded file error */
  109.     function uploaded($model, $check, $messages = array(), $param) {
  110.         if(!$this->upload_check($model, $check, $param)) {
  111.             return false;
  112.         }
  113.         $messages(array)$messages + array(
  114.             'Error while uploading file.',
  115.             UPLOAD_ERR_INI_SIZE     => 'The file is too large, max filesize on server: %s.',
  116.             UPLOAD_ERR_FORM_SIZE    => 'The file is too large, max filesize on form: %s.',
  117.             UPLOAD_ERR_PARTIAL      => 'The file was only partially uploaded.',
  118.             UPLOAD_ERR_NO_TMP_DIR   => 'The servers temporary folder is missing.',
  119.             UPLOAD_ERR_CANT_WRITE   => 'Failed to write file to disk.',
  120.             UPLOAD_ERR_EXTENSION    => 'File upload stopped by extension.'
  121.         );
  122.         $data = array_shift(array_values($check));
  123.         $message = !empty($messages[$data['error']]) ?
  124.             $messages[$data['error']] :
  125.             (!empty($param['message']) ? $param['message'] : $messages[0]);
  126.         switch($data['error']) {
  127.             case UPLOAD_ERR_OK:
  128.                 return true;
  129.             case UPLOAD_ERR_NO_FILE:
  130.                 return isset($param['no_upload']) && $param['no_upload'];
  131.             case UPLOAD_ERR_INI_SIZE:
  132.                 $message = sprintf($message, $this->_size_format($this->_size_int(ini_get('upload_max_filesize'))));
  133.             break;
  134.             case UPLOAD_ERR_FORM_SIZE:
  135.                 $message = sprintf($message, $this->_size_format($_POST['MAX_FILE_SIZE']));
  136.             break;
  137.         }
  138.         return $model->invalidate(array_shift(array_keys($check)), $message) && true;
  139.         // return true to show the custom message
  140.     }
  141.  
  142.     /* check if file is uploaded via HTTP POST */
  143.     function upload_check($model, $check, $param) {
  144.         $data = array_shift(array_values($check));
  145.         return !empty($data['tmp_name']) ?
  146.             is_uploaded_file($data['tmp_name']) :
  147.             (isset($param['no_upload']) && $param['no_upload']);
  148.     }
  149.  
  150.     /* check uploaded file name */
  151.     function upload_name($model, $check, $regex = VALID_NOT_EMPTY, $param) {
  152.         $data = array_shift(array_values($check));
  153.         return !empty($data['tmp_name']) ?
  154.             preg_match($regex, $data['name']) :
  155.             (isset($param['no_upload']) && $param['no_upload']);
  156.     }
  157.  
  158.     /* check uploaded file type */
  159.     function upload_type($model, $check, $allowed = array('image/jpeg', 'image/png', 'image/gif'), $param) {
  160.         $data = array_shift(array_values($check));
  161.         return !empty($data['tmp_name']) ?
  162.             in_array(mime_content_type($data['tmp_name']), $allowed) :
  163.             (isset($param['no_upload']) && $param['no_upload']);
  164.     }
  165.  
  166.     /* check uploaded file size */
  167.     function upload_size($model, $check, $min = 0, $max = null, $param) {
  168.         $max = !$max ? ini_get('upload_max_filesize') : $max;
  169.         $data = array_shift(array_values($check));
  170.         return !empty($data['tmp_name']) ?
  171.             Validation::range(filesize($data['tmp_name']), $this->_size_int($min), $this->_size_int($max)) :
  172.             (isset($param['no_upload']) && $param['no_upload']);
  173.     }
  174.  
  175.     function _size_format($size) {
  176.         return array_reduce (
  177.             array ('octets', 'Ko', 'Mo'),
  178.             create_function('$a,$b', 'return is_numeric($a)?($a>=1024?$a/1024:intval($a)." ".$b):$a;'),
  179.             $size
  180.         );
  181.     }
  182.  
  183.     function _size_int($size) {
  184.         switch(substr(low(preg_replace('/[^tgmk]/i' , '', $size)), 0, 1)) {
  185.             case 'm':
  186.                 $size *= 1024;
  187.             case 'k':
  188.                 $size *= 1024;
  189.         }
  190.         return intval($size);
  191.     }
  192.  
  193. }
  194. ?>
  195.  
Parsed in 0.488 seconds, using GeSHi 1.0.7.14

Modify this Paste