htaccess rewrite url to hide variable - .htaccess

My knowledge of htaccess is pretty limited, so please be gentle...
I have a php page that displays an article, based on a variable passed through the url. For each article, I want the url to be changed to the article title, but I can't lose the article id being passed to the page...
So, for ...
www.somesite.com/news/article?id=4
... I can change it to ...
www.somesite.com/news/here-is-the-article-title
Or for
www.somesite.com/news/article?id=7
... I can change it to ...
www.somesite.com/news/some-other-title-that-I-choose
Bascially, I want the content for "article?id=4" to be shown on the page, but the URL to read "here-is-the-article-title". Is this even possible using htaccess? Or is there a similar solution? I know that I'll probably have to rewrite EACH url, and I'm fine with that.
I have some standard htaccess code I use...
Options +FollowSymLinks -MultiViews
# enable the rewrite engine
RewriteEngine On
# Set your root directory
RewriteBase /
# remove the .php extension
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index and reference the directory
RewriteRule (.*)/index$ $1/ [R=301]
# remove trailing slash if not a directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# forward request to html file, **but don't redirect (bot friendly)**
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
# Disable Directory Browsing
Options -Indexes
# Protect htaccess File
<files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
satisfy all
</files>
Basic REDIRECT doesn't work, since I lose the article id.

Related

Htaccess, go through files until exists?

I have this .htaccess file:
Options +FollowSymLinks
Options -Indexes
RewriteEngine On
RewriteEngine On
RewriteRule \.(png|jpg|gif|jpeg|bmp|ico|flv|mpeg|mp4|mp3|swf|exe|WAgame|wsc|eot|svg|ttf|woff|woff2|rar|wav)$ - []
RewriteRule ^ entryPoint3.php
RewriteRule ^ entryPoint2.php
RewriteRule ^ entryPoint.php
RewriteRule ^robots\.txt$ http://www.example.com [R,NE,L]
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST} [L,R=301]
<Files .htaccess>
Order Allow,Deny
Deny from All
</Files>
If the entryPoint3.php exists, load it, otherwise load entryPoint2.php otherwise entryPoint.php. How to achieve this?
Have it this way:
Options +FollowSymLinks -Indexes
RewriteEngine On
RewriteRule \.(png|jpg|gif|jpeg|bmp|ico|flv|mpeg|mp4|mp3|swf|exe|WAgame|wsc|eot|svg|ttf|woff|woff2|rar|wav)$ - [L]
RewriteRule ^robots\.txt$ / [R,NC,L]
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
# if entryPoint3 exists then use it
RewriteCond %{DOCUMENT_ROOT}/entryPoint3.php -f
RewriteRule ^ entryPoint3.php [L]
# if entryPoint2 exists then use it
RewriteCond %{DOCUMENT_ROOT}/entryPoint2.php -f
RewriteRule ^ entryPoint2.php [L]
# if entryPoint exists then use it
RewriteCond %{DOCUMENT_ROOT}/entryPoint.php -f
RewriteRule ^ entryPoint.php [L]
<Files .htaccess>
Order Allow,Deny
Deny from All
</Files>
I solved it like that: DirectoryIndex entryPoint3.php entryPoint2.php entryPoint.php what's the difference?
...but remember it will try to open entryPoint files in every directory not just in site root
You can specify root-relative URL-paths as arguments to the DirectoryIndex directive, they do not need to be relative, as you have here. For example:
DirectoryIndex /entryPoint3.php /entryPoint2.php /entryPoint.php
This will search for files in the document root only, regardless of which directory is requested.
But also, this is quite different to #anubhava's solution using mod_rewrite (and similar to what you were attempting in the question). With DirectoryIndex, the necessary file will only be served if you are requesting a directory (which includes the document root, ie. https://example.com/). eg. example.com/ and example.com/directory/ will trigger the relevant entryPoint file, but example.com/something will not.
However, with the mod_rewrite solution as stated, the relevant entryPoint file is served for "any" requested URL (except for the few URL-extension exceptions as stated). eg. example.com/, example.com/something, example.com/file.php and example.com/directory/ will all trigger the relevant entryPoint file.
For the mod_rewrite solution to work the same way as DirectoryIndex you will need an additional condition that explicitly checks that the request maps to a directory (including the trailing slash). For example:
# When requesting a directing... if entryPoint3 exists (in the root) then use it
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{DOCUMENT_ROOT}/entryPoint3.php -f
RewriteRule ^(.+/)?$ entryPoint3.php [L]
:
The RewriteRule pattern simply checks that the requested URL ends with a slash (or is the document root) - the same behaviour as DirectoryIndex. (If you request a directory without a trailing slash then mod_dir appends it with a 301 redirect.)
So the solution you choose really depends on your requirements. However, if DirectoryIndex is working for you then I assume you are only requesting filesystem directories, so DirectoryIndex would be the way to go.

.htaccess specific url changes

