Tuesday, December 22, 2009

Running PHP 5.2.x and 5.3 on the same webserver

I've been trying to find a nice way of setting up my development webserver to run PHP 5.2.9 and PHP 5.3 at the same time.

My goal would be to run a single webserver and add an entry in the VirtualHost entry to indicate if it should use PHP 5.2.9 or PHP 5.3. These virtual hosts should be able to run on the same port.

It should be noted that currently I use XAMPP for my development, and I'm currently using the one that distributes PHP 5.2.9 (1.7.1, I think).

I had a look around, and it looked like FastCGI could have been a solution. But then I came across this article on FastCGI and PHP 5 on Windows. I had enough troubles with an unstable server when running Xdebug. I didn't fancy inviting more trouble by running non-thread safe PHP, just to get FastCGI working.

I did try doing a few stupid things by just using the LoadFile, LoadModule and PHPINIDir directives the VirtualHost that I wanted to run PHP5.3. However, since the php5_module was already loaded, Apache just skipped over those settings.

In the end, I came across this article at Flow3. In short, you install PHP 5.3 beside your PHP5.2.9 installation, and copy the apache/conf directory to make a apache/conf-php5.3 directory and install it as a separate service that runs on its own port. It wasn't quite what I was looking for, but it will have to do for the moment.

Some points I picked up on:

  • Make sure you change all ports and Listen commands. I have extra ports for SSL virtual hosts. Make sure you remember to change these not to conflict with the original port allocations.
  • Copy the extra/httpd-xampp.conf from the 1.7.2 distribution into your conf-php5.3 area. XAMPP had radically changed how they want to setup PHP 5.3 in XAMPP 1.7.2, so you may as well go with the flow. I ended up commenting out their new security stuff at the base of the file, because Apache didnt like the IP addresses there. I'm only running a development environment, so I'm not too concerned with this.
  • Create a php5.3/modules directory and copy php5apache2_2.dll and php5apache2_2_filter.dll from apache/modules into it, and alter the LoadModule php5_module to hardcode the directory location.
  • Update the conf-php5.3/extra/httpd-ssl.conf file to point the logs to logs-php5.3. You may as well leave the conf directories where they are, so they can share the security certificates with your PHP5.2.9 installation. Unless you want them to be different.
  • Because I've installed the PHP5.3 apache as a new service, it's available in the Apache Monitor for restarting.
So far, I've only done enough to get a simple phpinfo() displaying on a virtual host. I'm sure I'll come across a few other things, like needing extra drivers for my MS SQL datasources (yeah, some projects require those).

The plus side is that I can just swap port 80 for port 81, and see how some of the sites hold up under PHP 5.3. It's just a pity that most hosted environments I have to deploy to are still using PHP 5.2.X or older.

I have seen other instructions around that do things like a whole separate installation of XAMPP, and a few tricks to make the new installation of MySQL point to the existing datastores. Usually it just involves copying around the root and pma passwords. I may end up going down this route, to save my sanity, and migrate each project from the old XAMPP installation to the newer one as conversions are done.

As a minor rant against XAMPP, I think it's shitty that they include PHP5.3 in the bundle, and only give it a minor point release. PHP5.3 has enough changes to make it a pretty big deal, and should have warranted a major XAMPP point release, like 1.8. XAMPP should also continue to release minor releases that support PHP 5.2.X and any bug fixes for Apache 2.2 and MySQL under the 1.7.X release. However, XAMPP is a convenience service that I don't have to pay anything for, so I shouldn't complain too much.

FTR, at the time of writing, the latest releases of PHP are 5.2.12 and 5.3.1. I should probably update my XAMPP installs with those anyway.

Monday, November 9, 2009

We're Adopting

We're now into our second week of looking after a cockatiel that is recovering from surgery, after being attacked by something.

Sometime at the end of last week, we made the decision. If she passes her medical check with the vet this Saturday, we will be adopting her.

Previously named Jodie Bon Jovi by the RSPCA staff, she is now known as Missy Moo, or just Missy.

