dsdt66064367 2015-10-07 21:54
浏览 63
已采纳

如何从路由器制作好的重写网址

I'm making a toolkit for php applications. I've a made a routing system based on some conventions, it works well but i would like to learn how to make mod_rewrite rules or any other stuff to finally make the url good to see and good for seo.

The route system starts from a config file that set the app and url roots.

$app_root = $_SERVER["DOCUMENT_ROOT"].dirname($_SERVER["PHP_SELF"])."/";
$app_url = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
define("APP_URL",$app_url);
define("APP_ROOT",$app_root);

The route always get start from index.php, wich makes instances of controllers@actions from GET parameters controllers=?&action=?

This is the index.php

    <?php
include_once 'controller/Frontend.php';
require 'libraries/Router.php';
$params=array();
    if(isset($_GET['controller'])&&isset($_GET['action'])){
        $c = $_GET['controller'];   
        $a = $_GET['action'];    
        // add all query string additional params to method signature i.e. &id=x&category=y
        $queryParams = array_keys($_GET);
        $queryValues = array_values($_GET);
            for ($i=2;$i<count($queryParams);$i++) {
                $params[$queryParams[$i]] = $queryValues[$i];   
            }

    if ($_POST) {
    // add all query string additional params to method signature i.e. &id=x&category=y
    $queryParams = array_keys($_POST);
    $queryValues = array_values($_POST);
            for ($i=0;$i<count($_POST);$i++) {
                $params[$queryParams[$i]] = $queryValues[$i];   
            }
            }
    include_once APP_ROOT."/controller/$c.php";
    $controller = new $c();
    $controller->$a($params);

    }  else {   
    //attiva controller predefinito    
    $controller = new Frontend();
    $controller->index();
    }

This allow to select what controller and what action the router must call.

The router function here get the APP URL from settings.php in the root. You give im the two controllers@action params as string and it make the URL like so: index.php?controller=X&action=Y&[params...]

<?php

require './settings.php';

    function router($controller,$action,$query_data="") {
    $param = is_array($query_data) ? http_build_query($query_data) : "$query_data";
    $url = APP_URL."index.php?controller=$controller&action=$action&$param";
    return $url;
}
    function relativeRouter ($controller,$action,$query_data=""){
    $param = is_array($query_data) ? http_build_query($query_data) : "$query_data";
    $url = "index.php?controller=$controller&action=$action&$param";
    return $url;
}
    function redirectToOriginalUrl() {
        $url = $_SERVER['HTTP_REQUEST_URI'];
        header("location: $url");
    }

    function switchAction ($controller, $action) {
        $r = router($controller, $action);
        header("location:$r", true, 302);
    }

