Content Cycler — a content randomizer

A PHP script that selects content at random.

What is Content Cycler?

Content Cycler is a small PHP script that allows you to define groups of content, and then request a random piece of content from the desired content group. For example, you can create a content group that contains famous quotations, and then have Content Cycler return one quotation at random.

Who can use Content Cycler

Content Cycler is a very simple piece of code, so anyone can use it free of charge, so long as they agree that they are using it at their own risk. I am not liable for any loss or damage caused by the use of Content Cycler. You are permitted to modify the code — setup file and main code script — for your own use. However, you are not permitted to redistribute the code, whether or not you've modified it. If you want to let people know about Content Cycler, point them to this page.

Suggested uses of Content Cycler

Content Cycler can be used for:

How to use Content Cycler

As Content Cycler is a script written in PHP, you need to be running PHP 4 (at least version 4.0.4). I haven't yet tested in PHP 5, but I see no reason why Content Cycler would behave differently under PHP 5.

However, you must use Content Cycler at your own risk. If you choose to use the Content Cycler scripts, you agree that I am not liable for any undesirable outcome, loss or damage. I strongly recommend testing on a non-production server first.

If you want to use Content Cycler, download the zip file, then unzip it into a suitable directory that is accessible by your web server. Three PHP scripts should now be in the directory, along with a few image files. The first PHP script is called content_cycler_code.php and this is the script that does the random selection. The second script is called example_content_cycler_setup.php and this script is a working example of how to define content descriptions. The third PHP file is called test_page.php and this script generates an HTML page that contains example calls to the Content Cycler.

To test that the Content Cycler scripts work on your server, point a web browser to the file called test_page.php located in the directory where you unzipped the download.

If you see the test page, with a (crude-looking) advert graphic for Content Cycler and random quotation, definition and fact, then your server is running the PHP scripts correctly. Refresh the page to see the ad banner, quotation, definition, and fact change.

Creating your own content descriptions

All that Content Cycler really does is choose one entry in a content group array, then send the data from that entry to a specified function that uses the data to produce useful text output.

A content setup script such as example_content_cycler_setup.php must contain one or more content group arrays. Each content group array contains two or more content entries. Each content entry is an array, where the first element is a positive integer, the second element is a callback function name, and the remaining elements are the parameters that will be passed to the callback function if this content entry is selected by the cycler code. A callback function must use the parameters from the content entry to produce and return a single output string.

illustration: A graphic representation of how the code for Content Cycler fits together.

An example of a content group array definition is probably most helpful. Say we create a new content setup file called my_random_content.php and put this code into it:

// Load Content Cycler main code
include_once 'content_cycler_code.php';

// Define a content group array called fruits
$fruits = array(
    array(1, 'return_string', 'orange'),
    array(1, 'return_string', 'apple'),
    array(1, 'return_string', 'tomato'),
    array(1, 'return_string', 'lemon')
);

