Removing .php extensions from output - apache

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/.

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.

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.

why doesn't this .htacess file prevent users from accessing content I want secured?

I am trying to accomplish several things with this .htacess file, but cannot seem to
get it to serve the rewrites I need, while preventing unathorized access to files I want
hidden. My goal is to allow any file located in /sections/section_name/webroot/ to be accessed through /section_name/. So, /admin/images/kittens/cat.jpg would serve up /sections/admin/webroot/images/kittens/cat.jpg if it existed. I want to be able to have multiple sections. If a section is not specified, but the file exists in /sections/default/webroot, then I'd like for that to be served. Any other request should
go to /dispatcher.php. I thought I had this working, until I requested a configuration
file in /config and was able to see it. Then I realized I could basically view any file
if I knew that path.
How can I fix this security issue while still keeping the rewrites working?
Here is my .htacess file:
Options +FollowSymlinks -MultiViews -Indexes
RewriteEngine On
# If a file is requested in the admin webroot, and it exists, allow it to pass through
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^admin(/.*)$ sections/admin/webroot/$1 [L,QSA]
# if the requested url begins with /customers and it is located in /sections/customers/webroot
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^customers(/.*)$ sections/customers/webroot/$1 [L,QSA]
# if the requested url begins with /resellers and it is located in /sections/resellers/webroot
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^resellers(/.*)$ sections/resellers/webroot/$1 [L,QSA]
# if the requested file does not begin with /admin, /customers, or /resellers, and is in /sections/default/webroot, then serve it
RewriteCond %{DOCUMENT_ROOT}/sections/default/webroot/$1 -f
RewriteRule ^(.*)$ sections/default/webroot/$1 [QSA,L,NC]
# Send everything else to the dispatcher
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ dispatcher.php [QSA,L]
I know this isn't quite a solution, but have you tried cutting it all the way down and then adding the rules back one by one, testing each one along the way? For starters, if you can get files in /config that you're not supposed to, I'd try cutting everything except the final rule (which is supposed to send requests in /config to dispatcher) and see if that works. If it does, keep adding things back slowly until you see which specific rule is allowing /config files to be seen. Then you know what to fix.
Adding this to the end worked. Anything that wasn't a valid file requested in one of the
webroot folders, and that wasn't a call to dispatcher.php, was redirected to dispatcher.
RewriteCond %{REQUEST_URI} !=/dispatcher.php
RewriteCond %{REQUEST_URI} !^/sections/[a-zA-Z0-9_-]+/webroot/
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule ^(.*)$ dispatcher.php [QSA,L]

Rewriting an Apache RewriteRule?

In my application's .htaccess file I have the following:
Options -Indexes
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+) index.php
A very lightweight file that puts all unmatched requests through index.php.
However, this application is a social networking website that I've been tasked with making multi-lingual. Therefore, URLs like www.example.com/profile/martin need to be converted in to say, Spanish, and will therefore become www.example.com/perfil/martin.
Therefore, my question is: is it possible to rewrite a RewriteRule? In this instance, I want to rewrite /perfil/martin to /profile/martin, but then have /profile/martin passed to index.php.
Adding the following line before the 'RewriteRule ^(.+) index.php' line should achieve what you want.
RewriteRule perfil/(.*) profile/$1
I'd argue that you should be doing this in your web app's URL routing code though, rather than the htaccess file.

RewriteRule checking file in rewriten file path exists

How can you use ModRewrite to check if a cache file exists, and if it does, rewrite to the cache file and otherwise rewrite to a dynamic file.
For example I have the following folder structure:
pages.php
cache/
pages/
1.html
2.html
textToo.html
etc.
How would you setup the RewriteRules for this so request can be send like this:
example.com/pages/1
And if the cache file exists rewrite tot the cache file, and if the cache file does not exists, rewrite to pages.php?p=1
It should be something like this: (note that this does not work, otherwise I would not have asked this)
RewriteRule ^pages/([^/\.]+) cache/pages/$1.html [NC,QSA]
RewriteCond %{REQUEST_FILENAME} -f [NC,OR]
RewriteCond %{REQUEST_FILENAME} -d [NC]
RewriteRule cache/pages/([^/\.]+).html pages.php?p=$1 [NC,QSA,L]
I can off coarse do this using PHP but I thought it had to be possible using mod_rewrite.
RewriteRule ^pages/([^/\.]+) cache/pages/$1.html [NC,QSA]
# At this point, we would have already re-written pages/4 to cache/pages/4.html
RewriteCond %{REQUEST_FILENAME} !-f
# If the above RewriteCond succeeded, we don't have a cache, so rewrite to
# the pages.php URI, otherwise we fall off the end and go with the
# cache/pages/4.html
RewriteRule ^cache/pages/([^/\.]+).html pages.php?p=$1 [NC,QSA,L]
Turning off MultiViews is crucial (if you have them enabled) as well.
Options -MultiViews
Otherwise the initial request (/pages/...) will get automatically converted to /pages.php before mod_rewrite kicks in. You can also just rename pages.php to something else (and update the last rewrite rule as well) to avoid the MultiViews conflict.
Edit: I initially included RewriteCond ... !-d but it is extraneous.
Another approach would be to first look if there is a chached representation available:
RewriteCond %{DOCUMENT_ROOT}/cache/$0 -f
RewriteRule ^pages/[^/\.]+$ cache/$0.html [L,QSA]
RewriteRule ^pages/([^/\.]+)$ pages.php?p=$1 [L,QSA]
To generalize the question: insert this above the rule that should not be matched if the file exists.
RewriteCond %{REQUEST_FILENAME} !-f
Sean Bright's answer provides a nice worked example for the caching question, but this line works more broadly. In my case, I have a link shortener where people can choose custom URLs and I didn't want it to be able to override existing files such as favicon.ico. Adding this line before the rewriterule fixed that issue.