.htaccess syntax code needing revision - xcode

1) i am trying to 301 all non www's to www's (including files)
e.g. /subdirectory/ + /subdirectory/1.jpg (all possibilities with the www.)
2) i am trying to exclude ONLY but ALL .html and .php files from showing and would like only the non trailing version to be indexed, the rest to be 301's to my domain
e.g. /example.html or .php >> /example
e.g. /example.html or .php >> to not work + to not be indexed
e.g. /example to ONLY work and to ONLY be indexed (to avoid duplicate content)
3) i am trying to 301 all dead links and 404's to my domain
e.g. /deadlink or /deadlink.pdf >> 301'd to my domain, example.com
Here is the code i currently have, however i am not sure if it's 100% proper.
Can someone please reply with a validated syntax for these 3 tasks? Thanks.
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . / [L,R=301]

OK, you've got three parts you're trying for here, and I'll address them all separately.
Before we begin, you only need to have one
RewriteEngine on
It only needs to be turned on once.
You should also set:
Options -MultiViews
as MultiViews can otherwise cause some weird issues here.
Redirect to WWW
Your current rules should work, but you can simplify them a little using the != prefix on RewriteCond:
RewriteCond %{HTTP_HOST} !=www.example.com
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
Removing .php and .html suffixes
You need two separate sets of rules here: one to remove suffixes from URLs, and another to readd them internally.
Let's do the second half first, since that's easier:
RewriteCond %{SCRIPT_FILENAME}.html -f
RewriteRule ^(.*)$ $1.html [L]
RewriteCond %{SCRIPT_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [L]
With this in place, though, removing suffixes is a little tricky without conflicting with the rule that goes ahead and tries to put them back on. The best approach I was able to come up with was:
RewriteCond %{THE_REQUEST} \.(html|php)
RewriteRule ^(.*)\.(html|php)$ $1 [R=301,L,NC]
But I'm open to suggestions.
301ing all dead links
Don't do that. If a link doesn't exist, it should return a page with a 404 status. If you want to redirect visitors to your home page from dead links, put a link in your 404 page.

Related

Friendly URL for images

Please suggest me what to put into .htaccess file.
I have PNG, GIF, JPG images on server http://domain.tld/images/anyimage.anyextension
Want to make URLs more friendly like a http://domain.tld/anyimage.anyextension
This I have now. First two strings change links as described. But last string doesn't change it back for server.
RewriteCond %{REQUEST_URI} ^/images/(.+)(\.gif|\.jpg|\.png)$ [NC]
RewriteRule ^image/(.+)$ /$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/(.+)$ /images/$1 [L]
If I add
RewriteCond %{REQUEST_URI} ^/([^/.]+\.(png|gif|jpg))$ [NC]
RewriteCond %{DOCUMENT_ROOT}/image/%1 -f
RewriteRule ^([^/.]+\.(png|gif|jpg))$ /image/$1 [L,NC]
Right after previous query string rule then images don't open. If before there's no problem. What it could be? Do you have an idea how to fix it? The last string RewriteRule ^/?(.+)$ /?$1 [L] cause this conflict
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /\?([^\ ]+) [NC]
RewriteRule ^$ /%1? [R=301,L]
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?(.+)$ /?$1 [L]
Not sure how that makes it more friendly, aside from it being shorter. You can try adding this to the htaccess file in your document root:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/([^/.]+\.(png|gif|jpg))$ [NC]
RewriteCond %{DOCUMENT_ROOT}/images/%1 -f
RewriteRule ^([^/.]+\.(png|gif|jpg))$ /images/$1 [L,NC]
Then you can change all of your links from http://domain.tld/images/anyimage.anyextension to http://domain.tld/anyimage.anyextension
The first condition checks to make sure the request is for anyimage.anyextension, as long as the extension is a case-insensitive png, gif, or jpg.
The second condition checks to make sure the requested image actually exists in the /images/ directory.
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /images/(.+)(\.gif|\.jpg|\.png) [NC]
RewriteRule ^image/(.+)$ /$1 [R=301,L]
This redirects the browser to the non-/image/ URL. There's 2 completely different things going on here. One deals with the browser and the other deals with content on the server. See the top part of this answer that explains how they are different.
The rules that you have won't work. First:
RewriteRule ^/(.+)$ /images/$1 [L]
will never match. URI's used to match against the regex of a RewriteRule in htaccess files have the leading slash removed, so no URI is going to start with a /. You need to get rid of it.
Secondly, once you do, you'll get a 500 internal server error because your rules will cause an internal infinite loop. You need to match against %{THE_REQUEST} to ensure that a browser is actually requesting a URL with the /images/ path in it, not what has been internally rewritten.

Protecting image/video folder in cakephp 2.0

We're currently using folders inside webroot to store images and videos which we're loading in views (using the usual html image helper) that require log in.
How can I prevent outside visitors from just doing a site.com/img/photos/1.jpg url and having access to the images?
From what I understand I can't really use media views to render an image inside a proper view, and I can't figure out if there's a solution through htaccess manipulation.
Which is the best practise for this?
Perhaps choosing to go with a non-webroot folder would be best (although that would make it harder in the file-storing part)?
As poncha suggested, I tried editing the main .htaccess file into this
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_REFERER} !localhost
RewriteCond %{REQUEST_URI} ^app/webroot/img/
RewriteRule .* / [L,F]
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
But the rewrite base line seems to be forbidding access to the whole site, and without it there seems to be no change in img access.
Edit 2:
Editing the htaccess inside webroot:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
# this RewriteCond is needed to avoid rewrite loops
RewriteCond %{REQUEST_URI} !^/app/webroot/
RewriteRule (.*) app/webroot/$1 [L,R]
RewriteCond %{HTTP_REFERER} !127.0.0.1
RewriteCond %{REQUEST_URI} ^/app/webroot/img/
RewriteRule .* - [L,F]
</IfModule>
This checks if Referer http header is set to something containing your domain, and denies access to img/ folder if not.
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_REFERER} !site.com
RewriteCond %{REQUEST_URI} ^img/
RewriteRule .* / [L,F]
Note: it is easy enough to "break" this protection if someone wants to steal your content, however, it does prevent hotlinking without the need to produce some sort of script that would pass thorugh all the images/videos to check if access should be granted.
EDIT:
In case your website is not in /, You have two options:
Change RewriteBase to reflect the base uri of the site (eg RewriteBase /app/webroot/)
Change RewriteCond to reflect the path from / (eg RewriteCond ^app/webroot/img/)
The second option is preferred in your case because you have other rules there
EDIT2:
In your case, the whole set should look like this:
RewriteEngine on
RewriteBase /
# this RewriteCond is needed to avoid rewrite loops
RewriteCond %{REQUEST_URI} !^/app/webroot/
RewriteRule (.*) app/webroot/$1 [L,R]
RewriteCond %{HTTP_REFERER} !localhost
RewriteCond %{REQUEST_URI} ^/app/webroot/img/
RewriteRule .* - [L,F]

