PHP Membership Provider

I came across a post made a little while ago by Steven Benner on PHP’s notable lack of a consistent Membership Provider as in ASP.Net. All good points, but I think the hard bit isn’t so much session management since there are a million examples out there on how to provide a login interface.

The tough part seems to be a consistent method of accessing, creating and maintaining users in a database. Also a lot of those examples tend to be MySQL specific so if you need something easily customized for something else, like say PostgreSQL, you’re pretty much stuck customizing to no end, at which point you might as well write your own.

And that seems to be what an overwhelming majority of people are doing if they’re not getting an off-the-shelf CMS to start with. Of the few frameworks for membership management that are available out there, most are a bit over complicated and have licenses, fees and other strings attached.

So most people are stuck writing a user management system from scratch or getting a CMS off the shelf with its own unique (and usually incompatible) user management system.

I got home from work early on Friday and have this weekend off for a pretty good rest, so early this morning, I thought I’d write up a Membership Provider for PHP that anyone can use with no strings attached (and hopefully doesn’t suck too much). The idea is to have a simple drop-in user management interface.

Keep in mind that I haven’t actually tested any of this and it all may in fact blow up spectacularly (since I didn’t do any testing, everything is as-is and I’m not a professional PHP programmer). It’s a bit late for Steven’s post, but better late than never eh? ;)

AND YOU NEED TO VALIDATE ALL INPUTS BEFORE SENDING THEM… ahem.

I didn’t want to mimic everything in the Membership Provider for ASP.Net in that there are a lot of things that I don’t like, some features that could be improved and others that are completely missing.

Notably, I don’t see the need for password questions and answers since resetting by email is often a better solution than lowering the security barrier by introducing (essentially) a weaker password in the form of an answer to a known question. Also, people often forget the answers to questions too or repeat the same questions and answers on different sites, which defeats the purpose of a strong password anyway.

I’d also like to have a way to find and delete users by either Id, Name or Email and easily lock/unlock, approve/unapprove users and provide strong passwords with Blowfish. For this last option, I downloaded the Portable PHP password hashing framework, which I think is the best implementation for PHP I’ve found so far.

Now I need a table…

Although this example table is in MySQL, you could modify this for any other database. In the queries, I avoided any MySQL specific commands like sql_calc_found_rows and the like and because I’m using PDO the code itself should work with no modifications on PostgreSQL and SQLite provided it’s the same table structure.

