.htaccess with multiple slashes on the condition - apache

I am trying to implement clean URL with the help of .htaccess in my project.
I got a 404 when i implimented a condition with multiple condition strings like keyword1/keyword2/param
all other conditions like RewriteRule ^home index.php [L,NC] works fine
My file structure be like
/subdirectory/
|-.htaccess
|-index.php
|-edit-user.php
|-new-user.php
my desired clean url is
mysite.com/subdirectory/user/edit/10
and it should translated into
mysite.com/subdirectory/edit-user.php?id=10
Some of the closest solutions i tried so far (but no luck)
RewriteRule (.*)/user/edit/([0-9]+)$ edit-user?id=$1 [L,NC]
RewriteBase /user/
RewriteRule ^user\/edit\/([0-9]+)$ edit-user.php?id=$1 [L,NC]
Any suggestions are highly appreciated.

RewriteRule (.*)/user/edit/([0-9]+)$ edit-user?id=$1 [L,NC]
Since the .htaccess file is inside the /subdirectory then you would need to write the directive like this:
RewriteRule ^user/edit/(\d+)$ edit-user.php?id=$1 [L]
And remove any RewriteBase directive.
\d is simply a shorthand character class for [0-9].
The RewriteRule pattern matches against the relative URL-path (no slash prefix). That is relative to the directory that contains the .htaccess file. You were also missing the .php extension on the filename you are rewriting to. You do not need the NC flag unless you really do want to allowed a mixed-case request, but that opens you up to potential "duplicate content" which would need to be resolved in other ways.
RewriteBase /user/
RewriteRule ^user\/edit\/([0-9]+)$ edit-user.php?id=$1 [L,NC]
Actually, you are very close here, but the RewriteBase directive would have caused this to fail. The sole purpose of the RewriteBase directive is to override the directory-prefix that is added back on relative path substitutions. The RewriteBase directive sets the "URL-path" (as opposed to filesystem path) that is added back.
So, in this example, RewriteBase /user/ would result in the request being rewritten to /user/edit-user.php?id=10 (relative to the root), which is clearly wrong based on the file structure you posted.
Without the RewriteBase defined then the directory-prefix is added back, which results in the rewrite being relative to the directory containing the .htaccess file.
Also, there's no need to backslash-escape slashes since there are no slash delimiters to the regex. (The spaces that surround the argument are the delimiters.)
all other conditions like RewriteRule ^home index.php [L,NC] works fine
Careful with this, as this will also match /homeanything and /home/something etc.

Finally found the issue.
My .htaccess was
RewriteRule ^home index.php [L,NC] RewriteRule ^([^\.]+)$ $1.php [NC]
RewriteRule ^user/edit/(\d+)$ edit-user?id=$1 [L]
(1st line to add .php to anything that comes in, and the 2nd line to convert the desired URL I needed)
What happened here is, when I try to access the URL mysite.com/subdirectory/user/edit/10
The first rule converts that into mysite.com/subdirectory/user/edit/10.php instead of mysite.com/subdirectory/edit-user.php?id=10
This causes the 404 error.
Now I changed the order and the new .htaccess file looks like,
RewriteRule ^admin/edit/(\d+)$ edit-admin.php?aid=$1 [L]
RewriteRule ^([^\.]+)$ $1.php [NC]
So, when a URL comes in, it will check into all other rules before its matches against the last rule(which appends .php) and translate into the desired result.
Lesson learned: Order matters a lot in .htaccess

Related

How to prevent rewrite .htaccess file conflict problem

