Archive

Archive for the ‘PHP/MySQL’ Category

SEO for Charity

February 17th, 2006 No comments

Fellow Coloradan Alex Komarnitsky decided to bring a charity twist to an SEO competition. Despite not being a professional SEO, he currently ranks number three for the search phrase. This is my attempt to help him win. The best way to get good Google mojo is to link to the target site with the keyphrase in the link, like this: v7ndotcom-elursrebmem

If you get a moment and want to help a good cause, paste the link code below into one of your web pages.

Categories: Misc, PHP/MySQL Tags:

MVC and PHP Fusebox

December 10th, 2004 No comments
I’ve been following Jeff Moore’s comments about Model View Controller (MVC) and the resulting discussion because I’m thinking of moving Click Thru Stats to more of an MVC approach. I currently use PHP Fusebox. It’s procedural, but it can be adapted to support OO reasonably well. (I believe the latest version is OO, but I haven’t had a chance to look at it closely). It also has an OO-ish structure, so it subtly encourages you to move in the OO direction.
 
I’m a novice at design patterns and MVC, but I’ve been slowly trying to apply some of the principles. From an OO perspective, I started at the database level and worked my way back from there. (I would bet this is where most people start with OO.) After isolating the database as an object, the next level up was to store data as persistent objects and use vars and methods to get/set/store/retrieve. I built an abstract class to handle 90% of these methods, then extend it for specific exceptions. This worked very well and I got a lot of mileage out of it within the context of Fusebox.
 
The biggest drawback is that I still used a procedural approach to generating HTML for pages, and I found myself doing a lot of copying/pasting of existing files into new directories as the application evolved, which was not good when it came time to make a global change. So more recently I’ve been building HTML classes that accept persistent objects as arguments and dynamically build pages based on what the persistent objects tell them. The coupling is fairly loose, but I’m still locked in the Fusebox layout model for generating the full page. (The current HTML classes only generate elements within a page.) That said, most of the time there is not a lot of exception handling necessary once you get beyond the individual elements except for the occasional user security issue. (Note: I could’ve used these classes to generate XML and format them with a separate XSL component, but I didn’t do that, mainly because I just haven’t had time to get up to speed with XSL.)
 
Another thing I’ve done is enhance the abstract persistent class to automatically populate itself with data submitted via GET/POST, validate the data, and throw catchable errors. I do this with a data dictionary approach that was heavily influenced by Tony Marston’s Development Infrastructure for PHP. The biggest difference is that Tony accesses data at the dataset level (i.e. he gets/inserts/updates data by specifying a row within a larger data set, whereas I still have class definitions that instanciate for a specific row in the table). That said, I also have a DataSet class that optionally takes a row-level instance class as an argument and can instanciate and return a row-level object.
 
Despite some of the controversy around it, I think the data dictionary approach that Tony takes is very solid, though it can be a little overwhelming to map out all the metadata. To make it easier to get started, I have a lot of defaults built in. So you can start just by defining the columns in a table. If nothing else is defined, the form used to edit the data will just show text entry fields. If you decide something is better handled as, say, a <select> drop-down, you can define a widget_type property for the column as well the <option> tags the <select> should show. Those options are accessed via a get_selectOptions($name_of_field,$language=[current language defined by constant]) method, which can be overridden in subclasses. That way you could, for example, return the options from the database instead of the static data dictionary.
 
This data dictionary also has data validation rules (e.g. min length, max length etc.), type rules (int, text, longtext etc), a regular expression rule, and even a class rule. This is implemented by $object->data_errors(). For example, you may want to enforce referential integrity to prevent an invalid person_id from being inserted into the users table. To do that, you specify that this column is of custom_type Person. During data validation, the class will look for a class called Person.php. If found, it will instanciate a Person object with the submitted value in the constructor, then check for Person->is_valid(). Of course, you can also just override the data_errors() method in a subclass.
 
Finally, the data dictionary allows you to define custom, language-specific error messages. There are default messages for times when a message is not specified.
 
While I agree with Allen Holub’s contempt for the set_ and get_ orthodoxy (I learned the hard way why these can be a waste of time), they are exceptionally useful in the context of an abstract persistent class. Rather than referencing the data dictionary array directly, I’ve found you get more flexibility if you use get_ and set_ with them, mainly because they give you great flexibility in your subclasses. The only downside is that you get a loooooong call stack when debugging. You also get a minor performance hit because the HTML rendering classes check for method_exists() for every field in the class. If the method exists, it uses get_/set_. If it doesn’t exist, it access the data dictionary array via a generic get_value($fieldName) method.
 
One more thing: since the abstract DataSet class can accept a row-level instance class as a var, you only need to define the data dictionary once in the row-level class. If no dictionary is defined in the DataSet class, it looks at the instance class and uses it’s data dictionary (again, using get_ and set_ whenever possible).
Categories: PHP/MySQL Tags:

