WHERE无法识别和INSERT抛出唯一异常

时间:2013-02-12 16:58:39

标签: php mysql sql pdo

我在这里阅读了一些答案并获得“精心锁定”。我是新人,不在这方面工作,只是在过去的43年里自学了。我转换了我前几天写的点击计数器中的一段代码,它只是计算IP运行被拒绝的访问页面的次数。代码检查IP是否已存在于数据库表中(唯一)。如果是,它只是递增和更新。如果不存在,则将其值为1插入。

一切都很好,然后我发现测试时没有增加。所以我将其隔离并发现它不会识别表列值来更新它,并且当它尝试将其作为新值插入时抛出异常,因为它是唯一的。

我看了看,似乎无法理解为什么它在我的hitcounter中工作得很好,但在这里惨遭失败?!?

$IP = $_SERVER['REMOTE_ADDR'];
$IP = preg_replace('#[^0-9\.]#','',$IP);
$db_table = 'deniedcounter';
echo 'Enter denied_record.php<br />';
//$IP = str_replace('.','x',$IP);

function setdeniedcounter($IP, $db_handle, $db_table){
    $hits = null;
    $ip = "'".$IP."'";
    try{
        echo "SELECT * FROM $db_table WHERE ip = $ip".'<br />';
        $stmt = $db_handle->query("SELECT * FROM $db_table WHERE ip = $ip");
        $row_count = $stmt->rowCount();
        echo $row_count.' = Rows selected.<br />';
    }
    catch(PDOException $e){
        db_exception_handler($e);
    }
    if($row_count == 1){
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        echo $row['ip'].' '.$row['hits'].'<br />';
        $hits = $row['hits']; $ip = $row['ip'];
        $hits++;
        try{
            $stmt = $db_handle->prepare("UPDATE $db_table SET hits=? WHERE ip=?");
            $stmt->execute(array($hits, $ip));
            $affected_rows = $stmt->rowCount();
            echo $affected_rows.'<br />';
        }
        catch(PDOException $e){
            db_exception_handler($e);
        }
        exit();
    }
    elseif($row_count == 0){
        $hits = 1;
        try{
            $stmt = $db_handle->prepare($sql = "INSERT INTO $db_table(ip, hits) VALUES(?, ?)");
            $stmt->execute(array($ip, $hits));
            $affected_rows = $stmt->rowCount();
            //echo $affected_rows.'<br />';
        }
        catch(PDOException $e){
            db_exception_handler($e);
        }
    }
    //echo 'Hits = '.$hits.'<br />';
    if(isset($hits)){return $hits;}
}    

$db_handle = db_OPEN($db_host, $db_name, $db_username, $db_pwd);
if(strlen($IP) > 6){$da_hits = setdeniedcounter($IP, $db_handle, $db_table);}
if(!isset($da_hits)){$da_hits = setdeniedcounter('ALERT', $db_handle, $db_table);}
$db_handle = db_CLOSE($db_handle);
echo 'Exit denied_record.php<br />';
exit();

====================
输出:

Enter denied_record.php

SELECT * FROM deniedcounter WHERE ip = '127.0.0.1'

0 = Rows selected.

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ''127.0.0.1'' 
for key 'ip'

Exit denied_record.php

3 个答案:

答案 0 :(得分:2)

Mysql有一个特殊的操作符。
首先不需要SELECT - 只需要使用一些额外的代码INSERT:

INSERT INTO $ db_table(ip,hits)VALUES(?,?)ON DUPLICATE KEY UPDATE hits = hits + 1

所以,你的功能实际上必须是

function setdeniedcounter($ip, $db_handle, $db_table) {
    $sql  = "INSERT INTO $db_table(ip, hits) VALUES(?, 1) 
             ON DUPLICATE KEY UPDATE hits=hits+1";
    $stmt = $db_handle->prepare();
    $stmt->execute(array($ip));
}    

如果你想要返回命中,你需要选择它们

答案 1 :(得分:1)

问题是你正在检查两个不同的东西。当您使用准备好的语句问号时,MySQL会插入自己的单引号。所以你最初检查的是127.0.0.1是否存在,而不是。然后你尝试插入'127.0.0.1'(包括中的单引号),这已经存在,这就是它失败的原因。

答案 2 :(得分:-3)

数据库中的IP字段是一个字符串。可能在第一个sql语句中你必须使用引号?

$db_handle->query("SELECT * FROM $db_table WHERE ip = $ip");

替换为:

$db_handle->query("SELECT * FROM $db_table WHERE ip = '".$ip."'");