What is AWS S3 and Why Integrate It with CodeIgniter 4?

Amazon Simple Storage Service (S3) is a highly durable, scalable object storage service used by millions of websites. Benefits of CodeIgniter 4 + AWS S3 integration include:

  • Unlimited scalable storage without server disk limits
  • 99.999999999% (11 9's) durability
  • Built-in security features (encryption, IAM policies)
  • Lower costs for large files vs local hosting
  • Easy CDN integration (CloudFront) for fast global delivery

Local file storage becomes a bottleneck as your app grows – S3 solves this permanently.



How to Upload Files to AWS S3 Bucket in CodeIgniter 4 – Complete Tutorial

Table Of Content

1 Prerequisites

  • PHP 8.2+
  • Composer
  • Active AWS account with S3 bucket and IAM user (Access Key + Secret)

2 How to Set Up AWS S3 File Upload in CodeIgniter 4 (Step-by-Step)

In modern web apps, storing user-uploaded files locally limits scalability and security. CodeIgniter 4 AWS S3 integration solves this by using Amazon's reliable cloud storage. This step-by-step tutorial shows how to upload, list, download, and delete files from an S3 bucket using the official AWS SDK for PHP.

3 Create / Install a Codeigniter 4 Project

3.1 Install Codeigniter 4 Project

First, make sure your computer has a composer.
Use the following command to install new Codeigniter Project.

composer create-project codeigniter4/appstarter ci-4-amazon-s3-app

Then, navigate to your project directory:

cd ci-4-amazon-s3-app

3.2 Configure Environment (.env)

When we install CodeIgniter 4, we will have env file at root. To use the environment variables, we need to rename env to .env

Also we can do this in command Line.

Open project in Command Line

sudo cp env .env

Above command will create a copy of env file to .env file. Now we are ready to set environment variables.

Configure Development Mode
CodeIgniter starts up in production mode by default. You need to make it in development mode to debug or check any error if you are working with application.

Open .env file from root.

# CI_ENVIRONMENT = production
CI_ENVIRONMENT = development


Now application is in development mode.

4 Create / Login into AWS Account

You need to create or Login into AWS account
After Sign into the account, In the top bar and Search for the S3 service and go to the S3 Management Console.

In S3 Management Console create a New Bucket to store files.

Get AWS Access Key ID and AWS Secret Access Key:
Search "IAM Console" and go to the IAM Console.

From the left navigation menu, select Users under the Access management section.
Create a user with AmazonS3FullAccess permission.

Once User Created Succefully, the Access Key ID and Secret Access Key will be generated.

5 Install AWS SDK for PHP

First, make sure your computer has a composer.
Use the following command to install PHP AWS SDK.

composer require aws/aws-sdk-php

6 Configure AWS Credentials in .env file

In the .env file, AWS configuration variables are defined.
Add these to your .env file (replace with your actual values):

AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_REGION=your-region  # e.g., us-east-1
AWS_BUCKET=your-bucket-name
# Optional: AWS_ENDPOINT=https://s3.amazonaws.com (for custom S3-compatible services)

7 Create S3 Service Class

This class interacts with S3 to upload images to S3 bucket Codeigniter 4. It handles uploading, downloading, and managing files within your application. app/Services/S3Service.php

<?php
namespace App\Services;

use Aws\S3\S3Client;
use Aws\Exception\AwsException;

class S3Service
{
    protected $s3;
    protected $bucket;

    public function __construct()
    {
        $this->s3 = new S3Client([
            'region'  => getenv('AWS_REGION'),
            'version' => 'latest',
            'credentials' => [
                'key'    => getenv('AWS_ACCESS_KEY_ID'),
                'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
            ],
            // Uncomment if using a custom endpoint
            // 'endpoint' => getenv('AWS_ENDPOINT'),
        ]);

        $this->bucket = getenv('AWS_BUCKET');
    }

    public function uploadFile($filePath, $key)
    {
        try {
            $result = $this->s3->putObject([
                'Bucket'     => $this->bucket,
                'Key'        => $key,
                'SourceFile' => $filePath,
                'ACL'        => 'private',  // Change to 'public-read' if files should be public
            ]);
            return $result->get('ObjectURL');
        } catch (AwsException $e) {
            return $e->getMessage();
        }
    }

    public function getFileUrl($key)
    {
        return $this->s3->getObjectUrl($this->bucket, $key);
    }

    public function listFiles()
    {
        $objects = $this->s3->getIterator('ListObjects', [
            'Bucket' => $this->bucket,
            'Prefix' => ''
        ]);
        return $objects;
    }

    public function deleteFile($key)
    {
        try {
            $this->s3->deleteObject([
                'Bucket' => $this->bucket,
                'Key'    => $key,
            ]);
            return true;
        } catch (AwsException $e) {
            return $e->getMessage();
        }
    }
}
?>

8 Create the Controller

This controller will manage the upload and listing of files using Codeigniter AWS S3 integration library.
Use the following artisan command to Create Controller.

php spark make:controller S3Controller

app/Controllers/S3Controller.php

<?php
namespace App\Controllers;

use App\Controllers\BaseController;
use App\Services\S3Service;

class S3Controller extends BaseController
{
    public function index()
    {
        return view('upload_form');
    }

    public function upload()
    {
        $file = $this->request->getFile('file');

        if ($file->isValid() && !$file->hasMoved()) {
            $filePath = $file->getTempName();
            $fileName = $file->getName();

            $s3Service = new S3Service();
            $fileUrl = $s3Service->uploadFile($filePath, $fileName);

            if (strpos($fileUrl, 'http') === 0) {  // Check if upload succeeded (returns URL on success)
                return redirect()->to('list')->with('message', 'File Uploaded Successfully!');
            } else {
                return redirect()->to('list')->with('message', 'Upload Failed: ' . $fileUrl);
            }
        }

        return redirect()->to('list')->with('message', 'Invalid file');
    }

    public function list()
    {
        $s3Service = new S3Service();
        $objects = $s3Service->listFiles();
        $data['objects'] = $objects;
        return view('file_list', $data);
    }

    public function download($fileName)
    {
        $s3Service = new S3Service();
        $fileUrl = $s3Service->getFileUrl($fileName);
        return redirect()->to($fileUrl);
    }

    public function delete($fileName)
    {
        $s3Service = new S3Service();
        $result = $s3Service->deleteFile($fileName);

        if ($result === true) {
            return $this->response->setJSON(['message' => 'File deleted successfully']);
        }

        return $this->response->setStatusCode(400)->setJSON(['error' => $result]);
    }
}
?>

Improvements Added: Basic error checking in upload() to handle failures. You can add file validation (e.g., size/type) like this in upload() before processing:


$validationRule = [
    'file' => 'uploaded[file]|max_size[file,10240]|ext_in[file,jpg,png,pdf]',
];
if (!$this->validate($validationRule)) {
    return redirect()->to('list')->with('message', $this->validator->getErrors()['file']);
}

9 Create Index View File

Create View "index.php" File to Show Form app/Views/upload_form.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Upload to S3</title>
    <!-- Add Bootstrap or CSS for better UX -->
</head>
<body>
    <h2>Upload File to AWS S3</h2>
    <?php if (session()->getFlashdata('message')): ?>
        <p style="color:green;"><?= session()->getFlashdata('message') ?></p>
    <?php endif; ?>
    <form method="post" action="<?= base_url('upload') ?>" enctype="multipart/form-data">
        <input type="file" name="file" required>
        <button type="submit">Upload</button>
    </form>
    <p><a href="<?= base_url('list') ?>">View Uploaded Files</a></p>
</body>
</html>

10 Create List View File

Create View "list.php" File to Show Form app/Views/file_list.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>S3 File List</title>
    <!-- Add Bootstrap or CSS for better UX -->
</head>
<body>
    <h2>Files in AWS S3 Bucket</h2>
    <?php if (session()->getFlashdata('message')): ?>
        <p style="color:green;"><?= session()->getFlashdata('message') ?></p>
    <?php endif; ?>
    <table border="1" cellpadding="5" cellspacing="0">
        <thead>
            <tr>
                <th>Filename</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
        <?php if (!empty($objects)): ?>
            <?php foreach ($objects as $object): ?>
                <?php if (isset($object['Key'])): ?>
                    <tr>
                        <td><?= esc($object['Key']) ?></td>
                        <td>
                            <a href="<?= base_url('download/' . rawurlencode($object['Key'])) ?>">Download</a>
                            <form action="<?= base_url('delete/' . rawurlencode($object['Key'])) ?>" method="post" style="display:inline;">
                                <?= csrf_field() ?>
                                <button type="submit" onclick="return confirm('Are you sure you want to delete this file?');">Delete</button>
                            </form>
                        </td>
                    </tr>
                <?php endif; ?>
            <?php endforeach; ?>
        <?php else: ?>
            <tr><td colspan="2">No files found.</td></tr>
        <?php endif; ?>
        </tbody>
    </table>
    <p><a href="<?= base_url() ?>">Upload Another File</a></p>
</body>
</html>

11 Define a Route

Define routes for your Codeigniter AWS S3 integration in
app/Config/Routes.php


use CodeIgniter\Router\RouteCollection;
$routes->get('/', 'Home::index');
$routes->get('/', 'S3Controller::index');
$routes->get('list', 'S3Controller::list');
$routes->post('upload', 'S3Controller::upload');
$routes->get('download/(:any)', 'S3Controller::download/$1');
$routes->delete('delete/(:any)', 'S3Controller::delete/$1');

12 Folder Structure

13 Run Web Server to Test the App

Use the following command to Test the App.

php spark serve

  • Visit http://localhost:8080/ for the upload form.
  • After upload, redirect to /list to see files.
  • Download redirects to the S3 URL (for private files, this generates a temporary signed URL).
  • Delete uses a POST form for security.

Best Practices & Troubleshooting

  • Security: Use presigned URLs for private downloads (modify getFileUrl() to use createPresignedRequest() with expiration). Block public access on your bucket.
  • Large Files: For files >100MB, implement multipart uploads in S3Service.
  • Costs: Monitor S3 storage and data transfer fees.
  • Common Issues:
    • "Signature mismatch": Verify AWS region and credentials.
    • "Permission denied": Check IAM policy and bucket permissions.
    • "No such key": Ensure file keys match exactly.
  • Testing: Upload small files first. Use AWS Console to verify bucket contents.

14 Conclusion

With this setup, your CodeIgniter 4 app gains scalable, secure file storage. Ready to implement? Fork the code on GitHub [add link if available] or drop questions below!
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

You need PHP 8.2 or higher, Composer installed, and an AWS account.

Run `composer create-project codeigniter4/appstarter ci-4-amazon-s3-app`, then `cd ci-4-amazon-s3-app`.

Copy `env` to `.env`, then set `CI_ENVIRONMENT = development` in the `.env` file.

Log into AWS Console, create an S3 bucket. Then in IAM, create a user, attach `AmazonS3FullAccess` policy, and generate Access Key ID and Secret Access Key.

Run `composer require aws/aws-sdk-php`.

Add these to your `.env` file: `AWS_ACCESS_KEY_ID=your-key`, `AWS_SECRET_ACCESS_KEY=your-secret`, `AWS_ENDPOINT=your-endpoint` (optional), `AWS_REGION=your-region`, `AWS_BUCKET=your-bucket-name`.

Create `app/Services/S3Service.php` with an S3Client instance using credentials from env, and methods for uploadFile, getFileUrl, listFiles, and deleteFile.

Run `php spark make:controller UploadController`, then implement index (for upload form), upload (handle file and use S3Service), list (list files), download (redirect to object URL), and delete methods.

Get the file with `$this->request->getFile('file')`, validate it, then use S3Service to upload with `uploadFile($filePath, $fileName)`.

In the list method, use `$s3Service->listFiles()` to get objects via ListObjects, then pass to the view and display file names with download/delete links.

Use `$s3Service->getObjectUrl($bucket, $key)` to generate the URL and redirect to it (files are private by default with ACL 'private').

Verify AWS credentials, region, bucket name in `.env`. Ensure the IAM user has proper S3 permissions (e.g., s3:PutObject, s3:GetObject, s3:ListBucket).

Change 'ACL' => 'private' to 'ACL' => 'public-read' in the putObject call in S3Service.

Start the server with `php spark serve`, visit the root route (e.g., `/`) for upload form, and `/list` to view files.