htaccess directory to file redirect problem - .htaccess

I’m trying to use the following .htaccess file
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^images/
RewriteRule (.*) view.php?picid=$1 [L]
RewriteRule ^/user/(.*)$ /users.php?user=$1
I want two things to happen: Whenever someone requests /1234, it redirects to /view.php?picid=1234, and also when someone visits /users/bob, it redirects to /users.php?user=bob.
My code however, doesn’t seem to be working correctly.

There are several ways to do that. Here’s one that should work:
RewriteRule ^user/(.+)$ users.php?user=$1 [L]
RewriteRule ^([0-9]+)$ view.php?picid=$1 [L]
The first rule will catch any request that’s URI path begins with /user/ followed by one or more arbitrary characters. And the second will catch any request that’s URI path begins with / followed by one or more digits.

The initial problem with your rules is that the RewriteRule with (.*) will match everything.
If you do not want it to match a URL with a slash in it (such as users/bob), try ^([^/]*)$
Secondly, after a URL is rewritten, the new URL goes through your rules again. If you want to avoid matching something that has already been rewritten once, you should add a condition like
RewriteCond %{REQUEST_URI} !\.php

Related

htaccess dynamic url redirect

I have the following URL
https://example.com/expert-profile?id=john-doe&locale=en
I want it to be redirected to
https://example.com/expert/john-doe
I tried the following
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)id=([^&]+)&?(.*)?$
RewriteRule ^expert-profile$ https://example.com/expert/%3?%1%4 [L,R=301]
And a couple of other solutions, nothing is working here. Can someone help me to go in the right direction?
Update:
This is my current .htaccess file
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . /index.html [L]
</IfModule>
Redirect 301 "/en/download-app" "/download-app"
Please keep your htaccess file in your root and have it in following way.
Please clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{QUERY_STRING} ^id=([^&]*)&locale=(.*)$ [NC]
RewriteRule ^([^-]*)-.*/?$ $1/%1-%2 [R=301,L]
OR in case you don't have Rules to handle non-existing files/directories then use following Rules set. Please make sure either use above OR following Rules set one at a time only.
RewriteEngine ON
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{QUERY_STRING} ^id=([^&]*)&locale=(.*)$ [NC]
RewriteRule ^([^-]*)-.*/?$ $1/%1-%2 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?:expert)/([^-]*)-(.*)$ $1-profile?id=$1&locale=$2 [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^ /index.html [L]
I have following URL
https://example.com/expert-profile?id=john-doe&locale=en
I want it to be redirected to
https://example.com/expert/john-doe
You would need to do something like the following at the top of your .htaccess file, before your existing directives (order is important):
RewriteCond %{QUERY_STRING} (?:^|&)id=([^&]+)
RewriteRule ^expert-profile$ /expert/%1 [QSD,R=301,L]
This captures the value of the id URL parameter (in the %1 backreference) regardless of where it appears in the query string and discards all other URL parameters. I'm assuming you don't specifically need to match locale=en?
Note that the regex subpattern ([^&]+) (the id value) only matches something, not nothing. If the URL parameter is empty (ie. id=&locale=en) then no redirect occurs.
The QSD flag is necessary to discard the original query string.
Test first with a 302 (temporary) redirect to avoid potential caching issues. And clear your browser cache before testing. Only use a 301 (permanent) redirect if this really is intended to be permanent.
To redirect the specific URL /expert-profile?id=<name>&locale=en to /expert/<name>, ie. the id parameter is at the start of the query string and is followed by locale=en only then you can (and should) be more specific in the condition. For example:
RewriteCond %{QUERY_STRING} ^id=([^&]+)&locale=en$
RewriteRule ^expert-profile$ /expert/%1 [QSD,R=301,L]
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)id=([^&]+)&?(.*)?$
RewriteRule ^expert-profile$ https://example.com/expert/%3?%1%4 [L,R=301]
This is close (providing you placed the rule at the top of the file), however, this tries to preserve the other URL parameters, ie. locale=en and whatever else, to create another query string - which you've not stated in your requirements.
Aside: The existing answers are assuming you are wanting to internally rewrite (URL rewrite) the request in the other direction, ie. from /expert/john-doe to /expert-profile?id=john-doe&locale=en. This is probably due to how questions of this nature are notoriously miswritten and this is often the real underlying intention. However, you've made no mention of this here and a URL of the form /expert-profile is not a valid endpoint - so it wouldn't really make sense to "rewrite" the URL in that direction. (?)
If you want it rewritten, capture the name (.+) and insert it into the target $1
RewriteRule ^expert/(.+)$ /expert-profile?id=$1&locale=en [L]
And don't use flag R|redirect here, unless you really want a redirect.---
To redirect from expert-profile?id=john-doe to expert/john-doe, capture the id (.+?) from the query string and insert it in the substitution URL %1
RewriteCond &%{QUERY_STRING}& &id=(.+?)&
RewriteRule ^expert-profile$ /expert/%1 [R,L]
When everything works as it should, you may replace R with R=301 (permanent redirect).
Don't use both rules together. If you do, it will result in an endless redirect loop and finally give a "500 Internal Server Error".
Unrelated, but never test with R=301!

