PHP + BBEdit + RegEx for code generation get/set functions

Here’s a handy way to generate getter/setter functions. I use BBEdit, but since this is based on Regular Expressions it could be done in just about any code editor.

Say you start a class and have defined the following private member variables:

private $ip_range_id;
private $subscriber_id;
private $low_ip;
private $high_ip;

The next thing I commonly would want to add to my class is a public function for each member variable that can be used for either getting or setting its value. So for $high_ip, I might want a functiont that looks something like this:

public function high_ip($high_ip=false)
{
    if($high_ip) {
        $this->high_ip = $high_ip;
        return $this->high_ip;
    } else {
        return $this->high_ip;
    }
}

This way if I have instantiated an object from this class called $ipr I can get the current value of the private $high_ip like this: $ipr->high_ip() and if I want to set the value of $ipr‘s $high_ip to be '127.0.0.1' I can do it like this: $ipr->high_ip('127.0.0.1').

Ok, but what about those RegExs and the code generation bit?

Since the getter/setter functions generally start off very similar, they are ripe for templates and templates are a good place to build generators. I’ve seen many approaches, and they have their benefits but this is so quick and easy I thought it might be helpful to someone.

1. Copy the private member declaration from the class into a temporary document (BBEdit’s “Scratchpad” is great for this, as is Emac’s *scratch* buffer).

2. Open the “Find…” dialog, and enter this RegEx in the “Find” field:

^private \$([\w]+);$

3. Paste this into the “Replace” field:


public function \1($\1=false)
{
    if($\1) {
        $this->\1 = $\1;
        return $this->\1;
    } else {
        return $this->\1;
    }
}

4. Make sure “Grep” and “Wrap around” are checked off, and then press the “Replace All” button, and voila!


public function ip_range_id($ip_range_id=false)
{
    if($ip_range_id) {
        $this->ip_range_id = $ip_range_id;
        return $this->ip_range_id;
    } else {
        return $this->ip_range_id;
    }
}
public function subscriber_id($subscriber_id=false)
{
    if($subscriber_id) {
        $this->subscriber_id = $subscriber_id;
        return $this->subscriber_id;
    } else {
        return $this->subscriber_id;
    }
}
public function low_ip($low_ip=false)
{
    if($low_ip) {
        $this->low_ip = $low_ip;
        return $this->low_ip;
    } else {
        return $this->low_ip;
    }
}
public function high_ip($high_ip=false)
{
    if($high_ip) {
        $this->high_ip = $high_ip;
        return $this->high_ip;
    } else {
        return $this->high_ip;
    }
}

Checking IP Ranges for Sanity / Validity

This doesn’t cover a lot of cases so it is really a sanity check for IP Ranges. It takes two IP addresses a low one and a high one and makes sure they are valid IPv4 addresses and it take a look to make sure (at least I hope it makes sure, anyone want to help me out here?) the low_ip is ‘lower’ than the high_ip.

This is used by some code that allows a user to specify an IP address range and then when the application ‘sees’ a client coming from within a known range, it associates the client with the ‘user’ who set up the range. (Think library systems that restrict content via institutional IPs)

$low_ip = '18.0.0.0';
$high_ip = '18.255.255.255';

if( validate_ip_range($low_ip, $high_ip) ) {
    print "yes\n";
} else {
    print "no\n";
}
function validate_ip_address($ip)
{
    if( ($long_ip = ip2long($ip)) !== false) {
        if($ip == long2ip($long_ip)) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

function validate_ip_range($low_ip, $high_ip)
{
    if(validate_ip_address($low_ip) && validate_ip_address($high_ip)) {
        $long_low_ip = ip2long($low_ip);
        $long_high_ip = ip2long($high_ip);
        if( ($low_ip == long2ip($long_low_ip)) && ($high_ip == long2ip($long_high_ip)) ) {
            if($long_low_ip <= $long_high_ip) {
                # now check that 1st octet matches in each ip (18.* == 18.*)
                $low_octets = explode(".", $low_ip);
                $high_octets = explode(".", $high_ip);
                if($low_octets[0] != $high_octets[0]) { return false; }
                # for each of the remaining 3 octets, low_ip's octet <= high ips.
                # e.g. 18.151.1.0 18.151.1.255
                # 18.57.0.41 - 18.57.0.100
                for($i = 1; $i < 4; $i++) {
                    if($low_octets[$i] > $high_octets[$i]) { return false; }
                }
                $num_ips = ( sprintf("%u", $long_high_ip) - sprintf("%u", $long_low_ip) );
                if($num_ips > 65535) { echo "warn: above a class C address space\n"; }
                # if we made it this far, should be a valid rang for our purposes
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

Attached is a text file disguised as a .doc with the test “harness” for this function and the function suggested by tevis below. For malformed IP ranges such as $low_ip = ’18.0.0.14′ and $high_ip = ’18.255.255.1′; the suggestion below doesn’t seem to work, but the cumbersome process does correctly indicate that there’s a problem with that kind of IP range.

Configure OpenX Maintenance Scripts on SliceHost

Setup:

  • SliceHost 1gb RAM Xen VPS x86_64
  • CentOS 5.2
  • MySQL 5.0.45
  • PHP 5.1.6 (cli)
  • Apache 2.2.3
  • OpenX 2.6.3

Unless you love vi, set your environment’s EDITOR first. For me, this is the most important part of the process. I hear the cool kids use nano these days. I work at MIT so I feel like I have to use Emacs. 

edit ~/.bash_profile and add these lines
EDITOR=/usr/bin/emacs
export EDITOR

Then edit your crontab file and add a line like this to it:
crontab -e
30 10 * * * /usr/bin/php /var/www/i.mitsmr.com/openx/scripts/maintenance/maintenance.php i.mitsmr.com

That will run the maintenance script once per day at 10:30pm. Check your crontab log for any errors:
sudo tail /var/log/crontab

Oh, and OpenX pushed 2.6.4 update out yesterday. Take one thing off the todo-list, add something new right back on! Sheesh.

Reading List – 2009 (January)

Title, (Author Last Name, Date of Publication) – Date Completed

  1. Angler, (Gellman 2008) – 1/4/2009
  2. Hot, Flat and Crowded, (Friedman 2008) – 1/14/2009
  3. When You Are Engulfed in Flames (Sedaris 2009) – 1/21/2009
  4. How Fiction Works (Wood 2009) – 1/26/2009
  5. Imperial Life in the Emerald City, inside Iraq’s green zone (Chandrasekaran 2006) – 1/28/2009
  6. McSweeney’s Quarterly Concern (Vol 25 2007)

Page count for January: 1,917 (61.84/day)

The list of books read in 2008 struggled its way to 66, I’m aiming for 100 in 2009.

The walk to work

After the snow, rain and overnight freezing temperatures, this is what greets you in the morning.

I have a car, but I choose to take public transportation because I don’t want to me yet another solo-commuter in a car burning carbon left and right so I can listen to NPR and complain about traffic.

Days like these, Boston makes it tough.

It’s a 1/3 mile walk to the Forrest Hills T stop (subway, bus & commuter rail station). The whole way, sidewalks were completely frozen over (except that one huge slush-lake that required a blazing an overland portage route).

For the cars though, nice dry pavement. Now, don’t get me wrong I don’t want frozen roads crippling capitalism or anything, but when the roads are dry and sidewalks frozen, what do you get? –school children and old ladies walking down a busy street, in the traffic lanes, because they ate affraid of the sidewalks.

(posted, with typos, from iPhone)