© 2010 . All rights reserved. 4032129960_439aecbdb8_b

Creating an online advent calendar with PHP/Javascript/Ajax

**Skip to bottom if you just want the source code and instructions**!

As the festive season approaches, everyone in Britain looks forward to an advent calendar. Actually correction. Everyone looks forward to eating the chocolate from their advent calendar.

At work, I got asked to make an interactive online advent calendar to highlight some of the wonderful historic items in our Library Archive.  I had a quick browse of the web to see if anyone else had done something similar, but the closest was some horrific html page from about 1995. Suffice to say, starting from scratch was the only option.

I first thought about what exactly people enjoyed about advent calendars and how that could be recreated digitally:

  • Chocolate
  • Anticipation
  • Self control: only open one window a day
  • Viewing the image inside the calendar
  • Chocolate

With digital chocolate entirely unsatisfying, it was down the the other things. I needed a advent calendar that would have this functionality:

  • Allow people only to open windows for that particular date, or any date before it in December.
  • Remember which windows the user had already opened, even after repeated visits each day.
  • Present the ‘goodie’ inside the window in an attractive style
  • Record that a user has visited a window before.

With these in mind, I set about thinking about the easiest way to achieve these:

  • Allow people only to open windows for that particular date, or any date before it in December.PHP Scripting
  • Remember which windows the user had already opened, even after repeated visits each day.Cookies
  • Present the ‘goodie’ inside the window in an attractive style. Thickbox
  • Record that a user has visited a window before.Ajax

Combining JQuery thickbox, with some PHP scripting and cookies should make this crazy crazy dream (!) a reality.

First the layout. I decided on using a simple table to hold all the ‘windows’ in the advent calendar.  I could have used DIVS and CSS(remember kids: Tables are a big no no for anything but tabular data, especially layout), however, it was pretty much tabular data I was using so decided to stick with tables.

I created simple content DIV with the background image as an attractive winter scene as the ‘front’ of the advent calendar:

#content{
background: url(bg.jpg) top left no-repeat;
width: 1024px ;
margin-left: auto ;
margin-right: auto ;
height:680px;

}

And then placed a table with 8 columns and 3 rows(to make the 24 windows) into this DIV. I styled the cells of the table with a background colour that was semi-transparent(solid block when mouse over), and randomly placed numbers into the cells.

td{
/* Fallback for web browsers that doesn’t support RGBa */
background: url(tp.png);
height:180px;
width:125px;
font-size:55px;
color:#000000;
text-align:center;
padding:0px;
margin:5px;
filter: expression((runtimeStyle.backgroundImage != ‘none’) ? runtimeStyle.filter = ‘progid:DXImageTransform.Microsoft.AlphaImageLoader(src=’+currentStyle.backgroundImage.split(\”)[1]+‘, sizingMethod=scale)’ : runtimeStyle.filter,runtimeStyle.backgroundImage = ‘none’);

}
td:hover{
background-color:#000000;
height:180px;
width:125px;
font-size:55px;
color:#ffffff;
text-align:center;
}

I also then downloaded and installed thickbox for the images to appear in:

<script type=“text/javascript” src=“jquery.js”></script>
<script type=“text/javascript” src=“thickbox.js”></script>

Now I had the basic layout, I had to think about the best way to prevent people clicking on the image before the time was right, but also I had to ensure that any windows that had been opened before would stay open on any subsequent visists. To do this, I decided to just create one big PHP function to do it all.  Below I’ll go into detail about this function, but to call it, I put placed the call in the table cell.

<td id=“1″><? check(1,“Theatre programme for a touring production of Billy Liar directed by Lindsay Anderson (1960).<br />
http://www.is.stir.ac.uk/libraries/collections/anderson/LA307.php “
);?></td>

The above code calls the function ‘check’ and passes in the number of the window and a brief description of the image that will appear(this is needed for thickbox creation).

The function

The first step was to create a cookie and set it to expire a long time in the future, in this case, 30 days. I used PHP cookies to check for a cookie called ‘seen’ and create one if it doesn’t exist:

session_start();

if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
//echo "cookie is".$session;
}
else{
$expire=60*60*24*30;
setcookie(“seen”, “”, time()+$expire);
//echo  "session is nowhere";
}

