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.