I have a index.php which handle all the routing index.php?page=controller (simplified) just to split up the logic with the view.
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\w\d~%.:_\-]+)$ index.php?page=$1 [NC]
Which basically:
http://localhost/index.php?page=controller
To
http://localhost/controller/
Can anyone help me add the Rewrite for
http://localhost/controller/param/value/param/value (And soforth)
That would be:
http://localhost/controller/?param=value¶m=value
I can't get it to work with the Rewriterule.
A controller could look like this:
<?php
if (isset($_GET['action'])) {
if ($_GET['action'] == 'delete') {
do_Delete_stuff_here();
}
}
?>
And also:
<?php
if (isset($_GET['action']) && isset($_GET['x'])) {
if ($_GET['action'] == 'delete') {
do_Delete_stuff_here();
}
}
?>
Basically what people try to say is, you can make a rewrite rule like so:
RewriteRule ^(.*)$ index.php?params=$1 [NC, QSA]
This will make your actual php file like so:
index.php?params=param/value/param/value
And your actual URL would be like so:
http://url.com/params/param/value/param/value
And in your PHP file you could access your params by exploding this like so:
<?php
$params = explode( "/", $_GET['params'] );
for($i = 0; $i < count($params); $i+=2) {
echo $params[$i] ." has value: ". $params[$i+1] ."<br />";
}
?>
I think it's better if you redirect all requests to the index.php file and then extract the controller name and any other parameters using php. Same as any other frameworks such as Zend Framework.
Here is simple class that can do what you are after.
class HttpRequest
{
/**
* default controller class
*/
const CONTROLLER_CLASSNAME = 'Index';
/**
* position of controller
*/
protected $controllerkey = 0;
/**
* site base url
*/
protected $baseUrl;
/**
* current controller class name
*/
protected $controllerClassName;
/**
* list of all parameters $_GET and $_POST
*/
protected $parameters;
public function __construct()
{
// set defaults
$this->controllerClassName = self::CONTROLLER_CLASSNAME;
}
public function setBaseUrl($url)
{
$this->baseUrl = $url;
return $this;
}
public function setParameters($params)
{
$this->parameters = $params;
return $this;
}
public function getParameters()
{
if ($this->parameters == null) {
$this->parameters = array();
}
return $this->parameters;
}
public function getControllerClassName()
{
return $this->controllerClassName;
}
/**
* get value of $_GET or $_POST. $_POST override the same parameter in $_GET
*
* #param type $name
* #param type $default
* #param type $filter
* #return type
*/
public function getParam($name, $default = null)
{
if (isset($this->parameters[$name])) {
return $this->parameters[$name];
}
return $default;
}
public function getRequestUri()
{
if (!isset($_SERVER['REQUEST_URI'])) {
return '';
}
$uri = $_SERVER['REQUEST_URI'];
$uri = trim(str_replace($this->baseUrl, '', $uri), '/');
return $uri;
}
public function createRequest()
{
$uri = $this->getRequestUri();
// Uri parts
$uriParts = explode('/', $uri);
// if we are in index page
if (!isset($uriParts[$this->controllerkey])) {
return $this;
}
// format the controller class name
$this->controllerClassName = $this->formatControllerName($uriParts[$this->controllerkey]);
// remove controller name from uri
unset($uriParts[$this->controllerkey]);
// if there are no parameters left
if (empty($uriParts)) {
return $this;
}
// find and setup parameters starting from $_GET to $_POST
$i = 0;
$keyName = '';
foreach ($uriParts as $key => $value) {
if ($i == 0) {
$this->parameters[$value] = '';
$keyName = $value;
$i = 1;
} else {
$this->parameters[$keyName] = $value;
$i = 0;
}
}
// now add $_POST data
if ($_POST) {
foreach ($_POST as $postKey => $postData) {
$this->parameters[$postKey] = $postData;
}
}
return $this;
}
/**
* word seperator is '-'
* convert the string from dash seperator to camel case
*
* #param type $unformatted
* #return type
*/
protected function formatControllerName($unformatted)
{
if (strpos($unformatted, '-') !== false) {
$formattedName = array_map('ucwords', explode('-', $unformatted));
$formattedName = join('', $formattedName);
} else {
// string is one word
$formattedName = ucwords($unformatted);
}
// if the string starts with number
if (is_numeric(substr($formattedName, 0, 1))) {
$part = $part == $this->controllerkey ? 'controller' : 'action';
throw new Exception('Incorrect ' . $part . ' name "' . $formattedName . '".');
}
return ltrim($formattedName, '_');
}
}
How to use it:
$request = new HttpRequest();
$request->setBaseUrl('/your/base/url/');
$request->createRequest();
echo $request->getControllerClassName(); // return controller name. Controller name separated by '-' is going to be converted to camel case.
var_dump ($request->getParameters()); // print all other parameters $_GET & $_POST
.htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Your rewrite rule would pass the entire URL:
RewriteRule ^(.*)$ index.php?params=$1 [NC]
Your index.php would interpret that full path as controller/param/value/param/value for you (my PHP is a little rusty):
$params = explode("/", $_GET['params']);
if (count($params) % 2 != 1) die("Invalid path length!");
$controller = $params[0];
$my_params = array();
for ($i = 1; $i < count($params); $i += 2) {
$my_params[$params[$i]] = $params[$i + 1];
}
How about redirect to index.php?params=param/value/param/value, and let php split the whole $_GET['params']? I think this is the way wordpress handling it.
For some reason, the selected solution did not work for me. It would constantly only return "index.php" as value of params.
After some trial and error, I found the following rules to work well. Assuming you want yoursite.com/somewhere/var1/var2/var3 to point to yoursite.com/somewhere/index.php?params=var1/var2/var3, then place the following rule in a .htaccess file in the "somewhere" directory:
Options +FollowSymLinks
RewriteEngine On
# The first 2 conditions may or may not be relevant for your needs
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-f
# This rule converts your flat link to a query
RewriteRule ^(.*)$ index.php?params=$1 [L,NC,NE]
Then, in PHP or whichever language of your choice, simply separate the values using the explode command as pointed out by #Wesso.
For testing purposes, this should suffice in your index.php file:
if (isset($_GET['params']))
{
$params = explode( "/", $_GET['params'] );
print_r($params);
exit("YUP!");
}
Is this what your looking for?
This example demonstrates how to easily hide query string parameters using loop flag. Suppose you have URL like http://www.mysite.com/foo.asp?a=A&b=B&c=C and you want to access it as http://www.myhost.com/foo.asp/a/A/b/B/c/C
Try the following rule to achieve desired result:
RewriteRule ^(.*?\.php)/([^/]*)/([^/]*)(/.+)? $1$4?$2=$3 [NC,N,QSA]
Are you sure you are using apache server,.htaccess works only on apache server. If you are using IIS then web.config is reqired. In that case:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Homepage">
<match url="Homepage"/>
<action type="Rewrite" url="index.php" appendQueryString="true"/>
</rule>
</rules>
</rewrite>
<httpErrors errorMode="Detailed"/>
<handlers>
<add name="php" path="*.php" verb="*" modules="IsapiModule" scriptProcessor="C:\Program Files\Parallels\Plesk\Additional\PleskPHP5\php5isapi.dll" resourceType="Unspecified"/>
</handlers>
</system.webServer>
</configuration>
Related
I am creating a custom Router for my web app.
I use MVC.
When I, for example, type fab.app/portfolio all is good.
But when I type fab.app/portfolio/ the css, images, and js are not displayed.
This is because the paths change. In the first case the path that it is looking for the images is fab.app/images/(the_image) but in the second case it is fab.app/portfolio/images/(the_image).
Also, in the index.php I have to have an entry for both the url with and without the slash in the end. Which I don't like. I would prefer to write it without the slash and it should work with the slash as well.
Below you can find the router and index.php
index.php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../app/setup.php';
use Fab\Controllers;
use Fab\Router;
$router = new Router\Router();
$router->get('/', 'MainController', 'index');
$router->get('/portfolio', 'ItemsController', 'showAllItems');
$router->get('/portfolio/', 'ItemsController', 'showAllItems');
$router->get('/portfolio/[\w\d]+', 'ItemsController', 'single_item');
$router->get('/about', 'MainController', 'about');
$router->get('/contact', 'MainController', 'contact');
$router->get('/admin/dashboard', 'AdminController', 'index');
$router->get('/admin/dashboard/addItem', 'AdminController', 'addItem');
$router->get('/admin/dashboard/deleteItem', 'AdminController', 'deleteItem');
$router->get('/admin/dashboard/editItem', 'AdminController', 'editItem');
$router->get('/admin/dashboard/contactSupport', 'AdminController', 'contactSupport');
$router->post('/admin/addItem', 'AdminController', 'postAddItem');
$router->post('/admin/deleteItem', 'AdminController', 'postDeleteItem');
$router->post('/admin/editItem', 'AdminController', 'postEditItem');
//$router->get('/test', 'ItemsController', 'showAllItems');
////See inside $router
//echo "<pre>";
//print_r($router);
$router->submit();
Router.php
<?php
/**
* Created by PhpStorm.
* User: antony
* Date: 5/30/16
* Time: 3:31 PM
*/
namespace Fab\Router;
class Router
{
private $_getUri = array();
private $_getController = array();
private $_getMethod = array();
private $_postUri = array();
private $_postController = array();
private $_postMethod = array();
public function __construct()
{
}
/**
* Build a collection of internal GET URLs to look for
* #param $uri - The url that the user types in the browser
* #param $controller - The controller that will handle the url
* #param $method - The method of the controller that will run
*/
public function get($uri, $controller, $method)
{
$this->_getUri[] = $uri;
$this->_getController[] = $controller;
$this->_getMethod[] = $method;
}
/**
* Build a collection of internal POST URLs to look for
* #param $uri - The url that the user types in the browser
* #param $controller - The controller that will handle the url
* #param $method - The method of the controller that will run
*/
public function post($uri, $controller, $method)
{
$this->_postUri[] = $uri;
$this->_postController[] = $controller;
$this->_postMethod[] = $method;
}
public function submit()
{
$found = 0;
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //get the url
//Map URL to page
foreach ($this->_getUri as $key => $value)
{
if ( $found = preg_match("#^$value$#", $path) )
{
// echo $key . ' => ' . $value; //See what the $path returns
//Find parameter if passed
$parts = explode('/', $path);
count($parts) > 2 ? $parameter=$parts[2] : $parameter=null;
//Instantiate Controller
$controller = 'Fab\Controllers\\' . $this->_getController[$key];
$controller = new $controller($parameter);
//Call the appropriate method
$method = $this->_getMethod[$key];
$controller->$method();
break;
}
}
//Show 404 page
if ( $found == 0 )
{
//Instantiate Controller
$controller = 'Fab\Controllers\MainController';
$controller = new $controller();
//Call the appropriate method
$method = 'error404';
$controller->$method();
die();
}
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //get the url
foreach ($this->_postUri as $key => $value)
{
if ( $found = preg_match("#^$value$#", $path))
{
// echo $key . ' => ' . $value; //See what the $path returns
//Find parameter if passed
$parts = explode('/', $path);
count($parts) > 2 ? $parameter=$parts[2] : $parameter=null;
//Instantiate Controller
$controller = 'Fab\Controllers\\' . $this->_postController[$key];
$controller = new $controller($parameter);
//Call the appropriate method
$method = $this->_postMethod[$key];
$controller->$method();
break;
}
}
//Show 404 page
if ( $found == 0 )
{
//Instantiate Controller
$controller = 'Fab\Controllers\MainController';
$controller = new $controller();
//Call the appropriate method
$method = 'error404';
$controller->$method();
die();
}
}
}
}
.htaccess
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
AddType 'text/css; charset=UTF-8' css
</IfModule>
Example of calling css (but also images and js) in html
<link href="/css/my-admin-custom.css" rel="stylesheet">
-------------------------------------------------------------------
For sake of clarity, here is how I resolved the issue (per #Max13's answer).
This goes into Router.php:
/**
* If last char in URL is '/' redirect without it
* and also check if url is root '/' because this would result
* in infinite loop
*/
if ( ($path[strlen($path)-1] === '/') && !($path === '/') ) { //
$newPath = substr($path, 0, -1);
header("Location: $newPath", true, 302);
exit;
}
With and without trailing slash doesn't mean the same directory level, so I don't think it would be a good idea to "accept" both, in your router.
So, a good solution IMHO would be: During your checks, if the path ends with "/", then send a 302 Found header without the trailing slash.
-- Edit --
See (For header redirects and meta tag redirection, both are often used at the same time): https://www.arclab.com/en/websitelinkanalyzer/http-and-meta-redirects.html
The below example shows how I am currently doing things.
index.php includes index_controller.php then index_template.php.
index_controller.php
$uri = explode('/', $_SERVER['REQUEST_URI']);
$action = $uri[1];
$call = $uri[2];
$tmp = explode('?', $call);
$call = $tmp[0];
$call = preg_replace('/-/', ' ', $call);
switch ($action) {
case "about":
$page = "about.inc.php";
$title = "About Us";
$description = "Description of page";
break;
case "category":
try {
//PDO query to make sure category ($call) exists
}
catch (PDOException $e) {
logError($e->getMessage());
}
if (query->rowCount() < 1) {
$page = "404.inc.php";
$title = "404 Error";
}
else {
//Meta information for selected category pulled from DB and put into variables.
$page = "category.inc.php";
break;
default:
$page = "404.inc.php";
$title = "404 Error";
}
The above example shows 2 of around 12 different page options in the switch statement. A simple request (about) and a more complex request (category).
index_template.php has all my head, body, and footer HTML. It sets the meta data for the page, sets up the sites structure, and includes whatever file the $page variable is set to in index_controller.php
Using the above example, if someone goes to mysite.com/category/books index_controller.php will see if the books category exists and if it does category.inc.php will be included.
category.inc.php does another PDO query to get all the items and information required to display a list of items for the selected category. It also includes a template file to structure the display of the returned items.
I am trying to achieve a MVC type structure (without using a framework like Codeigniter or CakePHP), but I don't really have the model end down.
How can I get the user from the URL to the view using classes and/or functions instead of all the includes I am currently using?
If you feel I didn't do a good job explaining the other files mentioned I can provide code examples from those files as well.
Any help, input, or suggestions will be greatly appreciated.
EDIT: Clarified question as per comment below.
With a little trick and with .htaccess you can make this much easier.
I use this method in my self made MVC based application. You can copy paste the whole code or just use a part of it. The main logic is in the Bootstrap class.
.htaccess
Options -Indexes
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
RewriteRule ^$ /news [R]
index.php
require 'brInit.php';
$app = new \brInclude\brClasses\mvc\Bootstrap();
I use brInit to automatically include classes and to include my config file
Bootstrap.php
class Bootstrap {
private $url = array();
/** #var Controller $controller */
private $controller;
function __construct(){
try {
$this->_getUrl();
$this->_loginUser();
if(!$this->_setController($this->url[0]))
throw new Exception('404');
if(!$this->_executeControllersMethod())
throw new Exception('404');
} catch(Exception $e){
$this->_error($e->getMessage());
}
}
private function _error($msg){
$this->url = array('Error', 'error', $msg);
$this->_setController($this->url[0]);
$this->_loginUser();
$this->_executeControllersMethod();
}
private function _getUrl(){
if(isset($_GET['url']))
$this->url = explode('/', rtrim($_GET['url'], '/'));
else
$this->url = array('news');
unset($_GET['url']);
}
private function _setController($name){
$path = 'brInclude/brMVC/controller/';
if(!file_exists($path)) return false;
$url = ucfirst($name) . 'Controller';
$namespace = str_replace('/', '\\', $path);
$file = $path . $url . '.php';
if(!file_exists($file)) return false;
$classWithNamespace = $namespace . $url;
$this->controller = new $classWithNamespace;
$this->controller->view->name = $name;
return true;
}
private function _loginUser(){
$model = new UserModel();
$user = $model->login();
Controller::$user = $user;
}
private function _executeControllersMethod(){
if(isset($this->url[1])){
if(method_exists($this->controller, $this->url[1])){
$count = count($this->url);
if($count > 2)
call_user_func_array(
array($this->controller, $this->url[1]),
array_slice($this->url, 2)
);
else
$this->controller->{$this->url[1]}();
} else {
return false;
}
} else {
$this->controller->index();
}
return true;
}
public static function isLoginRequired(){
return self::$loginRequired;
}
}
I created a PHP RESTful API following this example (code at the bottom). From what I understand, the API converts non-existing URI components to GET parameters in the address via the .htaccess file like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule api/v1/(.*)$ api/v1/api.php?request=$1 [QSA,NC,L]
</IfModule>
So if I do, e.g.:
http://mysite/api/v1/endpoint1/param1
endpoint1/param1 can be parsed in the API implementation to call a PHP function endpoint1(param1).
Now my issue is, param1 is really long, and I want use AJAX to POST param1, but the POST doesn't go through
For example, for the RESTful API:
http://mysite/api/v1/endpoint1
I POSTed data using AJAX as follows:
$.post('http://mysite/api/v1/endpoint1/',data,callback,'json');
In API.class.php, $_SERVER['REQEUEST_METHOD'] is 'POST', but $_POST is empty array.
My questions are:
What is actually happening when I POST to a virtual URL to be handled by mod_rewrite. Is the end result a GET request by mode_rewrite or a POST request by my AJAX call?
How can I modify the code to get the POSTed data through? (Is it possible to ask mod_rewrite to use the POST method instead?)
I am confused here, any pointers are appreciated.
The interface for the relevant REST api is (API.class.php, please see the example for complete code):
<?php
abstract class API
{
protected $method = '';
protected $endpoint = '';
protected $args = Array();
protected $file = Null;
public function __construct($request) {
header("Access-Control-Allow-Orgin: *");
header("Access-Control-Allow-Methods: *");
header("Content-Type: application/json");
$this->args = explode('/', rtrim($request, '/'));
$this->endpoint = array_shift($this->args);
$this->method = $_SERVER['REQUEST_METHOD'];
if ($this->method == 'POST' && array_key_exists('HTTP_X_HTTP_METHOD', $_SERVER)) {
if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'DELETE') {
$this->method = 'DELETE';
} else if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'PUT') {
$this->method = 'PUT';
} else {
throw new Exception("Unexpected Header");
}
}
switch($this->method) {
case 'DELETE':
case 'POST':
$this->request = $this->_cleanInputs($_POST);
$this->args[] = ???; //Problem line: how do I add post to the args
break;
case 'GET':
$this->request = $this->_cleanInputs($_GET);
break;
case 'PUT':
$this->request = $this->_cleanInputs($_GET);
$this->file = file_get_contents("php://input");
break;
default:
$this->_response('Invalid Method', 405);
break;
}
}
public function processAPI() {
if ((int)method_exists($this, $this->endpoint) > 0) {
return $this->_response($this->{$this->endpoint}($this->args));
}
return $this->_response("No Endpoint: $this->endpoint", 404);
}
private function _response($data, $status = 200) {
header("HTTP/1.1 " . $status . " " . $this->_requestStatus($status));
return json_encode($data);
}
private function _cleanInputs($data) {
$clean_input = Array();
if (is_array($data)) {
foreach ($data as $k => $v) {
$clean_input[$k] = $this->_cleanInputs($v);
}
} else {
$clean_input = trim(strip_tags($data));
}
return $clean_input;
}
private function _requestStatus($code) {
$status = array(
200 => 'OK',
404 => 'Not Found',
405 => 'Method Not Allowed',
500 => 'Internal Server Error',
);
return ($status[$code])?$status[$code]:$status[500];
}
}
?>
I believe this is the issue you are running into:
Is it possible to redirect post data?
You should change this line in your .htaccess file from:
RewriteRule api/v1/(.*)$ api/v1/api.php?request=$1 [QSA,NC,L]
to:
RewriteRule api/v1/(.*)$ api/v1/api.php?request=$1 [QSA,NC,P]
I just recently started to work with .htaccess on a website i'm working on. Everything works just fine, but when I try to acces the user.php file which is located on the index, I keep getting this url:
http://lifeline.andornagy.info/user/?url=user
on every other file and place, it works just great.
This is the function with what I call different pages depending on the URL :
public function lifeline() {
global $templatePath;
if ( isset($_GET['url']) && $_GET['url'] !== 'user' ) {
$url = $_GET['url'];
$result = mysql_query("SELECT * FROM posts WHERE url='$url' ");
if ( !mysql_num_rows($result) ) {
if ( file_exists($templatePath.'404.php') ) {
include_once($templatePath.'404.php');
} else {
include_once('404.php');
}
}
while($row = mysql_fetch_assoc($result)){
if ( $row['type'] === 'post' ) {
include_once($templatePath.'post.php');
} elseif ( $row['type'] === 'page' ) {
include_once($templatePath.'page.php');
}
}
} elseif ($_GET['url'] === 'user') {
include_once($templatePath.'user.php');
} else {
include_once($templatePath.'index.php');
}
}
And this is my .htaccess file.
Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)$ index.php?url=$1
RewriteRule ^([a-zA-Z0-9_-]+)/$ index.php?url=$1
RewriteRule ^(.+)(\s|%20)(.+)$ /$1-$3 [R=301,QSA,L,NE]
ErrorDocument 404 /404.php
And I would like if my URL would look like this:
http://lifeline.andornagy.info/user
Without the /?url=user
Sorry If I sound noobish. :(
Without examining this too closely, the last RewriteRule in your .htaccess includes [R=301], making it the only rule capable of "adding" (i.e. redirecting you to) the /?user=x. I'd take a closer look at that last rule.
I have a index.php which handle all the routing index.php?page=controller (simplified) just to split up the logic with the view.
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\w\d~%.:_\-]+)$ index.php?page=$1 [NC]
Which basically:
http://localhost/index.php?page=controller
To
http://localhost/controller/
Can anyone help me add the Rewrite for
http://localhost/controller/param/value/param/value (And soforth)
That would be:
http://localhost/controller/?param=value¶m=value
I can't get it to work with the Rewriterule.
A controller could look like this:
<?php
if (isset($_GET['action'])) {
if ($_GET['action'] == 'delete') {
do_Delete_stuff_here();
}
}
?>
And also:
<?php
if (isset($_GET['action']) && isset($_GET['x'])) {
if ($_GET['action'] == 'delete') {
do_Delete_stuff_here();
}
}
?>
Basically what people try to say is, you can make a rewrite rule like so:
RewriteRule ^(.*)$ index.php?params=$1 [NC, QSA]
This will make your actual php file like so:
index.php?params=param/value/param/value
And your actual URL would be like so:
http://url.com/params/param/value/param/value
And in your PHP file you could access your params by exploding this like so:
<?php
$params = explode( "/", $_GET['params'] );
for($i = 0; $i < count($params); $i+=2) {
echo $params[$i] ." has value: ". $params[$i+1] ."<br />";
}
?>
I think it's better if you redirect all requests to the index.php file and then extract the controller name and any other parameters using php. Same as any other frameworks such as Zend Framework.
Here is simple class that can do what you are after.
class HttpRequest
{
/**
* default controller class
*/
const CONTROLLER_CLASSNAME = 'Index';
/**
* position of controller
*/
protected $controllerkey = 0;
/**
* site base url
*/
protected $baseUrl;
/**
* current controller class name
*/
protected $controllerClassName;
/**
* list of all parameters $_GET and $_POST
*/
protected $parameters;
public function __construct()
{
// set defaults
$this->controllerClassName = self::CONTROLLER_CLASSNAME;
}
public function setBaseUrl($url)
{
$this->baseUrl = $url;
return $this;
}
public function setParameters($params)
{
$this->parameters = $params;
return $this;
}
public function getParameters()
{
if ($this->parameters == null) {
$this->parameters = array();
}
return $this->parameters;
}
public function getControllerClassName()
{
return $this->controllerClassName;
}
/**
* get value of $_GET or $_POST. $_POST override the same parameter in $_GET
*
* #param type $name
* #param type $default
* #param type $filter
* #return type
*/
public function getParam($name, $default = null)
{
if (isset($this->parameters[$name])) {
return $this->parameters[$name];
}
return $default;
}
public function getRequestUri()
{
if (!isset($_SERVER['REQUEST_URI'])) {
return '';
}
$uri = $_SERVER['REQUEST_URI'];
$uri = trim(str_replace($this->baseUrl, '', $uri), '/');
return $uri;
}
public function createRequest()
{
$uri = $this->getRequestUri();
// Uri parts
$uriParts = explode('/', $uri);
// if we are in index page
if (!isset($uriParts[$this->controllerkey])) {
return $this;
}
// format the controller class name
$this->controllerClassName = $this->formatControllerName($uriParts[$this->controllerkey]);
// remove controller name from uri
unset($uriParts[$this->controllerkey]);
// if there are no parameters left
if (empty($uriParts)) {
return $this;
}
// find and setup parameters starting from $_GET to $_POST
$i = 0;
$keyName = '';
foreach ($uriParts as $key => $value) {
if ($i == 0) {
$this->parameters[$value] = '';
$keyName = $value;
$i = 1;
} else {
$this->parameters[$keyName] = $value;
$i = 0;
}
}
// now add $_POST data
if ($_POST) {
foreach ($_POST as $postKey => $postData) {
$this->parameters[$postKey] = $postData;
}
}
return $this;
}
/**
* word seperator is '-'
* convert the string from dash seperator to camel case
*
* #param type $unformatted
* #return type
*/
protected function formatControllerName($unformatted)
{
if (strpos($unformatted, '-') !== false) {
$formattedName = array_map('ucwords', explode('-', $unformatted));
$formattedName = join('', $formattedName);
} else {
// string is one word
$formattedName = ucwords($unformatted);
}
// if the string starts with number
if (is_numeric(substr($formattedName, 0, 1))) {
$part = $part == $this->controllerkey ? 'controller' : 'action';
throw new Exception('Incorrect ' . $part . ' name "' . $formattedName . '".');
}
return ltrim($formattedName, '_');
}
}
How to use it:
$request = new HttpRequest();
$request->setBaseUrl('/your/base/url/');
$request->createRequest();
echo $request->getControllerClassName(); // return controller name. Controller name separated by '-' is going to be converted to camel case.
var_dump ($request->getParameters()); // print all other parameters $_GET & $_POST
.htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Your rewrite rule would pass the entire URL:
RewriteRule ^(.*)$ index.php?params=$1 [NC]
Your index.php would interpret that full path as controller/param/value/param/value for you (my PHP is a little rusty):
$params = explode("/", $_GET['params']);
if (count($params) % 2 != 1) die("Invalid path length!");
$controller = $params[0];
$my_params = array();
for ($i = 1; $i < count($params); $i += 2) {
$my_params[$params[$i]] = $params[$i + 1];
}
How about redirect to index.php?params=param/value/param/value, and let php split the whole $_GET['params']? I think this is the way wordpress handling it.
For some reason, the selected solution did not work for me. It would constantly only return "index.php" as value of params.
After some trial and error, I found the following rules to work well. Assuming you want yoursite.com/somewhere/var1/var2/var3 to point to yoursite.com/somewhere/index.php?params=var1/var2/var3, then place the following rule in a .htaccess file in the "somewhere" directory:
Options +FollowSymLinks
RewriteEngine On
# The first 2 conditions may or may not be relevant for your needs
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-f
# This rule converts your flat link to a query
RewriteRule ^(.*)$ index.php?params=$1 [L,NC,NE]
Then, in PHP or whichever language of your choice, simply separate the values using the explode command as pointed out by #Wesso.
For testing purposes, this should suffice in your index.php file:
if (isset($_GET['params']))
{
$params = explode( "/", $_GET['params'] );
print_r($params);
exit("YUP!");
}
Is this what your looking for?
This example demonstrates how to easily hide query string parameters using loop flag. Suppose you have URL like http://www.mysite.com/foo.asp?a=A&b=B&c=C and you want to access it as http://www.myhost.com/foo.asp/a/A/b/B/c/C
Try the following rule to achieve desired result:
RewriteRule ^(.*?\.php)/([^/]*)/([^/]*)(/.+)? $1$4?$2=$3 [NC,N,QSA]
Are you sure you are using apache server,.htaccess works only on apache server. If you are using IIS then web.config is reqired. In that case:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Homepage">
<match url="Homepage"/>
<action type="Rewrite" url="index.php" appendQueryString="true"/>
</rule>
</rules>
</rewrite>
<httpErrors errorMode="Detailed"/>
<handlers>
<add name="php" path="*.php" verb="*" modules="IsapiModule" scriptProcessor="C:\Program Files\Parallels\Plesk\Additional\PleskPHP5\php5isapi.dll" resourceType="Unspecified"/>
</handlers>
</system.webServer>
</configuration>