She's still quite attached to me, though we're working on that. It's not that she dislikes Annika, it's just that given the choice, she will leave Annikas' place on the couch and waddle across the couch, floor and fly short distances to be on my shoulder. As a type, I have the door closed to my study, and Annika is spending quality time with her highness in front of the teev.

We'll see how things go, but we may end up getting Missy a friend so she's not so lonely during the day. Annika is hoping to get a cockatiel that likes her better than me, but I'm not sure how that's going to go. If the birds spend all day together, and actually like each other, they may also hang around together outside the cage. And if Missy is the dominant bird of the pair, that could result in both of them sharing my shoulders.

Now, as for the kitten and puupy situation. We're not going to have the fences done early enough in the new year for the puppy, so Annika has taken her name off the waiting list. And we've heard that if you get a kitten early enough, you can train it not to go after the birds. With Missy around, a kitty cat may not be possible.

Sunday, November 1, 2009

Wall Building and Bird Sitting


This weekend, for the next two weeks, it's all about wall building and bird sitting.

The wall building is fairly mundane. Two weeks ago, I commenced building a retaining wall down the side of the house with some very generous help from my brother-in-law. We got the footings in then, and a few starter block laid. This weekend, I've managed to get the first layer of the first two levels down. There are about 5 levels in all.

The bird sitting is a lot more exciting. Annika has been doing volunteer work for the RSPCA for the last few weeks. Late last week, she put her hand up to foster a cockatiel for a couple of weeks. The cockatiel, dubbed Jodie Bon Jovi, was bought in for surgery after being found, ravaged by something. Jody has a few stitches in her chest, but she seems to be recovering well. Much to Annikas' dismay, I seem to be the favourite roost.

Jodie doesn't say much, but she's very tame, loves human contact, and loves having her neck rubbed.

Best of all, I get to do pirate impersonations. Gar!

I think we're both going to miss her when she has to go back. If it wasn't for the puppy and kitten that we're going to get next year, she'd be a welcome addition to the family unit.

Friday, October 2, 2009

The Destroyer

My fingers tingle with deeds unspoken. My palms are blistered, yet comforting. My footprint, on this earth, on this land which I have made my home, shall be hard and unforgiving. The landscape that fronts my abode, that lies with weed and discarded stone shall be further torn asunder.

Front driveways, I come for you, armed with fencing post and 12 pound sledge. You have served your masters well, this past 40 years, but cycle must continue, and for this master, the cycle waxes destruction.

Um, ok. Enough with the melodramatics.

Between now and the start of next year, there are a few projects to complete around the house. A new driveway, a carport, some fencing and retaining wall that will probably come to about 30 metres long.

This weekend, I'm ripping up what I can of the existing front driveways, and will be making a start on the trench that will hold the bed of foundation for the retaining wall.

I've really got to get myself some proper leather gloves. The MTB gloves are getting torn to shreds, and dont really help when I'm driving the fencing post into the ground to lift the concrete of the old primary driveway.

Thursday, August 27, 2009

I kicked a board!

I've been doing Tae Kwon Do now for a little under six months, as a part of keeping (or getting) fit, staying active and sharing an interested with my partner. In fact, I've got a grading for my second belt (yellow with two white stripes) coming up in three weeks.

Last night at training, the instructor gave a few of the yellow belts the opportunity to break a board. I got a chance to do a front kick, as a speed break. Talk about a rush! :)

The front kick seems to be my bread and butter for non contact sparing, at the moment. It doesn't require alot of flexibility, or much upper body movement, as opposed to a round house or side kick. You can slip forward, go into a jumping front kick, and even quickly change feet on the spot to keep the opposition on their toes. So for me, the front kick isnt something I can mess up too badly, in front of my instructor and the rest of the class.

My first attempt failed to break the board, but I did kick it out of the instructors hands and it went quite vertical into the ceiling, before landing on the ground with a loud clack. And I knew why it failed. I landed the kick with the padding beside the ball of the foot, instead of the actual ball of the foot. I was still feeling pretty good about the kick. It had power, just slightly misdirected.

My second attempt nailed it. The foot snapped forward and back, and the broken part of the board went straight up, super fast. It was probably the nature of the kick, but it just didnt hurt at all.