The main guts of the main function had two major operations:

  • check for a cookie, and assign the contents of that cookie to a variable that contains all the numbers of the days that have been visited. This would be the mechanism for ensuring the windows stay open after multiple re-visits to the page. This also allowed the page to display the correct window contents: either an open window or a closed one.
  • check the current date and ensure that the window is allowed to be open (ensure the user doesn’t eat all the electronic chocolate at once!).

To check which windows the user had opened before, I first got the cookie and assigned it to a variable called $session;

function check($num,$blurb){
if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
//echo "sesis".$session;
}
else{
$session=$_COOKIE[‘seen’]=“”;
}

I then got the current day of the month as a number, and the month number(i.e 15th Dec would be 15 and 12):

$day=date(“j”);
$month=date(“n”);

After this I needed to see what days the user had already seen before. The way I had been mainting the cookie was to have the windows(i.e days) that the user had already opened, seperated by a comma. So if a user had opened days 1-5, the cookie would contain: “1,2,3,4,5″.  To seperate the contents of this cookie, I simply use the PHP command ‘explode’ with a comma to split up that string of numbers and place it into an array:

$array=explode(“,”,$session);

This now gave me my visited windows in an array called $array.  All I had to do now was check that the number on the advent calendar was allowed to be clicked on(i.e the day has already passed), and that the user had clicked on it before or not.

if ($month ==12){

if ($num<=$day){
if (in_array($num, $array)) {
$insert=“<img src=’images/t$num.jpg’ alt=’thumbnail for $num’ style=’width:120px;height:180px;margin:0px;padding:0px;’/>”;
}
else{
$insert=$num;
}

echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" class="thickbox" onclick="sndReq(\’.$num.\’)">’.$insert.‘</a>’;

}
else{
echo (“$num”);
}

}//month !=12
else{
echo (“$num”);
}

Let’s break that down a bit:

The first thing I’m doing here is checking that the month is December to make sure no one can access any of the windows before then:

