Mod_rewrite 在 Opencart 中用破折号(或连字符)替换下划线

Mod_rewrite 在 Opencart 中用破折号(或连字符)替换下划线

我正在将一个电子商务网站转移到一个新的购物篮。出于某种原因,旧网站使用破折号表示类别,但使用下划线表示产品。

因此,产品的完整 URL 如下所示:

http://www.example.com/Engineering-Common-Bricks/65mm_Class_B__Solid_Engineering_Brick__Price_Each

新的购物篮对所有内容都使用了破折号,因此我需要将上述传入 URL 重写为以下内容:

http://www.example.com/Engineering-Common-Bricks/65mm-Class-B--Solid-Engineering-Brick--Price-Each

我知道有很多关于将下划线重写为破折号的资料,但它们似乎都不适合我。

我正在使用 Opencart,它带有一组现有的重写规则,因此这些规则可能会干扰我尝试添加的新规则。

现有的.htaccess如下:

Options +FollowSymlinks

# Prevent Directoy listing 
Options -Indexes

# Prevent Direct Access to files
<FilesMatch "\.(tpl|ini|log)">
 Order deny,allow
 Deny from all
</FilesMatch>

# SEO URL Settings
RewriteEngine On
# If your opencart installation does not run on the main web folder make sure you folder it does run in ie. / becomes /shop/ 

RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]

任何帮助或指导都将不胜感激。


按照 Esa 的回答更新.htaccess如下:

Options +FollowSymlinks
Options -Indexes

<FilesMatch "\.(tpl|ini|log)">
 Order deny,allow
 Deny from all
</FilesMatch>

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]

RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]

适用于:

http://example.com/this_is_a_category

但会导致 Apache 崩溃:

http://example.com/this_is_a_category/this_is_a_product

答案1

由于 RewriteRules 用于正则表达式匹配而不是替换,因此

RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]

不重复。因此,你需要为每一行添加下划线,例如

RewriteRule ^(.*)_(.*)_(.*)_(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5-$6-$7 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5-$6 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)$ /$1-$2-$3 [R=301,L]
RewriteRule ^(.*)_(.*)$ /$1-$2 [R=301,L]

替换 1-5 个下划线,结果为

/Engineering_Common_Bricks/65mm_Class_B-Solid-Engineering-Brick-Price-Each

因此,对于 9 个替换,您需要在顶部添加几行。模式将相同,但较长的表达式需要放在最前面。

但是,这会将所有下划线替换为破折号(并在最后一个下划线后重定向),因此您不能使用任何包含下划线的文件名。您也可以通过在这些规则之前添加 RewriteCond 指令来防止这种情况发生:

RewriteCond %{REQUEST_FILENAME} !-f

答案2

RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]

适用于:

http://example.com/this_is_a_category

但会导致 Apache 崩溃:

http://example.com/this_is_a_category/this_is_a_product

要解决这个问题,您只需DPI在第一个RewriteRule指令中添加(丢弃路径信息)标志:

RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N,DPI]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]

“Apache 崩溃”是由于无尽的重写循环。该N标志导致规则集循环(在这种情况下,这是必需的,以便替换除一个下划线之外的所有内容),但是,原始请求的路径信息会在每次迭代时附加到重写的 URL 中(根据设计)。

在第一个示例中,只有一个路径段,没有额外的路径信息,因此没有附加任何内容。但是,第二个示例包含额外的路径信息,即/this_is_a_product(第一个路径段之后未映射到物理文件系统路径的所有内容) - 它本身包含下划线。这就是问题所在。循环的每次迭代只替换一个下划线,但循环的每次迭代还会附加 3 个下划线(在此示例中)!因此,它永远无法完成替换所有(除一个外)下划线的任务!

如果启用重写日志记录,错误日志将报告类似以下内容:

/this_is_a_category/this_is_a_product
/this-is_a_category/this_is_a_product/this_is_a_product
/this-is-a_category/this_is_a_product/this_is_a_product/this_is_a_product
/this-is-a-category/this_is_a_product/this_is_a_product/this_is_a_product/this_is_a_product
/this-is-a-category/this-is_a_product/this_is_a_product/this_is_a_product/this_is_a_product/this_is_a_product
:

如您所见,这很快就会失控。默认情况下,它会在 32,000 次迭代后停止(!),但您的服务器可能在此之前就耗尽了资源;因此崩溃。在 Apache 2.4.8+ 上,您可以限制迭代次数,例如N=10- 虽然这不能解决您的问题,但它会阻止您的服务器崩溃!

据我所知,该DPI标志(Apache 2.2.12+)是专门为解决此问题而创建的。它会丢弃重写 URL 中的原始路径信息,因此不会每次都重新附加,从而防止无限重写循环。

参考:

相关内容