PHP MVC with better htaccess - php

I have no idea how htaccess works, and the theory of it just wont connect in my head no matter how many tutorials I read.
I am building a simple MVC framework which works beautifully, except I don't like the way I am dealing with htaccess. To rewrite the URL's properly, this is what I am doing:
RewriteEngine on
RewriteRule ^users/([^/]+)(/([^/]+))?$ controller/users.php?method=$1&param=$3
If I add a new controller, I then have to go into htaccess and add a new line:
RewriteRule ^access/([^/]+)(/([^/]+))?$ controller/access.php?method=$1&param=$3
Is there a way to make it all automatic with wildcard fields so I don't have to access htaccess every time I do an update?

You can move logic for parsing query string into your framework/application. For this, make you rewrite rule like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
In this case, any request to server will be processed by index.php (if static file with same name not exists). And $_SERVER['REQUEST_URI'] will be equal real request uri - just parse it and use for your logic.
For example, if send /user/registry request with that .htaccess
$_SERVER['REQUEST_URI'] => '/user/registry'

You can try this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)(/([^/]+))?$ controller/$1.php?method=$2&param=$4
The two extra rules will skip the rewrite if the file or directoy referenced actually exists on the disk, eg: it won't try to rewrite requests for http://site.com/images/logo.jpg.

I'd redirect all URIs to index.php and allow another well established MVC concept handle the controller dispatching: Routers.
Many (most) MVC (and some non-MVC) applications use this by default because it allows advanced routing techniques (not only controller/action structured URIs).
Controllers can "register" (new) routers and set their priorities. The application can run all routers (in order of priority) until one router finds a matching route (and is able to discern which controller should be used).
For example many blog-like applications will need SEO friendly URIs meaning something like category/subcategory/subsubcategory/blog-article.html. Many cms-like applications will need the same for their hierarchical pages: top-level-page/mid-level-page/low-level-page.html. As well as many eCommerce applications will want that for their products: category/subcategory/product.html.
The above URIs need a router which will check the database to find out which article/page/product has that URI-key.

Related

htaccess: Issue with RewriteCond -f (if file exists)

I'm having a rough day into Apache's .htaccess manipulation methods and it seems I hit a wall.
My code intends to redirect all requests to /index.php just except for file requests, simple as that. I've been fairly reading other people's examples and documentation on every relatable statements and options to replicate the desired behavior.
So far this is the code:
RewriteEngine on
# If a requested file exists, rewrite route to the file
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ %{REQUEST_FILENAME} [L]
# If a requested file does not exist, rewrite route to index.php, works even if none was requested
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [L,QSA]
So far this is working properly, I can create virtual paths with my PHP controllers and still validate queries thanks to QSA.
The unexpected, though, comes when I decided to log the REQUEST_URI for each time /index.php was being called, to find that by trying to acces a file that does NOT exist, it's logging a call to /index.php, and at this point I don't know any techniques to apply a condition to this case.
My question in a single sentence is: How can I implement such a RewriteCond that validates if what is being requested is a file, rather than if it exists?
In addition, since it's my first time manually controlling URI requests, is there any security measures or strong suggestions I should take in account when using this rules in .htaccess?

.htaccess URL rewrite with random parameters

I'm currently writing a PHP app and am about to create various controllers. Currently I have one controller with certain method, so the URL looks like this:
http://somewebsite.com/index.php?c=controller&a=action
It's being rewritten to this:
http://somewebsite.com/controller/action
With this .htaccess file:
RewriteEngine On
RewriteRule ^([a-z]+)/([a-z]+)$ index.php?c=$1&a=$2 [NC]
What I want to achieve is the ability to rewrite URL with more than one controller (the more, the better), possibly in random order. Is there a more convenient way than rewriting every possible combination of URL parameters?
Many frameworks (Codeigniter, WordPress, Laravel, etc.) use an .htaccess file similar to the following:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
This rewrites all incoming URLs to be handled by the index.php file. You can then use $_SERVER['REQUEST_URI'] variable to get the exact request URI, parse it, and then handle it how you want.
if you're going for an arbitrary routing scheme, probably your best bet is to just pass the entire url string e.g. ^(.+)$ to index.php and let your php application split the string based on '/' and handle the array however makes sense for your application

how to access functions within php files using .htacess like codeigniter

I have a scenario where I want something similar to Codeigniter.
In Codeigniter my url is like:
http://www.example.com/filename/methodname
Now I want similar thing but using plain core PHP and .htaccess.
How is that possible ?
I want to have a index.php inside my folder and then redirect the http requests accordingly.
Searching the web I found this :
RewriteEngine on
RewriteRule ^([a-z0-9_-]+)\.html$ index.php/page/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|asset|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]
But I have little knowledge of .htaccess and don't know how this could help.
So I want an answer with example to understand how this can be achieved using .htaccess.
What would I need to do on my PHP side ?
Routing
Having urls like /filename/methodname is generally called routing. You have half of it done already; what you show in .htaccess is the part that will redirect all traffic towards an index.php file.
# starts rewrite engine
RewriteEngine on
# redirects direct .html page calls to their corresponding pages
RewriteRule ^([a-z0-9_-]+)\.html$ index.php/page/$1 [L]
# for anything that is not a file
RewriteCond %{REQUEST_FILENAME} !-f
# and for anything that is not a directory
RewriteCond %{REQUEST_FILENAME} !-d
# except if it's a robot
RewriteCond $1 !^(index\.php|asset|robots\.txt)
# send all that to index.php
RewriteRule ^(.*)$ index.php/$1 [L]
That index file will then parse the url and call relevant handlers with relevant arguments based on what matched.
How to create one such parser, or router, is beyond the scope of a single answer, but basically depends on the use of $_SERVER['REQUEST_URI'] and an array of urls with their corresponding handlers.
Solution
This is a "solved problem", and while it is interesting to implement such a thing by yourself, I would recommend simply to use a library that does it for you. I personally use Fast-Route, a pretty straightforward library that allows for customization in the way you handle routes, but if you google for "php routers" you will find plenty of them.
Of Filename/Methodname
(opinions follow from here on)
This point should be rethinked. While with psr-4 (and psr-0, and probably psr-whatever) the correspondance between a specific class and its file is that the file is named after the class it contains, I believe it better to not think about this as filename/methodname but rather section/action, or whatever speaks best of what the url actually does.
Moreover, if you start using namespaces (which you should do if your oop code becomes slightly more complicated than a hello world page), you obviously won't pass full namespaces in urls, and they actually are irrelevant to your users.

RewriteRule different pages per user

I am deciding to create separate profile links for each user who registers on the website. I am using the .htaccess file RewriteRule to achieve this. The url I want to achieve should look something like www.domain.com/username. (I don't want www.domain.com/users/username)
Now the problem is, if I add a rule like RewriteRule ^(.*)$ /users.php?username=$1
it will matchup all URL addresses for www.domain.com, which may direct to any path. Even if I would like to visit www.domain.com/about page, it will be redirected to
www.domain.com/users.php?username=about, which I don't want. (Even if the requests was www.domain.com/products/abc)
I could apply filters in my users.php to filter such usernames, or if a username is not found in database, redirect to the page, but this means I have to change filters every time I decide to add a new page in my directory (in this case, any). Also, all traffic will be directed through 1 page, which may cause a performance problem.
Please suggest a way to achieve this, as There are websites that work like this. A possible RewriteRule or PHP code to achieve this.
You can use this rule in your root .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(\w+)/?$ /users.php?username=$1 [L,QSA]
I always use just simple rewrite as below:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)(.*)/?$ index.php
All traffic is redirected to index.php and using php I can run specific controllers depending on url. You should also think about. Almost all frameworks use such rule.
Then in your PHP file you should examine
$_SERVER['REQUEST_URI']
variable to route request to specific controllers

URL rewriting in PHP when several values are being passed in the URL

I am currently researching how to modify URLs in php using Mod rewrite.
A typical URL could look like this:
http://www.fitness.com/find_a_pt/?county=&constituency=211&gender=&action=search
Now in the above example only a constituency has been selected. No county or gender has been specified.
Now the above constituency refers to 'Dartford'.
So it would be good if the URL read:
http://www.fitness.com/find_a_pt/dartford
Now the added complication is that a gender may be either:
1) Not selected - as per the URL above
2) Male
http://www.ego3fitness.com/find_a_pt/?county=&constituency=211&gender=1&action=search
3) Female
http://www.ego3fitness.com/find_a_pt/?county=&constituency=211&gender=&actiom=search
So the URLs would need to read:
1) http://www.fitness.com/find_a_pt/dartford
2) http://www.fitness.com/find_a_pt/dartford/male
3) http://www.fitness.com/find_a_pt/dartford/female
Firstly is it possible to be this specific with the URL rewrites and if so could someone provide an example for me to work from.
Thanks for your help in advance.
I always use the same mode_rewrite rules:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
With this rules everything is forwared to index.php.
So you are free to implement every url logic with PHP.
You can get the request uri with $_SERVER['REQUEST_URI'] and do whatever you want.
It is nice to have a Routing class with regex rules to parse the uri.
Look at an example here and also read
how the big frameworks like Zend, Code Igniter etc. do it.
(The rewrite rule I provided is from Zend Framework by the way)

Categories