Trongate PHP Framework Docs
Introduction
Quick Start
Basic Concepts
Understanding Routing
Intercepting Requests
Module Fundamentals
Database Operations
Templates
Helpers
Form Handling
Form Validation
Working With Files
Image Manipulation
Working With Dates & Times
Language Control
Security
Tips And Best Practices

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:

  1. Display the upload form
  2. Process the upload with validation
  3. Show the success page

Each method does one thing. Clean. Simple. Maintainable.

In a hurry? Head over to GitHub and download the Simple Uploader module:

https://github.com/trongate/Trongate-v2---Simple-Uploader

The code demonstrates basic file uploading concepts in the clearest possible way.

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
<?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:

View File
<!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:

View File
<!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:

PHP
// Run this once in a controller
$this->file->create_directory('uploads', 0755, true);

How It Works (The Flow)

  1. User visits yoursite.com/simple_uploader (or yoursite.com/simple_uploader/index)
  2. Form displays with file selection input
  3. User selects file and clicks "Upload File"
  4. Browser POSTs to yoursite.com/simple_uploader/submit_upload
  5. Trongate validates the file (required, type, size)
  6. If valid: Uploads file, sets success message, redirects to success page
  7. If invalid: Redisplays form with error messages
  8. Success page shows filename and "View File" button

Key Concepts Explained

1. form_open_upload() vs form_open()

Use for file uploads. It automatically adds:

HTML
<!-- 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:

PHP
// ❌ 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) → ProcessRedirectGET (success page)

3. Validation Before Upload

In addition, we always validate before touching the file system:

PHP
// ❌ 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

  1. Create the three files above
  2. Create the uploads directory
  3. Visit: yoursite.com/simple_uploader
  4. Upload a text file (.txt, .md, .csv, or .log)
  5. See the success message and view the file

Don't forget: You're welcome to download the code from GitHub.

We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.

Share your thoughts in the Documentation Feedback.

Leave Feedback About This Page