.htaccess Rewriterule redirecting to a URL on the same domain - apache

I am trying to redirect users to specific URLs. I want to create .htaccess rewriterules to accomplish this.
I would lke for these:
https://example.com/career_by_education
https://example.com/international_careers
https://example.com/major_careers
https://example.com/career
to transfer to:
https://example.com/career_by_education/careers-by-educational-level.php
https://example.com/international_careers/international_careers.php
https://example.com/major_careers/academic_major_careers.php
https://example.com/career/career.php
I have tried many variations of rewrite rules to get this to work, and am successful if I want it to redirect to a different domain.
For example, the following (in .htaccss):
RewriteRule career_by_education https://example2.com/career_by_education/careers-by-educational-level.php [L,R]
RewriteRule international_careers https:/example2.com/international_careers/international_careers.php [L,R]
RewriteRule major_careers https://example2.com/major_careers/academic_major_careers.php [L,R]
RewriteRule career https://example2.com/career/career.php [L,R]
Successfully transfer to (respectively):
https://example2.com/career_by_education/careers-by-educational-level.php
https://example2.com/international_careers/international_careers.php
https://example2.com/major_careers/academic_major_careers.php
https://example2.com/career/career.php
But I want the redirect to be to the same domain (example.com), so I tried this (in this order):
RewriteRule career_by_education https://example.com/career_by_education/careers-by-educational-level.php [L,R]
RewriteRule international_careers https://example.com/international_careers/international_careers.php [L,R]
RewriteRule major_careers https://example.com/major_careers/academic_major_careers.php [L,R]
RewriteRule career https://example.com/career/career.php [L,R]
When I enter any of these into the browser:
https://example.com/career_by_education
https://example.com/international_careers
https://example.com/major_careers
I always get this URL:
https://example.com/career/career.php
I tried to reverse the ordering of the RewriteRules to:
RewriteRule career https://example.com/career/career.php [L,R]
RewriteRule major_careers https://example.com/major_careers/academic_major_careers.php [L,R]
RewriteRule international_careers https://example.com/international_careers/international_careers.php [L,R]
RewriteRule career_by_education https://example.com/career_by_education/careers-by-educational-level.php [L,R]
But the resulting URL is always:
https://example.com/career/career.php
I also tried to remove the full URL for the substitution, as follows:
RewriteRule career_by_education /career_by_education/careers-by-educational-level.php [L,R]
RewriteRule international_careers /international_careers/international_careers.php [L,R]
RewriteRule major_careers /major_careers/academic_major_careers.php [L,R]
RewriteRule career /career/career.php [L,R]
But the result always redirects to this URL:
https://example.com/career/career.php
I have tried different expressions to see if it can work:
RewriteRule ^/career http://consul64.wwwaz1-ts107.a2hosted.com/career/career.php [L,R]
RewriteRule ^/major_careers http://consul64.wwwaz1-ts107.a2hosted.com/major_careers/academic_major_careers.php [L,R]
RewriteRule ^/international_careers http://consul64.wwwaz1-ts107.a2hosted.com/international_careers/international_careers.php [L,R]
RewriteRule ^/career_by_education http://consul64.wwwaz1-ts107.a2hosted.com/career_by_education/careers-by-educational-level.php [L,R]
These all result in a "403 Forbidden" error - From the command line I ensured that I have a "index.php" in the root directory, and permissions were correct, with the following:
chmod 644 ~/public_html/.htaccess
chmod 755 ~/public_html
Then I tried these:
RewriteRule .*(?=major_careers) http://consul64.wwwaz1-ts107.a2hosted.com/major_careers/academic_major_careers.php [L,R]
RewriteRule .*(?=international_careers) http://consul64.wwwaz1-ts107.a2hosted.com/international_careers/international_careers.php [L,R]
RewriteRule .*(?=career_by_education) http://consul64.wwwaz1-ts107.a2hosted.com/career_by_education/careers-by-educational-level.php [L,R]
RewriteRule .*(?=career) http://consul64.wwwaz1-ts107.a2hosted.com/career/career.php [L,R]
The resulting URL was always:
https://example.com/career/career.php
I don't understand why the pattern seems to work when redirecting to an outside URL, yet does not work if redirecting to a URL on the same domain.
Could anyone please help guide me?

