How to do different operations in PHP depending on the url structure - php

I have an index.php file which I would like to serve different content based on the url structure.
For example. If the url is mysite.com/index.php/folder1 I run a certain query and display the results and if the url is mysite.com/index.php/folder2, run a different query.
The solution also has to work for mysite.com/folder1 etc (ie index.php omitted).
And it would be ideal if the same approach could be extended to mysite/com/folder1/category1 etc. Note, GET variables aren't desired here.

What you need is a routing component that links url's to classes/functions in your code that do stuff. This component execute certain class/function depending on your request.
In this question, different strategies are discussed, although there are some already existing frameworks missing that are interesting:
Symfony Routing Component
SlimPHP
You could use any of those to do exactly what I mention earlier. For example, using the Symfony Routing Component, you could have your routes (potential urls) in a config file like:
# routes.yml
route1:
path: /foo
defaults: { _controller: 'MyController::fooAction' }
route2:
path: /foo/bar
defaults: { _controller: 'MyController::foobarAction' }
So when the requested uri matches with "/foo", the method fooAction from the class MyController is executed.
If you are not sure about how to implement this in your existing codebase, I'd strongly recommend you to read a series of posts about how to use different Symfony components in your code, written by Fabien Potencier. There is a specific post about the routing part.
As for the need to remove "index.php/" from your url, you need to rewrite it. If you are using Apache, you need to add the rewrite rules in your virtual host configuration file, or just create an .htaccess file in your document root. There are hundreds of questions in StackOverflow about this (like this one), and plenty of documentation in the official documentation page.

Add following RewriteRule in your .htaccess file and put .htaccess file into your webroot
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Above rule redirects all requests to index.php if there is not file/directory exists on the system.
For example, without above rule if http://example.com/test returns 404 error, then with above redirect rule, this will resolved to index.php. Now, within index.php you can parse the URL and do processing according to your requirements.

The best way is probably to assign variables in the browser. e.g.
index.php?folder=1 AND index.php?folder=2
In php then you use:
$folder = $GET_['folder']
if($folder == 1)
{
//show site 1
}
else if ($folder == 2)
{
//show site 2
}
else
{
//error code
}
there are other ways including .htaccess but for someone who does not want to go into that, i found this was the best way

Related

How to call a function in class/function format from localhost

I am using Yii2 framework for my PHP development. In my view files, If I want to call any of the functions, I just use Class/Function name
Eg : www.example.com/SiteController[class name]/index[function name]
And it is calling the function.
I like to know, How to do the same in a pure php script ?.
I searched in many places and I could get the suggestions for special_autoload_register();. But I could not understand the exact practical application.
Guidance is expected and Thanks is advance.
Its easy :).
It's all based on apache module mod_rewrite. This module allows you to modify path behavior in .htaccess file.
Using this .htaccess file
RewriteEngine On
# The following rule tells Apache that if the requested filename
# exists, simply serve it.
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
# The following rewrites all other queries to index.php. The
# condition ensures that if you are using Apache aliases to do
# mass virtual hosting, the base path will be prepended to
# allow proper resolution of the index.php file; it will work
# in non-aliased environments as well, providing a safe, one-size
# fits all solution.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
you will get following behavior:
If requested file exists (/styles/style.css - styles, javascripts, images, etc) serve it (dont change anything on current behavior)
If requested file doesn't exist, go to index.php.
If you are redirected to index.php, you can find full requested url in $_SERVER['REDIRECT_URL'] or $_SERVER['REQUEST_URI']. There you can take it, parse and based on requested uri, behave.
Please take this as explanation post, not a guide on how to get this going. Mostly it requires some apache configuration because mod_rewrite is mostly disabled by default.
If you want to get things going, I would recommend this post.
To fully answer your question, you can for example explode request uri by "/" sign, save first part into $firstPart and second into $secondPart and then have
$controllerName = $firstPart."Controller";
$controller = new $controllerName;
$actionName = $secondPart."Action"
$response = $controller->$actionName();
So if you call /help/me, helpController->meAction() will be called.
I hope I helped :)
To do this, Yii 2 (and other PHP frameworks) have routers. The router in Yii 2 is the UrlManager class.
I would not advice you write a router from scratch for a solution you want to deploy. There are routing packages in PHP which you could easily use in your solution. I like Klein. It's a pure router in PHP.
However, if for academic purposes, you want to know how routing works in PHP, get to understand the $_SERVER reserved variable. It has all the details of the HTTP request coming to your script. You can then use the details from this to call the specific function you want to call.

PHP framework work flow

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.

Disable direct access to files in PHP

I've already checked the issue disable access to included files , but I am wondering if that's the best solution.
Context: I'm building a bootstrap class for my PHP Framework, and realized that there are multiple solutions to this security issue.
After researching and reading posts like the one I mentioned at first and others related to htaccess, I think that there are basically three types of solutions:
1 - Checking a constant (like in the post I linked)
if(!defined('THIS_IS_NOT_A_DIRECT_ACCESS')) {
header('HTTP/1.1 404 Not Found');
include('./../error/404.php');
die;
}
Or
require('../error/include_file.php');
//
if(!defined('THIS_IS_NOT_A_DIRECT_ACCESS'))
{
header('HTTP/1.1 404 Not Found');
include('404.php');
die;
}
2 - Redirecting all calls to the Bootstrap and making a clever filtering.
//Something like
// if $urlRequested it's a file
// Go to Error
// else if $urlRequested it's not a controller
// Go to Error
// else
// Execute Controller Logic.
3 - Setting htaccess.
# Redirecting calls for non-directories, files or links
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA]
# Redirecting the rest of the calls to the error page.
RewriteRule ^(.+)$ index.php?url=error/404 [QSA]
Personally I think the solution 3 is the most interesting, but I am pretty new in the Htaccess control so I wonder if this is a safe solution.
For the purists and minimalists, the Question in here would be:
Are these (the three examples) nice direct access control systems for Apache-PHP applications? Else, which would be the safest approach? And the simplest?
This is a debatable topic but .htaccess rules applies to all the document on that particular directory. While applying 1 or 2 you may have to include that portion on every file.
Looking at all the options listed here IMO better would be to just place these files above the public_html folder or whatever is your DOCUMENT_ROOT folder and include with ../ paths. Then it would be available to your PHP scripts but for the web requests would get a default 404/ file not found error.

Avoid automatic PHP routing in a MVC

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.

How to understand PHP's URL parsing/routing?

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.

Categories