Error 500 on RewriteRule - .htaccess

I want the following behaviour:
http://www.example.com/mysubdir -> show /mysubdir/index.htm
http://www.example.com/mysubdir/first -> show /mysubdir/redirect.php?token=first
http://www.example.com/mysubdir/first/second -> show /mysubdir/redirect.php?token=first&action=second
http://www.example.com/mysubdir/first/second/third -> show /mysubdir/redirect.php?token=first&action=second&param=third
therefore I created the following .htaccess (inside mysubdir)
RewriteEngine on
RewriteBase /mysubdir/
RewriteRule ^([^\/]+)\/([^\/]+)\/([^\/]+)\/? ./redirect.php?token=$1&action=$2&param=$3 [L]
RewriteRule ^([^\/]+)\/([^\/]+)\/? ./redirect.php?token=$1&action=$2 [L]
RewriteRule ^([^\/]+)\/? ./redirect.php?token=$1 [L]
This causes an error 500
If I remove the last line, however, the first two rules work as expected. I can't see any visible difference between these rules that should cause such an error.

You're getting 500 (internal server error) because your rules are looping infinitely due to presence of [^/]+ in your last rule that will match rewritten URI redirect.php also.
You can fix it using this modified code:
RewriteEngine on
RewriteBase /mysubdir/
# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ redirect.php?token=$1&action=$2&param=$3 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)/?$ redirect.php?token=$1&action=$2 [L,QSA]
RewriteRule ^([^/]+)/?$ redirect.php?token=$1 [L,QSA]
Few more changes made are:
Use QSA to preserve any existing query string in URLs.
You should use anchor $ in your regex patterns.
No need to escape / in regex patterns.

Related

Rewrite rule in htaccess is not working

Here are the .htaccess rules:
RewriteEngine On
RewriteRule ^([^/]*)$ content.php?seourl=$1 [L]
RewriteRule ^pdf/([^/]*)$ content-single.php?seourl=$1 [L]
RewriteRule ^browsepdf$ browse.php [L]
RewriteRule ^browsepdf-([^/]*)$ browse.php?page=$1 [L]
RewriteRule ^download/([^/]*)$ download.php?pdf=$1 [L]
RewriteRule ^sitemap.xml$ xmlsitemap.php [L]
Options -Indexes
Here every URL is pointing to content.php?seourl=$1, even css, js and image files.
Here are some example URLs I need,
http://example.com/sjskjfsk21
http://example.com/asfasfasf43sf
http://example.com/pdf/fhfdhdh3432aaf
http://example.com/pdf/aisfyiahm2faf3
http://example.com/browsepdf
http://example.com/browsepdf-1
http://example.com/browsepdf-2
http://example.com/download/fjaskfjalsk3rs
http://example.com/download/usaydiy7aisydi
http://example.com/sitemap.xml
Can anyone please fix the .htaccess file.
Here every url is pointing to "content.php?seourl=$1"
Because your first (generic) rule catches all the requests. You need to change the order so you have the most specific rules first, and the most generic (catch-all) rules at the end. In your case you just need to move the first rule to the end. For example:
RewriteRule ^pdf/([^/]*)$ content-single.php?seourl=$1 [L]
RewriteRule ^browsepdf$ browse.php [L]
RewriteRule ^browsepdf-([^/]*)$ browse.php?page=$1 [L]
RewriteRule ^download/([^/]*)$ download.php?pdf=$1 [L]
RewriteRule ^sitemap\.xml$ xmlsitemap.php [L]
RewriteRule ^([^/]*)$ content.php?seourl=$1 [L]
NB: I backslash-escaped the dot in sitemap.xml to match a literal dot, otherwise it matches any character.
even css, js and image files.
You can make an exception for these static resources at the beginning of your file, before the existing directives. For example:
RewriteRule \.(js|css|png|jpg|gif)$ - [L]
For any URL that ends in any of the stated file extensions then stop processing the current mod_rewrite rules.
Alternatively (although perhaps marginally less efficient), you can prevent processing of requests for files that exist. Again, this goes before your existing mod_rewrite directives. For example:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
However, this must now check every request for the existence of a file on the filesystem that maps to the request. (It could also be combined with the above rule if required.)
UPDATE: Bringing this together, we have:
# Exclude any existing files from being rewritten
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Specific rewrites
RewriteRule ^pdf/([^/]*)$ content-single.php?seourl=$1 [L]
RewriteRule ^browsepdf$ browse.php [L]
RewriteRule ^browsepdf-([^/]*)$ browse.php?page=$1 [L]
RewriteRule ^download/([^/]*)$ download.php?pdf=$1 [L]
RewriteRule ^sitemap\.xml$ xmlsitemap.php [L]
# Any other requests for the form "/<anything>"
RewriteRule ^([^/]*)$ content.php?seourl=$1 [L]

.htaccess rewrite if nothing specified

