Come codificare caratteri speciali usando mod_rewrite e Apache?

Mi piacerebbe avere URL graziosi per il mio sistema di tagging insieme a tutti i caratteri speciali: + , & , # , % e = . C’è un modo per farlo con mod_rewrite senza dover codificare i collegamenti?

Ho notato che delicious.com e StackOverflow sembrano essere in grado di gestire caratteri speciali codificati singolarmente. Qual è la formula magica?

Ecco un esempio di ciò che voglio succedere:

 http://www.foo.com/tag/c%2b%2b 

Attiva la seguente RewriteRule:

 RewriteRule ^tag/(.*) script.php?tag=$1 

e il valore del tag sarebbe “c ++”

Il normale funzionamento di apache / mod_rewrite non funziona in questo modo, in quanto sembra trasformare i segni più in spazi. Se raddoppiare la codifica del segno più a “% 252B”, ottengo il risultato desiderato, tuttavia rende URL disordinati e mi sembra piuttosto intrusivo.

Il normale funzionamento di apache / mod_rewrite non funziona in questo modo, in quanto sembra trasformare i segni più in spazi.

Non penso che sia proprio quello che sta succedendo. Apache decodifica il% 2Bs in + s nella parte del percorso poiché + è un carattere valido lì. Lo fa prima di lasciare che mod_rewrite guardi la richiesta.

Quindi mod_rewrite cambia la tua richiesta ‘/ tag / c ++’ in ‘script.php? Tag = c ++’. Ma in un componente stringa di query nel formato codificato application / x-www-form, le regole di escape sono leggermente diverse da quelle applicabili nelle parti del percorso. In particolare, ‘+’ è una scorciatoia per lo spazio (che potrebbe anche essere codificato come ‘% 20’, ma questo è un comportamento vecchio che non saremo mai in grado di modificare ora).

Quindi il codice di lettura di formule di PHP riceve il “c ++” e lo scarica nel tuo _GET come C-space-space.

Sembra che il modo per aggirare sia usare rewriteflag ‘B’. Vedi http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteflags – curiosamente utilizza più o meno lo stesso esempio!

 RewriteRule ^tag/(.*)$ /script.php?tag=$1 [B] 

Non sono sicuro di capire cosa stai chiedendo, ma il flag NE (noescape) nella direttiva RewriteRule di Apache potrebbe essere di tuo interesse. Fondamentalmente, impedisce a mod_rewrite di mod_rewrite automaticamente l’escape di caratteri speciali nel modello di sostituzione fornito. L’esempio fornito nella documentazione di Apache 2.2 è

 RewriteRule /foo/(.*) /bar/arg=P1\%3d$1 [R,NE] 

che girerà, ad esempio, /foo/zed in un reindirizzamento a /bar/arg=P1%3dzed , in modo che lo script /bar vedrà quindi un parametro di query denominato arg con un valore P1=zed , se guarda nel suo PATH_INFO (okay, non è un parametro di query reale , quindi chiamami ;-P).

Almeno, penso che sia così che funziona. . . Non ho mai usato quella particolare bandiera me stesso.

Finalmente l’ho fatto funzionare con l’aiuto di RewriteMap.

Aggiunta la mappa di escape nel file httpd.conf RewriteMap es int: escape

e usato in regola Riscrivi

 RewriteRule ([^?.]*) /abc?arg1=${es:$1}&country_sniff=true [L] 

Il problema di fondo è che ci si sta spostando da una richiesta che ha una codifica (in particolare, un segno più è un segno più) in una richiesta con codifica diversa (un segno più rappresenta uno spazio). La soluzione è bypassare la decodifica eseguita da mod_rewrite e convertire il percorso direttamente dalla richiesta non elaborata alla stringa di query.

Per bypassare il normale stream delle regole di riscrittura, caricare la stringa di richiesta non elaborata direttamente in una variabile di ambiente e modificare la variabile di ambiente anziché il normale percorso di riscrittura. Sarà già codificato, quindi di solito non dobbiamo preoccuparci di codificarlo quando lo spostiamo nella stringa di query. Ciò che vogliamo, tuttavia, è codificare in percentuale i segni più, in modo che vengano inoltrati correttamente come segni e non spazi.

Le regole sono incredibilmente semplici:

 RewriteEngine On RewriteRule ^script.php$ - [L] # Move the path from the raw request into _rq RewriteCond %{ENV:_rq} ="" RewriteCond %{THE_REQUEST} "^[^ ]+ (/path/[^/]+/[^? ]+)" RewriteRule .* - [E=_rq:%1] # encode the plus signs (%2B) (Loop with [N]) RewriteCond %{ENV:_rq} "/path/([^/]+)/(.*)\+(.*)$" RewriteRule .* - [E=_rq:/path/%1/%2\%2B%3,N] # finally, move it from the path to the query string # ([NE] says to not re-code it) RewriteCond %{ENV:_rq} "/path/([^/]+)/(.*)$" RewriteRule .* /path/script.php?%1=%2 [NE] 

Questo script.php banale conferma che funziona:

  

Ho incontrato il problema simile per mod_rewrite con + accesso in url. Lo scenario come di seguito:

abbiamo bisogno di riscrivere un url con il segno + come http://deskdomain/2013/08/09/a+b+c.html

RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1

L’azione di puntamento urlRedirect ottiene il parametro url, fa qualche cambiamento e usa l’url per un altro reindirizzamento. Ma in req.getParameter (“url”) il segno + diventa vuoto, il contenuto http://deskdomain/2013/08/09/ab c.html parametro è http://deskdomain/2013/08/09/ab c.html , che causa il reindirizzamento 404 non trovato. Per risolverlo (ottenere aiuto dalla risposta precedente) utilizziamo il flag di riscrittura B (escape backreferences) e NE (noescape)

RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1 [B,NE]

La B, uscirà da + a% 2B, NE impedirà l’escape mod_write% 2B a% 252B (double escape + sign), quindi in req.getParameter("url")=http://deskdomain/2013/08/09/a+b+c.html

Penso che il motivo è req.getParameter (“url”) farà un unescape per noi, il segno + può essere rimosso per vuoto. Puoi provare unescape% 2B una volta a +, poi unescape + di nuovo a vuoto.

"%2B" unescape-> "+" unescape-> " "