Il mod_rewrite e la magia di riscrivere gli URL (prima parte)

In questo articolo vedremo le basi di una tecnica molto diffusa ed utile ovvero l’url rewrite. Si tratta di una funzionalità di Apache resa possibile dal modulo mod_rewrite, implementabile e configurabile tramite una nostra vecchia conoscenza: i files .htaccess. Il maggiore beneficio di riscrivere gli url é una migliore indicizzazione da parte dei motori di ricerca. Pare infatti che gli spider siano “disturbati” dalle query string (?id=34&type=5&mod=user), in particolare se passano molti parametri.
Sei pronto dunque a calarti in questo misterioso ed affascinate campo del web?
Come avviene la traduzione dell’url?
Poniamo che nel nostro sito, la pagina prodotti.php mostri un prodotto in base all’id passato nell’url.
http://www.tuosito.com/prodotti.php?id=79
Questa pagina mostra i dettagli del prodotto salvato nel database con id=79.
Con una semplice regola, possiamo riscrivere l’url in questo modo:
http://www.tuosito.com/prodotto-79.html
Quello che dobbiamo fare é dire ad Apache:
Quando trovi nell’url prodotto seguito da un trattino seguito da un numero seguito da .html, richiedi la pagina prodotti.php?id=quelNumero
Come avrai intuito, bisognerà lavorare con le espressioni regolari. Se ne sei a digiuno, non ti preoccupare. Giustino ha scritto un’ottima guida al riguardo.
Come dichiarare una regola?
Il modello generale per dichiarare una regola di rewrite é il seguente:
RewriteEngine On RewriteRule cosa-mi-aspetto-di-trovare-nella-barra-dell-url come-devo-tradurre-quello-che-trovo
In primo luogo va inizializzato il motore del mod_rewrite con la dichiarazione RewriteEngine On.
In seguito va dichiarata la regola (o le regole).
Ma passiamo alla pratica ed implementiamo quanto proposto nel paragrafo precedente.
Iniziamo a scrivere la pagina prodotti.php che realizzeremo semplicemente così:
<?php echo 'Questa pagina mostra il prodotto numero ' . $_GET['id']; ?>
Tanto basterà per verificare il corretto funzionamento della nostra regola.
Ora vediamo il file .htaccess che dovrà essere salvato nella stessa (o gerarchicamente superiore) cartella del file prodotti.php.
RewriteEngine On RewriteRule ^prodotto-([0-9]+)\.html$ prodotti.php?id=$1
Quanto dice questa regola, é esattamente quello che abbiamo visto in precedenza: Quando trovi nell’url qualcosa che inizia con (^ significa inizio della stringa) prodotto seguito da un trattino seguito da un numero di una o più cifre (+ significa uno o più) e che termina ($ significa fine della stringa) con .html, richiedi la pagina prodotti.php?id=quelNumero
$1 si riferisce infatti a quanto é stato trovato dalla prima (e in questo caso unica) sottostringa.
Ora impostando come url:
http://www.tuosito.com/prodotto-34.html
Dovresti visualizzare a video la seguente scritta:
“Questa pagina mostra il prodotto numero 34.”
Un esempio con due parametri
Poniamo ora che la nostra pagina prodotti.php dipenda da due parametri: l’id e la categoria del prodotto. L’URL originale potrebbe essere questo:
http://www.tuosito.com/prodotti.php?category=bevande&id=12
Mentre riscritto potrebbe avere questo aspetto:
http://www.tuosito.com/bevande/prodotto-12.html
Vediamo dunque una possibile regola per poi commentarla:
RewriteEngine On RewriteRule ^([a-z]+)/prodotto-([0-9]+)\.html$ prodotti.php?category=$1&id=$2
Cosa dice questa regola?
Se trovi una stringa che inizia con uno o più caratteri seguiti da / seguiti da prodotto seguito da un trattino seguito da un numero di una o più cifre seguito da .html, richiedi la pagina prodotti.php?category=quelloCheHaiTrovatoNellaPrimaSottostringa&id=quelloCheHaiTrovatoNallaSecondaSottostringa.
Modifichiamo il file prodotti.php in modo da poter verificare il funzionamento anche di questo secondo esempio in questo modo:
<?php echo 'Questa pagina mostra il prodotto numero ' . $_GET['id'] . ' appartenente alla categoria ' . $_GET['category']; ?>
Ora digitando l’url:
http://www.tuosito.com/bevande/prodotto-12.html
Visualizzerai a video la seguente scritta
Questa pagina mostra il prodotto numero 12 appartenente alla categoria bevande.
Conclusione
In questo articolo abbiamo visto le basi dell’url rewrite. Ti sarai reso conto di quanto sia importante una buona conoscenza delle espressioni regolari per poter padroneggiare questa tecnica. Nel prossimo articolo, vedremo un’applicazione pratica molto utile in campo SEO, ovvero un rewrite simile a quello che implementa wordpress con i permalink.
E tu, hai degli esempi di url rewrite da mostrare?