CREATE TABLE `users` (
  `userId` int(20) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `hash` varchar(10) NOT NULL,
  `password` varchar(200) NOT NULL,
  `passwordSalt` varchar(100) NOT NULL,
  `email` varchar(100) NOT NULL,
  `avatar` varchar(200) DEFAULT NULL,
  `createdDate` datetime NOT NULL,
  `modifiedDate` datetime NOT NULL,
  `lastActivity` datetime NOT NULL,
  `bio` text DEFAULT NULL,
  `isApproved` tinyint(1) NOT NULL DEFAULT '1',
  `isLocked` tinyint(1) NOT NULL DEFAULT '0',

  PRIMARY KEY (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Users' AUTO_INCREMENT=1 ;

Pretty typical for most websites. The “hash” there is just a unique key made by combining the username and email in a hash that will set apart users even with similar looking usernames. Think of it as a very primitive Tripcode shown alongside a username.

Configuration

If there’s one thing that makes configuring an ASP.Net web page consistent is the web.config file. It’s only appropriate then to put all the configuation stuff into one file, say a .ini, like so :

;*** Website configuration file ***
;
; All comments start with a semicolon (;), and this file can be something other than config.ini
; as long as the new file name is specified in index.php .

;*** Globally accessible settings ***

[Database]
dsn = "mysql:host=localhost;dbname=testdb"
username = "testuser"
password = "BKjSheQubKEufqHC"

[Tables]
usersTable = "users"
rolesTable = "roles"
tablePrefix = ""

;*** Membership specific settings ***

[MembershipProvider]
minRequiredPasswordLength = 5
maxInvalidPasswordAttempts = 3
passwordAttemptWindow = 10
userIsOnlineTimeWindow = 20
autoApproveUsers = "true"

Of course, for this example, we won’t be using all of that, but I just created a file called config.ini and put all that in there. Now how do we load all of this? First we need an index.php file.

index.php

<?php
ini_set( "display_errors", true );

// Set the application configuration file. You may store this outside the web root
// if your web host allows it.
define('INI', 'config.ini');


/*******************************

	End editing

********************************/


define('BASE_PATH', dirname(__FILE__));

// Platform specific include path separator
if ( strtolower(substr(PHP_OS, 0, 3)) === 'win') 
	define('SEP', ';');
else
	define('SEP', ':');

// There must be an /app folder in root with all the class files
define('CLASS_DIR', BASE_PATH . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR);

// Optionally there should also be a /mod folder in root where you can include modules/plugins in the future
define('MODULE_DIR', BASE_PATH . DIRECTORY_SEPARATOR . 'mod' . DIRECTORY_SEPARATOR);

// Modify include path
set_include_path( CLASS_DIR  . SEP . MODULE_DIR );


spl_autoload_extensions(".php");
spl_autoload_register();

?>

The down side to this approach is that all your file names must be lowercase, but it should be slightly faster than any other autoload implementation and I’m reasonably confident it should run on a *nix platform with no hiccups as well as on Windows.

For now, that autoload would force the application to look in the /app folder where all the magic happens and optionally in /mod for any future modules. And for that magic we’ll create a base class that all “action” classes would inherit from. This is basically to provide dynamic class properties.

<?php

/**
 * Base class provides dynamic class property functionality
 *
 * @package Base
 */
class Base {
	
	
	/**
	 * @var array Config properties storage
	 */
	protected $props = array();
	
	
	/**
	 * Get class accessible settings
	 */
	protected function __get( $key ) {
		return array_key_exists( $key, $this->props ) ? 
			$this->props[$key] : null;
	}
	
	
	/**
	 * Set class accessible settings
	 */
	protected function __set( $key, $value ) {
		$this->props[$key] = $value;
	}
	
	
	/**
	 * Checks whether accessible setting is available
	 */
	protected function __isset( $key ) {
		return isset( $this->props[$key] );
	}
}
?>

Now we need a configuration class that will load the settings from the defined .ini file into itself and make the settings accessible to all classes calling it.

<?php

/**
 * Application configuration file.
 * All settings are imported from the .ini file defined in index.php
 *
 * @package Config
 */

class Config extends Base {
	
	
	/**
	 * Class instance
	 */
	private static $instance;
	
	
	private function __construct() {
		$this->props = parse_ini_file(INI, true);
	}
	
	
	public static function getInstance() {
		if(!self::$instance)
			self::$instance = new Config();
		
		return self::$instance;
	}
}
?>

This is starting to get a bit long so onward to the next page

Site of the Week: BioLite

Ever think to yourself, “if only I could power my USB device by burning wood”?

BioLite Campstove. Power your devices with fire!

If you need to charge your USB device, but don’t want to rely on nasty nuclear or ugly coal that’s powering your house (if you’re not already on solar), then BioLite has the stove to do it. By burning leaves, twigs or what have you, never run out of power.

At first, I thought this was a joke, but it turns out to be a totally serious product. For $129, you get a stove, according to the product page that is able to :

Charge your gadgets
By converting heat from the fire into usable electricity, our stoves will recharge your phones, lights and other gadgets while you cook dinner. Unlike solar, BioLite CampStove is a true on-demand source.

But the real appeal of this is that it needs :

No fuel to buy or carry
Our stoves cook your meals with nothing but the twigs you collect on your journey, eliminating the need for heavy, expensive, polluting petroleum gas. Quick to light, fast to boil and easy to use.

Of course, there are backpack USB chargers in the market these days, but they don’t work well when it’s cloudy and not at all at night. Presumably, these probably won’t work as well when it’s raining unless you’re in a shelter with plenty of ventilation for the smoke, but you can still charge outside when dry, day or night. I’m not sure how eco-friendly it really is since you’re still burning fuel, but I imagine it’s a lot less than the several tons of CO2 expelled by your local coal power plant.

Check out the product promo :

Lorenzo Salon (Ritz Crackers Commercial)

I’m a bit torn since I saw this on TV. On one hand I think it’s funny, but on the other, it’s a pretty stereotypical potrayal of a male hairdresser so no doubt going to offend a lot of people. What do you think?

BTW… The actor playing Lorenzo is Chris Wylde.

Note, no where in the commercial is any mention of Lorenzo’s orientation. Here’s the actual dialog.

Lorenzo: Ugh! All work and no food is making Lorenzo very snippy… AAAH! Seriously!

(Client hands packet to Lorenzo)

Narrator: Hunger getting to you?

Lorenzo: Ooh!

Narrator: Grab a Ritz Crackerfuls. Made with with real peanut butter and whole grain.

Lorenzo Mmm! (Chewing)

Narrator: Get hunger before it gets you.

Drug PSAs mostly fall on deaf ears

So instead, I’ll leave you with this as a small insight of what may come out as a result of being high. Especially on marijuana.

Disclaimer:

I realize that I may inadvertantly turn people on to drugs. In which case, just tell the cops you’ve never been to this blog… if you remember it at all.

Drugs are bad m’kay?

RIP Adam Yauch (aka MCA From the Beastie Boys)

MCA From the Beastie Boys, a band many of us defined our generation with, died today at age 47 after a battling cancer. He will be sorely missed.

RIP MCA

Update 8:30PM

Now that I’ve collected my thoughts…

I was a 13 year old kid who had just moved up to New York after coming to America and, up until then, living in the South for a while. Nothing about Western culture — that I saw so much of on TV — had any discernable bearing on my real life. I felt let down by popular culture. At least TV culture.

Between my trips to Comedy Central to watch Dr. Katz, to Fox to watch the Simpsons and back to MTV, I grew into something of a cynic. High school was boring, my friends were stupid, enemies were evil, but at least I had entertainment to come home to. But then mere entertainment started to morph into something of a lifestyle. The Beastie Boys started to grow on me.

Once upon a time, believe it or not, the bane of civilization and all taste, MTV, used to be an OK place to visit for good music. It wasn’t great, it wasn’t really earth-shattering and most of it was incomprehensible. But the idea that it was all ”fake” was hammered in to all of us all the time by the surreality of the content. Between Liquid TV, Aeon Flux, Beavis and Butthead and Daria, I thought I had a pretty good sense of the popular culture.

No one pretended that this was “real”. Even the Real World, which started the apocalypse, was stupid enough to be innocuous.

We all derived some pleasure from the trivial theater that is the Music Video. And since CDs were expensive (to us) and your mom couldn’t afford the latest albums, MTV and radio were your only sources of music entertainment. You could repeat the experience thanks to blank tapes, which were cheap, and I managed to scrounge up a recorder someone had thrown out and, viola… My taste in music was simmering with the times and the Boys were becoming a formative part of my life.

I think the first Beastie Boys music video I ever saw was No Sleep Till Booklyn and that was considered “old” even back then (the mid 90′s and the track was from the late 80′s). I didn’t care, I thouroughly enjoyed it. If they didn’t take it seriously, why should I? The collection snowballed as I finally could afford CDs.

The Beastie Boys… and I only saw those magnificiently absurd young men a few times before latching on to MTV… it occured to me, I think these guys really know how to have fun while not giving a damn. Entertainment was entertaining on its own merit. The music was good, the tune was catchy and rhymes were starting to stick. I think I could get into this.

And boy did I.

My first mixtapes always had the following :

  • Cooky Puss
  • The New Style
  • No Sleep Till Brooklyn
  • Paul Revere
  • Hold it now, Hit it
  • Brass Monkey
  • High Plains Drifter
  • Hey Ladies
  • Jimmy James
  • Pass the Mic
  • So What’cha want
  • Sure Shot
  • Root Down
  • Sabotage (the song and video are Immortal)
  • Three MC’s and one DJ
  • Body Movin
  • Intergalactic
  • Root Down

Suffice it to say that today, the same as to many others, a part of our childhood died. Nothing will really replace what Adam brought to the trio (quartet with the DJ) and a part of our reality has a gaping hole as a result.

Farewell, MCA.