在没有INET6_ATON()的情况下将IPv6转换为二进制

时间:2015-07-05 02:23:35

标签: php mysql binary bitwise-operators

说明:我正在创建一个IP类,该类首先找到访问者的IP地址(使用$_SERVER['REMOTE_ADDR']getenv('REMOTE_ADDR')),确保'如果是有效的IP,请将数据(IPv4或IPv6)设置为数据成员,然后返回IP地址,如果是SQL查询,则返回SQL参数(请参阅{{1}以下函数可用于返回)。

问题:如果服务器没有运行MySQL 5.6.3+,如何将存储在数据库表(createQueryParam())中的IPv6二进制文件转换为字符串?

对于IPv6以及未运行MySQL 5.6.3+的系统,我想返回MySQL功能,还是可以进行按位操作?否则,我必须在varbinary(16)之后再使用PHP的inet_ntop()函数进行另一次调用,而我真的不愿意这样做。

PHP:

findIP()

示例:

访客的IP是2001:cdba:0000:0000:0000:0000:3257:9652

用于INSERT的MySQL或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.

用于SELECT的MySQL或PHP函数:

# 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);

0 个答案:

没有答案