Developing a tracking pixel - php

I am trying to build a pixel that would track the current URL the user is on when they visit. I can use either JS (preferred) or a 1x1 image pixel. With JS I am assuming that I'd need to run an AJAX request to a PHP script to capture the info that I need and with an image pixel I am having issues getting the currently URL.
I also thought about URL encoding the current URL with JS and dynamically placing the image pixel with the encoded current URL as a query string to a PHP script, but that I can get to be very long.
If I am to go the AJAX route, which AJAX library can I use? JQuery is too bloated for this purpose.
Any other ideas?

You can write a script that creates and returns a .gif, .jpeg or .png image using PHP for tracking purposes using the GD library (which is often distributed with PHP in modern versions). If you don't have access to GD, you can always recompile PHP with GD enabled.
Example:
pixel.php (commented for the purposes of explanation):
<?php
// Create an image, 1x1 pixel in size
$im=imagecreate(1,1);
// Set the background colour
$white=imagecolorallocate($im,255,255,255);
// Allocate the background colour
imagesetpixel($im,1,1,$white);
// Set the image type
header("content-type:image/jpg");
// Create a JPEG file from the image
imagejpeg($im);
// Free memory associated with the image
imagedestroy($im);
?>
In a simple example, you can then call this tracking pixel using the following example URL in an email or other page:
<img src="http://example.com/pixel.php?a=value1&b=value2&c=value3">
Using variables:
Within your pixel.php you can then parse and interpret any $_GET variables that are passed to it within the image tag, simplistically:
if (isset($_GET['a'])) {
// (Do|log) act on a
}
if (isset($_GET['b'])) {
// (Do|log) act on b
}
if (isset($_GET['c'])) {
// (Do|log) act on c
}
Apply and repeat as you need, but you can be quite sophisticated about what you do and especially as you have access to quite a lot of information about the user through being able to set vars on the $_GET string.
A more applicable example might be:
<img src="http://example.com/pixel.php?userid=98798&campaign=302&last=8">
Tracking more than just $_GET variables:
You can also pick up much more information using PHP, such as:
// Server variables
$ip = $_SERVER['REMOTE_ADDR'];
$referer = $_SERVER['HTTP_REFERER'];
$useragent = $_SERVER['HTTP_USER_AGENT'];
$browser = get_browser(null, true);
etc...
and then perhaps insert into a tracking table in your database:
$sql = "INSERT INTO campaign_tracking
('when','campaign','last','ip','useragent')
VALUES
(NOW(),'$campaign','$last','$ip','$useragent')";
This is a(the) basic method used widely for tracking email marketing campaigns and specifically in PHP, but the same method is applicable using other scripting/programming languages and libraries - and for other purposes too.
Further and useful information on GD:
GD reference - on php.net

Here is another PHP implementation of a tracking pixel, from the Open Web Analytics project, which attempts to basically be a PHP clone of Google Analytics.
It returns a 1x1 transparent GIF image (without using a PHP image library!), with a no-cache header (important for accurate tracking), and flushes the output so you can continue processing the analytics without blocking the HTTP response (performance). It seems like a pretty advanced implementation, worth trying out.
<?php
ignore_user_abort(true);
// turn off gzip compression
if ( function_exists( 'apache_setenv' ) ) {
apache_setenv( 'no-gzip', 1 );
}
ini_set('zlib.output_compression', 0);
// turn on output buffering if necessary
if (ob_get_level() == 0) {
ob_start();
}
// removing any content encoding like gzip etc.
header('Content-encoding: none', true);
//check to ses if request is a POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// the GIF should not be POSTed to, so do nothing...
echo ' ';
} else {
// return 1x1 pixel transparent gif
header("Content-type: image/gif");
// needed to avoid cache time on browser side
header("Content-Length: 42");
header("Cache-Control: private, no-cache, no-cache=Set-Cookie, proxy-revalidate");
header("Expires: Wed, 11 Jan 2000 12:59:00 GMT");
header("Last-Modified: Wed, 11 Jan 2006 12:59:00 GMT");
header("Pragma: no-cache");
echo sprintf('%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%',71,73,70,56,57,97,1,0,1,0,128,255,0,192,192,192,0,0,0,33,249,4,1,0,0,0,0,44,0,0,0,0,1,0,1,0,0,2,2,68,1,0,59);
}
// flush all output buffers. No reason to make the user wait for OWA.
ob_flush();
flush();
ob_end_flush();
// DO ANALYTICS TRACKING HERE

Output 1px x 1px this way:
header('Content-type: image/png');
echo gzinflate(base64_decode('6wzwc+flkuJiYGDg9fRwCQLSjCDMwQQkJ5QH3wNSbCVBfsEMYJC3jH0ikOLxdHEMqZiTnJCQAOSxMDB+E7cIBcl7uvq5rHNKaAIA'));

