• Super User

    Guida al mod_rewrite

    Appena inserita su WikiGT: Guida mod_rewrite 🙂
    Vi riporto qui sotto il testo, postate liberamente le vostre richieste.

    -> Per la correzione dei (pochi 😢) errori potete modificare direttamente la voce sul wiki.
    -> Per chiarimenti sul contenuto della guida (relativo al contenuto stesso) potete rispondere direttamente in questo thread
    -> Per le altre richieste vi prego di aprire un nuovo thread, in modo da tenere ogni situazione separata dalle altre e tenere il forum ordinato. Grazie!

    
    
    
    *Nonostante le tonnellate di esempi e documentazione, mod_rewrite è voodoo.
    Voodoo dannatamente figo, ma sempre voodoo.*[INDENT][INDENT][INDENT][INDENT][INDENT][INDENT][INDENT][INDENT][INDENT][INDENT] -- [Brian Moore](http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html)
    [/INDENT][/INDENT][/INDENT][/INDENT][/INDENT][/INDENT][/INDENT][/INDENT][/INDENT][/INDENT]Piccola guida al mod_rewrite - contiene le informazioni base da sapere per utilizzare questo utilissimo modulo. La guida anche se orientata ad Apache è ovviamente valida (per la parte teorica) ad IIS / ISAPI rewrite.
    
    INDICE:
    - <a href="#inizio">Prima di cominciare</a>
    - <a href="#focus">Uno sguardo da vicino</a>
    - <a href="#pratica">mod_rewrite in pratica</a>
    - <a href="#fine">Per i più bravi</a>
    
    Stando in linea con la filosofia del forum, questa guida *non è legge* ma solo un contributo alla comunità (che mi auguro ricambi, segnalando errori o ampliando le sezioni).
    
    
    __________________________________________________
    <a name="inizio">**Prima di cominciare**</a>
    
    **0.0- Requisiti**
    - conoscenza base delle [espressioni regolari](http://www.ilovejackdaniels.com/regular_expressions_cheat_sheet.png)
    
    
    __________________________________________________
     <a name="focus">**Uno sguardo da vicino**</a>
    
    **1.0- Cosa è il mod_rewrite**
    mod_rewrite è un modulo per Apache, il webserver più usato nel mondo Unix. Il modulo associa "al volo" un URL virtuale (non residente sul filesystem) ad uno reale, tramite delle regole definite nei file .htaccess
    **
    1.1- Come si attiva** 
    Se sei in un hosting condiviso, non devi fare niente: il modulo è attivo di default nella maggior parte dei casi. In ogni caso prima di acquistare un piano d'hosting chiedi esplicitamente se il modulo è installato!
    
    Se lavori invece su un tuo server dedicato / VPS / localhost, molto probabilmente devi attivare il modulo a mano:
    - per Apache2 a2enmod rewrite come root
    - per Apache1 è necessario decommentare la linea LoadModule mod_rewrite nel file di configurazione
    
    Apache di default ignora i file .htaccess (e di conseguenza le tue regole!) - per farglieli leggere devi modificare la direttiva AllowOverride all'interno del file di configurazione. Ricorda di riavviare il webserver.
    
    **1.2- La prova del nove**
    Per controllare se il modulo funziona:
    *Livello 1*) crea una pagina .php contenente
    [php]<?php phpinfo(); ?>[/php]Richiamala dal browser e cerca nella pagina mod_rewrite sotto *Loaded Modules*. Se trovi la stringa, vuol dire che il modulo è caricato.[INDENT] Attenzione!! Caricato in memoria non vuol dire utilizzabile - infatti se il modulo è presente, ma i file .htaccess vengono ignorati (vedi sopra), le regole di riscrittura non funzioneranno! Per questo entra in gioco il
    [/INDENT]*Livello 2*) testare se effettivamente gli indirizzi vengono riscritti: scarica [questo file](http://www.webmatters.it/labs2/rewritetest.zip) e segui le istruzioni contenute nell'archivo stesso.
    
    **1.3- Struttura di un file .htaccess**
    Riporto la struttura "base" di un file .htaccess contenente una semplice regola
    
    ```
    RewriteEngine On
    RewriteRule ^index.html$ fooindex.php 
    ```La prima linea attiva l'engine (va sempre inserita)
    La seconda linea specifica una regola (RewriteRule) composta da:
    *  l'URL da riscrivere, tra ^ (inizio stringa) e $ (fine stringa), quasi sempre formato da espressioni regolari
    * l'URL al quale inviare la richiesta
    * parametri (tra parentesi quadre, separati da virgole)
    * **L** "ultimo" -> paragonabile al break, dice all'engine di fermarsi e di non controllare le altre regole
    * **R=301** -> invia un header di contenuto spostato in modo permanente e crea il redirect
    * **R=302** -> invia un header di contenuto spostato in modo temporaneo e crea il redirect
    * **QSA** "accoda query string" -> se l'URL richiesto contiene più parametri di quelli previsti, vengono accodati - utile se si vogliono mettere parametri a pagine con indirizzi riscritti (!!). Inserendo queste due righe in domain.tld/.htaccess, quando un utente visita domain.tld/index.html il webserver invia la pagina domain.tld/fooindex.php. L'utente non si accorge di niente.[INDENT]**Deep focus:**
    - se fooindex.php non esiste, l'utente vede "404 fooindex.php", anche se ha richiesto index.html
    - index.html può anche non esistere: il webserver invierà al client direttamente il file php senza neppure curarsi del file html
    [/INDENT]__________________________________________________
     <a name="pratica">**mod_rewrite in pratica**</a>
    
    **2.0- Let's check it out!**
    Procediamo per casi analizzando alcuni URL-tipo che ognuno di noi ha incontrato almeno una volta. Sono solo degli esempi, **riadattabili** alle proprie esigenze. Il consiglio è di **leggere in modo lineare** tutti i casi, e non solo la parte finale.
    
    Lo scenario è la **sezione news di un sito.
    **Ricordate che in ogni file htaccess dovete inserire, prima delle regole, la direttiva RewriteEngine On.
    
    **2.1- Riscrittura "base"**
    URL prima dell'intervento: [www.domain.tld/news/index.php?id=1234](http://www.domain.tld/news/index.php?id=1234)
    URL dopo l'intervento: [www.domain.tld/news/notizia-1234.html](http://www.domain.tld/news/notizia-1234.html)
    
    ```
    RewriteRule ^notizia-([0-9]+)\.html$ index.php?id=$1
    ```- ([0-9]+) *uno o più* (+) *caratteri numerici da 0 a 9* ([0-9])
    - \.html indica ".html" (**.** è un metacarattere che vuol dire *qualsiasi carattere*, dobbiamo effettuare l'escape).
    - $1 viene sostituito con il valore "trovato" dalla regexp *([0-9]+)*
    
    Ok, abbiamo tolto la querystring (hai detto niente!). Ma non è proprio il sistema più raffinato e la semantica è a 0.
    
    
    **2.2- Gestire più parametri**
    URL prima dell'intervento: [www.domain.tld/news/index.php?id=1234&cat=recensione](http://www.domain.tld/news/index.php?id=1234&cat=recensione)
    URL dopo l'intervento: [www.domain.tld/news/recensione-1234.html](http://www.domain.tld/news/recensione-1234.html)
    
    ```
    RewriteRule ^(.+)-([0-9]+)\.html$ index.php?id=$2&cat=$1
    ```[INDENT]Consiglio: invece di usare (.+) (qualsiasi carattere in qualsiasi quantità) è più saggio usare ([^/]+) che vuol dire "qualsiasi carattere *tranne lo slash* in qualsiasi quantità".
    [/INDENT]**2.3- Associazioni tra ID e stringhe**
    URL prima dell'intervento: [www.domain.tld/news/categoria.php?id=2](http://www.domain.tld/news/categoria.php?id=2)
    URL dopo l'intervento: [www.domain.tld/news/recensioni.html](http://www.domain.tld/news/recensioni.html)
    
    ```
    RewriteRule ^([^/]+)\.html$ index.php?nomecat=$1
    ```[php]$cat = $_GET['nomecat'];
    $categoria = mysql_query("SELECT id FROM categorie WHERE nome='$cat'");
    if (mysql_num_rows($categoria)==0) {
        Make404(......);
    } else {
        $categoria = mysql_num_rows($categoria);
        $news = mysql_query("SELECT .... FROM news WHERE categoria='$categoria[0]'");
        ShowNews(......);
    }[/php]Nota bene: è possibile eliminare l'ID contenuto nell'URL se e solo se la corrispondenza ID<->stringa è biunivoca!
    
    
    **2.4- Il caso ideale**
    URL prima dell'intervento: [www.domain.tld/news/index.php?id=1234](http://www.domain.tld/news/index.php?id=1234)
    URL dopo l'intervento: [www.domain.tld/news/recensioni/php6-usera-goto-1234.html](http://www.domain.tld/news/recensioni/php6-usera-goto-1234.html)
    
    ```
    RewriteRule ^([^/]+)/([^/]+)-([0-9]+)\.html$ index.php?id=$3&cat=$1&titolo=$2
    ```[php]$newsid = $_GET['id']; // non serve fare il cast con (int)
    $news = mysql_query("SELECT ... FROM news WHERE id='$newsid'");
    if (mysql_num_rows($news)==0) {
        Make404(......);
    } else {
        .....
        // supponiamo di avere in $cat la categoria letta dal database
        // e in $titolo il.. titolo ovviamente
        if ($cat != $_GET['cat'] || ottimizza($titolo) != $_GET['titolo']) {
           // è stato cambiato titolo o categoria
           make301('http://www.domain.tld/news/' . $cat . '/' . $titolo . '-' . $newsid . '.html');
        }
    
        NewsClass:ShowNews(......);
    }[/php]
    * la funzione *ottimizza *deve essere la stessa usata per mostrare gli URL nella pagina con l'elenco delle news per evitare problemi di doppi-redirect e serve per eliminare spazi, caratteri accentati, ecc.
    * la funzione *make301* deve inviare un header 301, un header location e bloccare lo script (con exit; )
    * la semantica di questi URL è molto buona (un file chiamato come la news contenuto in una directory correlata)
    * se la news viene spostata di categoria o rinominata, viene automaticamente generato un header 301 invece di un 404 (come su questo forum)=> new! [scarica questo esempio](http://labs2.webmatters.it/rewriteexample.zip)
    __________________________________________________
     <a name="fine">**Per i più bravi**</a>**
    
    3.0- Quando qualcosa non funziona** 
    La direttiva RewriteLog permette di salvare l'output di debug di mod_rewrite su un file, ma va inserita nel file di configurazione principale di Apache, e in un hosting condiviso ciò non è possibile.
    
    Per vedere quali pezzi di url (e in che modo) vengono riconosciuti, basta usare uno script con questo semplice contenuto
    [php]<pre>
    <?php print_r($_GET);
    </pre>[/php]```
    RewriteRule ^(.+)-(.+)\.html$ debugger.php?id=$1&cat=$2
    ```Richiamando nel browser la pagina test-123.html:
    > Array
    (
        [id] => test
        [cat] => 123
    )capiremo di aver invertito $1 con $2.. ;)
    
    
    **3.1- Ottimizzazioni**
    Tre consigli:
    * se possibile, caricare le regole nella configurazione (ad ogni accesso, il file .htaccess viene aperto, letto, parsato, chiuso..)
    * evitare trasformazioni stupide (es .php -> .html) - ai fini dell'ottimizzazione non cambia assolutamente niente
    * usare  (va inserito quasi sempre) per non far testare a mod_rewrite le regole successive.

  • Community Manager

    Ottimo Lavoro Osvi 🙂

    Mettiamo in rilievo per un pochino 😉


  • Super User

    Complimenti !


  • Moderatore

    che guidona 🙂 thx ^_^


  • Super User

    Ottima ed utilissima guida. Ancor di più l'idea di far scaricare l'esempio!


  • Moderatore

    nell'esempio non usi il 301 è un errore o è fatto apposta?


  • Moderatore

    hai caricatoo tutti i file? lo vedi nell'ftp il file htaccess?

    lo script funziona per funzionare 🙂

    la mia domanda è sempre:

    @massimux said:

    nell'esempio non usi il 301 è un errore o è fatto apposta?


  • User

    @massimux said:

    hai caricatoo tutti i file? lo vedi nell'ftp il file htaccess?

    Si si lo vedo...


  • Moderatore

    mi dai l'indirizzo? magari apri un nuovo topic in questa sezione in modo da non "sporcare"(andare fuori tema) la guida di osvi 😄


  • User

    ottima guida anche se su IIs le cose sono davvero tristi, ma tristi tristi...
    in teoria funziona tutto, si installa Isapi rewrite, funziona benissimo ad ogni test e legge pure le espressioni regolari validandole...

    ma non cambia un url che sia uno!!

    Voto Apache e Linux per queste cose, su altro hosting Linux con Wordpress funzionavano tutte le combinazioni di url rewrite possibili.

    Mi sà che su Windows 2003 e IIs è come andare con la Ferrari sullo sterrato, non è il suo!


  • Super User

    grazie massimux per avermelo fatto notare 🙂

    ho aggiornato lo ZIP.. il 301 era già mezzo inserito (nel file funzioni.php), chissà a che pensavo.. 😄

    ho messo sia quello che controlla il titolo modificato, sia quello per gli url "prima del rewrite"

    ciao!


  • Moderatore

    lieto di esserti stato di aiuto avevo notato 😉


  • Moderatore

    ma se per il redirect301 avessimo usato [R=301] nell' .htaccess?


  • User

    Salve a tutti,
    ottima la guida, per il mio nuovo sito ho creato il file htacces..il redirect funziona nel senso però che mi ridireziona tutto all'home page..ad esempio

    RewriteRule ^index.php?option=com_content&task=view&id=55&Itemid=80$ azienda.php [L,R=301]

    può andare bene un record scritto così?
    Grazie a tutti comunque


  • User Attivo

    scusate la domanda stupida questa guida funziona solo per pagine php? se si per pagine asp come faccio?


  • User

    non ho capito i vantaggi che si hanno ad usare questa tecnica


  • Moderatore

    Vi rispondo una sola volta... ma la prossima volta sarebbe meglio aprire un nuovo topic in modo da poter rispondere in modo preciso...

    @digitos

    Allora aruba non ricordo se permetta l'URLrewrite ovviamente puoi vedere nelle loro faq.
    Il comando da dare sulla tua VPS per attivare il modulo apache rewrite è molto semplice:
    Accedi alla shell del tuo VPS con account root
    digiti il seguente comando: "apache2 a2enmod rewrite".

    @Totem80

    I vantaggi li ritrovi sul lato SEO e sulla praticità del sito. tutto qui 🙂


  • Super User

    attenzione, il comando corretto (testato su Debian) è

    a2enmod rewrite
    

    (apache2 enable module rewrite)

    guarda in phpinfo(). tra i moduli di apache vedi mod_rewrite caricato?
    se no, attivalo con quel comando
    se si, controlla la direttiva AllowOverride (su None ignora completamente i .htaccess :2: