Route requests of non-existent URIs via .htaccess [duplicate] - php

First of all, I'm a beginner to PHP. And have posted a question here:
Refactoring require_once file in a project
. I've tried to read about Front controller as much as I can, but can't get how it works or even what's all about.
Can somebody explain in brief how it works and what's all about?

Front Controller refers to a design pattern where a single component in your application is responsible for handling all requests to other parts of an application. It centralizes common functionality needed by the rest of your application. Templating, routing, and security are common examples of Front Controller functionality. The benefit to using this design pattern is that when the behavior of these functions need to change, only a small part of the application needs to be modified.
In web terms, all requests for a domain are handled by a single point of entry (the front controller).
An extremely simple example of only the routing functionality of a front-controller. Using PHP served by Apache would look something like this. Most important step is to redirect all requests to the front controller:
.htaccess
RewriteEngine On
RewriteRule . /front-controller.php [L]
front-controller.php
<?php
switch ($_SERVER['REQUEST_URI']) {
case '/help':
include 'help.php';
break;
case '/calendar':
include 'calendar.php';
break;
default:
include 'notfound.php';
break;
}

Related

Rewrite url with 2 or more params

I asked a question like this before but since i still can't find an answer to this i'll ask it again :-s.
I'm using this very basic 'templating' script:
require_once 'core/init.php';
if(empty($_GET['page'])){
header('Location: home');
die();
}
$basePath = dirname(__FILE__) . '/';
$viewPath = $basePath . 'view/';
$view = scandir($viewPath);
foreach($view as $file)
{
if (!is_dir($viewPath . $file))
{
$pages[] = substr($file, 0, strpos($file, '.'));
}
}
if(in_array($_GET['page'], $pages)){
include($viewPath . $_GET['page'] . '.php');
} else{
include($basePath . '404.php');
}
and i'm rewriting my url from /base/index.php?page=somepage to /base/somepage(somepage is a .php file in my template folder) using this htaccess file
RewriteEngine On
RewriteBase /base/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^?]*) index.php?page=$1 [L,QSA]
With 1 parameter it works just fine but my problem is that i don't know how to rewrite a second param /base/profile?user=username (with no htaccess file this would have look like this /base/index.php?page=profile?user=username) and i want it to look like this /base/profile/username.
I hope that this question is understandable :-s
Routing is a real issue and I can't be exhaustive in one comment, but I'll try to do my best. Please forgive my aproximative english and let me know if you don't understand. I still have a lot to learn so I'll try to explain through something I made, but it is probably fully improvable.
Today's PHP Standard Recommendation about routing and interpreting request should implement PSR7.
I personnaly use it through a FrontController Design Pattern in a MVC framework I'm building to understand these concepts. My folders are organized like this :
Public :
Where I launch my web server, where you can find JavaScript/CSS. There's an index.php which just contains
require_once('../index.php');
App :
Where there's the router and mostly all generic code
Src :
Where there's the specific code to the app. That means controllers and entities for now.
Vendor :
Composer dependencies such as GuzzleHTTP to have a class between the actual request and the code.
Here's the code in my root's index.php :
<?php
require_once 'vendor/autoload.php';
use Namespace\FrontController;
use \GuzzleHttp\Psr7\ServerRequest;
use function Http\Response\send;
$front_ctrl = new FrontController(ServerRequest::fromGlobals());
send($front_ctrl->getResponse());
The main point of it is that I interpret the request within an instance of a class implementing PSR7.
In my FrontController, my request travel through some methods (such as removing trailing slash) to finnaly be sent in a Router class to be handled.
The purpouse of my Router class is to check if the URI exist in the array where I stocked all my routes under this format in a json file :
{
"/": [
"AppController",
"indexAction",
["GET", "POST"]
],...
}
This is where I use regex to match variable inside the URI (/article/:id for example) too.
This Class can be resumed as "Does this URI exists in my app?".
At this point, I instantiate a new Route class with all the array as parameter. From here, I have to answer questions such as "Is it attached to a method in a controller ?", "Does the method in which it is asked is handled ?" ...
To summarize, at this point, I have an Instance of a Class that represents the Request, another one that represents all my routes. I confront them to get ONE Route which I'm gonna manipulate through an Instance of a Class Route.
If it passed all those tests, then I can instantiate the right Controller, where there will be the logical part specific of the app, requiring some action to get data, that I will send in my views to generate a HTML output which I will send back all the way back to my function send so the output is displayed when you ask for a specific URI.
The main point of this long answer is to show you something that is almost completely independent from the server. It's also useful if your app gets bigger and has to handle more specific rules for routing. It forces you to separates all the bundles of your app : A Controller is not a Model neither a Router...
Try to find some good tutorials to learn Oriented Object Programmation in PHP, which would avoid easy security issues and give you much more comfort when developping an app :)
Hope it was understandable and helpful

