Mysql从数据库克隆用户帐户

时间:2014-10-10 04:10:16

标签: mysql

我有一个大约200个表的数据库。我想在此数据库中克隆某个用户帐户。这在mysql中是否可行?

使用克隆我的意思是创建一个具有相同设置的新用户'作为id为14的用户。

2 个答案:

答案 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;
    }
}