How to re-write %3f to ? in apache - apache

Most of our pages are accessed by query string, so our URLs look like this:
http://www.example.com/?var=val&var2=val2
I found that somewhere on the web, someone has linked back to us with links like this:
http://www.example.com/%3Fvar%3Dval%26var2%3Dval2
I found a large block of code to add to my .htaccess file, but it REALLY slowed down my page requests. What I'd like is to just catch that "%" at the beginning of the filename and redirect it to a php file where I can parse it into a query string and 301 redirect it.
I have a feeling that if I knew what I was doing this would actually be a pretty easy thing. Let's presume that my php file will be called percent_fix.php
(I am sure I can write the php, I just need help with the .htaccess rewrite condition and rule.)

Try to give your default page to your links. e.g. index.php
Then add to your .htaccess
# for %3f ...
RewriteRule ^/index.php\?(.*)$ /index.php?$1

You are almost certainly getting a 403 error.
The error is caused because ? is a banned file/directory name character on Windows and Linux. This means when Apache attempts to find a file or directory named "/document/root/index.php?blah" (after decoding) and it causes a 403 error. This is before the .htaccess files are read so you cannot use mod_rewrite in the .htaccess file to override this 403 error or an ErrorDocument defined in the .htaccess file to catch this error.
The only way to catch %3f is to use mod_rewrite or an ErrorDocument in a "VirtualHost" e.g. in httpd-vhosts.conf (or the main server configuration if there aren't any "Virtualhost"s e.g. in httpd.conf).

try the following in your .htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php$1 [L,NC]

I went back to the link I included in my question, and realized that the simple case near the top of that thread actually does what I need.
Here's what actually work for me:
#in .htaccess
RewriteEngine on
# If an encoded "?" is present in the requested URI, and no unencoded "?" is
# present, then externally redirect to replace the encoded "?" character.
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?\ ]+)\ HTTP/
RewriteCond %1 ^(([^%]*(\%(25)*([^3].|.[^F]))*)*)\%(25)*3F(.*)$ [NC]
RewriteRule ^. http://www.example.com/percent_fix.php?%7 [NE,R=301,L]
Then in percent_fix.php
<?php
if($_SERVER['QUERY_STRING'])
{
$new_query=urldecode($_SERVER['QUERY_STRING']);
header('HTTP/1.1 301 Moved Permanently');
header('Location: http://www.example.com/?'.$new_query);
die();
}
else
{
header('HTTP/1.x 404 Not Found');
//readfile("http://www.example.com/?page=404_error");
die();
}
?>

Related

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

Problems redirecting from a 403 using .htaccess (Yourls)

I'm using a php app called Yourls. It's a self-hosted url shortener and it's pretty great, I'm happy with its overall functionality. Due to the nature of its development however there isn't much in the way of support. Let's pretend the base url is af.to, where a shortened url would be af.to/goo that might redirect to whatever url is defined by 'goo'. The problem I'm facing is that if someone goes to af.to, they end up on a 403-Forbidden. I'd rather the client is redirected to a specific url instead. I have already picked up a plugin for Yourls which redirects to a url when a shortlink is not found or mis-typed, but this does not cover the base of af.to
I attempted to put in a 403 redirect in the .htaccess, but that broke the whole yourls script resulting in a 500 server error.
Current .htaccess looks like this:
# BEGIN YOURLS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /yourls-loader.php [L]
</IfModule>
# END YOURLS
Any help on what I need to do?
Thank you.
The RewriteCond blocks tell the RewriteRule to skip existing files / folders. When you go to http://af.to/, the root folder exists : no redirection. The apache server doesn't find any index.html (or index.php) file, isn't allowed to list the content of the folder, give up and returns a 403 Forbidden.
You can create the index.html file to show some content or you can add these lines to redirect to an other url :
# just after RewriteEngine On
RewriteRule ^/$ http://my-compagny.com/ [L,R=301]

Mod-Rewrite rules are breaking 404 routing

