Page without extension with disregarded text before - .htaccess

My current .htaccess allows me to view the page as follows:
http://www.test.com/test.php as http://www.test.com/test
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
How it poissible to add anything text before the file name which will be disregarded such as:
http://www.test.com/test34566/test or http://www.test.com/anything/test

In terms of a regular expression, your URL would split in to everything before the last backslash, and everything after it.
^(.*)/([^/]*)/?$
This should allow you to ignore everything before ($1) and use everything after ($2).
Beware though if you are using directories such as in your example, you need to use a rewritecondition that also checks to make sure that the requested URL isn't an actual directory, as well as it not being a file.

Related

Mod_rewrite only working with certain folder names

Context
I'm using mod_rewrite to make my links better for SEO. I made the following rule for my page expanded_debate.php:
Options -MultiViews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^poll/([0-9a-zA-Z_-]+)/([0-9]+) expanded_debate.php?poll_title=$1&pollid=$2 [NC,QSA,L]
When I input this format in the URL (poll/filename/10, for example) I get a 404 error:
Object not found!
The requested URL was not found on this server. If you entered the URL manually please check your spelling and try again.
If you think this is a server error, please contact the webmaster.
Error 404
localhost
Apache/2.4.46 (Unix) OpenSSL/1.1.1h PHP/7.4.12 mod_perl/2.0.11 Perl/v5.32.0
However, when I change the first folder name to certain words, such as "debate" and "expanded_debate" (but not "expandedebate"), the file loads after page refresh. For example:
RewriteRule ^debate/([0-9a-zA-Z_-]+)/([0-9]+) expanded_debate.php?poll_title=$1&pollid=$2 [NC,QSA,L]
works fine.
I have an older .htaccess file, titled ".htaccess11", with the following info, in case it's of any use:
#forbids users from going to forbidden pages
IndexIgnore *
Options -Indexes
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[0-9a-zA-Z_-]+$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/(?:\ Ballot169)?
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
#404 error directions
ErrorDocument 404 /404.php
Question
Any idea why only certain terms in the first folder position ("^debate" in example above) work when using mod_rewrite?
There are no "poll" folders in my project, if that's of any interest.
Let me know if there are any questions.
The line
RewriteCond %{REQUEST_FILENAME}\.php -f
Means "Take the requested URL, map it to a full local path in the normal way, append .php to the resulting path, and then process the following rewrite rule only if there is an existing regular file at the modified path".
For example, the URL "poll/filename/10" will be rewritten only if there is a file called "poll/filename/10.php" in the relevant location.
Since the value of the AcceptPathInfo directive is evidently set to On, this condition will also be met if there is an existing file called "poll.php" or "poll/filename.php". That is why the rewrite rule works when you change "poll" to "debate" or "expanded_debate" – there are existing files called "debate.php" and "expanded_debate.php".
In any case, it sounds like this behavior is not what was intended. Removing the -f condition should give the desired result. Or, to prevent the rewrite rule from making existing files inaccessible, you could replace it with:
RewriteCond %{REQUEST_FILENAME} !-f
The exclamation point negates the -f test: "continue only if this file does not exist"
If you are using the %{REQUEST_FILENAME} server variable (anywhere), you should be aware of how the AcceptPathInfo directive will affect this, and consider setting that directive explicitly in the same .htaccess file.
If Options +MultiViews is in effect, then %{REQUEST_FILENAME} will match existing files whether or not the extension is included in the request (GET /foo will match an existing file "foo.php", "foo.html", etc.). And GET /foo.php will match in any case. So, omit the string "\.php" from the original rule.
Other configuration may also have an effect, too. The important point is that, unlike %{REQUEST_URI}, %{REQUEST_FILENAME} invokes all the processing that Apache would otherwise do to translate a URL into a local path.
(source)
NB: although I don't think it was the intention here, you actually might want to test for the existence of a local file as part of this rule. You could use a RewriteCond to check whether the back-end data file for a given poll has been manually created, and return 404 by default if it has not. That would be a simple way to prevent users from making up their own poll URLs at will.

How to rewrite directory for multiple level directories

