htaccess rewrite to reverse subfolders - apache

As basic as it gets, here is an example of what I'm trying to do:
I have a structure that takes different types of CMS' and inside each of those installations, are language variations.
By default the structure looks like this:
https://[domain]/[country]/[installation]/[language-code]
Ultimately, I'm trying to get this:
https://[domain]/[country]/[language-code]/[installation]/
I'm wondering if this can be accomplished, due to the fact the folders/languages themselves are not actual folders and in fact rewrites from the CMS' settings (within the subfolders).
As unmodified these would be examples of the current urls:
https://example.com/ca/events/en/
https://example.com/ca/store/en/
https://example.com/ca/network/en/
And example of the desired results:
https://example.com/ca/en/events/
https://example.com/ca/en/store/
https://example.com/ca/en/network/
and for each installation, they dont always have the same languages (eg. ca has en and fr, but us has en and es)
Note: subsequent pages would be appended... eg:
https://example.com/ca/en/events/event-name/subpage/

You may be be able to use this single redirect rule on top of your .htaccess:
RewriteEngine On
RewriteRule ^([a-z]{2})/(.+)/([a-z]{2}/?)$ $1/$3/$2 [L]

Related

Can mod_rewrite be used to find an older version of a file?

Say there are four files on a server which contain dates in the filename in some way:
file_2014-01-20.txt
file_2014-01-03.txt
file_2014-01-02.txt
file_2014-01-01.txt
...and the server receives a request for a dated file which doesn't exist:
file_2014-01-10.txt
...is there a way to use mod_rewrite or some other .htaccess code to make it find the most recent file that is older than the one requested? E.g. in this case it would return file_2014-01-03.txt, since that is the most recent existing file that is older than the (nonexistent) requested file.
I know I could redirect all 404's to a special script like this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+) getarchive.php?request=$1
...where getarchive.php will take request and use it find and return the correct file. However, this is not a good solution for me for several reasons, and I'd like to do the redirecting entirely with .htaccess without using any server-side scripts at all if possible.
Edit:
To put the question another way, given a nonexistent filename, can Apache be used to find the next file in the list, when sorted reverse-alphabetically.
Example:
a.txt
b.txt
z.txt
Given a request for n.txt, the server returns b.txt.
You're going to be way better off just writing a script to do this. Date comparison using mod_rewrite, if someone even manages to do it, sounds like a horrible idea. How are you going to code it for previous years? (Like file_2013-12-30.txt and file_2014-01-30.txt)
The functionality of mod_rewrite is completely inadequate to do this kind of comparison.
You'll have to create groupings for the year, month and date, then do comparisons with them all without the use of any conditionals (there's no If/Then/Else in mod_rewrite, you have to enumerate every possible condition every time for every rule) or controlled loops, without any arithmetic functions, and without the means to find a file with the next lowest number for a date, or a date/month, or a date/month/year. Which means for a request like file_2014-01-10.txt you have to check if the file file_2014-01-09.txt exists, then if file_2014-01-08.txt exists, then if file_2014-01-07.txt exists, etc. All without being able to do any math.
Not saying it isn't possible to create some clever way to make it all work somehow, but God help whoever has to make a tweak to it afterwards.

Mod Rewrite on get vars

I'm working on a private project, which is basicly a profile system.
Now I've been trying how to improve the URL formatting.
At this moment, I am using URL's which look like:
-> http://example.com/overview
-> http://example.com/profile/?name=foo
-> http://example.com/jobs/?name=foo
Both overview and profile are directories on my website, which contain a single index.php file, which holds the PageID of which should be retrieved from the database.
Now, my goal is to format the URL to something as:
-> http://example.com/foo OR http://example.com/profile/foo
-> http://example.com/foo/jobs OR http://example.com/profile/foo/jobs
Is there anyway to do this with MOD_REWRITE?
This would mean the original url would look something like http://example.com/?character=foo/jobs which is http://example.com/get_var/directory.
I've done my research on Stackoverflow and Google, searching for 'mod_rewrite get variables'. But nothing seemed to be what I'd like to see happening.
Yours Sincerely,
Larssy1
To extract a portion of the URI between slashes and append it as a URL parameter, use the expression ([^/]+) to capture all characters up to but not including the next / into $1:
RewriteEngine On
RewriteRule ^profile/([^/]+)/([^/]+/?)?$ profile/$2?character=$1 [L]
The above rule will dynamically capture what follows Foo from your example, meaning that whether it was followed by /jobs or /other or /somethingelse, it would be appended as /profile/somethingelse?character=Foo. If that isn't necessary, and /jobs is static, you don't need to capture it into $2:
RewriteEngine On
# Don't dynamically capture what comes after the first variable group...
RewriteRule ^profile/([^/]+)/jobs$ profile/jobs?character=$1 [L]