I'm trying to modify my .htaccess file to link to three different places, based on the input after the endpoint:
"/api" - Link to the API
"/ABCD123" - If it's a 7 character
alphanumeric string, link to a specific page
"/" - If nothing specified, or for any other inputs link to the homepage.
Here is my .htaccess file:
Options -Indexes
RewriteEngine On
RewriteRule ^api/(.*) ./api/index.php [R,L]
RewriteRule ^([a-zA-Z0-9]{7})$ index.php?l=$1 [L]
RewriteRule ^(.+)$ everythingelse.php [L]
Even though I have the [L] flag specified I always seem to get redirected to the everythingelse.php route, even if I have the 7 character string.
How can I rewrite to match this correctly?
Your rules are looping and executing more than once. L flag only breaks current loop but mod_rewrite can loop again and execute all the matching rules.
Options -Indexes
RewriteEngine On
# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^api/(.*)$ /api/index.php [R,L]
RewriteRule ^([a-zA-Z0-9]{7})$ index.php?l=$1 [L,QSA]
RewriteRule . everythingelse.php [L]

.htaccess RewriteRule Change Directory To Query String 500 Internal Server Error

I have the following code in my .htaccess file, which is mean to convert a directory to a query string parameter:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule ^g/XXXXXXXXXX-WINEGIFTS1$ g/index.php?u=XXXXXXXXXX-WINEGIFTS [L,QSA]
RewriteRule ^g/(.*)$ g/index.php?u=$1 [L,QSA]
So, http://example.com/g/SOMETEXT should get rewritten as http://example.com/g/index.php?u=SOMETEXT
As it stands, it works fine.
However, if I uncomment out the commented line, I get a 500 Internal Server Error.
That line is meant to rewrite one specific URL, http://example.com/g/XXXXXXXXXX-WINEGIFTS1, as http://example.com/g/index.php?u=XXXXXXXXXX-WINEGIFTS
The weird thing is that I have the exact same code running on a different domain, on a different server, and it works fine.
Any thoughts on what's causing this error?
Thanks!
The problem is that if you uncomment the first rule then the second rule becomes unconditional and it matches /g/index.php twice and rewrites to inself causing an endless rewrite loop .
You can use the following
Options +FollowSymLinks
RewriteEngine On
##--Skip the all rules bellow if an existent file/dir is requested--##
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
#########
RewriteRule ^g/XXXXXXXXXX-WINEGIFTS1$ g/index.php?u=XXXXXXXXXX-WINEGIFTS [L,QSA]
RewriteRule ^g/(.*)$ g/index.php?u=$1 [L,QSA]

Force redirect for certain files (based on referer) and trigger a 404 page otherwise

We distribute different versions of a software product through a single download link. The delivery is based on the referer in conjunction with a default value, which works fine. In addition the user should be redirected to a 404-page, in case the wrong filename was used.
At the moment the .htaccess-file looks like this:
# stop directory listing
Options -Indexes
# turn rewrite engine on
RewriteEngine On
# force 404 if file name is missing or wrong
RewriteCond %{REQUEST_URI} !^(download_mac\.zip|download_pc\.zip)$
RewriteRule (.*) 404/index.html [L]
# an example based on the referer
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-a\.com [OR]
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-b\.com
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ domain_ab/$1 [L]
# last rule if no referer matches
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ default/$1 [L]
So I have one issue and one additional question with this file:
The first rule, to force 404, is very greedy and gets the error page every time, no matter what URL is called. I also tried single statements like RewriteCond %{REQUEST_URI} !^download_mac\.zip$ without any effect. How can I fix this?
How can I get rid of the filenames in any other rule? I tried things like RewriteRule ^(.*)$ default/$1 [L] but it gives me a hard time and an 500 Internal Server Error.
You can avoid repeating your filenames by using an Env variable like this:
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ - [E=ALLOWED:$1,NC]
RewriteCond %{ENV:ALLOWED} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /404/index.html [L]
RewriteCond %{ENV:ALLOWED} !^$
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-a\.com [OR]
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-b\.com
RewriteRule ^ /domain_ab/%{ENV:ALLOWED} [L]
RewriteCond %{ENV:ALLOWED} !^$
RewriteRule ^ /default/%{ENV:ALLOWED} [L]
You can just move the rewrite rule to the end. The other rules handle the valid cases and if none of them matches the last rule applies
# an example based on the referer
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-[ab]\.com
RewriteRule ^download_(mac|pc)\.zip$ domain_ab/$0 [L]
# last rule if no referer matches
RewriteRule ^download_(mac|pc)\.zip$ default/$0 [L]
# force 404 if file name is missing or wrong
RewriteRule ^ 404/index.html [L]

same path of url but pointing to different directories

Im trying to redirect this,
www.example.com/about expect to matched with docs/about.html
www.example.com/register expect to matched with mod/register.php
RewriteCond %{REQUEST_URI} !\.+$
RewriteRule ^([^\.][a-z]+)$ docs/$1.html [L]
RewriteRule ^([^\.][a-z]+)$ mod/$1.php [L]
The first rewrite rule works great,
but the second rewrite rule won't work, it keeps showing 404 error.
As long as you don't have the same file in both places (e.g. /docs/foo.html and /mod/foo.php, you can do a check against the destination first before you rewrite:
# check for docs/.html first
RewriteCond %{REQUEST_URI} ^/([a-z]+)$
RewriteCond %{DOCUMENT_ROOT}/docs/%1.html -f
RewriteRule ^ /docs/%1.html [L]
# If not .html, then check for mod/.php
RewriteCond %{REQUEST_URI} ^/([a-z]+)$
RewriteCond %{DOCUMENT_ROOT}/mod/%1.php -f
RewriteRule ^ /mod/%1.php [L]

Resources