管理自己的PHP框架的URL路径(Manage URL routes in own php fram

2019-07-30 18:13发布

我创建一个PHP框架,我有一些疑问......

这个框架中的URL是这样的: http:/web.com/site/index

它需要的第一个参数装入控制器( site ),然后加载的特定动作( index )。

如果你已经安装的基础URL的框架工作正常,但如果你安装它在这样的子文件夹: http://web.com/mysubfolder/controller/action

我的脚本解析它为controller = mysubfolder和行动= controller

如果您有更多的子文件夹的结果将是最糟糕的。

这是我的路线代码:

Class Route
{
    private $_htaccess = TRUE;
    private $_suffix = ".jsp";

    public function params()
    {
        $url='';

        //nombre del directorio actual del script ejecutandose.
        //basename(dirname($_SERVER['SCRIPT_FILENAME']));

        if($this->_htaccess !== FALSE):
            //no está funcionando bien si está en un subdirectorio web, por ej stynat.dyndns.org/subdir/
            // muestra el "subdir" como primer parámetro
            $url = $_SERVER['REQUEST_URI'];
            if(isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])):
                $url = str_replace("?" . $_SERVER['QUERY_STRING'], '',$url);
            endif;
        else:
            if(isset($_SERVER['PATH_INFO'])):
                $url = $_SERVER['PATH_INFO'];
            endif;
        endif;

        $url = explode('/',preg_replace('/^(\/)/','',$url));
        var_dump($url);

        var_dump($_GET);

    }
}

谢谢你提供的所有帮助。

Answer 1:

你缺少一个基本路径。 路由脚本现在必须检测检测图案或路由时从哪里开始。

伪代码:

 //set the base URI
$base_uri = '/base';
//remove the base URI from the original uri. You can also REGEX or string match against it if you want
$route_uri = str_replace($base_uri,'',$uri);
//perform route matching $route_uri, in your code a simple explode

$url = explode('/',preg_replace('/^(\/)/','',$route_uri));

index.php文件 - 你可以,只要他们使用相同的线束带或不带RewriteBase用这个你的.htaccess。

此外,还可以使用正则表达式的功能类似的preg_match和preg_match_all提高您的路由匹配的过程。 他们让你定义一个模式来匹配和结果匹配字符串数组-见http://php.net/manual/en/function.preg-match.php 。



Answer 2:

是的,我想我知道如何解决这个问题。

(声明:我知道你知道大多数的这一点,但我会解释一切为别人谁可能不知道的一些陷阱的)

使用PATH_INFO和的.htaccess

PHP中一招,如果你去像一个路径,其中:

http://web.com/mysubfolder/index.php/controller/action

你会得到在“/控制器/动作” $_SERVER['PATH_INFO']变量

现在,你需要做的是采取.htaccess文件(或同等学历),并告诉它你的PHP脚本当前文件夹的深度。

要做到这一点,把.htaccess文件到“mysubfolder”

mysubfolder
    .htaccess
    index.php

的.htaccess应包含以下内容:

RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule (.*) index.php/$1

(I使用的Yii框架手册作为参考,我也建议使用HTML5样板 )

基本上你设置它在URL中的特定点的一切index.php文件重定向。

现在,如果你访问: http://web.com/mysubfolder/index.php/controller/action

现在,你可以从正确的道路“/控制器/动作” $_SERVER['PATH_INFO']

除了它不会有任何价值,如果你访问http://web.com/mysubfolder/因为.htaccess文件会忽略重写,因为http://web.com/mysubfolder/路径请求mysubfolder / index.php文件这实际上存在和被剥夺感哟RewriteCond %{REQUEST_FILENAME} !-f

ifsetor功能

为此,您可以使用此称为超级方便的功能ifsetor (我不记得在那里我得到了它)

function ifsetor(&$variable, $default = null) {
    return isset($variable)? $variable: $default;
}

