Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Friendly URLs and htaccess levels

I have this .htaccess

RewriteEngine On
RewriteRule ^custom index.php?page=value [NC,L]

It works if index.php and .htaccess are located in the same folder.

I'd like to place the .htaccess file in the root and make the content placed in a newFolder react to the htaccess rules. Say:

.htaccess -> root level
index.php -> root/newFolder level

I did try:

RewriteEngine On
RewriteRule ^custom newFolder/index.php?page=value [NC,L]

No reaction at all (404) :(

I guess the solution must by simple, but...

Any help will be appreciated.

like image 892
Sergio Avatar asked Dec 31 '14 16:12

Sergio


2 Answers

Let's make sure we're on the same page. ;) In my server root directory I have a .htaccess file and in that file I have:

RewriteEngine On
RewriteRule ^(.+/)?custom $1index.php?page=value [NC,L]

The RewriteRule has three components: a match pattern, a target, and a list of flags. The match pattern can contain plain text or a regular expression. The target can contain plain text or text with intermingled variables captured in the regular expression match pattern. Both match pattern and target are relative to the directory the .htaccess file is located in.

The match pattern is compared to the text in the URL that is after the current directory. If there's a successful match then the target is called from the directory the .htaccess file is in. If information is captured in the match pattern then the variables in the target are first interpolated in the target.

In this example the .htaccess file is in the server root therefore the match pattern is compared to the URL text after: http://localhost/

To test it out, here's the PHP code I put in an index.php file:

<?php

echo 'page value: ' .$_GET['page'] . '<br>';
echo 'script loaded: ' . $_SERVER['PHP_SELF'];

?>

When I navigate to http://localhost/custom in my browser: the regular expression match pattern is compared to the string "custom", there's a successful match so the target index.php?page=value is executed, and I get the index.php page in the root directory loaded. The displayed page looks like this:

page value: value
script loaded: /index.php

Next I create a new directory called "newFolder" in the server root and copy the index.php file to the newly created directory.

When I navigate to http://localhost/newFolder/custom in my browser: the regular expression match pattern is compared to the string "newFolder/custom", again there's a successful match, this time the target newFolder/index.php?page=value is executed, and I get the index.php page in the newFolder directory loaded. The displayed page now looks like this:

page value: value
script loaded: /newFolder/index.php

So, likewise, I can create any number of directories in the root directory and new index.php files in those directories, and when navigating to "custom" in those directories, this .htaccess file ought to load the corresponding index.php file in the current subdirectory.

~~~

I'm going to go out on a limb here and assume you want to load pages dynamically, therefore capture "custom" as a dynamic page name and dump it in the page field (replace "value") and send that to the index.php file in the current subdirectory.

RewriteEngine On

RewriteCond %{REQUEST_URI} !index\.php
RewriteRule ^(.+/)?(.+)$ $1index.php?page=$2 [NC,L]

As mentioned, the parentheses capture dynamic text and dump it in the target string where the dollar sign numbers are. So the text captured in the first set of parentheses replaces the "$1" and the text captured in the second set replaces "$2". I also added the RewriteCond statement to prevent this rule from double-dipping. :) If I don't this rule gets executed for both the "custom" call AND the redirection to index.php.

So now when I navigate to http://localhost/newFolder/whoopdeedoo, the regex match pattern is compared to "newFolder/whoopdeedoo", there's a successful match, the target newFolder/index.php?page=whoopdeedoo is executed, and I get:

page value: whoopdeedoo
script loaded: /newFolder/index.php

~~~

At the risk of droning on, here's some background info. You mentioned this works in the root directory:

RewriteEngine On
RewriteRule ^custom index.php?page=value [NC,L]

But it does not work when navigating your browser to subdirectories. After reading the comments, it appears you discovered this next bit works for subdirectories, specifically "newFolder":

RewriteEngine On
RewriteRule ^newFolder/custom newFolder/index.php?page=value [NC,L]

But now it no longer works for the root directory. So you could simply include both:

RewriteEngine On
RewriteRule ^custom index.php?page=value [NC,L]
RewriteRule ^newFolder/custom newFolder/index.php?page=value [NC,L]

However there's a couple things here that jump out at me. One is that rather than hardcoding directory names in my root .htaccess I'd rather put .htaccess files in each subdirectory and take over the URL processing there.

But if for whatever reason you prefer to maintain one .htaccess file in the root directory, then, what jumps out at me is the duplication in the rules. So, alternatively, you can use regular expressions to make the subdirectory name a captured variable, like shown at the top of this answer:

RewriteEngine On
RewriteRule ^(.+/)?custom $1index.php?page=value [NC,L]

The regex capturing parentheses replace the text "newFolder/", and inside the parentheses we're saying, "capture one or more characters followed by a forward slash". Then, if there's a successful match, the value captured replaces the "$1" in the target. The reason this also works in the root is because the question mark following the parentheses makes the regex inside the parens optional. So if there's nothing before "custom" we're still good for a match. In that case the "$1" gets replaced with an empty string.

like image 102
bloodyKnuckles Avatar answered Sep 20 '22 02:09

bloodyKnuckles


Try with this rewriterule:

# Activate RewriteEngine
RewriteEngine on
 
# Rewrite the URL requested by the user
#   Entry:  folder/clients/name/
#   Output: folder/clients.php?id=name
RewriteRule ^folder/clients/(\w+)/?$ /folder/clients.php?id=$1

Explanation of this rewriterule:

First part of the rewriterule:

  1. ^ Top expression
  2. folder/clients/ The requested URL string begins with folder/clients/
  3. (\w+) Capture any letters that follow and stores it in $1
  4. /? Optional backslash at the end of the URL
  5. $ End of the expression

Second part of the rewriterule:

  1. clients.php?id= Text string
  2. $1 The first capture we saw in the first part
like image 20
tomloprod Avatar answered Sep 23 '22 02:09

tomloprod