In templates file i call router('controller,'action') to retrive url's to actions and also pass GET/POST data (collected from index.php that put's them into the method signature as array).

Don't blame me for using global POST/GET without filtering i'm still developing the thing, security things will be made after ;)

What i would like to ask if someone could share some thoughts on how to make pretty urls like site/page/action.... For example www.site.com/blog/post?id=1

(Actually the N params in the router function ($query_data) works this way, you pass array['id' => '1'] and you get ?id=1)

What are best strategies to make good urls? Thank you so much, still learning PHP.

If there are best way to do such things just give your feedback.

  • 写回答

1条回答 默认 最新

  • dongwu9063 2015-10-10 09:35
    关注

    I found myself an answer to the question, i post here maybe it's useful.

    I've added a .htaccess file in the root:

    Options -MultiViews
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [QSA,L]
    

    This will return each request to the root/index.php file.

    Index file collect routes from the HTTP request, check if the route exist in the "routes.json" file.

    URL are written in this way: site.com/controller/action. GET params are written as follows site.com/controller/action/[params]/[value]...... This output for example site.com/blog/post/id/1 That should be also fine for REST.

    Here the index.php

        <?php
    require 'controller/Frontend.php';
    require 'Class/Router.php';
    
    //require 'libraries/Router.php';
    /*
     * ** ROUTING SETTINGS **
     */
    $app_root = $_SERVER["DOCUMENT_ROOT"].dirname($_SERVER["PHP_SELF"])."/";
    $app_url = $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
    define("APP_URL",$app_url);
    define("APP_ROOT",$app_root);
    
    $basepath = implode('/', array_slice(explode('/', $_SERVER['SCRIPT_NAME']), 0, -1));
    $uri = substr($_SERVER['REQUEST_URI'], strlen($basepath));
    //echo $uri;
    if ($uri == "/") {
        $frontend = new Frontend();
        $frontend->index();
    } else {
        $root = ltrim ($uri, '/');
        //$paths = explode("/", $uri);
        $paths = parse_url($root, PHP_URL_PATH);
        $route = explode("/",$paths);
        $request = new \PlayPhp\Classes\Request();
        // controller
        $c = $route[0];
        // action
        $a = $route[1];
    
        $reverse = Router::inverseRoute($c,$a);
    
        $rest = $_SERVER['REQUEST_METHOD'];
        switch ($rest) {
            case 'PUT':
                //rest_put($request);
                break;
            case 'POST':
                if (Router::checkRoutes($reverse, "POST")) {
                    foreach ($_POST as $name => $value) {
                        $request->setPost($name,$value);
                    }
                    break;
                } else {
                    Router::notFound($reverse,"POST");
                }
            case 'GET':
                if (Router::checkRoutes($reverse, "GET")) {
                    for ($i = 2; $i < count($route); $i++) {
                        $request->setGet($route[$i], $route[++$i]);
                    }
                    break;
                } else {
                    Router::notFound($reverse,"GET");
                }
                break;
            case 'HEAD':
                //rest_head($request);
                break;
            case 'DELETE':
                //rest_delete($request);
                break;
            case 'OPTIONS':
                //rest_options($request);
                break;
            default:
                //rest_error($request);
                break;
        }
    
    
    
        include_once APP_ROOT.'controller/'.$c.'.php';
        $controller = new $c();
        $controller->$a($request);
    
    
    }
    

    The Router class:

        <?php
    
    include 'config/app.php';
    /*
     * Copyright (C) 2015 yuri.blanc
    */
    require 'Class/http/Request.php';
    class Router {
        protected static $routes;
    
        private function __construct() {
            Router::$routes = json_decode(file_get_contents(APP_ROOT.'config/routes.json'));
        }
    
        public static function getInstance(){
            if (Router::$routes==null) {
               new Router();
            }
            return Router::$routes;
        }
    
        public static function go($action,$params=null) {
            $actions = explode("@", $action);
            $c = strtolower($actions[0]);
            $a     = strtolower($actions[1]);
            // set query sting to null
            $queryString = null;
            if(isset($params)) {
    
                foreach ($params as $name => $value) {
                    $queryString .= '/'.$name.'//'.$value;
                }
    
                return APP_URL."$c/$a$queryString";
            } 
            return APP_URL."$c/$a";
        }
    
    
         public static function checkRoutes($action,$method){
             foreach (Router::getInstance()->routes as $valid) {
              /*   echo $valid->action . ' == ' . $action . '|||';
                 echo $valid->method . ' == ' . $method . '|||';*/
                 if ($valid->method == $method && $valid->action == $action) {
                     return true;
                 }
             }
         }
    
        public static function inverseRoute($controller,$action) {
            return ucfirst($controller)."@".$action;
        }
        public static function notFound($action,$method) {
    
            die("Route not found:: $action with method $method");
    
        }
    
    
    
    }
    

    I use the json_decode function to parse the json object in stdClass().

    The json file looks like this:

        {"routes":[
      {"action":"Frontend@index", "method":"GET"},
      {"action":"Frontend@register", "method":"GET"},
      {"action":"Frontend@blog", "method":"GET"}
    ]}
    

    This way i can whitelist routes with their methods and return 404 errors while not found.

    System is still quite basic but gives and idea and works, hope someone will find useful.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Matlab怎么求解含参的二重积分?
  • ¥15 苹果手机突然连不上wifi了?
  • ¥15 cgictest.cgi文件无法访问
  • ¥20 删除和修改功能无法调用
  • ¥15 kafka topic 所有分副本数修改
  • ¥15 小程序中fit格式等运动数据文件怎样实现可视化?(包含心率信息))
  • ¥15 如何利用mmdetection3d中的get_flops.py文件计算fcos3d方法的flops?
  • ¥40 串口调试助手打开串口后,keil5的代码就停止了
  • ¥15 电脑最近经常蓝屏,求大家看看哪的问题
  • ¥60 高价有偿求java辅导。工程量较大,价格你定,联系确定辅导后将采纳你的答案。希望能给出完整详细代码,并能解释回答我关于代码的疑问疑问,代码要求如下,联系我会发文档