Перезапис URL-адрес за допомогою PHP


139

У мене є URL-адреса, яка виглядає так:

url.com/picture.php?id=51

Як би я міг перетворити цю URL-адресу на:

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

Я думаю, що WordPress робить те саме.

Як я можу створити дружні URL-адреси в PHP?


1
Вам потрібно багато налаштувати в конфігурації файлів Apache ... навести приклад того, що вам насправді потрібно? Як ви вставляєте цей текст? це заздалегідь визначено чи це створюється динамічно? дайте якомога більше інформації, щоб отримати правильну відповідь ... і так, url може бути трохи більш описовим :)
user123_456

1
Чому PHP? Apache - mod_rewriteце все, що вам потрібно для цього, і тут є багато питань щодо цього. І якщо ви "думаєте", що wordpress робить те саме, чому б вам просто не подивитися ? ;)
nietonfir

читати mod_rewrite

Чому ви це робите? Чи є мета переписати URL-адреси, якщо так використовується .htaccess чи щось подібне. Якщо мета - лише змінити рядок, $ _GET отримує лише рядок запитів?
adeneo

Текст буде назвою зображення, а потім ідентифікатором після косої риски :) Мені доведеться вивчити, що може запропонувати mod_rewrite апачі. Сподіваюся, це не надто складно: D
Jazerix

Відповіді:


194

Ви можете зробити це 2 способи:

Маршрут .htaccess з mod_rewrite

Додайте файл, названий .htaccessу вашій кореневій папці, та додайте щось подібне:

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

Це дозволить Apache увімкнути mod_rewrite для цієї папки, і якщо йому буде запропоновано URL-адресу, що відповідає звичайному виразу, він переписує її внутрішньо на те, що ви хочете, не бачачи кінцевий користувач. Легко, але негнучко, тому якщо вам потрібно більше енергії:

Маршрут PHP

Введіть замість цього .htaccess: (зверніть увагу на провідну косу рису)

FallbackResource /index.php

Це дозволить запустити index.phpфайли для всіх файлів, які він зазвичай не може знайти на вашому сайті. Тут ви можете, наприклад:

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

Це як великі сайти і CMS-системи роблять це, тому що це дозволяє набагато більше гнучкості в аналізі URL - адреси, конфігурацію і баз даних залежною URL - адреса і т.д. Для спорадичних використання жорстко закодоване правило перезапису в .htaccessробитиме штраф , хоча.


Замість жорсткого кодування, ви можете просто використовувати регулярний вираз, щоб повністю ігнорувати рядок. Іншими словами, єдине, що враховує, це частина посвідчення особи. Перехід picture.php/invalid-text/51також буде переспрямовано на те саме місце. Ви також можете додати чек, щоб перевірити, чи є рядок правильним, а якщо ні, перенаправити знову на правильне місце. Ось як я це робив на одному зі своїх сайтів, використовуючи htaccess.
Майк

7
Зручно для менших сайтів, але не дуже практично, якщо вам доведеться розбирати /blog/25так само, як /picture/51і /download/684. Крім того, це вважається дуже поганою практикою (і ви
отримуєте штрафи за

5
принаймні в моїй системі, це було FallbackResource /index.php(зверніть увагу на провідну косу рису)
Джек Джеймс,

4
@olli: коментар із поганою практикою конкретно стосується "не повернення 404 для неіснуючих URL-адрес", що вирішується рішенням у самій відповіді. Що стосується першого питання - FallbackResourceстартує лише для файлів, які насправді не існує у файловій системі, отже, резервна . Тож якщо у вас є файл /static/styles.cssі посилаєтесь на нього, оскільки http://mydomain.tld/static/styles.cssкод ніколи не виконується, він змушує працювати так, як очікувалося, і передбачалося прозоро.
Niels Keurentjes

ви повинні використовувати if($elements[0] === NULL)замість цього, оскільки $elementsви все одно повернете кількість одиниць, навіть якщо вона порожня.
вогневий простір

57

Якщо ви хочете змінити маршрут для подальшого picture.phpдодавання правила перезапису, .htaccessвідповідатиме вашим потребам, але, якщо ви хочете переписати URL, як у Wordpress, тоді це PHP. Ось простий приклад для початку.

Структура папок

У кореневій папці потрібні два файли, .htaccessі index.php, було б добре розмістити решту .phpфайлів в окремій папці, наприклад inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

Цей файл має чотири директиви:

  1. RewriteEngine - включити двигун перезапису
  2. RewriteRule- заборонити доступ до всіх файлів у inc/папці, перенаправити будь-який виклик до цієї папкиindex.php
  3. RewriteCond - дозволити прямий доступ до всіх інших файлів (наприклад, до зображень, css чи скриптів)
  4. RewriteRule - переадресувати що-небудь інше на index.php

index.php

Оскільки тепер усе переспрямовано на index.php, буде визначено, чи URL-адреса правильна, всі параметри присутні та якщо тип параметрів правильний.

Для перевірки URL-адреси нам потрібно встановити набір правил, і найкращим інструментом для цього є регулярний вираз. Використовуючи регулярні вирази, ми вбиємо двох мух одним ударом. URL, щоб пройти цей тест, повинні бути всі необхідні параметри, які тестуються на дозволених символах. Ось кілька прикладів правил.

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

Тепер, коли у нас є запит uri, останнім кроком є ​​тестування 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 )
         */
    }
}

Успішна відповідність, оскільки ми використовуємо названі підпрограми в регулярному виразі, заповнимо $paramsмасив майже так само, як PHP заповнює $_GETмасив. Однак при використанні динамічного URL-адреси $_GETмасив заповнюється без будь-яких перевірок параметрів.

    / малюнок / деякі + текст / 51

    Масив
    (
        [0] => / зображення / деякий текст / 51
        [текст] => деякий текст
        [1] => деякий текст
        [id] => 51
        [2] => 51
    )

    picture.php? text = деякий + текст & id = 51

    Масив
    (
        [текст] => деякий текст
        [id] => 51
    )

Цих кількох рядків коду та основного знання регулярних виразів достатньо для того, щоб почати будувати міцну систему маршрутизації.

Повне джерело

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
Як ви читаєте параметри? Це не працює з $ post_id = htmlentities ($ _ GET ['post']);
andrebruton

@Danijel Чи можу я мати повний вихідний код? Я спробував код вище, але виводився лише текст, CSS не мав ефекту. Дякую.
4 Залиште обкладинку

6

це .htaccess файл, який пересилає майже всі до 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

тобі вирішуватимеш $ _SERVER ["REQUEST_URI"] та рухатись до picture.php або будь-якого іншого


8
Apache представив FallbackResourceдирективу кілька основних версій тому, що є тепер кращим способом реалізувати цю поведінку з меншими витратами на продуктивність, оскільки не потрібно запускати весь механізм перезапису. Документація тут . Ваші правила також є помилковими, оскільки ви не посилаєтесь на каталоги ( !-d), а всі фільтри розширень є застарілими - -fвони вже повинні їх ловити.
Niels Keurentjes


2

Хоча вже відповів, а автор має намір створити додаток типу фронтального контролера, але я публікую буквальне правило для заданої проблеми. якщо хтось має проблему за те саме.

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

Вище має працювати для URL picture.php/Some-text-goes-here/51. не використовуючи index.php як додаток для переадресації.


Мені потрібно знати, яку URL-адресу ми маємо написати в href? тому що я отримую 404
запитань
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.