2009-07-02 36 views
6

Xin chào mọi người! Tôi cần một số trợ giúp với cụm từ thông dụng/v.v. Tôi cần trích xuất các khóa ảo từ url, một số loại router trong ứng dụng. Sau đây là các params:Bộ định tuyến Php, trích xuất các khóa từ uri

Rule: /books/:category/:id/:keyname 
Data: /books/php/12345/this-is-a-test-keyname 

Output nên một cái gì đó như thế:

array(
    'category' => 'php', 
    'id' => '12345', 
    'keyname' => 'this-is-a-test-keyname' 
); 

Vì vậy, câu hỏi là: làm thế nào tôi có thể làm điều này trong php?

P.S Kết hợp các quy tắc có thể khác nhau. Vì vậy, các phím chính là các từ có ký hiệu ':'. ví dụ như thế này:

/book-:id/:category/:keyname 
/book/:id_:category~:keyname 

P.S. 2: Đây là một đoạn mã tôi đã có trước đây. Nó hoạt động nhưng không linh hoạt.

function rule_process($rule, $data) { 
     // extract chunks  
     $ruleItems = explode('/',$rule); 
     $dataItems = explode('/',$data); 

     // remove empty items 
     array_clean(&$ruleItems); 
     array_clean(&$dataItems); 

     // rule and data supposed to have the same structure 
     if (count($ruleItems) == count($dataItems)) { 
      $result = array(); 

      foreach($ruleItems as $ruleKey => $ruleValue) { 
       // check if the chunk is a key 
       if (preg_match('/^:[\w]{1,}$/',$ruleValue)) { 
        // ok, found key, adding data to result 
        $ruleValue = substr($ruleValue,1); 
        $result[$ruleValue] = $dataItems[$ruleKey]; 
       } 
      } 

      if (count($result) > 0) return $result; 
      unset($result); 
     } 

     return false; 
    } 

    function array_clean($array) { 
     foreach($array as $key => $value) { 
      if (strlen($value) == 0) unset($array[$key]); 
     } 
    } 

Trên thực tế, phiên bản này có thể đủ cho tôi, nhưng tôi chỉ quan tâm đến cách tạo giải pháp linh hoạt. Nhân tiện, một số thử nghiệm: (30 lần trong số 10000 hoạt động):

TEST #0 => Time:0.689285993576, Failures: 0 
TEST #1 => Time:0.684408903122, Failures: 0 
TEST #2 => Time:0.683394908905, Failures: 0 
TEST #3 => Time:0.68522810936, Failures: 0 
TEST #4 => Time:0.681587934494, Failures: 0 
TEST #5 => Time:0.681943893433, Failures: 0 
TEST #6 => Time:0.683794975281, Failures: 0 
TEST #7 => Time:0.683885097504, Failures: 0 
TEST #8 => Time:0.684013843536, Failures: 0 
TEST #9 => Time:0.684071063995, Failures: 0 
TEST #10 => Time:0.685361146927, Failures: 0 
TEST #11 => Time:0.68728518486, Failures: 0 
TEST #12 => Time:0.688632011414, Failures: 0 
TEST #13 => Time:0.688556909561, Failures: 0 
TEST #14 => Time:0.688539981842, Failures: 0 
TEST #15 => Time:0.689876079559, Failures: 0 
TEST #16 => Time:0.689854860306, Failures: 0 
TEST #17 => Time:0.68727684021, Failures: 0 
TEST #18 => Time:0.686210155487, Failures: 0 
TEST #19 => Time:0.687953948975, Failures: 0 
TEST #20 => Time:0.687957048416, Failures: 0 
TEST #21 => Time:0.686664819717, Failures: 0 
TEST #22 => Time:0.686244010925, Failures: 0 
TEST #23 => Time:0.686643123627, Failures: 0 
TEST #24 => Time:0.685017108917, Failures: 0 
TEST #25 => Time:0.686363935471, Failures: 0 
TEST #26 => Time:0.687278985977, Failures: 0 
TEST #27 => Time:0.688650846481, Failures: 0 
TEST #28 => Time:0.688835144043, Failures: 0 
TEST #29 => Time:0.68886089325, Failures: 0 

Vì vậy, nó đủ nhanh. Im thử nghiệm trên máy tính xách tay thông thường. Vì vậy, chắc chắn - điều này có thể được sử dụng trong trang web thực sự.

Bất kỳ giải pháp nào khác?

+0

nhu cầu sử dụng preg_split –

Trả lời

1

Tôi không nghĩ điều này là có thể chỉ với một cụm từ thông dụng. Zend Framework hoạt động giống như ví dụ của bạn. Hãy xem source code của họ.

+0