How can a write correct rewrite rules in htaccess?

I havve been using an htaccess file to create rewrites so as not to not have to include .php/.html filenames in my urls.
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example-page.com [NC,OR]
RewriteCond %{HTTP_HOST} ^www.example-page.com
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule /front /front_page.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule /redirect /redirect-page.php
However as my code is currently written the redirects are not working and all attempts at loading the pages with anything else besides the filenames is giving me a 404 error. How might i fix my code to get the redirecting to work?
Write the directives like this instead:
RewriteEngine on
RewriteRule ^front$ /front_page.php [L]
RewriteRule ^redirect$ /redirect-page.php [L]
There doesn't seem to be a need for all your additional conditions? I assume you only have the one domain example-page.com and you don't have a file called /front etc.
In .htaccess, the URL-path matched by the RewriteRule pattern does not start with a slash. You should also include start/end-of-string anchors on the regex so that you only match front exactly and not match it anywhere in the URL-path.

.htaccess rules to separate page types

I'm having some problems rewriting URLs with the following rules
RewriteEngine on
RewriteRule ^page/(.*)$ index.php?pag=cms&title=$1 [NC]
RewriteRule ^admin/(.*)$ admin/$1 [NC]
RewriteRule ^(.*)$ index.php?pag=$1 [NC,L]
What I'm trying to achieve is to check if the URL is a cms page or not and leave admin URLs as they are.
If I remove the last condition it works but I will have no rule for not cms pages.
Ideally I would want to have just one rule for every page (cms or not) but I can't figure out how to check that other than using page/ in the URL.
Mod_rewrite will keep looping through all the rules until the URI stops changing (or it reaches its internal redirect limit, resuling in a 500 error). You need to add a few conditions to the last rule so that it won't rewrite URI's that's already been properly routed:
RewriteRule ^page/(.*)$ index.php?pag=cms&title=$1 [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?pag=$1 [NC,L]
Additionally, the second rule does nothing except a passthrough, so you can replace it with
RewriteRule ^admin/(.*)$ - [NC,L]
You need these rules:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
From the Apache documentation:
'-d' (is directory)
Treats the TestString as a pathname and tests whether or not it exists, and is a directory.
'-f' (is regular file)
Treats the TestString as a pathname and tests whether or not it exists, and is a regular file.

Create .htaccess with a variable

I am having trouble finding a solution for what I want to do. I am going to have a couple thounsand affiliates signing up on our site. They will provide a username, and basically give out the url www.domain.com/affiliate/username to their clients.
So, the url I will be starting with is www.domain.com/affiliate/home.html?userid=bob (if bob is the username they give).
I need that to check with the mysql database if that userid exists, then redirect it to the www.domain.com/affiliate/bob url.
Right now, I have this in my .htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\/]+)$ affiliate/home.html?affiliate=$1 [L]
It obviously doesnt work and Ive never dealt with .htaccess before. Any help is greatly appreciated. Thank you.
Try this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^affiliate/([^/]+)/?$ /affiliate/home.html?affiliate=$1 [L]
As for redirecting to the nicer looking URL if someone enters the one with the query string:
RewriteCond %{THE_REQUEST} ^(GET|HEAD)\ /affiliate/home.html\?affiliate=([^\ &]+)&?([^\ ]*)
RewriteRule ^ /affiliate/%2?%3 [L,R=301]
There's no way to check if a username is in your database before the rewrite happens, using an htaccess file. There's ways to talk to a database in apache 2.4 or using a RewriteMap (which can only be defined in server or vhost config, not in htaccess) but you're better off doing the check in your home.html and just return a 404 if the user isn't found.
See my answer on an other similar question.
You want www.domain.com/affiliate/home.html?userid=bob to be redirected to /affliate/bob. You want /affliate/bob to be rewritten to /affiliate/home.html?userid=bob.
Add this to your .htaccess in your /www/ or /public_html/.
RewriteEngine on
RewriteCond %{QUERY_STRING} ^affiliate=([^&]*)$
RewriteRule ^affiliate/home\.html /affiliate/%1? [R,L]
RewriteRule ^affiliate/(.*)$ affiliate/home.html?affiliate=$1&r=0 [L]
The first rule matches if the user tries to access affiliate/home.html?userid=bob. The RewriteCondition matches the part of the query string (after the ?) that you need to write the fancy url. %1 matches the first 'capturing group' in a rewrite condition. The ? at the end will clear the query string. [R] means it is a redirect (see the linked answer what that does). [L] means it will stop matching if this one matches.
The second rule is an internal rewrite. $1 matches the first 'capturing group' in the RewriteRule. The trailing &r=0 is there to stop the first rule from matching. It requires a RewriteCond %{REQUEST_FILENAME} !-f to function properly, because the fancy url is in the same directory is the file that handles it.

