简体   繁体   English

从PHP存储MySQL中的IP

[英]Storing IP in MySQL from PHP

After many hours of searching, I can only find "obsolete" and/or "incomplete" answers. 经过几个小时的搜索,我只能找到“过时”和/或“不完整”的答案。 (Apparently they predate PDO.) I'm writing PHP code (version 7.0.15), and using MySQL version 5.7.17-0 (both on a KUbuntu "virtual machine"). (显然它们早于PDO。)我正在编写PHP代码(版本7.0.15),并使用MySQL版本5.7.17-0(两者都在KUbuntu“虚拟机”上)。 Though I've been working with computers for more than 45 years, I'm fairly new to PHP and MySQL. 虽然我已经使用计算机超过45年了,但我还不熟悉PHP和MySQL。

I can get the visitor's IP address in PHP. 我可以用PHP获取访问者的IP地址。 I then want to check the "try_ur_table" to see if it already has an entry, and if not, then insert an entry and look it up, so I can then use the "ur_index" in other parts of the program. 然后我想检查“try_ur_table”以查看它是否已经有一个条目,如果没有,则插入一个条目然后查找,这样我就可以在程序的其他部分使用“ur_index”了。 The ur_index is an int(11), and the ur_ip is binary(16). ur_index是int(11),ur_ip是二进制(16)。

The problem is that every time I run the code, the first select fails, so a new entry is made, and then the second select also fails to find a match! 问题是,每次运行代码时,第一个选择失败,所以创建一个新条目,然后第二个选择也找不到匹配!

Here's the relevant code snippet: 这是相关的代码段:

  try
  {
    $pdc = new PDO('mysql:host=localhost;dbname=toy_database', 'xxxxx', 'xxxxx' );
    $pdc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdc->exec('SET NAMES "utf8"');
  }
  catch (PDOException $e)
  {
    $output = 'Unable to connect tothe databaseserver. ' . $e->getMessage();
    include 'errout.html.php';
    exit();
  }
  // Find the caller data...
  if ( isset( $_SERVER[ 'REMOTE_ADDR' ] ) )
  {
    $cd = inet_pton( $_SERVER[ 'REMOTE_ADDR' ] );
    if ( $cd )
    {
      // inet_pton thinks it succeeded...
      try
      {
        $sql = "SELECT * FROM try_ur_table WHERE ur_ip = ? ";
        $rt = $pdc->prepare($sql);
        $rt->execute(array($cd));
        $u_list = $rt->fetchAll();
      }
      catch (PDOException $e)
      {
        $output = 'Problem looking for ur_ip.  ' .  $e->getMessage();
        include 'errout.html.php';
        exit();
      }
      if ( $u_list == NULL )
      {
        // New user!
        try
        {
          $sqm = "INSERT INTO try_ur_table SET ur_ip=?";
          $rs = $pdc->prepare($sqm);
          $rs->execute(array($cd));
        }
        catch (PDOException $e)
        {
          $output = 'Problem inserting new ur_ip. ' . $e->getMessage();
          include 'errout.html.php';
          exit();
        }
        // Now go find the new entry...
        try
        {
          $sql = "SELECT * FROM try_ur_table WHERE ur_ip = ? ";
          $rt = $pdc->prepare($sql);
          $rt->execute(array($cd));
          $u_list = $rt->fetchAll();
        }
        catch (PDOException $e)
        {
          $output = 'Problem looking for new ur_ip.  ' . $e->getMessage();
          include 'errout.html.php';
          exit();
        }
      } // $u_list == NULL
      // At this point there should be exactly one row in $u_list...
    } // $cd != false
  }
  else
  {
    // ! isset( $_SERVER[ 'REMOTE_ADDR' ]
    $cd = false;
  }

Other testing has shown that $_SERVER[ 'REMOTE_ADDR' ] is returning 127.0.0.1 (which makes sense, as this is "local host"). 其他测试表明$ _SERVER ['REMOTE_ADDR']返回127.0.0.1(这是有意义的,因为这是“本地主机”)。 However, for each time I've run the above code, phpMyAdmin says that ur_ip is 0x7f00000001000000000000000000000 (hopefully I've counted the zeros correctly -- can't seem to copy & paste from phpMyAdmin, but that's minor). 但是,每次我运行上面的代码,phpMyAdmin说ur_ip是0x7f00000001000000000000000000000(希望我正确计算零 - 似乎无法从phpMyAdmin复制和粘贴,但这是次要的)。 Also, since I have ur_index, I've tried a select based on it, and when I tried to run the ur_ip through inet_ntop() I get garbage, neither a valid IPv4 nor an IPv6 address. 此外,由于我有ur_index,我已经尝试了基于它的选择,当我尝试通过inet_ntop()运行ur_ip时,我得到垃圾,既不是有效的IPv4也不是IPv6地址。

Your problem stems from the binary type. 您的问题源于二进制类型。 To match a stored value you should pad the data to be compared, as it shown in the documentation . 要匹配存储的值,您应该填充要比较的数据,如文档中所示。

Or you can simply use VARBINARY to avoid the hassle. 或者你可以简单地使用VARBINARY来避免麻烦。

Besides, your code is awfully duplicated and thus hard as hell to read and maintain. 此外,您的代码非常复制,因此难以阅读和维护。 The very idea of exceptions is that you are catching them all once . 异常的想法是你一次抓住它们。 Also some conditions are useless and you should use not fetchAll() but the fetch method that is appropriate for your task . 还有一些条件是无用的,你应该使用不是fetchAll(),而是使用适合你的任务fetch方法

And of course, trying to decode not the actual binary value , but its hexdecimal representation displayed by phpmyadmin wouldn't give you any sensible result indeed. 当然,尝试解码不是实际的二进制值 ,但是phpmyadmin显示的十六进制表示确实不会给你任何明智的结果。

Below is the Minimal, Complete, and Verifiable example you've been asked for. 以下是您被要求的最小,完整和可验证的示例。 It represents the actual problem and works for anyone who care to run it, as long as correct credentials are provided. 只要提供了正确的凭据,它就代表了实际问题并适用于任何关心运行它的人。

try {
    $pdc = new PDO('mysql:host=localhost;dbname=toy_database;charset=utf8', 'xxxxx', 'xxxxx' );
    $pdc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // let's create a temporary table for the example purpose
    // change varbinary for binary and it goes astray
    $pdc->query("CREATE temporary TABLE try_ur_table 
                 (ur_index int primary key auto_increment,ur_ip varbinary(16))");

    $cd = inet_pton( $_SERVER["REMOTE_ADDR"] );

    $sql = "SELECT ur_index FROM try_ur_table WHERE ur_ip = ? ";
    $rt = $pdc->prepare($sql);
    $rt->execute(array($cd));
    $ur_index = $rt->fetchColumn();

    if ( !$ur_index )
    {
        $sqm = "INSERT INTO try_ur_table SET ur_ip=?";
        $pdc->prepare($sqm)->execute(array($cd));
        // here: that's all you need to get the index
        $ur_index = $pdc->lastInsertId();
    }

    // OK, let's verify
    $sql = "SELECT ur_ip FROM try_ur_table WHERE ur_ip = ? ";
    $rt = $pdc->prepare($sql);
    $rt->execute(array($cd));
    $ur_ip = $rt->fetchColumn();
    var_dump($ur_ip === $cd, bin2hex($ur_ip));

} catch (PDOException $e) {
    error_log($e);
    $output = ini_get('display_errors') ? $e : "There is a temporary problem. Try again later";
    include 'errout.html.php';
    exit();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM