RewriteRule trigger 404 when given too many arguments - php

The site I'm building at the moment is made of two main parts: The side which the general public can access, and the admin side which only authorised people can access.
It's built with basic templating such that the different sections are accessed as follow (Using RewriteRules).
Public:
http://localhost/about should be rewritten to http://localhost/index.php?page=about
Admin:
http://localhost/admin/manage-users should be rewritten to http://localhost/admin/index.php?page=manage-users
All URLs only ever have one argument. That is, public will always be localhost/PAGE and admin will always be localhost/admin/PAGE.
At the moment, I have the following .htaccess file:
RewriteEngine on
RewriteRule ^admin/([^/.]+)/?$ /admin/index.php?page=$1 [L,NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?page=$1 [L,NC]
This seems to work properly when you construct the URL correctly. For example, if I navigate to localhost/about or localhost/admin/manage-users both pages load correctly. But if I go to localhost/about/blah or localhost/admin/manage-users/blah, the pages load, however the CSS is non-existant. Looking at the developer tools in Chrome, it appears that this is because it's trying to load the CSS file from the directories localhost/about/css/ and localhost/admin/css/ respectively, due to the style sheet being linked to the page with a relative path. (In reality, localhost/css/ is the directory it is actually located in.)
So even though the RedirectRule ignores any extra arguments in the URL, it is trying to load relative paths with respect to the last "directory" provided in the URL.
Is there any way to completely ignore any extra ../.. arguments? Or, even better, trigger a 404 when too many arguments are provided?
UPDATE: I have just discovered that the problem is actually a lot more complex than I previously thought. As my pages only had dummy data to test out the templating files, I didn't notice it until now.
It appears than when you navigate to localhost/admin or localhost/admin/manage-users it is loading from the http://localhost/admin/index.php file, but when you navigate to localhost/admin/manage-users/blah is reverts back to loading the http://localhost/index.php file. This makes me think that there is something I need to change in the RewriteRule, though I have no idea what.

It is better in long term to use absolute path in your css, js, images files rather than a relative one. Which means you have to make sure path of these files start either with http:// or a slash /.
But in order to avoid making changes to your website in-mass you can use these rules to fix your css/js/images links:
RewriteEngine on
# fix CSS/js/images links
RewriteRule (?:^|/)((?:css|js|images)/.+)$ /$1 [L,R=301]
RewriteRule ^admin/([^.]+)/?$ /admin/index.php?page=$1 [L,NC,QSA]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ /index.php?page=$1 [L,QSA]
Don't forget to replace first rule with your actual css/js/images directories.

You need to either make all of your links absolute URLs (e.g. href="/css/style.css") or add a relative URL base to the header of your page:
<base href="/" />

Related

.htaccess -- hide dir name in url while keeping folder structure

I have a site with files contained in a /pages/ dir.
I'm trying to hide the /pages/ directory from URLs but still have them in the directory, so basically I am trying to achieve this:
www.example.com/sub/
should load:
www.example.com/pages/sub/
or
www.example.com/sub/file.php
should load:
www.example.com/pages/sub/file.php
-- the aim here is to remove /pages/ from all urls
thanks in advance
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ pages/$1 [QSA,L]
If file or directory doesn't exist, then try in pages folder.
QSA adds url parameters if any (like ?param1=val1&param2=val2)
Apache Re-write: http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
Learn it.
Live it.
Hate it?
edit: its a first in first evaluated, last in last evaluated process, so be considerate when specifying rules, as even if one is established correctly, a broader, more general one which also meets the same pattern (depending on wildcards) has the chance to usurp the prior ( think CSS declaration squashing, if you're familiar with that )

Mod_rewrite website like facebook

I'm using mod_rewrite for the first time in order o create a website similar to facebook.
Whener I type mywebsite.com/user.name, the mod_rewrite redirects me to mywebsite.com/hotsite/index/php and there, I use a little php to get the user name from the url and get the userId from it.
Then I have the other areas like mywebsite.com/user.name/diary, mywebsite.com/user.name/contact, and so on...
This is all working well with this code in my .htaccess:
Options +FollowSymlinks
RewriteEngine on
RewriteBase /mywebsite
# ————————————————————————-
# > URL REWRITING
# ————————————————————————-
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)/diario$ hotsite/diary.php
RewriteRule ^(.*)/recados$ hotsite/messages.php
RewriteRule ^(.*)/fotos$ hotsite/photos.php
RewriteRule ^(.*)/videos$ hotsite/videos.php
RewriteRule ^(.*)/contato$ hotsite/contact.php
RewriteRule ^([a-z0-9._\-]+)$ hotsite/index.php [L]
The problem I have is with the path to the external files (css, images, backgrounds...).
Since my browser thinks I am in "website.com" I had to add "hotsite/" to all the paths. This works well for when I am at the user main page, like "mywebsite.com/user.name". However, if I go to "mywebsite.com/user.name/diary" the browser thinks I'm in another folder and then I have to add "../hotsite" in order for the paths to work.
I could make an IF in all the paths to check if I am at the index or not, but this would be very clumsy.
I could also put absolute paths in evertyhing, but since I'm developing offline with apache, this wouldn't be good either.
Any other solutions?
Thank you vey much.
You should probably use the base tag available in HTML (put it between the <head></head> tags):
<base href="yoursiteroot" />
In other words, something like this:
<base href="/mywebsite" />
However, this requires that your relative links are adjusted based on the path you specify. :-)