RewriteRule career_by_education /career_by_education/careers-by-educational-level.php [L,R]
RewriteRule international_careers /international_careers/international_careers.php [L,R]
RewriteRule major_careers /major_careers/academic_major_careers.php [L,R]
RewriteRule career /career/career.php [L,R]
The first argument to the RewriteRule directive (the pattern) is a regular expression. This is not an "exact string match". The problem with these rules is that the pattern also matches the redirected URL so would result in an endless "redirect loop", since the "regex" career_by_education matches that string anywhere in the URL-path.
You state that it always redirects to /career/career.php (the last rule above), but that's not possible with the rules as posted - due to the redirect-loop as mentioned above. However, it would happen if you reversed these directives (which you say you had also tried), since the first rule (that matches career only) would always match - but again, that is a redirect loop.
Aside: It might not trigger a redirect loop depending on your server config, eg. if requests for .php files are proxied to a CGI PHP engine.
You need to be more specific with the regex and match only the stated URLs. ie. You need to include anchors on the regex and match career_by_education only and not career_by_education anywhere.
For example:
RewriteRule ^career_by_education$ /career_by_education/careers-by-educational-level.php [L,R]
RewriteRule ^international_careers$ /international_careers/international_careers.php [L,R]
RewriteRule ^major_careers$ /major_careers/academic_major_careers.php [L,R]
RewriteRule ^career$ /career/career.php [L,R]
The order of these directives does not matter.
You don't necessarily need the scheme+hostname (ie. an absolute URL) in the substitution if you are redirecting to the same domain, however, it can help to reduce the number of redirects in the case of domain canonicalisation.
I don't understand why the pattern seems to work when redirecting to an outside URL
Because the directives are not processed again after the redirect (you are now on a different server).
RewriteRule .*(?=major_careers) http://consul64.wwwaz1-ts107.a2hosted.com/major_careers/academic_major_careers.php [L,R]
Using the unanchored positive lookahead is effectively the same as simply major_careers.
RewriteRule ^/career http://consul64.wwwaz1-ts107.a2hosted.com/career/career.php [L,R]
RewriteRule ^/major_careers http://consul64.wwwaz1-ts107.a2hosted.com/major_careers/academic_major_careers.php [L,R]
RewriteRule ^/international_careers http://consul64.wwwaz1-ts107.a2hosted.com/international_careers/international_careers.php [L,R]
RewriteRule ^/career_by_education http://consul64.wwwaz1-ts107.a2hosted.com/career_by_education/careers-by-educational-level.php [L,R]
These all result in a "403 Forbidden" error
Because of the slash prefix, these rules would never match, so they wouldn't actually do anything.
UPDATE:
However, a "problem" with these redirects is that the URL you are redirecting from, eg. /career_by_education is also the name of the filesystem directory you are redirecting to. So, by default, mod_dir will attempt to append a trailing slash, so the rule doesn't match. The 403 likely results from the absence of a DirectoryIndex document in that directory. Strictly speaking, your URLs need to end in a trailing slash, or make the trailing slash optional in the regex (but that could result in a double redirect).
For example:
# Trailing slash is mandatory
RewriteRule ^career_by_education/$ /career_by_education/careers-by-educational-level.php [L,R]
# Trailing slash is optional
RewriteRule ^career_by_education/?$ /career_by_education/careers-by-educational-level.php [L,R]
Although it would be preferable that the URL did not match the name of the directory in the first place.

Related

301 Redirect in htaccess for URLs having Parameter P

I need to set 301 redirect in htaccess for URLs having parameter P. One example URL is
http://www.price4india.co.in/vivo-x20-plus-ud-price-in-india-scanner-feature-real.html?p=1028
to
http://www.price4india.co.in/vivo-x20-plus-ud-price-in-india-scanner-feature-real.html
After redirect everything after .html shall get removed and the value after P=...... can be any numerical value. So far I have tried below query but it is not working. Any suggestion please...
RewriteCond %{QUERY_STRING} ^p(&|$) [NC]
RewriteRule ^ %{REQUEST_URI}? [R=301,L]
With your shown samples, please try following .htaccess rules file. Make sure to keep your .html file and .htaccess files in root path only.
Make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{THE_REQUEST} \s/(.*\.html)\?p=\d+\s [NC]
RewriteRule ^ /%1? [R=301,L]
NOTE: In case you have further more rules in your .htaccess rules, which includes internal rewrite of html files then you could keep these rules above those.
RewriteCond %{QUERY_STRING} ^p(&|$) [NC]
RewriteRule ^ %{REQUEST_URI}? [R=301,L]
This is almost correct, except the regex ^p(&|$) is incorrect. This matches p&<anything> or p exactly. Whereas you need to match p=<anything> (eg. ^p=) or p=<number> (eg. ^p=\d+). This is of course assuming the p URL parameter always occurs at the start of the URL-path (as in your example).
For example:
RewriteCond %{QUERY_STRING} ^p= [NC]
RewriteRule ^ %{REQUEST_URI}? [R=301,L]

