【问题标题】:generate a random password and update the database生成随机密码并更新数据库
【发布时间】:2018-12-13 19:19:53
【问题描述】:

我必须使用随机唯一密码更新所有现有用户的密码。我有大约 4000 个用户使用 SQL SERVER。

我的代码是

$userSQL = "SELECT a002UserID FROM tbl002password WHERE a002UserID LIKE 'non%'";
$userrs  = $db->query($userSQL);
$userList1 = array();
while($row = $userrs->fetch(PDO::FETCH_OBJ)){
    $userList1[] = $row->a002UserID;
}
foreach($userList1 as $uid){
    function generatePassword ($length = 8)
    {
        $password = '';
        $chars = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9));
        for ($i = 0; $i < $length; $i ++) {
            $password .= $chars[array_rand($chars)];
        }
        return $password;
    }

    $pass_gen = generate_password();
    $insertPass = "UPDATE tbl002password SET a002password = '$pass_gen' WHERE a002UserID = '$uid'";
    $db->exec($insertPass);
    echo "updated $uid";
}

如果删除'for'循环

  • 当我只为一个用户运行查询时,它运行良好。
  • 选择所有用户时为所有用户分配相同的密码。

【问题讨论】:

  • 看起来容易出现竞争条件,因为您先选择然后更新。此外,它看起来也容易出现 SQL 注入。如果外部世界无法访问此代码并且只有一个用户在运行,则忘记我所说的了。乍一看,您需要将函数 generatePassword() 放在循环之外。
  • 不要存储纯文本密码,对它们进行哈希处理。
  • 我确实将函数放在了循环之外,但它不起作用。

标签: php sql sql-server


【解决方案1】:
// 1. Don't declare functions inside loops. Functions should generally only ever be declared
//    in either the global scope, or a class definition.
function generatePassword ($length = 8) {
    $password = '';
    $chars = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9));
    for ($i = 0; $i < $length; $i ++) {
        $password .= $chars[array_rand($chars)];
    }
    return $password;
} 

$userSQL = "SELECT a002UserID FROM tbl002password WHERE a002UserID LIKE 'non%'";
$userrs  = $db->query($userSQL);

$userList1 = array();
while($row = $userrs->fetch(PDO::FETCH_OBJ)) {
    $userList1[] = $row->a002UserID;
}

// 2. Preparing statements like this increase performance as they are only parsed _once_,
//    but executed many times.
$insertPass = $db->prepare("UPDATE tbl002password SET a002password = ? WHERE a002UserID = ?");
foreach($userList1 as $uid) {
    $pass_gen = generate_password();
    $insertPass->execute([$pass_gen, $uid]);
    echo "updated $uid";
}

【讨论】:

    【解决方案2】:

    为什么要遍历 4,000 行?

    我会应用一个更新

    示例

    Declare @tbl002password  table (a002UserID  varchar(50),a002password varchar(50))
    Insert Into @tbl002password values
     ('JS1234'   ,'Password1')
    ,('nonTI5656','Password2')
    ,('nonSC5657','Password3')
    
    Update @tbl002password set a002password=right(NewID(),3)+left(abs(convert(bigint,HashBytes('MD5', a002UserID))),5)
     Where a002UserID like 'non%'
    
    
    Select *
     From  @tbl002password
    

    更新后的表格

    a002UserID  a002password
    JS1234      Password1
    nonTI5656   FED25902
    nonSC5657   3C815639
    

    【讨论】:

      【解决方案3】:

      我刚刚在沙盒中运行了这个:

      $userList1 = array(1, 2, 3, 4, 5);
      
      function generatePassword ($length = 8)
          {
              $password = '';
              $chars = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9));
              for ($i = 0; $i < $length; $i ++) {
                  $password .= $chars[array_rand($chars)];
          }
          return $password;
      }; 
      
      
      foreach($userList1 as $uid){
          $pass_gen = generatePassword();
      
          echo $pass_gen . '   ';
      }
      

      结果是这样的:

      ve6XzQzA   cL93fvVH   GtdP3LP3   8rKDRGJ2   qjt9j6Rv 
      

      这对我来说看起来不错。您的代码中有一个明显的语法错误。你叫“generate_password();”而该函数实际上称为“generatePassword”。我同意 Raymond Nijland 就您的 SQL 提出的观点。我也建议您更改此设置。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-08
        • 2012-08-09
        • 1970-01-01
        • 2012-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多