2013-05-29 63 views
2

我有一條SELECT語句,我通過PHP和PDO構建,提供已登錄最近XX分鐘的用戶列表。當我硬編碼的時間間隔的SQL語句執行正常,但當我嘗試替換從Web窗體中選擇的時間間隔時,我得到一個SQL錯誤。我不知道什麼是錯的。我使用的PDO和PREPARE語句使用POST數據值作爲參數時發生PDO錯誤

try 
{ 
    $sql = 'SELECT DISTINCT PlayerName 
     FROM Player_Data pd LEFT JOIN character_data cd 
     ON pd.PlayerUID = cd.PlayerUID 
     WHERE cd.LastLogin > DATE_SUB(NOW(), :login_interval_value)'; 
    $statement = $pdo->prepare($sql); 
    $statement->bindValue(':login_interval_value',$_POST['login_interval']); 
    $statement->execute(); 
    $results = $statement->fetchAll(); 
} 
catch (PDOException $e) 
{ 
    $error = 'Error getting player names: ' . $e->getMessage(); 
    include 'error.html.php'; 
    exit(); 
} 

這是我的錯誤...

Error getting player names: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''INTERVAL 60 MINUTES')' at line 4 
+2

爲什麼不嘗試存儲'$ _ POST [「login_interval」]'到另一個變量,並將它的參數? –

+0

根據你的建議,我嘗試過,但我最終有同樣的錯誤。 – webworm

回答

4

兩個更正。時間單位是單數(1)。另一個是你需要你的login_interval發佈數據只是分鐘數。這是完全合法的:

DATE_SUB(NOW(), INTERVAL '60' MINUTE) 

這是不正確的,是當您的文章的數據是整個區間表達式會發生什麼:

DATE_SUB(NOW(), 'INTERVAL 60 MINUTE') 

因此,要麼改變你的表格,以便$ _ POST [「login_interval」]只是分鐘數或從中提取數字。假設你改變你的形式,這是你的代碼更改爲:

try 
{ 
    $sql = 'SELECT DISTINCT PlayerName 
     FROM Player_Data pd LEFT JOIN character_data cd 
     ON pd.PlayerUID = cd.PlayerUID 
     WHERE cd.LastLogin > DATE_SUB(NOW(), INTERVAL :login_interval_value MINUTE)'; 
    $statement = $pdo->prepare($sql); 
    $statement->bindValue(':login_interval_value',$_POST['login_interval']); 
    $statement->execute(); 
    $results = $statement->fetchAll(); 
} 

1 - https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add

+1

我還想補充一點,我會添加一個檢查來確保$ _POST ['login_interval']實際上是一個數字。閱讀這些文檔,看看MySQL在這種情況下如何處理帶引號的字符串。嵌入像xdazz這樣的鑄造int值的另一點指出。 –

+0

這樣做了!我沒有意識到可以引用INTERVAL的整數值,也不知道bindValue參數是否有單引號。我也想用bindValue來針對SQL注入。非常感謝! – webworm

+0

@webworm請注意,評論與答案本身不同,完全是誤導。 Mysql會將引用的字符串轉換爲數字,而不會造成致命後果。並嵌入像xdazz鑄造int值指出**不是要走的路** –

1

您不能使用佔位符INTERVAL 60 MINUTES,它會引用它。

你只需要值轉換成整數。(郵政號碼,而不是。)

$sql = 'SELECT DISTINCT PlayerName 
    FROM Player_Data pd LEFT JOIN character_data cd 
    ON pd.PlayerUID = cd.PlayerUID 
    WHERE cd.LastLogin > DATE_SUB(NOW(), INTERVAL '.(int)$_POST['login_interval'].' MINUTES)'; 
$statement = $pdo->prepare($sql); 
$statement->execute(); 
$results = $statement->fetchAll();