I'll be looking forward to the next chance I get to break a board. The next board breaking kick I will need to do for a grading is a side kick, which should be about 6 months and 3 weeks away.

Other board breaking kicks I'll need to do are running side kicks, spinning back kicks, down spinning kicks and hook kicks. The down spinning kick looks like the most challenging, since the board is place vertically on the ground, and you need to spin and get your foot down low in the spin to hook your heel into the board and break it. The spinning back kick demonstrated last night didnt look all that easy, either.




Friday, June 26, 2009

PHP rounding errors

What's 2.3 * 100 - 230?

You'd expect 0, right?

Well, not so much in PHP.

PHP seems to have troubles with floating point math, even in the simplest of circumstances.

Take the following snippet of code

$r = 2.3;
echo $r.PHP_EOL;
$r = $r * 100.0;
echo $r.PHP_EOL;
echo ($r - 230).PHP_EOL;

Instead of 0 for the last echo, you get -2.8421709430404E-14.

And setting precision via ini_set() isnt going to help either. By default, precision is set to 14. Setting it to 2 will result in -2.8E-14.

To avoid rounding errors in PHP, especially when doing financial calculations that should be limited to 2 decimal places, you should round() every floating point operation with a precision of 2. Most of the time, the calculations will appear normal, but on the off chance that the value to the left of the decimal point is 0, what appears on the right might not be what you expect.

Just for clarity, I'm running PHP 5.2.8, though will be doing an upgrade to 5.2.10 in the near future.

Friday, June 19, 2009

What MS Bullshit is this?

http://www.microsoft.com/windows/internet-explorer/get-the-facts/

A work colleague sent this as a Friday giggle, but as I read through the comparison and the "myth busting", I felt the nerd rage rising.

On a technicality, some of their claims are true. For example, you may get better security in Firefox by installing the NoScript addon, or having the WebShield addon that comes with an AVG installation. But in the main, I'd still take FF3 over IE8, because if a bit of functionality wasn't available, at least FF3 has a framework to allow developers to write that needed functionality as an addon.

I'd like to call "Crap" on their Privacy claim. Of course IE8 is going to win out if "InPrivate Browsing" and "InPrivate Filtering" is used as the comparison basis. However, you can get addons like NoScript for Firefox to achieve the same thing.

I'd like to call "Crap" on the Web Standards comparison of being a tie, but I'm not sure that I can. Given that MS have released no less that 3 versions of browser that have all been an incremental improvement on the previous one, but still a disappointment on web standards compliance, I'm a bit reluctant to delve into IE8 and its specific niggles. I'd be quite happy if IE8 does live up to its CSS 2.1 claims, but there's still IE7 and IE6 I have to support.

I'd like to call "Crap" on their Developer Tools comparison. Even though the Firebug and Web Developer addons are not natively installed with Firefox, they're still head and shoulders above what MS has taken so long to bring to the table in IE8. Though I am glad IE8 has provided the tools that it has, because debugging CSS in IE7 and IE6 is a shit.

And further more, I actually like the separately downloaded tools of Firefox and Web Developer, since there seems to be a bit more active development on them. Should there be bugs in IE8, whether it be in the dev tools, or the CSS compliance, unless they're actually causing the program to crash, you'll probably have to wait until IE9 for them to get fixed.

I'm calling crap on the Compatibility claim. They only get to do that because of all the hacking you had to do to get your site to display the way you wanted it to in IE7.

I will give them the claim of Manageability, with respect to setting group policy in Active Directory. But that's about it. Considering that FF runs on more platforms than IE8, its a slim win.

The Myths.. well, they're mostly a crock too.

The speed claim is moot. Given the grunt you need to actually run a MS OS that will run IE8, and do all your other stuff, speed better not be a problem. For myself, I use FF for my development work, Chrome for my email, blogging, iGoogle and searching, and IE8 for debugging some website that doesn't display nice even though its working perfectly fine under FF, Chrome and Safari.

I'm going to throw security in the same boat. It should be secure. However, I'd stick with Chrome and FF over IE. Especially when that IE7 bug was there, that was allowing hackers to steal WoW usernames and passwords (because they sold more on the black market than credit card details).