RewriteEngine on
RewriteRule ^([^/\.]+)/?$ category.php?slug=$1
RewriteRule ^([^/\.]+)/([^/\.]+)$ product-details.php?slug1=$1&slug=$2
RewriteRule ^([^/\.]+)/?$ infrastructure-details.php?slug=$1
what I have already tried
This is my htaccess file. problem is when I am trying to execute (infrastructure-details.php?slug=$1) its move to (category.php?slug=$1) conflict with first rule of htaccess.
I tired multiple rewrite methods but its not working. Please help to solve this issue.
localhost/project/category.php?slug=pump, localhost/project/infrastructure-details.php?slug=paint second url i want to be-> localhost/project/paint both page is different. can you please specify how to write rules for this different pages.
There is no discernible pattern that differentiates these two URLs so the only way to implement these two rewrites is to hardcode them. For example:
RewriteRule ^pump$ category.php?slug=$0 [L]
RewriteRule ^paint$ infrastructure-details.php?slug=$0 [L]
Where the $0 backreference in the substitution string contains the entire match by the RewriteRule pattern (just saves some repetition).
If you need a more general solution (as your directives suggest) then there needs to be a discernible pattern in the URL that differentiates URLs that should be rewritten to category.php and infrastructure-details.php respectively.
I'm assuming your .htaccess file, and other files, are is inside the /project subdirectory.
RewriteRule ^([^/\.]+)/?$ category.php?slug=$1
RewriteRule ^([^/\.]+)/([^/\.]+)$ product-details.php?slug1=$1&slug=$2
RewriteRule ^([^/\.]+)/?$ infrastructure-details.php?slug=$1
Rule #1 and #3 conflict - they use exactly the same pattern (regex) to match against the requested URL. The first rule is always going to "win" and rewrite the request before rule#3 is able to process the request, so rule#3 never matches.
To write a generic rule like this there needs to be a discernible difference between the URL types that you can match with a pattern/regex. For example:
/category/pump
/infrastructure/paint
And then you can construct rules...
Options -MultiViews
RewriteRule ^category/([^/]+)$ category.php?slug=$1 [L]
RewriteRule ^infrastructure/([^/]+)$ infrastructure-details.php?slug=$1 [L]
Note that the order of these directives can be important. More specific rules need to be before more generalised rules.
Options -MultiViews
RewriteEngine on
RewriteRule ^infrastructure/([^/]+)$ infrastructure-details.php?slug=$1 [L]
RewriteRule ^([^/\.]+)/?$ category.php?slug=$1 [L]
RewriteRule ^([^/\.]+)/([^/\.]+)$ product-details.php?slug1=$1&slug=$2 [L]
This is work fine for me. (infrastructure-details.php?slug=$1 [L]) put on top.

I can't figure out why this RewriteCond isn't working

