我创建一个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
,那么你有你的改变RewriteBase
在htaccess
文件从/
到/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