2015-06-03 232 views
2

我正在为我的PHP MVC应用程序编写一个路由器,而且我目前需要找到一种方法来将路由中的匹配用作控制器和操作的变量。从另一个字符串中的一个字符串替换匹配项

举例来说,如果我有以下途径:/users/qub1/home

我想用正则表达式与此类似:\/users\/(?!/).*\/(?!/).*

然后我想说明这样的动作:$2(在例如,这将是家)

而参数传递到这样的动作:$1(在这个例子中,这将是qub1)。

这将随后执行类似的代码这样:

$controller = new UsersController(); 
$controller->$2($1); 

配置的路由被存储为,例如:

public function setRoute($route, $regex = false, $controller = 'Index', $action = 'index', $parameters = array()) { 
     if(!$regex) { 
      $route = preg_quote($route, '/'); 
     } 

     $this->routes[] = [ 
       'route' => $route, 
       'controller' => $controller, 
       'action' => $action, 
       'parameters' => $parameters 
     ]; 
    } 

当上面的例子将被存储这样的:$router->setRoute('\/users\/(?!/).*\/(?!/).*', true, 'User', '$2', [$1]);

所以基本上,我想用一个正则表达式中的匹配组作为变量来替换另一个正则表达式(如果有意义的话)。

我希望我已经足够准确地描述了我的问题。谢谢您的帮助。

编辑:

我目前使用解析路径(这是行不通的,但它应该说明我想要实现)代码:

public function executeRoute($route) { 
     // Loop over available routes 
     foreach($this->routes as $currentRoute) { 
      // Check if the current route matches the provided route 
      if(preg_match('/^' . $currentRoute['route'] . '$/', '/' . $route, $matches)) { 
       // If it matches, perform the current route's action 
       // Define names 
       $controllerClass = preg_replace('\$.*\d', $matches[str_replace('$', '', '$1')], ucfirst($currentRoute['controller'] . 'Controller')); 
       $actionMethod = preg_replace('\$.*\d', $matches[str_replace('$', '', '$1')], strtolower($currentRoute['action']) . 'Action'); 
       $parameters = preg_replace('\$.*\d', $matches[str_replace('$', '', '$1')], join(', ', $currentRoute['parameters'])); 

       // Create the controller 
       $controller = new $controllerClass(); 
       $controller->$actionMethod($parameters); 

       // Return 
       return; 
      } 
     } 
} 
+1

嗨,你可以尝试strstr();在PHP http://php.net/strstr –

+0

路由的目的是为了隐藏内部的实现,所以很容易添加新的路由。你认真做它更复杂,它需要是 – Yang

+0

@KarthikKeyan我已经使用strtr,它的工作原理。我首先必须将匹配数组转换为关联数组(将索引预置为'$'),然后将其用作针参数。我现在可以使用如下方式轻松设置路由:'$ router-> setRoute('\/users \ /([^ \ /] *)',true,'Users','index',['$ 1'] );''会在幕后执行这样的事情:'UsersController-> indexAction($ 1)',其中$ 1将是用户名。 – Qub1

回答

0

虽然我不确定这是一个设计得很好的方法,它是可行的。这是替换if内你的代码:

// you already specify the controller name, so no need for replacing 
$controllerClass = ucfirst($currentRoute['controller'] . 'Controller'); 

// also here, no need to replace. You just need to get the right element from the array 
$actionMethod = strtolower($matches[ltrim($currentRoute['action'], '$')] . 'Action'; 

// here I make the assumption that this parameter is an array. You might want to add a check here 
$parameters = array(); 
foreach ($currentRoute['parameters'] as $parameter) { 
    $parameters[] = $matches[ltrim($parameter, '$')]; 
} 

// check before instantiating 
if (!class_exists($controllerClass)) { 
    die('invalid controller'); 
} 
$controller = new $controllerClass(); 

// also check before invoking the method 
if (!method_exists($controller, $actionMethod)) { 
    die('invalid method'); 
} 
// this PHP function allows to call the function with a variable number of parameters 
call_user_func_array(array($controller, $actionMethod), $parameters); 

原因之一,你的做法是不是很有利的是,你做了很多假设:

  • 正则表达式需要有尽可能多的群体如您在其他参数使用
  • 如果你是不精确与正则表达式,有可能调用任何方法在你的代码

也许该W对于你的项目来说生病够好,但是如果你想创造一些不适合教育目的的东西,你应该考虑使用一个完善的路由器。

+0

感谢您的代码,它有帮助!是的,这主要是作为一种学习体验(为了更熟悉MVC模式),所以我不会在实际网站上使用它。至于你说用户能够调用任何方法,一旦应用正则表达式,字符串总是附加'Action',因此它们只能调用任何以action结尾的方法,这些方法都是它们应该是的方法无论如何都能访问。还是我忽略了那里的某些东西? – Qub1

+0

它应该很好,但我总是犹豫是否要将用户提供的字符串付诸行动。你永远无法猜测攻击者可能弄清楚什么。 – akirk

相关问题