Here's an extremely simplified tracking pixel written in PHP.
How a Tracking Pixel Works
A tracking pixel is like the most primitive beacon possible, and it operates by exploiting a fact of web pages: images are a separate request from the page.
If you are already able to run your JS code on someone else's page, you should just POST the data back to your server. No need to display a tiny pixel that will only get the same kind of data.

It is a similar problem with this effect, since a call to a function to execute a mark of when the email was seen or opened was introduced in the alt of the pixel, but it does not throw the action correctly.
<img src="https://datafeeds.baruwa.com/1x1spacer.gif" width="1" height="1" alt="Web Bug from https://devorpenguin.des1.net/module/cartabandonmentpro/FrontCartAbandonment?token_cart=87c83b8f77318a54fdd6be91aacc3574&id_cart=1002&action=visualize&wichRemind=1">
public static function visualize()
{
$wichRemind = Tools::getValue('wichRemind');
$id_cart = Tools::getValue('id_cart');
$token = Tools::getValue('token_cart');
if ($token == md5(_COOKIE_KEY_.'recover_cart_'.$id_cart)) {
$query = "UPDATE "._DB_PREFIX_."cartabandonment_remind SET visualize = 1 WHERE wich_remind = ".(int)$wichRemind." AND id_cart = ".(int)$id_cart;
Db::getInstance()->Execute($query);
}
header('Content-Type: image/png');
echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=');
}

Using OpenPixel will take care of most of the heavy lifting if the scope of your project calls for it.

Related

How to create a video stream from a single dynamic image in PHP

