File being matched first instead of .htaccess rule - php

Whenever I have a file in my webserver and rewrite rule for the same path in my .htaccess, the rule is ignored and the file is automatically served.
I have only one file in the public_html of my webserver - test.php as follows:
<?php
echo "hello ".$_GET['action']
?>
Initially my .htaccess is empty and so visiting http://<domain-name>/test.php?action=world echoes hello world as expected. Also my webhost is so configured that visiting /test?action=world (with empty .htaccess) also echoes hello world.
Now I add the following .htaccess in public_html:
RewriteEngine On
RewriteRule ^test/(\w+)$ test.php?action=$1 [NC,L]
I expect that visiting /test/world will echo hello world, but that does not happen! I get only hello in the response. Now my initially thought is that mod_rewrite is not enabled, so to test that I change the .htaccess to:
RewriteEngine On
RewriteRule ^testmod/(\w+)$ test.php?action=$1 [NC,L]
Now to my surprise visiting /testmod/world actually echoes hello world! This shows that mod_rewrite is indeed available, and confirms that the rewrite rule is ignored when a file actually exists for the requested url.
My mental model is that Apache goes through the rules in the .htaccess, and for any rewrite rule matching the requested rule, Apache internally redirects to path specified in the rule. But that does happen here. It looks like first it checks if there exists any file for the requested url, and if not present, then look at the rewrite rules. Or something entirely else is happening here, maybe because of my webhost's configuration? (FYI, I'm using Bluehost as my webhost).

Add this to disable MultiViews:
Options -MultiViews
The Apache docs on mod_negotiation, describes what the Multiviews Option does, when enabled:
If the
server receives a request for /some/dir/foo and /some/dir/foo does not
exist, then the server reads the directory looking for all files named
foo.*, and effectively fakes up a type map which names all those
files, assigning them the same media types and content-encodings it
would have if the client had asked for one of them by name. It then
chooses the best match to the client's requirements, and returns that
document.
Use:
Options -MultiViews
RewriteEngine On
RewriteRule ^test/(\w+)$ test.php?action=$1 [NC,L]

Related

