PHP中建库并导入SQL需分两步:先执行CREATE DATABASE(显式指定字符集),再重新连接该库;推荐用file_get_contents()+逐条mysqli_query()执行,避免multi_query缺陷,或用shell_exec("mysql")调用命令行工具,注意密码安全与错误检测。
PHP 本身不提供“一键建库+导入数据”函数,必须分两步:先建库,再连接该库并执行 SQL 语句。常见错误是建库后没切换数据库连接,导致 mysqli_query() 报错 No database selected。
实操建议:
mysqli::query() 或 PDO::exec() 执行 CREATE DATABASE `mydb` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci(显式指定字符集,避免后续乱码)mysqli_select_db()(mysqli),不能复用原连接file_get_contents() + mysqli_multi_query(),不要用 mysql_query()(已废弃)或逐行 explode(';', $sql)(会误切注释和字符串内的分号)mysqli_multi_query() 卡死mysqli_multi_query() 虽支持批量执行,但不会自动跳过空行、注释或 DELIMITER 变更,遇到存储过程或触发器定义容易中断,且无法获取每条语句的错误详情。
更稳妥的做法是预处理 SQL 内容:
-- 和 /*...*/ 注释(注意避开字符串内出现的 --); 分割语句前,先用状态机跳过引号包裹的内容和括号嵌套(简单场景可用 preg_split('/;(?!.*[\'"])/', $sql) 粗略处理)mysqli_query(),便于定位哪句失败(例如建表语句里字段类型写成 INT(11) 在 MySQL 8.0.19+ 会警告但不报错,而 JSON 字段在旧版本直接报错)shell_exec() 调用 mysql 命令行工具最省事但要注意权限和路径绕过 PHP SQL 解析,直接走系统命令导入,适合大文件或含复杂语法的 SQL(如 LOAD DATA INFILE)。但必须确认:mysqld 进程允许本地 socket 连接、PHP 进程有权限读取 SQL 文件、mysql 命令在 PATH 中。
典型命令写法:
shell_exec("mysql -u root -prootpas
s -h 127.0.0.1 mydb < /path/to/init.sql 2>&1");
关键点:
ps aux 可见),应改用配置文件:mysql --defaults-extra-file=/tmp/my.cnf mydb ,其中 /tmp/my.cnf 权限设为 600
skip-networking,-h 127.0.0.1 会强制走 TCP,需改为 -S /var/run/mysqld/mysqld.sock 指定 socket 路径shell_exec() 输出是否含 ERROR 或 Warning 字样SQL 文件若含 INSERT INTO user VALUES (1,'a'),(2,'b'),而表已有数据,会导致主键冲突;若含 SET FOREIGN_KEY_CHECKS=0 但结尾没恢复,后续操作可能意外破坏参照完整性。
安全做法:
SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET AUTOCOMMIT=0;,导入后补 SET FOREIGN_KEY_CHECKS=1; SET UNIQUE_CHECKS=1; COMMIT;
INSERT 前加 TRUNCATE TABLE 或 DELETE FROM + ALTER TABLE ... AUTO_INCREMENT = 1,否则新数据 ID 可能从高位开始mysqldump --no-create-info 生成,它默认不带 SET 语句,必须手动补全或用 --skip-extended-insert 避免单条语句过长触发 max_allowed_packetCREATE DATABASE 和后续导入最好包在事务外——因为建库操作本身不能回滚,但数据导入失败时得能清理掉空库,这点容易被忽略。