PHP do/while Prepared Statement 失败

Posted

技术标签:

【中文标题】PHP do/while Prepared Statement 失败【英文标题】:PHP do/while Prepared Statement failing 【发布时间】:2010-11-18 04:24:27 【问题描述】:

我有一个代码用于检查我的数据库以查看给定值是否唯一,如果是,则将其插入数据库。如果它不是唯一的,请重复该过程,直到找到唯一的值。

do 
    // Generate a new user ID (15 numbers) and check to make sure it doesn't already exist.
    $new_user_id = mt_rand(1000000000, 9999999999);

    // Generate a fake Login Email address and check to make sure it doesn't already exist.
    $new_username = rand_str(13, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890');
    $new_username_email = 'BP' . $new_username . '@web.com';

    // Generate a new fake password
    $new_password = rand_str(15, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()');

    // Check to make sure the extremely random Username and user ID doesn't already exist in the database
    // On the off chance that it does, we need to regenerate and try again.

    $preparedStatement = $connection->prepare("SELECT user_id, username FROM `$mysql_table` WHERE user_id = :new_user_id OR username = :new_username");
    $preparedStatement->execute(array(':new_user_id' => $new_user_id, ':new_username' => $new_username_email));
    $result_2 = $preparedStatement->fetchAll();

    //TODO Not sure if this is actually working if there is a duplicate entry
 while (!empty($result_2));

// Once it is unique, insert the values into the database

$preparedStatement = $connection->prepare(
    "INSERT INTO `$mysql_table` (
        open_id, 
        user_id, 
        username, 
        password
    ) VALUES (
        :open_id_value, 
        :user_id_value, 
        :username_value, 
        :password_value
    )");

    if (!$preparedStatement->execute(array(
        ':open_id_value' => $_SESSION['user'], 
        ':user_id_value' => $new_user_id, 
        ':username_value' => $new_username_email, 
        ':password_value' => $new_password
    ))) 
        $arr = $preparedStatement->errorInfo();
                    die(print_r($arr));                             
     else 
    // Send the new user to the account settings page, where they can set up their account information
        $_SESSION['new_user'] = 1;
        //echo 'You are a new user!';
        header("Location: /account-settings/");
        exit;                       
    

我得到的问题是 mt_rand 生成的值说它是重复的。

Array ( [0] => 23000 [1] => 1062 [2] => Duplicate entry '2147483647' for key 1 ) 1

首先,我不知道为什么我会从这段代码中得到一个重复的错误 - 它有什么问题?其次,如果我确实得到了一个副本,它应该会重新生成并重试,直到它起作用 - 但这显然不会发生。

有什么线索吗?

【问题讨论】:

2147483647 是一个可疑 ID,因为它是 2^31 - 1。您的 userID 列的数据类型是什么。如果它是 int ,那么您将生成高于该列允许的最大值的随机数并尝试插入它们。 它是 int - 我应该简单地切换到 char 吗? 我想我可以做 bigint... 让我试试 这解决了第一个问题 - 我完全忘记了数量限制,谢谢!不过,#2 仍然是一个问题——我至少不应该陷入循环,直到它产生小于 2147483647 的东西? 【参考方案1】:

详细说明我的评论...您的脚本生成了一个随机数,大约 80% 的时间会高于 int 的最大值。您用于测试 user_id 是否已被使用的查询将返回 false (mysql 允许您在列的范围限制之外进行查询,它只是说没有具有该 id 的记录),但随后插入查询将失败,因为数字会减小到最大 INT 大小。要解决此问题,请切换到 BIGINT 或限制随机范围。

【讨论】:

您是说脚本将检查生成数字的实际值(例如 9999999999)以查看它是否存在,这就是它通过的原因,但是要插入的数字会减少一次尝试插入? 谢谢老兄。天才。我本可以为此痛打自己几个小时,而你在几分钟内就做到了。如果可以的话,我会投票 8 次【参考方案2】:

尝试将您的 ID 列更改为 BIGINT 与 INT,因为您似乎正在尝试生成高于 INT 类型容量的随机数。这就是为什么它将它降低到 2147483647,这是 INT 最大数。

【讨论】:

谢谢,到目前为止 - 关于为什么代码在生成小于 2147483647 的数字之前不会循环的任何想法?【参考方案3】:

限制mt_rand(1000000000,2147483647); int 数据类型不能处理更多。

【讨论】:

感谢您的帮助 - 关于为什么代码在生成小于 2147483647 的数字之前不会循环的任何想法? 不是上述代码的情况。不会超过 2147483647【参考方案4】:

使用 auto_increment 字段会更好,因此只要用户 name 是唯一的,您就可以插入每条记录。您可以使用检索最后插入记录的 id mysql_insert_id() 如果你真的需要它。

如果您真的希望这些数字看起来是随机的,您可以使用一些加密(如异或或特定位随机播放)来生成另一个数字,您可以随时将其计算回存储在数据库中的真实用户 ID。

【讨论】:

以上是关于PHP do/while Prepared Statement 失败的主要内容,如果未能解决你的问题,请参考以下文章

php学习笔记-do while循环

php do / while循环

PHP循环语句深度理解分析——while, for, foreach, do while

PHP循环 跳转 替代语法 函数 返回总结

有没有办法在 PHP 中执行 do、while 循环时监听新的套接字连接?

PHP MySQLi Prepared Statements Tutorial to Prevent SQL Injection