Riscrittura URL con PHP


139

Ho un URL che assomiglia a:

url.com/picture.php?id=51

Come farei per convertire quell'URL in:

picture.php/Some-text-goes-here/51

Penso che WordPress faccia lo stesso.

Come faccio a creare URL amichevoli in PHP?


1
Devi modificare molto la configurazione dei file Apache ... dare un esempio di ciò di cui hai effettivamente bisogno? Come si inserisce questo testo? è predefinito o è stato creato dinamicamente? fornire quante più informazioni possibili per ottenere la risposta giusta ... e sì, l'URL potrebbe essere un po 'più descrittivo :)
user123_456

1
Perché PHP? Apache mod_rewriteè tutto ciò di cui hai bisogno per questo e ci sono molte domande su questo qui su SO. E se "pensi" che lo wordpress faccia lo stesso, perché non lo cerchi semplicemente ? ;)
nietonfir


Perché stai facendo questo? L'obiettivo è riscrivere gli URL, in tal caso utilizzare .htaccess o qualcosa di simile. Se l'obiettivo è solo quello di cambiare la stringa, $ _GET ottiene solo la stringa di query?
adeneo,

Il testo sarebbe il titolo di un'immagine e quindi l'id dopo la barra :) Dovrò esaminare ciò che mod_rewrite di apache ha da offrire. Spero non sia troppo difficile: D
Jazerix

Risposte:


194

Puoi essenzialmente farlo in 2 modi:

Il percorso .htaccess con mod_rewrite

Aggiungi un file chiamato .htaccessnella cartella principale e aggiungi qualcosa del genere:

RewriteEngine on
RewriteRule ^/?Some-text-goes-here/([0-9]+)$ /picture.php?id=$1

Questo dirà ad Apache di abilitare mod_rewrite per questa cartella, e se gli viene chiesto un URL corrispondente all'espressione regolare, lo riscrive internamente a quello che vuoi, senza che l'utente finale lo veda. Facile, ma non flessibile, quindi se hai bisogno di più potenza:

La rotta PHP

Inserisci invece quanto segue nel tuo .htaccess: (nota la barra iniziale)

FallbackResource /index.php

Questo ti dirà di eseguire il tuo index.phpper tutti i file che normalmente non trova nel tuo sito. Qui puoi ad esempio:

$path = ltrim($_SERVER['REQUEST_URI'], '/');    // Trim leading slash(es)
$elements = explode('/', $path);                // Split path on slashes
if(empty($elements[0])) {                       // No path elements means home
    ShowHomepage();
} else switch(array_shift($elements))             // Pop off first item and switch
{
    case 'Some-text-goes-here':
        ShowPicture($elements); // passes rest of parameters to internal function
        break;
    case 'more':
        ...
    default:
        header('HTTP/1.1 404 Not Found');
        Show404Error();
}

Questo è il modo in cui i grandi siti e i sistemi CMS lo fanno, perché consente una flessibilità molto maggiore nell'analisi di URL, configurazione e URL dipendenti dal database, ecc. Per un uso sporadico le regole di riscrittura codificate .htaccessandranno bene comunque.


Invece di codificarlo, puoi semplicemente usare regex per ignorare completamente la stringa. In altre parole, l'unica cosa che conta è la parte ID. Andare a picture.php/invalid-text/51reindirizzerebbe anche nella stessa posizione. È inoltre possibile aggiungere un segno di spunta per verificare se la stringa è corretta e, in caso contrario, reindirizzare nuovamente nella posizione corretta. È così che l'ho fatto su uno dei miei siti usando htaccess.
Mike,

7
Conveniente per i siti più piccoli, ma non molto pratico se devi analizzare /blog/25anche /picture/51e /download/684. Inoltre, è considerata una cattiva pratica (e ti penalizza Google PR!) Se non tutti gli URL generati casualmente restituiscono correttamente 404.
Niels Keurentjes

5
almeno sul mio sistema era FallbackResource /index.php(nota la barra iniziale)
Jack James,

4
@olli: il commento di cattiva pratica si riferisce specificamente al "non restituire 404 per URL inesistenti", che è risolto dalla soluzione nella risposta stessa. Per quanto riguarda la prima domanda, FallbackResourceentra in gioco solo per i file che in realtà non esistono sul filesystem, quindi il fallback . Quindi, se si dispone di un file /static/styles.csse si fa riferimento ad esso in quanto http://mydomain.tld/static/styles.cssil codice non viene mai eseguito, facendolo funzionare come previsto e previsto in modo trasparente.
Niels Keurentjes,

