Rebuilding our CMS, again. Stage 1

After years and years of using, learning and building a CMS this is the 5th time, and not the last time I am going to be starting fresh.

Why:
Technology has changed, I have learn’t more. its getting to be that time.

I am taking almost everything from the stable cms I have been running and building sites in for the last few years, it is awesomely powerful, while still so easy to use, so why rebuilt it?
Because it deserves to be better.
Weekly we make changes to the system, refinements here and there, and while I am trying to reduce these now to the minimum we are at the point that to keep the system clean, it needs to be started fresh.

Where to start:
Still using CodeIgnighter for the core, but this time splitting the admin and front end in to two projects.
There will be shared functions and classes to the setup goes a little like this:

-docroot
– www/
– index.php
– assets/
– application/
– system ( core CI )
– shared/
– admin/
– index.php
– assets/
– application/

Stage one:
Authentication.
I have rewritten both the database structure and code from the ground up, the old way was Okay, but not enough control on permissions/sessions/modules. The new way, more control than you can shake a stick at, more thought put in place. doing more checks and making a starter go at loggin in good users, keeping out bad users, setting permissions and access to everything required.

Stage two:
Content.
The key to every CMS and website is content right. while our existing system is kick-ass easy at adding and editing pages, this is going to be a bit smarter at letting you focus on the important pieces.
- Permalinks revisited.
I’m doing research right now on generating the best url for the page, incorporating parts of the parent url if relevant, removed dud words like ‘a’ and ‘and’ or ‘or’.

I found this good, so am taking it in to my thoughts when building this urls:

If you can make your title four- or five-words long – and it is pretty natural. If you have got a three, four or five words in your URL, that can be perfectly normal. As it gets a little longer, then it starts to look a little worse. Now, our algorithms typically will just weight those words less and just not give you as much credit.

here is my url clean function:
I’m open to suggestions here, I am prepending all parent permalinks in from before passing into this function, but feel safe that i limit 2 three levels of navigation, so this shouldn’t be toooo naaaasty…

< ?php 
	// example page title 'Chocolate Lolli-Pops' with a Parent of 'Our Range of Services' ( our-range-services ).  
	$title = 'Chocolate Lolli-Pops';
	$parent = 'our-range-services';
	$slug = $parent .'/'. $title;

	$url = create_permalink($slug); 
 
	function global_ignore_words() {
		return array('a','an','as','at','before','but','by','for','from','is','in','into','like','of','off','on','onto','per','since','than','the','this','that','to','up','via','with', 'gajshost', 'the', 'to', 'their', 'of', 'a', 'be' ,'and','is','in','or','that','for','will','over','as','when','on','can','with','your','are','at','not','you','using','each','end','this','used','may','by','if','any','same','gap','an','it','use','being','allow','side','so','we','long','edge','have','make','ends','occur','down','up','run','from','all','one','amp','fix','do','them','more','need','out','off','must','than'); 
	}

	function create_permalink($str = '') {
		
		// strip tags in case
		$str = strip_tags($str);

		// ignore these silly words...
		$global_ignore = global_ignore_words(); 

		// make url safe
		$trans = array(
			'&\#\d+?;'        => '',
			'&\S+?;'          => '',
			'\s+'             => '-',
			'[^a-z0-9\-\._]'  => '',
			'-+'              => '-',
			'-$'              => '-',
			'^-'              => '-',
			'\.+$'            => ''
		);
		foreach($trans as $key => $val) {
			$str = preg_replace("#".$key."#i", $val, $str);
		}

		// replace out the ignore words, make sure its full words. 		
		foreach ($global_ignore as $word) {
			$str = str_replace('-'.$word.'-', '-', $str);
		}

		// remove anythign else we dont want
		$special_chars = array("?", "[", "]", "/", "\\", "=", "< ", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}");
		$str = str_replace($special_chars, '', $str);
		$str = preg_replace('/[\s-]+/', '-', $str);

		// remove multilple spaces and full stops.
		$search = array('-----','----','---','--','.'); 
		$replace = '-';
		$str = str_replace($search, $replace, $str); 
		

		// now remove any other short words..
		$str = explode('-', $str);
		foreach($str as $k => $word) {
			if(strlen($word) < 3) unset($slug[$k]);
		}
		$str = implode('-', $str);

		// finaly, clear, lower and return
		$str = trim($str, '.-_');
		return strtolower($str);
		
	}

With this in mind I'm saving the page title, placement ( once was parent ), template and nice shiny new permalink.

Setting up a Debian PPTP VPN Server

I wanted to set up an external VPN server so I could close out some ports on my router and when required access more on our internal network when I’m outside.

I am pretty familiar with Debian and run a bunch or XEN virtual machines so figured that was a good place to start, I found a bunch of good examples on how to set this up, but they all missed a couple of not so obvious points.

This is a command line setup on a pretty fresh debian VM.

Connect to your box as root, else prepend each command with sudo. , The Internal IP of this box in this example is: 10.10.20.2 and my router/firewall is 10.10.20.1

apt-get install pptpd

Next we need to set in the PPTP Conf this servers IP and the DHCP pool range to hand out to the connected clients.

nano /etc/pptpd.conf

Add the bottom add the following two lines adjust to suit your network

localip 10.10.20.2
remoteip 10.10.20.20-10.10.20.40

The IP range I have set will allow up to 20 connections, if you are expecting more, or only every expecting one you can adjust this range. It pays to make sure your router is not assigning DHCP addresses in this range – but not critical.


Next we need to set PPTP network options:

nano /etc/ppp/pptpd-options

My file looks like:

name pptpd
# domain mydomain.net
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
proxyarp
nodefaultroute
debug
dump
lock
nobsdcomp
#DNS servers
# Router
ms-dns 10.10.20.1
ms-dns 10.10.20.3 # Internal DNS Server 1
ms-dns 10.10.20.4 # Internal DNS Server 2
# or use an external DNS Service, eg: google
ms-dns 8.8.8.8
ms-dns 8.8.4.4

netmask 255.255.255.0
nobsdcomp
noipx
mtu 1490
mru 1490

Note here, I have left the debug & dump lines, this will be useful while getting everything working.


Next we are going to add users that can connect in:
There are a couple of ways of doing things here, use the internal Secrets file to define your users or using SAMBA users.
below is the simple method using the chap-secrets file:

nano /etc/ppp/chap-secrets

Each user needs to be on a new line:

username * users-password * 
sheldon * myVPNPassword *

Make sure you set strong usernames & passwords


Now we need to restart the PPTP service to apply all of the changes we have made. NOTE: You can add/edit users with out restarting the PPTP service.

# /etc/init.d/pptpd restart

NAT routing:
If you want to allow users to access more than just the VPN server then you will need to enable NAT routing/forwarding.

The first thing to check is if this is enabled already:

cat /proc/sys/net/ipv4/ip_forward

If that returns zero, then your server isn’t enabled to do any routing.
Run this command:

echo 1 > /proc/sys/net/ipv4/ip_forward

Then restart the service:

# /etc/init.d/pptpd restart

Some people consider this a security risk, but with out it, it defeats the purpose of accepting incoming connections.
Make sure you set strong usernames & passwords


Opening Ports:
This varies on on how to do this with EVERY router, but the thing to know is, you need to open two ports:

GRE Port 47 and 1723. Point both of these to your PPTP VPN servers IP address, in may case 10.10.20.2.

All should be good to test now, find your external IP address by googling ‘IP Address‘, then test from out side of your network ( Hint: If your on the same network, get a friend via TeamViewer or other remote management app to test ).

While you are testing, or if you are having issues tail the syslog to see what is happening.

tail -f /var/logs/syslog

Simple PHP Script to Pluralize Month names

You often need to refer to a Month’s name in the Plural, Eg, “I want Junes Database back up” or “Display Marches Orders”.

Here is a very simple PHP function to show the nice Pluralized month, simply don’t pass in a param to show hte current months plural, or pass in the PHP Date’s ‘n’ ( n Numeric representation of a month, without leading zeros – 1 through 12)

	function pluralize_month($month = NULL) {

		if((int)$month < 1 or (int)$month > 12) $month = date('n'); 
		if($month == 3) return 'Marches';
		return date('F', strtotime(date('Y-'.$month.'-01'))). 's';

	}

Linux Crontab helpful hints

*    *    *    *    *  command to be executed
┬    ┬    ┬    ┬    ┬
│    │    │    │    │
│    │    │    │    │
│    │    │    │    └───── day of week (0 - 6) (Sunday=0 )
│    │    │    └────────── month (1 - 12)
│    │    └─────────────── day of month (1 - 31)
│    └──────────────────── hour (0 - 23)
└───────────────────────── min (0 - 59)

Calculating memory used by PHP to generate that page

Do you know how much memory those loops are using ?
Why is this page taking so long to load ?
Well with this simple PHP code you can daily benchmark different versions of your script to use the least possible amount of Memory.

< ?php echo "Memory Usage: ". (function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024, 2) : 'Unknown') .'MB'."\n"; ?>

An example of this can be seen by visiting the Precision Badges New Zealand site, and viewing the page source, right down the bottom.

PHP Framework – Day 1

Start of simple, start off clean.

I am going to assume a few things in these posts,
PHP 5.2 or above. ( 5.3 is better )
mySQL is our database of choice.
You understand the basics of setting up a virtual host/development area, and setting up your database.

Setting up your index file.

The ‘index.php’ is going to handle all requests. We will define the necessary contacts and then call out bootstrap file which starts and loads all of our needed classes.

from there, we load our bootstrap file that loads all needed classes.

The Core::Router() function does the routing.
The router function will check based on the 1st and 2nd segment to see if a matching view exists and then parse that view in to the main template file.

Download the source files and have a look trough, I have commented most functions, Follow trough from the index file and follow the includes.

There is no use of the database or sessions yet so just drop this on your web server and run it.

[download id="12"]

Beginners Guide to PHP Happiness.

Lately I have been seeing some nastiness being taught to a group of Junior web developers.
It comprises of maxing all sorts of nasty combinations of mixing your PHP, HTML, classes, queries and stand alone functions into an unorganised pile of mess.

Developing any project, simple of complex in this manor will very quickly become a nightmare, to me, and more so to those student developers.

I am going to put together a series of quick and simple posts to make a clean, simple and effective PHP based framework to act as a learning step for these students.

PHP Dump/Debug script.

Ever use PHP’s var_dump() or print_r() to debug what is going wrong with that $data you have ?

Well, this simple script acts as the above functions, yours first parameter is your data, and the second optional parameter is stoping the script or continuing on.

The ‘debug_backtrace()’ function will return which file call’s the dump function so you can easily track where your errors are coming from.


	function dump($data = array(), $finish = TRUE) {

		list($referrer) = debug_backtrace();
		$total = count($data);
		echo '
'; echo ''.$referrer['file'].' @ line: '.$referrer['line'].''; echo '
';
		$l = 0;
		if($data) {
			foreach($data as $line => $value) {
		        echo '
Debug #'.(++$l).' of '.$total.', Line: #'. $line .':
'; print_r($value); } } echo "

";
echo "

";
if($finish == TRUE) die;

}