Firefox is definitely the more adaptable browser. Their claim is that there are 1700 addons in the MS Add-on Gallery. But when I do a display all on their website, I'm getting 44 pages of results, with 12 addons to a page, and 2 addons for the last page. Thats only 518 addons. Quite a short fall from the claimed 1700.

And besides that, I dont need 1700 addons to get the job done. I only have 19 Firefox addons, and not all of those are necessary. In fact, here's a list:

Adblock Plus
English (Australian) Dictionary
Firebug
GMarks (not really used any more)
Google Gears
Google Toolbar for Firefox (not really used any more)
Java Quick Starter
Jiffy (Firebug plugin for Javascript timer measurements)
Live HTTP Headers
Microsoft .NET Framework Assistant
Net Usage Item (so I can see my home DSL usage)
NoScript
Personas for Firefox
Total Validator
Unit States English Dictionary
URL Flipper (for web based came called Imperial Galaxy)
Web Developer
Xdebug Helper (PHP debug and profile tool)
YSlow (web page performance tool)

And my favourite one is IE not playing well with Web standards. Time will tell, but I think they should have qualified that statement with IE8 not playing well with Web standards as the myth. I'm not sure if its a problem yet, but IE6 and IE7 definitely dont play well.

I've always been of the mind that if software is broke, then fix it and preferably, in that major release. MS really should have fixed their box model rubbish in IE6. Failing that, they should have fixed it in IE7. But they didnt. They should have fixed their CSS 2.0 compliance in IE7 as well, but they didnt.

Here's a little test. When looking a comparison of FF3 release dates and IE8 release dates, I found this link that highlights a few issues with CSS 2.1 compliance in IE8. Perhaps come back in 3 months, then 6 months, then 12 months and see if your latest installation of IE8 has these issues resolved. I bet they're not. And if they are, let me know :)

The nerd rage is fading now. IE8 is an improvement on IE7, but its still not a patch on FF3. I'd like MS to put their money where their collective mouths are... if IE8 is so great, then put an end of life on IE7 and IE6 so I dont have to waste time supporting the bloody things.


Wednesday, June 10, 2009

Blog Template Change

I've changed template for the blog.

Something with a bit more sideways stretch, so any code blocks can be viewed nicely.

Integrating CodeIgniter with Legacy PHP applications (Part III)

This is Part III of a blog covering how I've integrated CI into a legacy PHP application.  Part I is an introduction and Part II covers the initial replacing session creating while logging in to the application.

At the end of the last post, I was able to log into the application, and get to the initial screen, and it was making use of CIs Session class.  And I thought I was home free.

So the next thing I tried to do was use the legacy applications Search functionality to find a record.  And things did not go to plan.

As mentioned before, the application was not coded nicely, and made use of register_globals = on.  CI takes specific steps to prevent globals being used in this fashion.  Oh noes, but the application, as it stands, needs them.  It's way too much work to go through the entire application to detect all the globals and fix them.  So what was I to do?

My first step was to create a subclass of the Input class, since that is where the filtering gets done.  So I created a copy of trunk/src/legacy/libraries/Input.php and put it in trunk/src/legacy/application/libraries/MY_Input.php.  I changed it to make the class and the constructor be called My_Input (which extends CI_Input).  I kept  the contents of the constructor, and commented out the foreach() in _santize_globals() to prevent the register_globals = off processing.  All the other functions were removed, since they could be used from CI_Input.

Now, that kind of did the trick, but it wasnt what I wanted in the long run.  With newly created controllers for use in the application, I still wanted globals to be removed.  And in the My_Controller, I still wanted the Router to be initialised.

Since I only wanted My_Controller and My_Input to only ever be called for calls from the legacy application code, I decided to copy the trunk/src/legacy/application directory and call it trunk/src/legacy/legacy.  In the trunk/src/legacy/config.php, I changed the subclass_prefix variable to be 'Legacy_'.  I altered the $application_folder variable in ci_index.php to be "legacy".  I also changed the subclassed Controller and Input, now in trunk/src/legacy/legacy/libraries to be Legacy_Controller and Legacy_Input.  I could then delete the subclassed versions from trunk/src/legacy/application/libraries.  I then reverted the application/config.php to not allow querystrings.  This would mean that any new controllers would behave the way CI controllers were meant to behave, by not having querystrings, and legacy application code could still include CI sessions and use registered globals.

