PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] ); } catch (PDOException $e) { exit("数据库连接失败:{$e->getMessage()}\n"); } // 解析命令行参数(--table=xxx) $forcedTable = ''; foreach ($argv as $a) { if (strpos($a, '--table=') === 0) { $forcedTable = substr($a, strlen('--table=')); } } // 常见弱密码字典 $weakList = ['123456','12345678','123456789','password','admin123','qwerty','111111','abc123','123123','root']; // ---- 自动探测员工表与字段 ---- function getAllTables($pdo) { return $pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN); } function getColumns($pdo, $table) { return $pdo->query("SHOW COLUMNS FROM `{$table}`")->fetchAll(PDO::FETCH_COLUMN); } // 从字段列表中挑选首个命中的字段名 function pickField(array $cols, array $candidates) { foreach ($candidates as $c) { if (in_array($c, $cols, true)) return $c; } return ''; } function chooseEmployeeTable($pdo, $forced) { $tables = getAllTables($pdo); if ($forced !== '') { if (!in_array($forced, $tables, true)) { exit("指定的表 `{$forced}` 不存在。可用表:\n " . implode("\n ", $tables) . "\n"); } return $forced; } // 候选评分:优先名称含 employee,其次含 user/admin/staff,且字段需含密码字段 $scored = []; foreach ($tables as $t) { $cols = getColumns($pdo, $t); $pwdField = pickField($cols, ['password','pwd','passwd','user_pass','user_password','hash','pass']); if ($pwdField === '') continue; // 无密码字段,不是用户表 $score = 0; if (stripos($t, 'employee') !== false) $score += 100; if (stripos($t, 'admin') !== false) $score += 60; if (stripos($t, 'user') !== false) $score += 50; if (stripos($t, 'staff') !== false) $score += 40; if (stripos($t, 'member') !== false) $score += 30; if (stripos($t, 'jp_') === 0) $score += 10; // 业务前缀表 if ($score > 0) { $scored[] = ['table' => $t, 'score' => $score, 'cols' => $cols]; } } if (empty($scored)) { exit("未在数据库中找到含密码字段的用户表。所有表:\n " . implode("\n ", $tables) . "\n请使用 --table=表名 手动指定。\n"); } // 分数最高者唯一则直接用;否则列出候选请用户指定 usort($scored, fn($a, $b) => $b['score'] <=> $a['score']); $top = $scored[0]['score']; $topCandidates = array_values(array_filter($scored, fn($x) => $x['score'] === $top)); if (count($topCandidates) === 1) { return $topCandidates[0]['table']; } echo "检测到多个候选用户表,请使用 --table= 指定其中一个:\n"; foreach ($scored as $c) { echo " {$c['table']} (score={$c['score']})\n"; } exit; } $table = chooseEmployeeTable($pdo, $forcedTable); $cols = getColumns($pdo, $table); // 字段映射(自适应不同命名) $idField = pickField($cols, ['id']) ?: 'id'; $pwdField = pickField($cols, ['password','pwd','passwd','user_pass','user_password','hash','pass']); $empNoField = pickField($cols, ['emp_no','username','user_no','job_no','work_no','account','login_name','user_name','login_id']); $nameField = pickField($cols, ['emp_name','name','user_name','real_name','nickname','truename']); $roleField = pickField($cols, ['role','position','job_title','type','user_type']); if ($pwdField === '') { exit("表 `{$table}` 未找到密码字段,已中止以避免误操作。\n"); } echo "使用员工表:`{$table}`\n"; echo "字段映射:id={$idField}, 密码={$pwdField}, 工号=" . ($empNoField ?: '(无)') . ", 姓名=" . ($nameField ?: '(无)') . ", 角色=" . ($roleField ?: '(无)') . "\n\n"; // 构造 SELECT(仅选存在的字段) $selectCols = array_filter([$idField, $empNoField, $nameField, $pwdField, $roleField]); $sql = "SELECT " . implode(', ', array_map(fn($c) => "`{$c}`", $selectCols)) . " FROM `{$table}`"; $rows = $pdo->query($sql)->fetchAll(); $changed = []; foreach ($rows as $r) { $hash = $r[$pwdField] ?? ''; if (!is_string($hash) || $hash === '') continue; $isWeak = false; foreach ($weakList as $w) { if (password_verify($w, $hash)) { $isWeak = true; break; } } if (!$isWeak) continue; $newPwd = generateStrongPassword(16); $hashNew = password_hash($newPwd, PASSWORD_BCRYPT, ['cost' => 12]); $pdo->prepare("UPDATE `{$table}` SET `{$pwdField}` = :h WHERE `{$idField}` = :id") ->execute([':h' => $hashNew, ':id' => $r[$idField]]); $changed[] = [ 'emp_no' => $empNoField ? ($r[$empNoField] ?? '') : $r[$idField], 'emp_name' => $nameField ? ($r[$nameField] ?? '') : '', 'new' => $newPwd, ]; } if ($changed) { echo "已将以下使用弱密码的账号重置为强密码(请妥善保存):\n"; foreach ($changed as $c) { echo " emp_no={$c['emp_no']} name={$c['emp_name']} NEW_PASSWORD={$c['new']}\n"; } echo "\n等效 SQL(如需在 phpMyAdmin 手动执行):\n"; foreach ($changed as $c) { $h = password_hash($c['new'], PASSWORD_BCRYPT, ['cost' => 12]); $ident = $empNoField ? "{$empNoField} = '{$c['emp_no']}'" : "{$idField} = '{$c['emp_no']}'"; echo "UPDATE `{$table}` SET `{$pwdField}` = '$h' WHERE {$ident};\n"; } } else { echo "未发现使用弱密码的账号,无需处理。\n"; } function generateStrongPassword($len = 16) { $upper = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; $lower = 'abcdefghijkmnpqrstuvwxyz'; $digit = '23456789'; $special = '!@#$%^&*'; $all = $upper . $lower . $digit . $special; $pwd = $upper[random_int(0, strlen($upper) - 1)] . $lower[random_int(0, strlen($lower) - 1)] . $digit[random_int(0, strlen($digit) - 1)] . $special[random_int(0, strlen($special) - 1)]; for ($i = strlen($pwd); $i < $len; $i++) { $pwd .= $all[random_int(0, strlen($all) - 1)]; } $arr = str_split($pwd); shuffle($arr); return implode('', $arr); }