Uri dan php yönlendirici, ayıklanması tuşları

4 Cevap php

Hey millet! Ben düzenli ifadeler / etc ile biraz yardıma ihtiyacım var. Ben, url den uygulamada yönlendirici çeşit sanal tuşları ayıklamak gerekir. İşte params şunlardır:

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

Çıktı böyle bir şey olmalı:

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

Peki, soru şu: ben bu php nasıl yapabilirim?

Kurallar P.S. kombinasyonları değişebilir. ':' Sembolü Yani, ana tuşları ile kelimelerdir. Bu gibi, örneğin:

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

P.S. 2: Bu i daha önce vardı bir kod parçasıdır. Bu çalışma, fakat esnek değildir.

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]);
    	}	
    }

Aslında yönlendirici bu sürüm benim için yeterli olabilir, ancak esnek bir çözüm sadece nasıl ilgi im olabilir. Bu arada, bazı testler: (10000 işlemlerin 30 kez):

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

Yeterince Yani, onun hızlı. Düzenli bir laptop im test. Yani, emin - bu bir gerçek web sitesinde kullanılabilir.

Başka bir çözüm?

4 Cevap

Bu sadece tek bir düzenli ifade ile mümkün olduğunu sanmıyorum. Zend Framework sadece örnek gibi çalışır. Onların source code bakabilirsiniz.

Bu basit çözüm deneyin:

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

Sadece olumsuz, bu noktada fancy veri doğrulama olamaz, bu yüzden başka bir yerde bunu yapmak zorunda olduğunu. Regex sözdizimi ile kuralları çatışma (burada bazı ağır öncelemeli işi yapmak zorundayız) Ayrıca eğer dağınık alabilir.

Ben her eleman için bazı desenler tanımlayarak başlamak istiyorum

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

Sonra bir regex kurmak

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

Eğer geri $ harita dizisindeki eleman isimleri ile uygun olmalıdır olsun hedef verilere ki desen ve maç dizi kullanabilirsiniz - örneğin adı $ maç [1] $ haritası [1] vs olduğunu

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


}