2009-12-08 39 views
15

Tôi đang tranh luận việc định tuyến các yêu cầu của tôi với một trong hai lựa chọn:Mod-Rewrite hoặc PHP router?

Lựa chọn 1: đường chụp đơn giản với Mod-Rewrite và phễu viết $_GET đường đến index.php để tải ...

#default routing 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^blog/([0-9]+)?$ index.php?rt=blog&params=$1 [L,QSA] 
// ..more custom routes, and then a default route 
RewriteRule ^([A-Za-z]+)/([A-Za-z]+)/(.*)?$ index.php?rt=$1/$2&params=$3 [L,QSA] 

Tùy chọn 2: chỉ cần định tuyến các yêu cầu tới Front Controller và tạo một lớp định tuyến PHP để xử lý định tuyến ...

#default routing 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^(.*)$ index.php?rt=$1 [L,QSA] 

/* --- on front controller, process $_GET['rt'] --- */ 

vào cuối ngày, sẽ chạy nhanh hơn, dễ bảo mật hơn và dễ dàng hơn để duy trì?

bất kỳ ý tưởng nào khác?

LƯU Ý: Tôi không chạy một khuôn khổ đã biết. Tôi đang xây dựng mẫu MVC của riêng mình để tìm hiểu nó.

+0

những gì bạn có nghĩa là bởi an toàn? –

+0

tốt, tôi reall chỉ giả định có những biện pháp để thực hiện để đảm bảo hệ thống của tôi/khung/etc không có bất kỳ lỗ mà tôi không biết. chỉ giả định im ngây thơ hơn tôi hy vọng – johnnietheblack

+0

Tôi hoan nghênh những nỗ lực của bạn. –

Trả lời

16

Thông thường trong khung MVC, loại điều này thường được xử lý tốt nhất bởi bộ điều khiển mặt trước (có tên là index.php hoặc loại tương tự). Bạn sử dụng mod_rewrite để ẩn index.php từ tất cả các URL để người dùng của bạn thấy đường dẫn sạch đẹp.

Đó cũng là cách dễ dàng hơn để xử lý bằng PHP so với chỉ thị viết lại của Apache. PHP linh hoạt hơn và dễ viết/dễ hiểu hơn. Tôi không chắc tôi đã từng thấy mod_rewrite được sử dụng như là công cụ định tuyến duy nhất cho bất kỳ khuôn khổ web nào trên mạng, bây giờ tôi nghĩ về nó.

Mã lệnh thứ hai của bạn là cách để thực hiện các chỉ thị viết lại của bạn.

+1

Chắc chắn đồng ý. Ngoài ra, nhiều quy tắc để thực hiện cùng một nhiệm vụ cơ bản sẽ khó quản lý và hiểu sau một thời gian. Nếu bạn nhìn vào bất kỳ khung công tác php chính nào (có thể không phải bất kỳ tôi chỉ sử dụng Symfony và Zend, hehe), chúng chỉ sử dụng viết lại để lấy "url đẹp" cho bộ điều khiển, sau đó chúng thực hiện định tuyến nội bộ trong một lớp định tuyến của somesort giải mã các tham số thực tế dựa trên tất cả các loại quy tắc phức tạp. Id theo cách tiếp cận này nếu tôi là bạn. – prodigitalson

+4

Tôi đồng ý. Các trang web tôi đã làm việc với hơn 30 tuyến đường viết lại tùy chỉnh luôn là một nỗi đau. PS - thêm một số định tuyến để cho phép máy chủ web xử lý hình ảnh, js và css. Xem ví dụ về khung công tác zend htaccess - http://framework.zend.com/wiki/display/ZFDEV/Configuring+Your+URL+Rewriter – mozillalives

+0

@MarcW Tôi thích câu trả lời của bạn. Có lẽ bạn có thể lấy 300 điểm bằng cách đưa ra câu hỏi của tôi, trường đại học cũ tốt thử? http://stackoverflow.com/questions/42172228/is-this-how-an-mvc-router-class-typically-works –

0

Tôi cũng đang trong quá trình xây dựng hệ thống LAMP MVC từ đầu.

MVC Router Class Question

Performance

