Forum Moderators: phranque

Message Too Old, No Replies

HELP with mod rewrite issue

         

chrisguk

1:02 am on Jan 29, 2010 (gmt 0)

10+ Year Member



I currently have a rewrite solution setup on my site but as I am adding more and more pages the directory is becoming a little complicated. My setup is below for illustration:

index.php
PHP Code:

<?php
$page = isset($_GET['p']) ? $_GET['p'] : 'main';

switch($page) {

case 'contact':
$title = 'foo';
$keyword = 'bar';
$description = 'foobar';
$stylesheet = '../style.css'; break;

include($_SERVER['DOCUMENT_ROOT'].'/include/header.php');
include($_SERVER['DOCUMENT_ROOT'].'/host/'.$page.'.php');
include($_SERVER['DOCUMENT_ROOT'].'/include/rightnav.php');
include($_SERVER['DOCUMENT_ROOT'].'/include/footer.php');
?>


.htaccess

Code:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^host/([\w]+) /index.php?p=$1 [L]

So at the moment all my content files are in a directory called "content".

My question is how can I split the files up into different directories using the same or other mod_rewrite technique if you get my meaning.

for example currently its set up as /folder/all my files.php and I want

/folder1/somefiles
/folder/somefiles

Any help would be gratefully received.

jdMorgan

12:37 pm on Jan 31, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I've reviewed this thread several times, and can't make enugh sense of it to provide a useful reply.

I see directory paths called "host" and "content" and "folder1" and "folder", but have no idea how these interrelate. So I'll ask the questions in the way that would have to be answered to write the code:

What various client-requested URLs do you want to use? (i.e. What are your on-page links going to look like?)
What filepaths are to be used to serve content for those various URLs?

Those are two very different questions, and require two different answers (per URL).

Jim

chrisguk

2:29 pm on Jan 31, 2010 (gmt 0)

10+ Year Member



First of all there was a typo in that question of mine which I will try to clarify below:

I have an index.php file at the root folder with the following content:

<?php
$page = isset($_GET['p']) ? $_GET['p'] : 'main';

switch($page) {

case 'contact':
$title = 'foo';
$keyword = 'bar';
$description = 'foobar';
$stylesheet = '../style.css'; break;

include($_SERVER['DOCUMENT_ROOT'].'/include/header.php');
include($_SERVER['DOCUMENT_ROOT'].'/host/'.$page.'.php');
include($_SERVER['DOCUMENT_ROOT'].'/include/rightnav.php');
include($_SERVER['DOCUMENT_ROOT'].'/include/footer.php');
?>

All of the content i.e. my files that are being called by $page are located in a folder called /host/all my files .php

So it is fair to say that present all the files are being called from one folder only. This folder is becoming cluttered because there are so many. All I would love to do is split them up a bit into different folders (declutter).

I pasted my mod_rewrite rule so you could see how the urls are being manipulated. So, the present setup as the visitor to my site would see it is as follows:

http://www.mysite.com/host/contact

I want something like:

http://www.mysite.com/otherfolder/contact

http://www.mysite.com/otherfolder/aboutme

Hope that makes sense

jdMorgan

3:27 pm on Jan 31, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Chris,

Mod_rewrite works based on the URL requested by the client. That URL is defined by the links published on your pages. So the only way for mod_rewrite to 'know' to which directory a request should be resolved is by the requested URL -- either the 'path' of that URL, or the 'file extension' of that URL, or both.

If it helps in understanding, the whole process starts with a click on a link, or with a request invoked by an included-object reference in your HTML page code. The URL for that link or included object is then sent by your browser in an HTTP request to your server. At this point, mod_rewrite is activated, and can modify the default URL-to-filepath translation based on the 'incoming' URL.

In your case, you are rewriting all URL-requests which do not resolve to physically-existing files or directories and which begin with 'host/' followed by one or more letters, numbers, or underscores to a single script called index.php, passing the letters-numbers-underscores part of the requested path below 'host/' to that script as a variable named 'p'. Any characters following this letters-numbers-underscore part of the URL are discarded.

So basically, it appears that your script must now take responsibility for 'sorting out' which directories which 'things' are stored in, because at this point, you've finished the URL-to-filepath translation phase of the Apache API, mod_rewrite is no longer active, and you have entered the content-handling phase. At this point, the request is now a 'file' request, and is no longer a 'URL' request. Therefore, it is too late for mod_rewrite to further affect the server's behavior.

You've got to come up with a plan to partition your files into directories, and only then can you begin to implement it. It would make sense to move all images, css, and client-side JavaScripts into separate subdirectories because these are not to be handled by your script, and then use mod_rewrite to resolve them there, but other that those specific filetypes, all changes will be to your index.php script, and have nothing to do with mod_rewrite.

To sort out the images, css, and js, you'd precede the rule that you already have with:


RewriteCond %{REQUEST_URI} !^host/(images|css|js)/
RewriteCond images%{REQUEST_URI} ^(images)/host/([^/.]+/)*([^.]+\.)+(gif|jpe?g|png|ico)$ [OR]
RewriteCond %{REQUEST_URI} \.(css|js)
RewriteRule ^host/(.+)$ /host/%1/$1 [L]

The first rewritecond prevents recursion using a negative match on the expected outputs from this rule.
The second creates a back-reference (%1) to the 'images' subdirectory if the request is for an image type.
The third creates a back-reference (%1) to either a css or js subdirectory, based on the requested type.
The rule then inserts this back-referenced value into the filepath, and exits.

Your URL to filepath map would then be:

example.com/host/abc.gif -> /host/images/abc.gif
example.com/host/def.jpg -> /host/images/def.jpg
example.com/host/ghi.jpeg -> /host/images/ghi.jpeg
example.com/host/jkl.png -> /host/images/jkl.png
example.com/host/mno.ico -> /host/images/mno.ico
example.com/host/pqr.css -> /host/css/pqr.css
example.com/host/stu.js -> /host/images/stu.js

Note that requests for robots.txt and sitemap.xml, etc. will not be affected by this rule, and must therefore remain is their original directories.

You could of course add more filetype-based subdirectories and modify the code to rewrite to them if desired.

Jim

chrisguk

4:12 pm on Jan 31, 2010 (gmt 0)

10+ Year Member



Hi Jim,

Thanks for the long explanation which is fine. My folder structure already had the relevant areas split for example it looks like this:

/host/ >> All my *.php files i.e main pages
/images/ >> All images
/style/ >> All styles
/js/ >> All JS
/pdf/
/blog/wordpress default
/support/

So the issue is the folder /host/ >> too many *.php main pages which need category.

My proposed structure would be:

/contact/
/foo/ >>> selection of pages related to foo
/bar/ >>> selection of pages related to bar
/baz/ >>> selection of pages related to baz
/host/ >>> selection of pages related to wine host

I suppose I am trying to achieve calling a file from for example foo/ and if someone clicks on a link to select a file from bar/ then it will also be called to the index.php in the root.

Evidently I am a novice at this but I am trying very hard to understand.

I appreciate your input so far and will be grateful for any advice.

Another question, is calling everything to the index.php file a bad way to do it in the first place?

Chris

jdMorgan

4:36 pm on Jan 31, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You do not click on a link to select a file. You click on a link to select a URL.
The server translates URL-requests to file requests, but the filename may have nothing at all in common with the requested URL-path.

If you confuse URLs with files, there is no way to understand mod_rewrite, or to determine what it can and cannot do for you.


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(contact|foo|bar|baz|host)/([\w]+) /index.php?d=$1p=$2 [L]

So the rule now recognizes multiple subdirectory-paths in the requested URL, and extracts them and passes them as the "d=" value to your script. You'll need to modify your script to handle this additional parameter, so that it can locate the proper file to serve.

Jim

chrisguk

4:51 pm on Jan 31, 2010 (gmt 0)

10+ Year Member



Jim,

Many thanks and yes you are right. I dont think I understand mod_rewrite that well yet. Something I will be concentrating on in the very near future. If you have any tips for a learning resource then that will be great.

On the plus note your suggestion works great. Many thanks.

Feel free to add me to msn <snip>

[edited by: jdMorgan at 5:49 pm (utc) on Jan. 31, 2010]
[edit reason] No URLs, e-mails, or sigs, please. See TOS. [/edit]

jdMorgan

5:50 pm on Jan 31, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Check out our Apache Forum Charter for resources, and our Apache Forum Library for threads with examples. Both links are at the top of this page.

Jim