HOWTO: Block Spam Referrers in PHP

...and general pests, by IP address block

Introduction

Being fundamentally fed up with spam Referrers, I wanted a quick and easy way to ban entire blocks of IP addresses inside PhpWiki. My requirements were simple:

  • No database tables (I'm not going to waste time doing a query for these clowns)
  • Instantly editable with vim over SSH
  • Short and efficient, so that it can be included from all my PHP code
  • Support for IP network masks or ranges
  • Support for custom messages indicating the reason of the ban

I soon gave up trying to match substrings inside URLs and trying to prevent access before the fact - it would be extremely slow and require far too much effort.

The Code

Without further ado, here it is:

// Check if a given IP address is inside a given subnetfunction in_subnet($network, $mask, $ip) {    $ip_long=ip2long($ip);    $network_long=ip2long($network);    $mask_long=ip2long($mask);    if( ( $ip_long & $mask_long) == ($network_long & $mask_long)) {        return true;    } else {        return false;    }}// The bozos (in vim, just "/bozo" to get here)$aBanned = array(    array( 'ip' => "69.57.152.89",            'mask' => "255.255.255.255",            'reason' => "Referral spamming with URLs to spam services and porn sites" ),    array( 'ip' => "193.55.220.0",            'mask' => "255.255.255.0",            'reason' => "Referral spamming with drug advertising" ));// inline code (this gets executed by whoever includes this file)foreach( $aBanned as $aCheck ) {    if( in_subnet( $aCheck['ip'], $aCheck['mask'], $_SERVER['REMOTE_ADDR'] ) ) {        header( "HTTP/1.1 403 Access Denied" );        echo( "<H1>You Are Banned From Accessing This Site</H1>");        echo( "<p><b>Reason:</b> " . $aCheck['reason'] . "</p>" );        echo( "<p>I am in the process of reporting this abuse to your ISP or netblock owner" );        echo(" - on the Internet, nobody is really anonymous.</p>" );        // log this so we can grep it out of error_log        error_log( strftime("%d/%b/%Y:%H:%M:%S") . " [BANNED] " . $aCheck['ip'] . " " . $aCheck['reason'] );        exit;    }}