if ($month ==12){

Next, I’m checking to make sure that the window number(which is passed into the function, along with a blurb about the image that will be displayed) is less than or equal to the current day. This is the check to make sure that the user is allowed to click on the number.

if ($num<=$day){

After this, I need to do a check to see if the user has actually clicked on the window before, and if they have, they need to be presented with a thumbnail of the larger image they see in the thickbox when they click on the window. To do this, I’m simply checking to see if the passed in number ($num) exists in the array that was created from the cookie.  It assigns a string to the variable $insert that either just has the number as a clickable link, or displays a thumbnail of the image if it has been clicked on before(i.e it was in the cookie). The thumbnail image is called t+window number.jpg.  After it does this check it will print on the page either the thumbnail image or just the clickable number. Both link to the same place, it’s just whether it displays the number of the window or the thumbnail image.

if (in_array($num, $array)) {
$insert=“<img src=’images/t$num.jpg’ alt=’thumbnail for $num’ style=’width:120px;height:180px;margin:0px;padding:0px;’/>”;
}
else{
$insert=$num;
}

echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" class="thickbox" onclick="sndReq(\’.$num.\’)">’.$insert.‘</a>’;

Each link has a class as ‘thickbox’ that will open the image in a new thickbox on that page along with the description which is the ‘title=’ in the link.

You’ll noticed an ‘onclick’ action that takes place when the user clicks on the window link. This is to use Ajax to silently record the window number that the user had clicked on to the cookie of visited windows. Let’s take a look at this:

The AJAX bit

echo ‘<a href="images/’.$num.‘.jpg" title="’.$blurb.‘" onclick="sndReq(\’.$num.\’)">’.$insert.‘</a>’;

The onclick=”sndReq(\”.$num.’\')” calls a javscript function that passes in the number of the window the user just clicked on. This goes to some Ajax that then runs a PHP script to add that clicked on number to the cookie:

<script type=“text/javascript”>
function createRequestObject() {
var ro;
ro = (window.ActiveXObject) ? new ActiveXObject(“Microsoft.XMLHTTP”) : new XMLHttpRequest();

return ro;
}

var http = createRequestObject();

function sndReq(action) {
http.open(‘get’, ‘rpc.php?action=’+action);
http.onreadystatechange = handleResponse;
http.send(null);
}

function handleResponse() {
if(http.readyState == 4){
var response = http.responseText;
var update = new Array();

if(response.indexOf(‘|’) != -1) {
update = response.split(‘|’);
document.getElementById(update[0]).innerHTML = update[1];
}
}
}
</script>

The first function createRequestObject() just sets up the Ajax and then creates an instance of this request object call ‘http’. That is pretty much just a standard opener for using Ajax.

The next function ‘sndReq’ is the main meat of this ajax request.  It passes in the number of the window the user clicked in and assigns it to ‘action’ and then runs the PHP script ‘rpc.php?action=+action’ which will add the current window number to the cookie of visited windows.

Finally the ‘handleResponse’ function is there just for error handling-it returns from the rpc.php file which number was added and whether it was successful. It can then display that on the page for testing purposes.

The PHP script requested from AJAX (rpc.php)

This script is probably the easiest out the lot! It takes the window number passed in from the javascript using GET and checks again if there is a cookie called ‘seen’ and creates one if it doesn’t exist, or adds the passed in window number onto the string in the cookie, and then rewrites that cookie.  The ‘echo foo’ parts are just for error handling and testing.

<?
session_start();
$num=($_REQUEST[‘action’]);

if (isset($_COOKIE[‘seen’])){
$session=$_COOKIE[‘seen’];
$together=$session.“,”.$num;
setcookie(“seen”,$together, time()+3600);
//echo "foo| already session: $num";
}
else{
$expire=60*60*24*30;
setcookie(“seen”,$num, time()+$expire);
//echo "foo| no session";

}

?>

And that’s about it! It may seem incredibly complicated for something as silly as an advent calendar, but, outside of Flash, this was probably the easiest way to do it!

I understand that was pretty awful to follow, so worry not! I have included all the source files below. I’ve even got instructions!

  1. Create a folder on your website called whatever you want (mine was advent).
  2. Download and Extract the files in calendar1.zip file to that folder
  3. Create a folder called ‘images’ in that folder too(i.e advent\images)
  4. You can edit and change the bg.jpg file to whatever image you want-although keep the size at 1024×545 pixels.
  5. You can edit hbg.jpg too which is the header image of that page
  6. Create 24 images of whatever size you want(up to about 1024×768 pixels) and name them 1.jpg through to 24.jpg. Place these in the images folder.
  7. Create thumbnails of these images and call them t1.jpg through to t24.jpg. The thumbnail size has to be 120×180 pixels.Place these in the images folder.
  8. In index.php (from about line 183) edit all the descriptions to match the images for that particular number. Edit the ‘description here’ part.
  9. In thickbox.js edit search for any URL that is ‘http://www.is.stir.ac.uk/advent/’ and replace it with the URL of your advent calendar.
  10. Upload everything and cross your fingers!

Not sure if that was a very helpful post or not..sorry! But the end result is pretty good.

Ours is here: Try it out, all windows are accessible until the end of the month, and then you have to do it properly in December!

http://www.is.stir.ac.uk/advent/

Possible improvements: Use a MySQL database as the backend for organising the images. Plus actually randomly inserting the images every time too.

20 Comments

  1. cm
    Posted 17 Nov ’10 at 4:32 pm | Permalink

    Hi,
    I have tried your code and changed the month to 11 so i am guessing it should show just days in November.As i have tested this today i am assuming it should not open days prior than today and any days until the end of november should not open,. but it does, as today is 17 but i can open 24 th. i know it’s not december yet but should it still open even if you have not yet got the day or am i missing something. please help.

  2. admin
    Posted 17 Nov ’10 at 4:43 pm | Permalink

    Hi cm,

    Sorry, I’ve just realised that I had left a bit commented out on the code that was required.

    In index.php uncomment(i.e remove the double ‘//’ just as the line starts on the following lines):

    150ish:
    if ($month ==12){

    167-170ish:
    }//month !=12 (you can leave the second bit of comment there).
    else{
    echo (“$num”);
    }

  3. cm
    Posted 17 Nov ’10 at 4:55 pm | Permalink

    Hi,
    thanks for you quick response. I have uncommented the line as mentioned about and yes if i try and click any date nothing happens, so that’s good. But i want to test this with say this month, rather than december can i use november ?

  4. admin
    Posted 17 Nov ’10 at 5:02 pm | Permalink

    Sure thing! If you go to line 144ish in index.php and change:

    $month=date(“n”);

    to:

    $month=11;

    and then on line 150 change:

    if ($month ==12){

    to

    if ($month ==11){

  5. admin
    Posted 17 Nov ’10 at 5:02 pm | Permalink

    ps, just remember to change it back before december!

  6. cm
    Posted 17 Nov ’10 at 5:18 pm | Permalink

    Hi,
    I have changed the two places but i am still able to click dates 18-24, i have also cleared cache, cookies, history.

    BTW your script great!

    • admin
      Posted 17 Nov ’10 at 5:39 pm | Permalink

      ah, another line I forgot to comment out!

      Just deleted or comment out line 143:
      $day=25

      so then it will actually pick up todays date from the server rather than thinking its the 25th.

  7. cm
    Posted 18 Nov ’10 at 8:55 am | Permalink

    Thanks once again, i’ve just tested this and it works like a charm. this line $day=25 , do i need to active this in december or just leave it out.

    • admin
      Posted 18 Nov ’10 at 10:06 am | Permalink

      No problem! You can keep the $day=25 line deleted permenently, it was just so I could check all the days were opening fine up to christmas.

  8. cm
    Posted 18 Nov ’10 at 12:24 pm | Permalink

    Thank for all you help. It works GREAT!

  9. admin
    Posted 18 Nov ’10 at 1:28 pm | Permalink

    Glad it was helpful CM. You got a link to the calendar you’ve created?

  10. Cm
    Posted 18 Nov ’10 at 2:45 pm | Permalink

    I do not have a live link yet just testing on my local machine, when i do i will post online.

  11. Hakan
    Posted 25 Nov ’10 at 5:46 pm | Permalink

    Hi, Nice script!

    Is there a way to make the image ex 1.jpg linkable?
    If I want to link to another page on each day.

    • admin
      Posted 25 Nov ’10 at 6:37 pm | Permalink

      Hi hakan,

      Unfortunately I’m over in the states at the moment getting married so am away from my computer, but I think there may be a way with modifying thickbox: http://jquery.com/demo/thickbox/ .

  12. Hakan
    Posted 25 Nov ’10 at 6:46 pm | Permalink

    Oh!
    Congratulations!

    I’ll have a look at thickbox, managed to use .gif instead of jpg though :)

    Hope you’ll have a nice wedding and a great honeymoon after that!

  13. James
    Posted 29 Nov ’10 at 9:34 pm | Permalink

    Hey!
    I am new to this, so my question may seem out of left field. I am interested in doing something like this for a holiday contest for my company. Unfortunetely we don’t have access to create on our company website so I would need to create it through a free alt website. Any suggestions? Again, I am so amateur that I probably won’t understand how to it in general, but any infor would help!

  14. CM
    Posted 30 Nov ’10 at 11:55 am | Permalink

    Hi Again,
    First of all congrats, and hope your wedding day goes as plan.
    I will understand if your not able to respond sooner.. just a quick question, is there a way i can add a print button nex to the close button, as i wanted to print the advent picture that shows.
    thanks

  15. dave
    Posted 11 Dec ’10 at 7:58 pm | Permalink

    Hi,
    I want to modify your calendar in the following ways and would appreciate any help.

    I do not want a month or date, i want it to be open for 90days

    I may wantto modify the number of windows to X where x willbe muliples of 3 between 12-24 (to keep you column and row arrangement.

    The windows will be randomly numbered and the 1st time must be opened in numerical sequence ( by each new viewer), if to difficult will just allow them to open any window.

    thanks

    dave

  16. Posted 25 Feb ’11 at 10:46 pm | Permalink

    I really liked this tutorial but I wanted to recreate the whole thing using just JavaScript and cookies to remember the doors opened etc. I created a version which displays as different game from the Scratch MIT web site for each day. You can view it at http://www.glo.li/advent and download the whole thing from http://www.glo.li/advent.zip

  17. Posted 5 Oct ’12 at 5:29 pm | Permalink

    Hi!

    Love the script and would love to use it for a project for this coming Christmas, I’m noticing that everything works great, except the cookies thing, it forgets that I’ve clicked windows after a few hours, any ideas how to stop it doing that?

    Cheers :)

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>