Building a Simple Display CalendarYou'll use the date and time functions you learned in Chapter 9, "Working with Strings, Dates, and Times," to build a calendar that will display the dates for any month between 1980 and 2010 (those are randomly selected years and have no significanceyou can make your calendar go from 1990 to 2005 if you want). The user will be able to select both month and year with pull-down menus, and the dates for the selected month will be organized according to the days of the week. In this script, we will be working with two variablesone for month and one for yearwhich will be supplied by user input. These pieces of information will be used to build a timestamp based on the first day of the selected month. If user input is invalid or absent, the default value will be the first day of the current month. Checking User InputWhen the user accesses the calendar application for the first time, no information will have been submitted. Therefore, we must ensure that the script can handle the fact that the variables for month and year may not be defined. We could use the isset() function for this, which returns false if the variable passed to it has not been defined. However, let's use the checkdate() function instead, which not only will see if the variable exists, but will also do something meaningful with it, namely, validate that it is a date. Listing 23.1 shows the fragment of code that checks for month and year variables coming from a form, and builds a timestamp based on them. Listing 23.1. Checking User Input for the Calendar Script1: <?php 2: if (!checkdate($_POST['month'], 1, $_POST['year'])) { 3: $nowArray = getdate(); 4: $month = $nowArray['mon']; 5: $year = $nowArray['year']; 6: } else { 7: $month = $_POST['month']; 8: $year = $_POST['year']; 9: } 10: $start = mktime (12, 0, 0, $month, 1, $year); 11: $firstDayArray = getdate($start); 12: ?> Listing 23.1 is a fragment of a larger script, so it does not produce any output itself. But, it's an important fragment to understand, which is why it sits all alone here, ready for an explanation. In the if statement on line 2, we use checkdate() to test whether the month and year have been provided by a form. If they have not been defined, checkdate() returns false because the script cannot make a valid date from undefined month and year arguments. This approach has the added bonus of ensuring that the data submitted by the user constitutes a valid date. When the date is not valid, we use getdate() on line 3 to create an associative array based on the current time. We then set values for $month and $year ourselves, using the array's mon and year elements (lines 4 and 5). If the variables have been set from the form, we put the data into $month and $year variables so as not to touch the values in the original $_POST superglobal. Now that we are sure that we have valid data in $month and $year, we can use mktime() to create a timestamp for the first day of the month (line 10). We will need information about this timestamp later on, so on line 11, we create a variable called $firstDayArray that will store an associative array returned by geTDate() and based on this timestamp. Building the HTML FormWe now need to create an interface by which users can ask to see data for a month and year. For this, we will use SELECT elements. Although we could hardcode these in HTML, we must also ensure that the pull-downs default to the currently chosen month, so we will dynamically create these pull-downs, adding a SELECT attribute to the OPTION element where appropriate. The form is generated in Listing 23.2. Listing 23.2. Building the HTML Form for the Calendar Script1: <?php 2: if (!checkdate($_POST['month'], 1, $_POST['year'])) { 3: $nowArray = getdate(); 4: $month = $nowArray['mon']; 5: $year = $nowArray['year']; 6: } else { 7: $month = $_POST['month']; 8: $year = $_POST['year']; 9: } 10: $start = mktime (12, 0, 0, $month, 1, $year); 11: $firstDayArray = getdate($start); 12: ?> 13: <html> 14: <head> 15: <title><?php echo "Calendar:".$firstDayArray['month']." 16: ".$firstDayArray['year'] ?></title> 17: <head> 18: <body> 19: <h1>Select a Month/Year Combination</h1> 20: <form method="post" action="<?php echo "$_SERVER[PHP_SELF]"; ?>"> 21: <select name="month"> 22: <?php 23: $months = Array("January", "February", "March", "April", "May", 24: "June", "July", "August", "September", "October", "November", "December"); 25: for ($x=1; $x <= count($months); $x++) { 26: echo"<option value=\"$x\""; 27: if ($x == $month) { 28: echo " SELECTED"; 29: } 30: echo ">".$months[$x-1].""; 31: } 32: ?> 33: </select> 34: <select name="year"> 35: <?php 36: for ($x=1980; $x<=2010; $x++) { 37: echo "<option"; 38: if ($x == $year) { 39: echo " SELECTED"; 40: } 41: echo ">$x"; 42: } 43: ?> 44: </select> 45: <input type="submit" value="Go!"> 46: </form> 47: </body> 48: </html> Having created the $start timestamp and the $firstDayArray date array in lines 211, let's begin to write the HTML for the page. Notice that we use $firstDayArray to add the month and year to the TITLE element on lines 15 and 16. Line 20 is the beginning of our form. To create the SELECT element for the month pull-down, we drop back into PHP mode on line 22, to write the individual OPTION tags. First, we create an array called $months in lines 23 and 24 that contains the names of the 12 months, for display purposes. We then loop through this array, creating an OPTION tag for each name (lines 2531). This would be an overcomplicated way of writing a simple SELECT element, were it not for the fact that we are testing $x (the counter variable in the for statement) against the $month variable on line 27. If $x and $month are equivalent, we add the string SELECTED to the OPTION tag, ensuring that the correct month will be selected automatically when the page loads. We use a similar technique to write the year pull-down on lines 3642. Finally, back in HTML mode, we create a submit button on line 45. We now have a form that can send the month and year parameters to itself, and will default either to the current month and year, or the month and year previously chosen. If you save this listing as dateselector.php, place it in your Web server document root, and access it with your Web browser, you should see something like Figure 23.1 (your month and year may differ). Figure 23.1. The calendar form.
Creating the Calendar TableWe now need to create a table and populate it with dates for the chosen month. We do this in Listing 23.3, which represents the complete calendar display script. While line 2 is new, lines 347 come right from Listing 23.2. Line 2 simply defines a constant variable, in this case ADAY (for example, "a day") with a value of 86400. This value represents the number of seconds in a day, which will be used later in the script. Listing 23.3. The Complete Calendar Display Script1: <?php 2: define("ADAY", (60*60*24)); 3: if (!checkdate($_POST['month'], 1, $_POST['year'])) { 4: $nowArray = getdate(); 5: $month = $nowArray['mon']; 6: $year = $nowArray['year']; 7: } else { 8: $month = $_POST['month']; 9: $year = $_POST['year']; 10: } 11: $start = mktime (12, 0, 0, $month, 1, $year); 12: $firstDayArray = getdate($start); 13: ?> 14: <html> 15: <head> 16: <title><?php echo "Calendar: ".$firstDayArray['month']." 17: ".$firstDayArray['year'] ?></title> 18: <head> 19: <body> 20: <h1>Select a Month/Year Combination</h1> 21: <form method="post" action="<?php echo "$_SERVER[PHP_SELF]"; ?>"> 22: <select name="month"> 23: <?php 24: $months = Array("January", "February", "March", "April", "May", 25: "June", "July", "August", "September", "October", "November", "December"); 26: for ($x=1; $x <= count($months); $x++) { 27: echo"<option value=\"$x\""; 28: if ($x == $month) { 29: echo " SELECTED"; 30: } 31: echo ">".$months[$x-1].""; 32: } 33: ?> 34: </select> 35: <select name="year"> 36: <?php 37: for ($x=1980; $x<=2010; $x++) { 38: echo "<option"; 39: if ($x == $year) { 40: echo " SELECTED"; 41: } 42: echo ">$x"; 43: } 44: ?> 45: </select> 46: <input type="submit" value="Go!"> 47: </form> 48: <br> 49: <?php 50: $days = Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); 51: echo "<TABLE BORDER=1 CELLPADDING=5><tr>\n"; 52: foreach ($days as $day) { 53: echo "<TD BGCOLOR=\"#CCCCCC\" ALIGN=CENTER><strong>$day</strong></td>\n"; 54: } 55: for ($count=0; $count < (6*7); $count++) { 56: $dayArray = getdate($start); 57: if (($count % 7) == 0) { 58: if ($dayArray['mon'] != $month) { 59: break; 60: } else { 61: echo "</tr><tr>\n"; 62: } 63: } 64: if ($count < $firstDayArray['wday'] || $dayArray['mon'] != $month) { 65: echo "<td> </td>\n"; 66: } else { 67: echo "<td>".$dayArray['mday']." </td>\n"; 68: $start += ADAY; 69: } 70: } 71: echo "</tr></table>"; 72: ?> 73: </body> 74: </html> We pick up the new code at line 48. Because the table will be indexed by days of the week, we loop through an array of day names in lines 5254, printing each in its own table cell, on line 53. All the real magic of the script happens in the final for statement beginning on line 55. In line 55, we initialize a variable called $count and ensure that the loop will end after 42 iterations. This is to make sure that we will have enough cells to populate with date information, taking into consideration that a 4-week month may actually have partial weeks at the beginning and the end, thus the need for six 7-day weeks (rows). Within this for loop, we transform the $start variable into a date array with geTDate(), assigning the result to $dayArray (line 56). Although $start is the first day of the month during the loop's initial execution, we will increment this time-stamp by the value of ADAY (24 hours) for every iteration (see line 68). On line 57, we test the $count variable against the number 7, using the modulus operator. The block of code belonging to this if statement will therefore only be run when $count is either zero or a multiple of 7. This is our way of knowing whether we should end the loop altogether or start a new row, where rows represent weeks. After we have established that we are in the first iteration or at the end of a row, we can go on to perform another test on line 58. If the mon (month number) element of the $dayArray is no longer equivalent to the $month variable, we are finished. Remember that $dayArray contains information about the $start time-stamp, which is the current place in the month that we are displaying. When $start goes beyond the current month, $dayArray['mon'] will hold a different figure than the $month number provided by user input. Our modulus test demonstrated that we are at the end of a row, and the fact that we are in a new month means that we can leave the loop altogether. Assuming, however, that we are still in the month that we are displaying, we end the row and start a new one on line 61. In the next if statement, on line 64, we determine whether to write date information to a cell. Not every month begins on a Sunday, so it's likely that our rows will contain an empty cell or two. Similarly, few months will finish at the end of one of our rows, so it's also likely that we will have a few empty cells before we close the table. We have stored information about the first day of the month in $firstDayArray; in particular, we can access the number of the day of the week in $firstDayArray['wday']. If the value of $count is smaller than this number, we know that we haven't yet reached the correct cell for writing. By the same token, if the value of the $month variable is no longer equal to $dayArray['mon'], we know that we have reached the end of the month (but not the end of the row, as we determined in our earlier modulus test). In either case, we write an empty cell to the browser on line 65. In the final else clause on line 66, we can do the fun stuff. We have already determined that we are within the month that we want to list, and that the current day column matches the day number stored in $firstDayArray['wday']. Now we must use the $dayArray associative array that we established early in the loop to write the day of the month and some blank space into a cell. Finally, on line 68, we need to increment the $start variable, which contains our date stamp. We simply add the number of seconds in a day to it (we defined this value in line 2), and we're ready to begin the loop again with a new value in $start to be tested. If you save this listing as showcalendar.php, place it in your Web server document root, and access it with your Web browser, you should see something like Figure 23.2 (your month and year may differ). Figure 23.2. The calendar form and script.
Adding Events to the CalendarDisplaying the calendar is great, but in just a few extra lines of code, you can make it interactivethat is, you can add and view events on a given day. To begin, let's create a simple database table that holds event information. For purposes of simplicity, these events will only occur on a single day, and only their start date and time will be shown. Although you can make the event entries as complex as you'd like, this example is here just to show the basic process involved. The calendar_events table will include fields for the start date and time, the event title, and an event short description: CREATE TABLE calendar_events ( id int not null primary key auto_increment, event_title varchar (25), event_shortdesc varchar (255), event_start datetime ); We can use the code in Listing 23.3 as our base (the script called showcalendar.php). In this new script, we'll add a link to a popup window as part of the calendar display. Each date will be a link; the popup window will call another script that will display the full text of an event as well as the ability to add an event. To begin, add the following JavaScript code after the opening <HEAD> tagafter line 15 of the original script: <SCRIPT LANGUAGE="JavaScript"> function eventWindow(url) { event_popupWin = window.open(url, 'event', 'resizable=yes, scrollbars=yes, toolbar=no,width=400,height=400'); event_popupWin.opener = self; } </SCRIPT> This JavaScript function just defines a 400x400 window, which will call a URL that we provide. We use this JavaScript function at what was line 67 of the original script; we now wrap the date display in this link to the JavaScript-based popup window, which calls a script named event.php. The new line is shown: echo "<td><a href=\"javascript:eventWindow('event.php?m=".$month."&d= ".$dayArray['mday']."&y=$year');\">".$dayArray['mday']."</a> </td>\n"; Not only do we call the event.php file, but we have to send along with it the date information for the particular link that is clicked. This is done via the query string, and you can see we're sending along three variables: $_GET[m] for the month, $_GET[d] for the day, and $_GET[y] for the year. Only one change remains for this particular script, before we tackle the event.php scriptadding an indicator to this particular view, if events do indeed exist. To do this, we have to connect to the database, so after the opening PHP tag at the original line 1, add the database connection code: $conn = mysql_connect("localhost", "joeuser", "somepass") or die(mysql_error()); mysql_select_db("testDB",$conn) or die(mysql_error()); The query that checks for existing events on a given day, it appears at the onset of the else statement that was originally found at line 66. An entirely new else statement is shown, where you can see that the query is issued and, if results are found, text is printed within the table cell for that day: } else { $chkEvent = "SELECT event_title FROM calendar_events WHERE month(event_start) = '$month' AND dayofmonth(event_start) = '".$dayArray['mday']."' AND year(event_start) = '$year' ORDER BY event_start"; $chkEvent_res = @mysql_query($chkEvent) or die(mysql_error()); if (@mysql_num_rows($chkEvent_res) > 0) { while ($ev = @mysql_fetch_array($chkEvent_res)) { $event_title = stripslashes($ev['event_title']); $event_title_txt .= "$event_title <br>"; } } echo "<td><a href=\"javascript:eventWindow('event.php?m=".$month." &d=".$dayArray['mday']."&y=$year');\">".$dayArray['mday']."</a> <br><br> $event_title_txt </td>\n"; unset($event_title_txt); $start += ADAY; } In Listing 23.4, you can see the entirely new script, which we'll call showcalendar_withevent.php. Listing 23.4. Calendar Display Script with Entry-Related Modfications1: <?php 2: $conn = mysql_connect("localhost", "joeuser", "somepass") 3: or die(mysql_error()); 4: mysql_select_db("testDB",$conn) or die(mysql_error()); 5: define("ADAY", (60*60*24)); 6: if (!checkdate($_POST['month'], 1, $_POST['year'])) { 7: $nowArray = getdate(); 8: $month = $nowArray['mon']; 9: $year = $nowArray['year']; 10: } else { 11: $month = $_POST['month']; 12: $year = $_POST['year']; 13: } 14: $start = mktime (12, 0, 0, $month, 1, $year); 15: $firstDayArray = getdate($start); 16:?> 17: <html> 18: <head> 19: <title><?php echo "Calendar: ".$firstDayArray['month']." ".$firstDayArray['year'] ?>< /title> 20: <head> 21: <SCRIPT LANGUAGE="JavaScript"> 22: function eventWindow(url) { 23: event_popupWin = window.open(url, 'event', 'resizable=yes, scrollbars=yes, 24: toolbar=no,width=400,height=400'); 25: event_popupWin.opener = self; 26: } 27: </SCRIPT> 28: <body> 29: <h1>Select a Month/Year Combination</h1> 30: <form method="post" action="<?php echo "$_SERVER[PHP_SELF]"; ?>"> 31: <select name="month"> 32: <?php 33: $months = Array("January", "February", "March", "April", "May", "June", "July", 34: "August", "September", "October", "November", "December"); 35: for ($x=1; $x <= count($months); $x++) { 36: echo"<option value=\"$x\""; 37: if ($x == $month) { 38: echo " SELECTED"; 39: } 40: echo ">".$months[$x-1].""; 41: } 42: ?> 43: </select> 44: <select name="year"> 45: <?php 46: for ($x=1980; $x<=2010; $x++) { 47: echo "<option"; 48: if ($x == $year) { 49: echo " SELECTED"; 50: } 51: echo ">$x"; 52: } 53: ?> 54: </select> 55: <input type="submit" value="Go!"> 56: </form> 57: <br> 58: <?php 59: $days = Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); 60: echo "<TABLE BORDER=1 CELLPADDING=5 width=95%><tr>\n"; 61: foreach ($days as $day) { 62: echo "<TD BGCOLOR=\"#CCCCCC\" ALIGN=CENTER WIDTH=14%><strong>$day</strong></td>\n"; 63: } 64: for ($count=0; $count < (6*7); $count++) { 65: $dayArray = getdate($start); 66: if (($count % 7) == 0) { 67: if ($dayArray['mon'] != $month) { 68: break; 69: } else { 70: echo "</tr><tr>\n"; 71: } 72: } 73: if ($count < $firstDayArray['wday'] || $dayArray['mon'] != $month) { 74: echo "<td> </td>\n"; 75: } else { 76: $chkEvent = "SELECT event_title FROM calendar_events WHERE 77: month(event_start) = '$month' AND 78: dayofmonth(event_start) = '".$dayArray['mday']."' AND 79: year(event_start) = '$year' ORDER BY event_start"; 80: $chkEvent_res = @mysql_query($chkEvent) or die(mysql_error()); 81: if (@mysql_num_rows($chkEvent_res) > 0) { 82: while ($ev = @mysql_fetch_array($chkEvent_res)) { 83: $event_title = stripslashes($ev['event_title']); 84: $event_title_txt .= "$event_title <br>"; 85: } 86: } 87: echo "<td><a href=\"javascript:eventWindow('event.php?m=".$month."&d= 88: ".$dayArray['mday']."&y=$year');\">".$dayArray['mday']."</a> 89: <br> <br> $event_title_txt </td>\n"; 90: 91: unset($event_title_txt); 92: 93: $start += ADAY; 94: } 95: } 96: echo "</tr></table>"; 97: ?> 98: </body> 99: </html> In Figure 23.3, you can see the new calendar, including the representation of the event title on a date that I pre-populated with an event. Figure 23.3. Showing the calendar, with an event.
All that remains is adding the all-in-one event.php script, used in the pop-up window to display and also add an event to the calendar (on a particular day). Listing 23.5 contains all the necessary code; the fun part starts at lines 89, which connect to the MySQL database. Lines 1219 look to see if the event entry form has been submitted; if it has, an INSERT statement is used to add the event to the calendar_events table before continuing. Listing 23.5. Showing Events/Adding Events via Pop-Up1: <html> 2: <head> 3: <title>Show/Add Events</title> 4: <head> 5: <body> 6: <h1>Show/Add Events</h1> 7: <?php 8: $conn = mysql_connect("localhost", "joeuser", "somepass") or die(mysql_error()); 9: mysql_select_db("testDB",$conn) or die(mysql_error()); 10: 11: //add any new event 12: if ($_POST[op] == "do") { 13: $event_date = $_POST[y]."-".$_POST[m]."-".$_POST[d]." 14: ".$_POST[event_time_hh].":".$_POST[event_time_mm].":00"; 15: 16: $insEvent = "INSERT INTO calendar_events VALUES('', '$_POST[event_title]', 17: '$_POST[event_shortdesc]', '$event_date')"; 18: @mysql_query($insEvent) or die(mysql_error()); 19: } 20: 21: //show events for this day 22: $getEvent = "SELECT event_title, event_shortdesc, 23: date_format(event_start, '%l:%i %p') as fmt_date FROM calendar_events 24: WHERE month(event_start) = '$_GET[m]' AND dayofmonth(event_start) = '$_GET[d]' 25: AND year(event_start) = '$_GET[y]' ORDER BY event_start"; 26: 27: $getEvent_res = @mysql_query($getEvent) or die(mysql_error()); 28: 29: if (@mysql_num_rows($getEvent_res) > 0) { 30: while ($ev = @mysql_fetch_array($getEvent_res)) { 31: $event_title = stripslashes($ev['event_title']); 32: $event_shortdesc = stripslashes($ev['event_shortdesc']); 33: $fmt_date = $ev['fmt_date']; 34: $event_txt .= "<P><strong>$fmt_date</strong>: $event_title<br>$event_shortdesc"; 35: } 36: } 37: 38: if ($event_txt != "") { 39: echo "<P><strong>Today's Events:</strong> 40: $event_txt 41: <hr noshade width=80%>"; 42: } 43: 44: // show form for adding an event 45: echo "<form method=post action=\"$_SERVER[PHP_SELF]\"> 46: <P><strong>Would you like to add an event?</strong><br> 47: Complete the form below and press the submit button to add the event 48: and refresh this window.</p> 49: <p><strong>Event Title:</strong><br> 50: <input type=text name=event_title size=25 maxlength=25> 51: <p><strong>Event Description:</strong><br> 52: <input type=text name=event_shortdesc size=25 maxlength=255> 53: <p><strong>Event Time (hh:mm):</strong><br> 54: <select name=event_time_hh>"; 55: for ($x=1; $x <= 24; $x++) { 56: echo "<option value=\"$x\">$x</option>"; 57: } 58: echo "</select> : 59: <select name=event_time_mm> 60: <option value=\"00\">00</option> 61: <option value=\"15\">15</option> 62: <option value=\"30\">30</option> 63: <option value=\"45\">45</option> 64: </select> 65: <input type=hidden name=m value=$_GET[m]> 66: <input type=hidden name=d value=$_GET[d]> 67: <input type=hidden name=y value=$_GET[y]> 68: <input type=hidden name=op value=do> 69: <br><br> 70: <input type=submit name=submit value=\"Add Event\"> 71: </form>"; 72:?> 73: </body> 74: </html> Lines 2127 issue the query and retrieve all records that correspond to events on this given day. The text block used to display entries is created in lines 3842. However, users also need to see the form for adding an event, and this is built in lines 4471, effectively the end of the script. In Figure 23.4, we see how a pop-up looks when a link is followed from the calendar and an entry is already present. In this example, we wanted to add another event on this day, so the form has been completed in preparation for adding the additional event. Figure 23.4. Showing the day detail, ready to add another event.
In Figure 23.5, the second event has been added to this particular day. Figure 23.5. A second event has been added.
Obviously, this is a simple example, but shows that it is indeed simple to built a little calendar type of system in just a few short scripts. |