Viết lại URL bằng PHP


139

Tôi có một URL giống như:

url.com/picture.php?id=51

Làm cách nào để chuyển đổi URL đó thành:

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

Tôi nghĩ rằng WordPress cũng làm như vậy.

Làm cách nào để tạo các URL thân thiện trong PHP?


1
Bạn cần tinh chỉnh rất nhiều trong cấu hình của các tệp Apache ... đưa ra một ví dụ về những gì bạn thực sự cần? Làm thế nào để bạn chèn văn bản này? nó được xác định trước hay nó được tạo ra một cách linh hoạt? cung cấp càng nhiều thông tin càng tốt để có câu trả lời đúng ... và url của bạn có thể mô tả thêm một chút :)
user123_456

1
Tại sao lại là PHP? Apache mod_rewritelà tất cả những gì bạn cần cho việc này và có rất nhiều câu hỏi liên quan đến vấn đề này ở đây trên SO. Và nếu bạn "nghĩ" rằng wordpress cũng làm như vậy, tại sao bạn không đơn giản tìm kiếm nó ? ;)
nietonfir

đọc mod_rewrite

Tại sao anh làm điều này? Là mục tiêu viết lại URL, nếu vậy hãy sử dụng .htaccess hoặc một cái gì đó tương tự. Nếu mục tiêu chỉ là thay đổi chuỗi, $ _GET chỉ nhận được chuỗi truy vấn?
adeneo

Văn bản sẽ là tiêu đề của một hình ảnh và sau đó là id sau dấu gạch chéo :) Tôi sẽ phải xem xét mod_rewrite của apache cung cấp những gì. Hy vọng nó không quá khó: D
Jazerix

Câu trả lời:


194

Về cơ bản bạn có thể làm 2 cách này:

Tuyến đường .htaccess với mod_rewrite

Thêm một tệp được gọi .htaccesstrong thư mục gốc của bạn và thêm một cái gì đó như thế này:

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

Điều này sẽ bảo Apache kích hoạt mod_rewrite cho thư mục này và nếu nó được hỏi một URL khớp với biểu thức chính quy, nó sẽ ghi lại nội bộ theo những gì bạn muốn mà không cần người dùng cuối nhìn thấy. Dễ dàng, nhưng không linh hoạt, vì vậy nếu bạn cần thêm sức mạnh:

Tuyến đường PHP

Thay vào đó, hãy đặt phần sau vào .htaccess của bạn: (lưu ý dấu gạch chéo hàng đầu)

FallbackResource /index.php

Điều này sẽ bảo nó chạy index.phptất cả các tệp mà nó thường không thể tìm thấy trong trang web của bạn. Trong đó bạn có thể lấy ví dụ:

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

Đây là cách các trang web lớn và hệ thống CMS làm điều đó, bởi vì nó cho phép linh hoạt hơn nhiều trong việc phân tích cú pháp URL, cấu hình và URL phụ thuộc cơ sở dữ liệu, v.v. Để sử dụng lẻ tẻ, các quy tắc viết lại mã hóa cứng .htaccesssẽ hoạt động tốt.


Thay vì mã hóa cứng, bạn chỉ có thể sử dụng regex để bỏ qua chuỗi hoàn toàn. Nói cách khác, thứ duy nhất được tính là phần ID. Đi đến picture.php/invalid-text/51cũng sẽ chuyển hướng đến cùng một vị trí. Bạn cũng có thể thêm một kiểm tra để xem chuỗi có đúng không và nếu không, hãy chuyển hướng một lần nữa đến vị trí chính xác. Đó là cách tôi đã làm trên một trong những trang web của mình bằng htaccess.
Mike

7
Thuận tiện cho các trang web nhỏ hơn, nhưng không thực sự thiết thực nếu bạn phải phân tích cú pháp /blog/25cũng như /picture/51/download/684. Ngoài ra, nó được coi là thực tiễn rất tệ (và khiến Google PR bị phạt!) Nếu không phải tất cả các URL được tạo ngẫu nhiên đều trả về đúng 404.
Niels Keurentjes

5
ít nhất trên hệ thống của tôi, đó là FallbackResource /index.php(lưu ý dấu gạch chéo hàng đầu)
Jack James

4
@olli: nhận xét thực tiễn xấu đề cập cụ thể đến việc "không trả lại 404 cho các URL không tồn tại", được giải quyết bằng chính giải pháp trong câu trả lời. Đối với câu hỏi đầu tiên - FallbackResourcechỉ khởi động cho các tệp không thực sự tồn tại trên hệ thống tệp, do đó dự phòng . Vì vậy, nếu bạn có một tệp /static/styles.cssvà tham chiếu đến nó vì http://mydomain.tld/static/styles.cssmã không bao giờ được thực thi, làm cho nó hoạt động như mong đợi và dự định trong suốt.
Niels Keurentjes

if($elements[0] === NULL)thay vào đó, bạn nên sử dụng , vì $elementsvẫn sẽ trả về số lượng một, ngay cả khi nó trống.
gian lửa

