URL-Umschreibung mit PHP

139

Ich habe eine URL, die wie folgt aussieht:

url.com/picture.php?id=51

Wie würde ich diese URL konvertieren in:

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

Ich denke, WordPress macht das gleiche.

Wie mache ich freundliche URLs in PHP?

Jazerix
quelle
1
Sie müssen die Konfiguration der Apache-Dateien stark optimieren ... geben Sie ein Beispiel dafür, was Sie tatsächlich benötigen? Wie fügen Sie diesen Text ein? ist es vordefiniert oder dynamisch erstellt? Geben Sie so viele Informationen wie möglich, um die richtige Antwort zu erhalten ... und Ihre URL könnte etwas
aussagekräftiger sein
1
Warum PHP? Apache's mod_rewriteist alles was Sie dafür brauchen und es gibt viele Fragen dazu hier auf SO. Und wenn Sie "denken", dass WordPress dasselbe tut, warum suchen Sie es nicht einfach nach ? ;)
Nietonfir
Lesen Sie mod_rewrite
Warum tust du das? Ist das Ziel das Umschreiben der URLs, wenn ja, verwenden Sie .htaccess oder ähnliches. Wenn das Ziel nur darin besteht, den String zu ändern, erhält $ _GET nur den Querystring?
Adeneo
Der Text wäre der Titel eines Bildes und dann die ID nach dem Schrägstrich :) Ich muss untersuchen, was apaches mod_rewrite zu bieten hat. Hoffe, es ist nicht zu schwierig: D
Jazerix

Antworten:

194

Sie können dies im Wesentlichen auf zwei Arten tun:

Die .htaccess-Route mit mod_rewrite

Fügen Sie eine Datei hinzu, die .htaccessin Ihrem Stammordner aufgerufen wird , und fügen Sie Folgendes hinzu:

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

Dadurch wird Apache angewiesen, mod_rewrite für diesen Ordner zu aktivieren. Wenn eine URL gefragt wird, die dem regulären Ausdruck entspricht, wird sie intern nach Ihren Wünschen neu geschrieben , ohne dass der Endbenutzer sie sieht. Einfach, aber unflexibel. Wenn Sie also mehr Leistung benötigen:

Die PHP-Route

Fügen Sie stattdessen Folgendes in Ihren .htaccess ein: (Beachten Sie den führenden Schrägstrich)

FallbackResource /index.php

Dadurch wird es angewiesen, index.phpalle Dateien auszuführen, die normalerweise nicht auf Ihrer Site gefunden werden. Dort können Sie dann zum Beispiel:

$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();
}

So machen es große Sites und CMS-Systeme, weil es viel mehr Flexibilität beim Parsen von URLs, konfigurations- und datenbankabhängigen URLs usw. bietet. Für die sporadische Verwendung .htaccessreichen die fest codierten Umschreiberegeln jedoch aus.

Niels Keurentjes
quelle
Anstatt es fest zu codieren, können Sie die Zeichenfolge auch mit Regex vollständig ignorieren. Mit anderen Worten, das einzige, was zählt, ist der ID-Teil. Wenn Sie zu gehen, wird picture.php/invalid-text/51auch zum selben Speicherort umgeleitet. Sie können auch eine Überprüfung hinzufügen, um festzustellen, ob die Zeichenfolge korrekt ist, und wenn nicht, erneut an die richtige Position umleiten. So habe ich es auf einer meiner Websites mit htaccess gemacht.
Mike
7
Praktisch für kleinere Websites, aber nicht wirklich praktisch, wenn Sie /blog/25ebenso wie /picture/51und analysieren müssen /download/684. Außerdem wird es als sehr schlechte Praxis angesehen (und Sie werden mit Google PR bestraft!), Wenn nicht alle zufällig generierten URLs ordnungsgemäß 404 zurückgeben.
Niels Keurentjes
5
Zumindest auf meinem System war das FallbackResource /index.php(beachten Sie den führenden Schrägstrich)
Jack James
4
@olli: Der Kommentar zu schlechten Praktiken bezieht sich speziell auf "Keine Rückgabe von 404 für nicht vorhandene URLs", was durch die Lösung in der Antwort selbst gelöst wird. Was die erste Frage FallbackResourcebetrifft - wird nur für Dateien aktiviert, die im Dateisystem nicht vorhanden sind, daher der Fallback . Wenn Sie also eine Datei haben /static/styles.cssund darauf verweisen, dass http://mydomain.tld/static/styles.cssder Code nie ausgeführt wird, funktioniert er wie erwartet und transparent.
Niels Keurentjes
Sie sollten if($elements[0] === NULL)stattdessen verwenden, da $elementsimmer noch eine Zählung von eins zurückgegeben wird, auch wenn es leer ist.
Feuerraum
57