Sau khi tạo ra một kịch bản bash shell để biên dịch Apache 2.4.x từ nguồn, bạn nhận thấy rằng một Perl Tương thích thư viện Regular Expression được nướng vào quá trình này. Bất cứ lúc nào mã biểu thức chính quy phải được sử dụng, phản hồi của máy chủ http sẽ chậm hơn. Do đó, tùy chọn số một là không đi nếu hiệu suất là mối quan tâm của bạn. Có một chi phí cho các phân tích có liên quan với các biểu thức thông thường. Máy chủ web Apache đang mượn logic cho các cụm từ thông dụng. Nó không phải là Apaches home grown code.

an

Security là một vấn đề khác nhau. Thứ nhất, không có gì về việc viết lại các URL làm cho chúng an toàn. Nó là bảo mật đơn giản thông qua sự tối tăm và làm cho mọi thứ trông khá đẹp ở phía khách hàng. Theo thời gian, các lỗ hổng bảo mật được tìm thấy trong mã công cụ biểu thức chính quy. Do đó, về mặt bảo mật thực sự, bạn có thể ở trong cùng một vị trí cơ bản mà bạn không cần phải viết lại: con người hoặc bot, có thể gửi nội dung xấu đến máy chủ của bạn và bạn cần một cách để lọc và xác thực đầu vào theo cách có hệ thống. Hãy chắc chắn để lọc và xác nhận tất cả các đầu vào, đặc biệt là bất kỳ phần nào của chuỗi truy vấn được viết lại mà bạn định sử dụng.

Do đó, tùy chọn số một trình bày giao diện gọn gàng hơn (INPUT_GET/$_GET) để bắt đầu nhiệm vụ bảo mật của bạn. Tùy chọn số hai yêu cầu (nếu bạn đang cố gắng để được triệt để) bạn để lọc và xác nhận toàn bộ chuỗi như là một bước đầu tiên. Bước thứ hai (nói chung) sẽ là chia nhỏ và trích xuất những gì bạn mong muốn thu thập từ chuỗi lớn hơn.

Một lần nữa, bạn nên lọc và xác thực từng phần của chuỗi. Do đó, trong khi có lẽ nó dễ quản lý hơn (dễ dàng hơn, thuận tiện) để lọc/xác nhận/chia nhỏ/trích xuất/chuỗi lớn hơn trong PHP (nói, với một phương thức trong lớp bảo mật nào đó), bạn vẫn cần phải làm việc cho từng phần , cho mọi yêu cầu. Tùy chọn số một giúp bạn tiết kiệm những rắc rối của việc phải phá vỡ chuỗi lớn hơn cho chi phí thực hiện các công cụ regex trên mọi yêu cầu. Tuy nhiên, đối với hầu hết các phần, bạn chỉ có thể bắt đầu lọc và xác thực các yếu tố bạn mong muốn nhận được trong INPUT_GET hoặc $_GET. Tuy nhiên, một tùy chọn là chủ yếu dành cho những người thực sự hiểu cách biểu thức chính quy hoạt động và cách thức áp dụng điều này cho các URL tiềm năng mà máy chủ của bạn có thể nhận được. Nếu bạn cần nhiều hơn một RewriteRule, nó có thể là để bạn có thể có một cái gì đó như thế này (hoặc các lý do khác) đi vào máy chủ.

index.php?0=model 

index.php?0=model&1=method 

index.php?0=model&1=method&2=methodArgs 

Điều này giúp dễ dàng lọc và xác thực đầu vào của bạn hơn. Tuy nhiên, lưu ý rằng dòng cuối cùng ngụ ý rằng bạn vẫn có thể cần phải tách một số dòng và lọc/xác nhận thêm (nhưng điều đó có thể không xảy ra đối với mọi yêu cầu, như trong tùy chọn số 1).

Mã mẫu: Bắt tham số URL sử dụng Lựa chọn 2 (bắt đầu ở phía dưới!)

Note: Đây chỉ là một số điều cần lưu ý, không phải "là" cách để làm điều đó.

const QS_ARRAY_LIMIT = 3; 

private function getPairValue($delimiter, $string) 
{ 
    return explode('$delimiter', $string)[1]; //Get the value for a pair. 
} 

private function isMultiValuedQueryString() 
{ 
    return (mb_strpos($this->queryStr, '&', 0, 'UTF-8') > 2); 
} 

private function getAllowedPairs($argsStr) 
{ 
    $pairs = explode('&', $argsStr); 
    $numPairs = count($pairs); 

    if($numPairs > self::QS_ARRAY_LIMIT) 
    { 
     throw new SecurityException("Too many query string pairs ({$numPairs}) submitted to the router.\n"); 
    } 

    return $pairs; 
} 

