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.
Related
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.
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]
I'm developing a small CMS solution with Perch. It's currently running on WampServer on my local development machine.
As Perch doesnt provide friendly URL's out of the box, I wanted to implement this, whilst ensuring the /perch directory remains untouched.
So far, I have the rewriting part working i.e. a request for /blog.php will 301 to /blog, and, /blog will rewrite to /blog.php, using the rules below:
Options +FollowSymLinks -MultiViews
RewriteEngine On
# Rewrites domiain.com/file to domain.com/file.php
RewriteCond %{REQUEST_URI} !^/perch
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
# Redirects domain.com/file.php to domain.com/file
RewriteCond %{REQUEST_URI} !^/perch
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteCond %{REQUEST_URI} ^(.+)\.php$
RewriteRule (.*)\.php$ /$1 [R=301,L]
However, I'm still left with .php extensions in the HTML output. I tried adding the following to my .htaccess file:
AddOutputFilterByType SUBSTITUTE text/html
#Replace all .php extensions
Substitute s|.php||ni
#Original blog pattern /blog/post.php?s=2014-11-18-my-first-blog-post
Substitute s|blog/post\?s=(\w+)|blog/$1|i
However, this is applied globally, i.e. even to links within the /perch folder. I couldn't find anyway of adding a condition to apply it to everything except for the /perch folder - is there such a way?
I also looked at the ProxyPass/ProxyReversePass documentation, but this seems like overkill to just replace some HTML on a page.
Any help would be greatly appreciated.
Kind regards,
dotdev
Are you talking about the Perch CMS from www.grabaperch.com?
Everything is here: http://docs.grabaperch.com/video/v/simple-url-rewriting/
However, I'm still left with .php extensions in the HTML output
.htaccess / mod_rewrite does nothing to your HTML output.
Think of the RewriteRules as a postman who delivers mail (URLs) to target mailboxes (actual files).
What you do is you "manually" omit the .php extension in your markup (HTML output):
In perch_pages_navigation(), you need to set hide-extensionsto true
URLs you add manually: just write them without .php
Now you need to instruct the postman to route those addresses to the .php file anyway. That's what these RewriteRules are for. So .htaccess doesn't remove the .php suffix - on the contrary, it adds it.
Here's the basic .htaccess (goes into your public_html directory) for Perch (or any "remove .php" use case) + Perch Blog. I've added some explanations:
# make sure the address we received (e.g. /mypage) is not an existing file
RewriteCond %{REQUEST_FILENAME} !-f
# make sure it's not an existing directory either
RewriteCond %{REQUEST_FILENAME} !-d
# make sure there IS an existing .php file corresponding to it
RewriteCond %{REQUEST_FILENAME}.php -f
# if the address starts with "blog/", pick what comes afterwards, put it into the GET Parameter and quit (that's the [L])
RewriteRule ^blog/([a-zA-Z0-9-/]+)$ /blog/post.php?s=$1 [L]
# if the first conditions are ok, but it wasn't a blog post (else we would have quit), just append .php to it. Ah, and keep other get params (that's the QSA=Query String Append).
RewriteRule ^(.+)$ $1.php [L,QSA]
For more refined possibilities, you can e.g. start here: https://github.com/PerchCMS/perchdemo-swift/blob/master/public_html/.htaccess
This will have no impact at all on the functionality of the CMS in /perch/.
I am trying to redirect files in a directory to a CGI if the URL does not exist, where the URL is further processed. Since that has also consquences for non-existing files referenced inside of HTML-documents, an HTML-document can trigger an entire cascade of redirects if it contains a lot of references (imgs, css files, js files) that do not exist. Of course, in an ideal world, all of those should exist but, well...
Anyway, since I won't be using the character "." in any of the URLs I want to redirect, I thought it a pretty nifty idea to exclude file names with a "." in the RewriteCond, since that should take care of .css, .js and .gif/.jpg.
Not so lucky. If I enter a URL with a "." in the browser location, I get the (correct) message "file not found", but when I check in the server logs, every non-existent file referenced by the HTML template is passed on to the CGI, regardless of whether it contains "." or not. css/doc.css is processed as will be images/bg.png and all other files containing ".". My .htaccess file contains the following rules:
RewriteEngine on
RewriteBase /bla
RewriteCond %{REQUEST_FILENAME} !\.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /cgi-bin/env.pl?.template=Main.html&.query=$1 [PT]
However, after changing one of the references in the HTML-file for an external stylesheet (css/doc.css) to an absolute URL (aka /css/doc.css), it only provokes the "File not found" error, as it should according to the above rule. Is Apache not applying those regexes to relative URLs?
First of all there is nothing relative when Apache receives a HTTP/HTTPS request. Relative paths are resolved by your browser itself before sending out request to web server.
Now try changing your code to this:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /bla/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !\.
RewriteRule ^(.+)$ /cgi-bin/env.pl?.template=Main.html&.query=$1 [L,QSA]
I'm trying to write an .htaccess file that will
a) when navigating to mysite.com/myusername (which is non existent) it will show the contents of mysite.com/dmp/temp/myusername
b) hide .php from the URL's
When going to mysite.com it however it shows me the contents of mysite.com/dmp/temp folder. If I add /index in front then it will work.
Everything is working as intended except that. How can I make sure users that simply navigate to mysite.com are served index.php (without actually writing /index/ or /index.php) and also not redirected to the /dmp/temp folder?
Code:
Options +FollowSymLinks
Options +Indexes
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %(REQUEST_URI) !^temp
RewriteRule ^(.*) dmp/temp/$1 [L]
Let's look at your two regular expressions:
^([^\.]+)$
and
^(.*)
First one: Match every query which do not contain . with length 1 or more.
Second: Match everything from length 0 or more.
So if you open http://mysite.com/ you have an empty query, and it's matched by the second regex. This means it tries to open dmp/temp/.
Try changing the second regex from ^(.*) to ^(.+). That means it will match only if you have a query of length 1 or more, and it will not match http://mysite.com/. Hopefully, you then will go to standard behaviour, showing the index.* file according to server settings (in your case index.php)