它所做的是采取一个变量的引用可能会或可能不存在,并提供一个默认的,如果它不存在,没有抛出任何通知或错误

现在你可以用它来拍摄的PATH_INFO变量安全,像这样

在你的index.php

function ifsetor(&$variable, $default = null) {
    return isset($variable)? $variable: $default;
}
$path = ifsetor($_SERVER['PATH_INFO'],'/');
var_dump($path);

PHP 5.4也有,如果你不关心的通知,你可以使用这个新的更短的三元格式(我)

$path = $_SERVER['PATH_INFO']?:'/';

处理QUERY_STRING

现在tecnically你没有得到一个URL,它仅仅是它的路径部分和来访时将不包含QUERY_STRING,例如

http://web.com/mysubfolder/index.php/test?param=val

你只会得到“/测试”在$ PATH变量,以获取查询字符串中使用$_SERVER['QUERY_STRING']变量

的index.php

function ifsetor(&$variable, $default = null) {
    return isset($variable)? $variable: $default;
}
$path = ifsetor($_SERVER['PATH_INFO'],'/');
$fullpath = ($_SERVER['QUERY_STRING'])? $path.'?'.$_SERVER['QUERY_STRING']:$path;
var_dump($fullpath);

但是,这可能取决于你的需求

$ _ SERVER [ 'QUERY_STRING'] VS $ _GET

也请记住, $_SERVER['QUERY_STRING']变量是从不同的$_GET$_REQUEST变量,因为它不断重复的参数从查询字符串,例如:

访问此页

http://web.com/mysubfolder/controller/action?foo=1&foo=2&foo=3

如果要给你一个$_SERVER['QUERY_STRING']看起来像

?foo=1&foo=2&foo=3

虽然$_GET变量将是这样一个数组:

array(
    'foo'=>'3'
);

如果你不具备的.htaccess

你可以尝试使用SCRIPT_NAME你的优势

list($url) = explode('?',$_SERVER['REQUEST_URI']);
list($basepath) = explode('index.php',$_SERVER['SCRIPT_NAME']);
$url = substr($url,strlen($basepath));

如果您想炸毁的东西像我:)

你的情况下,

Class Route
{
private $_htaccess = TRUE;
private $_suffix = ".jsp";

public function params()
{
    $url='';

    //nombre del directorio actual del script ejecutandose.
    //basename(dirname($_SERVER['SCRIPT_FILENAME']));

    if($this->_htaccess !== FALSE):
        //no está funcionando bien si está en un subdirectorio web, por ej stynat.dyndns.org/subdir/
        // muestra el "subdir" como primer parámetro
        list($url) = explode('?',$_SERVER['REQUEST_URI']);
        $basepath = dirname($_SERVER['SCRIPT_NAME']);
        $basepath = ($basepath==='/')? $basepath: $basepath.'/';
        $url = substr($url,strlen($basepath));
    else:
        if(isset($_SERVER['PATH_INFO'])):
            $url = $_SERVER['PATH_INFO'];
            $url = preg_replace('|^/|','',$url);
        endif;
    endif;

    $url = explode('/',$url);
    var_dump($url);

    var_dump($_GET);


}
}

我希望这有帮助

PS抱歉这么晚才回复:(



Answer 3:

即使您正在创建自己的框架,没有理由不重用健壮,很好的测试和记录组件 ,这样路由组件。

只要使用作曲 ,这已成为PHP依赖管理的标准,你会被罚款。 只要你想你的筹码添加为许多组件。

在这里,你有一个必须阅读 指南就如何使自己的框架。



Answer 4:

在一些点,你将不得不检查$ _SERVER [“HTTP_HOST”]和由程序员/用户至极定义一个配置变种指示了应用程序所在的子文件夹(多个),并取出部分你不感兴趣的从该URL的其余部分。

您可以检查此论坛的帖子上的笨formus了一些提示。

CodeIgniter使用另一不同的方式来路由内部控制器/方法。 你如果想通过路由$_SERVER['PATH_INFO']值。 您可以使用的URL是这样的: myapp.com/index.php/controller/method

为避免在您必须依赖于一个Apache重写规则的URI的index.php,但即便如此我认为一个CI是一个很好的解决方案,一旦你有你的索引文件的位置,就可以避免解析的所有麻烦URL。



Answer 5:

如果我理解你是什么正确后,再一种解决方案可能是继续做你正在做什么,而且(例如使用真实路径())让主路由脚本的路径。

如果最后一个文件夹(或文件夹等之前)开始的URL项(或其他部分)相匹配,你忽略它,去下一个。

只是我的2美分:-)。



