2 different .htaccess rules - php

I am trying to set up for my website two different .htaccess rules, but I still cannot find the correct solution.
I would like to route everything on website.com/almost-everything - this is working me well. And further, I would like to add yet this route: website.com/car/car_id - and here comes troubles, I don't know how to set up it.
Here are my attempts:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?skill=$1 [L,QSA]
RewriteRule ^car/(.*)$ ./index.php?id=car&car_id=$1 # the wrong rule - the page with website.com/car/car_id just doesn't display the correct file
Could you help me please with the second rule?

Instead of
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?skill=$1 [L,QSA]
RewriteRule ^car/(.*)$ ./index.php?id=car&car_id=$1 # the wrong rule - the page with website.com/car/car_id just doesn't display the correct file
I would do this
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+) - [PT,L] ## passthru + last rule because the file or directory exists. And stop all other rewrites. This will also help your css and images work properly.
RewriteRule ^car/(.*)$ /index\.php?id=car&car_id=$1 [L,QSA]
RewriteRule ^(.*)$ /index\.php?skill=$1 [L,QSA]
P.s. I seperated my rules with blank lines so it is clear how many there are. The above shows 3 distinct rules.

Rewrite works line by line, from the top to the bottom.
After checking the initial conditions (file doesn't exists), it encounters your first rule.
It says, if the URL is anything, modify it. It also has two options:
"QSA" means append the query string
"L" means this is the last rule, so stop processing
Because of this "L", it stops the processing, and nothing happens after this rule.
To fix this:
change the order of your rules, since "car/" is more specific
also add the L and QSA flags to the "car/" rule.
So:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^car/(.*)$ ./index.php?id=car&car_id=$1 [L,QSA]
RewriteRule ^(.*)$ index.php?skill=$1 [L,QSA]

A better solution would be, to redirect all your request to index.php, and then parse $_SERVER['REQUEST_URI']. Then you newer need to change htaccess for every new future.
In apache you can do that like this >
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php [L]
In php you can manualy fill your $_GET, so it would look like your old requests...
$f = explode('/', substr($_SERVER['REQUEST_URI'], 1));
switch ($f[0]) {
case 'car' :
$_GET['id'] = $f[0];
$_GET['car_id'] = $f[1];
break;
default:
$_GET['skill'] = $f[0];
}
# your old code, that reads info from $_GET
A better practice it would be to make class, that will take care of the urls.

Related

How to stop RewriteEngine/PHP redirect loop?

The task seems very simple:
all requests must be passed through one file.
However,
when following code is added to httpd.conf:
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ /index.php?route=$1 [QSA,R=301,L]
and following code is added to /index.php:
if( isset($_GET["route"]) && $_GET["route"] != "/index.php" ){
header("Location: ".$_GET["route"]);
}
then it causes redirect loop!
Causes for example such loop:
www.site.com/image.jpg -> (redirected by httpd.conf)
www.site.com/index.php?route=/image.jpg -> (redirected by index.php)
www.site.com/image.jpg -> (redirected by httpd.conf)
www.site.com/index.php?route=/image.jpg -> (redirected by index.php)
...
So, the question is following:
How to stop this loop?
To stop for example in such way:
www.site.com/image.jpg -> (redirected by httpd.conf)
www.site.com/index.php?route=/image.jpg -> (redirected by index.php)
www.site.com/image.jpg (no further redirection)
This one is a bit of patch, but I think it works.
httpd.conf:
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{QUERY_STRING} !^(.*)a=a$ [NC]
RewriteRule ^(.*) index.php?route=$1 [QSA,L]
index.php:
<?php
if( isset($_GET["route"]) && $_GET["route"] != "/index.php" ){
header("Location: ".$_GET["route"].'?a=a');
}
The thing is: First time the rewrite engine redirects the page to index.php. Then, in index.php there's a redirection to the same file but adding parameter a=a. Then rewrite engine comes again, but he has orders of not redirect when found the string a=a in the query string, and there's no further redirection.
Of course this will end in a 404 error, since you're filtering only non-existant files with the first two rewritecond, but I guess you know how to deal with that.
Your rule looks fine but R=301 is a bit odd in your rule as you don't want to expose your internal URL in browser.
However PHP code is looking suspect due to this condition:
$_GET["route"] != "/index.php"
Which will always be true since /index.php itself will not be routed through this rule due to these conditions:
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
Hence your code will cause a redirect loop by continuously redirecting using header function.
I suggest keep your rule like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ /index.php?route=$1 [QSA,L]
And your PHP code should just check presence of $_GET['route'] but should not do any redirects.
First, put this to .htaccess file, not in httpd.conf
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php [QSA,R=301,L]
Then, remove this redirect from your index.php file. You can get all your variables via $_GET or $_REQUEST.
What a senseless solutions. Of course it will cause redirect loop. In the RewriteCond-s you trying to catch files and dirs names that not exists in the server file system, and then you trying to pass their names to the index.php in which you make to request them again, again and again.
There is a single boilerplate that may come in handy, it should be placed on the top, after RewriteEngine on condition:
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} !^[\s/]*$
RewriteRule ^ - [L]
An env was added, it works by theory, however I have tested it only once, see if it can solve the issue.
Why are you putting this:
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ /index.php?route=$1 [QSA,R=301,L]
In httpd.conf? You need to place this into file called .htaccess, create it into your root directory.