And that's basically it!

There's only one more item left to solve, and thats the base_url config item in config.php.

Where I work, we all run our own development environments of the same project on our local machines.  We all point to the same database for an environment, but we have our own code base and web servers.  When we're done with changing some code, it gets checked into SVN and anyone else can do an update to get those changes for that branch.  

Because we all run our own webservers, the base_url is not the same.  We all have DNS redirects to our local machines and use vhosts in Apache to have multiple environments and projects running on the same machine.  For example, the normal development URL I'd use for this product would be http://legacy-trunk.reubenh/ for the trunk release.  The current bugfix release would be found at http://legacy-bugfix.reubenh/, and the branch that I took to do this CI testing would be found at http://legacy-ci.reubenh/.  

If one of my colleagues, Corey, were to also be doing bugfixes, the URL for his bugfix release would be http://legacy-bugfix.corey/.  So hardcoding the base_url into the code base doesnt work too well for us.

I'd really like it if CI could support multiple configs per environment, but what I'll probably end up doing to putting some code in the config to try and recognise which machine it has been deployed to, and either hardcode the base_url to the production one, or just use whatever is available in $_SERVER.

I'll probably try and do a similar thing with database.php, as well, so we can deliver the code base, and not have to be concerned development database parameters being used instead of production ones.

One more thing to note.  Because we use register_globals in our legacy application, we get alot of notices about variables being used without initialisation.  This can actually stop CI in its tracks if the error_reporting is set too high.  By default, its E_ALL.  You may want to update ci_index.php to be E_ALL && ~E_NOTICE, to suppress the error handler from going nuts.  Even when you have this enabled, you may still get alot of notices in the error log, they just wont be prevent processing.  I havent bothered to figure that one our yet.  I thought the log_threshold should maybe have taken care of it, but that seems to be more about calls to log_message(), than actual PHP error reporting.

Anyway, I hope this has been instructional.  Good luck with integrating CI into your legacy application, warts and all.

(Update:  In a *nix environment, file names are case sensitive, so make sure the subclasses for Controller and Input are called Legacy_Controller.php and Legacy_Input.php, not legacy_controller.php or legacy_input.php.)

Code Blogs in Blogger

What a bloody trial it is to get code blocks to display nice in the Blogger editor.

Maybe I should just setup the email thing, and email my posts in, rather than trying to use the Blogger Editor.

Integrating CodeIgniter with Legacy PHP applications (Part II)

This is Part II of a blog covering how I've integrated CI into a legacy PHP application. Have a read of Part I for an introduction.

Firstly, a bit of background about the legacy application. To protect the client, and myself, I'm going to call it Legacy.

In SVN, the code has the following general structure:

trunk/src/legacy. This directory is where all the source code lives. There are about 30 directories under it, and a bucket load more of programs, either in those directories, or at the root level. Each sub directory has tried to split out a logical part of the system, but it hasnt worked so well. There are two items of note. One is config.inc.php, which contains the global configuration information. Its mostly about database connection information, and a few other tidbits of information relevant to the application. The other is that when deployed, the application will be accessed as https://legacy.host.com/legacy.
trunk/config. This directory contains different versions of the global configuration file. There's one for production, and there's one for development.
trunk/db. This directory contains database information, like what the latest schema looks like.

Some other things worthy of note.

The PHP ini setting register_globals is forced on. The code base was already quite large when I got it, and it was going to be too risky to go around and find all those globals and change them to $_GET or $_POST accesses. One might argue its just as risky to leave them there, but given that the application is intranet based, I figured the risk was low.

The application also runs under PHP5. Probably one of the few things that works in our favour, with regard to support for OOP.

So how did I integrate CI into the mess?

First thing was to download CI and unzip it. For reference, I used CodeIgniter 1.7.1. I put the contents of the system directory under the trunk/src/legacy directory. Luckily, I didnt have any directory name clashes.

