I am confused about how a php framework works with a web server like apache. Now if there wasn't a framework and if it was using classic php, then I understand how it works(if a php file is requested, the php parser executes it and returns the htm to the server).
When a framework like cakePHP is used, I have noticed that no matter which url the client requests, the index.php in the root folder gets executed first. How is this possible? if we were using pure php then, only the file we requested will get executed. So how does cakePHP make each and every request to go through the /index.php file?
CakePHP, and many other websites, leverage mod_rewrite which is an Apache module that "Provides a rule-based rewriting engine to rewrite requested URLs on the fly".
To do so, the web framework will use a .htaccess file with specific rules defined. These rules, in the case you're asking about, point any URL matching a specific pattern to to a real index.php file (this file can be named anything really, but index.php is a good "default" name).
Per CakePHP's URL Rewriting outline, a base rule is defined as:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /path/to/cake/app
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
What the above does is:
Turns on the rewrite module
Sets two conditions for rewriting the current URL
a. Only if the requested file is not a real directory (!-d)
b. Only if the requested file is not a real file (!-f)
Sends the full requested URL, (.*) to index.php
Sometimes, you'll see the RewriteRule line as:
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
This will set the requested url into the $_GET['url'] parameter instead of forcing the application to process the $_SERVER['REQUEST_URI']. Other times, there will be a lot of rewrite rules, some complicated, some basic.
There are a lot of good resources online, and in books, regarding mod_rewrite. Check out Introduction to URL Rewriting for one (it's one I have bookmarked, has a lot of good basic rules / formats).
That's a pretty simple one (https://github.com/gilbitron/PIP).
Read the files in the System folder.
Basically it goes like this:
All requests are sent to the index file (with mod_rewrite, or like a plain get parameter).
The index file includes configuration files and definitions of constants.
Then it loads the main class for the framerwork.
The main class does some configurations, initiates a database connection and so on.
Depending on how it is implemented, there might be a router but it's possible there isn't.If there is one the main class checks what controller should be loaded against the request in the router.
Then the main class loads the controller that should be loaded with that particular request.
PIP is not that good and the main class is actually not a class but you can get the point in it.
You can also read about the following things:
Object oriented programming: http://php.net/manual/en/language.oop5.php
Scopes: http://php.net/manual/en/language.variables.scope.php
Autoloading classes: http://php.net/manual/en/language.oop5.autoload.php
You mentioned
"I have noticed that no matter which url the client requests, the index.php in the root folder gets executed first."
This is what front controllers do. You can have a front controller with a framework or if coding from scratch using the .htaccess file. Front controllers enable rendering of pages using PHP functions/methods, such as $app->get($uri, $callback); in Lumen.
Related
How does instagram.com pass the username variable like "instagram.com/username" or like
instagram.com/floydmayweather
without using the $_GET function and it does not turn out looking like this
instagram/index.php?username=floydmayweather
Use a URL rewrite command in your HTTP server. There are many examples out there for both Apache and nginx.
The rewrite rule happens at the server level before it hits your code. This means the URL doesn't actually have to get modified before your code receives it.
The way I do it is I configure Apache/nginx to send all URLs that do not match an existing file (so that static files like images, js and css still work) to my index.php file. Then in the index.php file I parse the URL to determine what page type to load and what data.
In your example, they would grab the last token off the URL, know that it would be a user's name in URL format, look up that user in the database and build the page accordingly.
This is where something like a front controller or URL router comes in to play in most frameworks. In index.php I would map each URL, based on its components, to a class that would then handle the actual page building.
Here is more info on the rewrite modules;
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
http://wiki.nginx.org/HttpRewriteModule
Some quick Googling will show you many examples for how to configure this.
Your index.php file can examine the $_SERVER array to determine the URL that has been requested. In this situation, the explode() function is your friend, for parsing the URL and checking its components :)
The Rewrite engine will be a perfect solution, for example:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
Rewrite engine - A rewrite engine is software located in a Web application framework running on a Web server that modifies a web URL's appearance. This modification is called URL rewriting. Rewritten URLs (sometimes known as short, fancy URLs, search engine friendly - SEF URLs, or slugs) are used to provide shorter and more relevant-looking links to web pages. The technique adds a layer of abstraction between the files used to generate a web page and the URL that is presented to the outside world.
Usage
Instead getting URL with extenstion link (.php / html etc..)
www.stackoverflow.com/index.php
You will get URL Without extenstion
www.stackoverflow.com/index
I don't even know how this method is called, I just know the behavior I want to achieve.
My example for this is Facebook. If you go to facebook.com/[username or id] you get to the profile page, but I can't imagine that they're creating a directory in their root folder and putting a index file in there for every user.
So how's the following behavior accomplished; You go to somepage.com/foo/bar/hello but actually you're requesting somepage.com/foo?bar=hello ?
Is this even possible with Apache and PHP?
I don't even know how this method is called, I just know the behavior I want to achieve.
That thing is called URI/URL and the local part of it is passed to a webserver. The webserver then processes the request.
Is this even possible with Apache and PHP?
Yes. Not even even. This is what a webserver is for. What happens on the server is entirely shielded by the HTTP protocol which knows only the URI/URL specification which does not regulate if and how that needs to match to concrete processes or files on the webserver.
For example with the Apache HTTP Server there is a famous module called Mod_Rewrite that does URL-Rewriting. Often in a fashion that the user with her browser does not take any notice of it.
Example configuration with a PHP file (Apache HTTPD):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
</IfModule>
In a PHP script you can obtain the URI/URL by making use of special variables like $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING'].
Commonly this is made with mod rewrite. There you can make a "path" to a variable of a script.
E.g. http://example.com/user/1/edit could be translated with mod rewrite to http://example.com/index.php?function=edit&userid=1
Such a rule would look like this:
RewriteEngine on
RewriteRule ^/user/([0-9]+)/([a-z]+)$ index.php=function=$2&userid=$1 [L]
The first line activated the rewrite module the second line has a regular expression which must match for rewrite the url internally. If you like you can also make that externally with an [R] modifier instad of the [L].
Have a look to the whole documentation to learn more.
The stuff in the breckets are so called flags which are also well documentated.
I hope that helps!
I am using a MVC and on my application file, I am routing this way :
# Routing
$routing = array(
'([a-zA-Z]+)\/?' => array('Post', 'view')
);
framework::routing($routing);
It means that all the URLs like "mysite.com/anything/" will be routed to the same template but with different content. Until then, everything is okay.
My problem is that I would like to make an exception for that,
because I want to access my page "mysite.com/uploads" directly into the browser, but I am redirected, due to the routing php stuff.
Is there a way to make an exception to this routing? Like route all names excepted "upload" ?
I can submit the routing file, but since it's almost the same than codeigniter maybe you won't need it really.
Thanks
Seeing that your urls don't contain the index.php part anymore, I guess that you added an .htaccess file to do that, probably one that looks like this (straight from the codeigniter docs):
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
If this is that case and the uploads folder is in the same folder as the root index.php file of codeigniter, you should change the second line to:
RewriteCond $1 !^(index\.php|images|uploads|robots\.txt)
But this all depends on your specific configuration.
EDIT: Altough it seems that you aren't using CodeIgniter, the same applies to Zend Framework MVC. You should make an exception to the rewrite rules to allow direct access to your upload directory.
I noticed in Drupal if you add .php to the url bar of any page it gives you a 404 message; clean urls enabled. The page is obviously a .php, but the .htaccess is preventing the user from being able to tamper with url extensions in the url bar. How could you do this using .htaccess. I have file extensions omitted at the moment, but would also like to add that feature. Thank you.
Also, this question does not pertain to Drupal. I only mentioned Drupal for and example.
Just because a file contains PHP code it doesn't mean it has to have the .php extension; even more so when you're accessing a file over the internet.
When you request http://mysite.com/page and you're using an .htaccess like Drupal's, the request is forwarded onto index.php?q=page whereupon Drupal will check it's database for a path matching page. If it finds one it will display the content for that page, if not it will (rightly) give a 404.
If you want all of your pages to be accessible with a PHP extension you could add an extra rule in your .htaccess file to remove .php from any request where the PHP file doesn't physically exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.php $1 [NC]
Bear in mind though that this adds zero extra value for your site's visitors (in fact they have to remember a file extension as well as the path to the page), and it exposes exactly what server-side technology you're using so a potential attacker would have some of his work done for him.
Hope that helps.
Could you please explain that in more depth. How can it redirect content into an existing page? Is that common practice / typical way of doing things?
Yes it is a very common practice, used by most frameworks and CMS.
The principle is simple: you setup your .htaccess so that every request which doesn't match a real file or directory will be redirected to a front controller, usually the index.php in the root directory of the application. That front controller handles the request by analyzing the URL and calling the necessary actions.
In this way you can minimize the rewrite rules to just one, and you can offer customized 404 pages.
I dunno Drupal but in the usual php app every request being routed to the front controller which performs some validations and throws 404 on errors.
easy-peasy
I just inherited a website built in PHP. The main page of www.mysite.com has a href to www.mysite.com/index/35.html somewhere in the page. In the site's root directory and its children there is no document 35.html.
The number 35 is actually an id found in a DB which also holds the html contents of the page.
If I load URL: www.mysite.com/index.php?id=35 the same page loads.
How does PHP know how to automatically convert
/index/35.html
to
/index.php?id=35
EDIT
Based on the answers, I have found a .htaccess file containing rewrite instructions that would explain the functionality.
However, IIS doesn't seem to (or is not configured) know how to use this. (probably because this is an Apache feature?)
So this begs the following question: Is there a way to configure IIS to work with this?
it will be done usign URL Rewriting using .htaccess - should be in the webroot.
It may look something like:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
May have other bits, but what this basically tells apache is to send anything that DOES NOT physically exist to index.php
It doesn't. There is a mod_rewrite rule that rewrites from /index/foo to /index.php?id=foo, either in a .htaccess file somewhere or in the httpd configuration itself.
RewriteEngine On
RewriteRule ^index/([\d]+)\.html /index.php?id=$1 [NC,L]
This is off the top of my head. Any browsers trying to load an address starting with index/ has any number ending in .html will be internally redirected to index.php?id= whatever the number is.
Edit: Just saw that your working on IIS. This probably won't work for you. Sorry.
I think you will be using .htaccess to redirect all requests to index.php. From there You can pass the query string a routing class, which will parse the url and identify the unique ids.
In this case we can say like, your routing class will parse the request /index/35.html to indexController, indexAction, id=35. now you can pass this id to the model to get corresponding page contents
NB : Here I a am assuming you are using mvc pattern. Anyway it can be treated in your own way, with the concept remaining the same. Hope this make sence.