2017-03-04 31 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