I then set up trunk/src/index.php to rename the $system_folder to "legacy", then edited trunk/src/legacy/application/config/config.php and database.php for the base_url and database connection information. I also configured sessions to be stored in the database, as per CI Session instructions, and added a trunk/src/.htaccess file so I could skip having index.php in the URL.

Having

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]

in the .htaccess file would allow me to run the legacy application, and any new CI controllers side by side. Make sure you change the index_page in config.php to "".

Just to make sure everything was ok, I made sure I could log into the application and perform a few basic tasks. Yippee! All working.

The next step was to follow some basic guide lines from the article Calling CI models from outside script to create some stubs to allow integration with the application.

First file was a trunk/src/ci_index.php, to match index.php in CI, and config_constants.php from the article.


<?php/*
* Copy of index.php for use with legacy code
*/
/*
|---------------------------------------------------------------
| PHP ERROR REPORTING LEVEL
|---------------------------------------------------------------
|
| By default CI runs with error reporting set to ALL.  For security
| reasons you are encouraged to change this when your site goes live.
| For more info visit:  http://www.php.net/error_reporting
|
*/
error_reporting(E_ALL && ~E_NOTICE);

/*
|---------------------------------------------------------------
| SYSTEM FOLDER NAME
|---------------------------------------------------------------
|
| This variable must contain the name of your "system" folder.
| Include the path if the folder is not in the same  directory
| as this file.
|
| NO TRAILING SLASH!
|
*/
  $system_folder = "legacy";

/*
|---------------------------------------------------------------
| APPLICATION FOLDER NAME
|---------------------------------------------------------------
|
| If you want this front controller to use a different "application"
| folder then the default one you can set its name here. The folder
| can also be renamed or relocated anywhere on your server.
| For more info please see the user guide:
| http://codeigniter.com/user_guide/general/managing_apps.html
|
|
| NO TRAILING SLASH!
|
*/ 
$application_folder = "application";

/*
|===============================================================
| END OF USER CONFIGURABLE SETTINGS
|===============================================================
*/


/*
|---------------------------------------------------------------
| SET THE SERVER PATH
|---------------------------------------------------------------
|
| Let's attempt to determine the full-server path to the "system"
| folder in order to reduce the possibility of path problems.
| Note: We only attempt this if the user hasn't specified a
| full server path.
|
*/
if (strpos($system_folder, '/') === FALSE)
{
if (function_exists('realpath') AND @realpath(dirname(__FILE__)) !== FALSE)
{
$system_folder = realpath(dirname(__FILE__)).'/'.$system_folder;
}
}
else
{
// Swap directory separators to Unix style for consistency
$system_folder = str_replace("\\", "/", $system_folder);
}

/*
|---------------------------------------------------------------
| DEFINE APPLICATION CONSTANTS
|---------------------------------------------------------------
|
| EXT  - The file extension.  Typically ".php"
| FCPATH - The full server path to THIS file
| SELF  - The name of THIS file (typically "index.php")
| BASEPATH - The full server path to the "system" folder
| APPPATH - The full server path to the "application" folder
|
*/
define('EXT', '.'.pathinfo(__FILE__, PATHINFO_EXTENSION));
define('FCPATH', __FILE__);
define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
define('BASEPATH', $system_folder.'/');

if (is_dir($application_folder))
{
define('APPPATH', $application_folder.'/');
}
else
{
if ($application_folder == '')
{
$application_folder = 'application';
}

define('APPPATH', BASEPATH.$application_folder.'/');
}


/* End of file index.php */
/* Location: ./index.php */
?>


The second file was a trunk/src/ci_open.php to match a part of codeigniter/CodeIgniter.php in CI, and ci_model_remote_open.php from the article.

<?php
/*
* Copy of system/codeigniter/CodeIgniter.php
* Beginning processing and load the base controller
*/

require_once('ci_index.php');

/*
* ------------------------------------------------------
*  Load the global functions
* ------------------------------------------------------
*/
require(BASEPATH.'codeigniter/Common'.EXT);

/*
* ------------------------------------------------------
*  Load the compatibility override functions
* ------------------------------------------------------
*/
require(BASEPATH.'codeigniter/Compat'.EXT);

