Convert Query Parameters to Pretty URL - apache

I have script file post.php which I'm using without .php extension using code below
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
I want to use a pretty URL. For example, when I request the URL /post/12 it should give me $_GET parameter 12 like I'm using with a query string: post?id=12.
Is it possible? Also, I don't want to direct all requests to index.php. Only requests that are made to posts.php script.

Handle requests of the form /post/12 with a separate rule, before your generic rewrite that appends the .php extension.
Try it like this:
Options -Indexes -MultiViews
RewriteEngine On
# Remove trailing slash if not a directory
# eg. "/post/" is redirected to "/post"
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ /$1 [R=301,L]
# Rewrite "/post/<id>" to "/post.php?id=<id>"
RewriteRule ^(post)/(\d+)$ $1.php?id=$2 [L]
# Rewrite "/post" to "/post.php" (and other extensionless URLs)
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
Notes:
MultiViews needs to be disabled for the second rule to work.
Your initial rule that appends the .php extension was not quite correct. It could have resulted in a 500 error under certain conditions. However, the first condition was superfluous - there's no point checking that the request does not map to a file before checking that the request + .php does map to a file. These are mutually inclusive expressions.
Without the first rule that removes the trailing slash (eg. /post/ to /post) it raises the question of what to do with a request for /post/ (without an id) - should this serve /post.php (the same as /post) or /post.php?id= (empty URl param)? Both of which are presumably the same thing anyway. However, these would both result in duplicate content (potentially), hence the need for a redirect.

Related

Why my htaccess is not working when i upload it to ionos webspace?

I've tried in in my localhost at it worked fine but after I upload it to my ionos webspace the website index is working but after I click the content it is not directing to anywhere and there is an error message:
Error 404 not foound, Your browser can't find the document corresponding to the URL you typed in.
Here is my .htaccess:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^news/([0-9a-zA-Z_-]+) news.php?url=$1 [NC,L]
RewriteRule ^seksikateg/([0-9a-zA-Z_-]+) seksikateg.php?kategori=$1 [NC,L]
and i placed he file in the same place as the index.php, news.php, and seksikateg.php
It's possible that MultiViews is enabled at your host and this will break your rules since this will append the .php extension before mod_rewrite processes the request.
However, your directives are also in the wrong order. The generic rewrite to append the .php extension should appear after the other rules.
Your rewrite to append the .php extension is not strictly correct as it could result in a rewrite loop (500 error) under certain circumstances.
Try it like this instead:
# Ensure that MutliViews is disabled
Options -MultiViews
RewriteEngine on
RewriteRule ^news/([0-9a-zA-Z_-]+)$ news.php?url=$1 [NC,L]
RewriteRule ^seksikateg/([0-9a-zA-Z_-]+)$ seksikateg.php?kategori=$1 [NC,L]
# Append ".php" extension on other URLs
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
I've also added the end-of-string anchor to the regex of your existing rewrites, otherwise you are potentially matching too much. eg. /news/foo/bar/baz would have also been rewritten to news.php?url=foo - potentially creating duplicate content and opening up your site to abuse.
I would also question the use of the NC flag on these rewrites. If this is required then you potentially have a duplicate content issue.
No need to backslash-escape literal dots in a regex character class and the NC flag is certainly redundant on the last rule.

htaccess pretty urls not working

