PHP header跳转商品页如何拼接带横杠分隔商品名的SEO URL
问题说明
现有PHP业务文件通过自定义编号字段id_4d查询映射对应商品主键id_product,目前已实现搜索栏输入id_4d提交后,跳转地址可自动填充查询到的id_product值,但还需在URL中拼接横杠分隔的商品名称,才能匹配站点商品页路由,目标URL格式为:/website/www/fr/{id_product}-here-is-the-name-of-the-product.html。
当前待解决问题共2项:
- 不知道如何将商品名称处理为横杠分隔的格式拼接到URL中
- 站点数据库体量较大,暂未定位到商品名称存储的对应字段
现有代码
页面查询逻辑
?> <form action="p.php" method="GET"> <input name="4d"> </form> <p class="card-text"><b>ID 4d</b> : <?php echo $_GET['4d']; ?></p> <p class="card-text"><b>Id_product</b> : <?php $id_4d = $_GET['4d']; $db = \Db::getInstance(); $request = 'SELECT `id_product` FROM `' . _DB_PREFIX_ . 'product` WHERE `id_4d` = '.$id_4d.' '; $id = $db->executeS($request); $prod = new Product($id); if(empty($id)) { echo 'Le produit demandé n\'existe pas'; } else{ echo ($id[0]['id_product']); } ?></p> </div> <?php $page = $id[0]['id_product'];
当前跳转逻辑
header("location:/website/www/fr/$page.html");
实现方案
从代码里的_DB_PREFIX_常量、Product类、Db类调用方式判断,站点基于PrestaShop开发,不需要全库遍历查找字段,直接按系统原生结构处理即可。
1. 定位商品名称存储字段
PrestaShop商品多语言名称默认存储在{_DB_PREFIX_}product_lang表,通过id_product和主商品表关联,路由中fr对应法语,可直接关联查询:
- 商品名字段为
name - 系统预生成的URL slug(横杠分隔格式)字段为
link_rewrite,优先取这个字段值,和系统原生生成的商品URL规则完全匹配,不会出现路由404 - 关联时需匹配法语语言ID、当前店铺ID,避免多语言、多店铺场景下取错数据
2. 商品名称转横杠分隔格式
不需要自己写正则替换规则,直接调用系统自带的Tools::link_rewrite()方法即可,该方法会自动处理重音符号、特殊字符、空格转横杠、去除无效字符,完全匹配站点路由规则。如果product_lang表中已经有预生成的link_rewrite值,直接使用即可,不需要重复生成。
3. 修正后完整代码
原有代码存在SQL注入风险、参数未校验、空结果下标报错、Product类实例化传参错误、header跳转前有输出导致报错等问题,修正后代码如下:
<?php $errorMsg = ''; $productInfo = []; // 校验提交参数 if (isset($_GET['4d']) && trim($_GET['4d']) !== '') { $id_4d = trim($_GET['4d']); $db = \Db::getInstance(); $context = \Context::getContext(); // 连表查询商品ID、法语名称、预生成slug,参数用pSQL转义防注入 $request = 'SELECT p.id_product, pl.name, pl.link_rewrite FROM `' . _DB_PREFIX_ . 'product` p LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON p.id_product = pl.id_product AND pl.id_lang = (SELECT id_lang FROM `' . _DB_PREFIX_ . 'lang` WHERE iso_code = "fr") AND pl.id_shop = ' . (int)$context->shop->id . ' WHERE p.id_4d = "' . pSQL($id_4d) . '"'; $productInfo = $db->getRow($request); if (empty($productInfo) || empty($productInfo['id_product'])) { $errorMsg = 'Le produit demandé n\'existe pas'; } else { // 优先取系统预生成slug,不存在则现场生成 $slug = !empty($productInfo['link_rewrite']) ? $productInfo['link_rewrite'] : \Tools::link_rewrite($productInfo['name']); $targetUrl = '/website/www/fr/' . (int)$productInfo['id_product'] . '-' . $slug . '.html'; // 清空提前输出的内容,避免header报错 ob_clean(); header("Location: " . $targetUrl, true, 302); exit; } } ?> <form action="p.php" method="GET"> <input name="4d"> <button type="submit">查询</button> </form> <?php if ($errorMsg): ?> <p class="text-danger"><?php echo $errorMsg; ?></p> <?php endif; ?> <?php if (!empty($productInfo)): ?> <p class="card-text"><b>ID 4d</b> : <?php echo htmlspecialchars($_GET['4d']); ?></p> <p class="card-text"><b>Id_product</b> : <?php echo (int)$productInfo['id_product']; ?></p> <?php endif; ?>
注意事项
- 所有数据库查询参数必须做转义处理,ID类参数强制转整型,避免SQL注入风险
- 页面输出用户提交的内容时必须做HTML转义,避免XSS漏洞
- header跳转前必须清空已输出的内容,跳转后加
exit终止后续代码执行 - 不要自己写slug生成规则,优先使用系统原生方法或预生成的slug值,避免和系统路由规则不匹配导致404
内容的提问来源于stack exchange,提问作者Guillaume KS
相关产品推荐
相关产品推荐

