1<?php
2/**
3 * Class for <input type="file" /> elements
4 *
5 * PHP version 5
6 *
7 * LICENSE
8 *
9 * This source file is subject to BSD 3-Clause License that is bundled
10 * with this package in the file LICENSE and available at the URL
11 * https://raw.githubusercontent.com/pear/HTML_QuickForm2/trunk/docs/LICENSE
12 *
13 * @category  HTML
14 * @package   HTML_QuickForm2
15 * @author    Alexey Borzov <avb@php.net>
16 * @author    Bertrand Mansion <golgote@mamasam.com>
17 * @copyright 2006-2021 Alexey Borzov <avb@php.net>, Bertrand Mansion <golgote@mamasam.com>
18 * @license   https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
19 * @link      https://pear.php.net/package/HTML_QuickForm2
20 */
21
22/**
23 * Base class for <input> elements
24 */
25require_once 'HTML/QuickForm2/Element/Input.php';
26
27/**
28 * Class for <input type="file" /> elements
29 *
30 * @category HTML
31 * @package  HTML_QuickForm2
32 * @author   Alexey Borzov <avb@php.net>
33 * @author   Bertrand Mansion <golgote@mamasam.com>
34 * @license  https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
35 * @version  Release: 2.2.2
36 * @link     https://pear.php.net/package/HTML_QuickForm2
37 */
38class HTML_QuickForm2_Element_InputFile extends HTML_QuickForm2_Element_Input
39{
40   /**
41    * Language to display error messages in
42    * @var  string
43    */
44    protected $language = null;
45
46   /**
47    * Information on uploaded file, from submit data source
48    * @var array
49    */
50    protected $value = null;
51
52    protected $attributes = ['type' => 'file'];
53
54   /**
55    * Message provider for upload error messages
56    * @var  callback|HTML_QuickForm2_MessageProvider
57    */
58    protected $messageProvider;
59
60   /**
61    * Class constructor
62    *
63    * Possible keys in $data array are:
64    *  - 'messageProvider': an instance of a class implementing
65    *    HTML_QuickForm2_MessageProvider interface, this will be used to get
66    *    localized error messages. Default will be used if not given.
67    *  - 'language': language to display error messages in, will be passed to
68    *    message provider.
69    *
70    * @param string       $name       Element name
71    * @param string|array $attributes Attributes (either a string or an array)
72    * @param array        $data       Data used to set up error messages for PHP's
73    *                                 file upload errors.
74    */
75    public function __construct($name = null, $attributes = null, array $data = [])
76    {
77        if (isset($data['messageProvider'])) {
78            if (!is_callable($data['messageProvider'])
79                && !$data['messageProvider'] instanceof HTML_QuickForm2_MessageProvider
80            ) {
81                throw new HTML_QuickForm2_InvalidArgumentException(
82                    "messageProvider: expecting a callback or an implementation"
83                    . " of HTML_QuickForm2_MessageProvider"
84                );
85            }
86            $this->messageProvider = $data['messageProvider'];
87
88        } else {
89            HTML_QuickForm2_Loader::loadClass('HTML_QuickForm2_MessageProvider_Default');
90            $this->messageProvider = HTML_QuickForm2_MessageProvider_Default::getInstance();
91        }
92        if (isset($data['language'])) {
93            $this->language = $data['language'];
94        }
95        unset($data['messageProvider'], $data['language']);
96        parent::__construct($name, $attributes, $data);
97    }
98
99
100   /**
101    * File upload elements cannot be frozen
102    *
103    * To properly "freeze" a file upload element one has to store the uploaded
104    * file somewhere and store the file info in session. This is way outside
105    * the scope of this class.
106    *
107    * @param bool $freeze Whether element should be frozen or editable. This
108    *                     parameter is ignored in case of file uploads
109    *
110    * @return   bool    Always returns false
111    */
112    public function toggleFrozen($freeze = null)
113    {
114        return false;
115    }
116
117   /**
118    * Returns the information on uploaded file
119    *
120    * @return   array|null
121    */
122    public function getRawValue()
123    {
124        return $this->value;
125    }
126
127   /**
128    * Alias of getRawValue(), InputFile elements do not allow filters
129    *
130    * @return   array|null
131    */
132    public function getValue()
133    {
134        return $this->getRawValue();
135    }
136
137   /**
138    * File upload's value cannot be set here
139    *
140    * @param mixed $value Value for file element, this parameter is ignored
141    *
142    * @return $this
143    */
144    public function setValue($value)
145    {
146        return $this;
147    }
148
149    protected function updateValue()
150    {
151        // request #16807: file uploads should not be added to forms with
152        // method="get", enctype should be set to multipart/form-data
153        // we cannot do this in setContainer() as the element may be added to
154        // e.g. a group first and then the group may be added to a form
155        $container = $this->getContainer();
156        while (!empty($container)) {
157            if ($container instanceof HTML_QuickForm2) {
158                if ('get' == $container->getAttribute('method')) {
159                    throw new HTML_QuickForm2_InvalidArgumentException(
160                        'File upload elements can only be added to forms with post submit method'
161                    );
162                }
163                if ('multipart/form-data' != $container->getAttribute('enctype')) {
164                    $container->setAttribute('enctype', 'multipart/form-data');
165                }
166                break;
167            }
168            $container = $container->getContainer();
169        }
170
171        foreach ($this->getDataSources() as $ds) {
172            if ($ds instanceof HTML_QuickForm2_DataSource_Submit) {
173                $value = $ds->getUpload($this->getName());
174                if (null !== $value) {
175                    $this->value = $value;
176                    return;
177                }
178            }
179        }
180        $this->value = null;
181    }
182
183   /**
184    * Performs the server-side validation
185    *
186    * Before the Rules added to the element kick in, the element checks the
187    * error code added to the $_FILES array by PHP. If the code isn't
188    * UPLOAD_ERR_OK or UPLOAD_ERR_NO_FILE then a built-in error message will be
189    * displayed and no further validation will take place.
190    *
191    * @return   boolean     Whether the element is valid
192    */
193    protected function validate()
194    {
195        if (strlen($this->error)) {
196            return false;
197        }
198        if (isset($this->value['error'])
199            && !in_array($this->value['error'], [UPLOAD_ERR_OK, UPLOAD_ERR_NO_FILE])
200        ) {
201            $errorMessage = $this->messageProvider instanceof HTML_QuickForm2_MessageProvider
202                            ? $this->messageProvider->get(['file', $this->value['error']], $this->language)
203                            : call_user_func($this->messageProvider, ['file', $this->value['error']], $this->language);
204            if (UPLOAD_ERR_INI_SIZE == $this->value['error']) {
205                $iniSize = ini_get('upload_max_filesize');
206                $size    = intval($iniSize);
207                switch (strtoupper(substr($iniSize, -1))) {
208                case 'G': $size *= 1024;
209                case 'M': $size *= 1024;
210                case 'K': $size *= 1024;
211                }
212
213            } elseif (UPLOAD_ERR_FORM_SIZE == $this->value['error']) {
214                foreach ($this->getDataSources() as $ds) {
215                    if ($ds instanceof HTML_QuickForm2_DataSource_Submit) {
216                        $size = intval($ds->getValue('MAX_FILE_SIZE'));
217                        break;
218                    }
219                }
220            }
221            $this->error = isset($size)? sprintf($errorMessage, $size): $errorMessage;
222            return false;
223        }
224        return parent::validate();
225    }
226
227    public function addFilter($callback, array $options = [])
228    {
229        throw new HTML_QuickForm2_Exception(
230            'InputFile elements do not support filters'
231        );
232    }
233
234    public function addRecursiveFilter($callback, array $options = [])
235    {
236        throw new HTML_QuickForm2_Exception(
237            'InputFile elements do not support filters'
238        );
239    }
240}
241?>
242