Folder structure:
- assets
- all css / js
- calsses
- all models, db ant etc
- views
- admin
- app
- index.php
- customers.php
.......
my .htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^(www.)?localhost:8080$
RewriteRule ^(.*)$ /views/$1
RewriteRule ^(/)?$ /views/index.php [L]
address : localhost:8080/app/ - working fine, but then I try to add pretty url for example in my customers.php - localhost:8080/app/customers.php?id=5 change to localhost:8080/app/customers/id/5
htaccess added new line:
RewriteRule /id/(.*) customers.php?id=$1
It's not working, it always return 500 Internal Server Error there could be the problem?
plus Need all urls without .php extend
You'd have to include those conditions for every rule. You'd be better off just rewriting everything to, say views/router.php then using PHP to include the different controllers, or serve a 404 when the URL isn't valid.
RewriteRule !^views/router\.php$ views/router.php [NS,L,DPI]
I agree with Walf in that handling routes through a router class is a better idea (especially in the long run!) than using .htaccess redirects.
However, as your question seems to be more about why is this not working than about how you should do it, here is an explanation for what is going on.
I will be using these URLs as examples:
localhost:8080
localhost:8080/app
localhost:8080/app/customers/id/5
Your first rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^(www.)?localhost:8080$
RewriteRule ^(.*)$ /views/$1
As you intended, this RewriteRule will match any URL which is not a file, not a directory, and made to localhost:8080.
localhost:8080 # not matched because it leads to a directory.
localhost:8080/app -> localhost:8080/views/app
localhost:8080/app/customers/id/5 -> localhost:8080/views/app/customers/id/5
Your next rule:
RewriteRule ^(/)?$ /views/index.php [L]
It is important to realize that RewriteCond statements apply only to the first RewriteRule following them, thus all that is being checked here is the path.
Side note: ^(/)?$, as you are not using $1, can be simplified to ^/?$.
localhost:8080 -> localhost:8080/views/index.php
localhost:8080/views/app # not matched
localhost:8080/views/app/customers/id/5 # not matched
As the L flag is specified, Apache will immediately stop the current iteration and start matching again from the top. The documentation is badly worded. Thus, localhost:8080/views/index.php will be run through the first rule, fail to match, be run through this rule, fail to match, and then as no other rules exist to check (yet) no rewrite will be done.
Now lets look at what happens when you add your broken rule.
RewriteRule /id/(.*) customers.php?id=$1
There are a few problems here. First, as you don't require that the URL start with /id/ the rule will always match a URL that contains /id/, even if you have already rewritten the URL. If you amended this by using ^/id/(.*), then you would still have issues as the string that the rewrite RegEx is tested against has leading slashes removed. Lastly and most importantly, customers.php does not exist in your root directory.
localhost:8080/views/index.php # not matched
localhost:8080/views/app # not matched
localhost:8080/views/app/customers/id/5 -> localhost:8080/customers.php?id=5
This is the last rule in your file currently, so now Apache will start over. customers.php does not exist in your directory, so it will be rewritten to views/customers.php. No other rules matched, but the URL has changed and so Apache will start over again, as /views/customers.php does not exist, it will be rewritten to /views/views/customers.php ... This pattern will repeat until you hit the maximum iteration limit and Apache responds with a 500 error.
You can solve this several ways. Here would be my preferred method, but only if you cannot use a router.
RewriteEngine on
# Rewrite the main page, even though it is a directory
RewriteRule ^/?$ views/index.php [END]
# Don't rewrite any existing files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .? - [S=999,END]
RewriteRule ^app/?$ views/app/index.php [END]
RewriteRule ^app/id/(.*)$ views/app/customers.php?id=$1 [END]
TL;DR Use a PHP based router. .htaccess rules can be incredibly confusing.
Please refer to the question, How to make Clean URLs
I think this is what you needed.
you can use RewriteRule ^(.*)$ index.php [QSA,L]
Having another crack.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{HTTP_HOST} !^(?:www\.)?localhost:8080$ [OR]
RewriteCond $0 =views
RewriteRule [^/]* - [END]
RewriteRule ^(app|admin)/([^/]+) views/$1/$2.php [DPI,END]
RewriteRule ^(app|admin)/?$ views/$1/index.php [DPI,END]
You may have to use L instead of END flags if your Apache is older. Set up an ErrorDocument for 404s, too.
Don't muck around with query strings, just parse $_SERVER['REQUEST_URI'] in PHP, e.g. start by exploding it on /. Then you'll have all the parameters of the original pretty URL. You can do that part in an include so each controller can reuse the same code.
I tried your structure and .htaccess file myself and found an endless loop in the apache logs. I bet you got something like this:
Mon Nov 28 19:57:32.527765 2016] [core:error] [pid 10] [client 172.18.0.1:35048] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
I could fix it by adding the last rule like:
RewriteRule id/(.*) /views/app/customers.php?id=$1
The leading / is not needed for the match and the target needs the full path. Note that I got the id double (e.g. 123/123) on the url: http://localhost:8080/id/123.
This is caused by one of the 2 previous rules (removing them fixes it) so you might need to change them.
Here is what you want :
RewriteEngine On
RewriteBase /app/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^\/?$ views/index.php [L]
RewriteRule ^([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)\/?$ views/$1.php?$2=$3 [L]
RewriteRule ^([a-zA-Z0-9]+)\/?$ views/$1.php [L]

Mod Rewrite & CheckSpelling/CheckCase redirect solution

I have a number of pages setup, to be accessed by clients' guests. The problem being, case sensitive URLs.
Currently I have in my htaccess file (to remove the .php)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) $1.php [L]
for example: (the target file is ClientName.php)
website.com/rsvp/ClientName <-this works, and the file is ClientName.php
website.com/rsvp/clientname <-this serves a Internal Server Error
-- edit/update --
Adding both CheckSpelling on & CheckCaseOnly on does not work, unless the .php is in the url. No combination of the two [mod_spelling & mod_rewrite] would work. I also found out, I do not have RewriteMap
based on this thread/post can I redirect to a php file rather than the 500 error page if the file does not exist? (or edit my 500 error page?)
from the post;
RewriteCond %{REQUEST_URI} !^([a-z0-9/]*)\.html
RewriteRule ^(.*)\.html$ redir.php?p=$1 [L]
Will examine the {REQUEST_URI} string and EXCLUDE (!) everything that's lowercase (or directory -- see the "/"?) .html then rewrite EVERYTHING.html to the redir script. Ahhhhh! I just added the "0-9" in there to handle your digits, too. Remember, these "excluded" strings are the ones you want to PASS through to your pages and NOT rewrite.

