Przepisywanie adresów URL za pomocą PHP

Mam URL, który wygląda tak:

url.com/picture.php?id=51

Jak mam przerobić ten adres URL na:

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

Myślę, że WordPress robi to samo.

Jak zrobić przyjazne adresy URL w PHP?

Author: GraphicsMuncher, 2013-05-06

5 answers

Możesz zasadniczo zrobić to na dwa sposoby:

The .htaccess route with mod_rewrite

Dodaj plik o nazwie .htaccess w folderze głównym i dodaj coś takiego:

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

To powie Apache, aby włączył mod_rewrite dla tego folderu, a jeśli zostanie zapytany o adres URL pasujący do wyrażenia regularnego, przepisuje go wewnętrznie do tego, co chcesz, bez tego, że użytkownik końcowy go zobaczy. Proste, ale nieelastyczne, więc jeśli potrzebujesz więcej mocy: {]}

Trasa PHP

Put the podążam za tobą .zamiast tego htaccess: (zwróć uwagę na ukośnik wiodący)

FallbackResource /index.php

Spowoduje to uruchomienie index.php dla wszystkich plików, których normalnie nie może znaleźć w Twojej witrynie. Tam możesz na przykład:

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

Tak robią duże witryny i systemy CMS, ponieważ pozwala to na znacznie większą elastyczność w analizowaniu adresów URL, adresów URL zależnych od konfiguracji i bazy danych itp. W przypadku sporadycznego użycia reguły przepisywania na twardo w .htaccess będą dobrze działać.

 166
Author: Niels Keurentjes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-19 12:22:35

Jeśli chcesz tylko zmienić trasę dla picture.php to dodanie reguły przepisywania w .htaccess będzie służyć twoim potrzebom, ale jeśli chcesz przepisać adres URL tak jak w WordPressie, PHP jest drogą. Oto prosty przykład na początek.

Struktura folderów

Są dwa pliki, które są potrzebne w folderze głównym, .htaccess i index.php, i dobrze byłoby umieścić resztę plików .php w osobnym folderze, jak inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

Ten plik ma cztery dyrektywy:

  1. RewriteEngine - włącz silnik przepisywania
  2. RewriteRule - deny access to all files in inc/ folder, redirect any call to that folder to index.php
  3. RewriteCond - umożliwiają bezpośredni dostęp do wszystkich innych plików (takich jak obrazy, css lub skrypty )
  4. RewriteRule - przekieruj cokolwiek innego na index.php

Indeks.php

Ponieważ wszystko jest teraz Przekierowano do indeksu.php, zostanie ustalone, czy adres url jest poprawny, wszystkie parametry są obecne i czy typ parametrów jest poprawny.

Aby przetestować url musimy mieć zestaw reguł, a najlepszym narzędziem do tego jest wyrażenie regularne. Używając wyrażeń regularnych zabijemy dwie muchy jednym ciosem. Url, aby przejść ten test musi mieć wszystkie wymagane parametry, które są testowane na dozwolonych znaków. Oto kilka przykładów zasad.

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

Następnie należy przygotować URI żądania.

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

Teraz, gdy mamy URI żądania, ostatnim krokiem jest przetestowanie uri na zasadach wyrażeń regularnych.

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

Pomyślne dopasowanie, ponieważ używamy nazwanych podpatternów w regex, wypełni tablicę $params prawie tak samo jak PHP wypełnia tablicę $_GET. Jednak przy użyciu dynamicznego adresu url tablica $_GET jest wypełniana bez sprawdzania parametrów.

    /picture/some+text/51

    Array
    (
        [0] => /picture/some text/51
        [text] => some text
        [1] => some text
        [id] => 51
        [2] => 51
    )

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

    Array
    (
        [text] => some text
        [id] => 51
    )

Te kilka linijek kodu i podstawowa znajomość wyrażeń regularnych wystarczy, aby zacząć budować solidny system routingu.

Complete source

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' );
 48
Author: Danijel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-02 08:47:18

To jest an .plik htaccess, który przekazuje prawie wszystkie do indeksu.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

Następnie należy parse $_SERVER ["REQUEST_URI"] i route to picture.php lub cokolwiek

 5
Author: Luca Rocchi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-05 21:01:45

PHP nie jest tym, czego szukasz, sprawdź mod_rewrite

 3
Author: rauchmelder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-05 20:47:09

Chociaż już odpowiedział, a intencją autora jest stworzenie front controller type app, ale zamieszczam dosłowną regułę dla zadanego problemu. jeśli ktoś ma problem z tym samym.

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

Powyżej powinno działać dla url picture.php/Some-text-goes-here/51. bez użycia indeksu.php jako aplikacja przekierowująca.

 2
Author: Abhishek Gurjar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-27 06:44:23