I've a small, but hard to understand problem with .htaccess in CMS system.
I've mod expires, that cache stuff on whole website, but I don't want to cache stuff in /admin URL, I can't make another .htacess, couse I've MVC structure and no real directory that could hold all my admin stuff.
I've found directive, but it only works in server configuration and I want it to work on different hostings, so only in htaccess file.
EDIT- Rewrite
# Turn on URL rewriting
RewriteEngine On
# Installation directory
RewriteBase /
RewriteCond %{HTTP_HOST} !^www. [NC]
RewriteCond %{HTTP_HOST} ![0-9]$ [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [L,R=301]
# Protect hidden files from being viewed
<Files .*>
Order Deny,Allow
Deny From All
</Files>
# Protect application and system files from being viewed
RewriteRule ^(?:application|modules|system)\b.* index.php/$0 [L]
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php/$0 [PT]
You can apply your Expires directive using a <if> directive with an expression to match against /admin:
<If "%{REQUEST_URI} =~ /^\/admin\//">
# Your expiry directives
</If>
If you know the exact URL then you can try this pattern.
RewriteRule ^facebook/get/(.*)?$ http://$1 [NC,R]
RewriteRule ^wrapper/share/(.*)?$ http://example.com/wrapper/share/$1 [NC,R]
This will check for URL where <-any-value->facebook/get/<-any-value2-> and then will send to the <-any-value2->
Like
RewriteRule ^stats/(.*)$ admin/dashboard.php?mode=openstats&event_id=$1 [NC,L,QSA]
**If URL has stats/<--any-value--> then it will redirect/open admin/dashboard.php **
If your URLs doesn't have exact value but you do know the URL slot pattern then you can try this.
RewriteRule ^([^/.]+)/([a-zA-Z0-9_-]+)/$ wrapper/index.php?id=$2 [NC,L,QSA]

htacces redirect for SEO friendly URLs

I have my htaccess file setup, so that the pages remove extensions. Now, I am trying to make the pages that transfer variables, into SEO friendly urls ... so, for example...
http://www.example.com/art-gallery?page=2 ... which is actually "art-gallery.php?page=2", would turn into... http://www.example.com/art-gallery/page/2
Or... http://www.example.com/art-piece?id=3 ...would go to... http://www.example.com/art-piece/id/3
... and so on ...
I have alot in my htaccess file, and am not sure how to do the above (there are plenty of tutorials on going from www.example.com/index.php?page=2 to www.example.com/page/2/ but none that do exactly what I need). Ideally, I'd like to be able to do this for all similar pages...
# enable the rewrite engine
RewriteEngine On
# Set your root directory
RewriteBase /
# Force www:
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301,NC]
# Remove the .php extension
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# Remove index and reference the directory
RewriteRule (.*)/index$ $1/ [R=301]
# Remove trailing slash if not a directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# Forward request to html file, **but don't redirect (bot friendly)**
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
# Disable Directory Browsing
Options -Indexes
# Disable Hotlinking of Images
# with forbidden or custom image option
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ – [NC,F,L]
# Protect htaccess File
<files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
satisfy all
</files>
You can transfer parameters with the variable QUERY_STRING.
Consider the following rule:
RewriteRule ^index.html index.php?%{QUERY_STRING}&m=main&a=index
This rule would transform
index.html?something=value
into
index.php?something=value&m=main&a=index
You should use the RewriteEngine.
You could also use a 301 redirect either alone or in conjunction with the RewriteEngine to redirect SEs.
Generally, though redirecting SEs to a different page than what users will see is not a good practice, and may result in your pagerank decreasing. Instead, try migrating all your pages to the second URL format, and consider using 301 redirects to help the transition.
Generally: Use 301 redirects for SE-friendly page changes. See this SO for additional reference.
You can insert this rule just before Forward request to html file rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/])/([^/])/([^/])/?$ $1.php?$2=$3 [L,QSA]
This is quite old but why not do the following:
RewriteEngine On
RewriteRule ^([^?]*) index.php?route=$1 [L,QSA]
Then in your index.php you can handle it like such;
if (isset($_GET['route'])) {
$route = explode('/', $_GET['route']);
if (iconv_strlen((end($parts)), 'UTF-8') == 0) {
array_pop($parts);
}
}
From here your main level would be handled with $route[0], second level $route[1]
For example;
http://example.com/art-gallery/2
$route[0] would equal 'art-gallery'
$route[1] would equal '2'

.htaccess rewrite file uri to either file-name.html or file-name.php - whichever exists

