XAMPP and the PHP CLI

Like a lot of people I do most of my development work on windows PC and locally run a web a server and database. Like a a lot of people I just downloaded and installed a server bundle. For the last few years I have used Apache2triad and it has generally been pretty painless, but I’ve recently been forced to abandon it. Unfortunately the development seems to have been abandoned about 2 years ago.

The reason I abandoned Apache2triad was PHP versions – I wanted to do some work with Google Base using the Zend Google Data Library which required PHP 5.1.4+.

Looking around at the various bundles I decided to go with XAMPP – a lot of people seem to use it and it seems to get pretty good feedback. I won’t say the process was entirely painless (it took a couple of goes to get everything up and running) but eventually it all seemed OK.

The fun started when I decided to do a bit of baking (generating scaffolding code for my CakePHP app from a command line interface). Nothing worked.

Looking into it I discovered more than I wanted to know about the PHP Command Line Interface (CLI) which I had happily used for years with no idea it actually existed, having assumed it was just there as part of PHP.

After a lot googleing and a lot of trial and error I got it all working again and this is how I did it.

My environment is Windows XP Pro Service Pack 2 with XAMPP installed on E:/

  1. Downloaded the latest version of PHP and replaced the entire contents of E:\xampp\php\.
  2. Added to the E:\xampp\php to my environment PATH.

At this stage PHP CLI wwas now working but there were nasty errors e.g. I was uanble to connect to MySQL from scripts. I discovered that this is because PHP CLI uses a different php.ini file to regular PHP.

To fix this I copied my php.ini from E:\xampp\apache\bin\php.ini (the default XAMPP ini file) to E:\xampp\php.

I then checked the PHP CLI again using php -v at a command prompt. There were now about 6 errors displayed, concerned with modules that could not be loaded or found. I believe that these concern modules just that aren’t meaningful in CLI mode. So I went through my new php.ini in E:\xampp\php and commented out the directives that were causing the errors until PHP CLI ran without errors.

Displaying Auth Error Messages

I feel a bit daft posting this because in the end the answer was so easy to find – but maybe it will help somebody else.

I’ve been re-writing my users / groups permission system for CakePHP 1.2 and decided to incorporate as much built in functionality as possible so I’m using the Auth Component – which is great – but one thing kept bugging me, I couldn’t for the life of me figure out how to get the messages from Auth to display in my views – but by debugging I could see they were sitting there right in the Session.

I spent a long time Googling and looking at the API for clues, eventually in desperation I looked at the cookbook (I have no idea why I hadn’t already looked there – as I use it a lot…) and the answer was both very easy and staring me right in the face.

Just pop the following in a view or layout:


if ($session->check('Message.auth')) {
		$session->flash('auth');
	}

CakePHP Calendar Helper

About six months ago I wrote a post about a Simple PHP calendar function I had written and how it was also really easy to use as a CakePHP helper.

Calendar Screenshot

I didn’t actually write the calendar specifically with Cake in mind, but I was working on a Cake site at the same time and I had a flash of inspiration. I was working on a project that needed a calendar, so I looked through all my old code but all the Calendars I had were all tied up in a terrible mess with bits of logic and SQL queries and layout all rolled into one. I looked on Google and still couldn’t find anything really easy to use – I wanted something I could just drop into place.

I suddenly realised that the way to do it was to stop trying to put any decision making into the calendar at all. The calendar only needs to display the right layout for the month and manage back and forward links. I decided to just dump the data in an array where the index corresponded to the day number (1 to 31) – the idea being that you can put anything in the array – plain text, html, javascript hooks for ajax etc.

It was in part influenced by some work I was doing using the The Yahoo! User Interface Library (YUI)
but I am very dubious about the whole notion of creating embedded calendars solely through Javascript when it could far more easily be done server side. (There is clearly a place for Javascript pop up calendars e.g. date pickers – I’m particularly fond of Marc Grabanski and Keith Woods’ version jQuery UI Datepicker)

At the time I had just moved over to using CakePHP as the main vehicle for my development work and it was clearly a great fit with the MVC setup of CakePHP – the calendar is just a shell that shows whatever you pour into it.

This is the first time I have had to go back and revisit the code, I have fixed the bugs, added some comments and set up a working example. At the moment all the logic is just sitting in the controller – but I am working on a component to tidy everything up and make it nice and portable (watch this space).

Thanks to everybody who commented or emailed me about the first version in September.

Calendar Helper