I am using the following mod-rewrite in my .htaccess file:
RewriteRule ^$ pages/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ pages/$1 [L]
The intention is to hide the subdirectory called /pages/ from displaying in the URL.
So this: http://mysite.com/pages/home.html
Will look like this: http://mysite.com/home.html
It works but there are some unintended consequences.
As a direct result of the .htaccess code I posted above, my 404 routing is no longer working at all. Anything that should trigger a 404 error page is instead generating a 500 Server Error.
How to fix?
EDIT:
As implied above, it does not matter if a custom 404 page is defined in the .htaccess or not. Without it, or a bad path to the error page, the server should still route to its default 404 page, and not give a 500 Server Error.
Surely, there must be a standard way to suppress sections of a URL without breaking the normal routing of 404 errors. From my online research it seems that my method above commonly breaks the 404 routing, and yet so far, I've seen no applicable solution. (This is not a Wordpress installation; just static HTML content)
EDIT 2:
Since I'm only wanting to suppress the one directory from the URL, I never mentioned that I also have other files & directories which are siblings to /pages/ that cannot be pointed at /pages/, such as /graphics/, /includes/, /css/, /cgi-bin/, robots.txt, favicon.ico, etc.
Maybe this is all an exercise in futility or more trouble than it's worth?
Looking for a definitive answer either way.
Following config will look for your static pages inside the pages/ and if found, it'll display them. This shouldn't break 404.
Put it in root folder of your web in .htaccess
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /pages/$1
This should achieve what you are trying to do.
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/([a-zA-Z0-9\_\-]+)\.html$
RewriteRule (.*) /pages/$1 [L]
Thank-you to #Kamil Šrot for getting the closest working solution. However, I needed to add another test ( -d ) to see if the requesting URI is a directory.
This is working great and the 404 error page is again routing properly.
RewriteEngine On
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /pages/$1
How about adding an error page direction to your htaccess file to handle the 404 page:
ErrorDocument 404 /path/to/your/404.html

RewriteCond breaking the RewriteRule for no apparent reason

I've just started playing with mod_rewrite and I'm trying to forward all requests to old html file to go to php files instead.
Here's the .htaccess contents:
RewriteCond $1.php -f
RewriteCond $1.html !-f
RewriteRule ^(.*).html$ $1.php
The problem is it doesn't work when I type in a url to a html page, I get a 404. Nothing in the error logs of Apache, just the 404 in the access log. It should redirect to the php.
Now, the index.php does exist and I can go to that directly and the old index.html file doesn't exist.
Yet, if I comment out the line
RewriteCond $1.php -f
It all works fine, i.e. it forwards my index.html requests to index.php.
Any ideas why? The -f should test that the 'file exists' and $1 should be 'the file', I think?
By the way, does anyone have a good, friendly mod_rewrite tutorial they'd recommend?
In .htaccess you need not use ^ and $. All the rules apply to the urls relative to the current directory.

Redirect site with .htaccess but exclude one folder

I want to 301 redirect an entire website, but exclude everything in a folder called /uploads which exists in the /root directory.
I have googled for this, but didn't come up with anything, or I didn't think what I saw was right.
Can we crack this?
Try this mod_rewrite rule:
RewriteEngine on
RewriteRule !^uploads($|/) http://example.com%{REQUEST_URI} [L,R=301]
This rule does match any URL path that does not begin with either /uploads or /uploads/ (leading / is missing in the pattern due to the path prefix removal when used in .htaccess files) and redirects the request to the corresponding path at example.com.
Simple answer I just stumbled upon myself.
At the top before any other calls add the following
RewriteRule ^(uploads) - [L]
I think you want this:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/uploads/
RewriteRule (.*) http://www.newdomain.com/$1 [R=301,L]
If you get 500 Internal Error then double-check that you have a space between } and ! on the second line.
A mod-alias based solution
Redirect all except a specific folder
Add the following line to your root/.htaccess :
RedirectMatch 301 ^/((?!uploads).*)$ http://newdomain.com/$1
This will redirect all pages (excluding /uploads/*) from your old domain to the newdomain.