Skip to content

Commit 91a0af2

Browse files
authored
Merge pull request #5411 from kenjis/fix-docs-uploaded_files.rst
docs: improve uploaded_files.rst
2 parents daf3e7f + 0daf8c9 commit 91a0af2

2 files changed

Lines changed: 182 additions & 25 deletions

File tree

user_guide_src/source/libraries/uploaded_files.rst

Lines changed: 179 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
***************************
1+
###########################
22
Working with Uploaded Files
3-
***************************
3+
###########################
44

55
CodeIgniter makes working with files uploaded through a form much simpler and more secure than using PHP's ``$_FILES``
66
array directly. This extends the :doc:`File class </libraries/files>` and thus gains all of the features of that class.
@@ -12,12 +12,166 @@ array directly. This extends the :doc:`File class </libraries/files>` and thus g
1212
:local:
1313
:depth: 2
1414

15-
===============
15+
***********
16+
The Process
17+
***********
18+
19+
Uploading a file involves the following general process:
20+
21+
- An upload form is displayed, allowing a user to select a file and
22+
upload it.
23+
- When the form is submitted, the file is uploaded to the destination
24+
you specify.
25+
- Along the way, the file is validated to make sure it is allowed to be
26+
uploaded based on the preferences you set.
27+
- Once uploaded, the user will be shown a success message.
28+
29+
To demonstrate this process here is brief tutorial. Afterward you'll
30+
find reference information.
31+
32+
Creating the Upload Form
33+
========================
34+
35+
Using a text editor, create a form called upload_form.php. In it, place
36+
this code and save it to your **app/Views/** directory::
37+
38+
<!DOCTYPE html>
39+
<html lang="en">
40+
<head>
41+
<title>Upload Form</title>
42+
</head>
43+
<body>
44+
45+
<?php foreach ($errors as $error): ?>
46+
<li><?= esc($error) ?></li>
47+
<?php endforeach ?>
48+
49+
<?= form_open_multipart('upload/upload') ?>
50+
51+
<input type="file" name="userfile" size="20" />
52+
53+
<br /><br />
54+
55+
<input type="submit" value="upload" />
56+
57+
</form>
58+
59+
</body>
60+
</html>
61+
62+
You'll notice we are using a form helper to create the opening form tag.
63+
File uploads require a multipart form, so the helper creates the proper
64+
syntax for you. You'll also notice we have an ``$errors`` variable. This is
65+
so we can show error messages in the event the user does something
66+
wrong.
67+
68+
The Success Page
69+
================
70+
71+
Using a text editor, create a form called upload_success.php. In it,
72+
place this code and save it to your **app/Views/** directory::
73+
74+
<!DOCTYPE html>
75+
<html lang="en">
76+
<head>
77+
<title>Upload Form</title>
78+
</head>
79+
<body>
80+
81+
<h3>Your file was successfully uploaded!</h3>
82+
83+
<ul>
84+
<li>name: <?= esc($uploaded_flleinfo->getBasename()) ?></li>
85+
<li>size: <?= esc($uploaded_flleinfo->getSizeByUnit('kb')) ?> KB</li>
86+
<li>extension: <?= esc($uploaded_flleinfo->guessExtension()) ?></li>
87+
</ul>
88+
89+
<p><?= anchor('upload', 'Upload Another File!') ?></p>
90+
91+
</body>
92+
</html>
93+
94+
The Controller
95+
==============
96+
97+
Using a text editor, create a controller called Upload.php. In it, place
98+
this code and save it to your **app/Controllers/** directory::
99+
100+
<?php
101+
102+
namespace App\Controllers;
103+
104+
use CodeIgniter\Files\File;
105+
106+
class Upload extends BaseController
107+
{
108+
protected $helpers = ['form'];
109+
110+
public function index()
111+
{
112+
return view('upload_form', ['errors' => []]);
113+
}
114+
115+
public function upload()
116+
{
117+
$validationRule = [
118+
'userfile' => [
119+
'label' => 'Image File',
120+
'rules' => 'uploaded[userfile]'
121+
. '|is_image[userfile]'
122+
. '|mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]'
123+
. '|max_size[userfile,100]'
124+
. '|max_dims[userfile,1024,768]',
125+
],
126+
];
127+
if (! $this->validate($validationRule)) {
128+
$data = ['errors' => $this->validator->getErrors()];
129+
130+
return view('upload_form', $data);
131+
}
132+
133+
$img = $this->request->getFile('userfile');
134+
135+
if (! $img->hasMoved()) {
136+
$filepath = WRITEPATH . 'uploads/' . $img->store();
137+
138+
$data = ['uploaded_flleinfo' => new File($filepath)];
139+
140+
return view('upload_success', $data);
141+
} else {
142+
$data = ['errors' => 'The file has already been moved.'];
143+
144+
return view('upload_form', $data);
145+
}
146+
}
147+
}
148+
149+
.. note:: Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global,
150+
only :ref:`rules-for-file-uploads` can be used to validate upload file with :doc:`validation`.
151+
The rule ``required`` also can't be used, so use ``uploaded`` instead.
152+
153+
The Upload Directory
154+
====================
155+
156+
The uploaded files are stored in the **writable/uploads/** directory.
157+
158+
Try it!
159+
=======
160+
161+
To try your form, visit your site using a URL similar to this one::
162+
163+
example.com/index.php/upload/
164+
165+
You should see an upload form. Try uploading an image file (either a
166+
**jpg**, **gif**, **png**, or **webp**). If the path in your controller is correct it should
167+
work.
168+
169+
***************
16170
Accessing Files
17-
===============
171+
***************
18172

19173
All Files
20-
----------
174+
=========
21175

22176
When you upload files they can be accessed natively in PHP through the ``$_FILES`` superglobal. This array has some
23177
major shortcomings when working with multiple files uploaded at once, and has potential security flaws many developers
@@ -72,7 +226,7 @@ In this case, the returned array of files would be more like::
72226
]
73227

74228
Single File
75-
-----------
229+
===========
76230

77231
If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly. This will return an instance of ``CodeIgniter\HTTP\Files\UploadedFile``:
78232

@@ -110,14 +264,14 @@ In controller::
110264
foreach($imagefile['images'] as $img) {
111265
if ($img->isValid() && ! $img->hasMoved()) {
112266
$newName = $img->getRandomName();
113-
$img->move(WRITEPATH.'uploads', $newName);
267+
$img->move(WRITEPATH . 'uploads', $newName);
114268
}
115269
}
116270
}
117271

118272
where the **images** is a loop from the form field name
119273

120-
If there are multiple files with the same name you can use ``getFile()`` ro retrieve every file individually::
274+
If there are multiple files with the same name you can use ``getFile()`` to retrieve every file individually::
121275
In controller::
122276

123277
$file1 = $this->request->getFile('images.0');
@@ -138,29 +292,29 @@ In controller::
138292
$file1 = $this->request->getFile('my-form.details.avatars.0');
139293
$file2 = $this->request->getFile('my-form.details.avatars.1');
140294

141-
.. note:: using ``getFiles()`` is more appropriate
295+
.. note:: Using ``getFiles()`` is more appropriate.
142296

143-
=====================
297+
*********************
144298
Working With the File
145-
=====================
299+
*********************
146300

147301
Once you've retrieved the UploadedFile instance, you can retrieve information about the file in safe ways, as well as
148302
move the file to a new location.
149303

150304
Verify A File
151-
-------------
305+
=============
152306

153307
You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method::
154308

155309
if (! $file->isValid()) {
156-
throw new \RuntimeException($file->getErrorString().'('.$file->getError().')');
310+
throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')');
157311
}
158312

159313
As seen in this example, if a file had an upload error, you can retrieve the error code (an integer) and the error
160314
message with the ``getError()`` and ``getErrorString()`` methods. The following errors can be discovered through
161315
this method:
162316

163-
* The file exceeds your upload_max_filesize ini directive.
317+
* The file exceeds your ``upload_max_filesize`` ini directive.
164318
* The file exceeds the upload limit defined in your form.
165319
* The file was only partially uploaded.
166320
* No file was uploaded.
@@ -169,7 +323,7 @@ this method:
169323
* File upload was stopped by a PHP extension.
170324

171325
File Names
172-
----------
326+
==========
173327

174328
**getName()**
175329

@@ -192,15 +346,16 @@ To get the full path of the temp file that was created during the upload, you ca
192346
$tempfile = $file->getTempName();
193347

194348
Other File Info
195-
---------------
349+
===============
196350

197351
**getClientExtension()**
198352

199-
Returns the original file extension, based on the file name that was uploaded. This is NOT a trusted source. For a
200-
trusted version, use ``guessExtension()`` instead::
353+
Returns the original file extension, based on the file name that was uploaded::
201354

202355
$ext = $file->getClientExtension();
203356

357+
.. warning:: This is NOT a trusted source. For a trusted version, use ``guessExtension()`` instead.
358+
204359
**getClientMimeType()**
205360

206361
Returns the mime type (mime type) of the file as provided by the client. This is NOT a trusted value. For a trusted
@@ -211,17 +366,17 @@ version, use ``getMimeType()`` instead::
211366
echo $type; // image/png
212367

213368
Moving Files
214-
------------
369+
============
215370

216371
Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move
217372
the file to as the first parameter::
218373

219-
$file->move(WRITEPATH.'uploads');
374+
$file->move(WRITEPATH . 'uploads');
220375

221376
By default, the original filename was used. You can specify a new filename by passing it as the second parameter::
222377

223378
$newName = $file->getRandomName();
224-
$file->move(WRITEPATH.'uploads', $newName);
379+
$file->move(WRITEPATH . 'uploads', $newName);
225380

226381
Once the file has been removed the temporary file is deleted. You can check if a file has been moved already with
227382
the ``hasMoved()`` method, which returns a boolean::
@@ -237,15 +392,15 @@ Moving an uploaded file can fail, with an HTTPException, under several circumsta
237392
- the file move operation fails (e.g., improper permissions)
238393

239394
Store Files
240-
------------
395+
===========
241396

242397
Each file can be moved to its new location with the aptly named ``store()`` method.
243398

244399
With the simplest usage, a single file might be submitted like::
245400

246401
<input type="file" name="userfile" />
247402

248-
By default, upload files are saved in writable/uploads directory. The YYYYMMDD folder
403+
By default, upload files are saved in **writable/uploads** directory. The **YYYYMMDD** folder
249404
and random file name will be created. Returns a file path::
250405

251406
$path = $this->request->getFile('userfile')->store();
@@ -255,7 +410,7 @@ passing it as the second parameter::
255410

256411
$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg');
257412

258-
Moving an uploaded file can fail, with an HTTPException, under several circumstances:
413+
Moving an uploaded file can fail, with an ``HTTPException``, under several circumstances:
259414

260415
- the file has already been moved
261416
- the file did not upload successfully

user_guide_src/source/libraries/validation.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,11 +892,13 @@ valid_cc_number Yes Verifies that the credit card number matches
892892
HSBC Canada Card (hsbc)
893893
======================= ========== ============================================= ===================================================
894894

895+
.. _rules-for-file-uploads:
896+
895897
Rules for File Uploads
896898
======================
897899

898900
These validation rules enable you to do the basic checks you might need to verify that uploaded files meet your business needs.
899-
Since the value of a file upload HTML field doesn't exist, and is stored in the $_FILES global, the name of the input field will
901+
Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global, the name of the input field will
900902
need to be used twice. Once to specify the field name as you would for any other rule, but again as the first parameter of all
901903
file upload related rules::
902904

0 commit comments

Comments
 (0)