Apache mod_rewrite path name as query parameters?

I want to use Apache's mod_rewrite in order to be able to take each folder of a path as a particular query parameter, for example consider the following:
Basic example
Url requested: http://domain.com/shoes/prada/image-1/
Page served: http://domain.com/?cid=shoes&bid=prada&pid=image-1
In this scenario, there are 3 sub-folders requested (/shoes/, /prada/ then image-1), so the first sub-folder is passed in the actual page served as cid, the second as bid and the third as pid.
Full example
However, I would also like it to serve a particular page depending on the number of sub-folders requested, e.g.
Url requested: http://domain.com/shoes/prada/
Page served: http://domain.com/shop.php?cid=shoes&bid=prada
So far all I've managed to find is regex based matching for mod_rewrite but my path's will vary a lot, which is why I would like to have conditions based on the number of folders accessed (please note, I'm not that good with regex - I reckon a wildcard character would help with this, but I wouldn't be sure where to start).
Any help on this would be greatly appreciated! This is pretty long winded, so if you need any more info for clarifying, please let me know!
With a little bit of work I was able to tweak some regex and get a working rule set for what I wanted:
RewriteEngine on
RewriteRule ^(.*)/(.*)/(.*)/(.)?$ product.php?tid=$1&sid=$2&eid=$3 [L]
RewriteRule ^(.*)/(.*)/(.)?$ brand.php?tid=$1&sid=$2 [L]
RewriteRule ^(.*)/(.)?$ shop.php?tid=$1 [L]
This is a bit different to the example, however it's what I intended for in the first place.
This allows for the rewriting of url's up to four folders deep, with the "name" of each folder being given as a parameter, and each additional level of depth rewriting the url to a separate resource for example:
http://x.com/shoes/prada/2011-high-heels/ -> http://x.com/product.php?tid=shoes&sid=prada&eid=2011-high-heels
Tested on http://martinmelin.se/rewrite-rule-tester/

Abusing Mod Rewrite for a clean file system, and pretty URLs

I have a few php files that do a few different jobs. I'd like to change the way my clients access these php files to make it more clean for the end user. The Mod_Rewrite system has shown that it can do some pretty powerful things when in the hands of the right server admin. So I was wondering how far can you abuse the Mod Rewrite rules for a cleaner file system, and pretty URLs. Considering that the PHP files themselves use query strings to get their data, I'd like to alias the way the query string is built based upon how the how deep into the fake files system we go.
Our website's URL is http://www.domain.tld/, but we shall call it domain.tld for short. I'd like to map a few different address to a few different query strings on a few different files. But I'd also like to to be expandable on a whim.
Or first set would be, anything going past domain.tld/series/ should be directed to the domain.tld/series.php script with any (fake) directory past series to become part of the query-string for series.php. The same should happen to anything directed in the direction of domain.tld/users/ that should be redirected to the domain.tld/users.php file.
So if we had a URLs like, domain.tld/series/Master/2010/ or domain.tld/series/Novice/Season 01/ they would still be redirected to the domain.tld/series.php script, but with the query-string of ?0=Master&1=2010 and ?0=Novice&1=Season 01. But should I want to get an overview of the Master series, I could go the the URL domain.tld/series/Master/ and produce the query-string of just ?0=Master. The idea being that the rewrite rule should allow for infinite expandability.
This is how I'm doing it, and it sure works infinitely:
RewriteRule ^((/?[^/]+)+)/?$ ?q=$1 [L]
The trick is that the whole path is passed on as a single parameter, q, to index.php. So for example domain.tld/series/Novice/Season 01/ becomes domain.tld/?q=series/Novice/Season 01. Then you can do:
<?php
$params = explode('/', $_GET['q']);
var_dump($params);
?>
to get the individual parts.
array(3) { 0 => 'series', 1 => 'Novice', 2 => 'Season 01' }
It is not possible to be completely dynamic in such a system and have, as you say 'infinite expandability. You would have to define a RewriteRule for every 'tier' you will allow in your URL, or alternatively match everything after the first 'tier' as a single variable and do the work with PHP.
Example 1
RewriteRule ^([^/]+)/?$ /$1.php
RewriteRule ^([^/]+)/([^/]+)/?$ /$1.php?0=$2
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ /$1.php?0=$2&1=$3
Example 2
RewriteRule ^([^/]+)/(.*)/? /$1.php?qs=$2
Obviously these are only very simple examples and you'd probably have to use RewriteConds etc. to exempt certain files etc.

