Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   1  <?php
   2  /* vim: set expandtab tabstop=4 shiftwidth=4: */
   3  // +----------------------------------------------------------------------+
   4  // | PHP version 4.0                                                      |
   5  // +----------------------------------------------------------------------+
   6  // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
   7  // +----------------------------------------------------------------------+
   8  // | This source file is subject to version 2.0 of the PHP license,       |
   9  // | that is bundled with this package in the file LICENSE, and is        |
  10  // | available at through the world-wide-web at                           |
  11  // | http://www.php.net/license/2_02.txt.                                 |
  12  // | If you did not receive a copy of the PHP license and are unable to   |
  13  // | obtain it through the world-wide-web, please send a note to          |
  14  // | license@php.net so we can mail you a copy immediately.               |
  15  // +----------------------------------------------------------------------+
  16  // | Authors: Adam Daniel <adaniel1@eesus.jnj.com>                        |
  17  // |          Bertrand Mansion <bmansion@mamasam.com>                     |
  18  // +----------------------------------------------------------------------+
  19  //
  20  // $Id$
  21  
  22  require_once("HTML/QuickForm/input.php");
  23  
  24  // register file-related rules
  25  if (class_exists('HTML_QuickForm')) {
  26      HTML_QuickForm::registerRule('uploadedfile', 'callback', '_ruleIsUploadedFile', 'HTML_QuickForm_file');
  27      HTML_QuickForm::registerRule('maxfilesize', 'callback', '_ruleCheckMaxFileSize', 'HTML_QuickForm_file');
  28      HTML_QuickForm::registerRule('mimetype', 'callback', '_ruleCheckMimeType', 'HTML_QuickForm_file');
  29      HTML_QuickForm::registerRule('filename', 'callback', '_ruleCheckFileName', 'HTML_QuickForm_file');
  30  }
  31  
  32  /**
  33   * HTML class for a file type element
  34   * 
  35   * @author       Adam Daniel <adaniel1@eesus.jnj.com>
  36   * @author       Bertrand Mansion <bmansion@mamasam.com>
  37   * @version      1.0
  38   * @since        PHP4.04pl1
  39   * @access       public
  40   */
  41  class HTML_QuickForm_file extends HTML_QuickForm_input
  42  {
  43      // {{{ properties
  44  
  45     /**
  46      * Uploaded file data, from $_FILES
  47      * @var array
  48      */
  49      var $_value = null;
  50  
  51      // }}}
  52      // {{{ constructor
  53  
  54      /**
  55       * Class constructor
  56       * 
  57       * @param     string    Input field name attribute
  58       * @param     string    Input field label
  59       * @param     mixed     (optional)Either a typical HTML attribute string 
  60       *                      or an associative array
  61       * @since     1.0
  62       * @access    public
  63       */
  64      public function __construct($elementName=null, $elementLabel=null, $attributes=null) {
  65          parent::__construct($elementName, $elementLabel, $attributes);
  66          $this->setType('file');
  67      } //end constructor
  68  
  69      /**
  70       * Old syntax of class constructor. Deprecated in PHP7.
  71       *
  72       * @deprecated since Moodle 3.1
  73       */
  74      public function HTML_QuickForm_file($elementName=null, $elementLabel=null, $attributes=null) {
  75          debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
  76          self::__construct($elementName, $elementLabel, $attributes);
  77      }
  78  
  79      // }}}
  80      // {{{ setSize()
  81  
  82      /**
  83       * Sets size of file element
  84       * 
  85       * @param     int    Size of file element
  86       * @since     1.0
  87       * @access    public
  88       */
  89      function setSize($size)
  90      {
  91          $this->updateAttributes(array('size' => $size));
  92      } //end func setSize
  93      
  94      // }}}
  95      // {{{ getSize()
  96  
  97      /**
  98       * Returns size of file element
  99       * 
 100       * @since     1.0
 101       * @access    public
 102       * @return    int
 103       */
 104      function getSize()
 105      {
 106          return $this->getAttribute('size');
 107      } //end func getSize
 108  
 109      // }}}
 110      // {{{ freeze()
 111  
 112      /**
 113       * Freeze the element so that only its value is returned
 114       * 
 115       * @access    public
 116       * @return    bool
 117       */
 118      function freeze()
 119      {
 120          return false;
 121      } //end func freeze
 122  
 123      // }}}
 124      // {{{ setValue()
 125  
 126      /**
 127       * Sets value for file element.
 128       * 
 129       * Actually this does nothing. The function is defined here to override
 130       * HTML_Quickform_input's behaviour of setting the 'value' attribute. As
 131       * no sane user-agent uses <input type="file">'s value for anything 
 132       * (because of security implications) we implement file's value as a 
 133       * read-only property with a special meaning.
 134       * 
 135       * @param     mixed    Value for file element
 136       * @since     3.0
 137       * @access    public
 138       */
 139      function setValue($value)
 140      {
 141          return null;
 142      } //end func setValue
 143      
 144      // }}}
 145      // {{{ getValue()
 146  
 147      /**
 148       * Returns information about the uploaded file
 149       *
 150       * @since     3.0
 151       * @access    public
 152       * @return    array
 153       */
 154      function getValue()
 155      {
 156          return $this->_value;
 157      } // end func getValue
 158  
 159      // }}}
 160      // {{{ onQuickFormEvent()
 161  
 162      /**
 163       * Called by HTML_QuickForm whenever form event is made on this element
 164       *
 165       * @param     string    Name of event
 166       * @param     mixed     event arguments
 167       * @param     object    calling object
 168       * @since     1.0
 169       * @access    public
 170       * @return    bool
 171       */
 172      function onQuickFormEvent($event, $arg, &$caller)
 173      {
 174          switch ($event) {
 175              case 'updateValue':
 176                  if ($caller->getAttribute('method') == 'get') {
 177                      return self::raiseError('Cannot add a file upload field to a GET method form');
 178                  }
 179                  $this->_value = $this->_findValue();
 180                  $caller->updateAttributes(array('enctype' => 'multipart/form-data'));
 181                  $caller->setMaxFileSize();
 182                  break;
 183              case 'addElement':
 184                  $this->onQuickFormEvent('createElement', $arg, $caller);
 185                  return $this->onQuickFormEvent('updateValue', null, $caller);
 186                  break;
 187              case 'createElement':
 188                  static::__construct($arg[0], $arg[1], $arg[2], $arg[3], $arg[4]);
 189                  break;
 190          }
 191          return true;
 192      } // end func onQuickFormEvent
 193  
 194      // }}}
 195      // {{{ moveUploadedFile()
 196  
 197      /**
 198       * Moves an uploaded file into the destination 
 199       * 
 200       * @param    string  Destination directory path
 201       * @param    string  New file name
 202       * @access   public
 203       * @return   bool    Whether the file was moved successfully
 204       */
 205      function moveUploadedFile($dest, $fileName = '')
 206      {
 207          if ($dest != ''  && substr($dest, -1) != '/') {
 208              $dest .= '/';
 209          }
 210          $fileName = ($fileName != '') ? $fileName : basename($this->_value['name']);
 211          if (move_uploaded_file($this->_value['tmp_name'], $dest . $fileName)) {
 212              return true;
 213          } else {
 214              return false;
 215          }
 216      } // end func moveUploadedFile
 217      
 218      // }}}
 219      // {{{ isUploadedFile()
 220  
 221      /**
 222       * Checks if the element contains an uploaded file
 223       *
 224       * @access    public
 225       * @return    bool      true if file has been uploaded, false otherwise
 226       */
 227      function isUploadedFile()
 228      {
 229          return $this->_ruleIsUploadedFile($this->_value);
 230      } // end func isUploadedFile
 231  
 232      // }}}
 233      // {{{ _ruleIsUploadedFile()
 234  
 235      /**
 236       * Checks if the given element contains an uploaded file
 237       *
 238       * @param     array     Uploaded file info (from $_FILES)
 239       * @access    private
 240       * @return    bool      true if file has been uploaded, false otherwise
 241       */
 242      function _ruleIsUploadedFile($elementValue)
 243      {
 244          if ((isset($elementValue['error']) && $elementValue['error'] == 0) ||
 245              (!empty($elementValue['tmp_name']) && $elementValue['tmp_name'] != 'none')) {
 246              return is_uploaded_file($elementValue['tmp_name']);
 247          } else {
 248              return false;
 249          }
 250      } // end func _ruleIsUploadedFile
 251      
 252      // }}}
 253      // {{{ _ruleCheckMaxFileSize()
 254  
 255      /**
 256       * Checks that the file does not exceed the max file size
 257       *
 258       * @param     array     Uploaded file info (from $_FILES)
 259       * @param     int       Max file size
 260       * @access    private
 261       * @return    bool      true if filesize is lower than maxsize, false otherwise
 262       */
 263      function _ruleCheckMaxFileSize($elementValue, $maxSize)
 264      {
 265          if (!empty($elementValue['error']) && 
 266              (UPLOAD_ERR_FORM_SIZE == $elementValue['error'] || UPLOAD_ERR_INI_SIZE == $elementValue['error'])) {
 267              return false;
 268          }
 269          if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
 270              return true;
 271          }
 272          return ($maxSize >= @filesize($elementValue['tmp_name']));
 273      } // end func _ruleCheckMaxFileSize
 274  
 275      // }}}
 276      // {{{ _ruleCheckMimeType()
 277  
 278      /**
 279       * Checks if the given element contains an uploaded file of the right mime type
 280       *
 281       * @param     array     Uploaded file info (from $_FILES)
 282       * @param     mixed     Mime Type (can be an array of allowed types)
 283       * @access    private
 284       * @return    bool      true if mimetype is correct, false otherwise
 285       */
 286      function _ruleCheckMimeType($elementValue, $mimeType)
 287      {
 288          if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
 289              return true;
 290          }
 291          if (is_array($mimeType)) {
 292              return in_array($elementValue['type'], $mimeType);
 293          }
 294          return $elementValue['type'] == $mimeType;
 295      } // end func _ruleCheckMimeType
 296  
 297      // }}}
 298      // {{{ _ruleCheckFileName()
 299  
 300      /**
 301       * Checks if the given element contains an uploaded file of the filename regex
 302       *
 303       * @param     array     Uploaded file info (from $_FILES)
 304       * @param     string    Regular expression
 305       * @access    private
 306       * @return    bool      true if name matches regex, false otherwise
 307       */
 308      function _ruleCheckFileName($elementValue, $regex)
 309      {
 310          if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
 311              return true;
 312          }
 313          return preg_match($regex, $elementValue['name']);
 314      } // end func _ruleCheckFileName
 315      
 316      // }}}
 317      // {{{ _findValue()
 318  
 319     /**
 320      * Tries to find the element value from the values array
 321      * 
 322      * Needs to be redefined here as $_FILES is populated differently from 
 323      * other arrays when element name is of the form foo[bar]
 324      * 
 325      * @access    private
 326      * @return    mixed
 327      */
 328      function _findValue()
 329      {
 330          if (empty($_FILES)) {
 331              return null;
 332          }
 333          $elementName = $this->getName();
 334          if (isset($_FILES[$elementName])) {
 335              return $_FILES[$elementName];
 336          } elseif (false !== ($pos = strpos($elementName, '['))) {
 337              $base  = substr($elementName, 0, $pos);
 338              $idx   = "['" . str_replace(array(']', '['), array('', "']['"), substr($elementName, $pos + 1, -1)) . "']";
 339              $props = array('name', 'type', 'size', 'tmp_name', 'error');
 340              $code  = "if (!isset(\$_FILES['{$base}']['name']{$idx})) {\n" .
 341                       "    return null;\n" .
 342                       "} else {\n" .
 343                       "    \$value = array();\n";
 344              foreach ($props as $prop) {
 345                  $code .= "    \$value['{$prop}'] = \$_FILES['{$base}']['{$prop}']{$idx};\n";
 346              }
 347              return eval($code . "    return \$value;\n}\n");
 348          } else {
 349              return null;
 350          }
 351      }
 352  
 353      // }}}
 354  } // end class HTML_QuickForm_file
 355  ?>