mod_rewrite aliasing a subdirectory

I'm struggling with mod_rewrite as always. We have a number of client portals running through WordPress multisite, all accessed through a subdirectory: portal.
So for example: http://www.mydomain.com/portal/clientA/
I'd like to be able to get there just by typing http://www.mydomain.com/clientA/ and it would redirect me to http://www.mydomain.com/portal/clientA/
Here's what I have so far, and it's not producing any rewrite that I can tell:
RewriteCond %{REQUEST_URI} /portal/
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule . - [S=1]
RewriteRule /clientA(/?) /portal/clientA/
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
The second part I can't touch because WordPress needs it. My pattern is also trying to anticipate someone not putting in the trailing slash, hence the (/?)
EDIT: I should also note that I don't want to create a more general rule - I'm comfortable having to add a rewrite rule for each new client and increasing the S=x number each time.
EDIT (Aug 11), So after a little more puttering this is what my .htaccess is at:
RewriteEngine On
RewriteRule ^clientA(/?) /portal/clientA/ [R]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Needless to say it doesn't work. However, the first part works IF I delete the entire WordPress section. I need them BOTH to work simultaneously. WHAT is it about the WordPress piece that is causing the failure of the first section? I suppose it's the combination of RewriteBase and the very last rule which aliases anything else to /index.php, which frankly is a bit of a bummer. In fact I don't truly understand how that rule could even work in a multisite context, and yet it seems to.
FINAL SOLUTION
thanks to LazyOne for the correct answer! For others' reference, the final solution I used was:
RewriteEngine On
RewriteRule ^clientA(/.+)? /portal/clientA$1 [R,L]
RewriteRule ^clientB(/.+)? /portal/clientB$1 [R,L]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
As simple as this:
RewriteCond %{REQUEST_URI} !^/portal/
RewriteRule (.*) /portal/$1 [L]
It will rewrite (internal redirect) all requests into /portal/ folder (e.g. /clientA/something => /portal/clientA/something).
If you need to do it for some clients only (or, better say, only specific folders that are clients while still having some general/common folders as is), you can use this rule for each client:
RewriteRule ^clientA(.*) /portal/clientA$1 [L]
So that .htaccess will look like this:
RewriteRule ^clientA(.*) /portal/clientA$1 [L]
RewriteRule ^clientB(.*) /portal/clientB$1 [L]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
I posted part of this as a comment, but figured it might be more clear for people who land here to do this as an answer. To the OPs point, he found a way to do this using the [R] (redirect) line, but this eliminates the subdirectory URL structure you created that would be preferable in most URL Rewrites. So, the answer previously posted is right, I'm not contesting that, but depending on your implementation, you may still get WordPress 404 errors. Here is a solution to my situation, which I think might be more common.
In my case, I needed a URL structure like this:
http://mysite.com/p/profile_name/
Each user who comes to register can create his/her own profile on the fly, and aside from a few modifications to the content, for the most part all of the WordPress content at the root is what will be displayed. Essentially, I need this:
http://mysite.com/p/profile_name/(.*)
To be rewritten to this:
http://mysite.com/$1
This is the .htaccess code posted in the other answer that WILL handle that rule correctly:
RewriteRule ^p/([-a-zA-Z0-9_]+)(/.*) $2 [L]
The problem with this is that WordPress does not care about your rewrite in terms of understanding what $2 is because WordPress uses $_SERVER['REQUEST_URI'], which no matter what you rewrite to, it's always what's in the user's browser window. The OP found a way to get around this by using the [R] option, but that causes you to lose your URL:
RewriteRule ^p/([-a-zA-Z0-9_]+)(/.*) $2 [R,L]
Redirects:
http://mysite.com/p/profile/(.*)
To:
http://mysite.com/$1
But, the user loses his unique URL this way. At best you can add a query string to at least retain the data, but then you lose the point of the pretty URLs to begin with.
I did come up with a solution; however, it involves hacking the WordPress include files :( If someone has a better way, please update. Here we go:
SOLUTION
I set my .htaccess file equal to this:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
#My addition:
RewriteRule ^p/([-a-zA-Z0-9_]+)(/.*) $2 [L]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Then, I knew WordPress used the REQUEST_URI variable, so I did a recursive search, and located this line of code in /wp-includes/class-wp.php (line 147 v3.4.2):
$req_uri = $_SERVER['REQUEST_URI'];
I changed it to this:
$req_uri = preg_replace(#'/^\/?p\/([-a-zA-Z0-9_]+)\//', '', $_SERVER['REQUEST_URI']);
Which basically just tricks WordPress by filtering out the profile stuff at the beginning of the URI.
Lastly, I also needed a solution for the links within the site. For that, I added this filter:
NOTE: Some of these regexes might be a little bonkers; I was filtering out the site specific stuff, so please use this as a concept and not a copy/paste.
function mysite_wp_make_link_relative( $link ) {
$sBaseUrl = (preg_match('/^\/(p\/[-a-zA-Z0-9_]+\/)(.*)/', $_SERVER['REQUEST_URI'], $matches)) ? $matches[1] : '';
return preg_replace( '|https?://[^/]+/(.*)|i', '/' . $sBaseUrl . '$1', $link );
}
function rw_relative_urls() {
$filters = array(
'page_link', // Page link
'home_url',
'site_url',
'get_site_url',
'home_link',
);
foreach ( $filters as $filter ) {
add_filter( $filter, 'mysite_wp_make_link_relative' );
}
}
Some of those filters might not be relevant; I'm pretty sure page_link and home_url are the only important ones. Anyway, you need that code for your internal linking to work.
I hope that helps and if anyone has any comments suggestions for improving this, I would greatly appreciate it.

How to redirect an url with parameters?

I'm at a total loss trying to integrate a mod_rewrite in my existing page. Currently, I am building a new site from scratch, and there i have some nice clean url's such as:
http://www.example.nl/nl/example
The old site, running Cms made simple, has some not-rewritten url's that would need to be redirected to the new pages. Those url's look like this:
http://www.example.nl/index.php?page=cake-and-pie&hl=nl_NL
But shorter versions of that like:
http://www.example.nl/index.php?page=cake-and-pie
also work.
It took me a while to figure out that url's with parameters cannot simply be redirected with "Redirect 301", like i'd normaly do. So i tried some online mod_rewrite generators like this and this, but the rules outputted by those result only in 404 errors, (the redirect doesn't work at all).
My .htaccess file current looks like this:
RewriteEngine On
RewriteBase /
# remove .php;
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index
RewriteRule (.*)/index$ $1/ [R=301]
# remove slash if not directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# add .php to access file, but don't redirect
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
The old pages would seize to exist.
How do i redirect the old pages to the new ones?
Thanks.
EDIT
RewriteCond %{QUERY_STRING} =page=pie
RewriteRule ^index\.php$ /nl/? [L,R=301]
RewriteCond %{QUERY_STRING} =page=pie&hl=nl_NL
RewriteRule ^index\.php$ /nl/? [L,R=301]
Seems to do the trick. This is of course manual for every url, but i only have a few.
RewriteEngine On
RewriteBase /
RewriteRule ^(.+)/([^/]+)/?$ index.php?page=$1&hl=$2
RewriteRule ^([^/]+)/?$ index.php?page=$1 [QSA]

mod_rewrite precedence

Let's say I want to support urls like twitter where:
twitter.com/username redirects to twitter.com/user_name.php?user=username
I have the following
RewriteRule ^(.*)$ user_name.php?user=$1
And that works fine. But the problem is now that everything, including twitter.com/index.php will of course redirect to user_name.php
How can I either create exceptions or precedence so that "real files" don't get rewritten? I tried adding an explicit rule for index.php before and after that one, but it doesn't seem to take effect.
You need to add RewriteCond for this
RewriteCond %{REQUEST_URI} !-f [OR] # for existing files
RewriteCond %{REQUEST_URI} !-d # for existing directories
RewriteRule ^(.*)$ user_name.php?user=$1

Resources