Description: I am creating an IP class that first finds the visitor's IP address (using $_SERVER['REMOTE_ADDR']
or getenv('REMOTE_ADDR')
), makes sure it's a valid IP, set's the version (IPv4 or IPv6) to a data member, then it either returns the IP address, or returns the SQL parameter if it's for an SQL query (see createQueryParam()
function below for available returns).
Question: If the server is not running MySQL 5.6.3+, how can I convert a IPv6 binary stored in the database table (varbinary(16)
) to a string?
For an IPv6 and on systems not running MySQL 5.6.3+ I'd like to return a MySQL function, or is it possible to do a bitwise operation? Otherwise, I'd have to do another call after the findIP()
to use PHP's inet_ntop() function and I really rather not do that.
PHP:
class IP
{
protected $ip=NULL;
protected $ip_version=NULL;
/**
* setIP
*
* Sets the data member $ip.
*
* @param $ip
* @access protected
*/
protected function setIP($ip)
{
# Check if the passed value is empty.
if(!empty($ip))
{
# Clean it up.
$ip=$ip;
}
else
{
# Explicitly set it to NULL.
$ip=NULL;
}
# Set the data member.
$this->ip=$ip;
} #==== End -- setIP
/**
* setIPVersion
*
* Sets the data member $ip_version.
*
* @param $ip_version
* @access protected
*/
protected function setIPVersion($ip_version)
{
# Set the Validator instance to a variable.
$validator=Validator::getInstance();
# Check if the passed value is NULL.
if($ip_version!==NULL)
{
# Clean it up.
$ip_version=trim($ip_version);
# Check if the passed value is an integer.
if($validator->isInt($ip_version)===TRUE)
{
# Explicitly make it an integer.
$ip_version=(int)$ip_version;
}
else
{
throw new Exception('The passed IP version was not a number!', E_RECOVERABLE_ERROR);
}
}
else
{
# Explicitly set it to NULL.
$ip_version=NULL;
}
# Set the data member.
$this->ip_version=$ip_version;
} #==== End -- setIPVersion
/**
* getIP
*
* Returns the data member $ip.
*
* @access public
*/
public function getIP()
{
return $this->ip;
} #==== End -- getIP
/**
* getIPVersion
*
* Returns the data member $ip_version.
*
* @access public
*/
public function getIPVersion()
{
return $this->ip_version;
} #==== End -- getIPVersion
/**
* createQueryParam
*
* Determines what MySQL function should be used based on MySQL version.
*
* @param $ip The visitor's IP address or ip field in database table.
* @access public
* @return string
*/
public function createQueryParam($ip, $select_query=FALSE)
{
# Set the Database instance to a variable.
$db=DB::get_instance();
# Get the database client version.
$client_version=$db->client_version;
# If the client version is 5.6.3+ use INET6_ATON.
if($client_version>=50603)
{
# If this is not for a select query.
if($select_query===FALSE)
{
return " INET6_ATON('".$ip."')";
}
# This is for a select query.
return ' INET6_NTOA(`'.$ip.'`)';
}
# Else we assume PHP has IPv6 support and use PHP's inet_pton() to convert the IP to a binary.
else
{
# If this is not for a select query.
if($select_query===FALSE)
{
# If IPv4 then use MySQL function.
if($this->getIPVersion()==4)
{
return " INET_ATON('".$ip."')";
}
else
{
# Supports IPv4 & IPv6 (if PHP has IPv6 supprot enabled).
return inet_pton($ip);
}
}
# NOTE: How to handle select queries for IPv6 if MySQL version is less then 5.6.3?
# Can a MySQL bitwise operation be used here?
# IPv4 Only.
//return ' INET_NTOA(`'.$ip.'`)';
# For IPv6 I could use PHP's inet_ntop() but we can't return it here.
}
} #=== End -- createQueryParam
/**
* findIP
*
* Returns the IP of the visitor.
* Throws an error if the IP address is not valid.
*
* @param bool $for_sql_query Convert IP addresss to binary for database.
* @access public
* @return string
*/
public function findIP($for_sql_query=FALSE)
{
# Get the visitor's IP addreess.
# Use $_SERVER over getenv() since it's more server compatible.
# If $_SERVER['REMOTE_ADDR'] is empty, use getenv().
$ip=$ip=(!empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : getenv('REMOTE_ADDR');
# Check if the IP Address is valid.
# Throws an error if the IP is not valid.
if($this->ipValid($ip)===TRUE)
{
# If we need to create the IP to a binary.
if($for_sql_query===TRUE)
{
# Convert the visitor's IP to a binary.
$ip=$this->createQueryParam($ip);
}
# Set the IP address to the data member.
$this->setIP($ip);
}
# Return the data member.
return $this->getIP();
} #==== End -- findIP
/**
* ipValid
*
* Will determine if a given IP address is valid or not.
* Will set the version of the IP address to the $ip_version data member.
* Throws an error if the IP is not valid.
*
* @access public
* @param $ip The IP address to validate.
* @return boolean
*/
public function ipValid($ip)
{
# Detect if it is a valid IPv4 Address
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
{
# This is an IPv4 address.
$version=4;
}
# Detect if it is a valid IPv6 Address
elseif(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
{
# This is an IPv6 address.
$version=6;
}
if(isset($version))
{
$this->setIPVersion($version);
return TRUE;
}
else
{
throw new Exception('The IP address was not valid!', E_RECOVERABLE_ERROR);
}
return FALSE;
} #==== End -- ipValid
} #=== End IP class.
Examples:
Visitor's IP is 2001:cdba:0000:0000:0000:0000:3257:9652
The MySQL or PHP function used for an INSERT:
# Create a new IP object.
$ip_obj=new IP();
# This is for an SQL query.
$ip=$ip_obj->findIP(TRUE);
# On systems not running MySQL 5.6.3+ it uses PHP's inet_pton().
# $ip = ͺ2W�R
$sql='INSERT INTO `ip_log` (`ip`) VALUES ('.$ip.')';
# $sql = INSERT INTO `ip_log` (`ip`) VALUES ( ͺ2W�R);
The MySQL or PHP function used for a SELECT:
# Create a new IP object.
$ip_obj=new IP();
# Will return the correct MySQL function to use.
# `ip` is the field in the `ip_log` table.
$ip_field=$ip_obj->createQueryParam('ip', TRUE);
# On systems not running MySQL 5.6.3+ I'd like to return a MySQL function, or is it possible to do a bitwise operation? Otherwise, I'd have to do another call in the PHP to use PHP's inet_ntop() function.
# This is where I need help.