Using PHP, Post an Image to Amazon S3 and save several sizes of that image
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

I know Amazon has a PHP dev kit. Just haven't got the time or skills.

Step 1 Simple web page to Upload an image (could be as large as 25mb) from the browser to an Amazon S3 bucket. Include some indicator to show progress

Step 2 Present a Success/Fail message

Step 3 Create several versions of that image with different sizes on the S3 bucket. File name based on some variables I can set. see examples below

More details

I want to be able to set the naming convention on the new images and the size options in pixels. E.g.

$filename = "image1";

$imagewidth[0]=800;
$imageheight[0]=400;
$image_suffix[0]="_800x400"

$imagewidth[1]=400;
$imageheight[1]=200;
$image_suffix[1]="_400x200"

$imagewidth[2]=150;
$imageheight[2]=75;
$image_suffix[2]="_150x75"

creates an images named "image1_800x400.jpg" and "image1_400x200.jpg" and "image1_150x75.jpg" respectively

The image would fit the aspect ratio and cropped if too wide or tall. I don't want different scaling in the X and Y. So an image 800x600 uploaded would have the bottom 200px chopped off on the first image. An image uploaded 1000x600 would have the right 200 pixels cropped on the first image.

Needs to work on current desktop browsers including mobile (Chrome on Android and Safari on iOS)

Will tip for extras

