Fix CodeIgniter IP address detection on lighttpd

If the results of a call to $this->input->ip_address() gives you “0.0.0.0” (the “invalid address” response) and you’re running lighttpd as your web server, you may be able to fix it with a minor tweak to by extending one of the base CodeIgniter libraries. An IPv6-style header is being appended to the IPv4 address, most likely, and stripping it out before CodeIgniter considers the validity of your address should restore functionality without circumventing any of the logic.

Crack open the system/libraries/Input.php file and find the following code:

PHP code:

if ( ! $this->valid_ip($this->ip_address))

…and replace it with this:

PHP code:

$this->ip_address = preg_replace("#^[:a-z0-9]+:#i", "", $this->ip_address);		

if ( ! $this->valid_ip($this->ip_address))

Update

As mentioned in Anthony’s comment below, this edit requires that you modify a core CodeIgniter library. In order to avoid this, you can create a class definition in system/application/libraries/Input.php that extends the functionality of the valid_ip() function (which is used internally by $this->input->ip_address()). He has been so kind as to provide a class-encapsulated version of my snippet on github which does just that. Thanks, Anthony!

Here is the updated code:

PHP code:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

require_once(BASEPATH.'/libraries/Input.php');

/**
 * Input Class Override
 *
 * Pre-processes global input data for security
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Input
 * @author		Todd Boyd / ExpressionEngine Dev Team
 * @link		http://codeigniter.com/user_guide/libraries/input.html
 */
class Input extends CI_Input
{

	function Input()
	{
		parent::CI_Input();
		
	}
	/**
	* Validate IP Address
	*
	* Updated version suggested by Geert De Deckere
	*
	* @access	public
	* @param	string
	* @return	string
	* @see		http://roadha.us/2010/10/fix-codeigniter-ip-address-detection-on-lighttpd/
	*/
	function valid_ip($ip)
	{
		$ip = preg_replace("/^[:a-z0-9]+:/i", "", $ip); // See the link in the @see declaration above for more info 
		
		$ip_segments = explode('.', $ip);

		// Always 4 segments needed
		if (count($ip_segments) != 4)
		{
			return FALSE;
		}
		// IP can not start with 0
		if ($ip_segments[0][0] == '0')
		{
			return FALSE;
		}
		// Check each segment
		foreach ($ip_segments as $segment)
		{
			// IP segments must be digits and can not be
			// longer than 3 digits or greater then 255
			if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
			{
				return FALSE;
			}
		}

		return TRUE;
	}
}

If having “::ffff:” in front of your addresses was causing the problem, this snippet should have you back on your way juggling IP addresses in no time.