I use wordpress cms. I allow selective people to upload image. I have a script that resizes it and outputs resized image back to the browser where they can right click and save it. Here is the relevant part of the code. If needed I will put up the whole code. The script works and puts the resized image in the browser nicely.
header('Content-type: image/jpeg');
ob_start();
imagejpeg($resized, null, 100);
echo '<img src="data:image/jpeg;base64,' . base64_encode(ob_get_clean()) . '">';
imagedestroy($resized);
ISSUE : The form has just one upload field. I only allow images to be resized and saved one-by-one. Since all these resized images generated by the script has a same name index, an issue arises, which is when the visitor goes to save his image in windows the first time, say in a folder, it is saved as index.jpeg but when he goes to save images after that he is prompted to replace index.jpeg image. Because "these people " are not tech savvy so they usually replace the image end up wasting my time solving the case. So I would like these resized images to have unique name generated either by uniqid() or time().
WHAT I TRIED / AM TRYING : I am confused to what phpfunction I should be using here together with time() so that I could create a new filename each time a resized images is generated. In order to first set a variable, i tried to use basename() function like this, but it wont work.
$new_filename = basename($resized); echo '<br>' .$new_filename. '<br>';
Obviously it throws a warning:basename() expects parameter 1 to be string. I tried that and realized that in this case the variable $resized is a resource not a string. I am still crawling through threads for imagejpeg() at php.net in search of a solution, have not found any resource yet.
Bottomline question : how do I set or get a variable for resized file so
that I can manipulate it alongwith time() to create new names each
time.
FINAL UPDATE : #CBroe, pointed out that this is not possible so I am off to looking for an alternative.
Related
I have a application which is generating images with file_get_contents and file_put_contents method from a dynamic image source. After creating the image the image is uploaded to a directory on my server. The problem I face is every time the image is generated and I refresh the page I see the old image appear. It shows the new image when I clear the cache.
How could I solve the issue?
<?php
$imagename = "img".$id.".png";
$host = $_SERVER['DOCUMENT_ROOT'];
$path = $host.'/url/path/img/'.$imagename;
if(file_exists($path)) {
//echo 'File already exists in that directory';
unlink($path);
$filehandler = file_get_contents($imgurl);
file_put_contents($path, $filehandler);
}
else {
$filehandler = file_get_contents($imgurl);
file_put_contents($path, $filehandler);
}
It would always be better to use version as query Param to all images, js and css files. Using timestamp will not be as good since it will not be shown from cache if image is not updated. So in order to avoid additional overhead use version of images
That is,
Initially
<img src="image.png?v1" />
Till now next updation occurs this should be the URL
Once it is updated, it should change to
<img src="image.png?v2" />
As the other answers already stated, simplest solution is to add a parameter to the image URL. To still leverage browser caching when the image is unchanged, you should not use a random value.
My recommendation is to use the modification time of the image file, e.g.
<img src="image.png?<?php filemtime('image.png'); ?>" />
This has the advantage, that you don't need to keep track of versions to increment a number or similar.
This can be solved by adding random parameters to the image src, as shown here. For example, turn this:
<img src="image.png" />
Into this:
<img src="image.jpg?1222259157.415">
In the second src, the numbers after the question mark are the current timestamp. This is demonstrated in this answer, which sets the timestamp in JavaScript and appends it to the src using Date.now().
I'm building a web based system, which will host loads and loads of highres images, and they will be available for sale. Of course I will never display the highres image, instead when browsing people will only see a low resolution, watermarked image. Currently the workflow is as follows:
PHP script handles the highres image upload, when image is uploaded, it's automatically re-sized to a low res image and to a thumbnail image as well and both of the files are saved on the server, (no watermark is added).
When people are browsing, the page displays the thumbnail of the image, on click, it enlarges and displays the lowres image with watermark as well. At the time being I apply the watermark on the fly whenever the lowres image is opened.
My question is, what is the correct way:
1) Should I save a 2nd copy of the lowres image with thumbnail, only when it's access for the first time? I mean if somebody access the image, I add the watermark on the fly, then display the image & store it on the server. Next time the same image is accessed if a watermarked copy exist just display the wm copy, otherwise apply watermark on the fly. (in case watermark.png is changed, just delete the watermarked images and they will be recreated as accessed).
2) Should I keep applying watermarks on the fly like I'm doing now.
My biggest question is how big is the difference between a PHP file_exists(), and adding a watermark to an image, something like:
$image = new Imagick();
$image->readImage($workfolder.$event . DIRECTORY_SEPARATOR . $cat . DIRECTORY_SEPARATOR .$mit);
$watermark = new Imagick();
$watermark->readImage($workfolder.$event . DIRECTORY_SEPARATOR . "hires" . DIRECTORY_SEPARATOR ."WATERMARK.PNG");
$image->compositeImage($watermark, imagick::COMPOSITE_OVER, 0, 0);
All lowres images are 1024x1024, JPG with a quality setting of 45%, and all unnecessary filters removed, so the file size of a lowres image is about 40Kb-80Kb.
It is somehow related to this question, just the scale and the scenarios is a bit different.
I'm on a dedicated server (Xeon E3-1245v2) cpu, 32 GB ram, 2 TB storage), the site does not have a big traffic overall, but it has HUGE spikes from time to time. When images are released we get a few thousand hits per hours with people browsing trough the images, downloading, purchasing, etc. So while on normal usage I'm sure that generating on the fly is the right approach, I'm a bit worried about the spike period.
Need to mention that I'm using ImageMagick library for image processing, not GD.
Thanks for your input.
UPDATE
None of the answers where a full complete solution, but that is good since I never looked for that. It was a hard decision which one to accept and whom to accord the bounty.
#Ambroise-Maupate solution is good, but yet it's relay on the PHP to do the job.
#Hugo Delsing propose to use the web server for serving cached files, lowering the calls to PHP script, which will mean less resources used, on the other hand it's not really storage friendly.
I will use a mixed-merge solution of the 2 answers, relaying on a CRON job to remove the garbage.
Thanks for the directions.
Personally I would create a static/cookieless subdomain in a CDN kinda way to handle these kind of images. The main reasons are:
Images are only created once
Only accessed images are created
Once created, an image is served from cache and is a lot faster.
The first step would be to create a website on a subdomain that points to an empty folder. Use the settings for IIS/Apache or whatever to disable sessions for this new website. Also set some long caching headers on the site, because the content shouldn't change
The second step would be to create an .htaccess file containing the following.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*) /create.php?path=$1 [L]
This will make sure that if somebody would access an existing image, it will show the image directly without PHP interfering. Every non-existing request will be handled by the create.php script, which is the next thing you should add.
<?php
function NotFound()
{
if (!headers_sent()) {
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
header($protocol . ' 404 Not Found');
echo '<h1>Not Found</h1>';
exit;
}
}
$p = $_GET['path'];
//has path
if (strlen($p)<=1)
NotFound();
$clean = explode('?', $p);
$clean = explode('#', $clean[0]);
$params = explode('/', substr($clean[0], 1)); //drop first /
//I use a check for two, because I dont allow images in the root folder
//I also use the path to determine how it should look
//EG: thumb/125/90/imagecode.jpg
if (count($params)<2)
NotFound();
$type = $params[0];
//I use the type to handle different methods. For this example I only used the full sized image
//You could use the same to handle thumbnails or cropped/watermarked
switch ($type) {
//case "crop":if (Crop($params)) return; else break;
//case "thumb":if (Thumb($params)) return; else break;
case "image":if (Image($params)) return; else break;
}
NotFound();
?>
<?php
/*
Just some example to show how you could create a responds
Since you already know how to create thumbs, I'm not going into details
Array
(
[0] => image
[1] => imagecode.JPG
)
*/
function Image($params) {
$tmp = explode('.', $params[1]);
if (count($tmp)!=2)
return false;
$code = $tmp[0];
//WARNING!! SQL INJECTION
//USE PROPER DB METHODS TO GET REALPATH, THIS IS JUST EXAMPLE
$query = "SELECT realpath FROM images WHERE Code='".$code."'";
//exec query here to $row
$realpath = $row['realpath'];
$f = file_get_contents($realpath);
if (strlen($f)<=0)
return false;
//create folder structure
#mkdir($params[0]);
//if you had more folders, continue creating the structure
//#mkdir($params[0].'/'.$params[1]);
//store the image, so a second request won't access this script
file_put_contents($params[0].'/'.$params[1], $f);
//you could directly optimize the image for web to make it even better
//optimizeImage($params[0].'/'.$params[1]);
//now serve the file to the browser, because even the first request needs to show the image
$finfo = finfo_open(FILEINFO_MIME_TYPE);
header('Content-Type: '.finfo_file($finfo, $params[0].'/'.$params[1]));
echo $f;
return true;
}
?>
I would suggest you to create watermarked images on-the-fly and to cache them at the same time as everybody suggested.
Then you could create a garbage-collector PHP script that will be executed every days (using cron). This script will browse your cache folder to read every image access time. This can done using fileatime() PHP method. Then when a cached wm image has not been accessed within 24 or 48 hours, just delete it.
With this method, you can handle spike periods as images are cached at the first request. AND you will save your HDD space as your garbage-collector script will delete unused images for you.
This method will only work if your server partition has atime updates enabled.
See http://php.net/manual/en/function.fileatime.php
For most scenarios, lazily applying the watermark would probably make most sense (generate the watermarked image on the fly when requested then cache the result) however if you have big spikes in demand you are creating a mechanism to DOS yourself: create the watermarked version on upload.
Considering your HDD storage capacity and Pikes.
I would only create a watermarked image if it is viewed.(so yes on the fly) In that way you dont use to much space with a bunch a files that are or might not be viewed.
I would not watermark thumbnails i would rather make a filter that fake watermark and protect from being saved. That filter would apply to all thumbnails without creating a second image.
In this way all your thumbbails are watermarked (Fake with onther element on top).
Then if one of these thumbnails is viewed it generate a watermarked image (only once) since after its generated you load the new watermarked image.
This would be the most efficient way to deal with your HDD storage and Pikes.
The other option would be to upgrade your hosting services. Godaddy offer unlimited storage and bandwith for about 50$ a year.
This is an odd question but I'm stuck on how I would achieve this and I am unable to find any methods of doing so.
I have a simple php script that takes variables (containing file names) from the URL, cleans then and then uses them to generate a single image from the inputted values. This works fine and outputs a new png to the webpage using:
imagepng($img);
I also have a facebook sharing script in PHP that takes a filepath as an input and then shares the image on the users feed where this statement is used to define the image variable:
$photo = './mypic.png'; // Path to the photo on the local filesystem
I don't know how I can link these two together though. I would like to use my generation script as the image to share.
Can anyone point me in the right direction of how to do this? I am not the master of PHP so go easy please.
-Tim
UPDATE
If it helps, here are the links to the two pages on my website containing the outputs. They are very ruff mind you:
The php script generating the image:
http://the8bitman.herobo.com/Download/download.php?face=a.png&color=b.png&hat=c.png
The html page with the img tag:
http://the8bitman.herobo.com/Share.html
Treat it as a simple image:
<img src="http://yourserve/yourscript.php?onlyImage=1" />
yourscript.php
if($_GET['onlyimage']) {
header('Content-type:image/png'); //or your image content type
//print only image
} else {
//print image and text too
}
I'm developing a web application to transform images uploaded by the user.
When the user changes the image, it is saved with an other name in the server and served again to the client, like an img tag.
I have a problem when going back to the previous image. The actual image is deleted, and the new image is the previous. But when it is changed again by the user, the image shown isn't the new image, but the deleted image before go back. However, the image shown does not exist. I guess it is cached by the browser, but don't know how to prevent this.
Example:
$image1 = imagefirst.jpg
$image2 = imagechanged.jpg
//Going back:
$image3 = imagefirst.jpg
//imagechanged.jpg is deleted
//change again the image
$image4 = imagechanged.jpg
//serve to the client
<img src="imagefirst.jpg">
//the image shown isn't the new one saved in the server, but the image deleted previously.
Simply add random number to image's src property:
<!-- 759293475438 generated randomly each time -->
<img src='imagefirst.jpg?759293475438'/>
-to do this, you can use mt_rand() in PHP.
A simple solution to this problem would be to add a random string to the image to force the browser to request for a new image every time. You can use uniqid(), rand(), or time() for this purpose:
echo "<img src='imagefirst.jpg?version=".time()."'/>";
This will produce output similar to:
<img src='imagefirst.jpg?version=1378811671' />
As the query string is unique, the image would appear different to the browser.
How can I display an image and pass it as an input parameter in an executable in php without saving the image in a folder. The user gives the image path as input and I am using ajax to display the image when it is selected when I save it to a folder it works but how can I display it without saving it in a folder? My code now is
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/".$_FILES["file"]["name"]);
//echo "Stored in "."upload/".$_FILES["file"]["name"];
echo "<img src='upload/".$_FILES["file"]["name"]."' class='preview'>";
I tried
<img src=$_FILES["file"]["tmp_name"]. class='preview'>
but it didnt work. As I will have thousands of input from thousands of user I dont want to save it. Is there any optimised and efficient method to do this?
I think, its not possible to show image without saving it. You could try to save the image in temp folder on the server side and clean this folder periodically to avoid much space consumption.
The src attribute of the <img> tag should be an URL accessible by the client.
You try to give a local path (ex: path/to/your/file.jpg) of a temporary file as URL, it will not working.
info: The uploaded image is save on the local disk on a temp directory, and could be deleted by PHP later.
If you want to show the image without moving it at a place reacheable by a URL, you can try to load its content as base64 content
$imagedata = file_get_contents($_FILES["file"]["tmp_name"]);
$base64 = base64_encode($imagedata);
and use in your HTML
<img src="data:image/png;base64, <?php echo $base64; ?>" />
I don't think you can show the image without saving it.
You need to save the file either to the filesystem or to memory if you want to later output
Your problem here is that $_FILES only exists in the script that the image was sent to. so when you initiate another http request for img source, php no longer has any clue what file your trying to read.
You need a way to tell which image to be read on http request.
One thing you can do is that you can save the file in a place accessible by the client and then just have php delete it after you output it. So once the image is outputted it will be deleted and no longer be existing in the file system.
Another approach would be to get the image from the memory by directly writing the contents to httpresponse.
You can do this way
$image = file_get_contents($_FILES["file"]["tmp_name"]);
$enocoded_data = base64_encode($image);
and when you show your image tag :
<img src="data:image/png;base64, <?php echo $enocoded_data ; ?>" />
Hope any of these helps you