How to create simple remove .php extension with .htaccess page? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
i am newbie of php
How to create simple remove .php extension with .htaccess page?
My aims is type this url http://site/Test
it can visit hello.php content, anyone know how to do that?? thx
I have one folder that call "Test", there are two file on "Test" Folder
Test/
-hello.php
-.htaccess
hello.php
<?php echo "Hello World"; ?>
.htaccess
RewriteEngine on
RewriteRule ^(.*)$ $1.php
finally, it is not successful
it display the following error message
**Internal Server Error**
The server encountered an internal error or misconfiguration and was unable to complete your request.
anyidea to solve this??? Thank you very much
My aims is type this url http://site/Test it can visit hello.php content, anyone know how to do that?
This isn't simply "file extension removal". If it was then /Test would serve the content from /Test.php. In your example, you are wanting to serve the contents of an entirely different file.
Rewriting the request with mod_rewrite
Since you are requesting a directory (/Test/) and wanting to serve a file from within that directory and the .htaccess file itself is actually located in that directory, you would need to write your RewriteRule like this:
RewriteRule ^$ hello.php [L]
In .htaccess (directory context), the RewriteRule pattern matches the URL-path relative to the location of the .htaccess file. So, in this case the URL-path we are matching against is simply an empty string, ie. ^$, since we are wanting to match /Test/<nothing>.
Likewise, when the susbtitution string (ie. hello.php) is relative (as it is here), it is relative to the location of the .htaccess file. So, in this case it effectively rewrites the request to /Test/hello.php (it's actually the absolute filesystem path, eg. /var/www/user/public_html/Test/hello.php - after the directory-prefix is added back).
Additional issues with this example
Since you are rewriting a request that would otherwise map to a physical directory there are a couple of potential issues you need to be aware of...
You should request the directory with a trailing slash, ie. /Test/, not /Test (as you stated in your initial example), otherwise mod_dir will issue a 301 redirect to append the slash before your rewrite is successful.
(There are ways to avoid the trailing slash, but this does increase the complexity and requires further manual rewrites.)
An additional complication occurs if there is a DirectoryIndex document in this subdirectory. eg. /Test/index.php. In this case mod_dir issues an internal subrequest to the DirectoryIndex document (eg. index.php) and this takes priority over your internal rewrite. (Your rewrite does still occur, but mod_dir "wins".) If this is the case then you can rewrite the DirectoryIndex document instead of an empty URL-path. For example:
RewriteRule ^index\.php$ hello.php [L]
This is perhaps counter-intuitive, as we are now rewriting the internal subrequest that mod_dir has issued in a later pass through the file.
You could handle both scenarios and make index.php optional. For example:
RewriteRule ^(index\.php)?$ hello.php [L]
RewriteRule ^(.*)$ $1.php
Your example would result in an internal rewrite loop (500 Internal Server Error response) since the pattern ^(.*)$ also matches the rewritten URL and it gets stuck in an endless loop. (The rewriting process doesn't just consist of a single pass through the file. The process repeats until the URL passes through unchanged.)
(Incidentally, this IS an extensionless URL type of rewrite, but it doesn't help you achieve what you stated in your example.)
There are various ways to prevent this "endless loop":
Use a more specific regex, that won't also match the rewritten URL. eg. a regex that excludes a dot such as ^([^.]+)$.
Use a RewriteCond (condition) directive that prevents the rule being triggered on the rewritten URL. eg. Exclude .php files or check that the request does not map to a file, etc.
Use the END flag on the RewriteRule to stop all further processing by the rewrite engine.
Alternative - change the DirectoryIndex
Instead of using mod_rewrite, as explained above, to internally rewrite the request, we could instead change the DirectoryIndex document.
This only works in this particular case where you are requesting a directory and wanting to serve a file from that directory (although strictly speaking the file could be anywhere).
The DirectoryIndex is the document that mod_dir will look for when requesting a directory (eg. /test/). By default, it looks for index.html (and often index.php) and possibly others. If a DirectoryIndex document is not found, you get a 403 Forbidden when requesting that directory (assuming auto-directory indexes are disabled).
For example, you could set the following:
DocumentIndex hello.php
And now when you request /Test/, mod_dir will serve hello.php in that directory.
However, this method (by itself) is limiting and potentially confusing for readers of your code (if changing the DirectoryIndex on a directory by directory basis). It is generally expected that the DirectoryIndex document(s) is consistent throughout your site.

Strange issue using Mod_rewrite and $_GET variable

After reading tons of SO questions, asking friends and so one, I'm coming here with a strange issue regarding Apache mod_rewrite.
I'm trying to catch http://api.server.com/.../results.php?id=X URL though a RewriteRule.
Quite simple you'll say, I know it, my .htaccess file content is :
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^results/(.*)$ results.php?id=$1
results.php is quite simple for debugging reasons, looks like
var_dump($_GET);
But this script always return array 0 { }
Shall I specify that I've already tried to clear the flags, and change the (.*) class by others, without effects.
Thanks for your help.
You will need to disable MultiViews option here:
Options +FollowSymlinks -MultiViews
RewriteEngine on
RewriteRule ^results/(.*)$ results.php?id=$1 [L,QSA,NC]
Option MultiViews is used by Apache's content negotiation module that runs before mod_rewrite and makes Apache server match extensions of files. So /file can be in URL but it will serve /file.php.
Your rewrite rule does not match the URL you are using (http://api.server.com/customer/2/results.php).
The correct URL according to your rule and setup is:
http://api.server.com/customer/2/results/123
However, you mention having placed everything in the /2/ folder. If 2 is the ID you are trying to get, it cannot work -- URL rewriting only works with non-existing paths.
Instead you should place your .htacess and results.php file in the customer folder, and use the following URL:
http://api.server.com/customer/results/2
Or change your rule and URL to:
RewriteRule ^([0-9]+)/results$ results.php?id=$1
http://api.server.com/customer/2/results

Apache PHP mod_rewrite not working

I'm trying to test out the mod_rewrite meaning:
I have two files: level1.php and warpzone.php.
In my .htaccess I have the following code:
RewriteEngine On
RewriteRule ^warp-zone.php$ level-1.php
Yet when I go to warpzone.php, nothing happens :/ (the url doesn't change)
Any suggestions? I really don't know what I'm doing wrong.
First of all you have dashes in php file names at your .htaccess file, while your files does not have them.
Rewrite conditions - this changes the content to new one, but URL stays as it was:
RewriteEngine On
RewriteRule ^warpzone\.php$ level1.php [L]
Redirect conditions - this changes both content and URL to new one:
RewriteEngine On
RewriteRule ^warpzone\.php$ /level1.php [R]
Also you can use Redirect condition instead of mod_rewrite:
Redirect 301 /warpzone.php /level1.php
In case if it does not work for you, you can use headers() method at the top of your warpzone.php file:
<?php
header("Location: " . $_SERVER['SERVER_NAME'] . "/level1.php");
?>
check whether warpzone.php or warp-zone.php is the correct filename, you are mixing them in your example.
check the apache error.log file if mod_rewrite is available, if not then enable it (this can be done either with "LoadModule ..." or it is wrapped by your Linux distribution)
check the apache error.log if you are allowed to use mod_rewrite, if not consider setting "AllowOverride All" in global config files httpd.conf/apache2.conf
change your rewrite rule to "RewriteRule ^warp-zone.php$ level-1.php [L]" to issue an http redirect; without L flag, is is handled internally in the web sever; see https://httpd.apache.org/docs/2.4/rewrite/flags.html for all flags
regards

htaccess rewrite rule not passing url vars when script file is same as rewrite directory

I'm trying to create nice urls with .htaccess files and have come across a weird issue.
I want to change portfolio.php?id=2 to /portfolio/2/
seems pretty simple solution
RewriteRule ^portfolio/([0-9]+)/$ /portfolio.php?id=$1 [L]
this does redirect to the correct script but when i try and run <?=$_GET['id'];?> it is undefined. but if change the script to something that does not equal the fake directory it works.
RewriteRule ^portfolio/([0-9]+)/$ /portfolioitem.php?id=$1 [L]
and just to make sure that it wasn't being caught by any other rules I tested this
RewriteRule ^portfolioitem/([0-9]+)/$ /portfolioitem.php?id=$1 [L]
and again it failed to pick up the id paramater!
any ideas?!
Cheers
This sounds suspiciously like a Multiviews related problem coupled with some PATH_INFO. The Multiviews option is part of mod_negotiation and it will try to match a requested URL path to a file path. It sees:
/portfolio/2/
And sees that there's a /portfolio.php file in the filesystem and assumes that this is what you want (which it is, but not in the same way). I'm willing to bet that instead of looking at $_GET['id'], which is blank of course since there are no GET params, if you look at $_SERVER['PATH_INFO'], you'll see it set to /2/. This is equivalent to going to:
/portfolio.php/2/
where the /2/ part gets passed to portfolio.php as part of the PATH_INFO. And since mod_negotiation is further up in the processing pipeline than mod_rewrite, your rewrite rules never get applied.
Try turning off multiviews. You can do this in your htaccess file using the Options directive (assuming your host has allowed Options):
Options -Multiviews

How to use directory names as options or parameters?

I don't even know how this method is called, I just know the behavior I want to achieve.
My example for this is Facebook. If you go to facebook.com/[username or id] you get to the profile page, but I can't imagine that they're creating a directory in their root folder and putting a index file in there for every user.
So how's the following behavior accomplished; You go to somepage.com/foo/bar/hello but actually you're requesting somepage.com/foo?bar=hello ?
Is this even possible with Apache and PHP?
I don't even know how this method is called, I just know the behavior I want to achieve.
That thing is called URI/URL and the local part of it is passed to a webserver. The webserver then processes the request.
Is this even possible with Apache and PHP?
Yes. Not even even. This is what a webserver is for. What happens on the server is entirely shielded by the HTTP protocol which knows only the URI/URL specification which does not regulate if and how that needs to match to concrete processes or files on the webserver.
For example with the Apache HTTP Server there is a famous module called Mod_Rewrite that does URL-Rewriting. Often in a fashion that the user with her browser does not take any notice of it.
Example configuration with a PHP file (Apache HTTPD):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
</IfModule>
In a PHP script you can obtain the URI/URL by making use of special variables like $_SERVER['REQUEST_URI'] and $_SERVER['QUERY_STRING'].
Commonly this is made with mod rewrite. There you can make a "path" to a variable of a script.
E.g. http://example.com/user/1/edit could be translated with mod rewrite to http://example.com/index.php?function=edit&userid=1
Such a rule would look like this:
RewriteEngine on
RewriteRule ^/user/([0-9]+)/([a-z]+)$ index.php=function=$2&userid=$1 [L]
The first line activated the rewrite module the second line has a regular expression which must match for rewrite the url internally. If you like you can also make that externally with an [R] modifier instad of the [L].
Have a look to the whole documentation to learn more.
The stuff in the breckets are so called flags which are also well documentated.
I hope that helps!

Categories