
本文详解如何在 prestashop 自定义模块中,通过钩子(hook)触发文件上传、在钩子逻辑中直接处理 csv 文件并写入数据库,无需额外前端控制器,兼顾安全性与可维护性。
本文详解如何在 prestashop 自定义模块中,通过钩子(hook)触发文件上传、在钩子逻辑中直接处理 csv 文件并写入数据库,无需额外前端控制器,兼顾安全性与可维护性。
在 PrestaShop 开发中,常见误区是将文件上传逻辑拆分到独立的 FrontController 中——这不仅增加路由复杂度,还容易导致 CSRF 风险、上下文丢失及表单验证脱节。实际上,推荐将文件上传、校验与入库逻辑全部封装在钩子方法内,利用 PrestaShop 的 Tools::isSubmit() 和 $_FILES 全局变量直接处理,既简洁又安全。
✅ 正确实现步骤
1. 增强模板:添加 enctype 与提交标识
views/templates/hook/mymodule.tpl 必须声明 multipart/form-data 编码类型,并为提交按钮设置唯一 name 属性,以便后端识别:
<div id="mymodule_block_home">
<form method="POST" enctype="multipart/form-data">
<label for="csv_file">上传 CSV 文件</label>
<input type="file" name="csv_file" id="csv_file" accept=".csv" required><button type="submit" name="submit_csv_upload">上传并导入</button>
</form>
</div>
⚠️ 注意:
name="csv_file"与$_FILES['csv_file']对应;name="submit_csv_upload"是Tools::isSubmit('submit_csv_upload')的判断依据。
2. 在钩子中统一处理上传与入库
修改 mymodule.php 中的 hookDisplayLeftColumnProduct 方法,嵌入完整业务逻辑:
public function hookDisplayLeftColumnProduct($params)
{
$message = '';
$error = '';
// 检查是否提交且存在文件
if (Tools::isSubmit('submit_csv_upload') && isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['csv_file'];
// 安全校验:扩展名、MIME 类型、大小
$allowedTypes = ['text/csv', 'application/vnd.ms-excel'];
if (!in_array($file['type'], $allowedTypes) || pathinfo($file['name'], PATHINFO_EXTENSION) !== 'csv') {
$error = '仅支持 .csv 格式文件。';
} elseif ($file['size'] > 5 * 1024 * 1024) { // 5MB 限制
$error = '文件大小不能超过 5MB。';
} else {
// 临时文件安全读取(避免直接使用 $_FILES['tmp_name'])
if (($handle = fopen($file['tmp_name'], 'r')) !== false) {
$dataRows = [];
while (($row = fgetcsv($handle)) !== false) {
$dataRows[] = $row;
}
fclose($handle);
// 示例:批量插入到自定义表 `ps_mymodule_import_log`
try {
foreach ($dataRows as $row) {
if (count($row) >= 2) { // 至少两列:name, email
Db::getInstance()->insert('mymodule_import_log', [
'name' => pSQL(trim($row[0])),
'email' => pSQL(trim($row[1])),
'date_add' => date('Y-m-d H:i:s')
]);
}
}
$message = 'CSV 数据已成功导入 ' . count($dataRows) . ' 条记录。';
} catch (Exception $e) {
$error = '数据库写入失败:' . $e->getMessage();
}
} else {
$error = '无法读取上传的 CSV 文件。';
}
}
}
$this->context->smarty->assign([
'message' => $message,
'error' => $error,
]);
return $this->display(__FILE__, 'mymodule.tpl');
}
3. 数据库表准备(示例)
确保已创建对应数据表(可通过 install() 方法自动建表):
CREATE TABLE IF NOT EXISTS `PREFIX_mymodule_import_log` ( `id_mymodule_import_log` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) NOT NULL, `date_add` DATETIME NOT NULL, PRIMARY KEY (`id_mymodule_import_log`) ) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
? 关键安全提醒
-
永远校验
$_FILES['xxx']['error']:防止伪造上传或客户端中断; -
绝不信任
$_FILES['type']:需结合finfo_file()或扩展名校验; -
使用
pSQL()清洗所有用户输入,防止 SQL 注入; - 避免在模板中暴露敏感逻辑:如数据库操作、路径等;
-
生产环境禁用
display_errors,错误应记录日志而非输出给用户。
? 提示:若需异步上传或大文件支持,建议升级为 AJAX +
XMLHttpRequest+ 后台队列(如 RabbitMQ),但基础场景下钩子内同步处理更轻量可靠。
至此,你已实现一个安全、可维护、符合 PrestaShop 最佳实践的 CSV 文件上传与入库流程——无需额外控制器、不破坏原有页面结构,且完全兼容 PS 1.7+。











