【问题标题】:Most efficient way to display a 1x1 GIF (tracking pixel, web beacon)显示 1x1 GIF(跟踪像素、网络信标)的最有效方式
【发布时间】:2011-01-12 06:32:07
【问题描述】:

我正在构建一个基本的分析服务,理论上基于 Google Analytics 的工作原理,但我不是请求实际图像,而是将图像请求路由到接受数据然后输出图像的脚本。由于浏览器会在每次加载时请求此图像,因此每毫秒都很重要。

我正在寻找文件从 PHP 脚本输出 gif 文件的最有效方式。到目前为止,我已经建立了 3 个主要方法。

有没有更有效的方法可以从 PHP 脚本中输出 1x1 GIF 文件?如果不是,哪些是最高效和可扩展的?

三种识别方法

PHP 图像构建库

$im = imagecreatetruecolor(1, 1);
imagefilledrectangle($im, 0, 0, 0, 0, 0xFb6b6F);
header('Content-Type: image/gif');
imagegif($im);
imagedestroy($im);

file_get_contents图片从服务器端出来并输出

$im = file_get_contents('raw.gif'); 
header('Content-Type: image/gif'); 
echo $im; 

base64_decode图片

header('Content-Type: image/gif');
echo base64_decode("R0lGODdhAQABAIAAAPxqbAAAACwAAAAAAQABAAACAkQBADs=");

(我的直觉是 base64 会是最快的,但我不知道该函数的资源密集程度如何;而且 file_get_contents 的扩展性可能不太好,因为它增加了另一个文件系统操作。)

作为参考,我使用的 GIF 在这里:http://i.stack.imgur.com/LQ1CR.gif

编辑

所以,我提供这张图片的原因是我的分析库构建了一个查询字符串并将其附加到这张图片请求中。我不是解析日志,而是将请求路由到处理数据并以图像响应的 PHP 脚本,这样最终用户的浏览器就不会挂起或抛出错误。我的问题是,如何在脚本范围内最好地提供该图像?

【问题讨论】:

  • 如果您的目的是提供一个 1x1 像素的 GIF,只需让您的网络服务器静态地提供它。如果您真的想提供更大的、动态构建的图像,您也应该使用代表性数据进行基准测试。
  • @Savetheinternet 很难模拟成百上千次查询的效果,但是是的,一些基准测试可能是有序的。我也在问是否还有其他可能更好的方法。
  • @Thomas 1x1 图像只是为了使请求不会挂起;我将分析信息附加到请求的查询字符串中,并将其用作我的数据收集的基础。我实际上并没有使用页面中的图像。这是 Google Analytics 使用的方法,它比其他一些选项(即隐藏的 iframe)更加优雅和高效。
  • @yc: 好吧,你还是可以通过网络服务器来服务它并在后台分析日志
  • 哦……我现在明白了。我以为你在画图表什么的。没关系!

标签: php javascript image performance analytics


【解决方案1】:

也许

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";

这将输出一个与 1x1 透明 gif 的二进制文件内容相同的二进制字符串。我声称这是高效的,因为它不会执行任何慢速 IO(例如读取文件),也不会调用任何函数。

如果你想制作你自己的上述十六进制字符串的版本,也许这样你可以改变颜色,你可以用它来为 echo 语句生成 php 代码。

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

【讨论】:

  • 为什么它应该是最好的解决方案?这个字符串是什么?请改进这个答案...
  • 优秀的解决方案。一个小问题是生成的 gif 不透明......如何从现有的 gif 文件中制作这样的字符串?
  • "\x1" 是 PHP 中 "\x01" 的缩写吗?我正在尝试将此像素调整为似乎不支持一位数十六进制代码的 Python。
  • @CarlG 是的。只需checked 以确保。文档在 x 之后明确说 1 或 2 个字符。
【解决方案2】:
   header('Content-Type: image/gif'); 
   header("Content-Length: " . filesize("image.gif"));
   $f = fopen('image.gif', 'rb');
   fpassthru($f);
   fclose($f);

对于来自磁盘的图像可能是最快的,但是(特别是如果您使用字节码缓存)对于预先知道的小图像,base64 方式将是我认为最快的。发送Content-Length 也可能是一个好主意,对于小图像,浏览器在大多数情况下在收到字节后不会等待任何内容,因此虽然您的服务器会花费尽可能多的时间,但使用体验会明显更好。

另一种方法是让 Apache/lighttpd/nginx 提供图像,记录访问并离线解析它。

【讨论】:

  • 嗯,添加 Content-Length 会导致加载时间全面减少 10%。为此+1。 :)
  • 是的,考虑日志路径。如果我这样做,我可能会切换到 S3 以提高性能并使用他们的日志记录。
【解决方案3】:

使用 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),
]);

如果有人出于某种原因想要这样做。

或者,如果您不喜欢代码中的长(ish)十六进制字符串:

base64_decode('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw')

【讨论】:

  • FWIW base64_decode 在我做的速度测试中比编码的十六进制字符串慢 5 倍
【解决方案4】:

为什么不直接重定向到静态图像,而不是动态生成/输出图像?

<?php
// process query param stuff

header('Location: pixel.gif');
exit();
?>

【讨论】:

  • 这绝对是一个选择。在测试它之前,我的直觉是说这可能效率较低。这会强制浏览器发出第二个 HTTP 请求(因为第一个请求将是 302/301'ed)。额外的 HTTP 请求通常对性能非常不利。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-09
  • 2020-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多