add trailing slash to my urls

I have a serious problem since two days trying to rewrite the urls of my php website with htaccess.
Options +FollowSymlinks
RewriteEngine On
RewriteRule devis demande-devis.php
RewriteRule mentions-legales mentions-legales.php
RewriteRule condition-utilisation condition-utilisation.php
RewriteRule condition-generales-ventes condition-generales-ventes.php
RewriteRule fournisseur fournisseur.php
RewriteRule qui-sommes-nous qui-sommes-nous.php
RewriteRule faq faq.php
RewriteRule services services.php
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !example.php
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=301]
But what I expect for example, is to have http://www.example.com/services/ .
With the code, when I type that URL into the browsers address bar, I have a web page without CSS.
Most likely the problem is relative versus absolute notation of the css file urls.
Consult the http servers error log to see what is actually referenced or check the delivered html source of the page that lacks the style definitions.
The page you specify in your comment to the question shows both, relative and absolute references of css files. However you have no rewriting rules for those...
That works as usual. Just ensure you set the right link to your CSS files so that the browser is able to request them without 404's from your server.
As you have probably edited the URLs within the .htaccess files after you've written the php script, you need to reflect these changes in your PHP script, too, by updting the links in there, too.
Monitor your server error log to find out which URIs are wrongly send.
Review those.
Then improve the output of your application by fixing that erroneous output.
Please see as well:
do-it-yourself universal header/footer.php
and similar questions that are about the root of your problem.

mod_rewrite trouble

So I'm using a simple rewrite rule like:
RewriteEngine On
RewriteRule ^foo/?$ foo.php [NC,L]
It redirects perfectly to foo.php, but it seems like all links and images in foo.php are being taken from folder foo on the server which doesn't exist. For instance, 1.png will now be foo/1.png or index.html will now be foo/index.html. So my question is: is there any way to make thing right without changing paths to the files in foo.php?
Your visitors' browsers see the current page as being at /foo/, thus all relative URLs will be resolved under /foo/. You will need to set the base URL, or update all your relative URLs to point to your site root (e.g. do not use relative/path/url.jpg but /relative/path/url.jpg).
In your code you should provide a rewrite rule for your resources (images, css, etc...) or add conditions for real files / folders like...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
The two RewriteCond lines test to see if the requested URL points to an actual real directory (the !-d part), and the second one tests if it's a real file (!-f)
In the future, you can easily debug your mod_rewrite stuff by adding this two lines to your .htaccess file:
RewriteLogLevel 3
RewriteLog "/path/to/a/file.log"
2 simple ways
absolutize the references as suggest by Ianzz
remove the foo path for referenced object still using htaccess
RewriteRule ^foo(/.*.(jpg|html|gif|css))$ $1 [L]
I prefer the 2nd solution because the htaccess do the mess and htaccess fix the situation, and no changes to your code are needed.

htaccess rewrite ".../pages/about.php" to ".../about"

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.

Categories