Trying to add trailing slash with htaccess, results in a absolute path

What I'm trying to achive is to have all urls on my page look like http://domain.com/page/, no extensions, but a trailing slash. If a user happends to write http://domain.com/page or http://domain.com/page.php it will redirect to the first url. After some googling i found this code, and it's close to working, but when you leave out the trailing slash in your request the url becomes something like http://domain.com/Users/"..."/page/ and therefor returns a 404.
My .htaccess looks like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ $1.php [L]
RewriteCond %{REQUEST_FILENAME} !(.*)/$
RewriteRule (.*)/$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule .*[^/]$ $0/ [L,R=301]
I've been trying to add an additional rule but I really don't get any of this and I haven't been able to find any answers.
For a scenario like this one, the .htaccess author has to consider both what the browser URL bar should display and what file the web server should return/execute. Note also that each external redirect starts the processing of the rewrite directives over.
With that in mind, start by taking care of which file is returned when the URL is in the correct format:
RewriteEngine on
RewriteRule ^/?$ /index.php [L]
RewriteRule ([^./]+)/$ /$1.php [L]
Then, deal with URLs with no trailing slash by redirecting them with [R=301]:
RewriteRule ^/(.*)\.[^.]*$ http://www.example.com/$1/ [R=301,L]
RewriteRule ^/(.*)$ http://www.example.com/$1/ [R=301,L]
Note that the first of these two rules should also take care of the case where there is a filename (like something.php) but also a trailing slash by eliminating the filename extension and re-adding the slash.
Keep in mind that, if your internal directory structure does not match what the web server is serving (as is often the case in shared hosting scenarios), you will likely need to add a RewriteBase directive immediately after the RewriteEngine directive. See the Apache docs for an explanation.

Resources