Answer 6:

在应用程序配置脚本地方将被设置为应用程序运行在路径的变量。

另一种方法是动态地设置该路径。

部分前

$url = explode('/',preg_replace('/^(\/)/','',$url));

剥除位置(子文件夹)路径出的$url使用预定义的应用程序的路径串。



Answer 7:

我这是怎么实现的loader.php

   <?php
/*@author arun ak
auto load controller class and function from url*/
class loader
{
    private $request;
    private $className;
    private $funcName;

    function __construct($folder    = array())
    {   
        $parse_res  = parse_url($this->createUrl());
        if(!empty($folder) && trim($folder['path'],DIRECTORY_SEPARATOR)!='')
         {
            $temp_path  = explode(DIRECTORY_SEPARATOR,trim($parse_res['path'],DIRECTORY_SEPARATOR));
            $folder_path    = explode(DIRECTORY_SEPARATOR,trim($folder['path'],DIRECTORY_SEPARATOR));
            $temp_path      = array_diff($temp_path,$folder_path);

                if(empty($temp_path))
                {
                    $temp_path =    '';
                }
         }else
         {
            if(trim($parse_res['path'],DIRECTORY_SEPARATOR)!='')
            {
             $temp_path = explode(DIRECTORY_SEPARATOR,trim($parse_res['path'],DIRECTORY_SEPARATOR));
            }
                 else
             $temp_path ='';
         }
        if(is_array($temp_path))
        {   
            if(count($temp_path) ==1)
            {
                array_push($temp_path,'index');
            }
            foreach($temp_path as $pathname)
            {   
                $this->request .= $pathname.':';
            }
        }
        else $this->request = 'index'.':'.'index';

    }

 private function createUrl()
 {  
    $pageURL  = (@$_SERVER["HTTPS"] == "on") ? "https://" : "http://";
    $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
    return $pageURL;
 }
 public function autolLoad()
 {
    if($this->request) 
    {   
        $parsedPath = explode(':',rtrim($this->request,':'));
        if(is_file(APPLICATION_PATH.DIRECTORY_SEPARATOR.'controllers'.DIRECTORY_SEPARATOR.$parsedPath[0].'_controller'.'.php'))
        {
            include_once(APPLICATION_PATH.DIRECTORY_SEPARATOR.'controllers'.DIRECTORY_SEPARATOR.$parsedPath[0].'_controller'.'.php');
            if(class_exists($parsedPath[0].'_controller'))
            {
                $class  = $parsedPath[0].'_controller';
                $obj    = new $class();
                //$config       = new config('localhost','Winkstore','nCdyQyEdqDbBFpay','mawinkcms');
                //$connect  =  connectdb::getinstance();
                //$connect->setConfig($config);
                //$connection_obj = $connect->connect();
                //$db               = $connect->getconnection();//mysql link object
                //$obj->setDb($db);
                $method = $parsedPath[1];
                if(method_exists ($obj ,$parsedPath[1] ))
                {
                    $obj->$method();
                }else die('class method '.$method.' not defined');

            }else die('class '.$parsedPath[0]. ' has not been defined' );

        } else die('controller not found plz define one b4 u proceed'.APPLICATION_PATH.DIRECTORY_SEPARATOR.'controllers'.DIRECTORY_SEPARATOR.$parsedPath[0].'.php');

     }else{ die('oops request not set,i know tis is not the correct way to error :)'); }
 }

}

