我有一个大约200个表的数据库。我想在此数据库中克隆某个用户帐户。这在mysql中是否可行?
使用克隆我的意思是创建一个具有相同设置的新用户'作为id为14的用户。
答案 0 :(得分:0)
快速谷歌搜索显示你实际上可以做到这一点。有一个名为" " mysql用户克隆",这让你出人意料地克隆了mysql的用户。
如果您查看the manual我确定它为您提供了有关如何使用它的重要提示,例如,此引用:
<强>实施例强>
要使用密码将joe克隆为sam和sally并在本地计算机上以root用户身份登录,请使用以下命令:
$ mysqluserclone --source=root@localhost \
--destination=root@localhost \
joe@localhost sam:secret1@localhost sally:secret2@localhost
# Source on localhost: ... connected.
# Destination on localhost: ... connected.
# Cloning 2 users...
# Cloning joe@localhost to user sam:secret1@localhost
# Cloning joe@localhost to user sally:secret2@localhost
# ...done.
答案 1 :(得分:0)
由于出现了@Nanne的方法,mysqluserclone
被EOL终止/ Oracle不支持,因此我在PHP中编写了类似的实用程序,用法:
<?php
$db = new \PDO("mysql:host={$db_creds->dbhost};dbname={$db_creds->dbname};charset=utf8mb4;port=" . $db_creds->dbport, $db_creds->superuser_user, $db_creds->superuser_pass, array(
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC
));
Mysqluserclone::clone_account($db, "original username", "cloned username");
这部分代码可能会特别令人感兴趣:
if (0) {
echo "the following SQLs will clone this account:\n";
echo implode("\n\n", $sqls_for_cloning) . "\n\n";
die();
}
<?php
class Mysqluserclone{
private function __construct(){
// by making this private, we ensure nobody try to instantiate us.
}
public static function clone_account(\PDO $db_connected_as_superuser, string $original_name, string $clone_name): void
{
$db = $db_connected_as_superuser;
$sqls_for_cloning = [];
$sql = "SELECT COUNT(*) FROM mysql.user WHERE User = " . $db->quote($clone_name);
if (0 !== $db->query($sql)->fetch(\PDO::FETCH_NUM)[0]) {
throw new \InvalidArgumentException("clone name already exists!");
}
$sql = "SELECT * FROM mysql.user WHERE User = " . $db->quote($original_name);
$current_user_one_for_each_host = $db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
foreach ($current_user_one_for_each_host as $user_record) {
$user_record["User"] = $clone_name;
$sql = "INSERT INTO mysql.user SET \n";
foreach ($user_record as $name => $val) {
$sql .= self::mysql_quote_identifier($name) . " = " . self::mysql_quote_better($db, $val) . ",\n";
}
if (! empty($user_record)) {
$sql = substr($sql, 0, - strlen(",\n"));
}
$sql .= ";";
$sqls_for_cloning[] = $sql;
$sqls_for_cloning[] = "FLUSH PRIVILEGES;"; // YES this is required, otherwise you might get "grant not allowed to create accounts" errors
$grants_raw_sql = 'SHOW GRANTS FOR ' . $db->quote($original_name) . '@' . $db->quote($user_record['Host']) . ";";
try {
$grants_raw = $db->query($grants_raw_sql)->fetchAll(\PDO::FETCH_NUM);
} catch (\Throwable $ex) {
// somehow an empty grant table is a mysql error, not an empty rowset.. ignore it.
$grants_raw = [];
}
$grants_raw = array_map(function (array $arr): string {
if (count($arr) !== 1) {
throw new \LogicException("mysql layout for SHOW GRANTS has changed? investigate");
}
return $arr[0];
}, $grants_raw);
$original_name_as_identifier = self::mysql_quote_identifier($original_name);
$clone_name_as_identifier = self::mysql_quote_identifier($clone_name);
foreach ($grants_raw as $grant) {
if (false === strpos($grant, $original_name_as_identifier)) {
throw new \LogicException("original grant without original name as identifier? investigate");
}
$grant = self::str_replace_last($original_name_as_identifier, $clone_name_as_identifier, $grant);
$grant .= ";";
$sqls_for_cloning[] = $grant;
}
}
if (! empty($sqls_for_cloning)) {
$sqls_for_cloning[] = "FLUSH PRIVILEGES;";
}
if (0) {
echo "the following SQLs will clone this account:\n";
echo implode("\n\n", $sqls_for_cloning) . "\n\n";
die();
}
foreach ($sqls_for_cloning as $clone_sql) {
$db->exec($clone_sql);
}
}
private static function mysql_quote_identifier(string $identifier): string
{
return '`' . strtr($identifier, [
'`' => '``'
]) . '`';
}
private static function mysql_quote_better(\PDO $db, $value): string
{
if (is_null($value)) {
return "NULL";
}
if (is_int($value)) {
return (string) $value;
}
if (is_float($value)) {
return number_format($value, 10, '.', '');
}
if (is_bool($value)) {
return ($value ? "1" : "0");
}
return $db->quote($value);
}
private static function str_replace_last(string $search, string $replace, string $subject): string
{
$pos = strrpos($subject, $search);
if ($pos !== false) {
$subject = substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
}