我正在创建一个PHP框架,我有些疑惑......
框架以这种方式获取url:
http:/web.com/site/index
第一个参数加载控制器(site
),然后加载特定操作(index
)。
如果您已经在基本URL中安装了框架,则可以正常工作,但如果您将其安装在如下的子文件夹中:
http://web.com/mysubfolder/controller/action
我的脚本将其解析为控制器= 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);
}
}
感谢您提供任何帮助。
答案 0 :(得分:2)
您缺少基本路径。现在,路由脚本必须在检测到检测到的模式或路径时从哪里开始。
伪代码:
//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。
答案 1 :(得分:2)
是的,我想我知道如何解决这个问题。
(免责声明:我知道你知道大部分内容,但我会为其他可能不了解其中一些问题的人解释一切)
在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
(我使用yii framework manual作为参考,我还建议使用html5 boilerplate)
基本上你将它设置为在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
的超级方便的功能(我不记得我从哪里得到它)
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']?:'/';
现在tecnically你没有得到一个URL,它只是它的path部分,不会包含query_string,例如访问时
http://web.com/mysubfolder/index.php/test?param=val
你只会在$ path变量中获得'/ test',以使查询字符串使用$_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']
变量与$_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'
);
您可以尝试使用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);
}
}
我希望这会有所帮助
P.S。对不起,迟到的回复:(
答案 2 :(得分:1)
即使您正在创建自己的框架,也没有理由不重复使用健壮,经过良好测试和记录的components,就像这个Routing组件一样。
只需使用Composer,它已经成为PHP中依赖管理的标准,你会没事的。在堆栈中添加任意数量的组件。
在这里,你有 必须阅读 guide如何制作自己的框架。
答案 3 :(得分:0)
在某些时候你必须检查$ _SERVER ['HTTP_HOST']和程序员/用户定义的配置var,它指示应用程序所在的子文件夹,并删除你不感兴趣的部分从URL的其余部分开始。
您可以在codeigniter formus上查看this forum post以获取一些提示。
CodeIgniter使用另一种不同的方式在内部路由控制器/方法。
您可以通过$_SERVER['PATH_INFO']
值进行路由。您可以使用以下网址:myapp.com/index.php/controller/method
。
为了避免在uri上显示index.php,你必须依赖Apache重写规则,但即便如此,我认为CI是一个很好的解决方案,一旦你有索引文件位置,你可以避免所有的麻烦解析URL。
答案 4 :(得分:0)
如果我正确理解你的内容,那么一个解决方案可能是继续做你正在做的事情,但也得到主路由脚本的路径(例如使用realpath())。
如果最后一个文件夹(或之前的文件夹等)与起始网址项(或其他部分)匹配,则忽略它并转到下一个文件夹。
只需2美分: - )。
答案 5 :(得分:0)
在应用程序配置脚本中放置一个变量,该变量将设置为应用程序运行的路径。
另一种方法是动态设置该路径。
在部分之前
$url = explode('/',preg_replace('/^(\/)/','',$url));
使用预定义的应用程序路径从$url
字符串中删除位置(子文件夹)路径。
答案 6 :(得分:0)
这是我实现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控制器动作和视图的概念。
答案 7 :(得分:0)
您确定自己有htaccess
吗?
我想如果您将框架放在subfolder
上,则必须将RewriteBase
文件中的htaccess
从/
更改为/subfolder/
。它会是这样的:
# on root
RewriteBase /
#on subfolder
RewriteBase /subfolder/
在你的情况下,我唯一能想到的就是......
答案 8 :(得分:0)
我不使用OOP,但可以向您展示我如何动态检测我是否在子目录中的一些片段。太简短了,我只会描述它的一部分而不是发布所有代码。
所以我开始使用.htaccess
将每个请求发送到redirect.php,我在其中拼接$_SERVER['REQUEST_URI']
变量。我使用正则表达式来决定哪些部分应该是键以及应该是什么值(我通过将以0-9开头的任何内容作为值来指定,以及以az作为键开头的任何内容)来构建数组$GET[]
。 / p>
然后检查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);
}
我希望有所帮助并能给你一些启发。
答案 9 :(得分:0)
忘记“重新发明轮子是错误的”声称。他们不必使用我们的轮子。我前一段时间走在同一条路上,我非常感激我得到的......我希望你也会这样做
当涉及到您的具体问题的答案时 - 如果面临同样的问题 - 有一个非常简单的解决方案。它是根文件夹中.htaccess的新行...
只需在您的根.htaccess文件中添加以下行; (如果你的subfoler是“子文件夹”)
RewriteRule subfolder/ - [L]
这将使此文件夹与重写指令
分开通过使用这种方式,您可以根据需要安装任意数量的框架实例。但是如果您希望这是框架驱动的,那么您必须在框架内创建/更改.htaccess。
答案 10 :(得分:0)
创建/myBaseDirectory/public
目录并将文件放在那里 - 例如index.php
这是有效的,因为Apache将此目录看作基本目录。
答案 11 :(得分:-1)
基本上在你的第一个斜杠后抓取url字符串,然后将它爆炸成一个数组(我使用'/'作为分隔符)。
然后小心地将array_shift关闭元素并将它们存储为变量
item 0: controller
item 1: the action / method in that controller
item 2 thru n: the remaining array is your params