06.05 php saved
adrien.gibrat
Tags add more
 
Note
An upload behavior that give standard methods to validate uploaded files and to get mimetype & filesize in model.
  1. <?php
  2. /** Example how to use upload behavior in your model:
  3.     var $actsAs                 = array(
  4.         'Upload'    => 'audio_file',                        // use one field with default options
  5. //      'Upload'    => array('audio_file', 'image_file')    // use two fields with default options
  6. //      'Upload'    => array('audio_file' => array(         // use one fields with custom options
  7. //              'dir'=> '/data',                    // absolute path where files will be uploaded
  8. //              'filename'=> 'my_rename_method',    // true will use the uploaded file name, false will generate a unique filename, 'my_rename_method' will call the user defined model method my_rename_method to generate a filename
  9. //              'overwrite' => false,               // do we overwrite existing files?
  10. //              'delete'    => true,                // do we delete file on delete?
  11. //              'cascade'   => true,                // do we delete all the entries in model that use the same file on delete?
  12. //              'messages'  => array(               // error messages
  13. //                  UPLOAD_ERR_OK           => 'Do you try to hack?',
  14. //                  UPLOAD_ERR_INI_SIZE     => 'Server allow files under %s.',
  15. //                  UPLOAD_ERR_FORM_SIZE    => 'This form  allow files under %s.',
  16. //                  UPLOAD_ERR_PARTIAL      => 'Partial file upload!',
  17. //                  UPLOAD_ERR_NO_FILE      => 'Please provide a file.',
  18. //                  UPLOAD_ERR_NO_TMP_DIR   => 'No temporary folder!',
  19. //                  UPLOAD_ERR_CANT_WRITE   => 'Chmod the temporary folder!',
  20. //                  UPLOAD_ERR_EXTENSION    => 'File upload stopped!',
  21. //                  'no_dir'        => 'No upload directory!',
  22. //                  'no_write'      => 'Chmod the upload directory!',
  23. //                  'file_exists'   => 'The file already exists!',
  24. //                  'no_move'       => 'Sorry, something went wrong!.'
  25. //              )
  26. //          )
  27.         );
  28.     var $validate               = array(
  29.         'audio_file'       => array(
  30.             'upload_type' => array(
  31.                 'rule'          => array('upload_type', array('audio/x-wav','audio/mpeg')),
  32.                 'allowNoFile'   => true,    // allowNoFile set to true will not trigger error if no file uploaded
  33.                 'message'       => 'Please provide a wav or mp3 file.'
  34.             ),
  35.             'upload_size' => array(
  36.                 'rule'          => array('upload_size', '30k', null),
  37.                 'allowNoFile'   => true,    // allowNoFile is like allowEmpty for file upload
  38.                 'message'       => 'Please provide file up to 30 ko.'
  39.             ),
  40.             'uploaded' => array(
  41.                 'rule'          => 'uploaded',
  42.                 'allowNoFile'   => true,    // return contextual error message only if upload process fails
  43.                 'message'       => 'Error while uploading file.' // so default message is not used if allowNoFile is true
  44.             ),
  45.             'create' => array(
  46.                 'rule'          => 'uploaded',
  47.                 'allowNoFile'   => false,
  48.                 'on'            => 'create',    // you can use on create/update rules!
  49.                 'message'       => 'Please provide a file.'
  50.             )
  51.         ),
  52. // Or you can validate the model data set with beforeValidate (replace the file's upload_size and upload_type rules)
  53. // display of errors in view will be affected, use $form->error('filesize') and $form->error('mimetype').
  54. //      'mimetype'      => array(
  55. //          'rule'          => array('in', array('audio/x-wav','audio/mpeg')),
  56. //          'message'       => 'Please provide a wav or mp3 file.'
  57. //      ),
  58. //      'filesize'      => array(
  59. //          'rule'          => array('comparison', '>', 30720),
  60. //          'message'       => 'Please provide file up to 30 ko.'
  61. //      ),
  62.     );
  63.  
  64.    function in($check, $allowed) {
  65.         $data = array_shift(array_values($check));
  66.         return in_array($data, (array)$allowed);
  67.     }
  68.  
  69.     function my_rename_method($filename) {
  70.         return md5(uniqid(time())) . '-' . $filename;
  71.     }
  72.  
  73. //  function beforeValidate() {
  74. //      $this->data['mimetype'] = $this->get_mimetype('audio_file');
  75. //      $this->data['filesize'] = $this->get_filesize('audio_file');
  76. //      return true;
  77. //  }
  78. */
  79. if (!defined('FILES')) {
  80.     define('FILES', WWW_ROOT . 'files' . DS);
  81. }
  82. class UploadBehavior extends ModelBehavior {
  83.  
  84.     var $default = array(
  85.         'dir'       => null,
  86.         'filename'  => null,
  87.         'overwrite' => null,
  88.         'delete'    => null,
  89.         'cascade'   => null,
  90.         'messages'  => array(
  91.             UPLOAD_ERR_OK           => 'Do you try to hack the form?',
  92.             UPLOAD_ERR_INI_SIZE     => 'The file is too large, max filesize on server is %s.',
  93.             UPLOAD_ERR_FORM_SIZE    => 'The file is too large, max filesize on form is %s.',
  94.             UPLOAD_ERR_PARTIAL      => 'The file was only partially uploaded.',
  95.             UPLOAD_ERR_NO_FILE      => 'Please provide a file.',
  96.             UPLOAD_ERR_NO_TMP_DIR   => 'The servers temporary folder is missing.',
  97.             UPLOAD_ERR_CANT_WRITE   => 'Failed to write file to disk.',
  98.             UPLOAD_ERR_EXTENSION    => 'File upload stopped by extension.',
  99.             'no_dir'                => 'The servers upload directory is missing.',
  100.             'no_write'              => 'Failed to write to the upload directory.',
  101.             'file_exists'           => 'The file %s already exists.',
  102.             'no_move'               => 'Failed to move file the upload directory.'
  103.         )
  104.     );
  105.  
  106.  
  107.     function setup(&$model, $config = array()) {
  108.         foreach((array)$config as $field => $options) {
  109.             if(is_numeric($field) && is_string($options) && $model->hasField($options)) {
  110.                 $field = $options;
  111.                 $options = array();
  112.             } elseif(!$model->hasField($field)) {
  113.                 continue;
  114.             }
  115.             $settings = array(
  116.                 $field => array_merge_recursive($this->default, $options)
  117.             );
  118.             if(empty($settings[$field]['dir'])) {
  119.                 $settings[$field]['dir'] = FILES . low(Inflector::pluralize($model->alias) . DS . $field) . DS;
  120.             } elseif(substr($settings['dir'], -1) != DS) {
  121.                 $settings[$field]['dir'] .= DS;
  122.             }
  123.         }
  124.         $this->settings[$model->alias] = $settings;
  125.     }
  126.  
  127.     /* Behavior save callback processing uploaded file */
  128.     function beforeSave(&$model) {
  129.         foreach($this->settings[$model->alias] as $field => $options) {
  130.             if (is_uploaded_file($model->data[$model->alias][$field]['tmp_name'])) {
  131.                 extract($options);
  132.                 if(!is_dir($dir) && !Folder::mkdirr($dir)) {
  133.                     return $model->invalidate($field, $messages['no_dir']) && false;
  134.                 }
  135.                 if(!is_writable($dir)) {
  136.                     return $model->invalidate($field, $messages['no_write']) && false;
  137.                 }
  138.                 if($filename === true) {
  139.                     $filename  = $model->data[$model->alias][$field]['name'];
  140.                 } elseif(method_exists($model, $filename)) {
  141.                     $filename  = call_user_func(array($model, $filename), $model->data[$model->alias][$field]['name']);
  142.                 } else {
  143.                     $filename  = md5(uniqid(time())) . '.' . pathinfo($model->data[$model->alias][$field]['name'], PATHINFO_EXTENSION);
  144.                 }
  145.                 $file = $dir . $filename;
  146.                 if(empty($overwrite) && file_exists($file)) {
  147.                     return $model->invalidate($field, sprintf($messages['no_write'], $filename)) && false;
  148.                 }
  149.                 if(!move_uploaded_file(@$model->data[$model->alias][$field]['tmp_name'], $file)) {
  150.                     return $model->invalidate($field, $messages['no_move']) && false;
  151.                 }
  152.                 $model->data[$model->alias][$field] = $filename;
  153.             }
  154.         }
  155.     }
  156.  
  157.     /* Behavior delete callback to delete file */
  158.     function beforeDelete(&$model, $cascade) {
  159.         $model->read(null, $model->id);
  160.         if(isset($model->data)) {
  161.             foreach($this->settings[$model->alias] as $field => $options) {
  162.                 $file   = $options['dir'] . $model->data[$model->alias][$field];
  163.                 if(!empty($options['delete']) && !unlink($file)) {
  164.                     return false;
  165.                 }
  166.             }
  167.         }
  168.         return true;
  169.     }
  170.  
  171.     /* Behavior delete callback for cascade deletion */
  172.     function afterDelete(&$model) {
  173.         foreach($this->settings[$model->alias] as $field => $options) {
  174.             if(!empty($options['cascade']) && $used = $model->findAll("{$model->alias}.$field = '{$model->data[$model->alias][$field]}'")){
  175.                 foreach($used as $line) {
  176.                     $model->del($line[$model->alias]['id']);
  177.                 }
  178.             }
  179.         }
  180.     }
  181.  
  182.     /* Behavior model method to get uploaded file mimetype */
  183.     function get_upload_mimetype($model, $field) {
  184.         if( is_uploaded_file($model->data[$model->alias][$field]['tmp_name'])) {
  185.             return mime_content_type($model->data[$model->alias][$field]['tmp_name']);
  186.         }
  187.     }
  188.  
  189.     /* Behavior model method to get uploaded file size */
  190.     function get_upload_filesize($model, $field) {
  191.         if( is_uploaded_file($model->data[$model->alias][$field]['tmp_name'])) {
  192.             return filesize($model->data[$model->alias][$field]['tmp_name']);
  193.         }
  194.     }
  195.  
  196.     /* Behavior validation method to check uploaded file error */
  197.     function uploaded($model, $check, $param) {
  198.         $field      = array_shift(array_keys($check));
  199.         $messages   = $this->settings[$model->alias][$field]['messages'];
  200.         $data       = array_shift(array_values($check));
  201.         $message    = @$messages[$data['error']];
  202.         switch($data['error']) {
  203.             case UPLOAD_ERR_OK:
  204.                 if($this->upload_check($model, $check, $param)) {
  205.                     return true;
  206.                 }
  207.             break;
  208.             case UPLOAD_ERR_NO_FILE:
  209.                 return !empty($param['allowNoFile']);
  210.             case UPLOAD_ERR_INI_SIZE:
  211.                 $message = sprintf($message, $this->_size_format($this->_size_int(ini_get('upload_max_filesize'))));
  212.             break;
  213.             case UPLOAD_ERR_FORM_SIZE:
  214.                 $message = sprintf($message, $this->_size_format($_POST['MAX_FILE_SIZE']));
  215.             break;
  216.         }
  217.         $model->invalidate($field, $message);
  218.         return true; // return true to show the custom message
  219.     }
  220.  
  221.     /* Behavior validation method to check if file is uploaded via HTTP POST */
  222.     function upload_check($model, $check, $param) {
  223.         $data = array_shift(array_values($check));
  224.         return !empty($data['tmp_name']) ?
  225.             is_uploaded_file($data['tmp_name']) :
  226.             !empty($param['allowNoFile']);
  227.     }
  228.  
  229.     /* Behavior validation method to check uploaded file name */
  230.     function upload_name($model, $check, $regex = VALID_NOT_EMPTY, $param) {
  231.         $data = array_shift(array_values($check));
  232.         return !empty($data['tmp_name']) ?
  233.             preg_match($regex, $data['name']) :
  234.             !empty($param['allowNoFile']);
  235.     }
  236.  
  237.     /* Behavior validation method to check uploaded file type */
  238.     function upload_type($model, $check, $allowed = array('image/jpeg', 'image/png', 'image/gif'), $param) {
  239.         $data = array_shift(array_values($check));
  240.         return !empty($data['tmp_name']) ?
  241.             in_array(mime_content_type($data['tmp_name']), (array)$allowed) :
  242.             !empty($param['allowNoFile']);
  243.     }
  244.  
  245.     /* Behavior validation method to check uploaded file size */
  246.     function upload_size($model, $check, $min = 0, $max = null, $param) {
  247.         $max = !$max ? ini_get('upload_max_filesize') : $max;
  248.         $data = array_shift(array_values($check));
  249.         return !empty($data['tmp_name']) ?
  250.             Validation::range(filesize($data['tmp_name']), $this->_size_int($min), $this->_size_int($max)) :
  251.             !empty($param['allowNoFile']);
  252.     }
  253.  
  254.     /* Private size formater helper */
  255.     function _size_format($size) {
  256.         return array_reduce (
  257.             array ('octets', 'Ko', 'Mo'),
  258.             create_function('$a,$b', 'return is_numeric($a)?($a>=1024?$a/1024:intval($a)." ".$b):$a;'),
  259.             $size
  260.         );
  261.     }
  262.  
  263.     /* Private formated size to integer helper */
  264.     function _size_int($size) {
  265.         switch(substr(low(preg_replace('/[^mk]/i' , '', $size)), 0, 1)) {
  266.             case 'm':
  267.                 $size *= 1024;
  268.             case 'k':
  269.                 $size *= 1024;
  270.         }
  271.         return intval($size);
  272.     }
  273.  
  274. }
  275. ?>
  276.  
Parsed in 0.454 seconds, using GeSHi 1.0.7.14

Modify this Paste