multiple folder redirect - apache

I have been trying variations of the following without success:
Redirect permanent /([0-9]+)/([0-9]+)/(.?).html http://example.com/($3)
It seems to have no effect. I have also tried rewrite with similar lack of results.
I want all links similar to: http://example.com/2002/10/some-long-title.html
to redirect the browser and spiders to: http://example.com/some-long-title
When I save this to my server, and visit a link with the nested folders, it just returns a 404 with the original URL unchanged in the address bar. What I want is the new location in the address bar (and the content of course).

I guess this is more or less what you are looking for:
RewriteEngine On
ReriteRule ^/([0-9]+)/([0-9]+)/(.?)\.html$ http://example.com/$3 [L,R=301]
This can be used inside the central apache configuration. If you have to use .htaccess files because you don't have access to the apache configuration then the syntax is slightly different.

Using mod_alias, you want the RedirectMatch, not the regular Redirect directive:
RedirectMatch permanent ^/([0-9]+)/([0-9]+)/(.+)\.html$ http://example.com/$3
Your last grouping needs to be (.+) which means anything that's 1 character or more, what you had before, (.?) matches anything that is either 0 or 1 character. Also, the last backreference doesn't need the parentheses.
Using mod_rewrite, it looks similar:
RewriteEngine On
RewriteRule ^/([0-9]+)/([0-9]+)/(.+)\.html$ http://example.com/$3 [L,R=301]

Related

How to create a redirect rule for 404 pages with many different path

Here my problem, the site I'm working on has many 404 pages, but they used to be the same pages with a different path
/mens/designers/mens/wales-bonner
/mens/designers/casual-shirts/wales-bonner
/mens/designers/coats-and-jackets/wales-bonner
etc.
THe client wants the redirect to go to the category, so
/mens/designers/mens/
/mens/designers/casual-shirts/
/mens/designers/coats-and-jackets/
I'm pretty sure, there must be a way to have regex rule to cover them all, but I can't seem to find how
Something like
RewriteRule ^/mens/designers/(.*)/wales-bonner /mens/designers/(.*)
but it doesn't work, I don't know how to group the middle part of the URL
Can anyone help ?
I see several potential problems with your rewrite rule:
You have a capturing group in the output URL rather than using $1 to use the result of the capturing group from the input URL.
^/ won't work in .htaccess, only in Apache .conf files. I' would use ^/? instead which will work in either context. That makes the starting slash optional.
You don't include an [R] flag on the rule to make it a redirect.
You don't include an [L] flag on the rule to prevent any following rules from interfering with it.
You can also add "mens/designers" to the capturing group so that you don't have to repeat it in the output. I would suggest:
RewriteRule ^/?(mens/designers/.*)/wales-bonner /$1 [R=301,L]

.htaccess RewriteRule based on anchors

