To start, I am a beginner with PHP and .htaccess. Here is my dilemma...
I have built dynamic pages and used htaccess to rewrite the urls. There are 3 types of pages... Examples:
State: example.com/massachusetts-colleges.html
City: example.com/massachusetts-colleges/boston-ma-colleges.html
College: example.com/massachusetts-colleges/boston-ma-colleges/harvard.html
The problem is that pages are being requested (from old linking structure probably) that shouldn't exist such as:
example.com/boston-ma-colleges.html
The state urls are stored in a locations table in the database (stateSlug = massachusetts-colleges). The city urls are also stored in the locations table in the database and the corresponding state slug is also stored with that city (citySlug = boston-ma-colleges and stateSlug = massachusetts-colleges). The Colleges are stored in a different table and use ID's to correspond with the cities.
How can I use .htaccess to prevent any "OTHER" urls from being accessible (page displays template and no data), and show a 404 page (or redirect to home page)?
This is what my .htaccess file looks like now:
RewriteEngine on
RewriteRule ^([^/\.]+)\.html?$ php/statePage.php?stateSlug=$1 [L]
RewriteRule ^([^/\.]+)-colleges/([^/\.]+)\.html?$ php/cityPage.php?citySlug=$2&stateSlug=$1 [L]
RewriteRule ^([^/\.]+)-colleges/([^/\.]+)/([^/\.]+)\.html?$ php/collegePage.php?collegeSlug=$3&citySlug=$2&stateSlug=$1 [L]
Again, I am somewhat new to the htaccess and php languages. I would appreciate any help in this matter.
Thank you!
Assuming all of your content is matched by one of the above URLs, you can simply forbid access to everything else by adding another rule to the end:
RewriteRule ^(.*)$ - [F]
To avoid messing with requests your images and CSS, you should add:
RewriteCond %{REQUEST_FILENAME} !\.(jpg|png|gif|js|css)$ [NC]
RewriteRule ^(.*)$ - [F]
If you have directories which should be made inaccessible, place a .htaccess in them with only the following:
Order deny,allow
deny from all
Try the following, but replace index.php with your 404 page:
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$l [L]
This should redirect all file and directory requests that were not found to index.php or your choice of script file, a 404 page for example. Just remember to set the headers to a 404 response code.
I got this from the CodeIgniter wiki page at http://codeigniter.com/wiki/mod_rewrite/
Their wiki page was very helpful when I tried to solve a similar problem.
rewrite all your public files to fake directory /allow/.., display 404 for any request which is not in /allow/.. directory. Finally rewrite files from /allow/.. to real directory.
It's great workaround IMO :) Better than using deny all in every dir...
Related
I'm struggling pretty hard with .htaccess. Even though I looked up quite a few solutions here, I couldn't get to setup the following:
I have a file called index.php. Inside the index.php I have a link like
Post
Clicking the link, should lead to a file in the same directory called post.php. Inside the post.php I'm grabbing the id through $GET['id'].
But I still like to display post/12345678901 as the URL.
I already tried editing the .htaccess but clicking the links leads to a 404.
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^post/([^/]+) /post.php?id=$1
You have a RewriteRule but you probably need a ReWriteCondition to go with it else this rewrite will be applied to every call to a page on the apache.
Options +FollowSymlinks
RewriteEngine on
# Not a file
RewriteCond %{REQUEST_FILENAME} !-f
# not a directory
RewriteCond %{REQUEST_FILENAME} !-d
# Edited to show root location of files.
# also added NoCaseSensitivity flag.
RewriteRule ^post/([0-9]+)/? /post.php?id=$1 [NC]
Also remove the first / in the second part of the RewriteRule because that will be domain.com/post.php which might not be your actual file location.
Your HTML appears to be showing relative filepathing which is not a good idea and might come back to bite you in the future, As a recommendation every URL on the same domain on your HTML should start with a / so;
Post
Which can then be manipulated by the .htaccess to go where you need, even in another folder (not the base).
My website has a library / directory path like:
{root}/pages/{files}.php
My index.php path is the following: {root}/index.php
I want, that when people go to (as an example) 'login.php' (which exists in the /pages directory. that the url does not contains the '/pages'.
So:
www.website.com/pages/dashboard.php
Redirects to
wwww.website.com/dashboard.php
And that it is possible that when people access www.website.com/dashboard.php they can access this page.
Sorry for the bad explaining, can't find the good words for it.
Edit : This is my .htacces now
RewriteEngine on
# Rewrite automatic to /index.
RewriteCond %{REQUEST_URI} ^/$
# Second check for if above doesn't do the job [www/https].
RewriteCond %{REQUEST_URI} !^/index [NC]
RewriteRule ^$ /index [R=301,L]
# Delete all the .php and .html extensions from files [url-related].
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
# Prevent people for looking inside the .htacces file.
<Files .htaccess>
order allow,deny
deny from all
</Files>
And I did try this:
RewriteRule ^/?pages/(.*)$ /$1 [R=301,L]
(Which did redirect me, but still received a 404 error.
I doubt you can do that with .htaccess only. (EDIT: you can, see "EDIT" below)
What you want is to PRETEND that login.php were in the root directory, but actually it is not.
EDIT: I think I mixed it up. You could do it with the .htaccess-file only. But I don't recommend it. You would have to add all redirections per hand (or develop expressions for the different cases).
Instead, I propose to use the following technique. It is basically the start of a self-made Content-Management-System, where the user can create pages on their own and name the URL leading to this page. Also, this all can be extended to an ajax-supporting website to be really up-to-date!
Using .htaccess only
In case you are not interested in the named advantages of the controller-technique, replace the code in your .htaccess-file and your login-page-problem is solved.
RewriteEngine on
#catch www.example.com/login.php and redirect without user's conciousness to www.example.com/pages/login.php
RewriteRule ^(login.php)$ http://www.example.com/pages/login.php [NC,L,QSA]
# Prevent people from looking inside the .htacces file.
<Files .htaccess>
order allow,deny
deny from all
</Files>
In case you want to gain more (and actually helpful) knowledge and want to learn a universal technique of how to start a CMS with the named advantages, continue reading!
Goal of this example
When the user calls the URL "www.example.com/login", the login-page ("login.php") will be loaded.
Setup
You need a .htaccess-file in the root directory.
You need a "controller" in the root directory (I propose index.php).
You need content pages somewhere, in this example a file called "login.php" in root/pages.
Htaccess will redirect all URLs to this controller, also it passes the URL originally called by the user. Based on the passed URL the controller decides which page content to load. In our case it will be login.php.
Controller
path: root/index.php
<?php
function callPage($data) {
if (isset($data['path'])) {
// get the correct file for the given path
switch ($data['path']) {
case "login":
include("/pages/login.php");
break;
default:
// show 404 error if given path is unknown
include("/pages/error.php");
}
}
}
?>
<html>
<head></head>
<body>
<div id="page"><?php callPage($_GET); ?><!-- load called page's content --></div>
</body>
</html>
Example content page
path: root/pages/login.php
<p>I am a happy login page. See, that I don't need any HTML Tags, a body or a head, because I am meant to be used only when mother index.php calls me up and integrates me. Life's so easy!</p>
<p>And do you know what's the best? I can even run PHP inside myself! Awesome, isn't it?</p>
.htaccess-file
path: root/.htaccess
RewriteEngine on
#if called file or directory reallyexists, don't redirect (might lead into a loop)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#redirect every URL (that does not really exist) to index.php
#the URL the user called can be accessed in index.php in $_GET['path']
RewriteRule ^(.*)$ http://www.exampe.com/index.php?path=$1 [NC,L,QSA]
# Prevent people from looking inside the .htacces file.
<Files .htaccess>
order allow,deny
deny from all
</Files>
Impulses
This is of course a very basic example. Currently, there is no advantage in using this technique instead of a simple redirection in the .htaccess-file, rather only disadvantages. But it is now on your own to enhance it. Some possibilities:
index.php: Replace the switch with a database call. It takes the user's url and returns the corresponding "real" URL (the one the user never sees)
Add a title to the page (also saved in database)
Implement an Ajax-support for your website
In the end, this leads to a small system, which can be extended to an own CMS
I have a question about using multiple .htaccess files - I couldn't find the answer to this after looking elsewhere on stackoverflow, so I hope you guys can help.
I currently have one .htaccess file in the root of my site, which performs a simple url rewrite:
Options -MultiViews
# CheckSpelling off
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?url=$1 [L]
ErrorDocument 404 /index.php
I'm currently working on the second phase of development of this site, and I've made a replica in a subfolder (e.g. www.abcdef.com/new/). The trouble is, at the moment if I click a link on this replica site, it redirects me to the root, original page, whereas I want it to go to the equivalent page in the new/ folder. I've put another .htaccess file in this new/ folder, which however doesn't have any noticeable effect:
Options -MultiViews
# CheckSpelling off
RewriteEngine On
RewriteBase /new/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /new/index.php?url=$1 [L]
ErrorDocument 404 /index.php
So my question is: is it permissible to have another .htaccess file in a subfolder like this? And if so, why aren't the above lines working?
Thanks in advance for any ideas on this!
It's possible to have multiple .htaccess files, and the system is designed to work the way you want it to.
You're setting RewriteBase, which explicitly sets the base URL-path (not filesystem directory path!) for per-directory rewrites.
So it seems like your requests would be rewritten to /new/new/index.php, a path and directory which probably doesn't exist on your filesystem (thus not meeting your RewriteConds) and such is being redirected to your /index.php 404.
As a test, perhaps try changing the ErrorDocument to:
ErrorDocument 404 /new/index.php
If you see rewritten calls go to this then it might indeed be your RewriteBase.
You say
The trouble is, at the moment if I click a link on this replica site,
it redirects me to the root, original page, whereas I want it to go to
the equivalent page in the new/ folder.
Could it be that you are using absolute links in your pages and not relative ones? For instance if a link looks like "/sample", when in your main site it will link to http://.../sample and the same is true if the link is inside a page under "/new/". If you'd use just "sample" then that would resolve as http://..../sample or http://...../new/sample, depending on the URL of the page.
Having a second htaccess file in a subdirectory shouldn't be an issue, and as far as I can tell, your two look okay.
Are you sure the links in the site are correct? (ex, they are /new/foo, not just /foo)?
I've searched and found a lot of questions on this site and elsewhere that are very similar, but I've tried implementing and modifying all the suggestions I've found and none of it works. I realize this is a very basic question an I am extremely frustrated because nothing I'm trying is working.
With that having been said... I am trying to organize my content pages within kurtiskronk.com/pages/... (e.g. kurtiskronk.com/pages/about.php)
What I want to do is make it so that I can simply link to kurtiskronk.com/about ... So how do I go about stripping "pages/" and ".php"? I don't have a ton of content pages, so it's not a big deal if I have to specify for each page, though something dynamic would be handy.
NOTES: I am using Rackspace Cloud hosting, and WordPress is installed in /blog. My phpinfo() can be seen at http://kurtiskronk.com/pages/phpinfo.php
This is my existing .htaccess file (in the root)
php_value register_globals "on"
Options +FollowSymLinks
RewriteEngine On
#301 redirect to domain without 'www.'
RewriteCond %{HTTP_HOST} ^www\.kurtiskronk\.com$ [NC]
RewriteRule ^(.*)$ http://kurtiskronk.com/$1 [R=301,NC]
RewriteBase /
RewriteCond %{ENV:PHP_DOCUMENT_ROOT}/pages/$1 -f
RewriteRule ^(.*)$ pages/$1 [L]
RewriteCond %{ENV:PHP_DOCUMENT_ROOT}/pages/$1.php -f
RewriteRule ^(.*)$ pages/$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/ blog/index.php [L]
# PHP - MAIL
php_value mail.force_extra_parameters -kurtis#kurtiskronk.com
I tested and the rewrite works with the line below (/about as URL brings up file /pages/about.php), but then the homepage gives a 500 Internal Server Error:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /pages/$1.php [L]
So I'm still sort of in the same boat as before, and as a follow-up, possibly more difficult question, if you go to http://kurtiskronk.com/weddings I am using SlideShowPro (flash) w/ SSP Director (self-hosted) as the back-end for it. When it pulls up a new image, it adds the following after /weddings ... "#id=album-152&num=content-9698"
There are four sections of the portfolio
# Homepage (kurtiskronk.com) id=album-148 ($id is constant for this section)
# Weddings (/weddings) id=album-152 ($id is constant for this section)
# Portraits (/portraits) id=album-151 ($id is constant for this section)
# Commercial (/commercial) id=album-150 ($id is constant for this section)
Assuming we get kurtiskronk.com/weddings to rewrite successfully without breaking anything, how would we make the total URL something cleaner kurtiskronk.com/weddings/9698 since the $num is the only thing that will change within a given section?
Kurtis, thanks for the extra information. It's a lot easier to give a specific answer to this.
My first comment is that you need to separate out in your thinking URI space -- that is what URIs you want your users to type into their browser -- and filesystem space -- what physical files you want to map to. Some of your mappings are URI->URI and some are URI->FS
For example you want to issue a permanent redirect of www.kurtiskronk.com/* to kurtiskronk.com/*. Assuming that you only server the base and www subdomains from this tree, then this cond/rule pair should come first, so that you can assume that all other rules only refer to kurtiskronk.com.
Next, you need to review the RewiteBase documentation. .htaccess files are processed in what Apache calls a Per-Directory context and this directive tells the rewrite engine what to assume as the URI base which got to this directory and .htaccess file. From what I gather, your blog is installed in docroot/blog (in the filesystem, and that you want to get to directory by typing in http://kurtiskronk.com/blog/ but that this .htaccess file is for the root folder -- that is the base should be (this goes before the www mapping rule)
DirectorySlash On
DirectoryIndex index.php
RewriteBase /
#301 redirect to domain without 'www.'
RewriteCond %{HTTP_HOST} ^www\.kurtiskronk\.com$ [NC]
RewriteRule ^(.*)$ http://kurtiskronk.com/$1 [R=301,NC]
You can add some field dumps look for REDIRECT_* in the Server or Environment table in the phpinfo O/P to see if these are sensible. For example:
RewriteWrite ^(.*)$ - \
[E=TESTDR:%{DOCUMENT_ROOT}/pages/$1.php,E=TESTPDR:%{DOCUMENT_ROOT}/pages/$1.php]
Your next rule is that if the file exists in the subdirectory pages then use it:
RewriteCond %{DOCUMENT_ROOT}/pages/$1 -f
RewriteRule ^(.*)$ pages/$1 [NS,L]
[Note that some shared service sites don't set up DOCUMENT_ROOT properly for the rewrite engine so you may need to run a variableinfo script (<?php phpinfo(INFO_ENVIRONMENT | INFO_VARIABLES); to see if it sets up alternatives. On your site you have to use %{ENV:PHP_DOCUMENT_ROOT} instead.]
Your next rule is that if the file exists, but with the extension .php in the subdirectory pages then use it:
RewriteCond %{DOCUMENT_ROOT}/pages/$1.php -f
RewriteRule ^(.*)$ pages/$1.php [NS,L]
Now redirect any blog references to the blog subdirectory unless the URI maps to a real file (e.g. the blog stylesheets and your uploads.)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/ blog/index.php [L]
A complication here is that WP may be using a poorly documented Apache feature call Path Info that is a script can act as a pseudo directory so http://kurtiskronk.com/blog/tag/downtown/ is redirected to docroot/blog/index.php/tag/downtown/ which is then executed by `docroot/blog/index.php using /tag/downtown/ as the PATH_INFO. But this is one for Wordpress experts to comment on. If this last rule doesn't work then try:
RewriteRule ^blog/(.*) blog/index.php/$1 [L]
PS. I like your site. I wish I was that young again :(
Postscript
When you say "it doesn't work", what doesn't with this .htaccess?
http://kurtiskronk.com/phpinfo,
http://kurtiskronk.com/phpinfo.php,
http://kurtiskronk.comblog/tag/downtown/
It's just that these rules work for these tests (with domain swapped) on mine. (One way is to move or copy the above variableinfo.php to the various subdirectories. If necessary temporarily rename the index.php to index.php.keep, say, and copy the variableinfo.php to the index.php file. You can now enter the various URI test patterns and see what is happening. Look for the REDIRECT_* fields in the phpinfo output, and the SCRIPT_NAME will tell you which is being executed. You can add more {E=...] flags to examine the various pattern results. (Remember that these only get assigned if the rule is a match.
Lastly note the changes above especially the additional NS flags. For some reason mod_rewrite was going directly into a subquery which was resulting in redirect: being dumped into the file pattern. I've had a look at the Apache code and this is a internal botch to flag that further redirection needs to take place (which then replaces this or backs out). However this open bug indicates that this backout can be missed in sub-queries and maybe that's what is happening here. Certainly adding the NS flas cured the problem on my test environment.
PS. Note the added explicit DirectoryIndex directive and also that whilst http://kurtiskronk.com will run the root index.php, the explicit /index.php version will run the one in pages, because that's what your rules say.
Here is a simple solution. You can use it apache conf file(s) or in .htaccess (easier to set up when you're trying).
mod_rewrite has to be enabled.
For example, use .htaccess in your DocumentRoot with:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /pages/$1.php [L]
It will redirect /about to /pages/about.php, and any other page.
The "RewriteCond" part is to authorize access to an existing file (eg: if you had an "about" file at the root of your site, then it will be served, instead of redirecting to /pages/about.php).
Options +FollowSymLinks
RewriteEngine On
RewriteRule /([0-9]+)$ /pages/$1.php [L]
Put something like this in your .htaccess file. I guess that is what you want.
Juest a redirect from a simple url to a longer url.
I have a static website with files like index.php, blog.php, contact.php etc
How can I get my website addresses to work so that www.site.com/blog takes you to blog.php?
I think htaccess could do this for me, but am a php noob!
The only alternative I currently use is to create individual folders called 'blog, contact etc' which contains another index.php file inside it
thanks
Yes, you can use mod_rewrite to rewrite all urls. The following will rewrite all non-existing files and folders to requested filename .php:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.php [L]
Visiting /blog and it's not an existing directory will cause this rule to rewrite it as /blog.php.
Something like this should do it.
RewriteEngine on
RewriteRule ^(.*)$ $1.php [NC]
Have a read on mod_rewrite: http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html
I have a static website with files like index.php, blog.php, contact.php etc
If you are generating your documents with PHP, then the site is dynamic, not static.
How can I get my website addresses to work so that www.site.com/blog takes you to blog.php?
Assuming you are using Apache, turn on MultiViews
In your .htaccess file on your server add
Options +MultiViews