Just to be sure, you have your own PHP server that will upload the generated images in your amazon S3 account ?
kerncy 5 months ago
yes I have my own PHP server, and an Amazon S3 account.
passerby 5 months ago
hi, the images, should be edited locally before uploads right? and what if the original image has 600x600, and you want select 800x800, then what should happens?
Houcem B. A. Chlegou 5 months ago
No I want to upload an image and have the server resize them. If they are wrong size then stretch/scale them..if they are different aspect ratio.. crop the leftover width or height off . There are some libraries that do it like https://www.verot.net/php_class_upload_samples.htm . If that is part of the solution I am OK with that.
passerby 5 months ago
when locally, i mean (on your server) just before upload. not using an amazon online product or something else. so actions will be: 1) select image. 2) create sized instances (through PHP ** this what i'm talking about**) 3) upload these instances to amazon s3
Houcem B. A. Chlegou 5 months ago
yes the link you passed, is part of solution, (2)
Houcem B. A. Chlegou 5 months ago
Oh yes, local on the server. Your flow looks appropriate. Thanks for clarifying.
passerby 5 months ago
if you could email me on my email, we can maybe talk about it. nicolastsue@gmail.com
Houcem B. A. Chlegou 5 months ago
awarded to 5osxcwbf

Crowdsource coding tasks.

1 Solution

Winning solution

Had some other stuff to take care of first, sorry for the delay.
Here you go;

<?php  
//__halt_compiler();


/* 
You sadly cannot set upload_max_filesize and post_max_size within a php script using ini_set(), it can be changed only via .conf or .ini files.

Before trying this script, find your php.ini with bash command; 
php --ini

Change these variables: 

upload_max_filesize 32M
post_max_size 64M
max_execution_time 300

(Don't forget to restart apache or reboot your server)


If you are on a shared host running apache, change the php.ini values using a .htcaccess file 
https://davidwalsh.name/php-values-htaccess

*/ 

//function that uploads an image based on filename to your s3 bucket
function upload_image_to_s3($filename){

    //Grab this class and place it in a file called S3.php in the same directory
    //  https://github.com/tpyo/amazon-s3-php-class/blob/master/S3.php
    if (!class_exists('S3')) require_once 'S3.php';

    //Some  bullshit to prevent php from throwing notices related to the s3 class 
    date_default_timezone_set('America/Los_Angeles');
    defined('CURL_SSLVERSION_TLSv1')   || define('CURL_SSLVERSION_TLSv1', 1);

    // AWS access info
    if (!defined('awsAccessKey')) define('awsAccessKey', 'xxxxxxx');
    if (!defined('awsSecretKey')) define('awsSecretKey', 'xxxxxxx');

    $s3 = new S3(awsAccessKey, awsSecretKey); 

    //change name of your S3 bucket
    $bucketName = "my_bucket";

    //Change "bountify" to the name of folder for where you want your images 
    $uploadName = "bountify/".$filename;

    //Determining content type based on filenames, its a quick hack but mostly accurate 
    $type = strtolower(substr(strrchr($filename,"."),1));
    if($type == 'jpeg') $type = 'jpg';
    if($type == 'JPEG') $type = 'jpg';
    if($type == 'JPG') $type = 'jpg';
    if($type == 'GIF') $type = 'gif';
    if($type == 'BMP') $type = 'bmp';
    if($type == 'PNG') $type = 'png';
    switch($type){
      case 'bmp': $ContentType = "image/bmp"; break;
      case 'gif':  $ContentType = "image/gif"; break;
      case 'jpg':  $ContentType = "image/jpg"; break;
      case 'png':  $ContentType = "image/png"; break;
      default : $ContentType = "image/jpeg";
    } 
    //upload; 
    $s3->putObject(file_get_contents($filename), $bucketName, $uploadName, S3::ACL_PUBLIC_READ, array(), array('Content-Type' =>  $ContentType ));
}

// stolen from; http://php.net/manual/en/function.imagecopyresampled.php#104028
function image_resize($src, $dst, $width, $height, $crop=0){
   if(!list($w, $h) = getimagesize($src)) return "Unsupported picture type!";

   $type = strtolower(substr(strrchr($src,"."),1));
   if($type == 'jpeg') $type = 'jpg';
   switch($type){
     case 'bmp': $img = imagecreatefromwbmp($src); break;
     case 'gif': $img = imagecreatefromgif($src); break;
     case 'jpg': $img = imagecreatefromjpeg($src); break;
     case 'png': $img = imagecreatefrompng($src); break;
     default : return "Unsupported picture type!";
   }

   // resize
   if($crop){
     if($w < $width or $h < $height) return "Picture is too small!";
     $ratio = max($width/$w, $height/$h);
     $h = $height / $ratio;
     $x = ($w - $width / $ratio) / 2;
     $w = $width / $ratio;
   }
   else{
     if($w < $width and $h < $height) return "Picture is too small!";
     $ratio = min($width/$w, $height/$h);
     $width = $w * $ratio;
     $height = $h * $ratio;
     $x = 0;
   }

   $new = imagecreatetruecolor($width, $height);

   // preserve transparency
   if($type == "gif" or $type == "png"){
     imagecolortransparent($new, imagecolorallocatealpha($new, 0, 0, 0, 127));
     imagealphablending($new, false);
     imagesavealpha($new, true);
   }

   imagecopyresampled($new, $img, 0, 0, $x, 0, $width, $height, $w, $h);

   switch($type){
     case 'bmp': imagewbmp($new, $dst); break;
     case 'gif': imagegif($new, $dst); break;
     case 'jpg': imagejpeg($new, $dst); break;
     case 'png': imagepng($new, $dst); break;
   }
   return true;
 }

 ?>

 <?php
 $debug = false;

 $dimentions = array(
     array(
         "imagewidth"  => 800, 
         "imageheight" => 400, 
         "image_suffix" => "_800x400"
     ),
     array(
         "imagewidth"  => 400, 
         "imageheight" => 200, 
         "image_suffix" => "_400x200"
     ),
     array(
         "imagewidth"  => 150, 
         "imageheight" => 75, 
         "image_suffix" => "_150x75"
     )
 ); 


 if(!empty ($_FILES)){   
     $filename = md5(time());
     //change to full path of your upload directory;
     $uploaddir = '/Users/root/desktop/bountify/';
     /* start fix */
     //removed this line, it only works in php versions newer than 5.4.0: 
     //$original_extension = explode(".",basename($_FILES['myfile']['name']))[1];
     //added these two lines
     $parts = explode(".",basename($_FILES['myfile']['name']));
     $original_extension = $parts[1];
     /* end fix */
     $uploadfile = $uploaddir . $filename.".".$original_extension;

     echo '<pre>';
     if (move_uploaded_file($_FILES['myfile']['tmp_name'], $uploadfile)){
         echo "File is valid, and was successfully uploaded.</br>";

        if($debug)
            "original_file:".$filename.".".$original_extension."<br/>";

         foreach( $dimentions as  $dimention){
             $resized_file = $filename.$dimention["image_suffix"].".".$original_extension;

             if($debug)
                 echo "resize_dimentions:". $dimention["imagewidth"] ." x " . $dimention["imageheight"]. " x ". $resized_file."</br>";

             if (true !== ($pic_error = @image_resize($filename.".".$original_extension, $resized_file, $dimention["imagewidth"], $dimention["imageheight"], 1))) {
                  //incase the image is too small for cropping, don't crop;
                  if($debug) 
                    echo "picture_resize_error:". $pic_error."<br>";

                  @image_resize($filename.".".$original_extension, $resized_file, $dimention["imagewidth"], $dimention["imageheight"], 0);
             }  

             upload_image_to_s3($resized_file);
             unlink($resized_file);


         } 
        unlink($filename.".".$original_extension);
     }

     if($debug) var_dump($_FILES); 

     print "</pre>";
     exit();
} 
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Untitled Document</title>

         <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script> 
         <script src="http://malsup.github.io/jquery.form.js"></script> 

    </head> 
    <body>
        <!-- change index.php  to the name/location of this file-->
        <form action="index.php" method="post" enctype="multipart/form-data">
            <input type="file" name="myfile"><br>
            <input type="submit" value="Upload File to Server">
        </form>

        <div class="progress">
            <div class="bar"></div >
            <div class="percent">0%</div >
        </div>

        <div id="status"></div>
        <script>
            $(function() {

                var bar = $('.bar');
                var percent = $('.percent');
                var status = $('#status');

                $('form').ajaxForm({
                    beforeSend: function() {
                        status.empty();
                        var percentVal = '0%';
                        bar.width(percentVal);
                        percent.html(percentVal);
                    },
                    uploadProgress: function(event, position, total, percentComplete) {
                        var percentVal = percentComplete + '%';
                        bar.width(percentVal);
                        percent.html(percentVal);
                    },
                    complete: function(xhr) {
                        status.html(xhr.responseText);
                    }
                });
            }); 
        </script>

    </body>
</html>

Folder permission checker;

<?php

$uploaddir = '/var/www/testimages/';

if (is_writable($filename)) {
    echo 'The folder is writable';
} else {
    echo 'The folder is not writable';
}

/*

Run this php script, If it said not writable, execute this bash  command; 
sudo chmod 777 /var/www/testimages/

Still not writable? try this bash command before running this php script again
sudo chown apache:apache /var/www/testimages/

Still not writable? try this bash command before running this php script again
sudo chown -R www-data:www-data /var/www/testimages/

These commands are based on;
http://stackoverflow.com/questions/13723174/php-warning-move-uploaded-file-unable-to-move
http://stackoverflow.com/questions/5023181/php-move-uploaded-file-unable-to-move
*/
?>

New permission checker, this time for the temporary files directory;

<?php
/*
#create folder tmp in /var/www/
cd /var/www/; mkdir tmp

#find your php.ini
php --ini

#change this variable in your php.ini
upload_tmp_dir = /var/www/tmp/
*/

echo "user:".exec('whoami')."<br/>\n";

$uploaddir = '/var/www/tmp/';

if (is_writable($filename)) {
    echo 'The file is writable';
} else {
    echo 'The file is not writable';
}


/*

Run this script, If not writable execute this command; 
sudo chmod 777 /var/www/tmp/

Still not writable?
check output of the php whoami command, use that user;
sudo chown -R [user]:[user] /var/www/tmp/

Still not writable? try this command before again running this php script
sudo chown apache:apache /var/www/tmp/

Still not writable? try this command before again running this php script
sudo chown -R www-data:www-data /var/www/tmp/


These commands are based on;
http://stackoverflow.com/questions/8103860/move-uploaded-file-gives-failed-to-open-stream-permission-denied-error-after/31398131#31398131
http://stackoverflow.com/questions/8103860/move-uploaded-file-gives-failed-to-open-stream-permission-denied-error-after
*/
?>
nothing so far?
passerby 5 months ago
Sorry for the delay. Updated my answer with the code. Hope you will accept it so i receive the bounty. I will give you free support on getting it working so feel free to post errors. But there are lots of ways it could be improved (this is just a quick prototype to get you going). I could make improvements for a tip, but lets first get it working on your side!
5osxcwbf 5 months ago
Appreciated. I will put it on the server later today and check it out. Thanks for the quick reply.
passerby 5 months ago
No problem, if i have some free time i will see if i can tidy things up a bit. All i know is that the code works & seems to do what you want :] Oh and i know it has multiple openings and closing tags for php, but thats just me being messy. Just place everything in one index.php file.
5osxcwbf 5 months ago
I put it up quick.. got this error. Parse error: syntax error, unexpected '[' in /var/www/upload_test1.php on line 145 Is there an email address I can share details like this at?
passerby 5 months ago
I made this anti-spam email address; alt.r2-5osxcwbf@yopmail.com if you send a question/error there i will contact you from my normal email address soon after with a solution! Don't forget to include your version of my code by uploading to http://pastebin.com or http://gist.github.com and giving me a link (it's impossible to debug a suggestion if the line numbers in the errors don't match the code in front of me!) Edit; looking into the error, it might have to do something with php versions, give me 1 minute.
5osxcwbf 5 months ago
Replicated the error, <?php $string = "test.jpg"; echo explode(".",$string)[1]; ?> if you try that line in http://sandbox.onlinephpfunctions.com/ You will see that it works fine in php versions newer than 5.4.0 but not on 5.3.29 and older. I will fix my code so it works in all php versions, give me 1 minute.
5osxcwbf 5 months ago
updated the code;it now works also in older php versions. if you don't want replace the whole file, simply ctrl+f search for "fix", i explained in the code the two lines i added and the one line i removed!
5osxcwbf 5 months ago
OK. it all seems to run thru, but no files appear. How about I approve your solution, since you have obviously done a lot of work. And will tip for the effort in getting this working on my server. Its probably permissions etc..
passerby 5 months ago
Was busy with some stuff, could you try commenting (adding // before them) these two lines: unlink($resized_file); . unlink($filename.".".$original_extension); Just try to upload and see if there are files appearing in your local upload folder in the server. If there are files appearing we now we know nothing is wrong with the permissions in your local folder. if there aren't files appearing make sure that the user thats executing apache/php has write access to that folder; chmod 777. If the files appear locally but not on s3, we know the error is in last part of the chain: client <> your_server <> s3. There could also be a permissions error in the s3 bucket itself (is it writable by the owner of the s3 credential
5osxcwbf 5 months ago
No change. Should a file remain in my uploads folder on my php server. There are no files in there.
passerby 5 months ago
please turn $debug = false; into $debug = true; and try uploading again so perhaps we get some more information, there seems to be a problem on your php server side of things
5osxcwbf 5 months ago
With DEBUG ON... Warning: moveuploadedfile(/var/www/testimages/520b26cbd87ef5d1635461b2dbc6858e.jpg): failed to open stream: Permission denied in /var/www/index.php on line 157 Warning: moveuploadedfile(): Unable to move '/tmp/phpgWxwGa' to '/var/www/testimages/520b26cbd87ef5d1635461b2dbc6858e.jpg' in /var/www/index.php on line 157 array(1) { ["myfile"]=> array(5) { ["name"]=> string(19) "20161106115925.jpg" ["type"]=> string(10) "image/jpeg" ["tmpname"]=> string(14) "/tmp/phpgWxwGa" ["error"]=> int(0) ["size"]=> int(2477895) } }
passerby 5 months ago
Now we know where the problem is! on the bottom of my answer you find a new small script that checks for permissions! its a bit of a shot in the dark though since i don't know exactly how your server is configured! Hope you will be able to get file permissions right. Anyways i received your email address so if you can't get it working i could always contact you over email so we could perhaps exchange login credentials for a development server? That way i wouldn't have to bother you so much, and i could provide you with a hassle free solution :] But perhaps the error is only small and you can fix it yourself based on the comment section of the folder permission check script i gave to you :]
5osxcwbf 5 months ago
It looks like it never writes the tmp file.
passerby 5 months ago
Think you are right, i might have misread the error; the problem could've been in the source directory; basically i added a new script to my answer, in it i explain how you can change the temporary folder path for uploaded files in your php.ini to a path where permissions don't cause issues (a new 777 chmodded tmp folder in your /var/www/ ) This seams to be the safest&quickest option to get it working. Let me know if it works :]
5osxcwbf 5 months ago
None of those worked.. drop me an email. How are your Webmin skills? :) We can discuss tip, since I know you are putting a lot of work in for $25
passerby 5 months ago
Emailed you. I have worked with webmin, directadmin, cpanel & plesk in the past so i'm confident in my ability to get it working :]
5osxcwbf 5 months ago
View Timeline