My .htaccess rule is not working

I want all my URL with matching pattern as
/released/2013/iron-man
/released/2013/abc-of-death
/released/2012/saw6
to be redirected to
/released/1.php
and I can the name as well.
I am adding this rule to my .htaccess file but its not working
RewriteRule ^released/([0-9]+)/?$ /released/1.php?id=$1 [L]
The trailing question mark matches an optional ending / which is not what you want.
^released/([0-9]+)/iron-man$
or
RewriteRule ^released/([0-9]+)/(.+)$ /released/1.php?id=$1+$2
Problem is that you have $ after second slash but you have movie name after 2nd slash like iron-man etc. Remove $ since you are not matching it.
Make sure that mod_rewrite and .htaccess are enabled through httpd.conf and then put this code in your .htaccess under DOCUMENT_ROOT directory:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(released)/([0-9]+)/ /$1/1.php?id=$2 [L,QSA,NC]
A RewriteRule which does not specify a specific external domain is always executed internally. To make it redirect as you ask add [R=301] at the end - or 302, 303 or 307 depending on which kind of redirect you require, but usually 301 is fine.
Besides that, the regular expression you wrote does not allow for extended URLs - remove the trailing $. After that the /? part is moot so you can remove it as well.
The resulting line would read:
RewriteRule ^released/([0-9]+) /released/1.php?id=$1 [L,R=301]

mod_rewrite condition for existing folder

I'm trying to set-up an .htaccess file that will pass every request URL as GET into a file called index.php. The only exception is, when the request URL points to a directory res.
Examples:
/wiki/cool-stuff => index.php?uri=/wiki/cool-stuff
/wiki/cool-stuff?news=on => index.php?uri=/wiki/cool-stuff&news=on
/res/cool-photo.jpg => res/cool-photo.jpg
Two problems:
The GET variable passed to /wiki/cool-stuff in the second example is not passed to index.php
Accessing /res (not /res/!!) suddenly shows me /res/?uri=res in my browser and index.php with uri=res/. Accessing /res/ instead, shows me index.php with uri=res/ and the URL in the browser stays (which is okay).
The .htaccess:
RewriteEngine on
RewriteBase /subthing/
RewriteCond %{REQUEST_URI} !/res/(.+)$
RewriteCond %{REQUEST_URI} !index.php
RewriteRule (.*) index.php?uri=$1
How can I achieve the desired behaviour?
Try using the Query-String-Append flag, QSA
Make the trailing slash optional - in Regex, this is achieved by adding ?.
New .htaccess:
RewriteEngine on
RewriteBase /subthing/
RewriteCond %{REQUEST_URI} !/res(/.*)?$
RewriteCond %{REQUEST_URI} !index.php
RewriteRule (.*) index.php?uri=$1 [QSA]
Note that I have tweaked the Regex on the /res folder to cause /resabc to be redirected (if the slash was the only optional piece, anything beginning with res would match.
Apache Mod_Rewrite Documentation