Wenn Sie nur die Route ändern möchten, um picture.phpdann eine Umschreiberegel hinzuzufügen, .htaccesswird dies Ihren Anforderungen entsprechen. Wenn Sie jedoch möchten, dass die URL wie in Wordpress neu geschrieben wird, ist PHP der richtige Weg. Hier ist zunächst ein einfaches Beispiel.

Ordnerstruktur

Es gibt zwei Dateien, die im Stammordner benötigt werden, .htaccessund index.php, und es wäre gut, den Rest der .phpDateien in einem separaten Ordner zu platzieren, wie z inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

Diese Datei enthält vier Anweisungen:

  1. RewriteEngine - Aktivieren Sie die Umschreibe-Engine
  2. RewriteRule- Verweigern Sie den Zugriff auf alle Dateien im inc/Ordner und leiten Sie jeden Aufruf an diesen Ordner umindex.php
  3. RewriteCond - Ermöglichen Sie den direkten Zugriff auf alle anderen Dateien (wie Bilder, CSS oder Skripte).
  4. RewriteRule - alles andere umleiten an index.php

index.php

Da jetzt alles auf index.php umgeleitet wird, wird festgestellt, ob die URL korrekt ist, alle Parameter vorhanden sind und ob die Art der Parameter korrekt ist.

Um die URL zu testen, benötigen wir eine Reihe von Regeln, und das beste Werkzeug dafür ist ein regulärer Ausdruck. Mit regulären Ausdrücken töten wir zwei Fliegen mit einem Schlag. URL, um diesen Test zu bestehen, muss alle erforderlichen Parameter enthalten, die an zulässigen Zeichen getestet werden. Hier sind einige Beispiele für Regeln.

$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'      => "/"                                      // '/'
);

Als nächstes bereiten Sie die Anfrage uri vor.

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

Nachdem wir die Anfrage uri haben, besteht der letzte Schritt darin, uri anhand der Regeln für reguläre Ausdrücke zu testen.

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 )
         */
    }
}

Eine erfolgreiche Übereinstimmung füllt das $paramsArray fast genauso, wie PHP das $_GETArray füllt , da wir in Regex benannte Untermuster verwenden . Bei Verwendung einer dynamischen URL wird das $_GETArray jedoch ohne Überprüfung der Parameter gefüllt.

    / Bild / etwas + Text / 51

    Array
    ((
        [0] => / Bild / etwas Text / 51
        [text] => etwas Text
        [1] => etwas Text
        [id] => 51
        [2] => 51
    )

    picture.php? text = some + text & id = 51

    Array
    ((
        [text] => etwas Text
        [id] => 51
    )

Diese wenigen Codezeilen und die Grundkenntnisse der regulären Ausdrücke reichen aus, um ein solides Routing-System aufzubauen.

Vollständige Quelle

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' );
Danijel
quelle
2
Wie liest du die Parameter? Es funktioniert nicht mit $ post_id = htmlentities ($ _ GET ['post']);
andrebruton
@Danijel Kann ich einen vollständigen Quellcode haben? Ich habe den obigen Code ausprobiert, aber es wurde nur Text ausgegeben, CSS keine Auswirkung. Danke dir.
4 Verlassen Sie die Deckung
6

Dies ist eine .htaccess-Datei, die fast alle an index.php weiterleitet

# 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

Dann liegt es an Ihnen, $ _SERVER ["REQUEST_URI"] zu analysieren und zu picture.php oder was auch immer zu routen

Luca Rocchi
quelle
8
Apache hat die FallbackResourceDirektive vor einigen Hauptversionen eingeführt. Dies ist nun die bevorzugte Methode, um dieses Verhalten zu geringeren Leistungskosten zu implementieren, da nicht die gesamte Rewriting-Engine gestartet werden muss. Dokumentation hier . Ihre Regeln sind auch fehlerhaft, weil Sie nicht auf Verzeichnisse ( !-d) verweisen und alle Erweiterungsfilter veraltet sind - die -fsollten sie bereits abfangen.
Niels Keurentjes
5

PHP ist nicht das, wonach Sie suchen. Schauen Sie sich mod_rewrite an

rauchmelder
quelle
Wird es alle URLs betreffen?
Jazerix
@Jazerix Dies hängt von den von Ihnen definierten Regeln ab.
Nietonfir
2

Obwohl bereits beantwortet, und der Autor beabsichtigt, eine Front-Controller-App zu erstellen, aber ich poste eine wörtliche Regel für das gestellte Problem. wenn jemand das Problem dafür hat.

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

Oben sollte für URL funktionieren picture.php/Some-text-goes-here/51. ohne eine index.php als Weiterleitungs-App zu verwenden.

Abhishek Gurjar
quelle
Ich muss wissen, welche URL wir in href schreiben müssen? weil ich 404 bin immer
questionbank