dovresti usare if($elements[0] === NULL)invece, poiché $elementsrestituirà comunque un conteggio di uno, anche se è vuoto.
fireinspace

57

Se vuoi solo cambiare il percorso per l' picture.phpaggiunta di una regola di riscrittura .htaccesssoddisfarai le tue esigenze, ma, se vuoi riscrivere l'URL come in Wordpress, PHP è la soluzione. Ecco un semplice esempio per cominciare.

Struttura delle cartelle

Ci sono due file che sono necessari nella cartella principale .htaccesse index.php, e sarebbe bene posizionare il resto dei .phpfile in una cartella separata, come inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

RewriteEngine On
RewriteRule ^inc/.*$ index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]

Questo file ha quattro direttive:

  1. RewriteEngine - abilita il motore di riscrittura
  2. RewriteRule - nega l'accesso a tutti i file in inc/ cartella, reindirizzare qualsiasi chiamata a quella cartellaindex.php
  3. RewriteCond - consentire l'accesso diretto a tutti gli altri file (come immagini, CSS o script)
  4. RewriteRule - reindirizzare qualsiasi altra cosa a index.php

index.php

Poiché ora tutto viene reindirizzato a index.php, verrà determinato se l'URL è corretto, tutti i parametri sono presenti e se il tipo di parametri è corretto.

Per testare l'URL dobbiamo avere un insieme di regole e lo strumento migliore per farlo è un'espressione regolare. Usando espressioni regolari uccideremo due mosche con un colpo. Url, per superare questo test devono avere tutti i parametri richiesti che vengono testati su caratteri consentiti. Ecco alcuni esempi di regole.

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

Il prossimo è preparare l'uri richiesta.

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

Ora che abbiamo la richiesta uri, il passo finale è testare uri sulle regole delle espressioni regolari.

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
    }
}

Una partita di successo, dato che utilizziamo repatterns nominati in regex, riempie l' $paramsarray quasi allo stesso modo in cui PHP riempie l' $_GETarray. Tuttavia, quando si utilizza un URL dinamico, l' $_GETarray viene popolato senza alcun controllo dei parametri.

    / Immagine / un po '+ text / 51

    Vettore
    (
        [0] => / immagine / del testo / 51
        [testo] => del testo
        [1] => del testo
        [id] => 51
        [2] => 51
    )

    picture.php? text = alcuni + testo & id = 51

    Vettore
    (
        [testo] => del testo
        [id] => 51
    )

Queste poche righe di codice e una conoscenza di base delle espressioni regolari sono sufficienti per iniziare a costruire un solido sistema di routing.

Fonte completa

define( 'INCLUDE_DIR', dirname( __FILE__ ) . '/inc/' );

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
        include( INCLUDE_DIR . $action . '.php' );

        // exit to avoid the 404 message 
        exit();
    }
}

// nothing is found so handle the 404 error
include( INCLUDE_DIR . '404.php' );

2
Come leggi i parametri? Non funziona con $ post_id = htmlentities ($ _ GET ['post']);
Andrebruton,

@Danijel Posso avere un codice sorgente completo? Ho provato il codice sopra ma è stato emesso solo testo, CSS non ha alcun effetto. Grazie.
4 Lascia la copertura il

6

questo è un file .htaccess che inoltra quasi tutto a index.php

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !-l
RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|gif|js)$ [NC]
# otherwise forward it to index.php
RewriteRule . index.php

allora spetta a te analizzare $ _SERVER ["REQUEST_URI"] e instradare a picture.php o altro


8
Apache ha introdotto la FallbackResourcedirettiva alcune versioni principali fa, che ora è il modo preferito per implementare questo comportamento a un costo inferiore in quanto non è necessario avviare l'intero motore di riscrittura. Documentazione qui . Anche le tue regole sono imperfette perché non fai riferimento alle directory ( !-d) e tutti i filtri di estensione sono obsoleti, il che -fdovrebbe già catturarli.
Niels Keurentjes,


2

Sebbene abbia già risposto, e l'intento dell'autore è quello di creare un'app di tipo front controller ma sto pubblicando una regola letterale per il problema richiesto. se qualcuno ha il problema per lo stesso.

RewriteEngine On
RewriteRule ^([^/]+)/([^/]+)/([\d]+)$ $1?id=$3 [L]

Sopra dovrebbe funzionare per url picture.php/Some-text-goes-here/51. senza utilizzare index.php come app di reindirizzamento.


Devo sapere quale URL dobbiamo scrivere in href? perché sto ricevendo il 404
questionbank il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.