处理RESTful url的PHP

时间:2012-12-01 00:08:16

标签: php url rest mod-rewrite query-string

我无法掌握处理RESTful网址的最佳方式。

我的网址是这样的:

http://localhost/products 
http://localhost/products/123
http://localhost/products/123/color 

原来:

http://localhost/index.php?handler=products&productID=123&additional=color

至于现在我正在使用mod_rewrite:

RewriteRule ^([^/]*)([/])?([^/]*)?([/])?(.*)$ /index.php?handler=$1&productID=$3&additional=$5 [L,QSA]

然后我把index.php中的请求拼凑起来,比如:

if ($_GET['handler'] == 'products' && isset($_GET['productID'])) {
   // get product by its id.
}

我见过有人将GET查询创建为一个字符串,如:

if ($_GET['handler'] == 'products/123/color')

然后,您是否使用正则表达式从查询字符串中获取值?

这是处理这些网址的更好方法吗? 这些不同方法的优缺点是什么? 还有更好的方法吗?

2 个答案:

答案 0 :(得分:6)

您可以使用不同的方法而不是匹配所有参数使用apache重写您可以使用preg_match匹配PHP中的完整请求路径。 应用PHP正则表达式,所有参数都将移动到$args数组中。

$request_uri = @parse_url($_SERVER['REQUEST_URI']);
$path = $request_uri['path'];
$selectors = array(
     "@^/products/(?P<productId>[^/]+)|/?$@" => 
            (array( "GET" => "getProductById", "DELETE" => "deleteProductById" ))
);

foreach ($selectors as $regex => $funcs) {
    if (preg_match($regex, $path, $args)) {
        $method = $_SERVER['REQUEST_METHOD'];
        if (isset($funcs[$method])) {
            // here the request is handled and the correct method called. 
            echo "calling ".$funcs[$method]." for ".print_r($args);
            $output = $funcs[$method]($args);
            // handling the output...
        }
        break;
     }
}

这种方法有很多好处:

  • 您正在开发的每个REST服务都没有重写。我喜欢重写,但在这种情况下你需要很多自由,并且使用重写时,每次部署/保留新服务时都需要更改Apache配置。
  • 您可以为所有传入请求设置一个PHP前端类。前端将所有请求分派给正确的控制器。
  • 您可以迭代地将正则表达式数组应用于传入请求,然后根据成功匹配调用正确的函数或类控制器/方法
  • 当最终控制器被实例化以处理请求时,在这里你可以检查用于http请求的HTTP方法

答案 1 :(得分:4)

此.htaccess条目会将除现有文件之外的所有内容发送到index.php:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php

然后你可以做这样的事情将url转换成数组:

$url_array = explode('/', $_SERVER['REQUEST_URI']);
array_shift($url_array); // remove first value as it's empty
array_pop($url_array); // remove last value as it's empty

然后你可以使用开关:

switch ($url_array[0]) {

    case 'products' :
        // further products switch on url_array[1] if applicable
        break;

    case 'foo' :
        // whatever
        break;

    default :
        // home/login/etc
        break;

}

这就是我一般所做的事情。