Substituição relativa em mod_rewrite RewriteRule

7

Eu quero criar um mod_rewrite RewriteRule que seja independente do local onde a página da web está instalada. Eu quero definir a regra de reescrita em um arquivo .htaccess. Vamos pegar isso como exemplo:

RewriteEngine on
RewriteRule ^(.*)\.html html.php

Com essa regra, quero mapear todas as solicitações * .html para um script html.php localizado na raiz da web. O problema é que a URL base pública do webroot pode mudar. Assim, a raiz da web pode estar localizada em http://www.somewhere.tld/ ou em algum subdiretório em http://www.somewhere.tld/foo/bar/ .

Mas o uso de um caminho relativo em uma regra de reescrita não funciona. Então eu tenho que escrever um destes:

/html.php (When web is located in root directory of the web)
/foo/bar/html.php (When web is located in foo/bar sub directory)

Como alternativa, posso definir um RewriteBase, mas simplesmente não quero configurar esse caminho. Eu quero que o apache automaticamente faça a coisa certa para que eu possa simplesmente copiar a web para algum diretório e ele simplesmente funciona sem dizer as regras de reescrita onde a web está localizada. Como eu posso fazer isso?

    
por kayahr 09.06.2011 / 13:34

4 respostas

3

Não há como, no meu conhecimento, você conseguir isso. Você tem que configurar o RewriteBase. Uma maneira é automatizar a configuração do RewriteBase usando um script PHP, talvez? Mas isso exigirá permissão de gravação (pelo menos) no .htaccess. Mas você terá que configurar o RewriteBase em .htaccess.

    
por 09.06.2011 / 13:40
11

Eu lutei com o mesmo problema e pelo mesmo motivo. Eu estou tentando fazer um aplicativo da web independente do local onde ele está instalado, sem recorrer a um script de configuração ou intervenção manual do usuário. Basta soltar o aplicativo em algum lugar e deixar que ele faça o que quiser.

E parece que há uma solução afinal, pelo menos para o Apache 2. Leva quatro linhas. Explicar o pensamento por trás disso leva mais de quatro linhas;)

Tl; dr tente isto:

RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)$
RewriteRule ^(.*)$ %2index.php [QSA,L]

Aqui está o como e porquê

  • Não podemos configurar o RewriteBase dinamicamente, por isso, definimos de uma vez por todas o URL raiz do servidor: RewriteBase / . Isso fornece consistência, mas também significa que temos que estabelecer o caminho da url para o diretório atual e prefixá-lo com a URL reescrita.

  • Em qual diretório estamos? Vamos supor que REQUEST_URI de / alguma / caminho / raiz de aplicativo / virtual / material. Nosso htaccess está na raiz do aplicativo. Se pegarmos a parte virtual - virtual / material - e removê-la do REQUEST_URI , ficamos com o caminho-url para o nosso diretório de aplicativos.

  • Capturar a peça virtual é simples e pode acontecer na própria regra de reescrita. RewriteRule ^(.*)$ ... torna disponível na variável $1 .

  • Agora fazemos nossa pequena operação de string e removemos a parte virtual do URI da solicitação. Nós não temos comandos de string para isso, mas o RewriteCond pode combinar strings e capturar substrings. Então, adicionaremos um RewriteCond com o único propósito de extrair o caminho-url para o diretório atual. Fora isso, a "condição" deve ficar fora do nosso caminho e ser sempre verdadeira.

  • Podemos usar a variável $1 do RewriteRule no RewriteCond porque o mod_rewrite realmente processa um conjunto de regras de trás para frente. Começa com o padrão na própria regra e, se corresponder, passa a verificar as condições. Então a variável está disponível até então.

  • Enquanto a string de teste no RewriteCond pode usar a variável, a condição real regex não pode. Dentro da condição, só podemos usar referências internas. Então, primeiro, montamos uma string de teste "[virtual part] [some separator] [request uri]". O caractere "#" é um bom separador porque não aparece no URL. Em seguida, combinamos com uma condição de

    ([^#]*) - anything up to the separator, captures the virtual part
    #       - the separator
    (.*?)   - anything in the request uri up to what we've captured in group one,
              grabs the current directory url-path
    $     - group one again, ie the virtual part of the request uri
    

    Então aqui está a condição completa: RewriteCond $1#%{REQUEST_URI} ([^#]*)#(.*?)$ .

  • O segundo grupo capturado no regex RewriteCond é a nossa localização. Precisamos apenas prefixar o URL reescrito com uma referência %2 . Isso nos deixa com RewriteRule ^(.*)$ %2index.php [QSA,L] . Voilà.

Ainda não fiz testes extensivos, mas estabeleci que funciona com hosts virtuais comuns, bem como hospedagem virtual em massa (usando o VirtualDocumentRoot). Por implicação, outros locais com alias também devem ser bons.

Apache 1.3

O Apache 1.3 ainda está por aí, infelizmente, e vai sufocar no padrão RewriteCond. O Apache 1.3 não suporta o modificador ungreedy (o '?' Em (.*?) ).

Mas para o Apache 2, isso deve funcionar. Eu definitivamente aprecio qualquer feedback, especialmente se ele falhar em seu ambiente.

Edit: Acabei de postar um artigo mais abrangente sobre o assunto em meu blog (" Usando mod_rewrite em. htaccess arquivos sem saber o RewriteBase "). Veja lá para mais detalhes.

    
por 24.08.2012 / 13:44
1

Acho que a documentação do Apache é enganosa:

When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the RewriteRule pattern matching and automatically added after any relative (not starting with a slash or protocol name) substitution encounters the end of a rule set. See the RewriteBase directive for more information regarding what prefix will be added back to relative substutions.

Mas o prefixo que ele adiciona é completamente diferente (caminho no disco em vez do URL original). Não consigo pensar em uma situação em que esse seria o comportamento correto.

    
por 09.09.2011 / 21:58
0

Que tal algo como

RewriteEngine on
RewriteRule ^(.*)\.html $1/html.php

Meu exemplo preserva a parte do nome do arquivo do arquivo html, por exemplo, page1.html seria redirecionado para page1 / html.php. (Nota: eu não testei isso, tente por sua conta e risco:))

Além disso, o guia mod_rewrite tem vários exemplos semelhantes ao seu problema. Você já deu uma olhada nisso?

    
por 09.06.2011 / 13:41