I'm having trouble grasping what would be the most proper way of handling RESTful url's.
I'm having url's like these:
http://localhost/products
http://localhost/products/123
http://localhost/products/123/color
Originally:
http://localhost/index.php?handler=products&productID=123&additional=color
As for now I'm using mod_rewrite:
RewriteRule ^([^/]*)([/])?([^/]*)?([/])?(.*)$ /index.php?handler=$1&productID=$3&additional=$5 [L,QSA]
And then I'm puzzling together the requests in index.php, something like:
if ($_GET['handler'] == 'products' && isset($_GET['productID'])) {
// get product by its id.
}
I've seen some creating a GET-query as one string like:
if ($_GET['handler'] == 'products/123/color')
Then, do you for example use regular expressions to get the values out of the query-string?
Is this a better approach to handle these url's? What are the pros and cons with these different approaches? Is there some better way?
You could use a different approach instead of match all parameters using apache rewrites you could match the full request path in PHP using preg_match. Applying the PHP regular expression all the parameters will be moved into the $args
array.
$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;
}
}
This approach has many benefits:
This .htaccess entry will send everything except existing files to index.php:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
Then you can do something like this to convert the url into an array:
$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
Then you can use a switch thusly:
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;
}
That's what I generally do anyway.