Penulisan ulang URL dengan PHP

139

Saya memiliki URL yang mirip:

url.com/picture.php?id=51

Bagaimana saya akan mengubah URL itu menjadi:

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

Saya pikir WordPress melakukan hal yang sama.

Bagaimana cara membuat URL yang ramah di PHP?

Jazerix
sumber
1
Anda perlu mengubah banyak dalam konfigurasi file Apache ... memberikan contoh apa yang sebenarnya Anda butuhkan? Bagaimana Anda memasukkan teks ini? apakah sudah ditentukan sebelumnya atau dibuat secara dinamis? berikan info sebanyak mungkin untuk mendapatkan jawaban yang benar ... dan ya url bisa menjadi sedikit lebih deskriptif :)
user123_456
1
Kenapa PHP? Apache mod_rewriteadalah semua yang Anda butuhkan untuk ini dan ada banyak pertanyaan mengenai hal itu di SO. Dan jika Anda "berpikir" bahwa wordpress melakukan hal yang sama, mengapa Anda tidak mencarinya saja ? ;)
nietonfir
Mengapa kau melakukan ini? Apakah tujuannya menulis ulang URL, jika demikian gunakan .htaccess atau yang serupa. Jika tujuannya hanya untuk mengubah string, $ _GET hanya mendapatkan querystring?
adeneo
Teks akan menjadi judul gambar dan kemudian id setelah slash :) Saya harus melihat apa yang mod_rewrite apache tawarkan. Semoga tidak terlalu sulit: D
Jazerix

Jawaban:

194

Anda pada dasarnya dapat melakukan 2 cara ini:

Rute .htaccess dengan mod_rewrite

Tambahkan file yang disebut .htaccessdi folder root Anda, dan tambahkan sesuatu seperti ini:

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

Ini akan memberi tahu Apache untuk mengaktifkan mod_rewrite untuk folder ini, dan jika ditanya URL yang cocok dengan ekspresi reguler, ia menulis ulang secara internal untuk apa yang Anda inginkan, tanpa pengguna akhir melihatnya. Mudah, tetapi tidak fleksibel, jadi jika Anda membutuhkan lebih banyak daya:

Rute PHP

Letakkan yang berikut ini di .htaccess Anda sebagai gantinya: (perhatikan slash utama)

FallbackResource /index.php

Ini akan memerintahkannya untuk menjalankan index.phpsemua file yang biasanya tidak dapat ditemukan di situs Anda. Di sana Anda dapat misalnya:

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

Ini adalah cara situs besar dan sistem CMS melakukannya, karena memungkinkan fleksibilitas yang lebih besar dalam penguraian URL, konfigurasi, dan URL yang bergantung pada database, dll .htaccess.

Niels Keurentjes
sumber
Daripada mengkodekannya, Anda bisa menggunakan regex untuk mengabaikan string sepenuhnya. Dengan kata lain, satu-satunya hal yang diperhitungkan adalah bagian ID. Pergi ke picture.php/invalid-text/51juga akan mengarahkan ulang ke lokasi yang sama. Anda juga bisa menambahkan tanda centang untuk melihat apakah string sudah benar dan jika tidak, arahkan lagi ke lokasi yang benar. Begitulah cara saya melakukannya di salah satu situs saya menggunakan htaccess.
Mike
7
Nyaman untuk situs yang lebih kecil, tetapi tidak benar-benar praktis jika Anda harus mengurai /blog/25serta /picture/51dan /download/684. Juga, itu dianggap praktik yang sangat buruk (dan membuat Anda PR Google dihukum!) Jika tidak semua URL yang dihasilkan secara acak mengembalikan 404.
Niels Keurentjes
5
pada sistem saya setidaknya, itu FallbackResource /index.php(perhatikan slash terkemuka)
Jack James
4
@olli: komentar praktik buruk secara khusus merujuk pada "tidak mengembalikan 404 untuk URL yang tidak ada", yang diselesaikan dengan solusi dalam jawaban itu sendiri. Adapun pertanyaan pertama - FallbackResourcehanya tendangan untuk file yang tidak benar-benar ada di sistem file, maka mundur . Jadi jika Anda memiliki file /static/styles.cssdan merujuknya sebagai http://mydomain.tld/static/styles.csskode tidak pernah dieksekusi, membuatnya berfungsi seperti yang diharapkan dan dimaksudkan secara transparan.
Niels Keurentjes
Anda harus menggunakan if($elements[0] === NULL)sebagai gantinya, karena $elementsmasih akan mengembalikan hitungan satu, bahkan jika itu kosong.
fireinspace
57