现在在我的索引文件

//include_once('config.php');
include_once('connectdb.php');
require_once('../../../includes/db_connect.php');
include_once('view.php');
include_once('abstractController.php');
include_once('controller.php');
include_once('loader.php');
$loader = new loader(array('path'=>DIRECTORY_SEPARATOR.'magsonwink'.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.'admin'.DIRECTORY_SEPARATOR.'atom'.DIRECTORY_SEPARATOR));
$loader->autolLoad();

我没有使用过modules.only控制器动作和视图的概念呈现。



Answer 8:

你确定你有你htaccess是否正确?

我想,如果你把你的框架subfolder ,那么你有你的改变RewriteBasehtaccess文件从//subfolder/ 。 这将是这样的:

# on root
RewriteBase /

#on subfolder
RewriteBase /subfolder/

这是我能在你的情况不知道的那些事儿......



Answer 9:

我不使用OOP,但可以告诉你我是如何做的一些片段,如果我在一个子目录是动态检测。 也尽量简短扼要,我只能形容它的一部分,而不是发布的所有代码。

于是,我开始了一个.htaccess是发送每个请求redirect.php中,我拼接起来的$_SERVER['REQUEST_URI']变量。 我用正则表达式来决定哪些部分应该是钥匙应该是什么值(我这样做是通过分配任何与0-9开始作为一种价值,和任何与AZ为重点开始),并建立数组$GET[]

然后我检查redirect.php和比较,我的路径$GET阵列,决定在哪里实际的URL开始-或者你的情况下,关键是控制器。 会是这个样子的你:

$controller = keyname($GET, count(explode('/', dirname($_SERVER['SCRIPT_NAME']))));

就是这样,我有URL的第一部分。 该keyname()函数如下:

/*************************************
 *  get key name from array position
 *************************************/
function keyname ($arr, $pos)
{
    $pos--;
    if ( ($pos < 0) || ( $pos >= count($arr) ) )
          return "";  // set this any way you like

    reset($arr);
    for($i = 0;$i < $pos; $i++) next($arr);

    return key($arr);
}

为了得到正确的指点我用一个调用的函数的链接fixpath()是这样的:

print '<a href="'.fixpath('/admin/logout').'">link</a>';

这是该函数的样子:

/*************************************
 *   relative to absolute path
 *************************************/
function fixpath ($path)
{
    $root = dirname($_SERVER['SCRIPT_NAME']);
    if ($root == "\\" || $root == ".") {
        $root = "";
    }
    $newpath = explode('/', $path);
    $newpath[0] .= $root;
    return implode('/', $newpath);    
}

我希望帮助,可以给你一些启示。



Answer 10:

忘了“重新发明轮子是错误的”索赔。 他们没有使用我们的车轮。 前一阵子我在同一条道路上走了进来,我完全感谢我得到什么......我希望你能过

当谈到回答您的具体问题哪位如果面对too-有一个很简单的解决方案。 它在根文件夹在.htaccess新线...

只需添加下面的根.htaccess文件行; (如果你的subfoler是“子文件夹”)

RewriteRule subfolder/ - [L]

这将使除了改写指令该文件夹

通过这种方式你愿意,你可以安装你的框架的多个实例。 但是,如果你想要这个驱动是框架,那么你必须创建/你的框架内改变的.htaccess。



Answer 11:

创建/myBaseDirectory/public目录,并把你的文件存在-就像index.php
这工作,因为Apache的看到这个目录像基本目录。



Answer 12:

基本上抓住你的第一斜线后的URL字符串,然后将其爆炸成一个阵列(我使用“/”作为分隔符)。

然后仔细array_shift了你的元素,并将它们保存为变量

item 0: controller
item 1: the action / method in that controller
item 2 thru n: the remaining array is your params


文章来源: Manage URL routes in own php framework