I am trying to update a RewriteRule. Previously, the redirect looked like this:
https://mywebsite.com/docs/#/en/introduction → https://manual.mywebsite.com/#/en/introduction
I would like to use /docs/ for something else now but I would like to keep redirecting requests containing a forward slash after the # to the manual subdomain. This is what I would like to achieve:
The old redirects continue working as usual:
https://mywebsite.com/docs/#/en/introduction → https://manual.mywebsite.com/#/en/introduction
This would not get redirected since there is no forward slash following the #:
https://mywebsite.com/docs/#overview
Here is what I have:
The .htaccess file containing the following existing rule which redirects everything:
RewriteRule ^docs/(.*) https://manual.mywebsite.com/$1 [L,R=301]
I tried this but it did not work (I tried with https://htaccess.madewithlove.com/ which says that my rule does not match the URL I entered):
RewriteRule ^docs/#/(.*) https://manual.mywebsite.com/#/$1 [L,R=301]
I also read about the NE (no escape) flag (https://httpd.apache.org/docs/2.2/rewrite/advanced.html#redirectanchors) which did not help either.
I am also sure that the server is actually using the file.
To summarize, my problem is that I want to match a URL containing /docs/#/ and redirect it to a subdomain, keeping the /#/ and everything that follows it.
Anchors are not part of the URL that's transmitted to the server: They stay within the browser, thus you can't build a rewrite rule that take anchors into account.
Inspect your access-logs to see what you get

Apache RedirectMatch

I'm working on an apache server (2.2), and I'm trying to redirect a URL based off of a URL filter. For example,
https://mywebsite.com/path/to/page?folder=folderDirectory/folderName
will redirect to:
https://mywebsite.com/static/contentUnavailable.html
In my httpd.conf file I have the following code ..
RedirectMatch (.*)path/to/page?folder=folderDirectory/folderName /static/contentUnavailable.html
I restart apache everytime I make modifications to this file, however the page is not redirecting. What am I doing wrong in the RedirectMatch?
You can't match query string with a redirectmatch, sorry, you need mod_rewrite for this and using a RewriteCond. Rough example:
RewriteCond %{QUERY_STRING} ^folder
RewriteRule ^ /static/contentUnavailable.html [R,L,QSD]
This will match a query string that starts with folder (and continues with whatever else, no matter what it is). and redirect everything to the destination you want, discarding the query string in the process (QSD flag).
In any case let me commend you for trying to stick to redirect/redirectmatch first (while everyone else just goes blindly for mod_rewrite even for the simplest redirects). You are doing things right.

Does REQUEST_URI hide or ignore some filenames in .htaccess?

I'm having some difficulty with a super simple htaccess redirect.
All I want to do is rewrite absolutely everything, except a couple files.
htaccess looks like this:
RewriteEngine On
RewriteCond %{REQUEST_URI} !sitemap
RewriteCond %{REQUEST_URI} !robots
RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]
The part that works is that everything gets redirected to new domain as it should be. And I can also access robots.txt without being forwarded, but not with sitemap.xml. If I try to go to sitemap.xml, the domain forwards along anyway and opens the sitemap file on the new domain.
I have this exact same issue when trying to "ignore" index.html. I can ignore robots, I can ignore alternate html or php files, but if I want to ignore index.html, the regex fails.
Since I can't actually SEE what is in the REQUEST_URI variable, my guess is that somehow index.html and sitemap.xml are some kind of "special" files that don't end up in REQUEST_URI? I know this because of a stupid test. If I choose to ignore index.html like this:
RewriteCond %{REQUEST_URI} !index.html
Then if I type example.com/index.html I will be forwarded. But if I just type example.com/ the ignore actually works and it shows the content of index.html without forwarding!
How is it that when I choose to ignore the regex "index.html", it only works when "index.html" is not actually typed in the address bar!?!
And it gets even weirder! Should I type something like example.com/index.html?option=value, then the ignore rule works and I do NOT get forwarded when there are attributes like this. But index.html by itself doesn't work, and then just having the slash root, the rule works again.
I'm completely confused! Why does it seem like REQUEST_URI is not able to see some filenames like index.html and sitemap.xml? I've been Googling for 2 days and not only can I not find out if this is true, but I can't seem to find any websites which actually give examples of what these htaccess server variables actually contain!
Thanks!
my guess is that somehow index.html and sitemap.xml are some kind of "special" files that don't end up in REQUEST_URI?
This is not true. There is no such special treatment of any requested URL. The REQUEST_URI server variable contains the URL-path (only) of the request. This notably excludes the scheme + hostname and any query string (which are available in their own variables).
However, if there are any other mod_rewrite directives that precede this (including the server config) that rewrite the URL then the REQUEST_URI server variable is also updated to reflect the rewritten URL.
index.html (Directory Index)
index.html is possibly a special case. Although, if you are explicitly requesting index.html as part of the URL itself (as you appear to be doing) then this does not apply.
If, on the other hand, you are requesting a directory, eg. http://example.com/subdir/ and relying on mod_dir issuing an internal subrequest for the directory index (ie. index.html), then the REQUEST_URI variable may or may not contain index.html - depending on the version of Apache (2.2 vs 2.4) you are on. On Apache 2.2 mod_dir executes first, so you would need to check for /subdir/index.html. However, on Apache 2.4, mod_rewrite executes first, so you simply check for the requested URL: /subdir/. It's safer to check for both, particularly if you have other rewrites and there is possibility of a second pass through the rewrite engine.
Caching problems
However, the most probable cause in this scenario is simply a caching issue. If the 301 redirect has previously been in place without these exceptions then it's possible these redirections have been cached by the browser. 301 (permanent) redirects are cached persistently by the browser and can cause issues with testing (as well as your users that also have these redirects cached - there is little you can do about that unfortunately).
RewriteCond %{REQUEST_URI} !(sitemap|index|alternate|alt) [NC]
RewriteRule .* alternate.html [R,L]
The example you presented in comments further suggests a caching issue, since you are now getting different results for sitemap than those posted in your question. (It appears to be working as intended in your second example).
Examining Apache server variables
#zzzaaabbb mentioned one method to examine the value of the Apache server variable. (Note that the Apache server variable REQUEST_URI is different to the PHP variable of the same name.) You can also assign the value of an Apache server variable to an environment variable, which is then readable in your application code.
For example:
RewriteRule ^ - [E=APACHE_REQUEST_URI:%{REQUEST_URI}]
You can then examine the value of the APACHE_REQUEST_URI environment variable in your server-side code. Note that if you have any other rewrites that result in the rewritting process to start over then you could get multiple env vars, each prefixed with REDIRECT_.
With the index.html problem, you probably just need to escape the dot (index\.html). You are in the regex pattern-matching area on the right-hand side of RewriteCond. With the un-escaped dot in there, there would need to be a character at that spot in the request, to match, and there isn't, so you're not matching and are getting the unwanted forward.
For the sitemap not matching problem, you could check to see what REQUEST_URI actually contains, by just creating an empty dummy file (to avoid 404 throwing) and then do a redirect at top of .htaccess. Then, in browser URL, type in anything you want to see the REQUEST_URI for -- it will show in address bar.
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^ /test.php?var=%{REQUEST_URI} [NE,R,L]
Credit MrWhite with that easy test method.
Hopefully that will show that sitemap in URL ends up as something else, so will at least partially explain why it's not pattern-matching and preventing redirect, when it should be pattern-matching and preventing redirect.
I would also test by being sure that the server isn't stepping in front of things with custom 301 directive that for whatever reason makes sitemap behave unexpectedly. Put this at the top of your .htaccess for that test.
ErrorDocument 301 default

Apache mod_rewrite not doing anything (?)

I'm having some trouble with Apache's mod_rewrite. One of the things I'm trying to get it to do is hide some of my implementation details, so that, for example, the user sees the URL http://www.mysite.com/login but Apache responds with the page at http://www.mysite.com/doc_root/login.php instead (preferably without showing the user that it's a PHP file or the directory structure). Here's what I have in my .htaccess file:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?mysite.com*
RewriteRule ^/(\w+) /doc_root/$1.php [L]
#Redirect http://www.mysite.com to the login page
RewriteRule ^/?$ https://www.mysite.com/doc_root/login.php
But when I go to http://www.mysite.com/login, I get a 404 error even though the page exists. I clearly don't have a great understanding of how the mod_rewrite conditionals and rules work, so can anyone please tell me what I'm doing wrong? Thanks.
Take doc_root out of all the stuff you have it in. That will give you the result you're asking for. However I'm not sure if it's desired or not. How are you going to force someone to login if they manually type http://www.mysite.com/index.php?
Also if you're trying to force all traffic to SSL it's better to use a second VirtualHost and Redirect instead of mod_rewrite. Those are all questions probably better suited for ServerFault
Unless your site has a bunch of different domain names, and you only want mysite.com to do the rewriting, you don't need the RewriteCond. (Potential problem. Apache likes to dick around with the domain name unless you set UseCanonicalName off. If the name isn't what it's expecting, the rewrite won't happen.)
In RewriteCond (and RewriteRule) patterns, . matches any character. Add a backslash before them. (Minor bug. Shouldn't cause rewrites to fail, but they would match stuff like "mysite-com" as well.)
mod_rewrite is actually a URL-to-filename filter. Though it is often used to rewrite URLs to other URLs, sometimes it will misbehave if what you're rewriting to is a URL and it can't tell. (Especially if what it's rewriting to would be an alias, or would otherwise not translate directly to a real filename.) If you add a [PT] flag onto your rule, though, it will consider the rewritten thing a URL and pass it along to the other filters (including the ones that turn URLs into filenames).
Do you really need "/doc_root"? The document root should already be set up in Apache using the DocumentRoot directive, and shouldn't need to be part of the URL unless you have multiple apps on the same domain (in which case it's the app root; the document root doesn't change).
UPDATE:
Another thing i just thought about: Rewrite rules work differently in .htaccess files. Apache likes to strip off the leading slash. So you will probably want to get rid of the first slash in your patterns, or at least make it optional (^/?login instead of ^/login).
^/?(\w+) will match /doc_root/login.php, and cause a rewrite to /doc_root/doc_root.php. You should probably have a $ at the end of your pattern.