';
	
	$str .= '';
	
	$str .= '';
	
	$str .= $this->Html->link(__(‘prev’, true), array($prev_year, $prev_month));
	
	$str .= '' . ucfirst($month) . ' ' . $year . '';
	
	$str .= $this->Html->link(__(‘next’, true), array($next_year, $next_month));


	
	$str .= '';
	
	$str .= '';
	
		for($i = 0; $i < 7;$i++) {
				$str .= '' . $day_list[$i] . '';
		}
		
	$str .= '';
	
	$str .= '';
	
	$str .= '';
		
	while($day <= $days_in_month) {
		$str .= '';
			
		for($i = 0; $i < 7; $i ++) {
		
			$cell = ' ';
			
			if(isset($data[$day])) {
				$cell = $data[$day];
			}
				
			$class = '';
			
			if($i > 4) {
				$class = ' class="cell-weekend" ';
			}
			
			if($day == $today) {
				$class = ' class="cell-today" ';
			}
		
                        $first_day_in_month = strtolower($first_day_in_month);
			if(($first_day_in_month == $day_list[$i] || $day > 1) && ($day <= $days_in_month)) {
				$str .= '
' . $day . '
' . $cell . '
'; $day++; } else { $str .= ' '; } } $str .= ''; } $str .= ''; $str .= ''; return $str; } } ?>

Calendar Controller

The controller is responsible for creating the data array containing the calendar ‘events’ and then passing this on to the view from where the calendar is called.


Event->recursive = 0;
		
		$month_list = array('january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december');
		$day_list = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
		$base_url = $this->webroot . 'events/calendar'; // NOT not used in the current helper version but used in the data array
		$view_base_url = $this->webroot. 'events';
		
		$data = null;
	
		if(!$year || !$month) {
			$year = date('Y');
			$month = date('M');
			$month_num = date('n');
			$item = null;
		}
			
		$flag = 0;
				
		for($i = 0; $i < 12; $i++) { // check the month is valid if set
			if(strtolower($month) == $month_list[$i]) {
				if(intval($year) != 0) {
					$flag = 1;
					$month_num = $i + 1;
					$month_name = $month_list[$i];
					break;
				}
			}
		}
					
		if($flag == 0) { // if no date set, then use the default values
			$year = date('Y');
			$month = date('M');
			$month_name = date('F');
			$month_num = date('m');
		}
		
		$fields = array('id', 'name', 'DAY(event_date) AS event_day');
		
		$var = $this->Event->findAll('MONTH(Event.event_date) = ' . $month_num . ' AND YEAR(Event.event_date) = ' . $year, $fields, 'Event.event_date ASC');
		
		/**
		* loop through the returned data and build an array of 'events' that is passes to the view
		* array key is the day of month 
		*
		*/
		
		foreach($var as $v) {
		
			if(isset($v[0]['event_day'])) {

				$day = $v[0]['event_day'];
				
				if(isset($data[$day])) {
					$data[$day] .= '
' . $v['Event']['name'] . ''; } else { $data[$day] = '' . $v['Event']['name'] . ''; } } } $this->set('year', $year); $this->set('month', $month); $this->set('base_url', $base_url); $this->set('data', $data); } } ?>

Event Model


 array(
			'rule' => array('minLength', 2),
			'message' => 'Name must be at least 2 characters long',
			'required' => true 
										),
		'notes' => array(
			'rule' => array('minLength', 2),
			'message' => 'Please add some notes',
			'required' => true 
										),	
	);

}
?>

Calendar View


calendar($year, $month, $data, $base_url); ?>

events SQL


CREATE TABLE `events` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `event_date` datetime default NULL,
  `notes` text,
  `created` datetime default NULL,
  `modified` datetime default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1;

CSS


/* calendar CSS */
 
table.calendar {width: auto; border: 1px solid #cccccc; border-collapse: collapse; margin: 0px; padding: 0px; background-color: #ffffff;}
table.calendar th {background-color: #eeeeee; text-transform: none; color: #444444; padding: 4px; text-align: center; border: 1px solid #eeeeee;}
 
table.calendar th.cell-prev {text-align: left;}
table.calendar th.cell-next {text-align: right;}
table.calendar th.cell-header {width: 70px; border-bottom: 1px solid #cccccc;}
table.calendar td.cell-today {background-color: #e2e8f6;} /* today in the current month */
table.calendar td.cell-weekend {background-color: #F3F5EB;}
table.calendar td {border: 1px solid #cccccc;}
 
table.calendar td div.cell-number {text-align: right; font-size: 8px; color: #444444; display: block;}
table.calendar td div {display: block; font-size: 10px; text-align: left;}
table.calendar thead th {border: 1px solid #cccccc;}

To Do List

I’m feeling a little less time poor at the moment and want to do a bit of work on this. If anybody has any comments or suggestions, please let me know. At the moment my plans are as follows (in no particular order).

  • add support for internationalisation
  • put the checking date checking (and possibly data array construction into a component)
  • add built in AJAX support (haven’t decided on jQuery or Prototype yet though)
  • look at using Cake 1.2 routes as part of date checking using regular expressions (how easy would it be to combine this with the internationalisation?)

Examples & Downloads

Check out the Working Calendar Helper Example

Form data in the View

Using CakePHP all your form fields are normally populated automatically, it is easy to forget that to access the POST array all you need to do is use either:

$this->data or $this->params[‘data’]

pr(); on either of these will present you with something like:

Array
(
    [Book] => Array
        (
            [id] => 402
            [name] => Everything about Everything
            [publisher] => 
            [ISBN] => 
            [publish_date] => 15/04/2001
            [summary] => 
        )

)