Mod_rewrite substitui sublinhados por traços (ou hífens) em Opencart

1

Estou transferindo um site de comércio eletrônico para um novo carrinho de compras. Por algum motivo, o site antigo usava traços para categorias, mas sublinhava os produtos.

O URL completo de um produto é assim:

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

A nova cesta usa traços para tudo, por isso preciso reescrever os URLs de entrada, como os acima, para os seguintes itens:

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

Eu sei que há muito material sobre reescrever sublinhados em traços, mas nenhum deles parece estar funcionando para mim.

Estou usando o Opencart, que vem com um conjunto existente de regras de reescrita, então talvez elas estejam interferindo nas novas regras que estou tentando adicionar.

O .htaccess existente é o seguinte:

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]

Qualquer ajuda ou direção seria recebida com gratidão.

Atualizando o .htaccess de acordo com a resposta da Esa para o seguinte:

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]

Funciona bem para:

http://example.com/this_is_a_category

Mas faz com que o Apache falhe:

http://example.com/this_is_a_category/this_is_a_product
    
por jx12345 13.03.2015 / 12:35

2 respostas

1

Como RewriteRules são para correspondências de expressões regulares em vez de substituições, a primeira linha em

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

não é repetido. Portanto, você precisará de uma linha para cada quantidade de sublinhados, por exemplo,

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]

substitui sublinhados de 1 a 5, resultando em

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

Assim, para 9 substituições, você precisará de mais algumas linhas no topo. O padrão será o mesmo, mas as expressões mais longas precisam se tornar as primeiras.

No entanto, isso substitui todos os sublinhados por traços (e redireciona após o último), portanto, você não deve ter nenhum nome de arquivo contendo sublinhados. Você também pode evitar que isso aconteça adicionando uma diretiva RewriteCond ANTES destas regras:

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

Works fine for:

http://example.com/this_is_a_category

But causes Apache to crash on:

http://example.com/this_is_a_category/this_is_a_product

Para resolver isso, basta adicionar o sinalizador DPI (Descartar informações do caminho) à primeira diretiva RewriteRule :

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

A "falha do Apache" é causada por um loop de reescrita sem fim . O N flag faz com que o conjunto de regras faça um loop (o que é necessário neste cenário para substituir todas as barras um dos sublinhados), no entanto, path-info da solicitação original é anexado à URL reescrita em cada iteração (por design ).

No primeiro exemplo, com apenas um único segmento de caminho, não há informações de caminho adicionais, portanto, nada é acrescentado. No entanto, o segundo exemplo contém informações de caminho adicionais, ou seja, /this_is_a_product (tudo após o primeiro segmento de caminho que não mapeia para um caminho de sistema de arquivos físico) - que contém sublinhados. Este é o problema. Cada iteração do loop substitui apenas um sublinhado, mas cada iteração do loop também está anexando mais 3 (neste exemplo)! Então, nunca é capaz de completar a tarefa de substituir todos (barra um) dos sublinhados!

Se você habilitar o registro de regravação, o log de erros informará algo como:

/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
:

Como você pode ver, isso rapidamente se descontrola. Por padrão, ele irá parar após 32.000 iterações (!), Mas seu servidor provavelmente está ficando sem recursos antes disso; daí o acidente. No Apache 2.4.8+ você pode limitar o número de iterações, por exemplo. N=10 - embora isso não resolva seu problema, ele irá parar o servidor de travar!

AFAIK, o sinalizador DPI (Apache 2.2.12+) foi criado especificamente para resolver esse problema. Ele descarta a informação do caminho original da URL reescrita, por isso não é reaplicada a cada vez, evitando assim o loop infinito de reescrita.

Referência:

  • Relatório de bugs de 2006 que menciona esse problema:
    link
  • N flag - link
  • DPI flag - link
por 23.09.2018 / 20:38