What is a Front Controller and how is it implemented?

First of all, I'm a beginner to PHP. And have posted a question here:
Refactoring require_once file in a project
. I've tried to read about Front controller as much as I can, but can't get how it works or even what's all about.
Can somebody explain in brief how it works and what's all about?
Front Controller refers to a design pattern where a single component in your application is responsible for handling all requests to other parts of an application. It centralizes common functionality needed by the rest of your application. Templating, routing, and security are common examples of Front Controller functionality. The benefit to using this design pattern is that when the behavior of these functions need to change, only a small part of the application needs to be modified.
In web terms, all requests for a domain are handled by a single point of entry (the front controller).
An extremely simple example of only the routing functionality of a front-controller. Using PHP served by Apache would look something like this. Most important step is to redirect all requests to the front controller:
.htaccess
RewriteEngine On
RewriteRule . /front-controller.php [L]
front-controller.php
<?php
switch ($_SERVER['REQUEST_URI']) {
case '/help':
include 'help.php';
break;
case '/calendar':
include 'calendar.php';
break;
default:
include 'notfound.php';
break;
}

How do extended urls work

I know how these kind of URLs load the page ... based on their GET parameter.
http://www.bedupako.com/songs.php?page=show_song_details.php&songid=1167&n=0&back=no
and in the back-end roughly something like this:
<?php
switch($_GET['page']) {
case 'xx': include('my page');break;
.
.
.
default: include('default');break;
}
?>
But how do these kinds of URLs work? I mean, how is the data loaded dynamically?
www.dummysite.com/parm/subpage1/xyz
www.dummysite.com/parm/subpage2/xyz
How are these parsed similar to the GET param like websites?
In most cases this will be handled by the web server on-the-fly according to a set of rules. The specifics of it will vary from server to server and on a case-by-case basis. In Apache it is usually done using the mod_rewrite extension.
You can use mod_rewrite by itself as others have suggested, but most sites do not do this because its not very flexible, and can be annoying to maintain if you have more than a couple of these "pretty" URLS.
Instead they set up a basic rewrite rule to forward everything to a single index.php and then on the application side they parse the URI based on defined patterns - these are called "routes". Route parsing usually happens in some kind of routing class which process the defined routes and compares them to the URI, and then when it finds a match parses out the parameters for the matched route.
These all provide good examples of a router, but they are hard to understand without the other interacting classes:
Zend: Zend_Controller_Router_Rewrite
Symfony: sfPatternRouting
Cake: Router
CodeIgniter: CI_Router
You should look at http://httpd.apache.org/docs/2.0/misc/rewriteguide.html url rewriting if you're with apache (most likely)

MVC - No Controller in the URI?

