summaryrefslogtreecommitdiff
path: root/framework/Web/UI/WebControls/TFileUpload.php
blob: 13afa9971b8b3d0934df99dd50402174953c9772 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
<?php
/**
 * TFileUpload class file
 *
 * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.pradosoft.com/
 * @copyright Copyright &copy; 2005-2014 PradoSoft
 * @license http://www.pradosoft.com/license/
 * @package Prado\Web\UI\WebControls
 */

namespace Prado\Web\UI\WebControls;

/**
 * TFileUpload class
 *
 * TFileUpload displays a file upload field on a page. Upon postback,
 * the text entered into the field will be treated as the name of the file
 * that will be uploaded to the server. The property {@link getHasFile HasFile}
 * indicates whether the file upload is successful. If successful, the file
 * may be obtained by calling {@link saveAs} to save it at a specified place.
 * You can use {@link getFileName FileName}, {@link getFileType FileType},
 * {@link getFileSize FileSize} to get the original client-side file name,
 * the file mime type, and the file size information. If the upload is not
 * successful, {@link getErrorCode ErrorCode} contains the error code
 * describing the cause of failure.
 *
 * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
 * (whether it succeeds or not).
 *
 * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
 * @package Prado\Web\UI\WebControls
 * @since 3.0
 */
class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
{
	/**
	 * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
	 */
	const MAX_FILE_SIZE=1048576;
	/**
	 * @var integer the size of the uploaded file (in bytes)
	 */
	private $_fileSize=0;
	/**
	 * @var string The original name of the file on the client machine
	 */
	private $_fileName='';
	/**
	 * @var string the name of the temporary file storing the uploaded file
	 */
	private $_localName='';
	/**
	 * @var string the uploaded file mime type
	 */
	private $_fileType='';
	/**
	 * @var integer error code of the current file upload
	 */
	protected $_errorCode=UPLOAD_ERR_NO_FILE;
	private $_dataChanged=false;
	private $_isValid=true;

	/**
	 * @return string tag name of the file upload control
	 */
	protected function getTagName()
	{
		return 'input';
	}

	/**
	 * Sets name attribute to the unique ID of the control.
	 * This method overrides the parent implementation with additional file update control specific attributes.
	 * @param THtmlWriter the writer used for the rendering purpose
	 */
	protected function addAttributesToRender($writer)
	{
		$this->getPage()->ensureRenderInForm($this);
		parent::addAttributesToRender($writer);
		$writer->addAttribute('type','file');
		$writer->addAttribute('name',$this->getUniqueID());
		$isEnabled=$this->getEnabled(true);
		if(!$isEnabled && $this->getEnabled())  // in this case parent will not render 'disabled'
			$writer->addAttribute('disabled','disabled');
	}

	/**
	 * Sets Enctype of the form on the page.
	 * This method overrides the parent implementation and is invoked before render.
	 * @param mixed event parameter
	 */
	public function onPreRender($param)
	{
		parent::onPreRender($param);
		if(($form=$this->getPage()->getForm())!==null)
			$form->setEnctype('multipart/form-data');
		$this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
		if($this->getEnabled(true))
			$this->getPage()->registerRequiresPostData($this);
	}

	/**
	 * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
	 * @see setMaxFileSize
	 */
	public function getMaxFileSize()
	{
		return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
	}

	/**
	 * Sets the maximum size that a file can be uploaded.
	 * Note, this is an advisory value to the browser. Sets this property with
	 * a reasonably large size to save users the trouble of waiting
	 * for a big file being transferred only to find that it was too big
	 * and the transfer failed.
	 * @param int the maximum upload size allowed for a file.
	 */
	public function setMaxFileSize($size)
	{
		$this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
	}

	/**
	 * @return string the original full path name of the file on the client machine
	 */
	public function getFileName()
	{
		return $this->_fileName;
	}

	/**
	 * @return integer the actual size of the uploaded file in bytes
	 */
	public function getFileSize()
	{
		return $this->_fileSize;
	}

	/**
	 * @return string the MIME-type of the uploaded file (such as "image/gif").
	 * This mime type is not checked on the server side and do not take its value for granted.
	 */
	public function getFileType()
	{
		return $this->_fileType;
	}

	/**
	 * @return string the local name of the file (where it is after being uploaded).
	 * Note, PHP will delete this file automatically after finishing this round of request.
	 */
	public function getLocalName()
	{
		return $this->_localName;
	}

	/**
	 * Returns an error code describing the status of this file uploading.
	 * @return integer the error code
	 * @see http://www.php.net/manual/en/features.file-upload.errors.php
	 */
	public function getErrorCode()
	{
		return $this->_errorCode;
	}

	/**
	 * @return boolean whether the file is uploaded successfully
	 */
	public function getHasFile()
	{
		return $this->_errorCode===UPLOAD_ERR_OK;
	}

	/**
	 * Saves the uploaded file.
	 * @param string the file name used to save the uploaded file
	 * @param boolean whether to delete the temporary file after saving.
	 * If true, you will not be able to save the uploaded file again.
	 * @return boolean true if the file saving is successful
	 */
	public function saveAs($fileName,$deleteTempFile=true)
	{
		if($this->_errorCode===UPLOAD_ERR_OK)
		{
			if($deleteTempFile)
				return move_uploaded_file($this->_localName,$fileName);
			else if(is_uploaded_file($this->_localName))
				return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
			else
				return false;
		}
		else
			return false;
	}

	/**
	 * Loads user input data.
	 * This method is primarly used by framework developers.
	 * @param string the key that can be used to retrieve data from the input data collection
	 * @param array the input data collection
	 * @return boolean whether the data of the control has been changed
	 */
	public function loadPostData($key,$values)
	{
		if(isset($_FILES[$key]))
		{
			$this->_fileName=$_FILES[$key]['name'];
			$this->_fileSize=$_FILES[$key]['size'];
			$this->_fileType=$_FILES[$key]['type'];
			$this->_errorCode=$_FILES[$key]['error'];
			$this->_localName=$_FILES[$key]['tmp_name'];
			return $this->_dataChanged=true;
		}
		else
			return false;
	}

	/**
	 * Raises postdata changed event.
	 * This method calls {@link onFileUpload} method.
	 * This method is primarly used by framework developers.
	 */
	public function raisePostDataChangedEvent()
	{
		$this->onFileUpload(null);
	}

	/**
	 * This method is invoked when a file is uploaded during a postback.
	 * The method raises <b>OnFileUpload</b> event to fire up the event handler.
	 * If you override this method, be sure to call the parent implementation
	 * so that the event delegates can be invoked.
	 * @param TEventParameter event parameter to be passed to the event handlers
	 */
	public function onFileUpload($param)
	{
		$this->raiseEvent('OnFileUpload',$this,$param);
	}

	/**
	 * Returns a value indicating whether postback has caused the control data change.
	 * This method is required by the IPostBackDataHandler interface.
	 * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
	 */
	public function getDataChanged()
	{
		return $this->_dataChanged;
	}

	/**
	 * Returns the original file name as the property value to be validated.
	 * This method is required by IValidatable property.
	 * @return mixed the property value to be validated
	 */
	public function getValidationPropertyValue()
	{
		return $this->getFileName();
	}

	/**
	 * Returns true if this control validated successfully.
	 * Defaults to true.
	 * @return bool wether this control validated successfully.
	 */
	public function getIsValid()
	{
	    return $this->_isValid;
	}
	/**
	 * @param bool wether this control is valid.
	 */
	public function setIsValid($value)
	{
	    $this->_isValid=TPropertyValue::ensureBoolean($value);
	}

}