Configure htaccess for url rewriting - apache

I need help for my url's rewriting. I want to organize my url's precisely by taking account of the current organization of my current tree:
-! /www
.htaccess,
index.php, ...
--! **/views**, /assets
pageA.php, pageB.php, pageC.php
---! **/pageA**, /pageB, /pageC, /errors (404.php, 500.php...)
pageA1.php, **pageA2.php**, pageA3.php
/!\ I use specific names for each pages, the prefixes and numbers are just for examples and for a better comprehension about connexions between files and folders. In reality I use pages names like: "contact-us.php", "our-product.php" ...
(1) When I going to pageA.php I would like this url path: www.mywebsite.fr/pageA
(2) When I going to pageA2.php, I would like: www.mywebsite.fr/pageA/pageA2
(3) I don't want extension files (.php, .html)
Actually, I can't go into the path (2) cause I have a 404 page.
I created folders with the same name as a specific php pages it's just for my own organization, but it can be a bad way (for SEO or anything else...) in fact, I don't know...
My rewrite module (in .htaccess of www) is:
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
# Retirer les extensions des pages et les rendres accessibles en lecture
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.php
RewriteRule ^/?(.*)\.php$ /$1 [L,R=301]
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php [L]
# Suppression d'un sous répertoire
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/views/$1.php -f
RewriteRule (.*) /views/$1.php [QSA,L]
</IfModule>

This is just off the top of my head, but it should work:
RewriteRule ^page([A-Z]{1})([1-9]?).php$ http://www.mywebsite.fr/page$1$2
RewriteRule ^page([A-Z]{1})([1-9]{1})$ http://www.mywebsite.fr/page$1/page$1$2 [L,R=301]
The first Rewrite directive checks for a filename match starting with
page
and ending (prior to the filename extension, .php) with
a single letter (from A to Z); and
(optionally) a single number (from 1 to 9)
If it does, it captures both the letter (and the optional number) and rewrites the URI without the .php file extension at the end.
For those URIs which do include the optional number, the second Rewrite directive captures both the letter and the number separately from each other.
It then builds the redirect according to the correct folder structure, deploying both the captured letter and the captured number.

Related

Why my htaccess is not working when i upload it to ionos webspace?

I've tried in in my localhost at it worked fine but after I upload it to my ionos webspace the website index is working but after I click the content it is not directing to anywhere and there is an error message:
Error 404 not foound, Your browser can't find the document corresponding to the URL you typed in.
Here is my .htaccess:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^news/([0-9a-zA-Z_-]+) news.php?url=$1 [NC,L]
RewriteRule ^seksikateg/([0-9a-zA-Z_-]+) seksikateg.php?kategori=$1 [NC,L]
and i placed he file in the same place as the index.php, news.php, and seksikateg.php
It's possible that MultiViews is enabled at your host and this will break your rules since this will append the .php extension before mod_rewrite processes the request.
However, your directives are also in the wrong order. The generic rewrite to append the .php extension should appear after the other rules.
Your rewrite to append the .php extension is not strictly correct as it could result in a rewrite loop (500 error) under certain circumstances.
Try it like this instead:
# Ensure that MutliViews is disabled
Options -MultiViews
RewriteEngine on
RewriteRule ^news/([0-9a-zA-Z_-]+)$ news.php?url=$1 [NC,L]
RewriteRule ^seksikateg/([0-9a-zA-Z_-]+)$ seksikateg.php?kategori=$1 [NC,L]
# Append ".php" extension on other URLs
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
I've also added the end-of-string anchor to the regex of your existing rewrites, otherwise you are potentially matching too much. eg. /news/foo/bar/baz would have also been rewritten to news.php?url=foo - potentially creating duplicate content and opening up your site to abuse.
I would also question the use of the NC flag on these rewrites. If this is required then you potentially have a duplicate content issue.
No need to backslash-escape literal dots in a regex character class and the NC flag is certainly redundant on the last rule.

Convert Query Parameters to Pretty URL

I have script file post.php which I'm using without .php extension using code below
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
I want to use a pretty URL. For example, when I request the URL /post/12 it should give me $_GET parameter 12 like I'm using with a query string: post?id=12.
Is it possible? Also, I don't want to direct all requests to index.php. Only requests that are made to posts.php script.
Handle requests of the form /post/12 with a separate rule, before your generic rewrite that appends the .php extension.
Try it like this:
Options -Indexes -MultiViews
RewriteEngine On
# Remove trailing slash if not a directory
# eg. "/post/" is redirected to "/post"
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ /$1 [R=301,L]
# Rewrite "/post/<id>" to "/post.php?id=<id>"
RewriteRule ^(post)/(\d+)$ $1.php?id=$2 [L]
# Rewrite "/post" to "/post.php" (and other extensionless URLs)
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
Notes:
MultiViews needs to be disabled for the second rule to work.
Your initial rule that appends the .php extension was not quite correct. It could have resulted in a 500 error under certain conditions. However, the first condition was superfluous - there's no point checking that the request does not map to a file before checking that the request + .php does map to a file. These are mutually inclusive expressions.
Without the first rule that removes the trailing slash (eg. /post/ to /post) it raises the question of what to do with a request for /post/ (without an id) - should this serve /post.php (the same as /post) or /post.php?id= (empty URl param)? Both of which are presumably the same thing anyway. However, these would both result in duplicate content (potentially), hence the need for a redirect.