/*
* ------------------------------------------------------
*  Load the framework constants
* ------------------------------------------------------
*/
require(APPPATH.'config/constants'.EXT);

/*
* ------------------------------------------------------
*  Define a custom error handler so we can log PHP errors
* ------------------------------------------------------
*/
set_error_handler('_exception_handler');
set_magic_quotes_runtime(0); // Kill magic quotes


/* $CFG =& load_class('Config'); */

if (floor(phpversion()) < 5)
{
load_class('Loader', FALSE);
require(BASEPATH.'codeigniter/Base4'.EXT);
}
else
{
require(BASEPATH.'codeigniter/Base5'.EXT);
}

// Load the base controller class
$CI = load_class('Controller');
?>


The third file was a trunk/src/ci_close.php to match the last part of codeigniter/CodeIgniter.php in CI, and ci_model_remote_close.php from the article.

<?php
/*
* Copy of system/codeigniter/CodeIgniter.php
* End processing
*
*/
/*
* ------------------------------------------------------
*  Close the DB connection if one exists
* ------------------------------------------------------
*/
if (class_exists('CI_DB') AND isset($CI->db))
{
$CI->db->close();
}

?>



My first task was to convert sessions to CI Sessions. The first program to change would be the login screen. Currently functionality was to clear any sessions that existed when visiting this screen. I replaced my ugly session clearing code in trunk/src/legacy/login/login.php with
require_once('../../ci_open.php');
$CI->load->library('session');
$CI->session->sess_destroy();
require_once('../../ci_close.php');

The next step was to change the page that handled the login post to use CI sessions once the user had been authenticated.

As I'd mentioned previously, the legacy application made use of register_globals, which is nasty. The login page used them as well, so I made a small change to load this from the post, but left the rest as close to the same as I could. I ended up with this...

<?php
ini_set('register_globals', 'on');
include_once('../config.inc.php');
require_once('../../ci_open.php');
$CI->load->library('session');

$userxname = $CI->input->post('userxname');
$passxword = $CI->input->post('passxword');
/* do user authentication with username and password
* if authentication is successful:
*/
$userdata = array('logged' => 'yes', 'User' => $row['userid'], ... );
$CI->session->set_userdata($userdata);
/* near the bottom */
require_once('../../ci_close.php');
?>


Now, luckily, we do all our session checking in one place (trunk/src/legacy/login/logincheck.php). And that modification went something like:

<?php
require_once('../ci_open.php');
$CI->load->library('session');
$found = $CI->session->userdata('logged');
if ($found != "yes") { /* redirect to login page */}
?>


Now, for this one, I've left the ci_close.php out, since it closed the database connection and prevented the legacy application from any more database accesses.

That all nearly worked.

After a successful login, the page would redirect to /legacy/legacy_main_screen.php?l=y. legacy_main_screen.php would use the quest string to work out what page to run, and where to position the menu structure. However, CI was getting in the way, and tried to remove the query string. So I had to enable the query string in config.php.

The next problem was that the Router would get initialised during the initialisation of the Controller, and would try to intepret the URL to work out what controller to forward the user to. I didnt want to forward control to a controller, I just wanted the controller to start and let processing continue.

So I subclassed the Controller with my own one that specifically did not initialise the Router.

To do this, I first made a note of the subclass_prefix in config.php. The value is "MY_".

Next, I made a copy of trunk/src/legacy/libraries/Controller.php and put it into trunk/src/legacy/application/libraries/my_controller.php, and changed a few things. The first was the class name and constructor name (MY_Controller). I made it extend the Controller, rather than CI_Base. The contents of the constructor remained the same, calling parent::CI_Base() and $this->_ci_initialize() rather than parent::Controller. And most important, I took a copy of _ci_initialize() and commented out the 'router' entry from the $classes array.

Awesome! I could now login into the application and see the first screen of the application. I thought I was home free. Not quite.

Stay tuned for Part III.

Integrating CodeIgniter with Legacy PHP applications (Part I)

One of the products that I do maintenance on, and occasionally do new development work on, at work, is a monster PHP thing.  It's web based, its procedural, if you're lucky, and its a bit of a mess.  It uses register_globals=on, and quite alot of the business logic, view and presentation is present all in the one program for any given particular screen.  Someone else wrote it originally, and we've never really recovered enough to turn it around and make it better.

