.htaccess 重写 GET 变量

Posted

技术标签:

【中文标题】.htaccess 重写 GET 变量【英文标题】:.htaccess rewrite GET variables 【发布时间】:2011-12-02 09:17:45 【问题描述】:

我有一个 index.php 来处理所有路由 index.php?page=controller(简化),只是为了将逻辑与视图分开。

Options +FollowSymlinks
RewriteEngine on
RewriteCond %REQUEST_FILENAME !-f
RewriteCond %REQUEST_FILENAME !-d
RewriteRule ^([\w\d~%.:_\-]+)$ index.php?page=$1 [NC]

这基本上是: http://localhost/index.php?page=controller 到

http://localhost/controller/

谁能帮我添加重写

http://localhost/controller/param/value/param/value(等等)

那就是:

http://localhost/controller/?param=value&param=value

我无法让它与 Rewriterule 一起使用。

控制器可能如下所示:

    <?php
if (isset($_GET['action'])) 
 if ($_GET['action'] == 'delete') 
do_Delete_stuff_here();


?>

还有:

    <?php
if (isset($_GET['action']) && isset($_GET['x'])) 
 if ($_GET['action'] == 'delete') 
do_Delete_stuff_here();


?>

【问题讨论】:

另见Everything You Ever Wanted to Know about Mod_Rewrite Rules but Were Afraid to Ask? 你想做的事情没有多大意义恕我直言。我的意思是,替换 & 和 = 并没有真正提高可读性。此外,它不允许您使用无价值的查询字符串。 【参考方案1】:

基本上人们想说的是,你可以像这样制定一个重写规则:

RewriteRule ^(.*)$ index.php?params=$1 [NC, QSA]

这将使您的实际 php 文件如下所示:

index.php?params=param/value/param/value

而你的实际 URL 应该是这样的:

http://url.com/params/param/value/param/value

在您的 PHP 文件中,您可以通过像这样爆炸来访问您的参数:

<?php

$params = explode( "/", $_GET['params'] );
for($i = 0; $i < count($params); $i+=2) 

  echo $params[$i] ." has value: ". $params[$i+1] ."<br />";



?>

【讨论】:

.htaccess 似乎不起作用。当我尝试访问 localhost/params/param/value 时,我被重定向 404。 当你只尝试放 localhost/params 会发生什么? 这是旧的,但为了将来参考,我对此进行了测试,但它不起作用(params 给了我'index.php')。我通过添加QSA flag 解决了这个问题,所以,我有[NC,QSA] 而不是[NC]。此外,它看起来像这样:index.php?params=params/param/value/param/value,所以可以删除 params 并保持这样的状态:http://url.com/param/value/param/value【参考方案2】:

我认为最好将所有请求重定向到 index.php 文件,然后使用 php 提取控制器名称和任何其他参数。与 Zend Framework 等任何其他框架相同。

这是一个简单的类,可以做你想做的事。

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, '_');
    

如何使用:

$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 文件:

RewriteEngine On
RewriteCond %REQUEST_FILENAME -s [OR]
RewriteCond %REQUEST_FILENAME -l [OR]
RewriteCond %REQUEST_FILENAME -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

【讨论】:

这也是我推荐的。效果也很好。 嗨。我已经使用了您的解决方案,它在本地主机上运行完美。但是当我尝试在动态托管服务器上部署我的应用程序时,它根本不起作用。你能告诉我 .htaccess 指令的每一行是什么意思吗?如果我理解那些 Rewrite 指令的含义,也许我可以解决这个问题。谢谢。 1 - 启用重写引擎 2 - 如果请求针对现有文件或 3 - 如果请求针对现有符号链接或 4 - 如果请求针对现有目录。 5 - 如果这些条件中的任何一个为真,则正常处理请求。 ELSE 6 - 将请求重定向到 index.php【参考方案3】:

您的重写规则将传递整个 URL:

RewriteRule ^(.*)$ index.php?params=$1 [NC]

您的 index.php 会将完整路径解释为您的控制器/参数/值/参数/值(我的 PHP 有点生疏):

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

【讨论】:

【参考方案4】:

重定向到index.php?params=param/value/param/value,然后让php拆分整个$_GET['params']怎么样?我认为这是 wordpress 处理它的方式。

【讨论】:

为此创建一个重写规则是可能的,但是让 php 代码处理它要简单得多。【参考方案5】:

这是你要找的吗?

本示例演示了如何使用循环标志轻松隐藏查询字符串参数。假设你有像http://www.mysite.com/foo.asp?a=A&b=B&c=C 这样的 URL,并且你想以 http://www.myhost.com/foo.asp/a/A/b/B/c/C 的身份访问它

尝试以下规则以获得所需的结果:

RewriteRule ^(.*?\.php)/([^/]*)/([^/]*)(/.+)? $1$4?$2=$3 [NC,N,QSA]

【讨论】:

所以,我只是尝试实际测试此规则,我的共享主机立即冻结。我不想 D/V,因为它是一个不好的建议,没有确认这是一个非常危险的规则(可能是别的东西,甚至是我的其他规则导致了这个问题)但同时我真的不是想再试一次,可能会激怒我的托管服务提供商。 绝对是这个规定。尝试了干净的 WAMP 安装。这似乎是一个可靠的想法,但以目前的形式来说太危险了。【参考方案6】:

由于某种原因,所选的解决方案对我不起作用。它只会返回“index.php”作为参数的值。

经过反复试验,我发现以下规则运行良好。假设您希望 yoursite.com/somewhere/var1/var2/var3 指向 yoursite.com/somewhere/index.php?params=var1/var2/var3,然后将以下规则放在“某处”的 .htaccess 文件中目录:

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]

然后,在 PHP 或您选择的任何语言中,只需使用 @Wesso 指出的 explode 命令分隔值。

出于测试目的,这在您的 index.php 文件中就足够了:

if (isset($_GET['params']))

    $params = explode( "/", $_GET['params'] );
    print_r($params);
    exit("YUP!");

【讨论】:

【参考方案7】:

您确定您使用的是 apache 服务器吗?.htaccess 仅适用于 apache 服务器。如果您使用的是 IIS,则需要 web.config。在这种情况下:

<?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>

【讨论】:

以上是关于.htaccess 重写 GET 变量的主要内容,如果未能解决你的问题,请参考以下文章

htaccess mod 用斜杠将 $_GET 重写为变量

.htaccess 重写 url 帮助使用 GET 变量指向 URL 中的值 [关闭]

重写规则问题:.htaccess

在 XAMPP 中使用 .htaccess local 重写 URL

如何在php中重写Get变量的url [重复]

htaccess 重写 URL 以仅删除一个 php 文件的 $_GET 查询[重复]