How to put PHP image resource into Amazon Web Services? - php

I am currently building a Zend Framework PHP web service that take an image uploaded from Android phone, resize it, and put it into Amazon Web Services S3.
Here are my codes:
$img = $_FILES['image'];
if(!$img)
{
return null;
}
if((($img['type'] == 'image/gif') ||
($img['type'] == 'image/jpeg') ||
($img['type'] == 'image/png')) &&
($img['size'] < 1048576))
{
if($img['error'] >0)
{
throw new Exception("image contain error ");
}
$size24 = 24;
//obtain the auth settings
$bootstrap = $this->getInvokeArg('bootstrap');
$awsConfigs = $bootstrap->getOption('aws');
$s3 = new Zend_Service_Amazon_S3($awsConfigs['appkey'], $awsConfigs['secretkey']);
$bucketName = 'item';
$folderName = 'image';
$perms = array(
Zend_Service_Amazon_S3::S3_ACL_HEADER =>
zend_service_amazon_s3::S3_ACL_PUBLIC_READ
);
$name = $bucketName.'/'. $folderName .'/'. uniqid() .'_'. Zend_Date::now()->toString('yyyyMMdd');
$smallPath = $name . '_32.png';
//resize and upload 24x24 image
$srcImg = imagecreatefrompng($img['tmp_name']);
$tmp = imagecreatetruecolor($size24, $size24);
list($oriWidth, $oriHeight) = getimagesize($img['tmp_name']);
imagecopyresampled($tmp, $srcImg, 0, 0, 0, 0, $size24, $size24, $oriWidth, $oriHeight);
//not working
imagepng($tmp, "tmp_32.png")
$smallret = $s3->putFile("tmp_32.png", $smallPath, $perms);
imagedestroy($tmp);
imagedestroy($srcImg);
}
else
{
throw new Exception("image size/format not qualified.");
}
I am thinking a way to convert the image resource to stream, so I can use $s3->putFileStream or putObject method, but I can't find a valid way.
Any idea??

Here is how you'll get your image into a variable without writing to a file:
ob_start();
imagepng($image);
$image_data = ob_get_contents();
ob_end_clean();
If you have the file contents in a variable, you can use putObject. Here's our example where we use file_get_contents. Notice we're getting all the S3 paths out of our Zend config file.
$image_data = file_get_contents(<filename>);
$aws_accesskey = Zend_Registry::get('config')->amazon->accesskey;
$aws_secret = Zend_Registry::get('config')->amazon->secret;
$s3 = new Zend_Service_Amazon_S3($aws_accesskey, $aws_secret);
$image_path = Zend_Registry::get('config')->amazon->s3->assetsbucket . "/images/$filename";
$s3->putObject($image_path, $image_data, array(Zend_Service_Amazon_S3::S3_ACL_HEADER => Zend_Service_Amazon_S3::S3_ACL_PUBLIC_READ));
}

Related

Compress image with PHP not reducing image size

I'm trying to compress and upload an image to the server with PHP. The upload are working correctly (without any errors), however the image size remains the same after the upload has completed. Could someone please advise what I could possibly be doing wrong?
Please find the code below:
public function addcoverimageAction()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Sanitize POST array
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
$userid = $this->route_params['userid'];
$thisuser = $userid;
$postid = $this->route_params['postid'];
$path_parts = pathinfo($_FILES['file']['name']);
$filename = $path_parts['filename'] . '_' . microtime(true) . '.' . $path_parts['extension'];
$directoryName = dirname(__DIR__) . "/images/$thisuser/listings/$postid/coverimage/";
// Check if directory exist
if (!is_dir($directoryName)) {
//If directory does net exist - create directory
mkdir($directoryName, 0777, true);
}
// Compress image
function compressImage($source, $destination, $quality)
{
$info = getimagesize($source);
if ($info['mime'] == 'image/jpeg') $image = imagecreatefromjpeg($source);
elseif ($info['mime'] == 'image/png') $image = imagecreatefrompng($source);
imagejpeg($image, $destination, $quality);
}
compressImage($_FILES['file']['tmp_name'], $directoryName . $filename, 60);
// Upload image
move_uploaded_file($_FILES['file']['tmp_name'], $directoryName . $filename);
}
$this->post = Post::findByID($postid);
Post::updateCoverimage($filename, $postid);
}
If it is working, then you're immediately overwriting the compressed file with the original, via the move_uploaded_file command, because you're sending it to the same destination as the compressed file, which was an earlier step.
The move_uploaded_file command is unnecessary in this case - you can remove it

