
本文详解如何在 prestashop 自定义模块中,通过钩子(hook)接收用户上传的 csv 文件,安全解析并存入数据库,无需额外前端控制器,全程集成于钩子逻辑中。
本文详解如何在 prestashop 自定义模块中,通过钩子(hook)接收用户上传的 csv 文件,安全解析并存入数据库,无需额外前端控制器,全程集成于钩子逻辑中。
在 PrestaShop 模块开发中,常需让用户通过前端表单上传文件(如 CSV),并在后端解析入库。但直接使用 Tools::getValue('files') 无法获取上传的文件内容——因为文件上传需通过 $_FILES 超全局数组访问,且表单必须设置 enctype="multipart/form-data"。此外,PrestaShop 的钩子(如 hookDisplayLeftColumnProduct)完全可承载完整的上传+处理逻辑,无需额外注册前端控制器(ModuleFrontController),既简化架构又提升执行效率。
✅ 正确实现步骤
1. 修正模板表单:添加 enctype 和提交按钮 name
<!-- views/templates/hook/mymodule.tpl -->
<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" value="1">上传并导入</button>
</form>
</div>
⚠️ 关键点:
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
-
enctype="multipart/form-data"是文件上传的强制要求; -
name="csv_file"用于 PHP 中定位上传项; -
name="submit_csv_upload"用于判断是否提交(替代Tools::isSubmit()的判定依据)。
2. 在钩子中统一处理上传与入库逻辑
// mymodule.php
public function hookDisplayLeftColumnProduct($params)
{
$message = '';
$success = false;
// 检查是否提交且存在文件
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'];
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if ($extension !== 'csv' || !in_array($file['type'], $allowedTypes)) {
$message = '仅支持有效的 CSV 文件。';
} elseif ($file['size'] > 5 * 1024 * 1024) { // 5MB 限制
$message = '文件大小不能超过 5MB。';
} else {
// 临时移动并解析
$tmpPath = $file['tmp_name'];
if (($handle = fopen($tmpPath, 'r')) !== false) {
$rows = [];
while (($data = fgetcsv($handle, 0, ',')) !== false) {
$rows[] = $data;
}
fclose($handle);
// 示例:将首列作为用户名批量插入数据库(请按实际字段调整)
foreach ($rows as $row) {
if (!empty($row[0])) {
Db::getInstance()->insert('my_custom_table', [
'username' => pSQL(trim($row[0])),
'date_add' => date('Y-m-d H:i:s')
]);
}
}
$success = true;
$message = 'CSV 数据已成功导入 ' . count($rows) . ' 条记录。';
} else {
$message = '无法读取 CSV 文件,请检查格式。';
}
}
}
$this->context->smarty->assign([
'upload_message' => $message,
'upload_success' => $success
]);
return $this->display(__FILE__, 'mymodule.tpl');
}
3. 模板中显示反馈(增强用户体验)
<!-- mymodule.tpl 补充 -->
{if $upload_message}
<div class="alert alert-{if $upload_success}success{else}danger{/if}">
{$upload_message}
</div>
{/if}
⚠️ 重要注意事项
-
绝不依赖
Tools::getValue()获取文件:$_FILES是唯一可靠来源,Tools::getValue()仅适用于普通表单字段; -
始终验证
$_FILES['xxx']['error']:避免因上传失败(如超限、无文件)导致空指针异常; -
使用
pSQL()或Db::getInstance()->escape()处理 CSV 数据:防止 SQL 注入; - 生产环境建议异步处理大文件:可通过 AJAX + 后台队列(如 Symfony Messenger)避免请求超时;
- 权限与路径安全:勿将上传文件保存至 Web 可访问目录,临时文件由 PHP 自动清理,无需手动删除。
通过将上传、校验、解析、入库全流程封装在钩子中,代码更内聚、调试更直观,也符合 PrestaShop “钩子即入口” 的设计哲学。无需额外控制器路由,减少配置复杂度,是轻量级文件导入场景的最佳实践。










