如何为插入动态链接的网站设置URL重写

时间:2017-12-31 19:12:01

标签: php .htaccess url

我正在尝试建立用户可以使用WYSIWYG编辑器发布内容的网站。在我的.htaccess文件中我有

 FallbackResource index.php

成功将所有请求发送到index.php文件。然后我使用PHP来获取所需的文件

$path = explode('/', $_SERVER['REQUEST_URI']);
//[SCRIPT_FILENAME] => C:/xampp/htdocs/tests/index.php
if($path[2] == 'notifications'){
    require_once 'notifications.php';
}

这一切都很好。当我尝试重定向到google.com等外部链接时出现问题。链接本身被重定向到索引页面而不是被重定向。 这是关键,因为用户可以使用WYSIWYG编辑器在其文本中插入其他网站的标记作为参考。所以我的问题是,我这样做是对吗还是我需要一种不同的方法?如果是的话,采用哪种方法?我非常感谢facebook或twitter等网站使用的类似方法。

1 个答案:

答案 0 :(得分:0)

AS的方法我将使用类似于CodeIgniter或其他MVC框架的方法(但更简单)。

首先你必须设计一个模式,我的意思是这样的

   www.yoursite.com/index.php/{controller}/{method}/args ...

然后你会构建一个路由器去解析url。我可以给你写一个,但这需要一分钟。

更新

您可以在我的github页面here

上找到它

但是对于参考,这里是代码:

SimpleRouter.php

/**
 * A simple 1 level router
 * 
 * URL schema is http://example.com/{controller}/{method}/{args ... }
 * 
 * @author ArtisticPhoenix
 * @package SimpleRouter
 */
class SimpleRouter{

    /**
     * should be the same as rewrite base in .htaccess
     * @var string
     */
    const REWRITE_BASE = '/MISC/Router/';

    /**
     * path to controller files
     * 
     * @var string
     */
    const CONTOLLER_PATH = __DIR__.'/Controllers/';

    /**
     * route a url to a controller
     */
    public static function route(){
        //normalize
        if(self::REWRITE_BASE != '/'){
            $uri = preg_replace('~^'.self::REWRITE_BASE.'~i', '',$_SERVER['REQUEST_URI']);
        }
        $uri = preg_replace('~^index\.php~i', '',$uri);      
        $uri = trim($uri,'/');

        //empty url, like www.example.com
        if(empty($uri)) $uri = 'home/index';

        //empty method like www.example.com/home
        if(!substr_count($uri, '/')) $uri .= '/index';

        $arrPath = explode('/', $uri);

        $contollerName = array_shift($arrPath);
        $methodName = array_shift($arrPath);;
        $contollerFile = self::CONTOLLER_PATH.$contollerName.'.php';

        if(!file_exists($contollerFile)){
            //send to error page
            self::error404($uri);
            return;
        }

        require_once $contollerFile;

        if(!class_exists($contollerName)){
            self::error404($uri);
            return;
        }

        $Controller = new $contollerName();

        if(!method_exists($Controller, $methodName)){
            self::error404($uri);
            return;
        }

        if(!count($arrPath)){
            call_user_func([$Controller, $methodName]);
        }else{
            call_user_func_array([$Controller, $methodName], $arrPath);
        } 
    }

    /**
     * call error 404
     * 
     * @param string $uri
     */
    protected static function error404($uri){
        require_once self::CONTOLLER_PATH.'home.php';     
        $Controller = new home();
        $Controller->error404($uri);
    }
}

默认控制器home.php

/**
 * 
 * The default controller
 * 
 * @author ArtisticPhoenix
 * @package SimpleRouter
 */
class home{

    public function index($arg=false){
        echo "<h3>".__METHOD__."</h3>";
        echo "<pre>";
        print_r(func_get_args());
    }

    public function otherpage($arg){
        echo "<h3>".__METHOD__."</h3>";
        echo "<pre>";
        print_r(func_get_args());
    }

    public function error404($uri){
        header('HTTP/1.0 404 Not Found');
        echo "<h3>Error 404 page {$uri} not found</h3>";
    }

}

第二控制器(示例)user.php

/**
 *
 * An example users router
 *
 * @author ArtisticPhoenix
 * @package SimpleRouter
 */
class user{

    public function index(){
        echo "<h3>".__METHOD__."</h3>";
    }