57

Nếu bạn chỉ muốn thay đổi tuyến đường picture.phpthì sau đó thêm quy tắc viết lại .htaccesssẽ phục vụ nhu cầu của bạn, nhưng, nếu bạn muốn URL viết lại như trong Wordpress thì PHP là cách. Đây là ví dụ đơn giản để bắt đầu.

Cấu trúc thư mục

Có hai tệp cần thiết trong thư mục gốc, .htaccessindex.php, sẽ rất tốt nếu đặt phần còn lại của các .phptệp vào thư mục riêng, như inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

Tập tin này có bốn chỉ thị:

  1. RewriteEngine - kích hoạt công cụ viết lại
  2. RewriteRule- từ chối quyền truy cập vào tất cả các tệp trong inc/thư mục, chuyển hướng bất kỳ cuộc gọi nào đến thư mục đó đếnindex.php
  3. RewriteCond - cho phép truy cập trực tiếp vào tất cả các tệp khác (như hình ảnh, css hoặc tập lệnh)
  4. RewriteRule - chuyển hướng bất cứ điều gì khác để index.php

index.php

Bởi vì mọi thứ bây giờ được chuyển hướng đến index.php, sẽ được xác định nếu url là chính xác, tất cả các tham số đều có mặt và nếu loại tham số là chính xác.

Để kiểm tra url chúng ta cần có một bộ quy tắc và công cụ tốt nhất cho đó là biểu thức chính quy. Bằng cách sử dụng các biểu thức thông thường, chúng ta sẽ giết hai con ruồi bằng một đòn. Url, để vượt qua bài kiểm tra này phải có tất cả các tham số bắt buộc được kiểm tra trên các ký tự được phép. Dưới đây là một số ví dụ về các quy tắc.

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

Tiếp theo là chuẩn bị uri yêu cầu.

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

Bây giờ chúng ta có uri yêu cầu, bước cuối cùng là kiểm tra uri theo các quy tắc biểu thức chính quy.

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

Kết hợp thành công sẽ, vì chúng ta sử dụng các mô hình con có tên trong regex, điền vào $paramsmảng gần giống như PHP điền vào $_GETmảng. Tuy nhiên, khi sử dụng url động, $_GETmảng được điền mà không có bất kỳ kiểm tra nào về tham số.

    / hình ảnh / một số + văn bản / 51

    Mảng
    (
        [0] => / hình ảnh / một số văn bản / 51
        [văn bản] => một số văn bản
        [1] => một số văn bản
        [id] => 51
        [2] => 51
    )

    ảnh.php? text = some + text & id = 51

    Mảng
    (
        [văn bản] => một số văn bản
        [id] => 51
    )

Một vài dòng mã và hiểu biết cơ bản về các biểu thức chính quy là đủ để bắt đầu xây dựng một hệ thống định tuyến vững chắc.

Nguồn hoàn chỉnh

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
Làm thế nào để bạn đọc các thông số? Nó không hoạt động với $ post_id = htmlentities ($ _ GET ['post']);
andrebruton

@Danijel Tôi có thể có một mã nguồn hoàn chỉnh không? Tôi đã thử mã ở trên nhưng chỉ có văn bản là đầu ra, CSS không có hiệu lực. Cảm ơn bạn.
4 Để lại

6

đây là tệp .htaccess chuyển tiếp gần như tất cả sang 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

sau đó tùy thuộc vào bạn phân tích $ _SERVER ["REQUEST_URI"] và định tuyến tới tệp.php hoặc bất cứ điều gì


8
Apache đã giới thiệu FallbackResourcechỉ thị một vài phiên bản chính trước đây, hiện là cách ưa thích để thực hiện hành vi này với chi phí hiệu năng thấp hơn vì không cần phải khởi chạy toàn bộ công cụ viết lại. Tài liệu ở đây . Các quy tắc của bạn cũng rất thiếu sót vì bạn không tham chiếu các thư mục ( !-d) và tất cả các bộ lọc tiện ích mở rộng đã lỗi thời - -fnên đã bắt chúng.
Niels Keurentjes

5

PHP không phải là những gì bạn đang tìm kiếm, hãy xem mod_rewrite


nó sẽ ảnh hưởng đến tất cả các url?
Jazerix

@Jazerix Điều này phụ thuộc vào các quy tắc bạn xác định.
nietonfir

2

Mặc dù đã được trả lời và ý định của tác giả là tạo ra một ứng dụng loại bộ điều khiển phía trước nhưng tôi đang đăng quy tắc nghĩa đen cho vấn đề được hỏi. nếu ai đó có vấn đề cho cùng.

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

Ở trên nên làm việc cho url picture.php/Some-text-goes-here/51. mà không sử dụng index.php như một ứng dụng chuyển hướng.


Tôi cần biết URL nào chúng ta phải viết trong href? bởi vì tôi đang nhận được 404
questionbank
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.