Amazon S3 PHP Class

This class is a standalone Amazon S3 REST implementation for PHP 5.2.x (using CURL), that supports large file uploads and doesn’t require PEAR.

Download source: (view changelog)

Usage: See the class documentation and example.php in the source distribution.

Known Issues:

  • Files larger than 2GB are not supported on 32 bit systems due to PHP’s signed integer problem
  • SSL is enabled by default and can cause problems with large files. If you don’t need SSL, disable it with S3::$useSSL = false;

More Information:

NOTE ON FOLDERS: Amazon S3 does not support folders.  Clients like S3Fox create specific files that are displayed as folders.  Just use slash paths for your object names (foo/bar.txt) and (foo/) as your prefix when listing contents.

Amazon S3™ is a trademark of Amazon.com, Inc. or its affiliates.

This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

295 Responses to Amazon S3 PHP Class

  1. Thomas Isaksen says:

    Hey Don,

    Just wanted to thank you for this great code. It’s exactly what I need and nothing more. :-)

    Keep up the good work!

  2. Chris says:

    The class seems to be updated with some of the suggestions here. So downloading the latest version will do the job without the need for any modifications. I am glad i came across it,thank you so much.

  3. ABCD says:

    This class does not support using french characters.

    When trying to copy from a folder called “Àbcdefg” I get an invalid signature error
    However, the same action from the folder “Abcdefg” and “abcdefg” work perfectly fine

  4. Matt Robinson says:

    Don, I just wanted to thank you for this. It Just Works™. Perfect!

  5. Lua says:

    Hi,
    I have the same problem of Troy. Here the detail:

    A PHP Error was encountered

    Severity: User Warning

    Message: S3::putObject(): [55] select/poll returned error

    Filename: libraries/S3.php

    Line Number: 410
    A PHP Error was encountered

    This error appears randomly and now more and more often (the class has worked correctly for me for six moths).

    I use ubuntu server 7.04, php 5.2.3 and the last class version. The uploaded files are about 70kb-700kb.

    Any idea to solve my issue?

    Ty in advance!!
    Lua.

  6. This is a great bit of code, thank you. The only slight issue I came across (as mentioned by some other respondents) was that bucket names get cast to lowercase meaning that it can never find an AWS bucket that uses mixed or all upper case.

    But the code is great. Thanks for sharing!

    • Don says:

      This was changed in the master branch… According to the API docs bucket names were never meant to include uppercase characters, but for some reason it was allowed.

  7. Mike says:

    Did anyone get a chance to look into my comment.
    Please help. How to use prefix with getBucket method.
    contents = $s3->getBucket(‘bucketName’, ‘this/folder’);
    Bucket location in S3: /bucketName/this/folder

    Thanks,
    Mike

  8. Mike says:

    Great work thank you.
    Can i get all the folder names inside the bucket and also all the files inside particular folder.
    I have tried to use getBucket() method with prefix option, But could not succeed.
    $contents = $s3->getBucket(‘bucketName’,, ‘this/folder’);

    Please let me know.

    Thanks,
    Mike

  9. Oscar says:

    This is a great class!
    Very useful to me and my requirements, thanks to share it!

  10. John says:

    this is really great script. Thanks webmaster.

  11. greg says:

    A cheap hack for everyone trying to get reduced redundancy to work:

    Insert:
    $rest->setAmzHeader(‘x-amz-storage-class’ , ‘REDUCED_REDUNDANCY’);
    below the
    $rest->setAmzHeader(‘x-amz-acl’, $acl);
    in the bottom of the putObject function

  12. Roman says:

    Hi!

    There’s bug in getBucket() method.
    If 0 is passed to this method as @maxKeys parameter, do while loop will circle until memory_limit or max_execution_time is reached.

    This is how we fix it:
    public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false) {
    if ($maxKeys == 0) return true;

    Cheers!

  13. Richard Soares says:

    Code Igniter / S3.php Library bug FIXED:

    The fix to my previous post on 28th Apr 2011 is as follows:

    Change:
    $s3 = new S3( AMZ_AWS_ACCESS_KEY, AMZ_AWS_SECRET_KEY );
    To:
    $this->s3->S3( AMZ_AWS_ACCESS_KEY, AMZ_AWS_SECRET_KEY );

    Reason:
    When CI Library classes extend tot he core CI_Controller class.

    Hope this saves someone time.

    Richard

  14. Richard Soares says:

    Thoughts on why S3 Keys are not authenticating. Getting this error back from S3: [InvalidAccessKeyId] The AWS Access Key Id you provided does not exist in our records.

    Overview: Added the s3.php class into CodeIgniter Libraries and modified all instance of class name to My_S3. Class seems to be working. When calling any function in teh class I get the above Access Key warning. Sample code below:

    $s3 = new S3( AMZ_AWS_ACCESS_KEY, AMZ_AWS_SECRET_KEY );
    $bucket_list = $this->s3->listBuckets( true );

    Verified the Access Key and Secret Key are working using other tools such as Panic Transmit S3 protocol and SFox for FireFox.

    Using SC Class 0.4.0 – $Id: S3.php 47 2009-07-20 01:25:40Z don.schonknecht $

    Where should I look for the bug?

    Thanks Richard

  15. Jeff Harden says:

    Hi,

    Firstly excellent Class, worked first time, so thankyou very much!

    I am having a issue (that i dont think is due to the class) with intermittent connection problems and was wondering whether anybody experienced this?

    I get the Warning:

    PHP Warning: S3::putObject(): [7] couldn’t connect to host in /libraries/S3/S3.php on line 358

    As said this doesnt happen all the time, it seems to be random, does anyone have any ideas? I would have thought that S3 was highly available so the cant connect to host doesnt really make sense!

    Thanks,

    Jeff

  16. Dave says:

    Hi am am fairly new to PHP and I am trying to generate a temporary autheticated URL for Amazon S3, using your S3 PHP class and the method below suggested by Wilson Mattos, but I keep getting:

    Fatal error: Call to undefined function add_action() in F:\wamp\www\test\S3.php on line 50

    Any clue to what I may be doing wrong? And thank you for your time and effort in developing this.

    <?php
    $S3AWSID=’ACCESS_KEY_ID’;
    $S3AWSSECRET=’SECRET_ACCESS_KEY’;
    require_once ‘S3.php’;
    $s3 = new S3(“$S3AWSID”, “$S3AWSSECRET”);
    ?>

    <?php echo $s3‐>getAuthenticatedURL(“BUCKET”, “FILE”, EXPIRE_TIME); ?>

  17. Michael says:

    Thank you.

  18. jonkraftsmall says:

    Thanks for info

  19. Hans Malkow says:

    Thank your for your really helpful class – it works great!

    @Mind: If you are located in Europe, you should try “s3-external-3.amazonaws.com” instead of “s3.amazonaws.com”

  20. Mind says:

    i get this error today after many month i use backup:

    PHP Warning: S3::listBuckets(): [6] Couldn’t resolve host ‘s3.amazonaws.com’ in S3.php on line 90

    i can’t understand why…can u help me?

  21. Thanks a lot for this.

    However I found that the Content-Type would not be set correctly. I tried various things and couldn’t figure it out then decided to make some changes in the class:

    In your function function putObject I added this line:

    <span class="source-variable">$input['type'] = self::getMimeType_new_from_jim(<span class="source-variable">$uri);

    Just before this line:

    if (!isset(<span class="source-variable">$input['type'])) {

    Then at the bottom just before the final } I added this:

    public static function getMimeType_new_from_jim(<span class="source-variable">$file) {
            static <span class="source-variable">$exts = array(
                'jpg' => 'image/jpeg',
                'gif' => 'image/gif',
                'png' => 'image/png',
                'tif' => 'image/tiff',
                'tiff' => 'image/tiff',
                'ico' => 'image/x-icon',
                'swf' => 'application/x-shockwave-flash',
                'pdf' => 'application/pdf',
                'zip' => 'application/zip',
                'gz' => 'application/x-gzip',
                'tar' => 'application/x-tar',
                'bz' => 'application/x-bzip',
                'bz2' => 'application/x-bzip2',
                'txt' => 'text/plain',
                'asc' => 'text/plain',
                'htm' => 'text/html',
                'html' => 'text/html',
                'css' => 'text/css',
                'js' => 'text/javascript',
                'xml' => 'text/xml',
                'xsl' => 'application/xsl+xml',
                'ogg' => 'application/ogg',
                'mp3' => 'audio/mpeg',
                'wav' => 'audio/x-wav',
                'avi' => 'video/x-msvideo',
                'mpg' => 'video/mpeg',
                'mpeg' => 'video/mpeg',
                'mov' => 'video/quicktime',
                'flv' => 'video/x-flv',
                'php' => 'text/x-php'
            );
            <span class="source-variable">$ext = split("[/\\.]", <span class="source-variable">$file) ; 
            <span class="source-variable">$n = count(<span class="source-variable">$ext)-1; 
            <span class="source-variable">$ext = <span class="source-variable">$ext[<span class="source-variable">$n]; // <span class="source-variable">$ext is now the file extension
            if (isset(<span class="source-variable">$exts[<span class="source-variable">$ext])) {
                return <span class="source-variable">$exts[<span class="source-variable">$ext];
            } else {
                return 'application/octet-stream';
            }
            
        }

    It works well for me. I release the above code to the public domain free for all to use.

  22. Mike says:

    @Stefan:
    To me the original Amazon PHP SDK seems too bloated. And it’s autoloader conflictet with that of my framework. So why use such a beast if there’s a lean class like this?

  23. Stefan says:

    Hi all!

    Im’ new to S3.
    Please let me ask a stupid question.
    This class seems to exist quite a long time now.
    Perhaps it was written at a time when Amazon had no PHP API?

    Why don’t you all use the Amazon PHP API?
    (http://aws.amazon.com/sdkforphp/)

    Is it not as easy to use as this one?

    Thanks for your coments!

  24. Burton Smith says:

    Thank you so much for this class.

    I don’t know how I could have ever fulfilled my client’s expectations for backup to S3 unless I had a pre-written class.

    Much Gratitude!

    …Burton

  25. chylvina says:

    It’s great.Thank you very much!

  26. Rubén Martínez says:

    Sorry, but the site documentation doesn’t explain this clearly, so I hope you can excuse my ignorance.

    I’m testing using S3 as a remote backup for critical files on a PHP application. I’m developing in Wamp (Win XP). When I try to run your example.php sample, I got the [60] error about no certificates.

    I want to use SSL, so I’ve downloaded the cert & key generated by the Amazon control panel (cert-****.pem & pk-****.pem), and then add the instructions to getResponse():

    if (S3::$useSSL) {
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);

    // New lines
    // Certificate & key file in pem format
    curl_setopt($curl, CURLOPT_SSLCERT, S3::$certFile);
    curl_setopt($curl, CURLOPT_SSLKEY, S3::$pkeyFile);
    // End new lines
    }

    but the error persists.

    On the other side, downloading a Certificates bundle from the curl site and adding the next line instead works:

    // CA bundle file
    curl_setopt($curl, CURLOPT_CAINFO, “C:\wamp\www\s3\certs\cacert.pem”);

    I think that the certificate is obtained automatically and verified against a root certificate present in the bundle, so it works. Still, why wasn’t the first option successful?

    Shouldn’t CURLOPT_SSLCERT bean an inmediate aceptance? Or are those certificates mean’t for other things, and the ssl is using the generic amazon certificate for *.s3.amazonaws.com.

    That would explain why it worked like that, and yet, what are the those cert and key for?

  27. Morne says:

    Hi there, how can I bulk upload files in a directory to my s3 bucket?

    Can I just get all file names from the directory and put it in to an array, then use the putObject() to upload?

  28. This class is awesome, use it all the time.

    It would be great if it was updated with the invalidation and default-object features amazon has added lately.

  29. aaron francis says:

    First off, thanks so much for this class. Works like a dream.

    Quick question though, every time I try to use the prefix option on getBucket I get a SignatureDoesNotMatch error.

    $contents = $s3->getBucket(“bucket”) – works
    $contents = $s3->getBucket(“bucket”, “a”); – error

    Warning: S3::getBucket(): [SignatureDoesNotMatch] The request signature we calculated does not match the signature you provided. Check your key and signing method. in /Applications/MAMP/htdocs/assets/classes/S3.class.php on line 126

    I’ve tried urlencoding different things and also sorting headers lexicographically. I just can’t seem to get it down. Any ideas?

  30. vince says:

    I like the profuseness of the comments.

    But,
    it seems that this class doesn’t support bucket names with capital letters, even though S3 will treat two buckets such as ‘SomeBucket’ and ‘somebucket’ as distinct, and will let them coexist as separate entities.

    If a user tries something like $s3->putBucket(‘SomeBucket’);
    a bucket with a name of ‘somebucket’ will created in S3.

    If a user has created a bucket with a name of ‘SomeBucket’ via some other means (like the AWS Management Console), it will be inaccessible with this class.

  31. Don says:

    @Jaka,

    Yes – I’m busy with a rewrite that will. But if you don’t like it, use something else :-)

  32. Jaka says:

    This is really poorly designed.

    All the objects share a single pair of credentials. They don’t behave as you would expect objects to behave at all.

  33. Andris says:

    I found the solution… You have to urlencode() the object’s name

  34. Andris says:

    If ther’s a backslash in the path of an object (not a slash which separates folders) then copyObject fails with ” The request signature we calculated does not match the signature you provided.”. A minor problem, and I’m looking into fixing it, but if anyone has a suggetion… Thanks.

  35. Bruce says:

    When I pass a short string to putObject it takes minutes to complete. The same data passed in a file completes immediately.

    Slow:
    $data = “0123456789\n”;
    $put = $s3->putObject($data, $bucket, $path, S3::ACL_PUBLIC_READ);

    Fast:
    $data = $s3->inputFile(“file.txt”);
    $put = $s3->putObject($data, $bucket, $path, S3::ACL_PUBLIC_READ);

  36. Anoop says:

    Hi,

    I have to transfer my files from amazon s3 to my new sever . My bucket has large number of images and videos. Is it possible to transfer all my files to my new server using php script ?

    Thanks in Advance,

    Anoop

  37. vinod says:

    Hey Bro Thank you very much, among the libraries out there I think yours is the best. Its simple and has nice documentation and example good enough for me…

  38. Just wanted to say thanks for this class and also curious as to if you have plans to update it to manage the recent bucket policy additions to S3. Thanks again.

  39. Heron says:

    @Frank Koehl: The API has not changed very much at all since the last update, with the exception of S3′s recently released RRS feature. If there’s a big demand for it I’ll pester Don to update the code ;)

    The code as it stands is quite stable and easy to use.

  40. Ty Wangsness says:

    I was having a hard time getting this class to let me create buckets in the US West or Asia Pacific regions. The location string for US West is “us-west-1″ and the location string for Asia Pacific is “ap-southeast-1″. Then you have to edit one line in this class due to Amazon being case sensitive:

    Line 213:
    $locationConstraint = $dom->createElement(‘LocationConstraint’, strtoupper($location));

    becomes:

    $locationConstraint = $dom->createElement(‘LocationConstraint’, $location);

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>