Add Events to the PHP Calendar
In a previous blog post I detailed how to create a basic calendar using PHP and then showed you how to add controls to that calendar. This post will detail how you may efficiently pull events from a MySQL table and display those events within the calendar.
The Event-Building PHP / SQL
$events = array();
$query = "SELECT title, DATE_FORMAT(event_date,'%Y-%m-%D') AS event_date FROM events WHERE event_date LIKE '$year-$month%'";
$result = mysql_query($query,$db_link) or die('cannot get results!');
while($row = mysql_fetch_assoc($result)) {
$events[$row['event_date']][] = $row;
}
Feel free to create the "events" table with any structure you'd like. The event date may be held in a DATE or DATETIME field. What's important is that the date is exported in YYYY-MM-DD format.
The CSS
div.day-number { background:#999; position:absolute; z-index:2; top:-5px; right:-25px; padding:5px; color:#fff; font-weight:bold; width:20px; text-align:center; }
td.calendar-day, td.calendar-day-np { width:120px; padding:5px 25px 5px 5px; border-bottom:1px solid #999; border-right:1px solid #999; }
The CSS code for the item will need to change slightly to accommodate for absolute positioning of the day. We need to apply absolute positioning so that the event text doesn't disrupt the placement of the day.
The PHP - Draw Calendar
/* draws a calendar */
function draw_calendar($month,$year,$events = array()){
/* draw table */
$calendar = '';
/* table headings */
$headings = array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
$calendar.= '';
/* days and weeks vars now ... */
$running_day = date('w',mktime(0,0,0,$month,1,$year));
$days_in_month = date('t',mktime(0,0,0,$month,1,$year));
$days_in_this_week = 1;
$day_counter = 0;
$dates_array = array();
/* row for week one */
$calendar.= '';
/* print "blank" days until the first of the current week */
for($x = 0; $x < $running_day; $x++):
$calendar.= '';
$days_in_this_week++;
endfor;
/* keep going with days.... */
for($list_day = 1; $list_day <= $days_in_month; $list_day++):
$calendar.= '';
if($running_day == 6):
$calendar.= '';
if(($day_counter+1) != $days_in_month):
$calendar.= '';
endif;
$running_day = -1;
$days_in_this_week = 0;
endif;
$days_in_this_week++; $running_day++; $day_counter++;
endfor;
/* finish the rest of the days in the week */
if($days_in_this_week < 8):
for($x = 1; $x <= (8 - $days_in_this_week); $x++):
$calendar.= '';
endfor;
endif;
/* final row */
$calendar.= '';
/* end the table */
$calendar.= '<table class="calendar" cellpadding="0" cellspacing="0"><tbody><tr class="calendar-row"><td class="calendar-day-head">'.implode('</td><td class="calendar-day-head">',$headings).'</td></tr><tr class="calendar-row"><td class="calendar-day-np"> </td><td class="calendar-day"><div style="position: relative; height: 100px;">';
/* add in the day number */
$calendar.= '<div class="day-number">'.$list_day.'</div>';
$event_day = $year.'-'.$month.'-'.$list_day;
if(isset($events[$event_day])) {
foreach($events[$event_day] as $event) {
$calendar.= '<div class="event">'.$event['title'].'</div>';
}
}
else {
$calendar.= str_repeat('<p> </p>',2);
}
$calendar.= '</div></td></tr><tr class="calendar-row"><td class="calendar-day-np"> </td></tr></tbody></table>';
/** DEBUG **/
$calendar = str_replace('',''."\n",$calendar);
$calendar = str_replace('',''."\n",$calendar);
/* all done, return result */
return $calendar;
}
function random_number() {
srand(time());
return (rand() % 7);
}
/* date settings */
$month = (int) str_pad(($_GET['month'] ? $_GET['month'] : date('m')),2,"0", STR_PAD_LEFT);
$year = (int) ($_GET['year'] ? $_GET['year'] : date('Y'));
/* select month control */
$select_month_control = '<select name="month" id="month"><option value="'.$x.'" .($x="" !="$month" ?="" :="" selected="selected" ).="">'.date('F',mktime(0,0,0,$x,1,$year)).'</option></select>';
/* select year control */
$year_range = 7;
$select_year_control = '<select name="year" id="year"><option value="'.$x.'" .($x="" !="$year" ?="" :="" selected="selected" ).="">'.$x.'</option></select>';
/* "next month" control */
$next_month_link = '<a href="?month='.($month != 12 ? $month + 1 : 1).'&year='.($month != 12 ? $year : $year + 1).'" class="control">Next Month >></a>';
/* "previous month" control */
$previous_month_link = '<a href="?month='.($month != 1 ? $month - 1 : 12).'&year='.($month != 1 ? $year : $year - 1).'" class="control"><< Previous Month</a>';
/* bringing the controls together */
$controls = '<form method="get">'.$select_month_control.$select_year_control.' <input name="submit" value="Go" type="submit"> '.$previous_month_link.' '.$next_month_link.' </form>';
/* get all events for the given month */
$events = array();
$query = "SELECT title, DATE_FORMAT(event_date,'%Y-%m-%D') AS event_date FROM events WHERE event_date LIKE '$year-$month%'";
$result = mysql_query($query,$db_link) or die('cannot get results!');
while($row = mysql_fetch_assoc($result)) {
$events[$row['event_date']][] = $row;
}
echo '<h2 style="float: left; padding-right: 30px;">'.date('F',mktime(0,0,0,$month,1,$year)).' '.$year.'</h2>';
echo '<div style="float: left;">'.$controls.'</div>';
echo '<div style="clear: both;"></div>';
echo draw_calendar($month,$year,$events);
echo '<br><br>';
We retrieve the events for the given month BEFORE calling the draw_calendar function. Doing so will allow us to avoid 27+ queries by not querying for each day. The events array is a key=>value array where the key is the date and the value is an array of events for that day. We pass that event into the draw_calendar function and when it gets to the day display DIV we run a FOREACH loop to output any events.
Tada! Happy calendar-creating!
Discussion
Be Heard!
Share your thoughts with fellow developers of all skill levels! I want to hear from you!
Thanks for the tutorial, this is a great resource for web developers just starting out!
One more great tutorial!!! Thanks David
Good tutorial. If only this would’ve been released 2 weeks ago. I was still working on a calendar bases project back then. :P
Good tut,
I think there is a bud at line 115
$events[$row['event_date']] = $row;
Should be:
$events[$row['event_date']][]= $row;
Right on SiTo — updated.
Badass. I was just randomly thinking about this the other night… how to avoid making a zillion queries when building a calendar on the fly. Makes perfect sense to query for the events first, then conditionally check for those events when building the calendar day cells.
I should show you how I handled this on a site about a year ago, almost funny now. I output a hidden list of event dates below the calendar, and then use JavaScript to read them and plug them back up into the calendar area.
David, did you ever check out the class that I wrote around this calendar? I spammed the original post with a bunch of links to it as I was working on it.
Here is what I use today:
http://pastie.org/748060
Thanks again, I use the fuck out of it
Thanks David.
Can you write an article about how to add events using php/mysql/ajax (hopefully with jquery)? Plz plz plz?
Awsome I have been waiting for this! I have a use for this in the near future but not at the very moment, does anyone have a demo of this
hello, i have some problems with the function mysql_fetch_assoc, i dont know if its only me, or i have the wrong version but i do some change and it works just right, this is what u have:
while($row = mysql_fetch_assoc()) {
$events[$row['time']][] = $row;
}
what i do is:
while($row = mysql_fetch_assoc($result)) {
$events[$row['time']][] = $row;
}
oh sorry, i change the name of the time column from event_date to time
I have the DB built, but can’t get the two connected. Any ideas on how to connect the two?
The database is connecting and I am able to print the events outside the calendar but they are not showing within the calendar. Any ideas?
Colby:
I took some time to work on this today and I am having a problem like yours. Is your events array empty?
My result set and events array both seem to be empty although the query I wrote works when using a MySQL editor.
Well, I know what my problem is, but I don’t know how to fix it.
The first part:
$query = “SELECT title, DATE_FORMAT(event_date’%Y-%c-%e’) AS event_date FROM events WHERE event_date LIKE ‘$year-$month%’”;
There is a missing comma “,” between event_date and the format type.
The second part is what I don’t know how to fix.
When you resolve the query string the $month value will be a single digit for months January through September and will not match the value in my database.
I made a test of this by inserting data into the previous month 12-2009 and it works perfectly.
So I am trying to figure out how to convert the month value in the query string to produce a two digit month like 01, 02 …
@William Rouse: Try this:
$month = str_pad($month,2,’0′, STR_PAD_LEFT);
@David Walsh: The problem is between the events array and the variable $event_day at the line “if(isset($events[$event_day])) {“.
“event_day = 2010-01-1 while events is “2010-1-1″.
$events = :Array ( [2010-1-1] => Array ( [0] => Array ( [title] => Former U.S. State Department official Alger Hiss [event_date] => 2010-1-1 ) ) [2010-1-5] => Array ( [0] => Array ( [title] => Universe created at 8:00 PM according [event_date] => 2010-1-5 ) )
The test to output to the calendar not met at
“if(isset($events[$event_day])) {” and the text is not sent to the browser. Hope that clarifes it.
I wanted to add that it seems when the data is returned at:
while($row = mysql_fetch_assoc($result)) {
$events[$row['event_date']][] = $row;
}
That is where the formatting needs to occur.
@William Rouse: I’ve updated my post. Try setting the date format in the SQL query to “%Y-%m-%D”
@David Walsh:
‘%Y-%m-%d this works for me.
“%Y-%m-%D” attaches English suffix like st, nd …
Thanks for the weekend work.
WBR
@William Rouse: Thank you William. I get data when the array is printed outside of the calendar so I know I am pinging the database correctly. However, there may be a formatting issue with my date display. Thanks for looking into this.
@William Rouse & David Walsh: Yes, thank you both for your efforts. This script has been a nice challenge to work on and will come in handy for a project I am working on.
@David Walsh: I am now able to get data onto the calendar, but no data shows up on single digit months. My SQL format is %Y-%m-%d which is includes leading zeros.
Is $month = str_pad($month,2,’0′, STR_PAD_LEFT); necessary? If so where might it fall in the code?
Yup, you’ll need to add a stri_pad.
Here is a bit of code to give you the location:
for($list_day = 1; $list_day <= $days_in_month; $list_day++):
$calendar.= '’;
/* add in the day number */
if($list_day < 10) {
$list_day = str_pad($list_day, 2, '0', STR_PAD_LEFT);
}
$calendar.= '’.$list_day.”;
$event_day = $year.’-’.$month.’-’.$list_day;
Hope that helps
WBR
@WBR Thanks,
Interesting, I added it right above the the $query
/* get all events for the given month */
$month = str_pad($month,2,”0″, STR_PAD_LEFT);
$events = array();
$query = “SELECT course_title, DATE_FORMAT(DTSTART,’%Y-%m-%d’)
The data now populates for current month and all previous months (14 total). Interestingly enough no data is showing for future months. Getting close though.
I have it in two places.
1) where you have it located.
2) In the function draw_calendar where I suggested in my last note. Search for the comment “keep going with days” and then look at my last note.
I just put in some events for 02/2010 as a quick test and they are being picked up. I have not entered any data beyond February 2010. Will check that out later tonight when I have time.
Try to locate the second location and let me know if that helps
WBR
I still can’t get anything from the db. I did get it to connect, but can’t get anything on the calendar.
http://simnar.com/calendar200.php?month=1&year=2010 A link to look at.
@William Rouse: Outstanding, adding it to the second location got me going. Thanks again William.
@William Rouse:
Yes, thanks for your help as well. Everything seems to be working!
Would it be very difficult to add a recurring event to this calendar? It’s working wonderfuly but I would like to be able to add the recurring event. Any ideas on how this would be done?
Dude, you gotta indent your code. spend more time trying to track down closing parenthesis in case of a problem than actually working at the problem.
i am having trouble getting my events to show up. i need some help. i can get the calendar to show up, but the actual events aren’t being displayed.
anyone have an idea?
for the event calendar, i have done querying the database and showing the results, but how would I “echo” in row, it in the right day of the event?
ex. Celebration week – Jan 01, 2010
@David Walsh: Would this calendar allow for events spanning multiple days? Do you have a *suggested* MySQL table layout?
@EmEhRKay: Any documentation for the class?
I’m working on a website for a small science museum in my town. I’ve been studying the calendar here and have got the basic version with the controls working. My roadblock is that the museum doesn’t have a database program or anything like that. I’ve been searching around for some way to do an event calendar based off of a flat file but I’ve come up with nothing. So if anyone has any advice for me or solutions I would love to hear them.
I can’t get this to work. I’m connecting to the DB but it’s not building the calendar with this (the events) version.
Any ideas what I’m doing wrong here? I can’t get the events into the calendar.
In my DB I have two test events, here’s the format: 2010-12-17 00:00:00
include (“../req/session.php”);
$db_link = mysql_connect(DB_SERVER, DB_USER, DB_PASS) or die(‘Cannot connect to the DB’);
mysql_select_db(DB_NAME,$db_link) or die(‘Cannot select the DB’);
/* draws a calendar */
function draw_calendar($month,$year,$events = array()){
/* draw table */
$calendar = ‘
‘;
/* table headings */
$headings = array(‘Sunday’,'Monday’,'Tuesday’,'Wednesday’,'Thursday’,'Friday’,'Saturday’);
$calendar.= ‘
‘.implode(‘
‘,$headings).’
‘;
/* days and weeks vars now … */
$running_day = date(‘w’,mktime(0,0,0,$month,1,$year));
$days_in_month = date(‘t’,mktime(0,0,0,$month,1,$year));
$days_in_this_week = 1;
$day_counter = 0;
$dates_array = array();
/* row for week one */
$calendar.= ‘
‘;
/* print “blank” days until the first of the current week */
for($x = 0; $x < $running_day; $x++):
$calendar.= '
‘;
$days_in_this_week++;
endfor;
/* keep going with days…. */
for($list_day = 1; $list_day <= $days_in_month; $list_day++):
$calendar.= '
‘;
/* add in the day number */
$calendar.= ‘ ‘.$list_day.’
‘;
if($running_day == 6):
$calendar.= ‘
‘;
if(($day_counter+1) != $days_in_month):
$calendar.= ‘
‘;
endif;
$running_day = -1;
$days_in_this_week = 0;
endif;
$days_in_this_week++; $running_day++; $day_counter++;
endfor;
/* finish the rest of the days in the week */
if($days_in_this_week < 8):
for($x = 1; $x <= (8 – $days_in_this_week); $x++):
$calendar.= '
‘;
endfor;
endif;
$event_day = $year.’-’.$month.’-’.$list_day;
if(isset($events[$event_day])) {
foreach($events[$event_day] as $event) {
$calendar.= ”.$event['title'].’
‘;
}
}
/** DEBUG **/
$calendar = str_replace(”,”.”\n”,$calendar);
$calendar = str_replace(”,”.”\n”,$calendar);
/* final row */
$calendar.= ‘
‘;
/* end the table */
$calendar.= ‘
‘;
/* all done, return result */
return $calendar;
}
function random_number() {
srand(time());
return (rand() % 7);
}
/* date settings */
$month = (int) str_pad(($_GET['month'] ? $_GET['month'] : date(‘m’)),2,”0″, STR_PAD_LEFT);
$year = (int) ($_GET['year'] ? $_GET['year'] : date(‘Y’));
/* select month control */
$select_month_control = ‘
‘;
for($x = 1; $x <= 12; $x++) {
$select_month_control.= ' ‘.date(‘F’,mktime(0,0,0,$x,1,$year)).’
‘;
}
$select_month_control.= ‘
‘;
/* select year control */
$year_range = 7;
$select_year_control = ‘
‘;
for($x = ($year-floor($year_range/2)); $x <= ($year+floor($year_range/2)); $x++) {
$select_year_control.= ' ‘.$x.’
‘;
}
$select_year_control.= ‘
‘;
/* “next month” control */
$next_month_link = ‘Next Month >>‘;
/* “previous month” control */
$previous_month_link = ‘<< Previous Month‘;
/* bringing the controls together */
$controls = ‘
‘.$select_month_control.$select_year_control.’
’.$previous_month_link.’ ’.$next_month_link.’
‘;
echo ‘
/* calendar */
body{font-size:12px;}
table.calendar{ border-left:1px solid #999;position:relative;margin:0 auto;}
td.calendar-day { height:80px;min-height:80px; font-size:11px; position:relative; }
td.calendar-day-np{ background:#eee; min-height:80px; }
th.calendar-day-head{ background:#ccc; font-weight:bold; text-align:center; width:120px; padding:5px; border-bottom:1px solid #999; border-top:1px solid #999; border-right:1px solid #999; }
div.day-number{ background:#999; padding:5px; color:#fff; font-weight:bold; float:right; margin:0px; width:20px;height:10px; text-align:center;}
/* shared */
td.calendar-day, td.calendar-day-np { width:120px; border-bottom:1px solid #999; border-right:1px solid #999;}
#controls{margin:0 auto;text-align:center;}
#controls #date{display:inline;margin:0;padding:0;}
‘;
echo ”.date(‘F’,mktime(0,0,0,$month,1,$year)).’ ‘.$year.”;
echo ”.$controls.”;
echo ”;
echo draw_calendar($month,$year,$events);
echo ”;
Sorry about the post above… didn’t think that would work and it didn’t.
Here’s a link:
http://www.codesend.com/view/8c20734d0c26121cc586a59bad27dd54/
@Colby Smart:
Colby – I seem to be stuck at the same point you were – I can get the query to work outside the calendar but can’t get the data to popluate the calendar.
What did you do to get it to work? Could you send me the working code?
@Chi Melville:
Change the uppercase “D” to a lowercase “d” in the query. Uppercase returns a day such as 1st, 2nd, etc. The lowercase returns 01, 02, etc.
Sorry, I posted before I read his issue, but I had a similar issue, I’m not finished customizing this, I’m on a separate project at the moment but have a look.
http://www.codesend.com/view/af65e27a05405a256a2391334d46f014/
I started to do an additional query for each expanded event, but then thought I’d just hide each expanded event and use reveal to expand it. I haven’t finished it but there should be enough there for you to figure out where you’re going wrong.
Hay Guys,
how can i change the month to germany or any lang?
I have now implementet this calendar on my site, but i doesn’t show the dates, it only shows the 32′th.
Any suggestions?
this code only shows ‘Sunday’,'Monday’,'Tuesday’,'Wednesday’,'Thursday’,'Friday’,'Saturday’ and the 31st day.
How is this code supposed to do anything if we keep on adding ” to calendar? The calendar in the first 2 examples worked for me …
Same here. Is something missing from the above PHP code example? I’m thinking it needs to be merged with code from the previous page. I know my database is connected.
I’ll admit it: I’m lazy and I just want to copy and paste : )
Thanks for your help, David!
@waspinator:
I’m having the same output. Any solutions?
@10ddmike: @Bo Gunnarson: @ waspinator
It looks like something may have gone wrong with the code upload. I’ve been messing with this all day and I just noticed that the HTML for the calendar build ( $calendar.=’ ‘ ) is not outputting any table tags etc. So, it’s basically appending nothingness to the $calendar HTML string that’s output. I’m in the middle of adding them all back in from the previous posts, I’ll let you know if that actually works. I’m about halfway through and I have a ugly looking bunch of calendar rows now, but at least it’s better than the 32th of the month…
Ooops. Just noticed that this probably isn’t going to work (adding in the HTML because the script builds in the dates and events and outputs all the HTML (supposedly) at the end. I think that’s where the problem is but it will take more time than copying and pasting to figure it out. Still, love to use David’s free code so I’m not complainin’.
Yeah I’m stuck also, I decided to go back to the previous code to try to figure it out. I am trying to query the db and if there is an event for the day, I want to add a little image to the calendar day instead of the actual text. Then I want to have the image be a link that will list the days events below the calendar.
I have it all pretty much squared away except for getting the images to display in the calendar.
I’ve been trying to replace this line
$calendar.= str_repeat(”,2);
but I can’t figure out how to get the images to list on the correct day
any ideas?
http://marchingrebels.org/Testing/Calendar2.php
This is all I’m getting. Any suggestions?
By doing a “View Source”, I can see your PHP is all sorts of messed up. PHP is displaying within the HTML source.
How can I fix that? All I did was copy and paste it and change the php for my own database. This code is a bit more advanced than I’m used to.
I am having the same issue as some above where the event is not showing up in the calendar. I have changed it as suggested above with the date formatting. I am getting the events from the database when I issue a print_r for the $events.
Array ( [2010-08-16] => Array ( [0] => Array ( [title] => Starts [event_date] => 2010-08-16 ) ) [2010-08-29] => Array ( [0] => Array ( [title] => Ends [event_date] => 2010-08-29 ) ) )
I think there is an issue in this section:
$event_day = $year.’-’.$month.’-’.$list_day;
if(isset($events[$event_day])) {
foreach($events[$event_day] as $event) {
$calendar.= ”.$event['title'].”;
}
}
I want it die here so I can see where it is going wrong but I am not sure where to put the ‘or die’ statement. Any suggestions?
Thanks
Nevermind. One of those d’uh moments. It is working now.
David, nice tutorial on the calendar. It is exactly what I was looking for to add to my neighborhood website. It was also nice to be able to put into practice what I have been learning in class. A another thanks to all the others with help on the extras.