OBJECTIVE: To cause the browser to rewrite to file-name.php, if it exists; else return file-name.html - whether the visitor has typed the url as any one of the following:
http://mydomain.com/file-name
http://mydomain.com/file-name.html
http://mydomain.com/file-name.php
Had good success with the following rules in my .htaccess file at root:
# REWRITE FILE URI TO file.php IF EXISTS
Options Indexes +FollowSymLinks +MultiViews
Options +ExecCGI
RewriteEngine on
RewriteBase /
# parse out basename, but remember the fact
RewriteRule ^(.*).html$ $1 [C,E=WasHTML:yes]
# rewrite to document.php if exists
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [S=1]
# else reverse the previous basename cutout
RewriteCond %{ENV:WasHTML} ^yes$
RewriteRule ^(.*)$ $1.html
However, I have since installed WP at root, alongside pre-existing website, and these rules are no longer working.
WHAT DOES WORK: file-name is rewritten to either file-name.html or file-name.php - whichever file exists.
WHAT DOES NOT WORK: file-name.html is not rewritten to file-name.php even when there is no file-name.html and file-name.php is there. Also, file-name.php is not rewritten to file-name.html when there is no file-name.php but there is file-name.html.
The entire .htaccess as it is now:
# BEGIN WP MULTISITE RULES
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
# uploaded files
RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) wp-includes/ms-files.php?file=$2 [L]
# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^[_0-9a-zA-Z-]+/(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^[_0-9a-zA-Z-]+/(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
# END WP MULTISITE RULES
# REWRITE FILE URI TO file.php IF EXISTS
Options Indexes +FollowSymLinks +MultiViews
Options +ExecCGI
RewriteEngine on
RewriteBase /
# parse out basename, but remember the fact
RewriteRule ^(.*).html$ $1 [C,E=WasHTML:yes]
# rewrite to document.phtml if exists
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [S=1]
# else reverse the previous basename cutout
RewriteCond %{ENV:WasHTML} ^yes$
RewriteRule ^(.*)$ $1.html
Any advices?
Quick overview tells that your original rules most likely will never get reached as WP rules should intercept all requests.
This line RewriteRule ^ - [L] with those conditions will abort rewriting for any already existing files or folders, while this line RewriteRule . index.php [L] will intercept/redirect all requests to index.php.
If you move your rules above WordPress one, then it will work again.
To rewrite request for non-existing .php file to .html file use this rule:
# rewrite non-existing .php file to existing .html
RewriteCond %{DOCUMENT_ROOT}/$1.php !-f
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule ^(.+)\.php$ $1.html [L,PT]
Place it below your rules (but above WP). The rule will check if .php files does not exist and rewrite will only occurs if .html file is present. If both files are unavailable then nothing will happen.
Keep in mind that because of these checks and the fact that rule is on the top of rewrite chain, this rule will be evaluated for every request to .php file (even WP pages) which may put extra pressure on very busy server. Ideally you would like to have proper URLs in first place so there will be no need for such manipulations.

Deny direct access to files or directory using .htaccess

I'm playing with .htaccess and I was wondering if with just an .htaccess inside the root directory is possible to block all the request from a browser directed on existing files or directories.
Let's try this example:
RewriteEngine On
RewriteBase /~my_user/my_base/
RewriteRule ^list/$ list.php [L]
RewriteRule ^element_of_list/([a-zA-Z0-9\-]+)/$ element.php?elem_id=$1 [L]
Now, if I write http://127.0.0.1/~my_user/my_base/list/, this is wroking fine but if I write http://127.0.0.1/~my_user/my_base/list.php it's still working. I don't want that. I want the user to obtain a 404 error in the last case.
We have /etc/apache2/mods-enabled/userdir.conf
<IfModule mod_userdir.c>
UserDir public_html
UserDir disabled root
<Directory /home/*/public_html>
AllowOverride All
Options Indexes FollowSymLinks
<Limit GET POST OPTIONS>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST OPTIONS>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>
</IfModule>
My first try was to use RewriteCond:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*)$ 404.php [L]
But it's not working. Every request ends up redirected to 404.php
UPDATE
So I've managed to create the filter for directories:
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !^/~my_user/my_base/$ [NC]
RewriteRule ^(.*)$ 404.php [L]
What it does is to check if the requested path (REQUEST_FILENAME) exists and it's a directory AND if it's not my RewriteBase which is basically index.php, then redirect to 404.php
I'm still trying to find something that does the same thing for files. I know I can selectively do that using extensions filename but I want an universal filter for files.
If I've understood your requirements correctly, you're looking to do something like this:
# This is a real directory...
RewriteCond %{REQUEST_FILENAME} -f [OR]
# Or it's a real file...
RewriteCond %{REQUEST_FILENAME} -d
# And it's not 404.php...
RewriteCond $0 !=404.php
# And it's not the root
RewriteCond $0 !=""
# And it's not any of the above due to an internal redirect...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
# So cause a 404 response (you could redirect to 404.php if you want)
RewriteRule ^.*$ - [R=404,L]
# Set the 404 error document
ErrorDocument 404 /~my_user/my_base/404.php
Keep in mind that this blocks everything that exists, so any images, stylesheets, or scripts will be sent to the 404 page too. If you just want to block access to the PHP files, Gumbo's solution is more appropriate. I think in that case you'll need another RewriteCond though to prevent looping:
# Make sure the reason this request has a .php is because it was requested
# by the user (and not due to a redirect)
RewriteCond %{THE_REQUEST} ^[A-Z]+\s/[^\s]+\.php
# Make sure we aren't on 404.php already
RewriteRule %{REQUEST_URI} !404\.php$
# We aren't, so redirect to 404.php
RewriteRule ^ 404.php [L]
Try this rule:
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /[^?\ ]*\.php[/?\ ]
RewriteRule .*\.php$ 404.php [L]
This will rewrite all requests whose paths contain a .php internally to 404.php.

Resources