2017-03-04 39 views
1

经过许多小时的搜索后,我只能找到“过时”和/或“不完整”的答案。 (显然他们早于PDO。)我正在编写PHP代码(版本7.0.15),并使用MySQL版本5.7.17-0(都在KUbuntu“虚拟机”上)。尽管我已经使用计算机超过45年了,但我对PHP和MySQL相当陌生。从PHP中存储IP到MySQL

我可以在PHP中获取访问者的IP地址。然后我想检查“try_ur_table”来查看它是否已经有一个条目,如果没有,然后插入条目并查找它,所以我可以在程序的其他部分使用“ur_index”。 ur_index是一个int(11),ur_ip是二进制(16)。

问题是,每次运行代码时,第一个选择都会失败,因此会创建一个新条目,然后第二个选择也无法找到匹配!

下面是相关的代码片段:

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; 
    } 

其他测试表明,$ _ SERVER [“REMOTE_ADDR”]将返回127.0.0.1(这是有道理的,因为这是“本地主机”)。然而,每次我运行上面的代码,phpMyAdmin说ur_ip是0x7f00000001000000000000000000000(希望我已经正确计算了零 - 似乎无法从phpMyAdmin复制&粘贴,但这是次要的)。另外,因为我有ur_index,所以我尝试了基于它的选择,当我试图通过inet_ntop()运行ur_ip时,我得到垃圾,既没有有效的IPv4也没有IPv6地址。

+1

[参见如何创建一个最小的,完整的,并且可验证的示例](http://stackoverflow.com/help/mcve) –

+0

当你插入一个新条目,你不必回去选择相同的数据。 PDO :: lastInsertId是你的朋友。 – malcanso

+0

45年?你是说当他们仍然是蒸汽动力? ;-) – Strawberry

回答

0

您的问题源于二进制类型。要匹配存储的值,您应该填充要比较的数据,如the documentation中所示。

或者你可以简单地使用VARBINARY来避免麻烦。

此外,你的代码是非常复制,因此难以阅读和维护。例外的想法是,你一次捕获所有。还有一些条件是无用的,你应该使用不fetchAll(),但fetch method that is appropriate for your task

当然,试图解码不是实际的二进制值,但其由phpmyadmin显示的十六进制表示不会给你任何明智的结果。

以下是您要求的最小,完整和可验证示例。它代表了实际的问题,并且只要提供了正确的证书,谁就可以运行它。

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(); 
} 
+0

谢谢!由于这仍然是“玩具”状态,我在桌上做了一个“放下”,并用ur_ip作为varbinary(16)而不是二进制(16)重建它,现在它可以工作。 – ClarkInAz

+0

由于它** INSISTS **在5分钟内输入我的评论(argh),我会在这里添加更多内容。 我想我可能误导了一下:我试着从SELECT * WHEN ur_index = 1的数据尝试inet_ntop(),而不是从phpMyAdmin手动剪切/粘贴。 一个临时的mod显示inet_ntop()认为ur_ip的内容是127.0.0.1,这是正确的答案。 也谢谢你的评论。正如我所指出的,当谈到MySQL/PHP时,我是一个“新手”。 – ClarkInAz