Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Working with the Play Framework
      • Working with Spring Boot
      • Java Advanced Topics
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • PHP
  • Uploading Files to S3 in PHP

Uploading Files to S3 in PHP

English — 日本語に切り替える

Last updated December 02, 2022

Table of Contents

  • S3 setup
  • Application setup
  • Using the AWS SDK for PHP
  • Setting application config vars
  • Handling file uploads

If your application needs to receive files uploaded by users, you need to make sure these uploads are stored in a central and durable location.

With Heroku’s ephemeral filesystem, any information written to a dyno’s filesystem will be lost when the dyno is restarted. Instead, Heroku recommends backing services. For file and media storage, Amazon’s Simple Storage Service (S3) is a great solution.

This article demonstrates how to set up a PHP application to use S3 for storing file uploads.

S3 setup

To follow this example, we’re assuming that you already have an Amazon Web Services (AWS) account set up, and you’re in possession of an AWS Access Key pair (access key ID and secret access key), see How do I Get Security Credentials? in the AWS documentation.

You’ll also need to create a new S3 bucket using your account, or re-use an existing one.

Read our Using AWS S3 to Store Static Assets and File Uploads guide for more information; it contains detailed background knowledge, step-by-step instructions for getting started with S3, and useful tips and tricks.

Application setup

If you haven’t created a Heroku application and Git repository yet, do so first:

$ mkdir heroku-s3-example
$ cd heroku-s3-example
$ git init
$ heroku create

Using the AWS SDK for PHP

The easiest way to install the AWS SDK for PHP is using Composer. The composer require command is the easiest way (alternatively, you can add the aws/aws-sdk-php package to composer.json by hand):

$ composer require aws/aws-sdk-php:~3.0

If you haven’t already done so, now is a good time to add the vendor/ directory to your .gitignore; you only want your composer.json and composer.lock, but not the vendor/ directory, under version control:

$ echo "vendor" >> .gitignore

Now you can commit everything:

$ git add composer.* .gitignore
$ git commit -m "use aws/aws-sdk-php"

Setting application config vars

Hard-coding database connection information, security credentials, or other runtime settings is not a good idea. Instead, you should store such information in an application’s environment and read it from there at runtime.

Any config var you set on your Heroku application will be available at runtime using getenv() or in $_ENV/$_SERVER. We will use this mechanism to dynamically read the AWS security keys (key ID and secret key) and the S3 bucket name in our code; all you need to do is set these three bits information (the code below uses “aaa”, “bbb” and “ccc” placeholders) as config vars using the Heroku CLI:

$ heroku config:set AWS_ACCESS_KEY_ID=aaa AWS_SECRET_ACCESS_KEY=bbb S3_BUCKET=ccc

All that’s missing now is some code to handle a file upload!

Handling file uploads

Next, we’ll build a very simple script that accepts a file to upload in the browser, and stores it on S3 under the same name it had on the client’s computer.

This is a very simple example without proper validation and using verbatim file names from the client. Make sure you always validate the file’s name and contents e.g. using fileinfo, and generate a custom filename or use another method of ensuring you’re not overwriting an existing file. You may also wish to put file type and size limits in place.

Put the following into a file named index.php:

<?php
require('vendor/autoload.php');
// this will simply read AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from env vars
$s3 = new Aws\S3\S3Client([
    'version'  => '2006-03-01',
    'region'   => 'us-east-1',
]);
$bucket = getenv('S3_BUCKET')?: die('No "S3_BUCKET" config var in found in env!');
?>
<html>
    <head><meta charset="UTF-8"></head>
    <body>
        <h1>S3 upload example</h1>
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['userfile']) && $_FILES['userfile']['error'] == UPLOAD_ERR_OK && is_uploaded_file($_FILES['userfile']['tmp_name'])) {
    // FIXME: you should add more of your own validation here, e.g. using ext/fileinfo
    try {
        // FIXME: you should not use 'name' for the upload, since that's the original filename from the user's computer - generate a random filename that you then store in your database, or similar
        $upload = $s3->upload($bucket, $_FILES['userfile']['name'], fopen($_FILES['userfile']['tmp_name'], 'rb'), 'public-read');
?>
        <p>Upload <a href="<?=htmlspecialchars($upload->get('ObjectURL'))?>">successful</a> :)</p>
<?php } catch(Exception $e) { ?>
        <p>Upload error :(</p>
<?php } } ?>
        <h2>Upload a file</h2>
        <form enctype="multipart/form-data" action="<?=$_SERVER['PHP_SELF']?>" method="POST">
            <input name="userfile" type="file"><input type="submit" value="Upload">
        </form>
    </body>
</html>

The example sets the ACL for the uploaded file so it’s publicly readable. If you want different permissions, adjust the example accordingly. You can also use a bucket policy to define what the default permissions for uploaded files in a bucket should be.

You can now add, commit and push this to Heroku:

$ git add index.php
$ git commit -m "file upload test form"
$ git push heroku master

After the deploy has finished, you can run heroku open or manually point your browser to your application to test it. Select a file from your computer (e.g. an image or text file) and upload it. If all went well, a success message will appear with a link to the uploaded file.

Keep reading

  • PHP

Feedback

Log in to submit feedback.

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences