Home arrow PHP Tutorials

Translate This Website
Sunday, 07 September 2008
Web Development
Request a Quote
Script Categories
RSS Media Grabber Funny Videos & Pictures Life Stories (Flash) Video Search & Download Video Downloader Script Country on Sale Advanced Polls Phone Upload/SMS Scripts PhotoCube Script SlideShow Creation Script Make Confessions Scripts Guitar Tabs Scripts Create Custom Smiley Script Short URLs & Subdomains Hot Or Not Game Scripts Put your text on images Watermark & Image Hosting Joomla Components Low Cost Scripts
Partners
WEBSITE TRAFFIC
Pissed Customers
Credit Cards
Broadband Tweaks & Info
eBay Sniping Software
Custom Programming
Scripts and Stuffs
Hot php scripts
Add your scripts
Script Search
php scripts directory
script heaven
the cgi site
Scripts
Software Development
Free Icons
SEO Services


PHP Calendar Tutorial Print E-mail

Sometimes telling what day it is can be a task for even the smartest of people. Therefore, we can create cool stuff in PHP such as calendars and stick them on our websites to show off your mad coding skills as a PHP developer. In this tutorial, we're going to create a calendar using PHP. There may be simpler ways of creating a calendar than the examples in this tutorial, but that's ok because we're going to practice using some advanced arrays, date/time functions and work on utilizing some other features of PHP that you may not be familiar with.

Grab yourself a cup of coffee, soda, smoke or whatever your pleasure is because this tutorial could make your head hurt, I know my head hurt when coming up with this code!

Before we begin tearing into this calendar, I want you to understand that we are not making this object oriented by creating a function or a class for it. The reason is I want this to tutorial to be as basic as possible, plus it will allow room for a follow-on tutorial that I have planned to show you how to utilize this calendar to it's full potential.

Also, you may want to view the screen shot below in Figure 1.1 to understand what the calendar will look like. Additionally, you can click on this hyperlink to view the calendar in action.


Planning and Concept

Planning a calendar shouldn't be too hard right? Well, have you thought about all of the variables involved in creating a calendar that will do exactly what we need? A true calendar can be a PHP developers' logic nightmare. The calendar that I came up with uses an HTML table that has seven columns across and starts with Sunday in the first column and ends on Saturday on the right column. Then I had to make it dynamic enough to figure out how many weeks are in the month. Sometimes days start at the end of the week and could create a problem for you to create another row in your table.

It's fairly easy to figure out how many days are in the current month by using PHP, but how about How many days are in the last month? That's pretty easy to do also, however what method would we use to merge those two values together to fit the HTML table properly? Also, what if we want to shade the days that are outside of the month? Well, this tutorial will show you how to figure all of that out.

There's more concepts than I care to try to explain up front, so we'll break things down in this tutorial in depth.

PHP Configuration

This calendar requires a special option to be enabled when you configure PHP. The option flags on Linux are: --enable-calendar in your configuration directives. In Windows, I believe you do not have to do anything special if you installed from the PHP Installer found at php.net/downloads.php

Additionally, we are going to be turning error_reporting and display_errors off in the actual code of this script. Is this good habbit? Sure. As long as it functions properly, then you don't need to see every little error and warning that PHP encounters, so we'll be fine. Besides, on a production server, I highly recommend shutting error_reporting AND display_errors completely off. If you need to debug something, you'll know when to turn it back on.

 Let's begin by setting up some standard HTML for this file. We'll be assigning styles to different elements of the calendar, so I decided to create some styles for it below.

<html>
<
head>
<
title>PHP Calendar</title>
<
style type="text/css">
<!--

The first style is the table outline of the calendar. I used a collapse method of the border as shown here.