Issue when uploading image to tmp folder, resize and then upload to S3 bucket

I've spend all day figuring out how to store an image in tmp, change its size and then upload it to my S3 bucket. The S3 bucket works fine and i am able to upload images when i don't resize. The resize function is the createThumbnail function and works fine when not combined with S3 probably because it's a wrong format or something. The second file "init.php" contains all the functions. The images are uploaded to the temp folder but when i run the script it doesn't get uploaded after it's resized. I don't get any error logs on localhost and when i upload the code to my AWS instance it just returns a internal server error but the error log in my instance is oddly empty... I need some fresh eyes on this issue.
banner_image.php
<?php
include "init.php";
if (#session($_SESSION["buddy"])){
$valid_file_formats = array("jpg","png","jpeg");
if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST" && !empty($_FILES['banner_image']['tmp_name']) && !empty($_FILES['banner_image']['name'])){
$folder = usernameFromEmail($_SESSION["user"]); // session based on users email
$buddy = $_SESSION["user"];
$name = $_FILES['banner_image']['name'];
$size = $_FILES['banner_image']['size'];
$path = $folder."/cover/"; // path to image folder
$temp = explode(".", $name);
$newfilenameKey = round(microtime(true)); // generating random file name
$newfilename = $newfilenameKey . "." . "png"; // always using png
if(strlen($newfilename) && strlen($name)) {
$ext = explode(".", $name);
$ext = end($ext);
if(in_array($ext,$valid_file_formats)) { // valid file format array check
if($size<=(10485760)) { // size check in bits
$tmp = $_FILES['banner_image']['tmp_name'];
$file_name = $path.$newfilename; // full path including file name
if(putS3IMG($bucket, $file_name, $tmp)){ // upload untouched image to S3 bucket
list($width, $height) = getimagesize($tmp);
$type = 2;
$w = 300;
$h = 300 * ($height / $width);
// getting new dimensions for the new image
if(createThumbnail(1,$tmp,$w,$h,$path,$file_name) == 1){ // function for smaller image
return json_encode(array("succ" => 1));
}
}
}
}
}
}
}
?>
here is my init.php file included in the banner_image.php file which contains my functions.
<?php
// connection to S3Client .... $client
function createThumbnail($type,$image_name,$new_width,$new_height,$uploadDir,$moveToDir){
global $bucket;
//$type: defines the name of the new file
//image_name: tmp name
//uploadDir: path
//moveToDir: files new path incl. file name
$mime = getimagesize($image_name);
if($mime['mime']=='image/png') {
$src_img = imagecreatefrompng($image_name);
} else if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
$src_img = imagecreatefromjpeg($image_name);
}
$old_x = imageSX($src_img);
$old_y = imageSY($src_img);
$thumb_w = $new_width;
$thumb_h = $new_height;
$dst_img = ImageCreateTrueColor($thumb_w,$thumb_h);
$background = imagecolorallocate($dst_img, 0, 0, 0);
imagecolortransparent($dst_img, $background);
imagealphablending($dst_img, false);
imagesavealpha($dst_img, true);
imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y);
$image_name_new = explode(".", $moveToDir);
if ($type == 1){
$new_image_name = $image_name_new[0] . "_thumb." . $image_name_new[1];
} else if ($type == 2){
$new_image_name = $image_name_new[0] . "_image." . $image_name_new[1];
}
$tmpPath = tempnam(sys_get_temp_dir(), $new_image_name); // getting temporary directory
if($mime['mime']=='image/png') {
imagepng($dst_img,$tmpPath,8);
} else if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
imagejpeg($dst_img,$tmpPath,80);
}
imagedestroy($dst_img);
imagedestroy($src_img);
if(putS3IMG($bucket, $image_name, $tmpPath)){ // this part does not work
return 1;
} else {
return 2;
}
}
function putS3IMG($bucket, $file_name, $tmp){ // function uploading to my bucket
//file_name is with directories
//tmp is $_FILES tmp_name
global $client;
$result = $client->putObject([
'Bucket' => $bucket,
'Key' => $file_name,
'SourceFile' => $tmp
]);
if ($result){
return true;
}
return false;
}
SOLUTION:okay, so eventually i ended up using AWS lambda which solved the issue but it isn't a free solution. So, if any of you come up with a solution that allow you to resize without using third party tools feel free to comment it in order to make life easier for the next programmers viewing this question.

Using PHP getimagesize and imagecreate with Google App Engine and Google Cloud Storage

