Spam control by IP blocking in Yii

By Ronald van Belzen | May 4, 2013

Any interactive website needs to take into account that that interactivity will be abused. The most common form of abuse is spam. Even when you control the user input by moderation there comes a time that you need to structure the control of user input. One way of getting control over input from abusive users is by using IP blocking.

The approach I will describe here will require that your application registers the IP address in all the database tables that store user input. As an example I will use a "blog_comment" table.

The stategy that will be followed is that upon creation of a comment (INSERT) the IP address will be checked against a database table containing the IP addresses that need to be blocked.

The moment to determine the IP address of a user and store it in the table "blog_comment" is during validation in the function "rules()":

    return array( 
      // ... other rules 
      array('ip', 'default', 'value'=>Yii::app()->request->userHostAddress), 
      // ... other rules 
    );

We start by creating the database table that will contain the IP addresses that need to be blocked.

CREATE TABLE `ipaddress` ( 
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
  `ip` VARCHAR(39) NULL , 
  `address` VARCHAR(255) NULL , 
  `source` TINYINT NULL DEFAULT 0 , 
  `count` INT NULL DEFAULT 0 , 
  `create_time` TIMESTAMP NULL , 
  `update_time` TIMESTAMP NULL , 
  PRIMARY KEY (`id`) , 
  UNIQUE INDEX `ip_UNIQUE` (`ip` ASC) );

The only mandatory field in that table will be "ip". The other fields are for extra functionality that can be used for maintaining the IP addresses. The field "source" can be used to distinguish manual input from automated input of IP addresses. The field "count" can be used to count the number of times an IP address has been checked.The field "update_time" is used to check when an IP address was last checked.

We use Gii to create a model from this table and use the Crud Generator. Next we improve the views that the Crud Generator has made, but I leave it to you to do that. In this blog post we concentrate on the model Ipaddress to which we add the following function:

    public static function blocked($ip) {
      $model = Ipaddress::model()->find("ip = '$ip'"); 
      if($model === null) { 
        return false; 
      } else { 
        $model->count++; 
        $model->save(); 
        return true; 
      } 
    }

In the model BlogComment we add a rule after determining the default value for the IP address:

    return array(
      // ... other rules
      array('ip', 'default', 'value'=>Yii::app()->request->userHostAddress),
      array('ip', 'blocked'),
      // ... other rules
    );

The validation function "blocked()" in the same model:

    public function blocked($attribute, $params) {
      if(Ipaddress::blocked($this->ip)) {
        $this->addError('ip', 'The IP address you are using is blocked on this site.');
      }
    }

All that is left now is to show to the user that his IP address is blocked in the view that contains the form for writing comments to a blog post. Because the IP address cannot be seen by the user we add the error display right after the display of the content error:

/* @var $comment BlogComment */
 ... 
    <?php echo $form->error($comment,'content'); ?>
    <?php echo $form->error($comment,'ip'); ?>

We are now ready to start using the IP blocking.

Add new comment