.table.calendar {border1px solid #000000; border-
collapse: collapse; color: #000000; background: #FFFFFF; }

The next style is for the table cell of the selected date. For example, if we selected July 18th, then the cell with the date of "18" would be shaded.

.td.today border1px solid whitecolor#000000;
 background: #EFEFEF; font-weight: bold;}

The next style is used for days within the current month. It's a basic style with a 1 pixel border and the background is white.

.td.monthdays {border1px solid #434470; color: 
#000000; background: #FFFFFF;}

The last style is "nonmonthdays" for days that are displayed in the calendar but fall outside of the selected month that is displayed.

.td.nonmonthdays border1px solid white
color#000000; background: #EFEFEF;}
-->
</
style>
<
body>

Let's jump into the PHP code. I started PHP with the open tag and then set the error_reporting level to 0. This ensures that no errors will be reported or displayed to the browser.

<?php
error_reporting
('0');
ini_set('display_errors''0');

Next, we are going to determine which arguments have been passed to the script by the querystring value of date. Example: cal.php?date=XXXXXXXXXX where XXXXXXX is the timestamp of the day and month we wish to view. If no date argument has been passed to the script, we will set the current date to today. We determine this method by using the isset() by checking if an error is returned from the Boolean. If no date argument is passed, then we'll set one.


// Gather variables from
// user input and break them
// down for usage in our script

if(!isset($_REQUEST['date'])){

If no date argument is passed, then we'll set one by using the mktime() function for the current month, date and year.


   $date 
mktime(0,0,0,date('m'), date('d'), 
date('Y'));
} else {

In the ELSE portion of this statement, we have determined that the date argument was set, so therefore we'll use the date passed to the script.


   $date 
$_REQUEST['date'];
}

Note: the previous example regarding the date argument could have been reversed, depending on your preference. I don't like typing some code over and over again, especially functions. In this script, we're going to be using the $day, $month, $year values that we set here by using the date() function.

$day date('d'$date);
$month date('m'$date);
$year date('Y'$date);

Alright, now we are going to dig into figuring out exactly how to determine the best method of finding information about the current month we are viewing. We start by setting variable named $month_start which is a timestamp of the very first second of the very first day for the current month and year being displayed. We'll use this variable later when we need it, for now, I am just setting up my script with easy variables to use later on.


// Get the first day of the month
$month_start mktime(0,0,0,$month1$year);

At the top of our table, we are going to be displaying the abbreviated month name, so I grab this and turn it into a variable by using the date() function again with the 'M' descriptor.


// Get friendly month name
$month_name date('M'$month_start);

Here's where things start to get tricky. We need to figure out what day of the week the first of the month is. So, we can use date function once again by using that $month_start variable we created earlier. The output of this would be "Sun, Mon, Tue…." And so on.


// Figure out which day of the week
// the month starts on.
$month_start_day date('D'$month_start);

Now that we have determined which day of the week the month starts on, we are going to create a number I call "offset" based on the values returned by the $month_start value. The output of this script would be a number. For example, if the month starts on a Sunday, the offset will be '0' and this we now know that we don't have to determine how many days from the previous month to enter into the table. On another note, if the start of the month is a Wednesday, we'll need to set an offset of '3' and then we'll utilize 3 days from the previous month to make our HTML table line up properly. Confused? If so, keep reading, this should make more sense later when we use the $offset value.

switch($month_start_day){
    case 
"Sun"$offset 0; break;
    case 
"Mon"$offset 1; break;
    case 
"Tue"$offset 2; break;
    case 
"Wed"$offset 3; break;
    case 
"Thu"$offset 4; break;
    case 
"Fri"$offset 5; break;
    case 
"Sat"$offset 6; break;
}

We now know how many columns we need to move the first of the month over by the $offset value. But wait! How many days were in the month before this one? Were there 28, 29, 30 or 31? How will we fill in the cells before the first of the month with the appropriate values? Here, we'll use the PHP calendar functions to determine that. Uh oh! Wait a second? Have you thought about if the current month was January 2002? How would we get the number of days for December of 2001? Well, we use an IF statement to check if the current month is set to '1' indicating that we are on January. If it is, then we'll utilize a separate set of instructions for the cal_days_in_month function.


// determine how many days are in the last month.
if($month == 1){
   
$num_days_last cal_days_in_month(012, ($year -1));
} else {
   
$num_days_last cal_days_in_month(0, ($month -1), $year);
}

Ok, now that we have determined the proper number of days for the last month, regardless of which month we are currently in, we can now grab the number of days for this month. There are no special rules we need to follow here, so we'll just use the standard cal_days_in_month function with the $month and $year variables we created earlier.


// determine how many days are in the current month.
$num_days_current cal_days_in_month(0$month$year);

Now that we have the days of this month and the previous month figured out, we'll jump into some building some arrays to work with. We'll build our arrays using the for loop on the $num_days_current variable and increment the $i value each time the loop is passed until we have created an array element for each day in the month.


// Build an array for the current days
// in the month
for($i 1$i <= $num_days_current$i++){
    
$num_days_array[] = $i;
}

The next code portion is the same as the previous one, except we are going to create a new array for the number of days for the last month.


// Build an array for the number of days
// in last month
for($i 1$i <= $num_days_last$i++){
    
$num_days_last_array[] = $i;
}

At this point, we have two arrays. The $num_days_array is an array of the current days in this month and the $num_days_last_array is an array of the number of days for last month. It's time to slice and merge the appropriate values together to make the beginning of our calendar. To better understand what we are trying to do, take this into consideration. Let's say last month had 30 days and this month starts on a Wednesday. The first portion of our calendar starting with Sunday of the first week would look like this: 28, 29, 30, 1 (Wednesday). After we create the array to work with, we'll have no problems creating the first 90% of our calendar HTML.


// If the $offset from the starting day of the
// week happens to be Sunday, $offset would be 0,
// so don't need an offset correction.

if($offset 0){

Remember that $offset value we created earlier? Well, if it is greater than '0', meaning that the month start date is any day besides Sunday, we'll need to create a special array from the values.

We achieve this by using the array_slice function which will slice an array by from a certain position for the number of elements defined in the arguments of this function. In our case, we are going to create an temporary array with the last portion of the previous month to fill in the offset value with the correct days. So, we slice the $num_days_last_array array starting from the end of the array and counting backwards the number of elements we need to grab by uinsg a negative value of the $offset value and we will also set the length of the slice to the number of $offset. In simple terms, if our $offset was '3', we are going to create a new value from the last 3 elements of the array.


    $offset_correction 
array_slice
($num_days_last_array, -$offset$offset);

Now that we have our $offset_correction array which contains the days from last month we need, we'll create a new array by merging the $offset_correction (last months' days we need) and the $num_days_array (days for this month) together using array_merge. Now we have the lead in for the month plus all of the days in the month in an array! Whew, that was painful huh?


    $new_count 
array_merge
($offset_correction$num_days_array);

Now, we want to figure out how many days we currently have in the offset, so we can use the count function to count the array elements for $offset_correction. We'll use this variable later on as well.


    $offset_count 
count($offset_correction);
}

// The else statement is to prevent building 
the $offset array.
else {

If by chance the first of the month was a Sunday, we need to skip all of the offset corrections we were doing in the previous steps. We still need the $new_count later on in this script, so we'll just assign the $num_days_array to $new_count and press on with it!


    $new_count 
$num_days_array;
}

Our next task is to create a variable by counting the array elements in the $new_count array that we created previously. We'll be using this number again later as well.


// count how many days we have with the two
// previous arrays merged together
$current_num count($new_count);

Let's do a quick recap of what we have covered so far. We had to determine the month, day and year that we are going to display. If no input was found, then we set it to the current date. Next, we had to figure out how many days are in this month and what day of the week this month starts on. Based on the findings thus far, we need to build an offset value and determine how many days were in last month, then we start counting backwards to fill in the beginning of the week from the days of last month with the appropriate values.

At this point, we have built an array with the days from last month and the days from this month all merged together in the proper order.

Now that we have all of our calculations figured out, we are ready to start determining some more values that will help us build our HTML table properly. We start off by figuring out exactly how many rows we are going to need to display this calendar like it should be displayed.


// Since we will have 5 HTML table rows (TR)
// with 7 table data entries (TD)
// we need to fill in 35 TDs
// so, we will have to figure out
// how many days to appened to the end
// of the final array to make it 35 days.

If the $current_num is greater than 35 (7 days * 4 weeks), we will set the number of weeks to 6. This is how many table rows we are going to draw in this situation.


if($current_num 35){
   
$num_weeks 6;

At this point, we're going to create another variable called $outset. Let's say that our month ends on a Tuesday, well, we need to fill in the rest of the table with next months' starting dates right? Yep. So, at this point, we know we are going to be drawing 42 table cells in our calendar to represent the days. So, our outset must be 42 minus the number of days we have already and then we'll have a number to work with later on.


   $outset 
= (42 $current_num);
} elseif(
$current_num 35){

If the $current_num is less than 35, we will draw 5 rows (5 weeks) in the table

   $num_weeks 5;
   
$outset = (35 $current_num);
}

In the event that we happen to have exactly 35 days, we need to set the number of weeks to '5' and set the $outset variable to '0'. This prevents our loops that we will use later on from displaying incorrect information.


if($current_num == 35){
   
$num_weeks 5;
   
$outset 0;
}

Ok, at this point, we now know what our $outset value is, so therefore, we are going to append the keys to our $new_count array to fill in the rest of the values for the last week of the month with the number of days we need to display for next month. For example, if our month had 30 days and it ended on Thursday, we need to fill in the days for this last table row of our calendar with the days of next month until Saturday. After this next bit of code, the end of our $new_count array would be something like: 30, 1, 2.


// Outset Correction
for($i 1$i <= $outset$i++){
   
$new_count[] = $i;
}

We're getting there! Now, we are going to use a function called array_chunk which allows you to break a current array into sub arrays with chunks of the original array. Whew! Basically, we are going to create sub arrays for every 7 days to represent weeks.


// Now let's "chunk" the $new_count array
// into weeks. Each week has 7 days
// so we will array_chunk it into 7 days.
$weeks array_chunk($new_count7);

Here's a quick recap for this page. At this point, we should have an array named $weeks that has either 35 or 42. This number is obtained from the number of days in a week (7) multiplied by the number of weeks we have in this month. This array is also broken down into a sub array with the days of each week in their respective sub arrays. If you were to print_r($weeks) on this array, you should get a clear picture of what I am talking about.

Alright, we now have the correct number of weeks and days to fill each block of those weeks from the previous month, the current month and the next month. Now it's time to start working on our calendar layout some more.

We'll start off by creating two variables: $previous_link which takes the user to the previous month calendar and then $next_link which naturally displays next month's calendar.

Remember earlier when I mentioned about viewing January and going to the previous month? Well, we have to create a special link for the Previous link when viewing January and also one for viewing December to go to the next year and month.

Before I get criticized, I know that mktime allows you to use numbers like 13 as the month and it will go to January of the next year, however I prefer to keep things lined up properly and in turn, I create a link using mktime with the current year values. The links below utilize the $_SERVER['PHP_SELF'] superglobal to display the URL as the current script being executed and we also create a timestamp for the appropriate month and date clicked on by the user.


$previous_link 
"<a href=\"".$_SERVER['PHP_SELF'].
"?date=";
if(
$month == 1){
   
$previous_link .= mktime(0,0,0,12,$day,($year -1));
} else {
   
$previous_link .= mktime(0,0,0,($month -1),
$day,$year);
}
$previous_link .= "\"><< Prev</a>";

$next_link "<a href=\"".$_SERVER['PHP_SELF'].
"?date=";
if(
$month == 12){
   
$next_link .= mktime(0,0,0,1,$day,($year 1));
} else {
   
$next_link .= mktime(0,0,0,($month +1),
$day,$year);
}
$next_link .= "\">Next >></a>";

At this point, we are going to build our calendar table and setup the first two rows. The first row will display the Previous and Next links with the abbreviated month name and year inside of an imbedded table. I used an imbedded table for alignment purposes.

 
    // Build the heading portion of the calendar table
echo "<table border=\"1\" cellpadding=\"2\" cellspacing
=\"0\" width=\"300\" class=\"calendar\">\n".
     
"<tr>\n".
     
"<td colspan=\"7\">".
     
"<table align=\"center\">".
     
"<tr>".
     
"<td colspan=\"2\" width=\"75\" align=\"left\">
$previous_link</td>\n".
     
"<td colspan=\"3\" width=\"150\" align=\"center\">
$month_name $year</td>\n".
     
"<td colspan=\"2\" width=\"75\" align=\"right\">
$next_link</td>\n".
     
"</tr>\n".
     
"</table>\n".
     
"</td>\n".
     
"<tr>\n".

The next row indicates which day of the week each column is for.


"<td>S</td><td>M</td><td>T</td><td>W</td><td>T</td><td>F</td><td>S</td>\n".
     
"</tr>\n";

Now it's time to really dig in and display the calendar. What makes this code so difficult is the fact that we need to know when to shade a cell that does not belong to the current month with the appropriate style we setup in the styles of this HTML document.

Additionally we are going to determine which day of the month is selected (or today by default) and shade it accordingly.


// Now we break each key of the array 
// into a week and create a new table row for each
// week with the days of that week in the table data

We need a way to track which loop cycle we are currently using, so we will set a variable named $i with the initial value of 0. This value is outside of the for loops and will be incremented as we loop through the arrays.


$i 
0;

The next task is to loop through each of the weeks sub arrays in our $weeks array. When we do this, we want to make each sub array in the current loop cycle a new array called $week which we will use in the next loop cycle.


foreach($weeks AS $week){

We now know that we are inside of a week, so we'll draw the table row (<tr>) for this week and begin draw.

       echo "<tr>\n";

The next loop cycle will draw the table cell for the current day in the loops. We do this by looping each of the sub arrays we built earlier and breaking it down as a single variable named $d (for day).


       
foreach($week as $d){

Now it's time to get on with the really tricky stuff! We will use some advanced arguments in the IF statements below to determine how to properly shade the current day we are looping.

To start off, if the $i value is less than the $offset_count we know that this is a day from the previous month, so we will draw the table, insert the value of the array element being looped ($d) and apply the appropriate CSS style to it. While we are at it, we'll create a hyperlink to allow someone to select this day.


         
if($i $offset_count){
             
$day_link "<a href=\"".$_SERVER['PHP_SELF']."?date=".
mktime(0,0,0,$month -1,$d,$year)."\">$d</a>";
             echo 
"<td class=\"nonmonthdays\">$day_link</td>\n";
         }

If the previous IF statement was not TRUE on the result, then nothing would have been drawn yet, so we are going to check and determine if the current day being looped belongs to the month being displayed. At the same time, we need to ensure that it 1.) does not belong to the previous month and 2.) does not belong to the next month. If both of these rules are passed, then the current day must fall into the current month being displayed.


         
if(($i >= $offset_count) && ($i < ($num_weeks 7) - $outset)){

Alright, here's a catchy part. We will determine if the current day of the $date value (argument passed to the script, or set if no date argument is passed) is the same as the current day being looped for this cycle, if it is, we will not display a hyperlink and we will shade the day with the appropriate CSS style.


           
if($date == mktime(0,0,0,$month,$d,$year)){
               echo 
"<td class=\"today\">$d</td>\n";
           } else {

At this point, we know that the day in the loop cycle is not the selected day of the $date argument passed to the script, so we'll draw a hyperlink and allow our users to click on that day to select it.


               
echo "<td class=\"days\"><a href=
\"".$_SERVER['PHP_SELF']."?date=".mktime(0,0,0,
$month,$d,$year)."\">$d</a></td>\n";
           }


        } elseif(
$i >= ($num_weeks 7) - $outset) {

At this point, if all of the rules we have set previously have not drawn a cell yet, we are going to check and make sure that the current date belongs to the next month (offset) if it does, we'll draw the leadout cells to fill in the dates of next month from the end of the current month to Saturday of the last week. We will also create the hyperlinks and shade them appropriately with the CSS style we desire.


            $day_link 
"<a href=\"".$_SERVER
['PHP_SELF']."?date=".mktime(0,0,0,$month +1,
$d,$year)."\">$d</a>";
            echo 
"<td class=\"nonmonthdays\">
$day_link</td>\n";
        }

Remember that good ol' $i value? Well, it's time to increment it by 1 for the next day in our loop so that the all of the IF statements we coded will work properly.

  $i++;

Close out the for loop for $week AS $d.


      
}

