|
2 | 2 | Working with Uploaded Files |
3 | 3 | *************************** |
4 | 4 |
|
5 | | -TODO |
| 5 | +CodeIgniter makes working with files uploaded through a form much simpler and more secure than using PHP's ``$_FILES`` |
| 6 | +array directly. |
| 7 | + |
| 8 | +.. note:: This is not the same as the File Uploading class in previous versions of CodeIgniter. This provides a raw |
| 9 | + interface to the uploaded files with a few small features. An uploader class will be present in the final release. |
| 10 | + |
| 11 | +.. contents:: |
| 12 | + :local: |
| 13 | + |
| 14 | +=============== |
| 15 | +Accessing Files |
| 16 | +=============== |
| 17 | + |
| 18 | +When you upload files they can be accessed natively in PHP through the ``$_FILES`` superglobal. This array has some |
| 19 | +major shortcomings when working with multiple files uploaded at once, and has potential security flaws many developers |
| 20 | +are not aware of. CodeIgniter helps with both of these situations by standardizing your usage of files behind a |
| 21 | +common interface. |
| 22 | + |
| 23 | +Files are accessed through the current ``IncomingRequest`` instance. To retrieve all files that were uploaded with this |
| 24 | +request, use ``getFiles()``. This will return an array of files represented by instances of ``CodeIgniter\HTTP\Files\UploadedFile``. |
| 25 | +:: |
| 26 | + |
| 27 | + $files = $this->request->getFiles(); |
| 28 | + |
| 29 | +Of course, there are multiple ways to name the file input, and anything but the simplest can create strange results. |
| 30 | +The array returns in a manner that you would expect. With the simplest usage, a single file might be submitted like:: |
| 31 | + |
| 32 | + <input type="file" name="avatar" /> |
| 33 | + |
| 34 | +Which would return a simple array like:: |
| 35 | + |
| 36 | + [ |
| 37 | + 'avatar' => // UploadedFile instance |
| 38 | + ] |
| 39 | + |
| 40 | +If you used an array notation for the name, the input would look something like:: |
| 41 | + |
| 42 | + <input type="file" name="my-form[details][avatar]" /> |
| 43 | + |
| 44 | +The array returned by ``getFiles()`` would look more like this:: |
| 45 | + |
| 46 | + [ |
| 47 | + 'my-form' => [ |
| 48 | + 'details' => [ |
| 49 | + 'avatar' => // UploadedFile instance |
| 50 | + ] |
| 51 | + ] |
| 52 | + ] |
| 53 | + |
| 54 | +In some cases, you may specify an array of files to upload:: |
| 55 | + |
| 56 | + Upload an avatar: <input type="file" name="my-form[details][avatars][]" /> |
| 57 | + Upload an avatar: <input type="file" name="my-form[details][avatars][]" /> |
| 58 | + |
| 59 | +In this case, the returned array of files would be more like:: |
| 60 | + |
| 61 | + [ |
| 62 | + 'my-form' => [ |
| 63 | + 'details' => [ |
| 64 | + 'avatar' => [ |
| 65 | + 0 => /* UploadedFile instance */, |
| 66 | + 1 => /* UploadedFile instance */ |
| 67 | + ] |
| 68 | + ] |
| 69 | + ] |
| 70 | + |
| 71 | +If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly:: |
| 72 | + |
| 73 | + $file = $this->request->getFile('avatar'); |
| 74 | + |
| 75 | +.. note:: This currently only works with simple file names and not with array syntax naming. |
| 76 | + |
| 77 | +===================== |
| 78 | +Working With the File |
| 79 | +===================== |
| 80 | + |
| 81 | +Once you've gotten the UploadedFile instance, you can retrieve information about the file in safe ways, as well as |
| 82 | +move the file to a new location. |
| 83 | + |
| 84 | +Verify A File |
| 85 | +------------- |
| 86 | + |
| 87 | +You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method:: |
| 88 | + |
| 89 | + if (! $file->isValid()) |
| 90 | + { |
| 91 | + throw new RuntimeException($file->getErrorString().'('.$file->getError().')'); |
| 92 | + } |
| 93 | + |
| 94 | +As seen in this example, if a file had an upload error, you can retrieve the error code (an integer) and the error |
| 95 | +message with the ``getError()`` and ``getErrorString()`` methods. The following errors can be discovered through |
| 96 | +this method: |
| 97 | + |
| 98 | +* The file exceeds your upload_max_filesize ini directive. |
| 99 | +* The file exceeds the upload limit defined in your form. |
| 100 | +* The file was only partially uploaded. |
| 101 | +* No file was uploaded. |
| 102 | +* The file could not be written on disk. |
| 103 | +* File could not be uploaded: missing temporary directory. |
| 104 | +* File upload was stopped by a PHP extension. |
| 105 | + |
| 106 | +File Names |
| 107 | +---------- |
| 108 | + |
| 109 | +**getName()** |
| 110 | + |
| 111 | +You can retrieve the original filename provided by the client with the ``getName()`` method. This will typically be the |
| 112 | +filename sent by the client, and should not be trusted. If the file has been moved, this will return the final name of |
| 113 | +the moved file.:: |
| 114 | + |
| 115 | + $name = $file->getName(); |
| 116 | + |
| 117 | +**getTempName()** |
| 118 | + |
| 119 | +To get the name of the temp file that was created during the upload, you can use the ``getTempName()`` method.:: |
| 120 | + |
| 121 | + $tempfile = $file->getTempName(); |
| 122 | + |
| 123 | +**getRandomName()** |
| 124 | + |
| 125 | +You can generate a cryptographically secure random filename, with the current timestamp prepended, with the ``getRandomName()`` |
| 126 | +method. This is especially useful to rename files when moving it so that the filename is unguessable. |
| 127 | +:: |
| 128 | + |
| 129 | + // Generates something like: 1465965676_385e33f741.jpg |
| 130 | + $newName = $file->getRandomName(); |
| 131 | + |
| 132 | + |
| 133 | +Other File Info |
| 134 | +--------------- |
| 135 | + |
| 136 | +**getExtension()** |
| 137 | + |
| 138 | +Attempts to determine the file extension based on the trusted ``getType()`` method instead of the value listed |
| 139 | +in ``$_FILES``. If the mime type is unknown, will return null. Uses the values in **application/Config/Mimes.php** |
| 140 | +to determine extension. |
| 141 | +:: |
| 142 | + |
| 143 | + // Returns 'jpg' (WITHOUT the period) |
| 144 | + $ext = $file->getExtension(); |
| 145 | + |
| 146 | +**getClientExtension()** |
| 147 | + |
| 148 | +Returns the original file extension, based on the file name that was uploaded. This is NOT a trusted source. For a |
| 149 | +trusted version, use ``getExtension()`` instead. |
| 150 | +:: |
| 151 | + |
| 152 | + $ext = $file->getClientExtension(); |
| 153 | + |
| 154 | +**getType()** |
| 155 | + |
| 156 | +Retrieve the media type (mime type) of the file. Does not use information from the $_FILES array, but uses other methods to more |
| 157 | +accurately determine the type of file, like ``finfo``, or ``mime_content_type``. |
| 158 | +:: |
| 159 | + |
| 160 | + $type = $file->getType(); |
| 161 | + |
| 162 | + echo $type; // image/png |
| 163 | + |
| 164 | +**getClientType()** |
| 165 | + |
| 166 | +Returns the mime type (mime type) of the file as provided by the client. This is NOT a trusted value. For a trusted |
| 167 | +version, use ``getType()`` instead. |
| 168 | +:: |
| 169 | + |
| 170 | + $type = $file->getClientType(); |
| 171 | + |
| 172 | + echo $type; // image/png |
| 173 | + |
| 174 | +**getSize()** |
| 175 | + |
| 176 | +Returns the size of the uploaded file in bytes. You can pass in either 'kb' or 'mb' as the first parameter to get |
| 177 | +the results in kilobytes or megabytes, respectively. |
| 178 | +:: |
| 179 | + |
| 180 | + $bytes = $file->getSize(); // 256901 |
| 181 | + $kilobytes = $file->getSize('kb'); // 250.880 |
| 182 | + $megabytes = $file->getSize('mb'); // 0.245 |
| 183 | + |
| 184 | +Moving Files |
| 185 | +------------ |
| 186 | + |
| 187 | +Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move |
| 188 | +the file to as the first parameter:: |
| 189 | + |
| 190 | + $file->move(WRITEPATH.'uploads'); |
| 191 | + |
| 192 | +By default, the original filename was used. You can specify a new filename by passing it as the second parameter:: |
| 193 | + |
| 194 | + $newName = $file->getRandomName(); |
| 195 | + $file->move(WRITEPATH.'uploads', $newName); |
| 196 | + |
| 197 | +Once the file has been removed the temporary file is deleted. You can check if a file has been moved already with |
| 198 | +the ``hasMoved()`` method, which returns a boolean:: |
| 199 | + |
| 200 | + if ($file->isValid() && ! $file->hasMoved()) |
| 201 | + { |
| 202 | + $file->move($path); |
| 203 | + } |
0 commit comments