John
John

Reputation: 3060

.htaccess rewrite GET variables

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&param=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();
}
}
?>

Upvotes: 30

Views: 112125

Answers (8)

Hakan
Hakan

Reputation: 623

use QSA

blabla.php?originialquery=333 RewriteRule ^blabla.php index.php?addnewquery1=111&addnewquery2=222 [L,NC,QSA] you will get all 111,222,333

Upvotes: -1

Wesley
Wesley

Reputation: 2200

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 />";

}

?>

Upvotes: 54

Nick
Nick

Reputation: 2613

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!");
}

Upvotes: 6

Kevin Stricker
Kevin Stricker

Reputation: 17388

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];
}

Upvotes: 10

Doug Chamberlain
Doug Chamberlain

Reputation: 11351

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]

Upvotes: 5

satrun77
satrun77

Reputation: 3220

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]

Upvotes: 15

Sibu
Sibu

Reputation: 4617

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>

Upvotes: 1

OpenGG
OpenGG

Reputation: 4560

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.

Upvotes: 6

Related Questions