Close out the table row for this current week.


      
echo "</tr>\n";   
}

Now close out your calendar table, PHP and your HTML tags and you're all done!


// Close out your table and that's it!
echo '<tr><td colspan="7" class="days"> </td></tr>';
echo 
'</table>';
?>
</body>
</html>
 

In this tutorial, we have created a calendar with PHP. Even though that was the topic, we have covered much more than just creating a calendar. The objective of this tutorial was more about showing you how to plan through the logic of creating something as complicated as this. Additionally, we also covered some advanced PHP date and time functions as well as digging a little deeper into arrays.

There is a planned follow on for this tutorial that will show you how to create a class from this calendar and perform queries within a date range of the specified month. I can't garuntee you when the follow on will be, so please be patient, there's a lot of things cooking right now.

 
Credit: phpfreaks.com 

 

 





Reddit!Del.icio.us!Facebook!Slashdot!Netscape!Technorati!StumbleUpon!Newsvine!Furl!Yahoo!Ma.gnolia!Free social bookmarking plugins and extensions for Joomla! websites!
 
Next >
Services
Script Installation
Hosting
Free Image Hosting
PageRank Checker
Login Form
On Sale
Watermark and Host Images
Watermark and Host Images
$45.00
$35.00
You Save: $10.00
Add to Cart
Home Announcements Support Newsletter Forum PHP Articles PHP Tutorials Scripts FAQs Free Scripts Links Contacts
Copyrighted © 2008 phppod.com