private function isQueryStrPair($pair) 
{ 
    $equalPos = null; 
    $pairLength = mb_strlen($pair, 'UTF-8'); 

    if($pairLength < 3) 
    { 
     throw new SecurityException("Query string pair is too short: Length: {$pairLength}!, Suspect: {$pair}\n"); //Sends to '/' 
    } 

    $equalPos = mb_strpos($pair, '=', 0, 'UTF-8'); 

    if($equalPos === 0) //The first position. 
    { 
     throw new SecurityException("Query sting pair cannot *start* with an equal sign (=): Suspect: {$pair}\n"); //Sends to '/' 
    } 

    if($equalPos === ($pairLength - 1)) //The last position. 
    { 
     throw new SecurityException("Query sting pair cannot *end* with an equal sign (=): Suspect: {$pair}\n"); //Sends to '/' 
    } 

    return true; 
} 

private function getQueryStringArgs($url) 
{ 
    $delimiter = '?'; 

    if(mb_strpos($url, $delimiter, 0, 'UTF-8') > 0) 
    { 
     return $this->getPairValue($delimiter, $url); 
    } 

    throw new RuntimeException("Malformed URL passed to query string parser."); 
} 

private function associateArgPairs(array $argPairs, array $values) 
{ 
    $i = 0; 

    foreach($argPairs as $key => &value) 
    { 
     if(isset($values[$i])) 
     { 
      $value[$key] = $values[$i]; 
      ++$i; 
     } 
    } 

    return $argPairs; 
} 

private function getQueryStrValues($url) 
{ 
    $delimiter = '='; 
    $argPairs = ['model' => null, 'method' => null, 'methodArgs' => null] 
    $inputValues = []; 
    // ================================================= 
    // Valid query strings might look like (amongst many combinations): 
    // 
    // index.php?arg1=foo&agr2=bar&arg3=/baz/bang/boom 
    // 
    // Or, just one pair with no ampersand,'&'. 
    // 
    // index.php?arg1=foo 
    // ================================================== 

    // Get everything after the question mark, '?'. 
    $queryStringArgsStr = $this->getQueryStringArgs($url); 

    if($this->isMultiValuedQueryString($queryStringArgsStr)) //Check if '&' exists. 
    { 
     foreach($this->getAllowedPairs($queryStringArgsStr) as $pair) 
     { 
      if($this->isQueryStrPair($pair)) 
      { 
       //Get the value for each pair., using '=' as the string delimiter. 
       $inputValues[] = $this->getPairValue($delimiter, $pair); 
      } 
     } 
    } 
    else 
    {  
     if($this->isQueryStrPair($queryStringArgsStr)) 
     { 
      $inputValues[] = $this->getPairValue($delimiter, $queryStringArgsStr); //Get the value for each pair. 
     } 
    } 

    return $this->associateArgPairs($argPairs, $inputValues); 

    //Remember, you will still need to split up $argPairs[$methodArgs] if necessary. 
    //With option #1, you could start closer to this point, 
    //and hence filter and validate sooner. 
} 

Tóm tắt

Nếu bảo mật là mối quan tâm chính của bạn (có nghĩa là, giao diện của bạn vào chương trình bảo mật của bạn), nhẫn nhục chịu đựng và sử dụng tùy chọn số một. Học mod_rewrite và viết lại URL khiến bạn khá mạnh mẽ. Tại sao để lại sức mạnh trên bàn? Apache là một động vật kỳ lạ khi nói đến cấu hình nó. Nhưng, nếu bạn hiểu các URL và cụm từ thông dụng, tôi nói người đàn ông/người phụ nữ và đi cho nó. :-) Nếu tốc độ, hiểu và dễ sử dụng là mối quan tâm chính của bạn, hãy chọn tùy chọn số một. Có những người nhiệt thành muốn mọi thứ được mã hóa bằng PHP, nhưng bạn phải tự mình đánh giá những ưu và nhược điểm của cả hai tình huống.

Cập nhật: Rất tiếc. Mã này sẽ thực sự làm việc tốt hơn cho số tùy chọn 1. Trong tùy chọn số 2, 1 = blah, nơi blah sẽ là một cái gì đó như /trt/43ff/3335/f/3/fr3r/ hoặc bất cứ điều gì. Bạn sẽ không phải tìm ký hiệu và.

PHP: filter_inpur_array(), (use INPUT_GET)

PHP: Superglobals

PHP: explode()

PHP: foreach (array_expression as $key => $value)

PHP: Multibtye String Functions