1: <?php
2: /**
3: * CUploadedFile class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CUploadedFile represents the information for an uploaded file.
13: *
14: * Call {@link getInstance} to retrieve the instance of an uploaded file,
15: * and then use {@link saveAs} to save it on the server.
16: * You may also query other information about the file, including {@link name},
17: * {@link tempName}, {@link type}, {@link size} and {@link error}.
18: *
19: * @property string $name The original name of the file being uploaded.
20: * @property string $tempName The path of the uploaded file on the server.
21: * Note, this is a temporary file which will be automatically deleted by PHP
22: * after the current request is processed.
23: * @property string $type The MIME-type of the uploaded file (such as "image/gif").
24: * Since this MIME type is not checked on the server side, do not take this value for granted.
25: * Instead, use {@link CFileHelper::getMimeType} to determine the exact MIME type.
26: * @property integer $size The actual size of the uploaded file in bytes.
27: * @property integer $error The error code.
28: * @property boolean $hasError Whether there is an error with the uploaded file.
29: * Check {@link error} for detailed error code information.
30: * @property string $extensionName The file extension name for {@link name}.
31: * The extension name does not include the dot character. An empty string
32: * is returned if {@link name} does not have an extension name.
33: *
34: * @author Qiang Xue <qiang.xue@gmail.com>
35: * @package system.web
36: * @since 1.0
37: */
38: class CUploadedFile extends CComponent
39: {
40: static private $_files;
41:
42: private $_name;
43: private $_tempName;
44: private $_type;
45: private $_size;
46: private $_error;
47:
48: /**
49: * Returns an instance of the specified uploaded file.
50: * The file should be uploaded using {@link CHtml::activeFileField}.
51: * @param CModel $model the model instance
52: * @param string $attribute the attribute name. For tabular file uploading, this can be in the format of "[$i]attributeName", where $i stands for an integer index.
53: * @return CUploadedFile the instance of the uploaded file.
54: * Null is returned if no file is uploaded for the specified model attribute.
55: * @see getInstanceByName
56: */
57: public static function getInstance($model, $attribute)
58: {
59: return self::getInstanceByName(CHtml::resolveName($model, $attribute));
60: }
61:
62: /**
63: * Returns all uploaded files for the given model attribute.
64: * @param CModel $model the model instance
65: * @param string $attribute the attribute name. For tabular file uploading, this can be in the format of "[$i]attributeName", where $i stands for an integer index.
66: * @return CUploadedFile[] array of CUploadedFile objects.
67: * Empty array is returned if no available file was found for the given attribute.
68: */
69: public static function getInstances($model, $attribute)
70: {
71: return self::getInstancesByName(CHtml::resolveName($model, $attribute));
72: }
73:
74: /**
75: * Returns an instance of the specified uploaded file.
76: * The name can be a plain string or a string like an array element (e.g. 'Post[imageFile]', or 'Post[0][imageFile]').
77: * @param string $name the name of the file input field.
78: * @return CUploadedFile the instance of the uploaded file.
79: * Null is returned if no file is uploaded for the specified name.
80: */
81: public static function getInstanceByName($name)
82: {
83: if(null===self::$_files)
84: self::prefetchFiles();
85:
86: return isset(self::$_files[$name]) && self::$_files[$name]->getError()!=UPLOAD_ERR_NO_FILE ? self::$_files[$name] : null;
87: }
88:
89: /**
90: * Returns an array of instances starting with specified array name.
91: *
92: * If multiple files were uploaded and saved as 'Files[0]', 'Files[1]',
93: * 'Files[n]'..., you can have them all by passing 'Files' as array name.
94: * @param string $name the name of the array of files
95: * @return CUploadedFile[] the array of CUploadedFile objects. Empty array is returned
96: * if no adequate upload was found. Please note that this array will contain
97: * all files from all subarrays regardless how deeply nested they are.
98: */
99: public static function getInstancesByName($name)
100: {
101: if(null===self::$_files)
102: self::prefetchFiles();
103:
104: $len=strlen($name);
105: $results=array();
106: foreach(array_keys(self::$_files) as $key)
107: if(0===strncmp($key, $name.'[', $len+1) && self::$_files[$key]->getError()!=UPLOAD_ERR_NO_FILE)
108: $results[] = self::$_files[$key];
109: return $results;
110: }
111:
112: /**
113: * Cleans up the loaded CUploadedFile instances.
114: * This method is mainly used by test scripts to set up a fixture.
115: * @since 1.1.4
116: */
117: public static function reset()
118: {
119: self::$_files=null;
120: }
121:
122: /**
123: * Initially processes $_FILES superglobal for easier use.
124: * Only for internal usage.
125: */
126: protected static function prefetchFiles()
127: {
128: self::$_files = array();
129: if(!isset($_FILES) || !is_array($_FILES))
130: return;
131:
132: foreach($_FILES as $class=>$info)
133: self::collectFilesRecursive($class, $info['name'], $info['tmp_name'], $info['type'], $info['size'], $info['error']);
134: }
135: /**
136: * Processes incoming files for {@link getInstanceByName}.
137: * @param string $key key for identifiing uploaded file: class name and subarray indexes
138: * @param mixed $names file names provided by PHP
139: * @param mixed $tmp_names temporary file names provided by PHP
140: * @param mixed $types filetypes provided by PHP
141: * @param mixed $sizes file sizes provided by PHP
142: * @param mixed $errors uploading issues provided by PHP
143: */
144: protected static function collectFilesRecursive($key, $names, $tmp_names, $types, $sizes, $errors)
145: {
146: if(is_array($names))
147: {
148: foreach($names as $item=>$name)
149: self::collectFilesRecursive($key.'['.$item.']', $names[$item], $tmp_names[$item], $types[$item], $sizes[$item], $errors[$item]);
150: }
151: else
152: self::$_files[$key] = new CUploadedFile($names, $tmp_names, $types, $sizes, $errors);
153: }
154:
155: /**
156: * Constructor.
157: * Use {@link getInstance} to get an instance of an uploaded file.
158: * @param string $name the original name of the file being uploaded
159: * @param string $tempName the path of the uploaded file on the server.
160: * @param string $type the MIME-type of the uploaded file (such as "image/gif").
161: * @param integer $size the actual size of the uploaded file in bytes
162: * @param integer $error the error code
163: */
164: public function __construct($name,$tempName,$type,$size,$error)
165: {
166: $this->_name=$name;
167: $this->_tempName=$tempName;
168: $this->_type=$type;
169: $this->_size=$size;
170: $this->_error=$error;
171: }
172:
173: /**
174: * String output.
175: * This is PHP magic method that returns string representation of an object.
176: * The implementation here returns the uploaded file's name.
177: * @return string the string representation of the object
178: */
179: public function __toString()
180: {
181: return $this->_name;
182: }
183:
184: /**
185: * Saves the uploaded file.
186: * Note: this method uses php's move_uploaded_file() method. As such, if the target file ($file)
187: * already exists it is overwritten.
188: * @param string $file the file path used to save the uploaded file
189: * @param boolean $deleteTempFile whether to delete the temporary file after saving.
190: * If true, you will not be able to save the uploaded file again in the current request.
191: * @return boolean true whether the file is saved successfully
192: */
193: public function saveAs($file,$deleteTempFile=true)
194: {
195: if($this->_error==UPLOAD_ERR_OK)
196: {
197: if($deleteTempFile)
198: return move_uploaded_file($this->_tempName,$file);
199: elseif(is_uploaded_file($this->_tempName))
200: return copy($this->_tempName, $file);
201: else
202: return false;
203: }
204: else
205: return false;
206: }
207:
208: /**
209: * @return string the original name of the file being uploaded
210: */
211: public function getName()
212: {
213: return $this->_name;
214: }
215:
216: /**
217: * @return string the path of the uploaded file on the server.
218: * Note, this is a temporary file which will be automatically deleted by PHP
219: * after the current request is processed.
220: */
221: public function getTempName()
222: {
223: return $this->_tempName;
224: }
225:
226: /**
227: * @return string the MIME-type of the uploaded file (such as "image/gif").
228: * Since this MIME type is not checked on the server side, do not take this value for granted.
229: * Instead, use {@link CFileHelper::getMimeType} to determine the exact MIME type.
230: */
231: public function getType()
232: {
233: return $this->_type;
234: }
235:
236: /**
237: * @return integer the actual size of the uploaded file in bytes
238: */
239: public function getSize()
240: {
241: return $this->_size;
242: }
243:
244: /**
245: * Returns an error code describing the status of this file uploading.
246: * @return integer the error code
247: * @see http://www.php.net/manual/en/features.file-upload.errors.php
248: */
249: public function getError()
250: {
251: return $this->_error;
252: }
253:
254: /**
255: * @return boolean whether there is an error with the uploaded file.
256: * Check {@link error} for detailed error code information.
257: */
258: public function getHasError()
259: {
260: return $this->_error!=UPLOAD_ERR_OK;
261: }
262:
263: /**
264: * @return string the file extension name for {@link name}.
265: * The extension name does not include the dot character. An empty string
266: * is returned if {@link name} does not have an extension name.
267: */
268: public function getExtensionName()
269: {
270: return CFileHelper::getExtension($this->_name);
271: }
272: }
273: