.htaccess for rewriting a personal system - php

I can't get my head around exactly what I want to do using mod_rewrite.
I want to be able to type in a url such as:
http://site.com/project/project-title/people/alex-coady
or
http://site.com/project/project-title/tasks/task-list-title
which will then be processed at handle.php with the variables available such that:
$_GET['project'] would equal 'project-title'
$_GET['people'] would equal 'alex-coady' (first example)
$_GET['tasks'] would equal 'task-list-title' (second example)
To reiterate: All requests will be managed by handle.php, but if any additional variables are tacked onto the URL, first the keyword people, tasks, projects (and any others I manually add) would be checked and the value immediately after them would be added in the form suggested above.
ie. http://site.com/handle.php?project=project-title&people=alex-coady&tasks= (first example)
Thank you.

How I would handle this is to forget about project,people,tasks and pass everything to the handle.php and then process it there, else you could end up having a rewrite rule for each request you add in the future.
So your mod_rewrite would look like:
RewriteEngine On
Options -Indexes
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ handle.php?route=$1 [L,QSA]
And your handle/router would look something like this (example)
<?php
//Get Route from request
$route = (!isset($_GET['route']))?'':$_GET['route'];
/*Split the parts of the route*/
$parts = explode('/', $route,4);
//http://site.com/project/project-title/people/alex-coady
//http://site.com/project/project-title/tasks/task-list-title
$project = (isset($parts[0]))?$parts[0]:null; //project/
$p_title = (isset($parts[1]))?$parts[1]:null; //project-title/
$action = (isset($parts[2]))?$parts[2]:null; //people or tasks
$sub_action = (isset($parts[3]))?$parts[3]:null; //alex-coady or task-list-title
//Then work with the above variables
?>

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^project/([^/]+)/([^/]+)/([^/]+)$ handle.php?project=$1&people=$2&tasks=$3 [L]
Or
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^project/(.*) handle.php?data=$1 [L]
And in handle.php
list($project, $task, $people, $foo, $bar) = explode('/', $_GET['data]);

Related

Pretty URL via htaccess using any number of parameters

Actually i have this URL:
http://www.example.com/index.php?site=contact&param1=value1&param2=value2&param3=value3
But i want to have this URL format:
http://www.example.com/contact/param1:value1/param2:value2/param3:value3
So the "contact" goes to variable $_GET["site"] and rest of parameters should be able to access via $_GET["param1"], $_GET["param2"] etc. The problem is, it has to work with any number of parameters (there could be param4 or even param50 or any other name of parameter). Is it possible via htaccess to cover all these cases?
Mod_rewrite has a maximum of 10 variables it can send:
RewriteRule backreferences:
These are backreferences of the form $N (0 <= N <= 9), which provide access to the grouped parts (in parentheses) of the pattern, from the RewriteRule which is subject to the current set of RewriteCond conditions.
mod_rewrite manual
so what you desire is NOT possible with htaccess only. a common way is to rewrite everything to one file and let that file determine what to do in a way like:
.htaccess
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,NC]
index.php
$aUrlArray = explode('/',str_ireplace(',','/',$_SERVER['REQUEST_URI'])); // explode every part of url
foreach($aUrlArray as $sUrlPart){
$aUrlPart = explode(':',$sUrlPart); //explode on :
if (count($aUrlPart) == 2){ //if not 2 records, then it's not param:value
echo '<br/>paramname:' .$aUrlPart[0];
echo '<br/>paramvalue' .$aUrlPArt[1];
} else {
echo '<br/>'.$sUrlPart;
}
}
Garytje's answer is almost correct.
Actually, you can achieve what you want with htaccess only, even if this is not something commonly used for that purpose.
Indeed, it would be more natural to delegate the logic to a script. But if you really want to do it with mod_rewrite, there are a lot of techniques to simulate the same behaviour. For instance, here is an example of workaround:
# Extract a pair "key:value" and append it to the query string
RewriteRule ^contact/([^:]+):([^/]+)/?(.*)$ /contact/$3?$1=$2 [L,QSA]
# We're done: rewrite to index.php
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^contact/$ /index.php?site=contact [L,QSA]
From your initial example, /contact/param1:value1/param2:value2/param3:value3 will first be rewritten to /contact/param2:value2/param3:value3?param1=value1. Then, mod_rewrite will match it again and rewrite it to /contact/param3:value3?param1=value1&param2=value2. And so on, until no pair key:value is found after /contact/. Finally, it is rewritten to /index.php?site=contact&param1=value1&param2=value2&param3=value3.
This technique allows you to have a number of parameters greater than 9 without being limited by mod_rewrite. You can see it as a loop reading the url step by step. But, again, this is maybe not the best idea to use htaccess only for that purpose.
This is entirely doable using some creative htaccess and PHP. Effectively what you are doing here is telling Apache to direct all page requests to index.php if they are not for a real file or directory on the server...
## No directory listings
IndexIgnore *
## Can be commented out if causes errors, see notes above.
Options +FollowSymlinks
Options -Indexes
## Mod_rewrite in use.
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
After this all you need to do is go into PHP and access the full user requested URL structure using the $_SERVER['REQUEST_URI'] superglobal and then break it down into an array using explode("/", $_SERVER['REQUEST_URI']).
I currently use this on a number of my sites with all of the sites being served by index.php but with url structures such as...
http://www.domain.com/forums/11824-some-topic-name/reply
which is then processed by the explode command to appear in an array as...
0=>"forums", 1=>"11824-some-topic-name",2=>"reply"
Try this..
.htaccesss
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /index.php [L,QSA]
index.php
$uri = $_SERVER['REQUEST_URI'];
$uri_array = explode( "/", $uri );
switch ( $uri_array[0] ) {
case '':
/* serve index page */
break;
case 'contact':
// Code
break;
}
This is doable using only htaccess with something along the lines of...
([a-zA-Z0-9]+):{1}([a-zA-Z0-9]+)
([a-zA-Z0-9]+) will match alpha-numeric strings.
:{1} will match 1 colon.
Expanding from there will probably be required based on weird URLs that turn up.

Apache + PHP without ".php" File Extension but Including Path Info

I'm trying to figure out how to modify the .htaccess file so I can do two things:
Not have to include the .php extension on my PHP files (e.g., a request to my.domain.com/page maps to my.domain.com/page.php).
Do #1 while also including additional path info (e.g., a request to my.domain.com/page/path/stuff/here maps to my.domain.com/page.php/path/stuff/here).
I've found out how to do #1 by adding the following to the .htaccess file:
# Allow PHP files without ".php" extension.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/.]+)/?$ /$1.php [L,QSA]
However, now I'd like to modify the RewriteRule so it works for #2.
OK, after searching for MultiViews, I found several articles warning against them (eh, to each his own), but that also led me to an answer that uses 2 rules instead of just 1:
RewriteRule ^([^\.]+)$ /$1.php [L]
RewriteRule ^([^\./]+)/(.*) /$1.php/$2 [L]
The first rule catches case #1 above, and the second rule catches case #2 above. Voila!
You could just try to use Multiviews, which is made to do exactly this:
Options +Multiviews
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^([^\.]+)$ $1.php [NC,L] #Remove the .php
Not sure what you want with the pathing stuff though.
Edit based off your comment, I've used something like this with php/angular. It's probably not "correct" or the best way to do it, but it worked for me.
Htaccess
RewriteEngine on
# Allow the API to function as a Front Controller
RewriteRule ^api/(.*)$ api/index.php?rt=$1 [L,QSA,NC]
# Allow Angular to have Pretty URL's
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
api/index.php
// Pull the routing path
$router = explode('/', $_GET['rt']);
$version = $router[0];
$controller = $router[1];
$action = $router[2];
// Check for the file
if(file_exists($version . '/controllers/' . $controller .'.class.php')) {
include $version . '/controllers/' . $controller .'.class.php';
} else {
return false;
}
// Initialize and execute
$method = new $controller($action);
print $method->$action();
This lets me do something like: api/v1/users/login in the url, then will find the users.class.php file in the V1 folder, and run the function login.

URL parameters with PHP

Are there ways to pass variables in a URL similarly to GET data? For example, with slashes?
I currently have a single .php file which reloads a div with different content using javascript to navigate pages, but as you can imagine, the address in the address bar stays the same.
I want users to be able to link to different pages, but that isn't possible conventionally if there is only one file being viewed.
You're probably going to want to use something along the lines of Apache's mod_rewrite functionality.
This page has a nice example http://www.dynamicdrive.com/forums/showthread.php?51923-Pretty-URLs-with-basic-mod_rewrite-and-powerful-options-in-PHP
Try using:
$_SERVER['QUERY_STRING']; // Or
$_SERVER['PHP_SELF'];
If that doesn't help, post an example of what kind of URL you are trying to accomplish.
Something like this might do the trick;
place this in /yourdir/
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ yourindexfile.php?string=$1 [QSA,L]
All requests will be sent to yourindexfile.php via the URL. So http://localhost/yourdir/levelone becomes yourindexfile.php?string=levelone.
You'll be able to break down the string like so;
$query= explode('/', rtrim($_GET['string'], '/'));
the technology your looking for is .htaccess. technically this isn't possible, so you'll have to hack your mod rewrite to accomplish this.
RewriteRule On +FollowSymLinks
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(user)/([^\.]+)$ ./index.html?tab=user&name=$2
add this to your .htaccess page in your top directory. you'll have to alter your website structure a little bit. assuming that index.html is your index. this is a backwards rewrite so if one was to go to the page with the query string it won't redirect them to the former page and if one went to the page without the query string it will work like GET data still.
you GET this data with your php file using $_GET['tab'] and $_GET['name']
I think the Symfony Routing Component is what you need ;) Usable as a standalone component it powers your routing on steroids.
I'm doing it like this (in my like framework, which is a fork of the JREAM framework):
RewriteEngine On
#When using the script within a subfolder, put this path here, like /mysubfolder/
RewriteBase /mysubfolder/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
Then split the different URL segments:
$url = isset($_GET['url']) ? $_GET['url'] : null;
$url = rtrim($url, '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url_array = explode('/', $url);
Now $url_array[0] usually defines your controller, $url_array[1] defines your action, $url_array[2] is the first paramter, $url_array[3] the second one etc...

htaccess and php - redirects and pretty urls

I have a webcommunity, and it's growing now. I like to do a link makeover for my web, and then I need to know the best solution for my case.
Right now my htaccess looks kind of like this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/\.]+)/?$ index.php?page=user&username=$1 [L]
You are able to link to users like this domain.com/username and that's nice.
Then I have different pages like
index.php?page=forum&id=1
index.php?page=someotherpage&id=1&anotherid=5
index.php?page=3rd
... and so on. I want them to look something like this:
domain.com/forum/23/title-of-the-thread
domain.com/page2/id1/id2
... and so on.
How do I make these pretty urls without removing my domain.com/username functionality? What solution would you suggest?
I was thinking about creating a file that checks the URL, if it matches any pages, and users and so on. Then it will redirect with a header location.
If all of the urls you are going to rewrite are going to the same end point, you could simply use:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
in index.php:
<?php
$url = $_SERVER['REQUEST_URI'];
How you use the request uri is up to you, you could for example use a simple strpos check:
<?php
$url = $_SERVER['REQUEST_URI'];
$rules = array(
'/forum/' => 'forum',
'/foo/' => 'foo',
'/' => 'username'
);
foreach($rules as $pattern => $action) {
if (strpos($url, $pattern) === 0) {
// use action
$file = "app/$action.php";
require $file;
exit;
}
}
// error handling - 404 no route found
I was thinking about creating a file that checks the URL,
you actually have that file, it's index.php
if it matches any pages, and users and so on. Then it will redirect with a header location.
that's wrong. HTTP redirect won't make your URLs look "pretty"
you have to include appropriate file, not redirect to.
Just change your rule to more general one
RewriteRule ^(.*)$ index.php [L,QSA]
You basically have two options.
Route all URLs to a central dispatcher (FrontController) and have that PHP script anaylze the URL and include the correct scripts
Note every possible route (url rewrite) you have in the .htaccess
I've always worked with option 1, as this allows greatest flexibility with lowest mod_rewrite overhead. Option 2 may look something like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^forum/([^/]+)/([^/]+)/?$ index.php?page=forum&id=$1 [L]
RewriteRule ^otherpage/([^/]+)/([^/]+)/?$ index.php?page=someotherpage&id=$1&anotherid=$21 [L]
RewriteRule ^page/([^/]+)/?$ index.php?page=$1 [L]
# …
RewriteRule ^([^/\.]+)/?$ index.php?page=user&username=$1 [L]
you said
I was thinking about creating a file that checks the URL, if it
matches any pages, and users and so on. Then it will redirect with a
header location.
While "creating a file that checks the URL" sounds a lot like option 1, "redirect with a header location" is the worst you could do. That would result in
an extra HTTP roundtrip for the client, leading to slower page loads
the "pretty URL" won't stick, the browser will show the URL you've redirected to
losing link-juice (SEO)
This can be done entirely with htaccess or php
//First Parameer
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)$ index.php?page=$1
RewriteRule ^([a-zA-Z0-9_-]+)/$ index.php?page=$1
//Second Parameter
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)/([0-9]+)$ index.php?page=$1&username=$2
RewriteRule ^([a-zA-Z0-9_-]+)/([0-9]+)/$ index.php?page=$1&username=$2
read more about it here:
http://net.tutsplus.com/tutorials/other/using-htaccess-files-for-pretty-urls/
http://www.roscripts.com/Pretty_URLs_-_a_guide_to_URL_rewriting-168.html

Rewrite Url Parameters - Change http://myweb/?dept=dept&app=app to http://myweb/dept/app

I've currently got a web application that I need optimizing, and one of methods or something I'm trying to achieve is such:
http://myweb/dept/app
from
http://myweb/?dept=dept&app=app
I've currently this as the PHP code for it:
if(empty($_REQUEST['dept'])) {
$folder = "apps/";
} else {
$folder = str_replace("/", "", $_REQUEST['dept']) . "/"; }
if(empty($_REQUEST['n'])) {
include('user/home.php');
} else {
$app = $_REQUEST['n'];
if(file_exists($folder.$app.".php")) {
include($folder.$app.".php");
} else {
include("global/error/404.php");
}
}
How do I do this?
I'm currently half there with:
RewriteRule ^([A-Za-z]+)$ /index.php?app=$1
but that only rewrites part of it.
Thanks
The way many frameworks do this is with one of the following rules:
RewriteRule ^(.*)$ /index.php?q=$1
RewriteRule ^(.*)$ /index.php
In the 1st case you get the query string in $_GET["q"].
In the 2nd case you have to get the query string from $_REQUEST or something. (just do some var_dumps till you find what you need).
Then you explode("/") this and you're all set.
Have a look at how TYPO3, eZPublish, Drupal do this.
You should also add the following conditions to allow the site to open your static files (like images/css/js/etc). They tell apache to not do the rewrite if the URL points to a location that actually matches a file, directoy or symlink. (You must do this before the RewriteRule directive)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
This should work:
RewriteRule ^([A-Za-z]+)/([A-Za-z]+)$ index.php?dept=$1&app=$2 [QSA]
You need the QSA part in order for any GET parameters to be appended to the rewritten URL.
You might find that it can be more flexible to rewrite everything to index.php, and then handle splitting up the url there, e.g.
.htaccess:
#only rewrite paths that don't exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1
PHP:
<?php
$parts = explode('/', $_SERVER['PATH_INFO']);
$dept = isset($parts[0]) ? $parts[0] : 'someDefault';
$app = isset($parts[1]) ? $parts[1] : 'anotherDefault';

Categories