Dynamically pointing multiple domains to a single domain's subfolder with .htaccess

In this example, I manage domain.com. Inside it, I have a store template in php that loads the selected store dinamically:
domain.com/store1
domain.com/store2
domain.com/store3
The nice urls are being generated by the .htaccess below. What's really being loaded in the back, is this:
domain.com/store/index.php?store=store1
domain.com/store/index.php?store=store2
domain.com/store/index.php?store=store3
Each store has internal links, such as these:
domain.com/store1/catalogue
domain.com/store1/catalogue/instruments
domain.com/store1/catalogue/instruments/guitars
domain.com/store1/electric-guitar/1337
It works exactly as expected. These are the .htaccess rules to make that work in domain.com. The store query string (store1, store2, store3) in each RewriteRule determines which store is being loaded:
# permalinks
RewriteEngine on
# errors
ErrorDocument 404 /error.php?error=404
# ignore existing directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
#################################################
# store
RewriteRule ^([0-9a-zA-Z-]{2,50})/?$ store/index.php?store=$1 [QSA,L]
# store: catalogue
RewriteRule ^([0-9a-zA-Z-]{2,50})/catalogue/?$ store/catalogue.php?store=$1 [QSA,L]
RewriteRule ^([0-9a-zA-Z-]{2,50})/catalogue/([0-9a-zA-Z-]{1,75})/?$ store/catalogue.php?store=$1&cat=$2 [QSA,L]
RewriteRule ^([0-9a-zA-Z-]{2,50})/catalogue/([0-9a-zA-Z-]{1,75})/([0-9a-zA-Z-]{1,75})/?$ store/catalogue.php?store=$1&cat=$2&subcat=$3 [QSA,L]
# store: products
RewriteRule ^([0-9a-zA-Z-]{2,50})/([0-9a-zA-Z-]{1,150})/([0-9]+)$ store/product.php?store=$1&slug=$2&id_product=$3 [QSA,L]
Now, here comes the tricky part. Some of the clients, would like to use their own domains, so that store1.com/* loads the same content of domain.com/store1/* (without using a redirect).
Example:
store1.com => domain.com/store1/
store1.com/catalogue => domain.com/store1/catalogue
store1.com/catalogue/instruments => domain.com/store1/catalogue/instruments
store1.com/catalogue/instruments/guitars => domain.com/store1/catalogue/instruments/guitars
store1.com/electric-guitar/1337 => domain.com/store1/electric-guitar/1337
You get the idea.
All the domains (domain.com, store1.com, store2.com, store3.com) are configured in the same Apache Web Server environment (using virtual hosts).
The question is: Can this be implemented in a .htaccess file in each one of the store's domain root path dynamically or inside the virtualhost .conf file? If so, how?
Make sure all your custom "store" domains (eg. store1.com, store2.com, etc.) are defined as ServerAlias in the domain.com vHost and so resolve to the same place as domain.com.
You can then rewrite requests for the custom store domain to prefix the URL-path with the store-id (the domain name) and then use your existing rules unaltered.
For example, a request for store1.com/catalogue/instruments is internally rewritten to /store1/catalogue/instruments and then processed by the existing rules as usual.
The following directives should go before the existing # store rules:
# Internally rewrite the request when a custom domain is used
# - the URL-path is prefixed with the domain name
RewriteCond %{HTTP_HOST} !^(www\.)?domain\. [NC]
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}#%1 !^/([^/]+)/.*#\1
RewriteRule (.*) %1/$1
And that's basically it, although you may also decide to implement a canonical redirect - see below.
Explanation of the above directives:
The first condition simply excludes requests for the main domain.com (which should already have the relevant store-id prefixed to the URL-path).
%{REQUEST_URI} !\.\w{2,4}$ - The second condition avoids rewriting requests for static resources (images, JS, CSS, etc.). Specifically, it excludes any request that ends in - what looks like - a file extension.
%{HTTP_HOST} ^([^.]+) - The third condition captures the requested domain name before the TLD which is then accessible using the %1 backreference later and used to prefix the URL-path. This assumes there is no www subdomain (as stated in comments). eg. Given a request for store1.com or store2.co.uk, store1 or store2 respectively are captured.
%{REQUEST_URI}#%1 !^/([^/]+)/.*#\1 - The fourth condition checks that the URL-path is not already prefixed with the domain name (captured above). This is primarily to ensure that rewritten requests are not rewritten again, causing a rewrite loop. This is achieved using an internal backreference (\1) that compares the first path-segment in the URL-path against the previously captured domain name (%1).
(.*) %1/$1 - Finally, the request is internally rewritten, prefixing the domain name to the requested URL-path.
Ignore existing files (may not be required)
# ignore existing directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
You've not stated how you are referencing your static resources (images, JS, CSS, etc.), but you may need to modify this rule to also match requests for existing files. (Although the condition I added to the rule above may already be sufficient to exclude these requests.) For example:
# ignore existing directories or files
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
Canonical redirect (optional)
You should also consider redirecting any direct requests of the form store1.com/store1/catalogue/instruments back to the canonical URL store1.com/catalogue/instruments - should these URLs ever be exposed/discovered. A request of the form store1.com/store2/catalogue/instruments will naturally result in a 404, so is not an issue.
For example, the following would go immediately after the ErrorDocument directive in your existing rules:
# Redirect to remove the "/store1" URL-prefix when the "store1.com" domain is requested.
# - Only applies to direct requests.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} !^domain\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}#%1 ^/([^/]+)/.*#\1
RewriteRule ^(?:[^/]+)(/.*) $1 [R=301,L]
Test first with a 302 (temporary) redirect to avoid potential caching issues.
This is basically the reverse of the above rewrite, but applies to direct requests only. The check against the REDIRECT_STATUS env var ensures that only direct requests from the client and not rewritten requests by the later rewrite are processed.
Summary
With the two rule blocks in place...
# permalinks
RewriteEngine on
# errors
ErrorDocument 404 /error.php?error=404
# Redirect to remove the "/store1" URL-prefix when the "store1.com" domain is requested.
# - Only applies to direct requests.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} !^domain\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}#%1 ^/([^/]+)/.*#\1
RewriteRule ^(?:[^/]+)(/.*) $1 [R=301,L]
# ignore existing directories
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Internally rewrite the request when a custom domain is used
# - the URL-path is prefixed with the domain name
RewriteCond %{HTTP_HOST} !^(www\.)?domain\. [NC]
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteCond %{REQUEST_URI}#%1 !^/([^/]+)/.*#\1
RewriteRule (.*) %1/$1
#################################################
# store
:
: existing directives follow
:

Mod Rewrite & CheckSpelling/CheckCase redirect solution

I have a number of pages setup, to be accessed by clients' guests. The problem being, case sensitive URLs.
Currently I have in my htaccess file (to remove the .php)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) $1.php [L]
for example: (the target file is ClientName.php)
website.com/rsvp/ClientName <-this works, and the file is ClientName.php
website.com/rsvp/clientname <-this serves a Internal Server Error
-- edit/update --
Adding both CheckSpelling on & CheckCaseOnly on does not work, unless the .php is in the url. No combination of the two [mod_spelling & mod_rewrite] would work. I also found out, I do not have RewriteMap
based on this thread/post can I redirect to a php file rather than the 500 error page if the file does not exist? (or edit my 500 error page?)
from the post;
RewriteCond %{REQUEST_URI} !^([a-z0-9/]*)\.html
RewriteRule ^(.*)\.html$ redir.php?p=$1 [L]
Will examine the {REQUEST_URI} string and EXCLUDE (!) everything that's lowercase (or directory -- see the "/"?) .html then rewrite EVERYTHING.html to the redir script. Ahhhhh! I just added the "0-9" in there to handle your digits, too. Remember, these "excluded" strings are the ones you want to PASS through to your pages and NOT rewrite.

Mod Rewirte for CalDav and CardDav urls in Owncloud

I want to shorten my owncloud caldav and carddav urls.
currently the urls are :
https://site.mysite.com/owncloud/remote.php/caldav/principals/edison/
https://site.mysite.com/owncloud/remote.php/carddav/addressbooks/edison/contacts
Note : The name edison and what ever follows after that is dynamic it will change depending on the users.
I want it to be
https://site.mysite.com/caldav/principals/edison/
https://site.mysite.com/carddav/addressbooks/edison/contacts
.htaccess file contains
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !\.sso/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Eg:
If the user request for https://site.mysite.com/caldav/principals/edison/ . Then it should redirect to https://site.mysite.com/owncloud/remote.php/caldav/principals/edison/
How can it be done using mod_rewrite ?
mod_rewrite Prepend Path to Requested URL with Dynamic Portion
Starting at server root, enter the requested URL path in the RewriteRule "pattern" parameter, and the desired path in the "substitution" parameter. In the form:
RewriteRule pattern substitution [flags]
In this case:
RewriteRule ^caldav/principals/edison/$ owncloud/remote.php/caldav/principals/edison/ [L]
If a portion of the URL (between slashes) varies and you don't want to (or can't) write a rule for every situation then use the regular expression ([^/]+) to capture the dynamic portion and inject it into your substituted path using the RE capture variable $1:
RewriteRule ^caldav/principals/([^/]+)/$ owncloud/remote.php/caldav/principals/$1/ [L]
The first set of parenthesis is $1, the second set is $2, etc. And capturing parenthesis can be nested.
Put the more specific rules higher in the rules list, and more general rules lower in the list. So I suggest putting this rule first, right after RewriteBase /.