Completed
Pull Request — 2.1 (#12704)
by Robert
08:59
created

UploadedFile   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Test Coverage

Coverage 73.44%

Importance

Changes 0
Metric Value
wmc 26
lcom 3
cbo 2
dl 0
loc 210
ccs 47
cts 64
cp 0.7344
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __toString() 0 4 1
A reset() 0 4 1
A saveAs() 0 11 4
A getExtension() 0 4 1
A getHasError() 0 4 1
A getBaseName() 0 6 1
A getInstance() 0 5 1
A getInstances() 0 5 1
A getInstanceByName() 0 5 2
A getInstancesByName() 0 14 4
B loadFiles() 0 12 5
A loadFilesRecursive() 0 16 4
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\web;
9
10
use yii\base\Object;
11
use yii\helpers\Html;
12
13
/**
14
 * UploadedFile represents the information for an uploaded file.
15
 *
16
 * You can call [[getInstance()]] to retrieve the instance of an uploaded file,
17
 * and then use [[saveAs()]] to save it on the server.
18
 * You may also query other information about the file, including [[name]],
19
 * [[tempName]], [[type]], [[size]] and [[error]].
20
 *
21
 * @property string $baseName Original file base name. This property is read-only.
22
 * @property string $extension File extension. This property is read-only.
23
 * @property boolean $hasError Whether there is an error with the uploaded file. Check [[error]] for detailed
24
 * error code information. This property is read-only.
25
 *
26
 * @author Qiang Xue <[email protected]>
27
 * @since 2.0
28
 */
29
class UploadedFile extends Object
30
{
31
    /**
32
     * @var string the original name of the file being uploaded
33
     */
34
    public $name;
35
    /**
36
     * @var string the path of the uploaded file on the server.
37
     * Note, this is a temporary file which will be automatically deleted by PHP
38
     * after the current request is processed.
39
     */
40
    public $tempName;
41
    /**
42
     * @var string the MIME-type of the uploaded file (such as "image/gif").
43
     * Since this MIME type is not checked on the server-side, do not take this value for granted.
44
     * Instead, use [[\yii\helpers\FileHelper::getMimeType()]] to determine the exact MIME type.
45
     */
46
    public $type;
47
    /**
48
     * @var integer the actual size of the uploaded file in bytes
49
     */
50
    public $size;
51
    /**
52
     * @var integer an error code describing the status of this file uploading.
53
     * @see http://www.php.net/manual/en/features.file-upload.errors.php
54
     */
55
    public $error;
56
57
    private static $_files;
58
59
60
    /**
61
     * String output.
62
     * This is PHP magic method that returns string representation of an object.
63
     * The implementation here returns the uploaded file's name.
64
     * @return string the string representation of the object
65
     */
66 7
    public function __toString()
67
    {
68 7
        return $this->name;
69
    }
70
71
    /**
72
     * Returns an uploaded file for the given model attribute.
73
     * The file should be uploaded using [[\yii\widgets\ActiveField::fileInput()]].
74
     * @param \yii\base\Model $model the data model
75
     * @param string $attribute the attribute name. The attribute name may contain array indexes.
76
     * For example, '[1]file' for tabular file uploading; and 'file[1]' for an element in a file array.
77
     * @return UploadedFile the instance of the uploaded file.
78
     * Null is returned if no file is uploaded for the specified model attribute.
79
     * @see getInstanceByName()
80
     */
81 1
    public static function getInstance($model, $attribute)
82
    {
83 1
        $name = Html::getInputName($model, $attribute);
84 1
        return static::getInstanceByName($name);
85
    }
86
87
    /**
88
     * Returns all uploaded files for the given model attribute.
89
     * @param \yii\base\Model $model the data model
90
     * @param string $attribute the attribute name. The attribute name may contain array indexes
91
     * for tabular file uploading, e.g. '[1]file'.
92
     * @return UploadedFile[] array of UploadedFile objects.
93
     * Empty array is returned if no available file was found for the given attribute.
94
     */
95 1
    public static function getInstances($model, $attribute)
96
    {
97 1
        $name = Html::getInputName($model, $attribute);
98 1
        return static::getInstancesByName($name);
99
    }
100
101
    /**
102
     * Returns an uploaded file according to the given file input name.
103
     * The name can be a plain string or a string like an array element (e.g. 'Post[imageFile]', or 'Post[0][imageFile]').
104
     * @param string $name the name of the file input field.
105
     * @return null|UploadedFile the instance of the uploaded file.
106
     * Null is returned if no file is uploaded for the specified name.
107
     */
108 1
    public static function getInstanceByName($name)
109
    {
110 1
        $files = self::loadFiles();
111 1
        return isset($files[$name]) ? new static($files[$name]) : null;
112
    }
113
114
    /**
115
     * Returns an array of uploaded files corresponding to the specified file input name.
116
     * This is mainly used when multiple files were uploaded and saved as 'files[0]', 'files[1]',
117
     * 'files[n]'..., and you can retrieve them all by passing 'files' as the name.
118
     * @param string $name the name of the array of files
119
     * @return UploadedFile[] the array of UploadedFile objects. Empty array is returned
120
     * if no adequate upload was found. Please note that this array will contain
121
     * all files from all sub-arrays regardless how deeply nested they are.
122
     */
123 1
    public static function getInstancesByName($name)
124
    {
125 1
        $files = self::loadFiles();
126 1
        if (isset($files[$name])) {
127
            return [new static($files[$name])];
128
        }
129 1
        $results = [];
130 1
        foreach ($files as $key => $file) {
131 1
            if (strpos($key, "{$name}[") === 0) {
132 1
                $results[] = new static($file);
133 1
            }
134 1
        }
135 1
        return $results;
136
    }
137
138
    /**
139
     * Cleans up the loaded UploadedFile instances.
140
     * This method is mainly used by test scripts to set up a fixture.
141
     */
142
    public static function reset()
143
    {
144
        self::$_files = null;
145
    }
146
147
    /**
148
     * Saves the uploaded file.
149
     * Note that this method uses php's move_uploaded_file() method. If the target file `$file`
150
     * already exists, it will be overwritten.
151
     * @param string $file the file path used to save the uploaded file
152
     * @param boolean $deleteTempFile whether to delete the temporary file after saving.
153
     * If true, you will not be able to save the uploaded file again in the current request.
154
     * @return boolean true whether the file is saved successfully
155
     * @see error
156
     */
157
    public function saveAs($file, $deleteTempFile = true)
158
    {
159
        if ($this->error == UPLOAD_ERR_OK) {
160
            if ($deleteTempFile) {
161
                return move_uploaded_file($this->tempName, $file);
162
            } elseif (is_uploaded_file($this->tempName)) {
163
                return copy($this->tempName, $file);
164
            }
165
        }
166
        return false;
167
    }
168
169
    /**
170
     * @return string original file base name
171
     */
172 1
    public function getBaseName()
173
    {
174
        // https://github.com/yiisoft/yii2/issues/11012
175 1
        $pathInfo = pathinfo('_' . $this->name, PATHINFO_FILENAME);
176 1
        return mb_substr($pathInfo, 1, mb_strlen($pathInfo, '8bit'), '8bit');
177
    }
178
179
    /**
180
     * @return string file extension
181
     */
182 2
    public function getExtension()
183
    {
184 2
        return strtolower(pathinfo($this->name, PATHINFO_EXTENSION));
185
    }
186
187
    /**
188
     * @return boolean whether there is an error with the uploaded file.
189
     * Check [[error]] for detailed error code information.
190
     */
191
    public function getHasError()
192
    {
193
        return $this->error != UPLOAD_ERR_OK;
194
    }
195
196
    /**
197
     * Creates UploadedFile instances from $_FILE.
198
     * @return array the UploadedFile instances
199
     */
200 2
    private static function loadFiles()
201
    {
202 2
        if (self::$_files === null) {
203 1
            self::$_files = [];
204 1
            if (isset($_FILES) && is_array($_FILES)) {
205 1
                foreach ($_FILES as $class => $info) {
206 1
                    self::loadFilesRecursive($class, $info['name'], $info['tmp_name'], $info['type'], $info['size'], $info['error']);
207 1
                }
208 1
            }
209 1
        }
210 2
        return self::$_files;
211
    }
212
213
    /**
214
     * Creates UploadedFile instances from $_FILE recursively.
215
     * @param string $key key for identifying uploaded file: class name and sub-array indexes
216
     * @param mixed $names file names provided by PHP
217
     * @param mixed $tempNames temporary file names provided by PHP
218
     * @param mixed $types file types provided by PHP
219
     * @param mixed $sizes file sizes provided by PHP
220
     * @param mixed $errors uploading issues provided by PHP
221
     */
222 1
    private static function loadFilesRecursive($key, $names, $tempNames, $types, $sizes, $errors)
223
    {
224 1
        if (is_array($names)) {
225
            foreach ($names as $i => $name) {
226
                self::loadFilesRecursive($key . '[' . $i . ']', $name, $tempNames[$i], $types[$i], $sizes[$i], $errors[$i]);
227
            }
228 1
        } elseif ((int)$errors !== UPLOAD_ERR_NO_FILE) {
229 1
            self::$_files[$key] = [
230 1
                'name' => $names,
231 1
                'tempName' => $tempNames,
232 1
                'type' => $types,
233 1
                'size' => $sizes,
234 1
                'error' => $errors,
235
            ];
236 1
        }
237 1
    }
238
}
239