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?
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.
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:
You don't have a rewrite for each REST service you're developing. I like rewrites, but in this case you need a lot of freedom, and using rewrites you need to change Apache config every time you deploy/mantain a new service.
You can have a single PHP frontend class for all incoming requests. The frontend dispatch all the requests to the correct controller.
You can apply iteratively an array of regular expression to the incoming requests and then call the correct function or class controller/method accordingly to the successful match
When finally the controller is instantiated to handle the request, here you can check the HTTP method used into http request
Related
I'd like to write a proper .htaccess rule and PHP code to parse url like this one : https://myapi.com/1.1/users/search.json?q=abc&page=1&count=3
Here's what I found so far:
RewriteRule ^([a-zA-Z_-])\.(xml|json)$ index.php?url=$1&format=$2
And my PHP code looks like
$requestParts = explode('/', $_GET['url']);
$contentType = $_GET['type'];
//$params = ... //Here's where I'm lost
How can I get the optional part with the RewriteRule and PHP code ?
My suggestion would be to use a very simple rewrite to a front controller (like index.php) and then use code in that file to evaluate the requested route.
RewriteRule ^index\.php$ index.php [L,QSA]
In your api example you would then have paremeters q,page,count available in $_GET due to the QSA (query string append) flag on the rewrite rule.
This leaves it up to you to interpret the rest of the URI.
You can do that rather simply using simple string manipulation techniques.
// discard query string after trimming leftmost '/' from URI
$uri_parts = explode('?', ltrim($_SERVER['REQUEST_URI'], '/'));
$uri_base = $uri_parts[0];
// get routing information from URI
$route_parts = explode('/', $uri_base);
$api_version = $route_parts[0];
$controller = $route_parts[1];
$action_parts = explode('.',$route_parts[2]);
$action = $action_parts[0];
$format = $action_parts[1];
// your parameters would be in $_GET['q'], $_GET['page'], etc.
You might consider Googling PHP URL routing to get more examples of how to set up a proper router, as this was just a very basic example and does not include any sort of validation or handling of more complex routes.
The benefit of this approach is that it keeps your routing logic all in PHP rather than split between Apache server config and PHP. If you need to make routing changes, you do it in PHP only. This also prevents mixing of routing information with actual parameter information within $_GET as would happen with your proposed rewrite.
I have decided to build a web application using clean urls. However its seems to be quite hard for at first. I have experienced many problems during testing and I couldn't figure out how is it recommended to build Clean URLs basically.
I have finally decided to redirect everything to the index.php and process the URI from there.
This is my .htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php?url=$0 [QSA]
In the PHP end I have created this, so only the URLs in the array will be passed:
$root_path = '/';
$uri = $_SERVER['REQUEST_URI'];
$url = array(
$root_path . 'login' => 'login'
);
$url_basic = array_keys($url);
$url_slash = array_keys($url);
array_walk($url_slash, function(&$value, $key) { $value .= '/'; return $value;});
if (in_array($uri, $url_basic) || in_array($uri, $url_slash)) {
$uri = rtrim($uri,'/');
require $url[$uri] . '.php';
exit();
} else {
echo 'Bad';
}
So basically if someone types: /login or /login/ they'll have the login.php required, otherwise they'll stay on the index.php page (as APACHE redirects everything else).
Question:
Let's say that the user has received an error while trying to log in. In this case I guess the best way (or if its not the best way, please tell me) to pass a $_GET variable with the name of 'error' for example. So the user would get: /login/?error=1
How is it possible to achieve that result? Because if I type that I get redirected to the index.php page. Can anyone please help me?
You can look at $_SERVER['QUERY_STRING'] at cut the query string out of $_SERVER['REQUEST_URI']:
if ($_SERVER['QUERY_STRING'])
echo substr($_SERVER['REQUEST_URI'], 0, -strlen($_SERVER['QUERY_STRING']) - 1);
The -1 is there to remove the question mark as well.
But setting the error in GET is not necessary. You can use a flash message and store the error in the session. You can find a simple way to use them here.
Maybe you should consider using a routing system as that of
Symfony: http://symfony.com/doc/current/book/routing.html
or its slimmer counterpart
Silex: http://silex.sensiolabs.org/doc/usage.html#routing
What i want to be able to do is if someone writes in the url bar
www.somesite.com/test
test is like the Username name so it will be www.somesite.com/Username
then page navigate to another and display data from the data where the username is the same
The page will navigate to another page and display data from he database
is this possible first of?
And this is what i have write now it not much, and i am also new to PHP
$url = 'http://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$url2 = "http://www.somesite.com/"$databaseVar1=mysql_result($result,$i,"username");
if ($url) == ($url2)
{
header("location: http://somesite.com/viewcontent.php");
}
else
{
//not found
}
Am i Able to do something like this? Any help will be great-full thanks
In PHP this is not exactly possible, however, you can do the following:
www.somesite.com/index.php/test
Apache will open index.php and you can use something like $_SERVER['REQUEST_URI'] to navigate from there
You will either need to use a rewrite rule in .htaccess to redirect all requests to index.php. Index.php can then use
Or you can put a ? before the username. Then index.php will automatically get all requests. The $_SERVER['querystring'] will then receive the username.
Taken some assumptions (due to lack of complete source code in your question):
mysql connection is estabilished
proper query has been sent to mysql server
variable $i is set to meaningful value
www server is configured to rewrite requests to index.php
You only have to compare REQUEST_URI with "username" column value taken from database.
Header "Location: ..." must have capital letter "L".
And avoid usage of "==" operator when comparing strings in PHP, strcmp() function is more reliable - "==" operator tests identity not equality - it's useful to compare numeric values.
You can define the index.php as the application dispatcher and create an .htaccess file that will redirect the requests to it:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
index.php:
$page = $_SERVER['REQUEST_URI']; //=> '/Users/show'
if ($page == '/some/page/') include('file_that_handles_this_request.php');
Or you could use this to create instances of classes and call methods:
$page = $_SERVER['REQUEST_URI']; //=> '/Users/show'
list($class, $method) = explode($page);
$object = new $class();
$object->{$method}();
you should use mvc architecture to get perfect as you want.
the url in mvc is like same as you want. You can call the method with the parameter from url directly. Here is a url pattern in mvc architecture -
www.yoursitename.com/controller/methodname/parameter
I try to go into MVC but come to a problem that is not explained anywhere, it is how to redirect from one to another controller.
I'm using the following .htaccess file:
RewriteEngine On
RewriteCond% {REQUEST_FILENAME}!-F
RewriteCond% {REQUEST_FILENAME}!-D
RewriteRule ^(.*)$ index.php? Url = $ 1 [L, QSA]
to use the controller directly after it put its methods and id th.
All this work accessing them in a standard way but when choosing a view to further pages ienata used directly as the controller.
<a href="next_page_controler"> NEXT_PAGE </ a>
and access the next controller, but when I want to access methods must use
<a href="next_page_controler/**controler_model**"> NEXT-pAGE_MODEL </ a>
and here we have two problems :
IN repeatedly link in address bar is displayed once again repeated as
www.site_pat/next_page_controler/next_page_controler/next_page_controler/next_page_controler/next_page_controler/controler_model
When you try to redirect as the method controler_model using header (Location: controler_name); nothing gets pulls no message or anything just want to try but the redirect does not work .
How to solve the problems I guess a lot of you have encountered these are basic things and I think that shouting at all began to work with framework should understand these basics.
Theres something wrong with your htaccess, should be something like...
RewriteEngine On
RewriteCond %{REQUEST_FILENAME}!-F
RewriteCond %{REQUEST_FILENAME}!-D
RewriteRule ^(.*)$ index.php/$1 [L, QSA]
UPDATE:
#prodigitalson coud you give me an example
So a super simple example might look like the following code. Ive never actually written a router from sractch because im typically using a framework, so there are probably soem features youll need that this doesnt include... Routing is a fairly complex things depending on how resuable you want it to be. I would reommend looking at how a few different php frameworks do it for good examples.
// define routes as a regular expression to match
$routes = array(
'default' => array(
'url' => '#^/categories/(?P<category_slug>\w*(/.*)?$#',
'controller' => 'CategoryController'
)
)
);
// request - you should probably encapsulate this in a model
$request = array();
// loop through routes and see if we have a match
foreach($routes as $route){
// on the first match we assign variables to the request and then
// stop processing the routes
if(preg_match($route['url'], $_SERVER['REQUEST_URI'], $params)){
$request['controller'] = $route['controller'];
$request['params'] = $params;
$request['uri'] = $_SERVER['REQUEST_URI'];
break;
}
}
// check that we found a match
if(!empty($request)){
// dispatch the request to the proper controller
$controllerClass = $request['controller'];
$controller = new $controllerClass();
// because we used named subpatterns int he regex above we can access parameters
// inside the CategoryController::execute() with $request['params']['category_slug']
$response = $controller->execute($request);
} else {
// send 404
}
// in this example $controller->execute() returns the compiled HTML to render, but
// but in most systems ive used it returns a View object, or the name of the template to
// to be rendered - whatever happens here this is where you send your response
print $response;
exit(0);
You shouldnt be implementing your controller routing soley from .htaccess. You should simple have all request other than for static assets go to index.php. Then on the php side you firgure out where to dispatch the request based on the pattern of the url.
I want to make a small web application, and I'm not sure how to go about this.
What I want to do is send every request to the right controller. Kind of how CodeIgniter does it.
So if user asks for domain.com/video/details
I want my bootstrap (index?) file to send him to the "Video" controller class and call the "details" method in that class.
If the user asks for domain.com/profile/edit I want to send him to the "Profile" controller class and call the "edit" method in that class.
Can someone explain how I should do this? I have some experience using MVC frameworks, but have never "written" something with MVC myself.
Thanks!
Edit: I understand now how the url points to the right Controller, but I don't see where the object instance of the Controller is made, to call the right method?
You need to re-route your requests. Using apache, this can be done using mod_rewrite.
For example, add a .htaccess file to your public base directory and add the following:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?rt=$1 [L,QSA]
This will redirect users trying to access
/profile/edit
to
index.php?rt=profile/edit
In index.php, you can access the $_GET['rt'] to determine which controller and action has been requested.
Use mod-rewrite (.htaccess) to
rewrite the url from
www.example.com/taco to
www.example.com/index.php?taco/
in index.php, grab the first URL
parameter key, use that to route to
the correct url. As it will look
like "taco/"
You may want to add / to the front
and back if it doesn't exist. As
this will normalize the urls and
make life easier
If you want to preserve the ability
to have traditional query strings.
Inspect the URL directly and take
the query string portion. break that
on ?, which will leave you with the
routing info in key 0 and the rest
in key 1. split that on &, then
split each of those on = and set the
first to the key and the second to
the value of an array. Replace $_GET
with that array.
Example:
$path = explode("?", $_SERVER["QUERY_STRING"],2);
$url = $path[0];
if(substr($url,0,1) != "/")
{
$url = "/".$url;
}
if(substr($url,-1,1) != "/")
{
$url = $url."/";
}
unset($_GET);
foreach(explode("&", $path[1]) as $pair)
{
$get = explode("=", $pair, 2);
$_GET[$get[0]] = $get[1];
}
// Define the Query String Path
define("QS_PATH", $url);
Depending on what you want to do or how much work you want to do, another option versus writing your own MVC is to use Zend Framework. It does exactly what you're asking for and more. You still need to configure URL rewriting as mentioned in the other answers, but it quick and easy.
Even if you're not interested in Zend Framework, the following link can help you configure your rewrite rules: http://framework.zend.com/wiki/display/ZFDEV/Configuring%2BYour%2BURL%2BRewriter