htaccess add .html extension for urls with or without trailing slash

So to begin with I have a custom url rewrite that sends a request variable to a php script
Rewrite rule is below:
RewriteRule ^([\w\/-]+)(\?.*)?$ test/index.php?slug=$1 [L,T=application/x-httpd-php]
So if you access something like domain.com/slug-text it sends slug-text to index.php located in folder named test.
What I want is all my urls to look like domain.com/slug-text.html, but slug-test variable should still be sent to index.php file.
And
What I can't figure out is the redirect. I want all the old urls to be redirected from domain.com/slug-text or domain.com/slug-text/ to domain.com/slug-text.html and slug-text sent to index.php file located in test folder.
Searched a lot but could not find the answer for this question anywhere on the Internet.
Thank you all for the help.
UPDATE:
my new code is:
RewriteEngine On
Options +FollowSymlinks
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(([\w/\-]+)?[\w-])(?!:\.html)$ http://domain.com/$1\.html [L,R=301]
RewriteRule ^(([\w/\-]+)?[\w-])(/|\.html)?$ test/index.php?slug=$1 [L]
domain.com/slug-text/ does not get redirected to domain.com/slug-text.html
domain.com/slug-text works as intended redirecting to domain.com/slug-text.html
What do i need to change?
This rule:
RewriteRule ^(([\w/\-]+)?[\w-])(/|\.html)?$ test/index.php?slug=$1 [L]
Will trap domain.com/slug-text, domain.com/slug-text/ and domain.com/slug-text.html and send slug-text to /test/index.php inside slug param.
If you really want to redirect using [R=301] from old urls to new then use this:
RewriteRule ^(([\w/-]+)?[\w-])/?(?!:\.html)$ http://domain.com/$1.html [L,R=301]
RewriteRule ^(([\w/-]+)?[\w-])\.html$ test/index.php?slug=$1 [L]
Also note that as using explicit redirect bottom rule is modified to trap url's ending with .html
It is also advisable (if your .htaccess does not already contain this) to filter conditions for existing files and folders not to be trapped by your redirect rules. Simply add these lines before RewriteRule lines:
# existing file
RewriteCond %{SCRIPT_FILENAME} !-f
# existing folder
RewriteCond %{SCRIPT_FILENAME} !-d
And if using symlinks:
# enable symlinks
Options +FollowSymLinks
# existing symlink
RewriteCond %{SCRIPT_FILENAME} !-l
// addition
Your .htaccess file should look like this:
RewriteEngine on
Options +FollowSymLinks
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(([\w/-]+)?[\w-])/?(?!:\.html)$ http://domain.com/$1.html [L,R=301]
RewriteRule ^(([\w/-]+)?[\w-])\.html$ test/index.php?slug=$1 [L]
This is supposed to redirect /slug-text to /slug-text.html
RedirectMatch ^/([\w-]+)/?$ http://domein.com/$1.html
This is in the case when slug-text is only letters, digits, – and _.
Rewrite slug-text.html to a php file and pass the slug as a param:
RewriteRule ^([\w-]+)\.html$ test/index.php?slug=$1 [R,L]
If you have both line in your .htaccess the first one will do the redirects from the legacy URLs to the new ones and the second one will process the request.

.htaccess rewriting