Jika Anda hanya ingin mengubah rute untuk picture.phpkemudian menambahkan aturan penulisan ulang .htaccessakan melayani kebutuhan Anda, tetapi, jika Anda ingin URL menulis ulang seperti di Wordpress maka PHP adalah caranya. Ini adalah contoh sederhana untuk memulai.

Struktur folder

Ada dua file yang diperlukan di folder root, .htaccessdan index.php, dan akan lebih baik untuk meletakkan sisa .phpfile di folder terpisah, seperti inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

File ini memiliki empat arahan:

  1. RewriteEngine - aktifkan mesin penulisan ulang
  2. RewriteRule- menolak akses ke semua file dalam inc/folder, mengalihkan semua panggilan ke folder itu keindex.php
  3. RewriteCond - memungkinkan akses langsung ke semua file lain (seperti gambar, css atau skrip)
  4. RewriteRule - redirect apa pun ke index.php

index.php

Karena semuanya sekarang dialihkan ke index.php, akan ditentukan apakah urlnya benar, semua parameter ada, dan jika jenis parameternya benar.

Untuk menguji url kita perlu memiliki seperangkat aturan, dan alat terbaik untuk itu adalah ekspresi reguler. Dengan menggunakan ekspresi reguler, kami akan membunuh dua lalat dengan satu pukulan. Url, untuk lulus tes ini harus memiliki semua parameter yang diperlukan yang diuji pada karakter yang diizinkan. Berikut ini beberapa contoh aturan.

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

Selanjutnya adalah menyiapkan permintaan uri.

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

Sekarang setelah kami memiliki permintaan uri, langkah terakhir adalah menguji uri pada aturan ekspresi reguler.

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

Pertandingan yang berhasil akan, karena kami menggunakan subpatterns bernama di regex, mengisi $paramsarray hampir sama dengan PHP mengisi $_GETarray. Namun, saat menggunakan url dinamis, $_GETarray diisi tanpa parameter apa pun.

    / picture / some + text / 51

    Himpunan
    (
        [0] => / gambar / beberapa teks / 51
        [text] => beberapa teks
        [1] => beberapa teks
        [id] => 51
        [2] => 51
    )

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

    Himpunan
    (
        [text] => beberapa teks
        [id] => 51
    )

Beberapa baris kode ini dan pengetahuan dasar tentang ekspresi reguler sudah cukup untuk mulai membangun sistem perutean yang solid.

Sumber lengkap

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
sumber
2
Bagaimana Anda membaca parameter? Itu tidak bekerja dengan $ post_id = htmlentities ($ _ GET ['post']);
andrebruton
@Danijel Dapatkah saya memiliki kode sumber lengkap? Saya mencoba kode di atas tetapi hanya teks yang dihasilkan, CSS tidak berpengaruh. Terima kasih.
4 Tutup
6

ini adalah file .htaccess yang meneruskan hampir semua ke 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

maka terserah Anda parse $ _SERVER ["REQUEST_URI"] dan rutekan ke picture.php atau apa pun

Luca Rocchi
sumber
8
Apache memperkenalkan FallbackResourcearahan beberapa versi utama yang lalu, yang sekarang merupakan cara yang disukai untuk menerapkan perilaku ini dengan biaya kinerja yang lebih rendah karena tidak perlu meluncurkan seluruh mesin penulisan ulang. Dokumentasi di sini . Aturan Anda juga cacat karena Anda tidak mereferensikan direktori ( !-d) dan semua filter ekstensi sudah usang - yang -fseharusnya sudah menangkap mereka.
Niels Keurentjes
5

PHP bukan yang Anda cari, lihat mod_rewrite

Rauchmelder
sumber
apakah ini akan memengaruhi semua url?
Jazerix
@Jazerix Ini tergantung pada aturan yang Anda tentukan.
nietonfir
2

Meskipun sudah dijawab, dan maksud penulis adalah membuat aplikasi tipe front controller, tetapi saya memposting aturan literal untuk masalah yang diajukan. jika seseorang memiliki masalah yang sama.

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

Di atas harus berfungsi untuk url picture.php/Some-text-goes-here/51. tanpa menggunakan index.php sebagai aplikasi pengalihan.

Abhishek Gurjar
sumber
Saya perlu tahu URL apa yang harus kami tulis dalam href? karena saya mendapatkan 404
questionbank