We've not done any active development work on it for about 9 months now, but there are some changes coming.  My past few projects have been done using CakePHP.  I really like MVC, and I'd like to drag this monolithic monster kicking and screaming into the realm of modern programming practices.  At the very least, it will keep the project work fresh, and make it something interesting to work on, as well as being maintainable.

As I said, it's a monster, and a full conversion to something easier to maintain is not something that the client is going to dish out for.  So converting to CakePHP is off the table.  What I need is a light weight MVC framework for PHP that is flexible and be worked into the legacy application one bit at a time.  The framework also needs to be in active development, and supported.

So I went for a wander on Google and found CodeIgniter (CI).  It would appear to be a light weight MVC framework for PHP, where you can choose to drink as much or as little of the kool aid as you want.  It seems to have an active development team, and an active community of folks using it.

I didnt go for CakePHP in selection because its just too heavy.  Its an all or nothing framework, and would take too much hacking around to make it work in the environment.

So I took a cut of the project in SVN so I could integrate CI.

The next thing I did was have a look around to see what I could do to integrate legacy PHP applications with CI.  By legacy, I mean old-ish code, nasty stuff thats all procedural, uses register_globals and is a general mess.  I eventually came across this article called Calling CI models from outside script.  It's pretty good article with some good pointers to other articles discussing how to make use of CI models without making your whole program CI.  However, wasnt quite what I wanted.

What I wanted was an introduction on how to use CI libraries in regular code.  My specific goal, and test case, was to replace the session control in the legacy application with the session control available in CI.  I figured, once I have that sorted, the rest should fall into place.

Part II will cover a little about the layout of the legacy application, and how I integrated CI session control into it.


Saturday, May 23, 2009

I'm Sleeping

I just noticed something funny/strange.

Doing a little Facebook scan and noticed a few people use a photo of themselves sleeping, as their profile picture.

Could it be that a picture of yourself sleep is a truer representation of yourself to the internet, that one of that night when you were dressed to kill, and thought you'd take a quick pic of yourself in the toilet mirror of some club before you pulled, or got so drunk you dont really remember the rest.

Wednesday, May 20, 2009

Welcome to Reuben In RL

Hi hi

This is my RL blog.  I have two other blogs, but I dont use them much.  Their content is a little boring, and off beat.  They're really only of interest to me, and a few close friends.. and even then, its just me that reads them.

So I've decided to start a new blog that has real life (RL) stuff.  Well, as RL as I'm comfortable with sharing.  I'm a bit of a private person, dispite what you may find by doing a Google on me.

RL for me currently consists of (and in no particular order) work, play, private and family time.

I'm a software developer and have been getting paid for it for about 14 years.  Though I've been tooling around with computers since first getting my hands on a Sinclair ZX Spectrum (48K) when I was 8.  These days I mainly use PHP, HTML and CSS in my work.  My previous work history has had me working with Progress 4GL, C and Java, with usual encounters of other languages such as Perl, Python and various shells.  There's the usual Uni days stuff as well, like Modula-2, Prolog, Pascal, Scheme and Smalltalk but the list could go on and on.  I'm trying to get into Ruby, but there's this other thing that takes up alot of my time.

World of Warcraft.

I'll try not to cover WoW stuff here.  Thats why I have Pathak/Malygos, one of my other blogs.  I use that to track progression and general ramblings about WoW and my toons.  Generally, its a post once a month about how my 10 or so toons are progressing with their trek to lvl80.  I've never been a big raider, though I was fortunate to run regular Karazhans for a while.  These days, I'm strictly casual and only do heroics.  I have lofty goals of getting all 10 of my toons on Malygos to 80, and getting them all epic flying mounts.  So far I'm 3/10 for the lvl 80 thing, and 4/10 for the mounts.  At least I'm 8/10 for toons > 70, so thats a small comfort for the moment.

Well, RL being RL, I'm ducking off to cook the chops for dinner.  I'll be back in a day, or a week, or a month to cover other topics.