I want to use PHP in GAE to upload file image files.
Before storing, I want to convert each file to JPEG and reduce it to thumbnail quality.
Using the following code (which fully works in a normal PHP environment, less the bucket-specific adjustments), I am able to receive the uploads and determine the temporary file name and location, but getimagesize produces an error when attempting to access the CloudStorage.
$bucket = CloudStorageTools::getDefaultGoogleStorageBucketName();
$bucketPath = "gs://" . $bucket . "/" . $_SERVER["REQUEST_ID_HASH"] . "/";
$counter = 0;
foreach($_FILES["file"]["name"] as $idx => $tempFile) {
$counter++;
$sourceFile = $bucketPath . $tempFile;
syslog(LOG_DEBUG, $sourceFile);
$photoInfo = getimagesize($sourceFile);
if ($photoInfo["mime"] == "image/jpeg") {
$photoImage = imagecreatefromjpeg($sourceFile);
$valid = true;
}
elseif ($photoInfo["mime"] == "image/gif") {
$photoImage = imagecreatefromgif($sourceFile);
$valid = true;
}
elseif ($photoInfo["mime"] == "image/png") {
$photoImage = imagecreatefrompng($sourceFile);
$valid = true;
}
if (isset($valid)) {
$date = date("Y-m-d H:i:s");
$photoFolder = rtrim($photoFolder, "/") . "/";
$photoFile = "Test {$counter} {$date}.jpg";
$imageSaved = imagejpeg($photoImage, $photoFolder.$photoFile, 50);
syslog(LOG_DEBUG, "File saved is " . $imageSaved);
}
}
The first syslog entry confirms the file path and name...
gs://[myappid].appspot.com/AC3E3530/IMG_20160701_120144.jpg
The error log shows an error in attempting to open the stream, but I don't know how to address it.
PHP Warning: getimagesize(gs://[myappid].appspot.com/AC3E3530/IMG_20160701_120144.jpg): failed to open stream: "\google\appengine\ext\cloud_storage_streams\CloudStorageStreamWrapper::stream_open" call failed in /base/data/home/apps/s~[myappid]/v1.394746390020376247/code/server.php on line 169
I already have a variation of this functionality working on GAE with photos that my server receives through Twilio (where processPhoto() is a function identical to the code I excerpted above). In this case, I'm using getimagesize and imagecreate with a URL. I just don't know how to do the same with CloudStorage.
if ($fetch && $numMedia > 0) {
for ($x = 0; $x < $numMedia; $x++) {
$sourceFile = $_REQUEST["MediaUrl" . $x];
$sid = $_REQUEST["MessageSid"];
processPhoto("sms", $projectID, $sourceFile, $caption, $sid, $mobile, $message);
}
}
I think the problem was that the temporary file was removed before I could process it. So, I...
Removed the functionality of processing multiple files (which I
didn't need anyhow).
Immediately move the file to another bucket.
Examine the file for its type.
Save it as desired.
Remove the temporary file.
This is the form that I generate in PHP. There's no Submit button because I watch for a file change with jQuery.
<form id='form_uploadPhotos' method='post' enctype='multipart/form-data' action='{$websiteURL}?action=uploadPhotos'>
<input type='file' id='input_uploadPhoto' name='file'>
<input type='hidden' name='projectID' value='{$projectID}'>
</form>
This is the uploadPhotos function that's called when the form is submitted:
if ($action == "uploadPhotos") {
$projectID = preg_replace("/\D/", "", $_REQUEST["projectID"]);
$bucket = CloudStorageTools::getDefaultGoogleStorageBucketName();
$bucketPath = "gs://" . $bucket . "/" . $_SERVER["REQUEST_ID_HASH"] . "/";
$date = date("Y-m-d H:i:s");
$time = time();
$photoFile = sprintf("%08d", $projectID) . "." . $date . "." . $time . ".TEMP";
$sourceFile = $photoFolder.$photoFile; // The default photo folder is defined elsewhere.
move_uploaded_file($_FILES["file"]["tmp_name"], $sourceFile);
processPhoto("upload", $projectID, $sourceFile, null, null, null, null);
}
This is the function that processes the photo. It's called by other processes that also receive photos (e.g., SMS attachments via Twilio).
function processPhoto($via, $projectID, $sourceFile, $caption, $twilioMessageID, $smsMobile, $smsMessage) {
global $photoFolder;
$photoInfo = getimagesize($sourceFile);
if ($photoInfo["mime"] == "image/jpeg") {
$photoImage = imagecreatefromjpeg($sourceFile);
$valid = true;
}
elseif ($photoInfo["mime"] == "image/gif") {
$photoImage = imagecreatefromgif($sourceFile);
$valid = true;
}
elseif ($photoInfo["mime"] == "image/png") {
$photoImage = imagecreatefrompng($sourceFile);
$valid = true;
}
if (isset($valid)) {
$date = date("Y-m-d H:i:s");
$time = time();
$photoFile = sprintf("%08d", $projectID) . "." . $date . "." . $time . ".JPEG";
$photoImage = imagecreatefromjpeg($sourceFile);
list($width, $height) = getimagesize($sourceFile);
if (max($width, $height) > 800) {
$scale = 800/max($width, $height);
$newWidth = floor($width * $scale);
$newHeight = floor($height * $scale);
$saveImage = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled($saveImage, $photoImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
}
$imageSaved = imagejpeg($photoImage, $photoFolder.$photoFile);
imagedestroy($photoImage);
if ($imageSaved) {
if (isset($twilioMessageID)) {
$twilioMediaID = substr($sourceFile, strrpos($sourceFile, "/") + 1);
purgeTwilioMedia($twilioMessageID, $twilioMediaID);
}
elseif (substr($sourceFile, strrpos($sourceFile, ".")) == ".TEMP") {
unlink($sourceFile);
}
<Additional processing (e.g., adding entry to database.)
.
.
.
}
}
}
Note: The image scaling code between "list($width, $height..." and "imagecopyresampled..." is based on Dano's answer to another question.
I'm guessing that you're hitting a limitation of the Standard Environment where the getimagesize native function in the Standard runtime doesn't work with file extensions like gs:// URLs.

PHP & Jquery FileAPI - shared PHP server configuration

I'm letting my users crop & upload their image with jQuery FileAPI. I'm calling this PHP file with jQuery from another page.
Everything works good on my local server, but when uploading it to my production (shared - cPanel) server, it does not create the file.
Do you know if there is something that I need to change on my cPanel or call my hosting company for?
I tried tweeking with header access but nothing works.
Here is the PHP file:
<?php include 'init.php'; ?>
<?php
if(logged_in() === false) {
header('Location: login.php');
exit();
} ?>
<?php
/**
* FileAPI upload controller (example)
*/
include 'FileAPI.class.php';
if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){
exit;
}
if( strtoupper($_SERVER['REQUEST_METHOD']) == 'POST' ){
$files = FileAPI::getFiles(); // Retrieve File List
$images = array();
// Fetch all image-info from files list
fetchImages($files, $images);
// JSONP callback name
$jsonp = isset($_REQUEST['callback']) ? trim($_REQUEST['callback']) : null;
// JSON-data for server response
$json = array(
'images' => $images
, 'data' => array('_REQUEST' => $_REQUEST, '_FILES' => $files)
);
// Server response: "HTTP/1.1 200 OK"
FileAPI::makeResponse(array(
'status' => FileAPI::OK
, 'statusText' => 'OK'
, 'body' => $json
), $jsonp);
exit;
}
function fetchImages($files, &$images, $name = 'file'){
if( isset($files['tmp_name']) ){
$filename = $files['tmp_name'];
list($mime) = explode(';', #mime_content_type($filename));
if( strpos($mime, 'image') !== false ){
$size = getimagesize($filename);
$base64 = base64_encode(file_get_contents($filename));
$images[$name] = array(
'width' => $size[0]
, 'height' => $size[1]
, 'mime' => $mime
, 'size' => filesize($filename)
, 'dataURL' => 'data:'. $mime .';base64,'. $base64
);
$iWidth = $iHeight = 330; // desired image result dimensions
$iJpgQuality = 100;
// new unique filename
$sTempFileName = 'userpics/' . md5(time().rand());
// move uploaded file into cache folder
move_uploaded_file($filename, $sTempFileName);
// change file permission to 644
#chmod($sTempFileName, 0644);
if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
$aSize = getimagesize($sTempFileName); // try to obtain image info
if (!$aSize) {
#unlink($sTempFileName);
return;
}
// check for image type
switch($aSize[2]) {
case IMAGETYPE_JPEG:
$sExt = '.jpg';
// create a new image from file
$vImg = #imagecreatefromjpeg($sTempFileName);
break;
case IMAGETYPE_GIF:
$sExt = '.gif';
// create a new image from file
$vImg = #imagecreatefromgif($sTempFileName);
break;
case IMAGETYPE_PNG:
$sExt = '.png';
// create a new image from file
$vImg = #imagecreatefrompng($sTempFileName);
break;
default:
#unlink($sTempFileName);
return;
}
$data = getimagesize($sTempFileName);
$width = $data[0];
$height = $data[1];
// create a new true color image
$vDstImg = #imagecreatetruecolor( $iWidth, $iHeight );
// copy and resize part of an image with resampling
imagecopyresampled($vDstImg, $vImg, 0, 0, 0, 0, $iWidth, $iHeight, $width, $height);
// define a result image filename
$sResultFileName = $sTempFileName . $sExt;
// output image to file
imagejpeg($vDstImg, $sResultFileName, $iJpgQuality);
#unlink($sTempFileName);
$user_id = $_SESSION['user_id'];
add_guest_picture($user_id, $sResultFileName);
// return $sResultFileName;
}
}
}
else {
foreach( $files as $name => $file ){
fetchImages($file, $images, $name);
}
}
}
?>
Ok issue resolved!
Apparently mime_content_type was not support by my host. after removing error suppression recommended by Musa I could catch the error.
I asked for my host to enable my mime php handling and now everything works.
Cheers.

Image upload with resize

i have a upload script and that works fine, but i want that its upload twice, one orginal format and one in a thubm size.
I did allready search on google and stackoverflow and i tried allready something, but i dont get it work.
My upload script
// If you want to ignore the uploaded files,
// set $demo_mode to true;
$demo_mode = false;
$upload_dir = 'uploads/';
$allowed_ext = array('jpg','jpeg','png','gif');
include('./../includes/core.php');
if(strtolower($_SERVER['REQUEST_METHOD']) != 'post'){
exit_status('Error! Wrong HTTP method!');
}
if(array_key_exists('pic',$_FILES) && $_FILES['pic']['error'] == 0 ){
$pic = $_FILES['pic'];
if(!in_array(get_extension($pic['name']),$allowed_ext)){
exit_status('Alleen '.implode(',',$allowed_ext).' bestanden zijn toegestaan');
}
if($demo_mode){
// File uploads are ignored. We only log them.
$line = implode(' ', array( date('r'), $_SERVER['REMOTE_ADDR'], $pic['size'], $pic['name']));
file_put_contents('log.txt', $line.PHP_EOL, FILE_APPEND);
exit_status('Uploads are ignored in demo mode.');
}
// Move the uploaded file from the temporary
// directory to the uploads folder:
$name = $pic['name'];
$sname = hashing($name);
$datum = date("d-m-Y");
if(move_uploaded_file($pic['tmp_name'], $upload_dir.$sname)){
mysql_query("INSERT INTO foto VALUES ('','".$pic['name']."','".$sname."', '".$datum."', '0')");
exit_status('Bestand succesvol geupload');
}
}
exit_status('Er is iets mis gegaan!');
// Helper functions
function exit_status($str){
echo json_encode(array('status'=>$str));
exit;
}
function hashing($naam){
$info = pathinfo($naam);
$ext = empty($info['extension']) ? '' : '.' . $info['extension'];
$hash = basename($naam, $ext);
$hash = $hash . genRandomstring();
$hash = md5($hash);
$hash = $hash . '-' . genRandomstring();
return $hash . $ext;
}
function genRandomString() {
$length = 5;
$string = "";
$characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+!#"; // change to whatever characters you want
while ($length > 0) {
$string .= $characters[mt_rand(0,strlen($characters)-1)];
$length -= 1;
}
return $string;
}
function get_extension($file_name){
$ext = explode('.', $file_name);
$ext = array_pop($ext);
return strtolower($ext);
}
?>
If someone can help me? I will be very happy then becuase i have allready try this for a week and i can get it out.
Thanks, Chris
You have the image uploaded once, which is all you need, then use that to create the second thumbnail file.
Try looking over the GD documentation.
as mentioned before you don't need to upload twice, copy and resize image once it's uploaded like this:
$pathToImages = "path/to/images"
$pathToThumbs = "path/to/thumbs"
$fname = "image-file-name";
$new_fname = "thumb-file-name";
$img = imagecreatefromjpeg( "{$pathToImages}{$fname}" );
$width = imagesx( $img );
$height = imagesy( $img );
$thumbWidth = //someValue//;
$thumbHeight = //someValue//;
// calculate thumbnail size
$new_height = floor($height * ($thumbWidth/$width));
$new_width = $thumbWidth;
// create a new temporary image
$tmp_img = imagecreatetruecolor($thumbWidth, $thumbHeight);
// copy and resize old image into new image
imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width,$new_height, $width, $height );
// save thumbnail into a file
imagejpeg( $tmp_img, "{$pathToThumbs}{$new_fname}" );

Categories