So I'm having trouble figuring out why my RewriteRules won't trigger. These rules are in an .htaccess file at the root directory of a subdomain of my website. I've turned on detailed logging for mod_rewrite in the VirtualHost but that isn't really helping me solve what's wrong, though the first three rules seem to be working simply by coincidence since their files exist at the requested location.
The goal of this set of rules is:
sub.domain.tld/ -> passthrough/serve actual file
sub.domain.tld/?q=test -> passthrough/serve actual file with query args intact
sub.domain.tld/.well-known/* -> passthrough/serve actual file (for letsencrypt)
sub.doamin.tld/* -> process.php?project=*
sub.domain.tld/*?q=test -> process.php?project=*&q=test while handling unlimited number of query args
And the current .htaccess is:
RewriteEngine on
#serve actual file if viewing main page or doing https renewal
RewriteCond %{REQUEST_URI} ^\?.+|\/$ [OR]
RewriteCond %{REQUEST_URI} ^\.well-known.*
RewriteRule (.*) - [L,QSA]
#redirect everything else to the processing script
RewriteCond %{REQUEST_URI} ^(\w+)
RewriteRule \/(\w+) process.php?project=$1 [NC,L,QSA]
Thank you for your help!
OK, This was actually a complex one and because most of the time, %{REQUEST_URI} tests are done using the RewriteRule itself, I got a bit confused and I'm sorry about that.
It turns out:
%{REQUEST_URI} contains the leading slash
the matching part of the RewriteRule doesn't
Also, keep in mind %{REQUEST_URI} doesn't contain the query string, as stated in the Apache manual:
REQUEST_URI
The path component of the requested URI, such as "/index.html". This notably excludes the query string which is available as its own variable named QUERY_STRING.
So, a rule like RewriteCond %{REQUEST_URI} ^\?.+ is pretty much useless as you'll never have a question mark in %{REQUEST_URI}
Also, and this probably is the most confusing part, when requesting /, %{REQUEST_URI} will contain the actual index file that has been served. So, if your DirectoryIndex is set to index.php index.html (in that order) and you have an index.html file in the root folder, {REQUEST_URI} will be index.html. If you have an index.php file, it will be index.php, but never /.
That being said, we can simply your rules to:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/(\.well-known|index\.php$)
RewriteRule (.+) process.php?project=%{REQUEST_URI} [QSA]
Note that I added the $ inside the brackets to only match the end of string character after index\.php but not after \.well-known, so anything after \.well-known will also match.
You will need to replace index\.php with index\.html if you have an html index.
Finally, you don't need 2 rules for that. It's always better to have only one and exclude some URLs from it.
PS: you'll also notice you don't need to escape / as this is not considered as a regexp delimiter.
You just need this single rule in your .htaccess:
RewriteEngine on
# skip files, directories and anything inside .well-known/ directory
RewriteRule ^(?!index\.|process\.php|\.well-known)(.+)$ process.php?project=$1 [L,QSA,NC]

Htaccess access specify file

I have .htaccess file:
DirectoryIndex index.php
RewriteEngine on
RewriteRule ^play/([^/\.]+) index.php?task=view&name=$1 [L]
Show page game.
My problem: When I need to load some file (or access by address bar) with path: /play/Assest/file-name.swf. This return 404 error.
How I can access file but don't change RewriteRule above?
I tried redirect code but it's not working:
RewriteRule ^/play/Assets/file-name.swf ^/games/Assets/file-name.swf [R=301,L]
Your RewriteRule is missing an anchor to the end of the URL, so partial matches still get rewritten. Add a $like this:
RewriteRule ^play/([^/.]+)$ index.php?task=view&name=$1 [L]
Shahaf's answer may also help you (although it means the file system gets polled twice for every request, which affects performance), but with this above you are saying "only match play/ with anything but dots or forward slashes following it" which seems to be what you mean. Without the dollar it can have anything after it and still match, as you have found.
I also removed the escaping of the dot which is not necessary in a character class.
Before the rewrite rule you should add conditions if it's not a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

.htaccess and rewrite from subdirectories inside unknown parent directory

So I have an htaccess file in a subdirectory and whenever I try to rewrite the url, it redirects to the document_root and not the subdirectory where the htaccess resides. Now, under normal circumstances, I'd rewrite it with the path to the subdirectory with path/to/subdirectory, but I won't know what the exact path will be. Is there a way either, through an Apache environment variable or something else, to write out that path?
Edit:
Here's the .htaccess file so far.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule (.*-file) a/b/c/$1.file
RewriteRule (.*-file) $1.file
So, I'm trying to, if the request contains the word file, I want to match the entire request prior to the word file and redirect there. This is so that if a request is to
example.com/a/b/c/file[any characters here].file
the request will be redirected to the right file. To reiterate, the problem is that I am trying to redirect within the subdirectory. So when I say Rewrite $1, I want that to include the entire request and not just what matched in the REQUEST_FILENAME. And the reason I need it to do that is because I can't simply put a/b/c/$1.file since I won't know for absolute certainty the a/b/c part.
Edit 2: Examples:
So, an example is that I'd send a request like:
example.com/a/b/c/fileacs.file
And want to redirect to:
example.com/a/b/c/file.file
Where I do not know a/b/c/. I have an actual regex and set of rules for the real-world use of this redirect, so don't mind the ridiculous nature of this example.
But currently it's redirecting to:
example.com/file.file
Which does not exist and even if it did, I do not want to redirect there. I've read about Rewrite Context, but can't find out anything substantial about it nor if it's the cause for this. Thank you, in advance.
You can use this rule to capture any path before fileacs.file and use that as bach-reference in RewriteRule:
RewriteEngine On
RewriteCond ^(.*)/file[^.]+\.file$ [NC]
RewriteRule ^ %1/file.file [L,R=302]
The solution is to use the a RewriteCond on the %{REQUEST_URI} (thanks anubhava!) that checks matches the entire request except for the %{REQUEST_FILENAME} without capturing it, using a lookahead. Write out this with the %1 followed by the desired filename. See the following:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} (.*)-file(?!\.file) [NC]
RewriteRule ^ %1.file [L,R=301]
The %1 now holds the path up to the directory that the .htaccess is stored, plus any prefix to the filename. This doesn't match the remainder of the request, but rather looksahead to ensure you're not actually requesting the file you would like to redirect to (causing a loop).

Problem with mod_rewrite rules in .htaccess file

This is my .htaccess file but it is not working. Not any URL is redirected. Help me.
RewriteEngine on
RewriteRule ^home index.php
RewriteRule ^contactus index.php?file=c-contactus
RewriteRule ^course_registration index.php?file=c-course_registration
RewriteRule ^ncplhpage index.php?file=c-ncplhpage
RewriteRule ^scplhpage index.php?file=c-scplhpage
RewriteRule ^corporatetra index.php?file=c-corporatetra
You may need to set a RewriteBase.
However, I suspect the problem is the lack of a / before index.php in all cases, i.e.
RewriteEngine on
RewriteRule ^home /index.php
As a side point, have you considered combining your directives into a single directive like:
RewriteRule ^(home|contactus|course_registration|ncplhpage|scplhpage|corporatetra)$ /index.php?file=c-$1
? You could take this a step further and hand down the checking of the name into your index.php file itself, i.e.
RewriteRule ^([_a-z]+)$ /index.php?file=c-$1
Bear in mind that your index.php should be checking that the $_GET['file'] that is requested is valid. Just because you have public URLs like /contactus doesn't mean that someone still can't type in /index.php?file=c-contactus directly (try it!). That means they could therefore type in /index.php?file=c-../../../../etc/passwd for instance. So do ensure that your index.php does some sanity-checking as well. That will be good both for security but also mean that you can avoid hard-coding your URLs into your .htaccess file.