I have a single image file on my server which its content changes every 100 ms.
I can load and serve this image as usual:
$image = file_get_contents('path/to/image.jpg');
header('Content-type: image/jpeg');
echo $image;
<img src="image.php">
Thus, every time the user updates the screen (pressing F5 for example) the server would reply a different image. I can also use Java Script (using setInterval for example) to update the image continuously so the users needn't to update the screen themselves.
However, I need to serve this image as a CONTINUOUS FLOW such as a LIVE VIDEO STREAM in order to be shown as an HTML5 video instead of a static image.
Some examples I`ve found so far use PHP-FFMpeg library for stream videos. It turns out that those examples require that I have a video file at hand (a file in the OS or a URL to a file) instead of a single (dynamic) image as I've described above.
I found this example for how to use PHP to streaming. It looks promisssing. But again the code supposes I have a video file url which I haven't.
I'm wondering if is it possible to adapt this code to my needs. For example, how to adapt the setHeader() method to the scenario where there are no begin and end? And considering that I have loaded the image contents using file_get_contents or so, how to change stream() properly? Or, at other hand, is there other way to serve this image as a video stream?
The code below should reload the image ever 200 ms. Adding a random number avoids any potential caching which is unlikely since you are requesting a PHP page.
<html>
<header>
<script>
function ReloadImage()
{
var image_element = document.getElementById('image_id');
image_element.src = 'image.php?rand=' + Math.random();
}
setInterval(ReloadImage,200);
</script>
</header>
<body>
<img src="image.php" id="image_id">
</body>
</html>
Well, I just found a solution for my needs:
$identifier = "an_identifier";
//set headers
header('Accept-Range: bytes');
header('Connection: close');
header('Content-Type: multipart/x-mixed-replace;boundary=' . $identifier);
header('Cache-Control: no-cache');
// loop to continuously serve an image
while(true) {
$image = load_image_contents();
echo "--" . $identifier . "\r\nContent-Type: image/jpeg\r\nContent-Length: ".strlen($image)."\r\n\r\n".$image;
flush();
usleep(50000);
}
On the browser side I just set a regular image tag:
<img src="image.php">

How to force browser to cache on-demand generated images?

An URL such as http://mydomain.com/text/SGVsbG8gd29ybGQh/params/Y29sb3I9I2Y5NzMwNixmb250LWZhbWlseT1Db21pYyBTYW5zLGZvbnQtc2l6ZT0yMnB4LGZvbnQtd2VpZ2h0PWJvbGQsZm9udC1zdHlsZT1ub3JtYWwsdGV4dC1kZWNvcmF0aW9uPW5vbmUsdGV4dC1hbGlnbj1sZWZ0/96 calls on a PHP script that generates an image based on the encoded information contained within the URL. The information encode is the actual text, plus some formatting options (e.g. color, font-weight etc.).
The first time this URL is called, the image is generated, saved to disk and then returned as the response. Starting with the second call to the same URL, the image is loaded from disk and output to the client instead of being generated all over again.
How can I force the browser to treat such a URL as any other path to a stored image file and cache it, so that the next time the URL is called, the browser will load the image from its cache?
Btw, the code I have in the controller (CodeIgniter-based) is as follows:
public function addText($text, $params, $resolution=96) {
$this->load->model("textimage_model");
$image = $this->textimage_model->getImage($text, $params, $resolution);
// Prepare the response headers and output the image to the client
header("Content-type: image/png");
header("Content-disposition: inline; filename=mytext.png");
if (is_string($image)) {
readfile($image);
} elseif (is_resource($image)) {
imagepng($image);
imagedestroy($image);
} else {
//
}
}
Send caching headers.
$seconds_to_cache = 60 * 60 * 24; // 1 day
header("Pragma: cache");
header("Cache-Control: max-age=" . $seconds_to_cache);
Since your caching mechanism seems to be a fingerprint you can have the browser cache it forever.

How are images cached when loaded via php script

I have a php script acting as a random image generator. The script queries the database for the user's images, and returns the path to one, at random. Here is the portion of the code responsible for returning the image, once the path has been chosen.
header('Content-Transfer-Encoding: binary');
header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($path));
echo file_get_contents($path);
I am calling it from the client like so
image.src = "/database/getRandomImage.php";
Every time I refresh the page I get a new image at random. However, if I call getRandomImage.php multiple times for side by side images, they will all be the same image. If I add a random property to the call like so
image.src = "/database/getRandomImage.php?path=" + Math.random() * 100;
The pictures become random. I take this to mean that the browser is caching them based on the random property I passed. The problem is this property has nothing to do with the actual image. Two different images might get cached as the same image, and the same image might not be retrieved from the cache. Is there any way for getRandomImage.php to inform the browser about the picture it is sending back?
Why not have getRandomImage be a PHP function, which returns a path to the image. You can render the page out with the random image paths already filled in.
<img src="<? echo getRandomImage() ?>">
Then you can actually serve your images with real cache headers, and your bandwidth wont be getting hammered so hard.
Do this on the server side while the page is rendering, not after. Doing it after is more work and, as you are finding out, is more complicated too.
The caching has nothing to do with the PHP script; it happens at the browser.
Try adding this to the script, to try and force the browser to not cache it (from PHP website):
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
Just make randomImage.php redirect to a seeded version if it isn't present.
if (!isset($_REQUEST['seed']))
{
header("Location: randomImage.php?seed="+rand());
exit;
}
Feel free to make the randomizer more random.
Browsers expect that the same will always represent the same image. And I think that even headers that force no caching at all wont even stop the browser from reusing the image on the same page. So a image source that is different each time you call it is pretty counter intuitive.
Cache busting is probably your best bet. That means like you random hack there, although there is ways to do it better. For instance, appending an increasing integer to the current time. This way you never duplicate urls.
var count = 0;
var now = new Date().getTime();
imgs[0].src = "/database/getRandomImage.php?" + (count++) + now;
imgs[1].src = "/database/getRandomImage.php?" + (count++) + now;
imgs[2].src = "/database/getRandomImage.php?" + (count++) + now;
But really, you may want to rethink your strategy here, because it sounds a little fishy.

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

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();
?>

GD - rotating image doesn't work in IE and Opera

I've created a function that rotates defined image. It works perfect in firefox, but in IE and Opera nothing happens - the image is reloaded but not rotated. Does anybody know why? Here goes the code:
function rotateImage($direction, $id, $angle) {
$dir = opendir($direction);
if ($img = imagecreatefromjpeg($_SESSION['files'][$id]['large'])) {
$width = imagesx ( $img );
$height = imagesy ( $img );
$rotate = imagerotate($img, $angle, 0);
imagejpeg($rotate, $_SESSION['files'][$id]['large'], 100);
}
else {
echo '<p>Error: image cannot be rotated</p>';
}
closedir($dir);
}
The problem is definitely not with the browser you are using as the rotation is done server-side.
You might be running into a caching issue or an issue with the code used to call that function.
Are you:
Using JavaScript to initiate a reload?
Your JavaScript code might be the issue here.
Sending the proper no-cache headers?
If not, you might be running into a situation where the image is cached on the browser, which is why you are not seeing your changes. Either send the proper Cache-control and Expires headers, or append a random identifier to the image url (?_=$x where $x = time() will work fine... Headers are preferred).
Sending the proper Content-type header?
Not sending the proper headers might cause erratic behavior in some browsers. You might want to try using header('Content-type: image/jpeg')
Sending only the image data without any extra characters?
Make sure you don't output anything else than the image. Your output stream must not have any extra characters, including whitespaces.
Try hit refresh! Or clear cache and reload.
This is because the image is saved in browsers cache, and browser know it has it, but it doesn't know it has been changed. One of the tricks is to save the image on the server side with randomly generated name.
I would suspect you aren't sending an appropriate Content-Type header for the image. Alternatively, the image may be slightly corrupted (commonly caused by spaces before/after the php tags in your source code). Save the image from Firefox on your hard drive, open it in a text editor (such as Editplus) and check it doesn't start or end with a space.
PHP is server side, so if it works on one browser the code works fine and the issue lies with the browser. I would assume that IE and opera are caching the image. If possible set the headers for the images so that they don't get cached:
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past

Categories