    public function login(){
        echo "<h3>".__METHOD__."</h3>";
    }

}

重写(删除index.php).htaccess

 RewriteEngine On

# For sub-foder installs set your RewriteBase including trailing and leading slashes
# your rewrite base will vary, possibly even being / if no sub-foder are involved
RewriteBase /MISC/Router/

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

最后是index.php

require_once __DIR__.'/SimpleRouter.php';
SimpleRouter::route();

我对路由器进行static调用只是为了简单起见,这样就不需要只有2个方法(1个公共)的类的实例。

我将它构建为单级路由器,我的意思是你不能将控制器放在子文件夹中,例如Controllers/user/home.php而不是Controllers/user.php。对于中小型站点,这应该没问题,但对于不同的大型站点,可能需要嵌套控制器。然而,这增加了一堆复杂性。

这种方式的优势应该是显而易见的,而不是单独创建路线。只要路径(网址)遵循我概述的简单模式,您就不必触摸代码。这还允许您按功能在自己的文件中组织站点的各个部分。例如,取user.php控制器。是否允许您将所有功能放在一个位置,例如登录,配置文件,注销页面等......

如果您要添加member.php控制器,您可以将您想要显示的所有内容放入登录用户。然后在该控制器的__construct方法中检查当前会话是否已登录,并且它涵盖了该文件的所有方法。

网址架构是http://example.com/{controller}/{method}/{args ... }。但您也可以使用此http://example.com/index.php/{controller}/{method}/{args ... }这样的网址。我正在使用Mod Rewrite来删除URL中的index.php,所以如果你没有,那么你必须将index.php放在URL中(或者将其删除意味着)

REWRITE_BASE 在我的本地测试服务器上,我只是将所有内容放在自己的文件夹中,因为我懒得设置虚拟主机。因此,您希望更改此常量,并将匹配的.htaccess值设置为您的子文件夹(可能没有)。我只是把它留在这里,例如如何在子文件夹中使用它。

最后,这是传统MVC架构中的C。您应该避免在控制器中执行所谓的“业务逻辑”,您还应该避免直接从控制器输出HTML(尽管我在示例中这样做了)。我建议使用像BladeTwig这样的模板引擎,而不是输出HTML,这些引擎可以免费提供。想象一个控制器就像“胶水”一样,将“模型(业务逻辑)”加入到“视图(模板)”中。业务逻辑就像User类(大写U像名词,而不是我们的用户控制器中的小写),为用户处理数据库功能。因此,不是将该代码放在Controller中,而是构建一个“用户模型”并将其导入控制器。这是做到这一点的“正确方法”,但当然它预先增加了一些复杂性,但你会发现它的组织后来远远超过节省的时间。

现在有些例子

404错误(和错过的路线):

  • http://example.com/foo路由到home::error404()和输出<h3>Error 404 page foo/index not found</h3>

  • http://example.com/home/foo路由到home::error404()和输出<h3>Error 404 page home/foo not found</h3>

默认主页:

  • http://example.com/路由到home::index()
  • http://example.com/index.php路由到home::index()
  • http://example.com/home路由到home::index()
  • http://example.com/home/index路由到home::index()
  • http://example.com/home/index/hello路由到home::index('hello')
  • http://example.com/home/index/hello/world路由到home::index('hello','world')

就目前而言,你必须把完整的路径放在home的参数中,上面的代码可以改为考虑到这一点,但它对丢失的页面有一些影响。基本上任何缺失的页面都将成为控制器的参数。因此,如果您有http://example.com/user/foo,那么如果已完成,则会调用user::index('foo')。当然,这也可以解释,但复杂性开始叠加。

  • http://example.com/home/otherpage路由到home::otherpage(),但会发出错误参数警告。
    • http://example.com/home/otherpage/hello路由到home::otherpage('hello')
    • http://example.com/index.php/home/otherpage/hello路由到home::otherpage('hello')

如果你看:home::index($arg=false)定义了一个默认值,这个方法没有。所以这个方法需要一个参数。其余部分应该是非常自我解释的。

第二个控制器用户示例:

  • http://example.com/user路由到user::index()
  • http://example.com/user/index路由到user::index()
  • http://example.com/user/login路由到user::login()

其余部分基本相同,我只想展示如何通过功能为网站整理控制器。

我应该注意,这可以在网址中的{method}之后处理无限数量的参数。

享受!