yeah, tôi thấy các tuyến đường như vậy trong đường ray –

0

tôi sẽ bắt đầu bằng cách xác định một số mẫu cho mỗi phần tử

$element=array(
    'id'=>'(\d+)', 
    'category'=>'([^/]+)' 
); 

Sau đó xây dựng một regex

$rule="/book-:id/:category/:keyname"; 

$pattern=preg_quote($rule); 
$map=array(); 
$map[]=null; 

function initrule($matches) 
{ 
    //forgive the globals - quickest way to demonstrate this, in 
    //production code I'd wrap this into a class... 
    global $element; 
    global $map; 

    //remember the order we did these replacements 
    $map[]=$matches[1]; 

    //return the desired pattern 
    return $element[$matches[1]]; 
} 

$pattern=preg_replace_callback('/:(\w+)/', "initrule", $pattern); 

Lưu ý bạn có thể sử dụng mô hình đó trên dữ liệu mục tiêu của bạn, và hàng loạt các trận đấu bạn lấy lại tương ứng với tên phần tử trong mảng bản đồ $ - ví dụ Tên $ trùng khớp [1] là trong $ bản đồ [1], vv

+0

nhưng những gì nếu tôi có 20-30 quy tắc khác nhau? vấn đề là - tôi không thể đưa ra giải pháp phổ quát. –

+0

bạn sẽ phải xây dựng một mẫu cho mỗi quy tắc và kiểm tra chúng theo thứ tự. Nếu không, tôi không nghĩ rằng bạn sẽ có một cách dễ dàng để tìm ra những gì mỗi trận đấu bị bắt tương ứng với. –

1

Hãy thử giải pháp đơn giản này:

$data = Array (
      "/book/:id/:category/:keyname" => "/book/12345/php/this-is-a-test-keyname", 
      "/book-:id/:category/:keyname" => "/book-12345/php/this-is-a-test-keyname", 
      "/book/:id_:category~:keyname" => "/book/12345_php~this-is-a-test-keyname", 
    ); 


    foreach ($data as $rule => $uri) { 
      $reRule = preg_replace('/:([a-z]+)/', '(?P<\1>[^/]+)', $rule); 
      $reRule = str_replace('/', '\/', $reRule); 

      preg_match('/' . $reRule .'/', $uri, $matches); 
      print_r($matches); 
    } 

Nhược điểm duy nhất là, bạn không thể có xác nhận ưa thích dữ liệu vào thời điểm này, vì vậy bạn phải làm điều đó ở nơi khác. Ngoài ra, nó có thể lộn xộn nếu các quy tắc xung đột với cú pháp regex (bạn phải thực hiện một số công việc thoát hiểm ở đây).

+0

ít nhất một cái gì đó để chơi với, cảm ơn. btw, tôi đăng mã hiện tại của tôi, nó không linh hoạt (chỉ có 1 loại dấu phân tách). –

0
$Url = preg_replace("/^(.*)\\/\\/\/|(.*)\\/*.php\//i", "", $_SERVER['REQUEST_URI']); 
$Url = str_replace("index.php", "", $Url); 
$data = array(); 

$data["/ttt/:xyz/:id"] =(object) Array ( "default" => array("controller"=>"default","action"=>"detail"), 
                "rule"  => array("xyz"=>"([a-zA-Z0-9_\+\-%]+)","id"=>"([0-9]+)")); 
$data["/xid-:id"] =(object) Array ( "default" => array("controller"=>"default","action"=>"categori"), 
            "rule"  => array("id"=>"([a-z]+)")); 

function parsePath($match) 
{ 
    global $data; 
    foreach($data as $router) 
    { 
     foreach($router->rule as $key=>$value) 
     { 
      if($match[1] == $key){ 
       $str ='(?P<'.$match[1].'>'.$value.')'; 
      } else { 
       $str = '(?P<'.$match[1].'>[^/]+)'; 
      } 
     } 
    } 

    return $str; 

} 

foreach($data as $path => $router) 
{ 
    $o=preg_replace_callback('/:([a-z]+)/',"parsePath", $path); 
} 

$regex = str_replace('/', '\/',$o); 
$regex ='/^' . $regex . '$/'; 

preg_match($regex, $Url, $matches); 
$map = array(); 

foreach($matches as $key => $value) 
{ 
    foreach($data as $route) 
    { 
     if(array_key_exists($key,$route->rule)){ 
      $map['controller'] = $route->default['controller']; 
      $map['action']= $route->default['action']; 
      $map[$key] = $value; 
     } 
    } 
} 
+0

Đó là rất nhiều mã mà không có bất kỳ lời giải thích hoặc ý kiến.Bạn có thể vui lòng thêm một số lời giải thích? –

Các vấn đề liên quan