splendido post
Ciao Iteand, grazie!
Complimenti!
Come sempre ottimo post.
Da un po’ vi seguo ed è la prima volta che commento.
Non so come fate ma riuscite sempre a rendere semplici e capibili anche argomenti ostici a tanti, compreso il sottoscritto.
Mi avete fatto preoccupare però… un giorno senza vostri post …. ma siete matti!
Grazie Luca.
No ti preoccupare se un giorno non vedi un post. Non è la prima volta che capita. Gli autori possono avere dei disguidi o degli impedimenti come pure possono sorgere problemi tecnici. :-)
ottimo post!
ecco il mio esempio più corposo che utilizzo sempre:
RewriteEngine On
RewriteBase /RewriteRule ^([A-Z]{2})/([A-Za-z0-9_-]+)/([A-Za-z0-9_-]+)/([A-Za-z0-9_-]+)/([A-Za-z0-9_-]+)/([A-Za-z0-9\.\(\)+-]+)/$ index.php?lang=$1&page=$2&cat=$3&&sottocat=$4&ultimacat=$5&nome=$6 [L,QSA,NC]
Grazie Luca. Vedo che sei un cultore del rewrite!
lo sono diventato per forza dopo averci sbattuto la testa per varie e varie volte.
Secondo me ancora non è perfetta.. ma nulla nel nostro campo lo è :)
Ammazza, non c’ho capito una fava! ._.
Noooooooo, impossibile!!!
Davvero complimenti Maurizio: da tenere sempre a portata di mano nei segnalibri :)
Grazie Just! La tua guida alle espressioni regolari tornerà utile a molti.
Grande Maurizio!!! Promessa mantenuta! I tuoi articoli uniti a quelli di Giustino sono un piacere per chi ama programmare!
Ogni promessa è debito. Non perderti la prossima puntata!
Ciao, veramente un post interessante…
ho una domanda, ma se io volessi ridenominare il mio indirizzo da:
http://www.miosito.com/prodotti?id=32&...in:
http://www.miosito.com/prodotti/come devo impostare l’espressione regolare?
grazie
ciao franco,
la trasformazione vuoi fare tu la devi fare tu quando scrivi il link nel tag
TESTOe nell’htaccess fai faer la cosa opposta ad apache con un espressione del genere:
RewriteRule ^/prodotti/([0-9]+)/$ http://www.miosito.com/prodotti?id=$1
Secondo me la tua è una cosa un po limitativa e te ne renderai conto quando inizierai a capire la potenza dell’utl rewrite :).
Spero che si veda tutto il codice che ho scritto e che hai capito.
Se ho ben capito la tua domanda, ti ha già risposto Luca
Ciao Maurizio, complimenti per questo e per tutti gli altri articoli. :-)
Ne approfitto per una domanda.
Siccome il mod_rewrite non è la mia specialità, tempo fa, tramite varie guide, sono riuscito a trasformare un url dinamico in una cosa tipo: vuvuvu.sito.it/1
Poi dopo che ho trovato una guida sul tuo blog sono riuscito a fare la trasformazione in: vuvuvu.sito.it/titolo-della-pagina
C’è un modo per reindirizzare sempre tramite mod_rewrite tutti gli url che ho creato in precedenza con i nuovi che sono riuscito a creare? Se è un procedimento lungo e non puoi qui, magari me lo scrivi nel forum? :-P
Perchè non cambi tutti i link. Tanto immagino che saranno creati dinamicamente
Sì, sono creati dinamicamente, ma siccome gli url del tipo sito.it/1 sono già indicizzati, volevo aggiungere la nuova regola per gli url del tipo: sito.it/titolo-della-pagina e poi creare una regola per fare in modo che i vecchi url reindirizzino ai nuovi, altrimenti ho due url diversi. C’avevo anche già provato ma senza risultati. Infatti qui trovi un topic nel forum
Cioè la vecchia regola è:
RewriteRule ^news/([^/\.]+)/?$ news/view.php?id=$1
La nuova regola è:
RewriteRule ^news/([0-9]+)/([^/]+)\.html$ news/view.php?id=$1
Ovviamente con le opportune modifiche alla pagina php.
Ma c’è poi un modo per rendirizzare tutti gli url creati con la vecchia regola alla nuova regola? :-(
Sì, questo modo esiste, anzi è una procedura utilizzata parecchio. adesso cerco se è descritta da qualche parte poi ti faccio sapere
Il rewrite è una risorsa inestimabile per il SEO quanto per la sicurezza del sito o per la pulizia, e per quanto si sia già visto tutto, è sempre sorprendente cosa puoi farci :) Ti do alcuni di quelli che uso io:
Regola per dinamicizzare le sitemap per google webmaster:
RewriteRule ^sitemap.xml$ ./sitemap.php
Canonicizzazione del dominio, per evitare indicizzazioni doppie del sito:
RewriteCond %{HTTP_HOST} ^dominio.com$
RewriteRule ^.*$ “http\:\/\/www\.dominio\.com” [R=301,L]
Eliminazione dei doppi slash dalle URL, anche queste per evitare indicizzazioni strane:
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
Protezione di un ramo del sito, per impedirne lo scaricamento (la directory si chiama .git):
RewriteRule “\.git/.*” – [F]
Ciao Cristian, grazie per averci offerto alcune regole interessanti e pronte per l’uso.
Per quanto riguarda la prima regola che hai postato, se ho ben capito, generi la sitemap alla richiesta. Questa procedura ha dei vantaggi?
Io solitamente per questo genere di cose (sitemap, feed, ecc…) prefersico ri-creare il file statico (xml) alla pubbilcazione di un nuovo contenuto in modo da non sollecitare ad ogni richiesta il database.
Grazie Cristian per le tue regole alcune molto molto interessante!!!
Quella della sitemap la utilizzo anche io.
@maurizio la regola della sitemap dinami ha il vantaggio che non ti devi preoccupare di generare il file ogni volta.
ciao
Sì, certo.
Quello che dico è: Ogni volta che c’è una modifica, tramite script genero automaticamente un file statico.
Prendi l’esempio di un feed.
Se il file xml viene generato “al volo”, ogni volta che c’è una richiesta lo script dovrà interrogare il database ed andare a leggere gli utilmi 10 articoli (se così è impostato).
Se invece stabilisco che, quando viene pubblicato un nuovo articolo, lo script genera fisicamente il file xml, risparmio diverse richieste al database.
Ma siccome in molti utilizzano la prima tecnica, volevo sapere se c’erano dei vantaggi.
Ciao Maurizio, guarda, avevo anch’io il tuo dubbio, poi ho visto dai log che la sitemap è caricata molto saltuariamente. Molto spesso, il database è aggiornato più frequentemente: quindi, in realtà, è spesso più efficiente fare la sitemap totalmente on demand.
Il vantaggio dell’on demand è chiaramente quello che non devi ricordarti di lanciarlo ogni volta che modifichi il database o cambi qualche html: lo script che ho fatto accede alle timestamp di modifica di tutti gli html statici e degli script per indicare l’ora url per url nella sitemap, oltre che di quelle dei record, e dà quindi una panoramica esatta a Google delle pagine nuove da reindicizzare.
Il discorso cambia per i feed, ma non di molto: la prima volta che lancio lo script eseguo l’interrogazione al database, genero l’rss, lo invio e lo salvo in un’area come cache. Alla seconda richiesta, verifico l’ora ultima sul database con quella del file in cache. Rigenero solo se necessario, altrimenti … fpassthru :)
Sia per la sitemap che per il feed, il codice riciclabile sito per sito è notevole: le funzioni per fare “quasi” tutto fanno parte dei miei framework in pianta stabile :)
Ciao Maurizio, complimenti per le pillole che elargisci ormai da molto…
Volevo chiederti quanto segue:
vorrei nascondere a tutti la pagina di login di WP (…/wp-login.php). Ciò significa che non è sufficiente una semplice rewrite (per semplificare l’URL, ad es. da wp-login.php in login.php) ma che ogni qualvolta un utente provi ad andare su una URL come wp-login.php venga “rediretto” sulla url login.php.
E’ possibile definire una regola del genere?
Grazie
Ciao Paolo. La regola è semplicissima. Ma sinceramente non ne capisco il senso. Che differenza fa se la pagina di login si chiama login.php o wp-login.php?
Interessantissimo articolo, il più semplice ed esaustivo che ho letto da parte di uno che sta imparando adesso con il mondo php.
Visto che lo sto imparando appunto la comodità seo, volevo fare una domanda che mi permettesse di capire un po’ meglio.
Se la pagina creata non esiste fisicamente sul server come fa ad indicizzarla il motore di ricerca?
Ciao dobrio e grazie.
Il motore di ricerca (o meglio lo spider), semplificando, naviga nel sito come ci naviga un qualsiasi utente.
La pagina richiesta esiste sul server, solo che ha un altro nome.
Il passaggio tra il nome reale e quello mostrato nella barra dell’url é un processo gestito dal server sia per l’utente che per lo spider
Ho googlato per ore alla ricerca di qualcosa di semplice ed esaustivo ed eccolo qua. Ottimo post. Ottimo!
Scusate, non ho capito come faccio a riscrivere l’url se ho una form di ricerca con 3 campi.
Mi spiego, ho creato la regola del rewrite corretta ma questa funziona solo se inserisco l’ulr direttamente già modificato. mentre se clicco sul pulsante di ricerca questo viene scritto con le query string. come faccio a farlo scrivere direttamente modificato?
Tnx
Salve a tutti, sono riuscito a fare il rewriting al volo delle query string passate dopo la selezione di valori da una form. Il mio dubbio adesso è il seguente:
Devo riscrivere regole distinte per ogni caso di selezione?
Al momento infatti per trasformare un url con 5 query string dove solo 2 di queste sono valorizzate faccio:
#PER TIPOLOGIA E CONTRATTO
RewriteCond %{REQUEST_URI} ricerca_avanzata.php$
RewriteCond %{QUERY_STRING} ^provincia=0&VF=([A-Za-z1-9\+]+)&tipologia=([A-Za-z1-9\+]+)&superficie=0&NRIF=&submit2=VAI$
RewriteRule ^(.*)$ /panoramaimmobiliare/%2-%1? [R=301,L]
#operazione inversa della regola di sopra
RewriteRule ^([^-]*)-([^-]*)$ ricerca_avanzata.php?provincia=0&VF=$2&tipologia=$1&superficie=0&NRIF=&submit2=VAI$ [L]
adesso se le variabile get valorizzate sono differenti, ovvero non VF e TIPOLOGIA ma PROVINCIA e TIPOLOGIA devo scrivere una regola diversa che però mi da errore se scritta in questo modo:
#PER TIPOLOGIA E PROVINCIA
RewriteCond %{REQUEST_URI} ricerca_avanzata.php$
RewriteCond %{QUERY_STRING} ^provincia=([A-Za-z1-9\+]+)&VF=0&tipologia=([A-Za-z1-9\+]+)&superficie=0&NRIF=&submit2=VAI$
RewriteRule ^(.*)$ /panoramaimmobiliare/%2-%1? [R=301,L]
#operazione inversa della regola di sopra
RewriteRule ^([^-]*)-([^-]*)$ ricerca_avanzata.php?provincia=$2&VF=0&tipologia=$1&superficie=0&NRIF=&submit2=VAI$ [L]
Seconda domanda, devo scrivere una regola per ogni altra variabile get selezionata via via? quindi se uno seleziona un valore nella form o 3 oppure 4? E per quanto riguarda la paginazione, devo aggiungere ancora altre regole che tengono presente del parametro di paginazione?
Al momento sto facendo cosi ma mi sembra molto macchinoso…
Grazie
Molto utile questo post! Grazie!
Ciao Miriam stai utilizzando un cms?
Ciao Maurizio e complimenti per l’ottimo articolo che mi ha chiarito, finalmente, il “mistero” dell’url_rewrite! ;)
Tuttavia, però, mi succede un problema strano:
Ho impostato la path (tramite define() ) del sito, del tipo “http://localhost/cartella/” e fin qui tutto ok.
Sto utilizzando, poi, l’url rewrite per la gestione delle lingue sul sito ed ho scritto questo file .htaccess
### Rewrite ###
RewriteEngine On
# Gestione Lingua
RewriteRule ^([a-z]{2})/index.php$ index.php?lang=$1
RewriteRule ^([a-z]{2})/$ index.php?lang=$1
RewriteRule ^([a-z]{2})$ index.php?lang=$1
Se scrivo localhost/nomesito/it => tutto funziona tranquillamente
Ma se scrivo:
- localhost/nomesito/it/ (quindi con un altro slash dopo la lingua)
- localhost/nomesito/it/index.php ecco che si sfasa tutto quanto.
Come mai?
Grazie già da ora.
sei molto chiaro.
hai mai pensato di fare l’insegnante?
Ciao Maurzio ottimo articolo!
ho però una domanda…come risolvo (se possibile) il problema dei path relativi?(CSS, SCRIPT, ecc, ecc)
é possibilie usare il RewriteRule senza path assoluti?
grazie in anticipo
Ciao Moise,
non capisco che problema possa creare l’url rewrite all’inclusione di script o fogli di stile. Forse non ho capito la tua domanda, ma non c’è nessun problema
Ciao a tutti ho un problema per quanto riguarda il mio sito, se andate su http://www.aste-gratis.it/Strumenti-Musicali-240.html e cliccate una asta il browser la vede così
http://www.aste-gratis.it/Cassa%20Marshall%20400%20watt%20jcm%20lead%20800%201982-3.html
praticamente il titolo dell’asta non mi mette i trattini negli spazi il titolo dell’asta sarebbe
Cassa Marshall 400 watt jcm lead 800 1982 e dovrebbe essere
Cassa-Marshall-400-watt-jcm-lead-800-1982.html
cosa posso fare?
Molto utile come guida!! però ho un problema…
quando genero le pagine dinamiche mi porto oltre all’id anche un altra variabile chiamata nome che equivale alla provincia
pagina.php?provincia=Torino&id=1
con url rewrite, poi, riesco a richiamare la stessa pagina con:
pagina-torino-1.php
con questo codice nel file htaccess
RewriteEngine On
RewriteBase /
RewriteRule ^pagina-([a-z]+)-(\w+).php$ /pagina.php?provincia=$1&id=$2
Vorrei eliminare il numero in modo che si visualizzi solo:
pagina-torino.php
Come modificare il file .htacces per questa cosa? Bisogna fare anche un reindirizzamamento dalle pagine
pagina.php?provincia=Torino&id=1
a
pagina-torino.php
per migliorare il seo?
Grazie!
Ciao a tutti, molto interessante l’articolo ma ho un problema. Con url rewrite con il file htaccess ho riscitto gli url e questo funziona.
Il problema sorge per il menu del mio sito. Devo riscrivere tutti i link sul menu?
Esempio.
da
http://www.miosito/ariticolo.php?lan=it
a
http://www.miosito/ariticolo-it.html
o esiste un altra soluzione?
Grazie!
Ottimo articolo, molto chiaro. Aggiungo la possibilità di un ottimo mod-rewrite generator:
http://www.generateit.net/mod-rewrite/