This is my .htaccess
RewriteEngine On
# browser requests PHP
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.php
RewriteRule ^/?(.*)\.php$ /$1 [L,R=301]
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php
RewriteCond %{REQUEST_URI} !^/(views|css|js|media|partials|php)
RewriteRule (.*) /views/$1
This is my project structure:
The idea is that all my HTML files are structured in the folder views, but I don't want my URL to be http://example.com/views/index but just http://example.com/index without the views-part.
This is working fine in the following case:
http://example.com/account/
But fails as soon as I try to access a file in the accounts-folder e.g: http://example.com/account/voeg-kind-toe
That results in a 404. Seems like this .htaccess solution only works for one-level directories.
Edit:
Interesting: If I place the bottom two lines on top (so placing the code to rewrite the view-part before the code to remove the php-extension); the php-extension works but the /views//part don't.
Create .htaccess like this
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/views/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /views/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ views/ [L]
As mentioned in my comment above, providing there are no other directives/conflicts then this should still "work" in a roundabout way. However, there is an issue with the following directive in the order you have placed it:
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php
You aren't testing for files in the /views subdirectory. But also, REQUEST_FILENAME does not necessarily contain what (I think) you think it does. When you request /account/voeg-kind-toe (an entirely virtual URL path) then REQUEST_FILENAME contains /account (it actually contains an absolute filesystem path, but I've kept it brief). So, the above is testing whether /account.php exists, not /account/voeg-kind-toe.php, or even /views/account/voeg-kind-toe.php - which is presumably the intention.
So, on the first pass, the above condition fails, no rewrite occurs, and processing continues...
The second rule then rewrites the request for /account/voeg-kind-toe to /views/account/voeg-kind-toe. Providing there are no further mod_rewrite directives, the rewrite engine then starts over. This time, /views/account/voeg-kind-toe is the input.
On the second pass, REQUEST_FILENAME is /views/account/voeg-kind-toe (since /views/account is a physical directory) and the request is rewritten to /views/account/voeg-kind-toe.php (since the filesystem check should be successful). Providing you have no other directives then processing should now stop.
This is working fine in the following case: http://example.com/account/
/account/ is simply rewritten to /views/account/ by the last rule.
Edit: Interesting: If I place the bottom two lines on top (so placing the code to rewrite the view-part before the code to remove the php-extension); the php-extension works but the /views//part don't.
The same process as above occurs, EXCEPT this all occurs in a single pass and so is less dependent on other directives that might occur later in the file.
I'm not sure what you mean by "the /views//part don't"?
Assuming you only have .php files within the /views directory and all URLs are intended to target the /views subdirectory and you don't need to reference directories directly then you could do this is a single directive and rewrite everything that does not contain (what looks like) a file extension to /views/<whatever>.php.
For example:
RewriteRule !\.\w{2,4}$ /views%{REQUEST_URI}.php [L]
The L (last) flag is required if you have other mod_rewrite directives that follow - to prevent additional processing.
This does mean you can't rely on the directory index. ie. You need to request /index (as in your example), not simply / to serve /views/index.php.
(You still need your first rule that removes .php from the requested URL - although this is only strictly necessary if you are changing an existing URL structure, where you previously used .php on the URLs.)

url rewriting with htaccess not working

I am trying to rewrite my urls in my site so whatever is after the slash is passed as an argument (example.com/Page goes to example.com/index.php?page=Page)
here is the code that isn't working (it gives a Forbidden):
RewriteEngine On
RewriteRule ^/(.+)/$ /index.php?page=$1 [L]
Any Help will be appreciated
This is what I suggested in the comment to your question:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^(.+)$ /index.php?page=$1 [L,B]
The leading slash does not make sense in .htaccess style files, since you do not process an absolute oath in there, but a relative one. About the trailing slash: your example does not show such a slash, so why do you want to have it in the regular expression? It results in your pattern not matching anything but a request terminated by a slash. Which is not what you want.
The RewriteCond lines are there to still allow access to physical existing files and directories and to prevent an endless loop, though that should not occur with an internal-only rewriting. And you need the B flag to escape the part of the request url you want to specify as GET argument.
The last condition is actually obsolete, since obviously /index.php should be a file. I leave it in for demonstration purposes.
In general it is a very good idea to take a look at the documentation of apaches rewriting module: httpd.apache.org/docs/current/mod/mod_rewrite.html
It is well written, very precise and contains lots of really good examples. It should answer all your questions.

How to make a clean .htaccess?

i have problem with htaccess and not quite good at it. I want to know how to make a url clean.
Here is the original
http://site.com/page.php?p=index1/index2
and i want this type of url
http://site.com/page/index/index2
and how do i get the p value which is index1/index2 if i what to $_get it from the database?
The pattern ([^/]+) matches everything up to but not including / into $1 and the remainder is captured in (.*) into $2.
RewriteEngine On
# Don't rewrite real existing files & directories (like css,js,img)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Add .php to the first group (like page.php) and stick the rest into p
RewriteRule ^([^/]+)/(.*)$ $1.php?p=$2
Inside of PHP, retrieve the value of p via:
$_GET['p']

mod_rewrite to php file unless directory exists

I have a mod_rewrite rule working to direct non-existing directories to a php file which does a database get based on the $1.
Everything works fine unless the directory does exist, which displays the proper directory, but it also appends the query string when it's not necessary.
I have been scouring the web for the past few hours and trying different methods with no luck.
Does anyone know how to keep this functioning as-is, but get rid of the query string?
Thanks much.
Here is my code:
RewriteEngine On
Options +FollowSymlinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([0-9a-zA-Z\-]+)/$ $1 [R]
RewriteRule ^([0-9a-zA-Z\-]+)$ product.php?product=$1
What ends up happening is the browser displays the URL as http://domain.com/existing_dir/?product=existing_dir
try that, it removes / on its own without repeating whole process
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*?)/?$ product.php?product=$1
if You insists on limiting special characters, that would do:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([0-9a-zA-Z\-]+?)/?$ product.php?product=$1
+ is 1 or more repeatition, * is 0 or more, and +?, *? are modifiers for not hungry matching - it allows /? to match anything
Additionally in Your example, first RewriteRule is been executed conditionally (when directory does not exists), the second one is executed always (if first whould not break the process) so even if directory exists
Mod_rewrite doesn't affect the query string, it will always be tagged on to the end of the new URL unless you tell mod_rewrite to have an empty query string. This is done by adding just a ? at the end of the new string. So the first line should look like this:
RewriteRule ^([0-9a-zA-Z\-]+)/$ $1? [R]

Resources