Redirect URL and change URL parameter value

I'm trying to do a .htaccess redirect with a parameter but it's not working. Seems like my regex are also wrong. :(
https://example.com/art.php?link=456
Target URL :
https://example.com/art.php?link=789
I tried:
RewriteEngine on
RewriteCond %{QUERY_STRING} link=456
RewriteRule link=789 [L,R=301]
RewriteCond %{QUERY_STRING} link=456
RewriteRule link=789 [L,R=301]
The first argument to the RewriteRule directive is the URL-path you need to match, ie. /art.php (except there is no slash prefix when used in .htaccess). You also need to specify the substitution (target URL) as the second argument (which happens to be the same: /art.php).
For example:
RewriteCond %{QUERY_STRING} ^link=456$
RewriteRule ^art\.php$ /art.php?link=789 [L,R=301]
If you've previously experimented with 310 (permanent) redirects then you'll likely need to clear your browser cache before testing. Test with 302 (temporary) redirects to avoid potential caching issues.
You can save repetition of the URL parts by using backreferences. For example:
RewriteCond %{QUERY_STRING} ^(link)=456$
RewriteRule ^art\.php$ /$0?%1=789 [L,R=301]
Where $0 is the URL-path that the entire RewriteRule pattern matches. And %1 contains the match from the parenthesised subpattern in the last matched condition.
Reference:
https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule

Apache Redirect // to no //

An email went out with the wrong link (https://www.digitalmarketer.com/digital-marketing/content-marketing-strategy//) and we need to redirect the // to (https://www.digitalmarketer.com/digital-marketing/content-marketing-strategy/) but no matter what I try, the redirect isn't working.
They also want it to be redirected to always have https:///www at the beginning and to never have index.html at the end, so already in the .htaccess file I have:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteRule ^content\-marketing\-strategy/index\.html$ /digital-marketing/content-marketing-strategy/? [L,R=301]
I've tried adding a new RewriteRule, but this won't work:
RewriteRule ^content\-marketing\-strategy//$ /digital-marketing/content-marketing-strategy/? [L,R=301]
I'm very new to Apache and redirects so any help is much appreciated! Thank you!
Edit: Of note, this is in an .htaccess file inside of the digital-marketing folder (https://www.digitalmarketer.com/digital-marketing/.htaccess) which was done so all the above rules would only apply to the digital-marketing folder.
You can use insert rule at the end of your other rules to strip multiple // into /:
RewriteCond %{THE_REQUEST} //
RewriteRule ^.*$ /digital-marketing/$0 [R=301,L,NE]
Apache automatically strips down multiple // into one inside the pattern for RewriteRule thus captured value $0 will have all // converted into /
You can write a wildcard expression to remove trailing slashes. The below will match any HTTP or HTTPS URL that trails in a forward slash, and remove all trailing forward slashes from that URL:
RewriteRule ^(.*)/+$ $1 [R=301,L]
And more using 301 redirects, see more here: Best Practice: 301 Redirect HTTP to HTTPS (Standard Domain)
Good luck!
I see nothing in the way that the rule is written that would make it not rewrite. However you have multiple rules with the L flag that might stop processing on the rewrite at an earlier point than you are looking for. From the documentation
The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed.
(https://httpd.apache.org/docs/current/rewrite/flags.html).
You can try this page out http://htaccess.mwl.be/ to test all your rules together. You might have to rewrite them a bit to work with that page, it's not aware of the level your .htaccess file is at so you will have to rewrite all your rules to trigger from the root for example: RewriteRule ^digital\-marketing/content\-marketing\-strategy//$ /digital-marketing/content-marketing-strategy/? [L,R=301]

Rewrite condition to particular URL and redirect

I have a redirect rule that redirects a url of pattern /abcd/* to http://myweb.com/abcd/*.
I want to apply this redirect except /abcd/index.html.
I have tried this.
RewriteCond %{THE_REQUEST} !^/abcd/index
RewriteCond %{REQUEST_URI} !^/abcd/index [NC]
RewriteRule ^/abcd/(.+)$ http://myweb.com/abcd/$1 [NC,R=301,L]
I am not sure if it is correct.
Please suggest me the correct way of doing this.
Try this rule without leading slash in RewriteRule:
RewriteCond %{REQUEST_URI} !^/abcd/index [NC]
RewriteRule ^abcd/(.+)$ http://myweb.com/abcd/$1 [NC,R=301,L]
Difference is ^abcd/(.+)$ instead of ^/abcd/(.+)$
Your 2 conditions were redundant so I reduced it to one.
.htaccess is per directory directive and Apache strips the current directory path (thus leading slash) from RewriteRule URI pattern.

Remove all Subfolders Condition Rewrite .htaccess Apache 1.3.42

I have done a lot of research about removing subfolders however cannot find away to create an .htaccess rule to remove all subfolders in my root directory, example below:
www.domain.com/dan/dan changes to www.domain.com/dan
www.domain.com/pam/pam changes to www.domain.com/pam
www.domain.com/jam/jam changes to www.domain.com/jam
The .htaccess rule should keep this pattern up through infinity without me having to add the names of the subfolders to my rule, kind of like a wildcard condition or catchall scenario.
However, there is one condition, only remove subfolder if the file has the same name as I have illustrated above in my example.
I’m on Apache 1.3.42 so will need a solution that is not for the newer versions please.
Checkout my .htaccess file below, I’ve done a lot of SEO work to it as you can see:
AddType application/x-httpd-php .html
RewriteEngine On
RewriteBase /
#non www to www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
#removing trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
#html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1.html [NC,L]
#index redirect
#directory remove index.html
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.html\ HTTP/
RewriteRule ^index\.html$ http://www.arkiq.com/ [R=301,L]
#directory remove index
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\ HTTP/
RewriteRule ^index http://www.arkiq.com/ [R=301,L]
#sub-directory remove index.html
RewriteCond %{THE_REQUEST} /index\.html
RewriteRule ^(.*)/index\.html$ /$1 [R=301,L]
#sub-directory remove index
RewriteCond %{THE_REQUEST} /index
RewriteRule ^(.*)/index /$1 [R=301,L]
#remove .html
RewriteCond %{THE_REQUEST} \.html
RewriteRule ^(.*)\.html$ /$1 [R=301,L]
Let me know if you know how to forward all subfolders to their respectively named files with one rule as that would be superb.
I have no setup here to test this rule with a real installation of apache, but I am pretty sure you can achieve this by using a positive lookahead with a capture group.
RewriteRule ^(.*?)([^/]+)/(?=\2(/|$))([^/]+)/?$ /$1$4 [R,L]
What does this do? ^(.*?) will match everything before the last two slashes. If you would go to example.com/test/test, it would match exactly nothing. ([^/]+) will match the first thing we want to test and puts it in capture group 2. (?=\2(/|$)) is the positive lookahead. A lookahead will 'peek' at the next characters, but will not consume any. \2 is replaced with the second capture group and (/|$) will either match a slash or the end of the string. The last ([^/]+) will match the second 'thing' and /? will make sure that the url is matched even if a / exists at the end of the url. After applying this rule this should happen:
example.com/test/test --> example.com/test
example.com/test/test2 --> no rewrite, because '2' does not match '/' or the end of the string
example.com/test/test/ --> example.com/test
example.com/sub/test/test --> example.com/sub/test
Debugging this rule
If you get an internal server error, please go to your apache error log and read what error it gives. Here is proof it works on a clean .htaccess on Apache 2.4.4 and, while it takes 1 minute to check an error log, it takes me several hours to read all patch notes for all Apache versions of the last 3 years.
External redirect, internal rewrite, preventing infinite loop
Assuming that above rule works on your version of mod_rewrite/apache/regex, the following construction will work to externally redirect your request, then internally rewrite it back. Please note that /test/test will not do anything sensible, unless you tell apache how to execute such a file. Proof of concept.
#The external redirect
RewriteCond %{THE_REQUEST} ^(GET|POST)\ /(.*?)([^/]+)/(?=\3(/|\ ))
RewriteRule ^(.*?)([^/]+)/(?=\2(/|$))([^/]+)/?$ /$1$4 [R,L]
#The internal rewrite
RewriteCond %{REQUEST_URI} !^/(.*?)([^/]+)/(?=\2(/|$))([^/]+)/?$
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*/|)([^/]+)/?$ /$1$2/$2 [L]
You mention DirectorySlash Off. Please note that on current versions of Apache this would only get applied to an actual external request. While doing internal rewrites you are safe. In both examples above, in Apache 2.4.4, even though I redirect to an url without a trailing slash, Apache will still append a slash in a second redirect. I am clueless how this was handled in 1.3.
If Apache 1.3 doesn't support backreferences or lookaround in it's regex engine, which I still can't test, there is no real way of testing if an url contains two segments that are the same via mod_rewrite. You'll either need to use a custom router page or write out every url out there (which can cause performance issues, as that is likely a lot). Rewriting to a router page goes like this:
RewriteRule ^(.*)$ /myrouter.php?url=$1 [L]
This router page in a language of your choice can send the 301 or 302 header too with a custom location. It will need to handle all other requests too that are matched by the rewriterule above.