Let's pretend I'm trying to learn CI, and as my test project I am building a group-buying site.
What I'd like is to have a different page for each city, e.g.:
http://www.groupon.com/las-vegas/
http://www.groupon.com/orlando/
I'd also like to have different pages such as:
http://www.groupon.com/learn
http://www.groupon.com/contact-us
If I am building this in CI and following the MVC ideology, how would this work? I'm having difficulty seeing how to accomplish the desired URL's with the concept of:
http://www.domain.com/controller/view/segment_a/segment_b/etc...
What I would do is create a custom 404 controller that acts as a catch-all for non-existent routes.
It would take the URI, possibly validate it, and re-route it to the (e.g.) "city" controller.
If the city controller can't find the city (whatever string was specified), then it needs to issue a proper 404. Otherwise, you're good to display your information for that city.
Also, once you create your custom 404 controller, you can send all 404 errors to it by specifying a route named '404_override'.
That's where URI Routing comes in. But in your case you'll probably will have to be carefull defining your routes as the first and only part of your route is a variable part already.
This really has nothing to do with MVC, and much more to do with good URL.
You're looking for URLs that are both (a) clear from the user's point of view and (b) that give hints to your application as to how it's meant to be handled.
What I'd do in this case is redesign your URLs slightly so that rather than:
http://www.groupon.com/las-vegas/
http://www.groupon.com/orlando/
You would have URLs that looks like this:
http://www.groupon.com/destinations/las-vegas/
http://www.groupon.com/destinations/orlando/
The bit at the beginning--/destinations/--can be used by your URL routing code to decide what controller should be dealing with it. If your routing code is URL-based, you might have an array like this:
$routes = array(
'/destinations/' => 'on_destination_list',
'/destinations/(.+)' => 'on_destination',
'/(.*)' => 'on_page');
// Basic URI routing code based off of REQUEST_URI
foreach ($pattern => $func) {
if (preg_match("`^$pattern$`", $_SERVER['REQUEST_URI'], $placeholders)) {
array_shift($placeholders);
call_user_func($func, $placeholders);
}
}
Keep in mind that I wrote that routing code off the top of my head and it may not be absolutely correct. It should give you the gist of what you need to do.
Doing things this way has the added benefit that if somebody goes to http://www.groupon.com/destinations/, you'll have the opportunity to show a list of destinations.

Are PHP MVC Controllers implemented by url rewrite?

The controller in a Java EE
application may be represented by a
servlet, which may be currently
implemented using JavaServer Faces
(JSF).
But in PHP there is no such servlet,so I guess is it implemented by url rewrite?
So that every request is directed to that controller?
It can be done with mod_rewrite but mostly in php there is a front-controller mechanisim which does all controlling through a single file. In this way, all controllers are specified in the url. See this for more explanation about controllers and mvc in php.
I think that's called the Front Controller pattern http://en.wikipedia.org/wiki/Front_controller and usually is achieved via mod_rewrite rules that any requests for phisically nonexisting files is redirected to index.php which then decides what to do.
MVC in PHP typically makes use of a front controller, which serves as the only entry point into the application.
This is usually implemented by using mod_rewrite to point all requests to a php file containing your bootstrap code.
This bootstrap code will contain your front controller.
The front controller takes it from there, redirecting the request based on the input parameters to the appropriate controller. Your target controller is usually specified as one of the parameters.
So, when you hit:
http://yourdomain.com/blog/new
The application would redirect the request to your bootstrap code with your front controller, which will interpret this input to mean 'blog' is the requested controller, 'new' is the action. It would then instantiate the 'blog' controller, pass it the 'new' action, and the rest is standard MVC.
As most of the other answers have shown, usually mod_rewrite is the way to do it. But, if you don't want to use mod_rewrite, you can let your bootstrap file actually configure variables from the URL itself.
I use a couple of my own functions which creates an array from a URL, so:
site.com/page/welcome/param1/param2
becomes
$url[0] = 'page'
$url[1] = 'welcome'
$url[2] = 'param1'
$url[3] = 'param2'
and then I can pass the $url array to my Router and it decides which parts of the Controller/Action/Param call each element belongs to.
The same URL request shown above creates the Controller/Action/Param call:
// http request for site.com/page/welcome/param1/param2
$controller = new Page_Controller('param1', 'param2');
$controller->welcomeAction();
while, depending on the settings in my Router object, I can create subdirectories, such as for calls to 'admin/':
// http request for site.com/admin/page/welcome/param1/param2
$controller = new Admin_Page_Controller('param1', 'param2');
$controller->welcomeAction();
With url_rewrite I think it would be harder (still possible though) to add those reroutes in, and with my method (Some frameworks might also do it, not too sure) it allows you to customize it more, ie you can edit the $url array if needed before passing it to the Router object.
I'm not sure what the negatives are in using this method, but it works pretty well for me!
You would use mod_rewrite to redirect everything to the index.php file. So you use mod_rewrite if you want this:
http://example.com/page/welcome
and not
http://example.com/index.php?page/welcome
or
http://example.com/index.php?controller=page&action=welcome

Categories