Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

File uploads

A post cover, an avatar, a document — files from visitors arrive together with a form. In CodeIgniter an uploaded file is an object: you get it from the request, check it with rules and move it to a storage folder. Public files go to public/uploads, private ones to writable/uploads.

The form

<!-- app/Views/posts/cover.php -->
<?= form_open_multipart('posts/cover') ?>
    <input type="file" name="cover">
 
    <button type="submit">Upload</button>
<?= form_close() ?>

form_open_multipart() prints the form tag with the enctype="multipart/form-data" attribute. Without it the file never reaches the server.

Routes

// app/Config/Routes.php
$routes->get('posts/cover', 'Posts::cover');
$routes->post('posts/cover', 'Posts::upload');

The cover() method only outputs the view: return view('posts/cover');.

Receiving and saving

// app/Controllers/Posts.php
public function upload()
{
    $file = $this->request->getFile('cover');
 
    if (! $file->isValid()) {
        return redirect()->back()->with('message', $file->getErrorString());
    }
 
    $name = $file->getRandomName();
    $file->move(FCPATH . 'uploads', $name);
 
    return redirect()->back()->with('message', "File saved: $name");
}

getFile('cover') returns the file object by the field name. getRandomName() creates a random name with the original extension, move() moves the file. FCPATH is the path to the public folder, so the file lands in public/uploads. Choose an image and submit the form — a file like 1709371200_a3f9c2.jpg appears in the folder.

Validation

Before saving, the file is checked with rules like ordinary fields. Add this to the beginning of the upload() method:

$rules = [
    'cover' => 'uploaded[cover]|is_image[cover]|max_size[cover,2048]|ext_in[cover,jpg,jpeg,png,webp]',
];
 
if (! $this->validate($rules)) {
    return redirect()->back()->withInput();
}

Now a text file or an image larger than two megabytes is rejected.

RuleWhat it checks
uploaded[cover]The file was really uploaded
max_size[cover,2048]The size is at most 2048 KB
is_image[cover]The file is an image
ext_in[cover,jpg,png]The extension is in the list
mime_in[cover,image/png,image/jpeg]The content type is in the list

Showing the image

The file name is saved in the post record, and the view builds the address with base_url():

<img src="<?= base_url('uploads/' . esc($post['cover'], 'url')) ?>" alt="Cover">

File methods

MethodWhat it returns
getClientName()The file name on the visitor's computer
getRandomName()A random name with the extension
getMimeType()The content type
getSizeByUnit('kb')The size in kilobytes
isValid()The upload finished without errors
store('invoices')Saves the file to writable/uploads/invoices

Files in writable/uploads cannot be reached by a direct address. A controller serves them after checking permissions: return $this->response->download($path, null);.

Common mistake

Saving a file under the visitor's name — getClientName() — is dangerous: the name may be shell.php or contain ../. A file with the .php extension in the public folder is executed by the server as a program. Create the name with getRandomName(), limit the extensions with the ext_in rule and check the type by content with is_image or mime_in.

Thanks for reading!

Donate to the site — we work hard for you.