PrestaShop 1.7/8.1批量INSERT SQL语法错误问题求助
环境与现象
- PrestaShop 1.6.1.23(PHP7.1)下模块运行正常
- PrestaShop 1.7.8.9(PHP7.4)、8.1.2(PHP8.1)下:提交2个及以上商品的入库单时触发SQL语法错误;无商品或仅1个商品时可正常提交
错误信息
PrestaShop 1.7
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO
ps_kfasupply_warehouse_receipt_detail(`id_warehou' at line 6
PrestaShop 8.1
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'INSERT INTO
ps_kfasupply_warehouse_receipt_detail(`id_ware...' at line 6
执行的SQL语句
INSERT INTO `ps_kfasupply_warehouse_receipt_detail` (`id_warehouse_receipt`, `row_number`, `name`, `quantity`, `sales_return_quantity`, `barcode`, `supplier_reference`, `package_type`, `quantity_per_package`, `description`) VALUES(1, '1', 'test1', 10, 0, '', '', '', 0, ''); INSERT INTO `ps_kfasupply_warehouse_receipt_detail` (`id_warehouse_receipt`, `row_number`, `name`, `quantity`, `sales_return_quantity`, `barcode`, `supplier_reference`, `package_type`, `quantity_per_package`, `description`) VALUES(1, '2', 'test2', 20, 0, '', '', '', 0, '');
背景补充
模块对应入库单表单,包含供应商、品牌、发票信息及商品列表;原处理逻辑为:通过foreach循环生成每个商品的INSERT语句,拼接成完整字符串后一次性执行。手动在phpMyAdmin中执行该SQL字符串可正常运行。
解决方法
原因分析
PrestaShop 1.7及后续版本为防范SQL注入,默认禁用了多语句SQL执行,直接执行拼接的多条INSERT语句会被拦截或触发语法错误,而PrestaShop 1.6无此限制。
方案1:使用批量INSERT语法(推荐)
将多个VALUES合并到同一条INSERT语句中,既符合安全限制,又提升执行效率:
INSERT INTO `ps_kfasupply_warehouse_receipt_detail` (`id_warehouse_receipt`, `row_number`, `name`, `quantity`, `sales_return_quantity`, `barcode`, `supplier_reference`, `package_type`, `quantity_per_package`, `description`) VALUES (1, '1', 'test1', 10, 0, '', '', '', 0, ''), (1, '2', 'test2', 20, 0, '', '', '', 0, '');
代码实现时,循环收集所有商品的VALUES数组,最后拼接成单条INSERT语句执行。
方案2:循环执行单个INSERT语句
放弃多语句拼接,改为在foreach循环中逐个执行单条INSERT语句,使用PrestaShop内置的Db::getInstance()->execute()方法分别插入每个商品数据。
方案3:开启多语句支持(不推荐,有安全风险)
若必须保留原逻辑,可修改数据库连接配置开启多语句执行,但会大幅提升SQL注入风险,仅适用于完全信任所有输入来源的场景:
- 在数据库连接参数中添加
PDO::MYSQL_ATTR_MULTI_STATEMENTS => true - PrestaShop中需修改
DbPDO类的连接参数,但版本升级时可能被覆盖
注意事项
- 所有用户输入必须通过PrestaShop提供的
Db::getInstance()->escape()方法转义,避免SQL注入 - 优先选择方案1,兼顾性能与安全性
内容的提问来源于stack exchange,提问作者Amirhossein Rzd

