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

14,570

Solution 1

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')));

Solution 2

   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.

Solution 3

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')
Share:
14,570
Yahel
Author by

Yahel

Updated on June 06, 2022

Comments

  • Yahel
    Yahel almost 2 years

    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?

  • Yahel
    Yahel over 13 years
    Hm, adding Content-Length results in a 10% reduction in load times across the board. +1 for that. :)
  • Yahel
    Yahel over 13 years
    Yeah, considering the log route. If I do that, I might switch to S3 for increased performance and use their logging.
  • Yahel
    Yahel over 13 years
    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.
  • nulll
    nulll over 11 years
    Why it should be the best solution? what is this string? Please improve this answer...
  • RonaldPK
    RonaldPK about 8 years
    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?
  • Carl G
    Carl G almost 7 years
    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.
  • mpen
    mpen over 6 years
    @CarlG Yes. Just checked to make sure. The docs explicitly say 1 or 2 chars after the x.
  • artfulrobot
    artfulrobot about 5 years
    FWIW base64_decode works 5× slower than the encoded hex string in a speed test I did