mod_rewrite ecommerce URL design

I have problems with how I should structure my product listing pages, products pages, webpages.
It roughly translate into this:
/bags/nicebag.html = /product.php?product=nicebag&category=bags
/nicebag.html = /product.php?product=nice_bag
/bags = productlisting.php?&category=bags
Problem is that webpages will share same URL structure as no.2 in the list
/contact.html = page.php?page=contact
The reason why it is not listed in .htaccess separatly is that webpages can have different names. And even the same page can be in multiple languages.
The reason of no. 1 and 2 is not combined, is that sometimes I just want to reference only to the product since it can be in multiple categories.
What kind of structure do you suggest?
.htaccess
# Mod rewrite enabled.
Options +FollowSymLinks
RewriteEngine on
# ---- Rules ----
# product.php (Search for category & product name)
RewriteRule ^([A-Za-z0-9-_]+)/([A-Za-z0-9-_]+)\.html?$ product.php?prod_id=$2&cid=$1 [NC,L]
# productlisting.php (Search for category)
RewriteRule ^([A-Za-z0-9-_]+)?$ productlisting.php?&cid=$1 [NC,L]
I would use the path prefix /products/ to identify the products related URLs. So:
/products/bags/nicebag.html → /product.php?product=nicebag&category=bags
/products/nicebag.html → /product.php?product=nice_bag
/products/bags → /productlisting.php?&category=bags
With such a structure you could also rewrite /products/ to /productlisting.php that then shows all products.
# product listing
RewriteRule ^products/$ productlisting.php [L]
RewriteRule ^products/([A-Za-z0-9-_]+])$ productlisting.php?category=$1 [L]
# product details
RewriteRule ^products/([A-Za-z0-9-_]+)\.html$ product.php?prod_id=$1 [L]
RewriteRule ^products/([A-Za-z0-9-_]+)/([A-Za-z0-9-_]+)\.html$ product.php?prod_id=$2&cid=$1 [L]
# other pages
RewriteRule ^([A-Za-z0-9-_]+)\.html$ page.php?page=$1 [L]
use a different suffix for different types, e.g html for products and htm for pages or something like that
/bags/nicebag.html = /product.php?product=nicebag&category=bags
/nicebag.html = /product.php?product=nice_bag
/bags = productlisting.php?&category=bags
/contact.htm = page.php?page=contact
or
/contact/page.html = page.php?page=contact
As it will be messy and cumbersome to maintain your rewriting rules in the .htaccess file, I would only put one rule in there, rewriting to something like:
/dispatch.php?request=[request]
e.g.
RewriteRule ^(.*)$ dispatch.php?request=$1 [L,QSA]
In dispatch.php, you dissect the request into its elements (path, querystring, anchor, ...) and decide where to go from there. That way, you can use code for the decision making, which will give you a lot more flexibility than just maintaining a huge list of custom rewrite mappings.
For example, you can identify product and category elements in the path by querying against your database and base the dispatch logic on the results in a more generic way.
[Pseudocode]
if (isProduct($lastPathElement)) {
// Maybe verify that leading path elements are categories ...
// Other preparations/verifications ...
// refer execution to product.php
}
elseif (isCategory($lastPathElement)) {
// Other preparations/verifications ...
// refer execution to productlisting.php
}
// ... (Checks for other specific stuff)
else {
// Static page or 404
// refer execution to page.php
}
I was facing the very same issue a few weeks ago.
Ended up defining a different structure for the "static" pages.
www.examples.com/contact/
or
www.examples.com/info/contact.html
So it can be distinguished from the "dynamic" pages.
There's pretty much no way to distinguish between www.examples.com/nicebag.html and www.examples.com/contact.html without putting non-product webpage names in .htaccess or doing some preliminary processing in the receiving php script.
As I see, the options are:
rewrite all requests to page.php and for those that don't match any of the non-product pages, include the product script
write the non-product page names to .htaccess dynamically (messy and bug-prone)
rethink the URL structure for non-product pages. Perhaps just as little as www.example.com/page/contact.html might help
I'd go for the third one, anyway.
I would recommend flat structure:
domain.com/bags
domain.com/contact
domain.com/nice-bag