RewriteRule: trying to get rid of dashes - php

I'm trying to rewrite dashes in URL so that they don't exist internally. For example this URL
localhost/mysite/about-me
"about-me" should be rewritten to "aboutme". I need this because the controller class name depends on this route string, and I obviously can't use dashes for this.
This is the condition and rule I found which I thought should fit my needs:
# Condition is to avoid rewrite on files within specified subdirs
RewriteCond $1 !^(css|img|ckeditor|scripts)
RewriteRule ^([^-]+)-([^-]+)$ $1$2 [L]
However it seems that it's not working, since the controller class Aboutme is not instanciated. I get a 404 error instead, and I don't have any problem with similar controller classes without a dash in their names.
Could you please give me a hand on this?

Why not go with routes?
$route['about-me'] = 'aboutme/index';

Try removing ^ and $
# Condition is to avoid rewrite on files within specified subdirs
RewriteCond $1 !^(css|img|ckeditor|scripts)
RewriteRule ([^-]+)-([^-]+) $1$2 [L]

You can extend the Router class.
In /application/core create a file called MY_Router.php (MY is the default prefix) and copy this into it;
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Router extends CI_Router {
function set_class($class) {
$this->class = str_replace('-', '_', $class);
}
function set_method($method) {
$this->method = str_replace('-', '_', $method);
}
function _validate_request($segments) {
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).'.php')) {
return $segments;
}
// Is the controller in a sub-folder?
if (is_dir(APPPATH.'controllers/'.$segments[0])) {
// Set the directory and remove it from the segment array
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);
if (count($segments) > 0) {
// Does the requested controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).'.php')) {
show_404($this->fetch_directory().$segments[0]);
}
} else {
$this->set_class($this->default_controller);
$this->set_method('index');
// Does the default controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php')) {
$this->directory = '';
return array();
}
}
return $segments;
}
// Can't find the requested controller...
show_404($segments[0]);
}
}
This will automatically rewrite - to _ for you.
If you don't want underscores change the code to replace them with nothing;
all occurences of str_replace('-', '_', to str_replace('-', '',

Here is a way to do it with mod-rewrite:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/(.*)([\w]*)-([\w]*)(.*)/?$ [NC]
RewriteRule .* %1%2%3%4 [L,DPI]
Won't redirect but can do it adding R=301 like this [R=301,DPI,L].
Does not have to be about-me. Can be any words pair at any position. i.e.
localhost/mysite/about-me = .../aboutme or
localhost/mysite/folder1/folder2/folder3/my-folder = .../myfolder or
localhost/mysite/folder1/folder2/my-folder/folder3 = .../myfolder/...

Related

How I can do something like "localhost/winter/2022" not "localhost/?season=winter&year=2022" [duplicate]

I know that you can add rules in htaccess, but I see that PHP frameworks don't do that and somehow you still have pretty URLs. How do they do that if the server is not aware of the URL rules?
I've been looking Yii's url manager class but I don't understand how it does it.
This is usually done by routing all requests to a single entry point (a file that executes different code based on the request) with a rule like:
# Redirect everything that doesn't match a directory or file to index.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php [L]
This file then compares the request ($_SERVER["REQUEST_URI"]) against a list of routes - a mapping of a pattern matching the request to a controller action (in MVC applications) or another path of execution. Frameworks often include a route that can infer the controller and action from the request itself, as a backup route.
A small, simplified example:
<?php
// Define a couple of simple actions
class Home {
public function GET() { return 'Homepage'; }
}
class About {
public function GET() { return 'About page'; }
}
// Mapping of request pattern (URL) to action classes (above)
$routes = array(
'/' => 'Home',
'/about' => 'About'
);
// Match the request to a route (find the first matching URL in routes)
$request = '/' . trim($_SERVER['REQUEST_URI'], '/');
$route = null;
foreach ($routes as $pattern => $class) {
if ($pattern == $request) {
$route = $class;
break;
}
}
// If no route matched, or class for route not found (404)
if (is_null($route) || !class_exists($route)) {
header('HTTP/1.1 404 Not Found');
echo 'Page not found';
exit(1);
}
// If method not found in action class, send a 405 (e.g. Home::POST())
if (!method_exists($route, $_SERVER["REQUEST_METHOD"])) {
header('HTTP/1.1 405 Method not allowed');
echo 'Method not allowed';
exit(1);
}
// Otherwise, return the result of the action
$action = new $route;
$result = call_user_func(array($action, $_SERVER["REQUEST_METHOD"]));
echo $result;
Combined with the first configuration, this is a simple script that will allow you to use URLs like domain.com/about. Hope this helps you make sense of what's going on here.

Clean url in php mvc

In first .htaccess,I send url to public/index.php:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ public/index.php [NC,L]
And my public/index.php:
<?php
// define root path of the site
if(!defined('ROOT_PATH')){
define('ROOT_PATH','../');
}
require_once ROOT_PATH.'function/my_autoloader.php';
use application\controllers as controllers;
$uri=strtolower($_SERVER['REQUEST_URI']);
$actionName='';
$uriData=array();
$uriData=preg_split('/[\/\\\]/',$uri );
$actionName = (!empty($uriData[3])) ? preg_split('/[?].*/', $uriData[3] ): '' ;
$actionName =$actionName[0];
$controllerName = (!empty($uriData[2])) ? $uriData[2] : '' ;
switch ($controllerName) {
case 'manage':
$controller = new Controllers\manageController($controllerName,$actionName);
break;
default:
die('ERROR WE DON\'T HAVE THIS ACTION!');
exit;
break;
}
// function dispatch send url to controller layer
$controller->dispatch();
?>
I have this directory :
application
controller
models
view
public
css
java script
index.php
.htaccess
I want to have clean URL for example localhost/lib/manage/id/1 instead of localhost/lib/manage?id=1,what should I do ?
Using your current rewrite rules, everything is already redirected to your index.php file. And, as you are already doing, you should parse the URL to find all these URL parameters. This is called routing, and most PHP frameworks do it this way. With some simple parsing, you can transform localhost/lib/manage/id/1 to an array:
array(
'controller' => 'manage',
'id' => 1
)
We can simply do this, by first splitting the URL on a '/', and then looping over it to find the values:
$output = array();
$url = split('/', $_SERVER['REQUEST_URI']);
// the first part is the controller
$output['controller'] = array_shift($url);
while (count($url) >= 2) {
// take the next two elements from the array, and put them in the output
$key = array_shift($url);
$value = array_shift($url);
$output[$key] = $value;
}
Now the $output array contains a key => value pair like you want to. Though note that the code probably isn't very safe. It is just to show the concept, not really production-ready code.
You could do this by capturing part of the URL and and placing it as a querystring.
RewriteRule /lib/manage/id/([0-9]+) /lib/manage?id=$1 [L]
The string inside the parenthesis will be put into the $1 variable. If you have multiple () they will be put into $2, $3 and so on.

codeigniter url segments containing leading slash

the url to access the method is like this:
http://localhost/site/cont/method
I want to access this method using GET method like this:
http://localhost/new-tera/paper/lookup_doi/segment but my segment part is already containing /like this:
http://localhost/lookup_doi/segment/containing/slashes
note that the whole segment/containing/slashes is one value.
I am getting this value in my method like this:
public function method ($variable)
{
echo $variable;
}
//output: segment
and not : segment/containing/slashes
CodeIgniter passes the rest of them as additional arguments. You can either specify the additional arguments (if the number is fixed) or use:
implode('/', func_get_args())
to get the entire string.
.htaccess mast be
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]
so ok...
$route = empty($_GET['route']) ? '' : $_GET['route'];
$exp = explode('/', $route);
results:
$exp[0] = new-tera
$exp[1] = paper
$exp[2] = lookup_doi
$exp[3] = segment
and so we mast be have routing! run example(with my projects):
if($exp[0] == '')
{
$file = $_SERVER['DOCUMENT_ROOT'] .'/controllers/controller_index.php';
}
else
{
$file = $_SERVER['DOCUMENT_ROOT'] .'/controllers/controller_'.$exp[0].'.php';
}
if(!file_exists($file))
{
engine :: away();
}
include_once $file;
$class = (empty($exp[0]) or !class_exists($exp[0])) ? 'class_index' : $exp[0];
$controller = new $class;
$method = (empty($exp[1]) or !method_exists($controller, $exp[1])) ? 'index' : $exp[1];
$controller -> $method();
you can add slashes by adding "%2F" in your query string hope this will work
segment = 'somethingwith%2F'
http://localhost/new-tera/paper/lookup_doi/segment
You can base64 encode it first and decode it after. Really, you can use a variety of methods to change the / to something else (i.e. a -) and change it back.
echo site_url('controller/method/' . base64_encode($variable));
public function method ($variable)
{
$variable = base64_decode($variable);
}

Pretty URLs in PHP frameworks

I know that you can add rules in htaccess, but I see that PHP frameworks don't do that and somehow you still have pretty URLs. How do they do that if the server is not aware of the URL rules?
I've been looking Yii's url manager class but I don't understand how it does it.
This is usually done by routing all requests to a single entry point (a file that executes different code based on the request) with a rule like:
# Redirect everything that doesn't match a directory or file to index.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php [L]
This file then compares the request ($_SERVER["REQUEST_URI"]) against a list of routes - a mapping of a pattern matching the request to a controller action (in MVC applications) or another path of execution. Frameworks often include a route that can infer the controller and action from the request itself, as a backup route.
A small, simplified example:
<?php
// Define a couple of simple actions
class Home {
public function GET() { return 'Homepage'; }
}
class About {
public function GET() { return 'About page'; }
}
// Mapping of request pattern (URL) to action classes (above)
$routes = array(
'/' => 'Home',
'/about' => 'About'
);
// Match the request to a route (find the first matching URL in routes)
$request = '/' . trim($_SERVER['REQUEST_URI'], '/');
$route = null;
foreach ($routes as $pattern => $class) {
if ($pattern == $request) {
$route = $class;
break;
}
}
// If no route matched, or class for route not found (404)
if (is_null($route) || !class_exists($route)) {
header('HTTP/1.1 404 Not Found');
echo 'Page not found';
exit(1);
}
// If method not found in action class, send a 405 (e.g. Home::POST())
if (!method_exists($route, $_SERVER["REQUEST_METHOD"])) {
header('HTTP/1.1 405 Method not allowed');
echo 'Method not allowed';
exit(1);
}
// Otherwise, return the result of the action
$action = new $route;
$result = call_user_func(array($action, $_SERVER["REQUEST_METHOD"]));
echo $result;
Combined with the first configuration, this is a simple script that will allow you to use URLs like domain.com/about. Hope this helps you make sense of what's going on here.

Themes outside application

I read this post and I want to use similar solution, but with db.
In my site controller after():
$theme = $page->get_theme_name(); //Orange
Kohana::set_module_path('themes', Kohana::get_module_path('themes').'/'.$theme);
$this->template = View::factory('layout')
I checked with firebug:
fire::log(Kohana::get_module_path('themes')); // D:\tools\xampp\htdocs\kohana\themes/Orange
I am sure that path exists. I have directly in 'Orange' folder 'views' folder with layout.php file.
But I am getting: The requested view layout could not be found
Extended Kohana_Core is just:
public static function get_module_path($module_key) {
return self::$_modules[$module_key];
}
public static function set_module_path($module_key, $path) {
self::$_modules[$module_key] = $path;
}
Could anybody help me with solving that issue?
Maybe it is a .htaccess problem:
# Turn on URL rewriting
RewriteEngine On
# Put your installation directory here:
# If your URL is www.example.com/kohana/, use /kohana/
# If your URL is www.example.com/, use /
RewriteBase /kohana/
# Protect application and system files from being viewed
RewriteCond $1 ^(application|system|modules)
# Rewrite to index.php/access_denied/URL
RewriteRule ^(.*)$ / [PT,L]
RewriteRule ^(media) - [PT,L]
RewriteRule ^(themes) - [PT,L]
# Allow these directories and files to be displayed directly:
# - index.php (DO NOT FORGET THIS!)
# - robots.txt
# - favicon.ico
# - Any file inside of the images/, js/, or css/ directories
RewriteCond $1 ^(index\.php|robots\.txt|favicon\.ico|static)
# No rewriting
RewriteRule ^(.*)$ - [PT,L]
# Rewrite all other URLs to index.php/URL
RewriteRule ^(.*)$ index.php/$1 [PT,L]
Could somebody help?
What I am doing wrong?
Regards
[EDIT]
My controller code:
class Controller_Site extends Controller_Fly {
public static $meta_names = array('keywords', 'descriptions', 'author');
public function action_main() {
$this->m('page')->get_main_page();
}
public function action_page($page_title) {
$this->m('page')->get_by_link($page_title);
}
public function after() {
$page = $this->m('page');
$metas = '';
foreach(self::$meta_names as $meta) {
if (! empty($page->$meta)) {
$metas .= html::meta($page->$meta, $meta).PHP_EOL;
}
}
$theme = $page->get_theme_name();
Kohana::set_module_path('themes', Kohana::get_module_path('themes').'/'.$theme);
$menus = $page->get_menus();
$this->template = View::factory('layout')
->set('theme', $theme)
->set('metas', $metas)
->set('menus', $menus['content'])
->set('sections', $page->get_sections())
->set_global('page', $page);
if ($page->header_on) {
$settings = $this->m('setting');
$this->template->header = View::factory('/header')
->set('title', $settings->title)
->set('subtitle', $settings->subtitle)
->set('menus', $menus['header']);
}
if ($page->sidebar_on) {
$this->template->sidebar = View::factory('sidebar', array('menus' => $menus['sidebar']));
}
if ($page->footer_on) {
$this->template->footer = View::factory('footer');
}
parent::after();
}
}
and parent controller:
abstract class Controller_Fly extends Controller_Template {
protected function m($model_name, $id = NULL) {
if (! isset($this->$model_name)) {
$this->$model_name = ORM::factory($model_name, $id);
}
return $this->$model_name;
}
protected function mf($model_name, $id = NULL) {
return ORM::factory($model_name, $id);
}
}
[Edit 2]
Previous link to post was dead, link was:
http://forum.kohanaframework.org/comments.php?DiscussionID=5744&page=1#Item_0
My guess is that your controller has a __construct() method and you aren't calling parent::__construct
Actually, I think for kohana V3 __construct needs to also be passed the $request object as follows:
public function __construct(Request $request)
{
parent::__construct($request);
}
I realized that I need to init all modules once again:
$theme = $page->get_theme_name();
Kohana::set_module_path('themes', Kohana::get_module_path('themes').'/'.$theme);
Kohana::modules(Kohana::get_modules());
Now I don't have an error. Instead I am getting white screen of death:
$this->template is null
:(
[EDIT]
Now I know, I had:
$this->template = View::factory('layout')
->set('theme', $theme)
->set('metas', $metas)
->set('menus', $menus['content'])
->set('sections', $page->get_sections())
->set_gobal('page', $page);
Ofcourse I forgot that set_global doesn't return $this :D
Anyway everything working now :)
I have one more question about efficiency. I am calling Kohana::modules() second time in request flow. Is this a big deal according to efficiency?
Regards

Categories