This (rather dull) example sets up a content group whose name is 'fruits'. It creates four content entries in the group. Every entry in this group has a weight of one (we'll get to that in a minute), and will send its parameters to the callback function named 'return_string'. The only thing that changes is the parameter list. In the case of these content entries, it's not a list but a single string that names a fruit. So if the first content entry is chosen by the cycler, the string 'orange' will be sent to the callback function 'return_string'. If the last content entry is chosen, the string 'lemon' will be sent to the callback function 'return_string'.

However, no function named 'return_string' exists in PHP, so we also have to define that in our my_random_content.php file:

function return_string($string) {
    return $string;
}

Okay, that's a simple content setup script ready to use. Now we want to use the Content Cycler to produce random output on a web page. On a (PHP-enabled) web page, we need to add PHP code that includes our content setup script (which in turn includes the Content Cycler code), then we need to call the get_random_content function with the name of a content group array. The get_random_content function should then select a content entry from the named content group array and generate output accordingly. Note that get_random_content will return false if a problem occurs, such as if the named content group does not exist. Otherwise, get_random_content will return a string.

For example, this simple page will contain a randomly-selected name of a fruit:

<html>
    <head><title>Random fruit page</title><head>
    <body>
        <?php
        include 'my_random_content.php';
        $output = get_random_content('fruits');
        echo $output;
        ?>
    </body>
<html>

There you go. The basic structure of using Content Cycler.

More advanced use of Content Cycler

The above example was very simple, as it contained only one content group array, and each content entry only contained one callback parameter. But you can create as many content setup scripts as you need, and each setup script can contain several content group arrays, and each content group array can contain content entries that have a long list of parameters. Content entries in one content group array can also name different callback functions.

All that matters is that each content group array contains content entries; that each content entry is an array whose first element is a positive integer, second element is the name of a callback function, and whose remaining elements are a set of parameters that can be successfully passed to the named callback function; and that the callback function exists and uses the provided parameter list to produce and return a string. Also remember that, when defining strings in a parameter list, PHP requires you to escape with a backslash any apostrophes or quote-marks (depending on whether you use apostrophes or quote-marks as the string delimiter) that appear inside the string.

It's also necessary to have each content setup script include the Content Cycler code using the following line:

include_once 'content_cycler_code.php';

A disorganised, but perfectly valid, example of a content setup script file could be:

<?php
    include_once 'content_cycler_code.php';

    $jumble = array(
        array(5, 'return_string', 'Just a lone string.'),
        array(2, 'combine_strings', 'I was split in two, ',
                'but now I\'m whole')
    );

    $numbers = array(
        array(1, 'add_numbers', 10, 20),
        array(1, 'multiply_numbers', 7, 9),
        array(1, 'return_string',
                '3i multiplied by negative 2i equals 6.')
    );

    function return_string($string) {
        return $string;
    }

    function combine_strings($a, $b) {
        return $a.$b;
    }

    function add_numbers($a, $b) {
        return "$a added to $b equals ".($a + $b);
    }

    function multiply_numbers($a, $b) {
        return "$a multiplied by $b equals ".($a * $b);
    }
?>

In the above example, note that the function return_string expects one parameter. So a content entry that names return_string as its callback function must provide one parameter in its parameter list. The function combine_strings expects two parameters, so a content entry that names combine_strings as its callback function must provide two parameters in its parameter list. Failure to match the parameter list to the callback function will result in script errors when that particular content entry is chosen. A mistake like this may be hard to track down, so check that parameter lists match the specified callback function.

Giving content entries different weights

Every content entry is an array whose first element is a positive integer. That integer is actually a weight, used to bias the random selection process.

When the Content Cycler is looking through a content group array, it pays attention to the weight of each content entry. A content entry whose weight is 2 is twice as likely to be picked as a content entry whose weight is 1. An entry with weight 3 is three times as likely to be chosen as an entry with weight 1. And so on.

Also, if you give a content entry a weight of 0, it will never be chosen by the Content Cycler. This allows you to disable content entries temporarily, rather than deleting them from the content setup script altogether.

The value used for each content entry's weight can be very high, but try to make the values as low as possible. For example, instead of using weights of 3500, 2500, and 4100, you should note that these values can all be divided by one-hundred without a remainder. So you'll get exactly the same effect with weights of 35, 25, and 41 instead. This should reduce the workload done by the CPU and RAM just a little.

Character encoding in the setup file

The example_content_cycler_setup.php file was created in the UTF-8 character encoding, because the pages on my website are all set to the UTF-8 character encoding. However, many sites do not use UTF-8, they use ISO-8859-1 or ASCII. Whichever character encoding you intend to use on pages that will call Content Cycler, you need to make sure you use that very same encoding when creating your own content setup script to be used on those pages. If you create and edit a content setup script file in the same editor you use to create and edit your HTML pages, you'll probably be fine.

If you create a setup file in one encoding, but ask Content Cycler to display content from that setup file on a page that uses a different encoding, then it's likely that many characters will appear incorrectly. If you've ever seen a web page full of question-marks where there should be pound-signs or apostrophes, that's almost certainly down to a mix-up in character encodings. Choose a character encoding, and stick with it across your site. That way you should not get mixed up.

I use UTF-8 because it is rich with characters that are not found in the ISO-8859-1 or ASCII character sets, such as Arabic characters. However, you may have no need for any exotic characters, so ISO-8859-1 may be enough for you.

Security issues with Content Cycler

I was originally going to create a simple PHP script that could be called using Apache server-side includes. This would have allowed the Content Cycler to be called from HTML pages that had server-side includes enabled, which would have been very convenient compared to PHP-enabling existing pages.

However, this approach had two weaknesses. Firstly, the desired content group name would have been specified by a query string. Secondly, any third-party website could have called this script and had your random content appear on their site.

Using a query string would be a bad idea because the supplied content group name is used as a key in the $GLOBALS array. And I found no way of stopping third-party websites from including the script.

So I've removed the invocation script, and I recommend you avoid using the Apache SSI method too. Even though it's not convenient having to PHP-enable a page, or several pages, it's much less open to abuse.

The Content Cycler code file and content setup files need not be in a publicly-accessible directory on your web server. So long as PHP can reach the files to include them, you can put them in any directory you like. Even though the files should produce no content if they are included remotely by a third-party website, it's probably still best to make them inaccessible to third parties. See my page about PHP file locations for more about this topic.

Feedback

If you've found this page confusing, or if you've spotted a problem or security weakness in the Content Cycler source code, or if you can suggest ways of improving the efficiency of the Content Cycler, then contact me and tell me about it.