I want the following rules but I don't seem to get the right setup.
<domain>/training-courses/
both with or without the slash at the end it should go to:
<domain>/?index.php?page=training-courses
and for each variable extra after this I want it to behave like this:
<domain>/training-courses/success/another-value/and-yet-another/
to
<domain>/?index.php?page=training-courses&val1=success&val2=another-value&val3=and-yet-another-value
If it's not possible to have the option for unlimited leading variables, i'd like to have at least 2 variables after the page variable
Is this possible? and how do I get this sorted out?
I have this so far:
RewriteEngine On
RewriteRule ^test/([^/]*)/$ /test/index.php?pagina=$1&val1=$2
RewriteRule ^test/([^/]*)$ /test/index.php?pagina=$1&val1=$2
RewriteRule ^test/([^/]*)/([^/]*)/$ /test/index.php?pagina=$1&val1=$2
RewriteRule ^test/([^/]*)/([^/]*)$ /test/index.php?pagina=$1&val1=$2
RewriteRule ^test/([^/]*)/([^/]*)/([^/]*)/$ /test/index.php?pagina=$1&val1=$2&val2=$3
RewriteRule ^test/([^/]*)/([^/]*)/([^/]*)$ /test/index.php?pagina=$1&val1=$2&val2=$3
You're quite correct, you can't handle unlimited variables as sub-folders in the way you would like to, mod_rewrite just doesn't support it.
However, in answer to your first problem, to make the trailing / optional, change your rules to the following:
RewriteRule ^test/([^/]*)/?$ /test/index.php?pagina=$1
RewriteRule ^test/([^/]*)/([^/]*)/?$ /test/index.php?pagina=$1&val1=$2
RewriteRule ^test/([^/]*)/([^/]*)/([^/]*)/?$ /test/index.php?pagina=$1&val1=$2&val2=$3
After hours and hours of struggeling it just WON'T work. Since unlimited variables just isn't supported I'm ok with two variables besides the page (pagina). What I have now is this:
RewriteEngine On
RewriteRule ^(test/images|test/css|test/js|test/lib)($|/) - [L]
RewriteRule ^test/(.*)/(.*)/(.*)/ test/index.php?pagina=$1&e=$2&t=$3
RewriteRule ^test/(.*)/(.*)/(.*) test/index.php?pagina=$1&e=$2&t=$3
RewriteRule ^test/(.*)/(.*)/ test/index.php?pagina=$1&e=$2
RewriteRule ^test/(.*)/(.*) test/index.php?pagina=$1&e=$2
RewriteRule ^test/(.*)/ test/index.php?pagina=$1
RewriteRule ^test/(.*) test/index.php?pagina=$1
None of the RewriteRules work except from the first one which excludes folders from the other rewriterules. With working I mean it will actually redirect the URLs to index.php but I can't get the values in PHP through ie $_GET['pagina']
Strange thing is this WILL work, though is way too limited for my liking:
RewriteEngine On
RewriteRule ^(test/images|test/css|test/js|test/lib)($|/) - [L]
RewriteRule ^test/(.*)/ test/index.php?pagina=$1
I would like to come back to my own question and answer it. For a while now i'm using exactly what I want.
First off I have this in my htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
# existing folders or files
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.* - [L]
# non-existing folders or files
RewriteRule ^(.*)/? index.php?p=$1 [L]
</IfModule>
This allows to access real files at all times. If the path does not exist it will pass the entire path to index.php.
In index.php I have the following code at the top:
// Split the URL in all its components
$request = parse_url(strip_tags($_GET['p']));
// Only take the path without any leading slashes
$path = rtrim($request['path'], '/');
// Split each variable from eachother
$path_array = explode("/", $path);
if(count($path_array)){
// By default I select the first variable as the page I will include later on
$page = $path_array[0];
// Each other variable I will pass as $val[#nr] starting with 1. Just to be sure I'm going to strip tags and slashes
for($i=1;$i<count($path_array);$i++){
$path_array[$i] = strip_tags($path_array[$i]);
$path_array[$i] = stripslashes($path_array[$i]);
$val[$i] = $path_array[$i];
}
}
else{
// If $path_array doesn't contain multiple variables lets assume $path will contain the $page
$page = $path;
}
// If $page is empty let's take on the default page to include later on
if(empty($page)){
$page = "home";
}
if(file_exists($page . ".php")){
include($page . ".php");
}
else{
echo "Page " . $page . ".php does not exist.";
}
To give you some examples of the posibilities:
domain.com/ will include home.php
domain.com/product/ will include product.php
domain.com/product/298833/ will include product.php and parse 298833 as $val[1];
domain.com/product/298833/purple-candle will include product.php and parse 298833 as $val[1]; and purple-candle as $val[2]; Notice the leading slash not being included. It does not matter.
I'm open for improvement or tips in general. For now this is definitely the answer I was looking for back when I asked this question.
Related
I have a bunch of different blogs on my site i.e.
mysite.com/news
mysite.com/blog
mysite.com/bits
etc..
I use the same php script behind the scenes and want to keep the urls tidy so I've setup these rules:
# blogs
RewriteRule ^(bits|blog|news)(/?)$ news/?type=$1
RewriteRule ^(bits|blog|news)/[a-zA-Z0-9_-]+/([0-9]+)(/?)$ news/article.php?type=$1&id=$2
Now what's happening is that the 'type' is always coming through as news? I don't see why.
I would suggest adding a leading '/' to the URL your are redirecting to - also you don't need to wrap the trailing '/' in parentheses.
Also, put a [L] flag at the end of the rule to stop it looking at the rest of the .htaccess
Try this:
RewriteRule ^(bits|blog|news)/?$ /news/?type=$1 [L]
RewriteRule ^(bits|blog|news)/[a-zA-Z0-9_-]+/([0-9]+)/?$ /news/article.php?type=$1&id=$2 [L]
Prepending a RewriteCond of ..
RewriteCond %{QUERY_STRING} ^$
.. to each rule will also filter out any chance of URL's with a query string being parsed.
I have 3 subdomains , which are based on Opencart.
What I need to force on each domain given language
to do so _GET['language'] should be defined strictly for each subdomain
en.handmade24.at -> language=en
ru.handmade24.at -> language=ru
www.handmade.24.at -> language=de
I was told .htaccess was a good option to force language variable...
But how can i define the rules? Any help? I am dummy in htaccess...
my Htaccess looks like this
Options +FollowSymlinks
# Prevent Directoy listing
Options -Indexes
# Prevent Direct Access to files
<FilesMatch "\.(tpl|ini)">
Order deny,allow
Deny from all
</FilesMatch>
# SEO URL Settings
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]
Or maybe you could offer nicer solution?
RewriteCond %{HTTP_HOST} ^(www\.)?handmade24\.at
RewriteRule ^(.*)$ $1?language=de [QSA,L]
RewriteCond %{HTTP_HOST} ^(\w+)\.handmade24\.at
RewriteRule ^(.*)$ $1?language=%1 [QSA,L]
Here is the .htaccess that should work for you:
Options +FollowSymlinks
# Prevent Directoy listing
Options -Indexes
# Prevent Direct Access to files
<FilesMatch "\.(tpl|ini)">
Order deny,allow
Deny from all
</FilesMatch>
# SEO URL Settings
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?_route_=$1 [QSA,L,NE]
RewriteCond %{HTTP_HOST} ^(www\.)?handmade24\.at$ [NC]
RewriteRule ^(.*)$ $1?language=de [QSA,L]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^(.*)\.handmade24\.at$ [NC]
RewriteRule ^(.*)$ $1?language=%1 [QSA,L]
First of all, I have taken out the OpenCart system for the project which I solved your issue, but this trick should work just fine.
Yes you can do it with .htaccess, however I do not want to recommend doing that. Messing with .htaccess can be a pain in a certain place. If you do it, at some point you will most likely end up doing something wrong and corrupt something. It isn't the only solution, and that is why I wont tell you how to do it with .htaccess.
The solution I would recommend is a neat little work-around/hack I've just made. I where looking for a way to do it with subdomains, since it is Google's preferred choice of doing the multi language versions of websites (except of TLD's of course).
I came up with the solution to overrule the default OpenCart language selection/detection.
First of all open up index.php in the root of your OpenCart install.
Go find the lines with this:
if (isset($session->data['language']) && array_key_exists($session->data['language'], $languages) && $languages[$session->data['language']]['status']){
$code = $session->data['language'];
} elseif (isset($request->cookie['language']) && array_key_exists($request->cookie['language'], $languages) && $languages[$request->cookie['language']]['status']) {
$code = $request->cookie['language'];
} elseif ($detect) {
$code = $detect;
} else {
$code = $config->get('config_language');
}
Then replace those lines with this:
$url_info = parse_url(str_replace('&', '&', $config->get('config_url')));
foreach ($languages as $language)
{
if ($language['code'] . '.' . $url_info['host'] == $request->server['HTTP_HOST'])
{
$overwrite_language = $language;
break;
}
}
if (isset($overwrite_language)) {
$code = $overwrite_language['code'];
} elseif (isset($session->data['language']) && array_key_exists($session->data['language'], $languages) && $languages[$session->data['language']]['status']) {
$code = $session->data['language'];
} elseif (isset($request->cookie['language']) && array_key_exists($request->cookie['language'], $languages) && $languages[$request->cookie['language']]['status']) {
$code = $request->cookie['language'];
} elseif ($detect) {
$code = $detect;
} else {
$code = $config->get('config_language');
}
What this do is (note: OpenCart did load the available languages from the database a few lines earlier):
We get the URL from the database ("setting table" where key = 'config_url'), then we use the PHP function parse_url, which splits it up in parts (do a print_r() on it to see what parts).
We then loops through the languages that is available (those that are enabled in the admin panel).
In the loop we check if the $language['code'] . '.' . $url_info['host'] == $request->server['HTTP_HOST'] (an alias of $_SERVER['HTTP_HOST']). I've put in a break so it would stop wasting resources if it already have found a matching language for the domain.
I've edited the if elseif etc etc else statement that OpenCart made whith the above one. What it does is that it check if $overwrite_language is set, if it is then it makes that the language that the user " * selected * ", since it hit the if in the if elseif etc etc else statement then it wont run any of the others (which then would overwrite this little work-arround/hack).
-- Bonus tip --
If you have access to the php.ini config file, or you have permission to use ini_set(), then you can share your PHP session between subdomains
ini_set('session.cookie_domain', '.yourdomain.TLD');
(you may need to destroy an already created session). That could be an advantage, however note that it will overwrite the default shop language, but you can modify the 2 if's below the lines you just changed. The currencies should work as usual though.
-- Finishing up --
That should be it, hope you will like it and can use it, even though it is a long time you asked this question, maybe someone else could use it, just as I could a few hours ago.
I’m having trouble doing both of these at once with .htaccess.
Removing index.php is working, but trying to add the force lowercase keeps throwing a 500 error. I am using codeigniter. Any help is appreciated!
here’s my .htaccess code:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1
RewriteMap lc int:tolower
RewriteCond %{REQUEST_URI} [A-Z]
RewriteRule (.*) ${lc:$1} [R=301,L]
The php code suggested does not work if you are just trying to force to lowercase. Below is the correct php code.
$url = $_SERVER['REQUEST_URI'];
$pattern = '/([A-Z]+)/';
if(preg_match($pattern, $url)) {
$new_url = strtolower($url);
Header( 'HTTP/1.1 301 Moved Permanently' );
Header( 'Location: ' . $new_url );
exit;
}
// your code here
Discussion Found Here Force lowercase .htaccess
That is because it is impossible, let me explain.
Removing the index.php still sends all requests to index.php/yadda/yadda so the requested uri still has the index.php in it even though you do not see it or add it into the url.
The redirect (triggered by the 2nd rewrite rule) nulls the index section so you would then get mysite.com/index.php/lowercase/
BUT beyond all this RewriteMap can only be declared in your Httpd.conf file, you would declare it there with:
RewriteMap lc int:tolower
Then in your .htaccess file use your variable lc, but then again only one of the two will win you can't have both.
You will either get the URL lowercase or have the site working without using the index.php because they are always going to conflict because of the nature of what each one does.
Really the only way I can see it happening is in php, like so:
$this->load->helper('url');
$your_URL = uri_string();
preg_match_all('/[A-Z]/', $your_URL, $match) ;
$total_count = count($match [0]);
if($total_count > 0){
$new_line = strtolower($your_URL);
redirect($new_line);
}
This I would put into the main construct of your classes, I hope this helps you.
I have a url http://domain.com/module/controller/action/get1/value1/?get2=value2&get3=value3 I want to use Mod_Rewrite to change the ?&= to appropriate / slashes inline with the first GET variable.
I also need to avoid conflicts with my current Mod_Rewrite rules:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ zend.php [NC,L]
If you don't need the GET parameters in their native $_GET container, you could leave the htaccess file as is, and have the front controller (I assume you are using PHP) do the parsing and not mod_rewrite.
You would have to access the $_SERVER["REQUEST_URI"] and parse out the parameters before any other URL parsing (I think you are using the Zend Frameworks') kicks in.
This works only if you can modify the part of your program that needs value1 value2 value3 etc. If it's some Zend component that needs the parameters, and that component fetches them directly from $_GET, this will not work for you and you may in fact have to build mod_rewrite instructions.
Btw, you are aware by the way that with the method in your .htaccess, invalid links to images, CSS files and other media types will all be routed to zend.php?
Try putting these rules in front of yours:
RewriteCond %{QUERY_STRING} ^([^&=]+)=([^&]+)&(.+)
RewriteRule ^ %{REQUEST_URI}%1/%2/?%3 [N]
RewriteCond %{QUERY_STRING} ^([^&=]+)=([^&]+)$
RewriteRule ^ %{REQUEST_URI}%1/%2/? [L,R]
I could not find a nice way to do this... so I resolved to write some minimised PHP code at the top of my zend.php.
list($sURL, $sQuery) = explode('?', $_SERVER['REQUEST_URI']);
$sOriginalURL = $sURL;
if ('/' !== substr($sURL, -1)) $sURL .= '/';
if (isset($sQuery)) {
foreach (explode('&', $sQuery) as $sPair) {
if (empty($sPair)) continue;
list($sKey, $sValue) = explode('=', $sPair);
$sURL .= $sKey . '/' . $sValue . '/';
}
}
if (isset($sQuery) || $sOriginalURL !== $sURL) header(sprintf('Location: %s', $sURL));
If anyone can improve on this please comment below.
In my present project I've got several directories: application (my MVC files, which mustn't be accessed), images, css, and js. Effectively I want all requests to images/css/js to proceed unchanged, but all others I wish to call index.php/my/path.
My .htaccess currently looks like this, and is wreaking havoc with my routing.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond $1 !^(index\.php|images|js|css|robots\.txt)
RewriteRule ^(.*)$ http://example.com/index.php/$1 [L]
</IfModule>
This isn't working as relative URLs start stacking up, such as: example.com/blog/view/1/blog/view/2.
When I attempt something like,--
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/(index\.php|images|js|css|robots\.txt)
RewriteRule ^ index.php%{REQUEST_URI} [PT]
</IfModule>
I get this error with any request: No input file specified.
How can I force all requests not to my whitelisted directories to call, not redirect to (redirection murders posting, I found), index.php/path? IE, when /blog/view/1 is requested by the browser, .htaccess calls index.php/blog/view/1. The reference files at Apache's site aren't too clear about how to do this sort of thing—that, or, I am just missing the point of what I'm reading about RewriteRule.
And, I really want to understand this. Why will your answer work? Why are my attempts failing?
This is what I have in my .htaccess for my framework:
<IfModule mod_rewrite.c>
RewriteEngine on
#This will stop processing if it's images
RewriteRule \.(css|jpe?g|gif|png|js)$ - [L]
#Redirect everything to apache
#If the requested filename isn’t a file….
RewriteCond %{REQUEST_FILENAME} !-f
#and it isn’t a folder…
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
#L = (last - stop processing rules)
#QSA = (append query string from requeste to substring URL)
</IfModule>
Hope this helps.
PS: Maybe you want to remove the lines to stop redirecting if it's a file or folder ;)
Antonio helped me get on the right track, so here's the resulting .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine on
# skip if whitelisted directory
RewriteRule ^(images|css|js|robots\.txt|index\.php) - [L]
# rewrite everything else to index.php/uri
RewriteRule . index.php%{ENV:REQUEST_URI} [NE,L]
</IfModule>
You're going to have to do that using PHP. For example, if you wanted to split your URI into something like domain.tld/controller/action/param, then you could use the following PHP code as a start:
<?php
// Filter URI data from full path
$uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['REQUEST_URI']);
$uri_string = trim($uri_string, '/'); // Make sure we don't get empty array elements
// Retrieve URI data
$uri_data = explode('/', $uri_string);
In that case, $uri_data[0] is the controller, $uri_data[1] is the action, and beyond that are parameters. Note that this isn't a foolproof method, and it's never a great idea to trust user-entered input like this, so you should whitelist those controllers and actions which can be used.
From here, knowing the controller and having a consistent directory structure, you can require_once the proper controller and call the action using variable variables.
This is what I use in my .htaccess file for my CMS:
Options -Indexes
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php/$1 [NC,L]
And then in my index.php file I have:
$path_info = '';
$path_info = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : $path_info;
$path_info = isset($_SERVER['ORIG_PATH_INFO']) ? $_SERVER['ORIG_PATH_INFO'] : $path_info;
$request = explode('/', trim($path_info, '/'));
// if $request[0] is set, it's the controller
// if $request[1] is set, it's the action
// all other $request indexes are parameters
Hope this helps.