I have this .htaccess that I've been using to rewrite URLs like these:
www.example.com/index.php?page=brand www.example.com/brand
www.example.com/index.php?page=contact www.example.com/contact
www.example.com/index.php?page=giveaways www.example.com/giveaways
RewriteEngine on
RewriteCond $1 !^(index\.php|resources|robots\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?page=$1 [L,QSA]
I used a file called index.php to handle the redirects. Code used below:
$page = trim($_GET['page']);
if($page == "giveaways")
require('pages/giveaways.php');
Now, I would like to add another URL type like these:
www.example.com/index.php?page=products&p=ford-mustang
TO
www.example.com/products/ford-mustang
How will I accomplish this? Any suggestion would be greatly appreciated.
You need to add a second RewriteRule above your current one.
Here's an example:
RewriteRule ^/(.*)/(.*)$ index.php?page=$1&p=$2 [L,QSA]
This will rewrite /product/ford-mustang to index.php?page=product&p=ford-mustang
Remember to add it above your current RewriteRule, because it first tries to match the first RewriteRule, when there's no match it will go on with the second RewriteRule and so further.
A URL rewrite for /products/ford-mustang would be:
RewriteRule ^(.*)/(.*)$ index.php?page=$1&p=$2 [L,QSA]

Pretty Profile URLs without conflicts with pages

I want to use profile URLs on my site such as xyz.com/username
I am using the follow code:
RewriteRule ^([a-zA-Z0-9_-]+)$ index.php?p=profile&u=$1 [L,QSA]
RewriteRule ^([a-zA-Z0-9_-]+)/$ index.php?p=profile&u=$1 [L,QSA]
My question is...
How can I use it like this, and keep the access to other links such as xyz.com/forums, xyz.com/friends, etc..
Thank you.
You can try using a condition:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9_-]+)/?$ index.php?p=profile&u=$1 [L,QSA]
The -f and -d are flags for "is a file" and "is a directory" respectively. ! negates that. Your rewrite should only happen for urls that don't actually exist in your web root. You'll probably want to add an initial condition to match against your username format so you don't stomp on every potential 404 error.
You could prepend the following, too:
RewriteCond %{REQUEST_URI} ^/[a-zA-Z0-9_-]+/?$
So you'll only match /adsfasdfasdf instead of /something/that/doesn't/exist
Use this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([a-zA-Z0-9_-]+)/?$ index.php?p=profile&u=$1 [L,QSA]
It checks whether the requested file is a directory or file, and if not passes it off to index.php
You can also put a ? after the / to make it optional (combining your two rules).

How can I redirect every URL that's not requesting an JPEG or PNG image to index.php/x?

For example, I have an URL that looks for an image like this:
http://example.com/img/foo.png
http://example.com/img/interface/menu/bar.png
http://example.com/static/users/avatars/small/3k5jd355swrx221.jpg
I don't want to redirect those. They should just pass through. But then, I have URLs like this:
http://example.com/register/
http://example.com/my_account/my_picture/
http://example.com/contact/email/
All such URLs that don't request for an .png or .jpeg should be redirected to:
http://example.com/index.php/x
Where x stands for everything after example.com/, so in this example for example:
http://example.com/register/ to
http://example.com/index.php/register/
http://example.com/my_account/my_picture/ to
http://example.com/index.php/my_account/my_picture/
http://example.com/contact/email/ to
http://example.com/index.php/contact/email/
(AcceptPathInfo is enabled)
Is there any way to do that in the .htaccess? I only know how I could do this if I had always something like http://example.com/someKindOfMarkerHere/stuff/stuff/stuff but I don't want to have the someKindOfMarker there to detect if it's an URL that has to be rewritten. I don't know how to exclude them.
You can either exclude specific URLs:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule !.*\.(jpeg|png)$ index.php%{REQUEST_URI}
Or you exclude any existing file:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php%{REQUEST_URI}
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} ^.+\.png$ [OR]
RewriteCond %{REQUEST_FILENAME} ^.+\.jp(e)?g$
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php/%{REQUEST_URI} [NC,L]
Hell yes it's possible.
mod_rewrite will do all of that for you pretty easily.
You can also set up an error handler, so every 404 on your site gets redirected through index.php. This is a nice little way of making sure all requests load index.php (or your bootstrap).
The mod_rewrite will need a regex and regex's hurt my head, so I'll let somebody else write one.
Hope that helps. Just comment if you need more info from me. :)
Put something like this in a .htaccess file and make sure mod_rewrite is enabled:
RewriteEngine On
RewriteRule ^(.*?)(?!(\.png|\.jpg))$ index.php/$1
http://www.regular-expressions.info/lookaround.html
I would use a slight variation to Gumbo's answer:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php%{REQUEST_URI}
It excludes folders as well as files (the !-d flag) - you may not may not want this, but think it belongs here for completeness.
The following ignores existing files, folder and files with the extension matching: jpg, jpeg, png, gif. If you wish to add additional extension, just add "|extension" before the )$ on line 3.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !.(jpg|jpeg|png|gif)$
RewriteRule ^(.*)?$ /index.php/$1 [QSA,L]

Categories