Я создаю PHP Framework, и у меня есть некоторые сомнения …
Структура принимает URL-адрес таким образом: http:/web.com/site/index
Он принимает первый параметр для загрузки контроллера ( site
), а затем загружает конкретное действие ( index
).
Если вы установили фреймворк в базовом URL-адресе, он работает нормально, но если вы установите его в подпапку, например: http://web.com/mysubfolder/controller/action
Мой скрипт анализирует его как controller = mysubfolder
и action = 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); } }
Спасибо за любую помощь, которую вы можете дать.
Вам не хватает базового пути. Теперь скрипт маршрутизации должен начинаться с момента обнаружения обнаруженного шаблона или маршрута.
Псевдокод:
//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));
Вы можете использовать это с RewriteBase или без него для вашего .htaccess, если они используют ту же привязку – index.php.
Кроме того, вы можете улучшить процедуру сопоставления маршрута с помощью функции регулярных выражений, таких как preg_match и preg_match_all. Они позволяют вам определить шаблон для сопоставления и результатов для массива совпадающих строк – см. http://php.net/manual/en/function.preg-match.php .
Да, я думаю, я знаю, как это исправить.
(Отказ от ответственности: я знаю, что вы знаете большую часть этого, но я собираюсь объяснить все для других, которые могут не знать некоторых из них)
В php есть трюк, где, если вы переходите к следующему пути:
http://web.com/mysubfolder/index.php/controller/action
вы получите «/ 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 в качестве справочного материала, я также рекомендую использовать шаблон html5 )
В основном вы настроили его для перенаправления всего на index.php в определенной точке URL-адреса.
Теперь, если вы посетите: http://web.com/mysubfolder/index.php/controller/action
Теперь вы можете получить правильный путь «/ 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']?:'/';
Теперь, когда вы не получаете URL-адрес, это просто его часть пути и не будет содержать query_string, например, когда вы посещаете
http://web.com/mysubfolder/index.php/test?param=val
вы получите только «/ test» в переменной $ 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']
отличается от переменных $_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); } }
надеюсь, это поможет
PS Извините за поздний ответ 🙁
Даже если вы создаете свою собственную инфраструктуру, нет причин не повторять использование надежных, хорошо протестированных и документированных компонентов , таких как этот компонент маршрутизации .
Просто используйте Composer , который стал стандартом для управления зависимостями в PHP, и все будет в порядке. Добавьте столько компонентов, сколько хотите для своего стека.
И здесь вы должны прочитать руководство о том, как создать свою собственную структуру.
В какой-то момент вам нужно будет проверить $ _SERVER ['HTTP_HOST'] и конфигурацию var, определенную программистом / пользователем, которая указывает подпапку (-ы), в которой находится приложение, и удалить часть, которую вы не интересуете остаток URL-адреса.
Вы можете проверить это сообщение форума на codeigniter formus для некоторых советов.
CodeIgniter использует другой способ маршрутизации контроллера / метода внутри страны. Вы выполняете маршрутизацию с помощью значения $_SERVER['PATH_INFO']
. Вы используете такие URL-адреса: myapp.com/index.php/controller/method
.
Чтобы не показывать index.php на uri, вы должны полагаться на правило перезаписи Apache, но даже с этим я считаю, что CI-это хорошее решение, как только у вас есть местоположение вашего индексного файла, вы можете избежать всех проблем, связанных с разбором URL.
Если я правильно понимаю, что у вас есть, то одно решение может состоять в том, чтобы продолжать делать то, что вы делаете, но также получить путь к главному сценарию маршрутизации (например, с помощью realpath ()).
Если последняя папка (или папка до этого и т. Д.) Соответствует начальному URL-адресу (или другому разделу), вы игнорируете его и переходите к следующему.
Просто мои 2 цента :-).
В сценарии конфигурации приложения укажите переменную, которая будет установлена в путь, на который выполняется приложение.
Альтернативой является динамический набор этого пути.
Перед частью
$url = explode('/',preg_replace('/^(\/)/','',$url));
удалите путь местоположения (подпапки) из строки $url
используя предопределенный путь приложения.
Вот как я реализовал 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();
в//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();
Я не использовал концепцию модулей. Выполняются действия и представление контроллера.
Вы уверены, что у вас есть htaccess
правильно?
Я предполагаю, что если вы размещаете свою фреймворк в subfolder
, тогда вам нужно изменить свой RewriteBase
в файле htaccess
из /
в /subfolder/
. это было бы примерно так:
# on root RewriteBase / #on subfolder RewriteBase /subfolder/
это единственное, о чем я мог подумать об этом в вашем случае …
Я не использую ООП, но могу показать вам некоторые фрагменты того, как я делаю вещи, чтобы динамически определить, есть ли я в подкаталоге. Слишком короткое время, и я просто опишу его части, а не отправляю весь код.
Поэтому я начинаю с .htaccess
который отправляет каждый запрос redirect.php, в который я $_SERVER['REQUEST_URI']
переменную $_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); }
Я надеюсь, что это поможет и может дать вам некоторое вдохновение.
Забудьте о требованиях «изобретать колесо неправильно». Им не нужно использовать наши колеса. Некоторое время я шел по тому же пути, и я полностью благодарен за то, что получаю … надеюсь, вы тоже
Когда дело доходит до ответа на вашу конкретную проблему, которая, если она встречается слишком, – это очень простое решение. это новая строка в .htaccess в корневой папке …
Просто добавьте строку ниже в свой файл .htaccess. (если ваш подпапок является «подпапкой»)
RewriteRule subfolder/ - [L]
Это позволит оставить эту папку от переписывающих директив
Используя этот способ, вы можете установить как можно больше экземпляров вашей инфраструктуры. Но если вы хотите, чтобы это было основано на каркасе, вам нужно создать / изменить .htaccess в своей структуре.
Создайте /myBaseDirectory/public
каталог и поместите туда свои файлы – например index.php
.
Это работает, потому что Apache видит этот каталог как базовый каталог.
в основном захватить строку url после вашей первой косой черты, а затем взорвать ее в массив (я использую '/' в качестве разделителя).
затем аккуратно массируйте_сброс с ваших элементов и сохраните их как переменные
item 0: controller item 1: the action / method in that controller item 2 thru n: the remaining array is your params