Apache rewrite rule similar to Nginx try_files - apache

In Nginx I played around with try_files which basically took any request for a file on the domain and passed it through a custom php script called file_parse.php. In Nginx it looked like this: try_files $url /file_parse.php
If the file did exist in the document root then it did not use try_files. This rule in Nginx doesn't redirect the user, for example if a user types in http://www.domain.com/123456.html that address shows in their browser but file_parse.php takes 123456.html and echo's out html code based on the number (123456). If file_parse.php doesn't have anything to echo out then file_parse.php sets a 404 header for the client.
Does something like this exist in Apache?

Found an answer, seems to work, no errors in error.log:
<Directory /this/is/the/directory/>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . file_parse.php [L]
</Directory>

Does something like this exist in Apache?
Take a look at mod_rewrite's RewriteMap directive, in particular the prg map type which allows you to run a script and pass it request info.

Related

How does Apache handle index.php/some_text webpage requests? It returns http status 200 instead of expected 404

I have a website on a shared server with some very basic php pages in the public_html directory, as well as some sub-directories with other pages in:
index.php
test.php
subdir1/index.php
subdir2/index.php
Looking at my visitor logs, I'm getting visits to index.php/some_text and index.php/some_other_text and so on. Naively I would expect those to receive an http status 404 as a) there is no directory called index.php and b) no files exist called some_text and some_other_text. However Apache is returning the file index.php with an http status 200.
Is there something I can set in .htaccess that will return a 404 status in these cases, without restricting the valid subdirectories?
I found some suggestions to set "DirectorySlash Off" but that made no difference. I've also tried
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ - [R=404,L]
But that too made no difference.
Thanks.
I'm getting visits to index.php/some_text and index.php/some_other_text and so on.
The part of the URL that starts with a slash and follows a physical file is called additional pathname information (or path-info). So, /some_text (in your example) is path-info.
In this case index.php receives the request and /some-text is passed to the script via the PATH_INFO environment variable (in PHP this is available in the $_SERVER['PATH_INFO'] superglobal).
By default, whether path-info is valid on the URL is dependent on the handler responsible for the request. PHP files allow path-info by default, but .html files do not. So, by default /index.html/some-text will result in a 404.
You can disable path-info by setting AcceptPathInfo Off in your Apache config / .htaccess file. By doing this, a request for /index.php/some-text will now result in a 404.
Conversely, if you set AcceptPathInfo On then /index.html/some-text will also be permitted.
Alternatively, you can use mod_rewrite in .htaccess to explicitly trigger a 404 for such URLs. For example, to target .php files (anywhere) only:
RewriteEngine On
RewriteRule \.php/ - [R=404]
Or, just .php files in the document root:
RewriteRule ^[^/]+\.php/ - [R=404]
Or, you can explicitly check the PATH_INFO server variable to block any URL that includes path-info. For example:
RewriteCond %{PATH_INFO} .
RewriteRule . - [R=404]
Note that some frameworks use path-info to route requests in a front-controller pattern (as opposed to using a query string or parsing the requested URI directly).
Reference:
https://httpd.apache.org/docs/2.4/mod/core.html#acceptpathinfo
I found some suggestions to set "DirectorySlash Off"
That has nothing to do with this issue. Setting DirectorySlash Off prevents mod_dir from appending trailing slashes to requests for directories.
I have since tried
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/[^/]+\.php/.*$
RewriteRule ^(.*)$ - [R=404,L]
This will only then impact *.php files in the root directory, leaving any subdirectories alone. I think. It produces the behaviour I want but it doesn't feel like a good solution.

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]

Nginx rewrite equivalent of apache rewrite

I am trying to change the configuration on my new Nginx server so it matches my current Apache settings.
At the moment I am using this htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php?url=$1 [L,QSA]
I have found a converter that could "translate" this into the Nginx equivalent. I have tried the following:
location / {
if (!-e $request_filename){
rewrite ^/(.*) /index.php?url=$1 break;
}
try_files $uri $uri/ =404;
}
But when I try to set a url query like this http://domain.tld/something my php file gets returned and downloaded and that ain't supposed to happen.
What I expect to happen is when a url like http://domain.tld/something is entered it gets treated like http://domain.tld/index.php?url=something
Can someone tell me what I am doing wrong?
Unlike Apache, nginx doesn't come out-of-the-box ready to run PHP. You need to setup a handler to deal with php files, otherwise nginx will serve them up just like any regular file.
See: Nginx downloads php instead of running it
Also: review the NGINX documentation on using fast-cgi to run php.

.htaccess rewrite url for missing reources

I would like to rewrite files that don't exist to a php handler. I am currently using this .htaccess file, but it doesn't work as I'd like:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /app/index.php?_url=/$1
When I have no files, it works; it redirects correctly for resource that does not exist to my app, and I am able to capture it.
When I have exactly matching file (e.g.: test.txt and I request /test.txt); it loads test.txt correctly.
However, when I have a partial match (e.g.: test.txt exists, but I request /test); it does not redirect at all. In fact, it gives me the standard Apache 404. I want this to actually rewrite to my app, so I can deal with the request in a different manner.
I'm using pretty much default apache 2.2.22 from Debian. Is there some configuration I am missing, or is this the intended behaviour of the rewrite? Is there a way to achieve what I want?
I think you have MultiViews enabled in your Apache by default. Try adding this line on top of your .htaccess:
Options -MultiViews
With MultiViews Apache does its own rewrites and that usually conflicts with mod_rewrite

How to re-write %3f to ? in 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();
}
?>