Search Engine Optimization (SEO) for phpBB URLs

November 20th, 2004 No comments

I recently installed phpBB on HappyMudan.com, a new site my wife and I launched last week. I like phpBB, but it’s not the most search engine friendly bulletin board. I did a little Googling and found this site, which has a few optimization tips and which I highly recommend.

However, one thing it doesn’t include is tips on how to rewrite your urls into more meaningful names. As an example, it’s usually a good idea to have the title of a page in the name of the url because search engines give those keywords more weight. So, for example, we’d like the url http://www.happymudan.com/discuss/viewforum.php?f=4 (which looks pretty meaningless) to be something relevant to the keyword “immigration,” which is the topic for this forum. After a little hacking, I was able to come up with a url of the form http://www.happymudan.com/discuss/forum-Immigration-id_4.html. It’s not perfect, but it’s a lot more meaningful than before.

Fortunately, there are only a couple of places where these kinds of urls are really necessary – the listing of forums and the listing of topics.

As an example, if you have two forums – “derek’s news” and “funny jokes” – you want the urls to be something like:

/derek’s-news.html
/funny-jokes.html

Since phpBB processing all happens in the same directory, we have to add some hints to the urls to tell Apache which script to pass them to. So alter those urls to something like:

/forum-derek’s-news.html
/forum-funny-jokes.html

Further muddying the waters, phpBB allows two different forums to have the exact same name (ditto with topics). So we have to also put the unique forum ID into the url:

/forum-derek’s-news-id_93.html
/forum-funny-jokes-id_234.html

Lastly, forum and post names can have non-standard url characters in them (such as ‘ and &). So we have to urlencode them:

/forum-derek%27s-news-id_93.html
/forum-funny-jokes-id_234.html [no change on this one]

So, how do we do this? It’s actually pretty simple. There are two files to edit.

The first is index.php in the root of your installation. Search for:

$template->assign_block_vars(’catrow.forumrow’

Immediately above this code block, add the following:

//derek’s seo url hack
//use the forum name as part of the url
$forum_name=$forum_data[$j][’forum_name’];
$view_forum_url=trim($forum_name);
//prepend ‘forum’ so we know this url is for viewforum.php
$view_forum_url=’forum-’ . $view_forum_url;
//replace spaces with dashes
$view_forum_url=str_replace(’ ‘,’-’,$view_forum_url);
//replace “/” with dashes – for some reason my (admittedly weak) Apache regex doesn’t like “/”
$view_forum_url=str_replace(’/’,’-’,$view_forum_url);
//append -id_ as a handle for the regex to find the correct forum_id
$view_forum_url = (urlencode($$view_forum_url).”-id_$forum_id”;
//add .html to make it look like a static web page
$view_forum_url .=’.html’;
$view_forum_url=append_sid($view_forum_url);

A few lines below the $template->assign_block_vars section, you should see this:

‘U_VIEWFORUM’ => append_sid(”viewforum.$phpEx?” . POST_FORUM_URL . “=$forum_id”))

Comment this out and replace it with:

‘U_VIEWFORUM’ => $view_forum_url)

Save the file.

Next, open the file viewforum.php. Search for “$view_topic_url = ” without the outer quotes.

Comment out this line using //. Immediately above this code block, add the following lines:

//derek’s seo hack
//use the topic title as part of the url
$view_topic_url=trim($topic_title);
//prepend ‘topic’ so we know this url is for viewtopic.php
$view_topic_url=’topic-’ . $view_topic_url;
//replace spaces with dashes
$view_topic_url=str_replace(’ ‘,’-’,$view_topic_url);
//replace “/” with dashes – for some reason my (admittedly weak) Apache regex doesn’t like “/”
$view_topic_url=str_replace(’/’,’-’,$view_topic_url);
//append -id_ as a handle for the regex to find the correct forum_id
$view_topic_url = urlencode($view_topic_url).”-id_$topic_id”;
//add .html to make it look like a static web page
$view_topic_url .=’.html’;
$view_topic_url=append_sid($view_topic_url);

Save the file. We’re almost done.

Add the lines below to your .htaccess. NOTE: this code assumes your phpBB is in a subdirectory called phpBB. Change the “phpBB” to whatever directory you use, or remove it altogether if phpBB is in your document root:

RewriteEngine On
RewriteRule ^/phpBB/topic-(.*)-id_([0-9]*).html /phpBB/viewtopic.php?t=$2 [QSA]
RewriteRule ^/phpBB/forum-(.*)-id_([0-9]*).html /phpBB/viewforum.php?f=$2 [QSA]

QED, no? At least so far. I hacked this out in a hurry and I suspect the regex is not robust enough for all situations. Let me know if you have problems or improvements and I’ll update them here.

Update: I haven’t tried it yet, but a friend pointed me to this mod for phpBB.