I'm building a basic analytics service, based in theory off of how Google Analytics works, but instead of requesting an actual image, I'm routing the image request to a script that accepts the data and then outputs an image. Since browsers will be requesting this image on every load, every millisecond counts.
I'm looking for the most efficient way for a file to output a gif file from a PHP script. So far, I've established 3 main methods.
Is there a more efficient way for me output a 1x1 GIF file from within a PHP script? If not, which of these is the most efficient and scalable?
Three Identified Methods
PHP image building libraries
$im = imagecreatetruecolor(1, 1);
imagefilledrectangle($im, 0, 0, 0, 0, 0xFb6b6F);
header('Content-Type: image/gif');
imagegif($im);
imagedestroy($im);
file_get_contents the image off of the server and output it
$im = file_get_contents('raw.gif');
header('Content-Type: image/gif');
echo $im;
base64_decode the image
header('Content-Type: image/gif');
echo base64_decode("R0lGODdhAQABAIAAAPxqbAAAACwAAAAAAQABAAACAkQBADs=");
(My gut was that base64 would be fastest, but I have no idea how resource intensive that function is; and that file_get_contents would likely scale less well, since it adds another file-system action.)
For reference, the GIF I'm using is here: http://i.stack.imgur.com/LQ1CR.gif
EDIT
So, the reason I'm serving this image is that my analytics library builds a query string and attaches it to this image request. Rather than parse logs, I'm routing the request to a PHP script which processes the data and responds with an image,so that the end user's browser doesn't hang or throw an error. My question is, how do I best serve that image within the confines of a script?
maybe
header('Content-Type: image/gif');
//equivalent to readfile('pixel.gif')
echo "\x47\x49\x46\x38\x37\x61\x1\x0\x1\x0\x80\x0\x0\xfc\x6a\x6c\x0\x0\x0\x2c\x0\x0\x0\x0\x1\x0\x1\x0\x0\x2\x2\x44\x1\x0\x3b";
That will output a binary string identical to the binary file contents of a 1x1 transparent gif. I'm claiming this as efficient based on the grounds that it doesn't do any slow IO such as reading a file, nor do I call any functions.
If you want to make your own version of the above hex string, perhaps so that you can change the color, you can use this to generate the php code for the echo statement.
printf('echo "%s";', preg_replace_callback('/./s', function ($matches) {
return '\x' . dechex(ord($matches[0]));
}, file_get_contents('https://upload.wikimedia.org/wikipedia/en/d/d0/Clear.gif')));
header('Content-Type: image/gif');
header("Content-Length: " . filesize("image.gif"));
$f = fopen('image.gif', 'rb');
fpassthru($f);
fclose($f);
Probably would be fastest for image from disk, but (especially if you're using bytecode caching) for a small images known in advance the base64 way will be the fastest I think. Sending Content-Length might be a good idea too, for the small image the browser would in most cases not wait for anything after receiving the bytes so while your server would take as much time, use experience will be sightly better.
Another way would be to let Apache/lighttpd/nginx serve the image, log the access and the parse it offline.
With Laravel:
$pixel = "\x47\x49\x46\x38\x39\x61\x1\x0\x1\x0\x80\x0\x0\xff\xff\xff\x0\x0\x0\x21\xf9\x4\x1\x0\x0\x0\x0\x2c\x0\x0\x0\x0\x1\x0\x1\x0\x0\x2\x2\x44\x1\x0\x3b";
return response($pixel,200,[
'Content-Type' => 'image/gif',
'Content-Length' => strlen($pixel),
]);
If anyone wants that for some reason.
Alternatively, if you don't like long(ish) hex strings in your code:
base64_decode('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw')
Instead of dynamically generating/outputting an image, why not just redirect to a static image?
<?php
// process query param stuff
header('Location: pixel.gif');
exit();
?>
Related
I'm working on an endpoint that returns a single image from the filesystem (like a user portrait). I use an ajax script for testing that processes the result of an endpoint and sticks it in a div. This raised the issue of constructing an image from an ajax response blob. The solutions I found on SO all assume that the image is being returned in base64 encoding. I got it working by changing the endpoint to output the image with base64 encoding, but this seems like an extra step, especially for iOS clients, which can understand the image being output by readfile.
Is this what people do in production environments? Doesn't conversion to base64 increase the size and put a load on the server? What advantages/disadvantages are there to each method? Is there another way that is even better?
header("Content-type: {$imginfo['mime']}");
// Output the file stream
readfile($filename);
// Output as base64
$type = pathinfo($filename, PATHINFO_EXTENSION);
$data = file_get_contents($filename);
base64_encode($data);
echo base64_encode($data);
I've the data uri of a png image, I've stored the data uri in mysql data base. Lets say img.php is the file that returns as a png image
<?php
$id=$_GET['id];
//data base connection and mysql queries
$data = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOAAAADMCAYAAABqQ6+sAAAEn0lEQVR4Xu3TUQkAIBAFQc1iHsOaUMES+zNX4MFwO9fZdzgCBBKBKcDE3SiBLyBAj0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+agAD9AIFQQIAhvmkCAvQDBEIBAYb4pgkI0A8QCAUEGOKbJiBAP0AgFBBgiG+awANJn7JcDjYVEQAAAABJRU5ErkJggg==";
//$data is obtained from mysql database
header('Content-Type: image/png');
$im = imagecreatefromstring($data);
imagepng($im);
imagedestroy($im);
?>
I've tried the above code, but its not giving me any output,
please help.
Thanks in advance.
The code is mostly pointless. You already have a PNG inside the data uri, so there is exactly ZERO point in loading that PNG into GD, then re-compressing to a PNG. that's massive waste of RAM and CPU time to basically accomplish nothing.
Also, GD doesn't understand data uris, so you cannot feed this uri into GD functions and expect something useful to happen.
You already have a PNG, so all you need to do is basically this:
$b64_png = string_operation_to_extract_base64_data_from_data_uri($datauri);
header('Content-type: image/png');
echo base64_decode($b64_png);
I have a .php file that's supposed to load an image for display in an img tag(i.e., <img src="the_file.php?which=0"/>). It looks like this:
<?php
ob_clean();
header("Content-type: image/png");
include_once("util.php");
//Do a simple calculation to get $name from (int)$_GET["which"];
$im = imagecreatefrompng("protected_directory/".$name.".png");
imagepng($im,NULL,0,NULL);
imagedestroy($im);
ob_end_flush();
?>
It works correctly, but the image loads substantially slower than just loading it directly(i.e. <img src="protected_directory/the_name.png"/>, where "the_name" was calculated the same way as in the PHP file, but I can't just do this because the protected_directory isn't world readable).
My question is, why is this suddenly so much slower? It's not a large image, but nor is it terribly small.
If you're just displaying an existing file, use readfile() to output it to the browser. There's no need to go through all the overhead of creating an editable GD object for this.
imagepng is known to be slow, if you need to output images with a PHP script, use code like this:
$filename = md5(time() . mk_rand());
imagepng($im, $filename);
echo file_get_contents($filename);
As another answer, I figured out that you can use the third parameter to compress the image (PNG uses zlib). Setting it to 9 works about as well as the other solutions.
So i have an iphone app that that uploads an image to my webserver and i looked around and people seem to be doing something like
$data = file_get_contents($_FILES['file']['tmp_name']);
$image = imagecreatefromstring($data);
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
I looked at the php docs, but i still don't understand what the header() does; does it convert the image into whatever format i want?
And for the imagepng(), where is the image outputted to? memory? is that why i need the imagedestroy()?
and where would i put in
move_uploaded_file()
Thanks in advance!
This code is intended to return as output an image - you could use it as a valid src for an image tag. That is, you could do this:
<img src="thatfile.php?something=1" />
The headers tell the browser that the data the server is going to send is an image (a PNG image, specifically).
In your example code, the file never actually gets written anywhere: the data stays in memory until the script ends, then it is simply "forgotten". imagedestroy frees up the memory and is good practice, but it really isn't necessary since the memory will be garbage collected after the request ends. If you want to preserve the image in a file, you'd have to use one of the related functions such as imagepng: http://www.php.net/manual/en/function.imagepng.php. The only difference between writing the file or not in your example code is the lack of a second argument for imagepng - second argument would be the desired file path.
It would help to read through the docs on this entire subject to gain a firm grasp of how these functions work and what each does. There are plenty of demos on the doc pages that show this in action.
This particular example gets the image uploaded through POST from the $_FILES array and simply outputs it back to the browser. The header is there to inform the browser that the content following is a PNG image.
Since you create an image from a string, it doesn't have "an extension". It's just an image resource at this point. You can create an actual file from it using imagepng, imagejpeg or any of the other methods to save an image resource to a file. You decide the extension (and file name) at that stage yourself.
E.g.:
imagepng($image, 'path/to/file.png');
and where would i put in move_uploaded_file()?
You wouldn't, since you don't have an uploaded file, only a string.
Header is purely for the server to let the browser know "Oh hey this is a png image please render it so"
imagepng encodes it into the png format and "prints" to the output
imagedestroy frees the memory taken by the image resource.
If you need to force extension you can use mod_rewrite
Here's a sample couple lines from my .htaccess:
RewriteEngine on
RewriteRule images/000000/00FF00/newmyinfo.jpg images/newmyinfo.php?bgcolor=000000&color=00ff00 [L]
Hope this helps!
I have a database that stores images in a MySQL BLOB field. I setup a script that selects and displays the images based on an ID in the URL, and I also made it so if you append ?resize=800x600, it would resize the image (in this case, to 800x600).
The host that I use doesn't have Imagemagick installed and won't let me do it myself, so I need to use PHP's GD library to resize the image.
But I've yet to find a function like Imagick's readImageBlob(), so I can't edit the binary string that I get from the database without first creating a temporary file, editing it, getting the binary string from it, sending it to the browser, and then deleting it (which is waaaay too many steps, especially since this will be getting a few thousand hits when it goes into production).
So my question is, is there any way to replicate readImageBlob with PHP's GD without going through the temporary file solution?
imagecreatefromstring() should do the trick. I think the function example in the manual is almost exactly what you need:
$im = imagecreatefromstring($data);
if ($im !== false) {
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
}
else {
echo 'An error occurred.';
}
Where $data is your binary data string from the database.