
本文详解如何在 PrestaShop 模块中利用 display 钩子(如 displayLeftColumnProduct)直接接收并处理用户上传的 CSV 文件,无需额外前端控制器,涵盖表单配置、文件接收、安全验证与数据库写入全流程。
本文详解如何在 prestashop 模块中利用 display 钩子(如 `displayleftcolumnproduct`)直接接收并处理用户上传的 csv 文件,无需额外前端控制器,涵盖表单配置、文件接收、安全验证与数据库写入全流程。
在 PrestaShop 模块开发中,常见误区是为简单文件上传单独创建 FrontController——这不仅增加路由复杂度,还易引发 CSRF 风险和上下文丢失问题。更高效、安全且符合 PrestaShop 架构的做法是:在钩子方法内统一处理表单提交与文件上传逻辑。
✅ 正确实现步骤
1. 表单必须支持文件上传
HTML 表单需设置 enctype="multipart/form-data",否则 $_FILES 将为空:
{** 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">上传并导入</button>
</form>
</div>⚠️ 注意:
name="csv_file"必须与后端Tools::getValue()和$_FILES中的键名一致;accept=".csv"提供基础前端校验。
2. 在钩子中统一处理上传与业务逻辑
修改 hookDisplayLeftColumnProduct(),嵌入完整的上传、解析与入库流程:
// mymodule.php
public function hookDisplayLeftColumnProduct($params)
{
$message = '';
// 检查是否提交且存在上传文件
if (Tools::isSubmit('submit_csv_upload') && isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] === UPLOAD_ERR_OK) {
$uploadedFile = $_FILES['csv_file'];
// 1. 安全校验:类型、大小、扩展名
if ($uploadedFile['type'] !== 'text/csv' && strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION)) !== 'csv') {
$message = $this->l('仅允许上传 .csv 文件。');
} elseif ($uploadedFile['size'] > 2 * 1024 * 1024) { // 2MB 限制
$message = $this->l('文件大小不能超过 2MB。');
} else {
// 2. 移动临时文件(关键!)
$uploadDir = _PS_MODULE_DIR_ . $this->name . '/uploads/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$targetPath = $uploadDir . uniqid() . '_' . basename($uploadedFile['name']);
if (move_uploaded_file($uploadedFile['tmp_name'], $targetPath)) {
// 3. 解析 CSV 并写入数据库(示例:假设导入到自定义表 `ps_mymodule_data`)
$handle = fopen($targetPath, 'r');
if ($handle) {
$firstRow = true;
while (($row = fgetcsv($handle, 0, ',')) !== false) {
if ($firstRow) {
$firstRow = false;
continue; // 跳过表头
}
if (count($row) >= 2) {
Db::getInstance()->insert('mymodule_data', [
'name' => pSQL(trim($row[0])),
'value' => pSQL(trim($row[1])),
'date_add' => date('Y-m-d H:i:s')
]);
}
}
fclose($handle);
$message = $this->l('CSV 文件已成功导入!');
@unlink($targetPath); // 可选:导入后删除临时文件
} else {
$message = $this->l('无法读取 CSV 文件,请检查格式。');
}
} else {
$message = $this->l('文件保存失败,请检查服务器权限。');
}
}
}
$this->context->smarty->assign([
'message' => $message,
'files' => Tools::getValue('csv_file') // 仅用于表单回显(非文件内容)
]);
return $this->display(__FILE__, 'mymodule.tpl');
}3. 模板中显示反馈信息
在 mymodule.tpl 中添加提示区域:
{if $message}
<div class="alert alert-{$message|strpos:'成功' !== false ? 'success' : 'danger'}">
{$message}
</div>
{/if}? 关键安全注意事项
-
绝不依赖
$_FILES['xxx']['name']直接存储:攻击者可伪造文件名,务必使用uniqid()+basename()组合生成安全文件名; -
始终验证
$_FILES['xxx']['error']:确保上传无错误(UPLOAD_ERR_OK); -
强制检查 MIME 类型与扩展名双重校验:仅靠前端
accept不可靠; -
使用
pSQL()或Db::getInstance()->escape()处理 CSV 数据,防止 SQL 注入; - 若需长期保留上传文件,应存于非 Web 可访问目录(如
_PS_MODULE_DIR_下),并设置合理清理策略。
? 为什么不需要 FrontController?
PrestaShop 的钩子(如 display*)本质是模板渲染入口,天然具备请求上下文($this->context)、Smarty 引擎和工具类(Tools)。将上传逻辑置于钩子中,既避免了 Controller 路由注册、权限配置等额外工作,又能直接复用模块现有语言包、日志及数据库连接,显著提升代码内聚性与可维护性。
通过以上方案,你即可在产品页侧栏安全、简洁地实现 CSV 文件上传与结构化入库,无需冗余控制器,完全遵循 PrestaShop 最佳实践。


















