ThinkPHP 3.2.5 无内置执行 SQL 文件函数,需自行封装:读取文件、剔除注释与空行、智能分割多语句(跳过引号内分号)、逐条执行并返回结果统计。

在 ThinkPHP 3.2.5 中,框架本身没有内置“执行 SQL 文件”的函数,但你可以自己封装一个通用函数,用于读取本地 SQL 文件(如 install.sql),并逐条执行其中的 SQL 语句(支持多语句、注释、分号分割等)。下面是一个实用、稳定、适配 TP3.2.5 的实现方式。
一、创建执行 SQL 文件的函数(推荐放于 Common/Function.php)
将以下函数添加到你的项目公共函数文件中(如 Application/Common/Function.php),这样全站可直接调用:
function executeSqlFile($sqlFilePath) {
if (!is_file($sqlFilePath)) {
return ['status' => false, 'msg' => 'SQL 文件不存在:' . $sqlFilePath];
}
<pre class="brush:php;toolbar:false;">$sqlContent = file_get_contents($sqlFilePath);
// 移除注释(-- 和 /* */ 类型)和空行
$sqlContent = preg_replace('/--.*$/m', '', $sqlContent); // 删除 -- 注释
$sqlContent = preg_replace('//*[sS]*?*//', '', $sqlContent); // 删除 /* */ 注释
$sqlContent = preg_replace('/^s*[
]+/m', '', $sqlContent); // 清理空行
// 按分号切分语句(注意:需跳过引号/转义内的分号)
$sqls = [];
$len = strlen($sqlContent);
$sql = '';
$inSingleQuote = false;
$inDoubleQuote = false;
$escaped = false;
for ($i = 0; $i < $len; $i++) {
$char = $sqlContent[$i];
$nextChar = ($i + 1 < $len) ? $sqlContent[$i + 1] : '';
if ($escaped) {
$sql .= $char;
$escaped = false;
continue;
}
if ($char === '\') {
$escaped = true;
$sql .= $char;
continue;
}
if ($char === "'" && !$inDoubleQuote) {
$inSingleQuote = !$inSingleQuote;
} elseif ($char === '"' && !$inSingleQuote) {
$inDoubleQuote = !$inDoubleQuote;
} elseif ($char === ';' && !$inSingleQuote && !$inDoubleQuote) {
$sql = trim($sql);
if (!empty($sql)) {
$sqls[] = $sql;
}
$sql = '';
continue;
}
$sql .= $char;
}
$sql = trim($sql);
if (!empty($sql)) {
$sqls[] = $sql;
}
// 使用 ThinkPHP 原生 M() 或 Db() 执行(TP3.2.5 推荐用 M 或 D 配合原生查询)
$model = M(); // 或 new ThinkModel();
$successCount = 0;
$errorList = [];
foreach ($sqls as $index => $sql) {
if (empty($sql)) continue;
try {
$result = $model->execute($sql);
if ($result !== false) {
$successCount++;
} else {
$errorList[] = "第 " . ($index + 1) . " 条执行失败:$sql";
}
} catch (Exception $e) {
$errorList[] = "第 " . ($index + 1) . " 条异常:{$e->getMessage()}($sql)";
}
}
if (!empty($errorList)) {
return [
'status' => false,
'msg' => '部分语句执行失败',
'success' => $successCount,
'failed' => count($errorList),
'errors' => $errorList
];
}
return ['status' => true, 'msg' => 'SQL 文件执行成功', 'total' => count($sqls), 'success' => $successCount];}
二、使用示例(如在控制器中调用)
比如在 Application/Home/Controller/InstallController.class.php 中:
立即学习“PHP免费学习笔记(深入)”;
public function index() {
$sqlFile = RUNTIME_PATH . '../Public/install.sql'; // 路径按实际调整
$result = executeSqlFile($sqlFile);
<pre class="brush:php;toolbar:false;">if ($result['status']) {
$this->success('安装成功!', U('Home/Index/index'));
} else {
$this->error('安装失败:' . $result['msg'] . '<br/>错误详情:' . implode('<br/>', $result['errors']));
}}
三、注意事项与建议
-
SQL 文件路径要正确:建议放在
Public/或Conf/下,避免被 Web 直接访问;执行后可考虑自动删除或重命名。 -
不支持存储过程/函数定义:TP3.2.5 的
$model->execute()对DELIMITER和多语句复杂结构兼容性差,如含CREATE PROCEDURE,建议拆分处理或改用命令行导入。 -
字符集注意:确保 SQL 文件保存为 UTF-8 无 BOM 格式,且数据库连接已设好
'DB_CHARSET' => 'utf8'(在Conf/config.php中)。 -
大文件慎用:该函数一次性加载全文,若 SQL 文件超几 MB,建议改用分块读取或系统命令(如
mysql -u -p )。
四、替代方案(简单场景可用)
如果 SQL 文件很简短、无注释/复杂语法,也可用极简版:
function quickImportSql($file) {
$sqls = array_filter(array_map('trim', explode(';', file_get_contents($file))));
$m = M();
foreach ($sqls as $sql) {
if ($sql) $m->execute($sql);
}
}⚠️ 仅限测试环境或纯建表/插入语句,生产环境请用上面完整版。



















