Basic File Uploading
Let's build a file uploader. Not a theoretical example. Not a "hello world" toy. A real uploader that lets you upload files, using Trongate's File module.
We'll use the following three-method pattern:
- Display the upload form
- Process the upload with validation
- Show the success page
Each method does one thing. Clean. Simple. Maintainable.
Uploading images? Image uploads usually require additional processing.
For image uploads, use the Image Module, which includes support for common image manipulation tasks.
The Complete Controller
Create modules/simple_uploader/Simple_uploader.php:
<?php
class Simple_uploader extends Trongate {
/**
* 1. Display the upload form
*/
function index() {
$data['view_module'] = 'simple_uploader';
$data['view_file'] = 'upload_form';
$this->view('upload_form', $data);
}
/**
* 2. Process the file upload
*/
function submit_upload() {
// Validate first
$this->validation->set_rules(
'userfile',
'File',
'required|allowed_types[txt,md,csv,log]|max_size[500]'
);
$result = $this->validation->run();
if ($result === true) {
// Configure and upload
$config['destination'] = 'uploads';
$config['upload_to_module'] = true;
$config['make_rand_name'] = false;
$file_info = $this->file->upload($config);
// Success - redirect to prevent resubmission
set_flashdata('File uploaded successfully!');
redirect('simple_uploader/success/' . $file_info['file_name']);
} else {
// Validation failed - show form with errors
$this->index();
}
}
/**
* 3. Display the success page
*/
function success($filename = '') {
$data['filename'] = $filename;
$data['view_module'] = 'simple_uploader';
$data['view_file'] = 'upload_success';
$this->view('upload_success', $data);
}
}
?>
That's the entire controller. Three methods. Zero complexity. Production-ready pattern.
The File module automatically processes the first file uploaded in your form, regardless of its input field name. This makes it consistent with the Image module.
Important: File Input Name
The name attribute of your file input field must match what you're validating. In this example, we use userfile consistently throughout:
- Form:
form_file_select('userfile', ...)
- Validation:
set_rules('userfile', 'File', ...)
The Upload Form View
Create modules/simple_uploader/views/upload_form.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="simple_uploader_module/css/simple_uploader.css">
<title>Upload Form</title>
</head>
<body>
<h1>Upload Form</h1>
<?= validation_errors() ?>
<div class="info">
<p><strong>Allowed file types:</strong> TXT, MD, CSV, LOG</p>
<p><strong>Maximum file size:</strong> 500 KB</p>
<p><strong>Note:</strong> For image uploads, use the <code>image</code> module instead.</p>
</div>
<?php
echo form_open_upload('simple_uploader/submit_upload');
echo form_label('Select File:', ['for' => 'userfile']);
$select_attr = [
'id' => 'userfile',
'size' => '20',
'accept' => '.txt,.md,.csv,.log'
];
echo form_file_select('userfile', $select_attr);
echo form_submit('submit', 'Upload File');
echo form_close();
?>
</body>
</html>
About the CSS file: The two view files mentioned on this page reference simple_uploader.css, which should be located at:
modules/simple_uploader/css/simple_uploader.css
Trongate's Module Asset Manager will automatically find and load this file when the views are rendered.
As a reminder, you can download the complete module (including the CSS file) from GitHub:
Simple Uploader Module
The Success Page View
Create modules/simple_uploader/views/upload_success.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="simple_uploader_module/css/simple_uploader.css">
<title>Upload Complete</title>
</head>
<body>
<h1>Upload Complete!</h1>
<?= flashdata() ?>
<?php if (!empty($filename)) { ?>
<div class="file-info">
<p><strong>File Name:</strong></p>
<p class="file-name"><?= out($filename) ?></p>
</div>
<p>
<a href="<?= BASE_URL ?>simple_uploader_module/uploads/<?= $filename ?>"
target="_blank"
class="button">
View File
</a>
<?= anchor('simple_uploader', 'Upload Another File', ['class' => 'button secondary']) ?>
</p>
<?php } else { ?>
<div class="alert">
<p>No file information available.</p>
<p><?= anchor('simple_uploader', 'Upload a File', ['class' => 'button']) ?></p>
</div>
<?php } ?>
</body>
</html>
Create the Upload Directory
One last step - create the directory where files will be stored:
# From your application root:
mkdir modules/simple_uploader/uploads
chmod 755 modules/simple_uploader/uploads
Or create it via PHP if you prefer:
// Run this once in a controller
$this->file->create_directory('uploads', 0755, true);
How It Works (The Flow)
- User visits
yoursite.com/simple_uploader (or yoursite.com/simple_uploader/index)
- Form displays with file selection input
- User selects file and clicks "Upload File"
- Browser POSTs to
yoursite.com/simple_uploader/submit_upload
- Trongate validates the file (required, type, size)
- If valid: Uploads file, sets success message, redirects to success page
- If invalid: Redisplays form with error messages
- Success page shows filename and "View File" button
Key Concepts Explained
1. form_open_upload() vs form_open()
Use form_open_upload() for file uploads. It automatically adds:
<!-- form_open() -->
<form action="..." method="post">
<!-- form_open_upload() -->
<form action="..." method="post" enctype="multipart/form-data">
That enctype attribute is required for file uploads. Trongate adds it automatically.
2. The POST-Redirect-GET Pattern
Notice, we don't render the success page directly. Instead, when an upload is successful, we immediately direct the user elsewhere:
// ❌ WRONG - causes "resubmit form?" on refresh
if ($result === true) {
$data['filename'] = $file_info['file_name'];
$this->view('upload_success', $data); // Don't do this!
}
// ✅ RIGHT - clean refresh, no duplicate uploads
if ($result === true) {
set_flashdata('File uploaded successfully!');
redirect('simple_uploader/success/' . $file_info['file_name']);
}
POST (upload) → Process → Redirect → GET (success page)
3. Validation Before Upload
In addition, we always validate before touching the file system:
// ❌ WRONG - uploads then validates
$file_info = $this->file->upload($config);
$this->validation->set_rules(...); // Too late!
// ✅ RIGHT - validates then uploads
$this->validation->set_rules(...); // Validate first
if ($this->validation->run() === true) {
$file_info = $this->file->upload($config); // Upload only if valid
}
Try It Right Now
- Create the three files above
- Create the uploads directory
- Visit:
yoursite.com/simple_uploader
- Upload a text file (.txt, .md, .csv, or .log)
- See the success message and view the file
Don't forget: You're welcome to download the code from GitHub.