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 Image Uploading

Let's build an image uploader. Not a theoretical example. Not a "hello world" toy. A real image uploader that resizes images and generates thumbnails automatically, using Trongate's Image 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 with image preview

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

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

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

The code demonstrates basic image uploading concepts with automatic resizing and thumbnail generation.

The Complete Controller

Create a simple_image_uploader directory with a controller file (name 'Simple_image_uploader.php') at:

modules/simple_image_uploader/Simple_image_uploader.php

Here's the code for the controller file:

PHP
<?php
class Simple_image_uploader extends Trongate {

    /**
     * 1. Display the upload form
     */
    function index() {
        $data['view_module'] = 'simple_image_uploader';
        $data['view_file'] = 'upload_form';
        $this->view('upload_form', $data);
    }

    /**
     * 2. Process the image upload
     */
    function submit_upload() {
        // Validate first
        $this->validation->set_rules(
            'userfile',
            'Image',
            'required|max_size[5000]|max_width[3000]|max_height[3000]'
        );

        $result = $this->validation->run();

        if ($result === true) {
            // Configure image upload with automatic processing
            $config = [
                'destination' => 'uploads',
                'upload_to_module' => true,
                'max_width' => 800,
                'max_height' => 800,
                'thumbnail_dir' => 'uploads/thumbs',
                'thumbnail_max_width' => 150,
                'thumbnail_max_height' => 150,
                'make_rand_name' => false
            ];
            
            $file_info = $this->image->upload($config);
            
            set_flashdata('Image uploaded successfully!');
            redirect('simple_image_uploader/success/' . $file_info['file_name']);
                
        } else {
            $this->index();
        }
    }

    /**
     * 3. Display the success page
     */
    function success() {
        $data['filename'] = segment(3);
        $data['view_module'] = 'simple_image_uploader';
        $data['view_file'] = 'upload_success';
        $this->view('upload_success', $data);
    }

}
?>

That's the entire controller. Three methods. Zero complexity. Production-ready pattern.

The Image module automatically processes the first file uploaded in your form, regardless of its input field name. This makes it consistent with the File 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 a view file named 'upload_form.php' at the following location:

modules/simple_image_uploader/views/upload_form.php

Here's the code for the view file:

View File
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="simple_image_uploader_module/css/simple_image_uploader.css">
    <title>Upload Image</title>
</head>
<body>
    <h1>Upload Image</h1>
    
    <?= validation_errors() ?>

    <div class="info">
        <p><strong>Allowed file types:</strong> JPEG, PNG, GIF, WEBP</p>
        <p><strong>Maximum file size:</strong> 5 MB</p>
        <p><strong>Maximum dimensions:</strong> 3000 x 3000 pixels</p>
        <p><strong>Note:</strong> Images larger than 800x800px will be automatically resized. A 150x150px thumbnail will be generated.</p>
    </div>

    <?php
    echo form_open_upload('simple_image_uploader/submit_upload');
    echo form_label('Select Image:', ['for' => 'userfile']);

    $select_attr = [
        'id' => 'userfile',
        'accept' => 'image/jpeg,image/png,image/gif,image/webp'
    ];

    echo form_file_select('userfile', $select_attr);
    echo form_submit('submit', 'Upload Image');
    echo form_close();
    ?>
</body>
</html>

About the CSS file: The two view files mentioned on this page reference simple_image_uploader.css, which should be located at:

modules/simple_image_uploader/css/simple_image_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 Image Uploader Module

The Success Page View

Create a file named 'upload_success.php' and have it located at:

modules/simple_image_uploader/views/upload_success.php
View File
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="simple_image_uploader_module/css/simple_image_uploader.css">
    <title>Upload Complete</title>
</head>
<body>
    <h1>Upload Complete!</h1>
    <?= flashdata() ?>

    <?php if (!empty($filename)) { ?>
        <div class="image-info">
            <h2>Your Uploaded Image</h2>
            <p><strong>File Name:</strong> <code><?= out($filename) ?></code></p>
            
            <div class="image-preview">
                <h3>Full Size (max 800x800px)</h3>
                <img src="<?= BASE_URL ?>simple_image_uploader_module/uploads/<?= $filename ?>" 
                     alt="Uploaded image"
                     class="uploaded-image">
            </div>

            <div class="thumbnail-preview">
                <h3>Thumbnail (150x150px)</h3>
                <img src="<?= BASE_URL ?>simple_image_uploader_module/uploads/thumbs/<?= $filename ?>" 
                     alt="Thumbnail"
                     class="thumbnail-image">
            </div>

            <div class="actions">
                <?= anchor('simple_image_uploader', 'Upload Another Image', ['class' => 'button']) ?>
            </div>
        </div>
    <?php } else { ?>
        <div class="alert">
            <p>No image information available.</p>
            <p><?= anchor('simple_image_uploader', 'Upload an Image', ['class' => 'button']) ?></p>
        </div>
    <?php } ?>
</body>
</html>

Create the Upload Directories

Before uploading, create the directories where images and thumbnails will be stored:

# From your application root:
mkdir -p modules/simple_image_uploader/uploads/thumbs
chmod 755 modules/simple_image_uploader/uploads
chmod 755 modules/simple_image_uploader/uploads/thumbs

Or create them via PHP if you prefer:

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

How It Works (The Flow)

  1. User visits yoursite.com/simple_image_uploader
  2. Form displays with image file selection input
  3. User selects image and clicks "Upload Image"
  4. Browser POSTs to yoursite.com/simple_image_uploader/submit_upload
  5. Trongate validates the image (required, type, size, dimensions)
  6. If valid:
    • Uploads image to modules/simple_image_uploader/uploads/
    • Automatically resizes if larger than 800x800px
    • Generates 150x150px thumbnail in uploads/thumbs/
    • Sets success message and redirects
  7. If invalid: Redisplays form with error messages
  8. Success page shows both full-size image and thumbnail

Key Concepts Explained

1. form_open_upload() vs form_open()

Use for image 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 redirect 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('Image uploaded successfully!');
    redirect('simple_image_uploader/success/' . $file_info['file_name']);
}

POST (upload) → ProcessRedirectGET (success page)

3. Validation Before Upload

We always validate before uploading:

PHP
// ❌ WRONG - uploads then validates
$file_info = $this->image->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->image->upload($config); // Upload only if valid
}

4. What Happens Automatically

When you call $this->image->upload($config), the Image module automatically:

  • Validates MIME types (JPEG, PNG, GIF, WEBP only)
  • Checks file signatures to prevent spoofed uploads
  • Scans for embedded malicious content
  • Resizes images that exceed max_width or max_height
  • Maintains aspect ratios during resizing
  • Generates thumbnails with specified dimensions
  • Prevents filename conflicts (car.jpg → car_2.jpg → car_3.jpg)

All of this happens with zero configuration beyond the simple config array.

Try It Right Now

  1. Create the three files above
  2. Create the upload directories (uploads and uploads/thumbs)
  3. Visit: yoursite.com/simple_image_uploader
  4. Upload an image (JPEG, PNG, GIF, or WEBP)
  5. See the resized image and thumbnail on the success page

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