Most efficient way to display a 1x1 GIF (tracking pixel, web beacon)
Asked Answered
G

5

22

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: https://i.sstatic.net/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?

Glenine answered 12/1, 2011 at 6:32 Comment(6)
If your purpose is really to serve a 1x1 pixel GIF, just have your webserver serve it up statically. If you actually want to serve a larger, dynamically constructed image, you should do your benchmarks with representative data too.Hultgren
@Savetheinternet hard to simulate the effect of hundreds/thousands of queries, but yes, some benchmarking would probably be in order. I'm also asking if there are any other, possibly better, methods.Glenine
@Hultgren the 1x1 image is just so that the request doesn't hang; I'm attaching analytics information to the request's query string and using that as a basis for my data collection. I'm not actually using the image in the pages. This is the method Google Analytics uses, and its much more elegant and efficient than some of the other options (namely, a hidden iframe).Glenine
@yc: well, you still can serve it by webserver and analyze logs in backgroundMicrovolt
Ohhh... I see now. I thought you were drawing graphs or something. Never mind!Hultgren
@yc - Can't you just use apache rewrite ? log this 1x1 gif access into a dedicate apache log file, and it can be parsed later onUnmeet
A
40

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')));
Advert answered 12/1, 2011 at 8:16 Comment(4)
Why it should be the best solution? what is this string? Please improve this answer...Dependency
Excellent solution. A minor issue is that the resulting gif is not transparent... How can I make such a string from an existing gif file?Percentile
Is "\x1" short for "\x01" in PHP? I'm trying to adapt this pixel to Python which doesn't seem to support single-digit hex codes.Stannic
@CarlG Yes. Just checked to make sure. The docs explicitly say 1 or 2 chars after the x.Luxembourg
M
1
   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.

Markman answered 12/1, 2011 at 6:41 Comment(2)
Hm, adding Content-Length results in a 10% reduction in load times across the board. +1 for that. :)Glenine
Yeah, considering the log route. If I do that, I might switch to S3 for increased performance and use their logging.Glenine
L
1

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')
Luxembourg answered 27/1, 2018 at 20:57 Comment(1)
FWIW base64_decode works 5× slower than the encoded hex string in a speed test I didVandusen
H
0

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();
?>
Hydrocephalus answered 13/1, 2011 at 16:33 Comment(1)
This is definitely an option. Before testing it, my instinct is to say that this is likely less efficient. This forces the browser to make a second HTTP request (as the first one will be 302/301'ed). Extra HTTP requests are generally pretty bad for performance.Glenine
L
0

I found this is the most effective for 1x1 gif. and also this one is transparent .

header('Content-Type: image/gif');
die("\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x90\x00\x00\xff\x00\x00\x00\x00\x00\x21\xf9\x04\x05\x10\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x04\x01\x00\x3b");
Lizabethlizard answered 5/10, 2023 at 20:5 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.