Not So Random Image Rotation in PHP (…for HTML) – The Sequel

A long time ago, I wrote code to randomly rotate images, and submitted to SitePoint, and they published it.

I finally decided to post it here – and include some questions I’ve gotten over the last few years:

  1. Can I include links?
    Not with the eBay-only (HTML) style code. If you have access to the PHP, then you can keep the two items together, but if you can only reference an image link, then no. This is because the image returned has no ‘memory’, nor does the HTML link used to access it.
  2. Really?
    Not really – if you wanted to be horrendously complicated, you could remember the IP of every visitor, and the image you served them. If they clicked, then use that info to serve up the proper link. Not trivial, though.
  3. Do you have that code? Can you write it?
    No, and not unless you’re offering cash – and a fair amount of it.
  4. The image doesn’t always rotate.
    This is a problem with caching – some browsers/systems store th eimage, and so you can’t give away a new one – it isn’t asking for it! The solution (if indeed there is a comphrehensive one) is to age the headers returned – again, not trivial.

The moral of this is use the PHP version whenever possible – the image-only version was simply for specific sites like eBay, where you have no control over the page, and can only add an HTML link.

To conclude, here’s the article:

Original Article

I recently decided to create a showcase for one of my sites. I needed a row of five thumbnail images of my products, randomly displayed. I thought it would be easy to find this PHP code, but this turned out not to be the case, so I rolled up my sleeves and wrote my own. The result is a new way (at least, to me) of rotating images — I hope you’ll find it as useful as I did.

The problem was that I didn’t really want a random display. I wanted random, but without duplicates. I had about 25 images, so the chance of repeat images in a row of five was pretty good — and would be pretty unprofessional!

To further complicate the situation, I wanted to avoid using a PHP page (which would have simplified things immensely), and instead, call a PHP script from within my HTML code, something like this:

  <img src="mysite.com/rotate.php?i=0"/>
  <img src="mysite.com/rotate.php?i=1"/>
  <img src="mysite.com/rotate.php?i=2"/>

Using a parameter like ‘?i=0’ provides a way to distinguish the calls from one another. It will be the key to avoiding duplicate images.

Easy Does It – The Solution in PHP (Only)

If I was to use a PHP page, the code would be extremely simple: just take an array of image URLs, shuffle that array, then ‘deal them out’, displaying entry 0 first, then 1, then 2, and so on, like this:

  <?php
  // display a series of random images - PHP form solution
  // (c) 2004 David Pankhurst - use freely, but please leave in my credit
  $images=array( "img1.gif","img2.gif","img3.gif","img4.gif","img5.gif" );
  srand(time());
  shuffle($images);
  for ($i=0;$i<5;++$i) // display my five images
    echo "<a href='$images[$i]'>image $i</a><br>";
  ?>

But, as I needed occasionally to use an HTML form instead of PHP, I decided a PHP call from within an HTML page would be better, though this made the problem harder to solve.

The reason is that the code above is all done at once. Requests to PHP scripts are largely stateless (barring PHP sessions, which are impractical in this instance). This makes it difficult to call a script five times (once for each image), and get the same ‘state’ (shuffled order) back. But the alternative was for the images to be completely random, in which case I’d end up with duplicates.

HTML And The Other Option: srand()

To solve this problem, I used a solution much like that shown above for a single PHP script: I created a shuffled array. But this time I used the query string parameter passed (i=0, i=1, etc.) as the index to the array, to determine which picture to display.

To keep this array stable between calls, I needed a pseudo-random value, which was provided by PHP and its seeded random function, srand().

PHP’s random numbers, although random enough for most uses, are not random at all — they’re based on a seed value. This means that, if you use the same seed value each time, the sequence of ‘random’ numbers it generates will be the same. This repeatability made this function ideal for my needs, which included a shuffled image list that stayed the same for long periods of time. By seeding with the same number each time, and shuffling the list with those numbers, my array would be in the same ‘random’ order each time.

In this case, I used time() as the seed value for each call. Dividing it by 10 gave me a seed value that changed once every ten seconds, which meant that the array would stay shuffled in the same order for 10 seconds at a time.

The result is that the array appears random, but the order stays static long enough for the five PHP calls to occur — each selecting a different image from the list.

Here’s the new code:

  <?php
  // rotate images randomly but w/o dups on same page - format:
  // <img src='rotate.php?i=0'> - rotate image #0 - use 'i=1'
  // for second, etc
  // (c) 2004 David Pankhurst - use freely, but please leave in my credit
  $images=array( // list of files to rotate - add as needed
    "img1.gif",
    "img2.gif",
    "img3.gif",
    "img4.gif",
    "img5.gif" );
  $total=count($images);
  $secondsFixed=10; // seconds to keep list the same
  $seedValue=(int)(time()/$secondsFixed);
  srand($seedValue);
  for ($i=0;$i<$total;++$i) // shuffle list 'randomly'
  {
    $r=rand(0,$total-1);
    $temp =$images[$i];
    $images[$i]=$images[$r];
    $images[$r]=$temp;
  }
  $index=(int)($_GET['i']); // image index passed in
  $i=$index%$total; // make sure index always in bounds
  $file=$images[$i];
  header("Location: $file"); // and pass file reference back
  ?>

The shuffle() function has now been replaced by my own shuffle loop, partly because I wasn’t happy with the output of shuffle() in this case, and partly because I wanted to make sure ‘my’ list of random numbers was always used to shuffle the array (the key to keeping it repeatable).

The Code in Your Pages

To use this code, you’ll need to do the following:

  1. Replace the entries in $images with your own (including the path as needed).
  2. Change the $secondsFixed to decide for how long the list will stay the same before it’s reordered. The timeframe should be large enough to allow all the PHP calls to be made easily within the time allotted.
  3. 3. Upload the script, and call it from your HTML like this:
          <img src='mysite.com/rotate.php?i=0'>image #1
          <img src='mysite.com/rotate.php?i=1'>image #2
          <img src='mysite.com/rotate.php?i=2'>image #3
            ...
    

Of course, if you have more calls than images in the array, it will wrap around; otherwise, you will get random, non-duplicating images.

One note: setting the $secondsFixed value to 10 ensures that the random list reorders every ten seconds. So, if the PHP calls for a page straddle this boundary — some within a ten second boundary, some outside it — the list could still be poorly randomized. To avoid this, you can increase the value. For instance, at 3600, the list will stay the same for an hour, and it’s the rare page load that will cross that boundary exactly.

Aside from that small hitch, this is a useful PHP technique that allows me to show a randomly-selected series of images without duplicates. I’ve already placed it successfully on one of my sites, as well as a client’s eBay auction (to ‘freshen’ the display from time to time). I hope it can prove useful to you as well.

Comments are closed.