4

I am not a PHP developer at heart and I have been asked to perform some SEO on an existing PHP website.

The first thing I noticed was the ugly URLs so I want to get these to rewrite to something more informative. Here are all the possible patterns:

/index.php?m=ModuleType&categoryID=id
/index.php?m=ModuleType&categoryID=id&productID=id
/index.php?page=PageType
/index.php?page=PageType&detail=yes

So basically what I want to do is convert these into something like:

/ModuleType/Category
/ModuleType/Category/ProductName
/Page
/Page

I haven't used mod_rewrite before any advice or examples would be great!

Thanks.

sepehr
  • 17,110
  • 7
  • 81
  • 119
James
  • 80,725
  • 18
  • 167
  • 237

3 Answers3

1

mod_rewrite would rather be used to do the opposite: rewrite requests of /ModuleType/Category/ProductName internally to /index.php?m=ModuleType&categoryID=id&productID=id. Using the new URLs in the documents is the job of your application.


Edit    Here’s an example of how a function might look like that turns your parameterized URLs into the new ones:

function url($url, $rules) {
    $url = parse_url($url);
    parse_str($url['query'], $url['query']);
    $argNames = array_keys($url['query']);
    foreach ($rules as $rule) {
        if ($rule[0] == $url['path'] && array_keys($rule[1]) == $argNames) {
            $newUrl = $rule[2];
            foreach ($rule[1] as $name => $pattern) {
                if (!preg_match('/'.addcslashes($pattern, '/').'/', $url['query'][$name], $match)) {
                    continue 2;
                }
                $newUrl = str_replace('<'.$name.'>', $match[0], $newUrl);
            }
            return $newUrl;
        }
    }
    return $url;
}

$rules = array(
    array(
        '/index.php',
        array('m'=>'.*', 'categoryID'=>'.*', 'productID'=>'.*'),
        '/<m>/<categoryID>/<productID>'
    )
);
echo '<a href="' . url('/index.php?m=ModuleType&categoryID=categoryID&productID=productID', $rules) . '">/ModuleType/Category/ProductName</a>';
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • Ok how would I do this then? How would I convert the parameterized queries into nicer URL's? – James Oct 03 '09 at 09:40
  • @James: Your web application should do that. Typically you would have a mapping to map from the one form to the other. – Gumbo Oct 03 '09 at 09:44
  • Yeah but I am not quite sure how I do this, could you provide an example? – James Oct 03 '09 at 09:52
  • @James: The *nice to parameterized* or *parameterized to nice* direction? – Gumbo Oct 03 '09 at 10:20
  • @Gumbo, basically the way the website is at the moment is the URLs are displaying as parameterized, so I want them to be displayed nicer. – James Oct 03 '09 at 10:21
  • @James: I would write a function that will to the mapping. Describe the map as an array of rules that are array themselves that contain an array of URL parameters and the resulting nice URL. So something like `array( /* first mapping rule: */ array( /* array of parameters: */ array('m', 'categoryID', 'productID'), /* replacement: */ '///'), /* more rules following … */ )`. Then use the `parse_url` to parse the URL and `parse_str` for the URL parameters, look for a corresponding rule in the ruleset and do the replacement. – Gumbo Oct 03 '09 at 10:33
  • Could you provide a small example please? i.e. update your answer. – James Oct 03 '09 at 10:41
  • Thaks for taking the time to provide that example, appreciate it. – James Oct 03 '09 at 11:34
  • Turns out you were correct in terms of achieving this throughout the links on my site, however, the other answers did contribute as I do need the server to translate these new friendly urls. – James Oct 03 '09 at 17:32
  • Do I need to use mod-rewrite for this? – user3733831 Aug 30 '15 at 13:59
1

I'm not a mod_rewrite expert by any means, but this is an example of how I put together the .htaccess for the Image Flair site:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)/(.*)\.png$ imageFlair.php?mode=$1&userid=$2 [L]
RewriteRule ^(.*)\.png$ imageFlair.php?userid=$1 [L]
</IfModule>

This basically maps:

MODE/USERID.png -> imageFlair.php?mode=MODE&userid=USERID

and

USERID.png -> imageFlair.php?userid=USERID

You should be able to adapt that to your needs, but you may have a couple of issues:

  1. If you want to use "names" rather than IDs on your URL you will need to alter the PHP to accept the names.
  2. You might have an issue with /Page and /ModuleType conflicting, if you wanted to also include more parameters in with Page, unless you can put together a regex that can determine which is which.

Going on the list of URLs you want, this should work, although I won't claim it's the best or only way to do it :-)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)/(.*)/(.*)$ index.php?m=$1&categoryID=$2&productID=$3 [L]
RewriteRule ^(.*)/(.*)$ index.php?m=$1&categoryID=$2 [L]
RewriteRule ^(.*)$ index.php?Page=$1 [L]
</IfModule>

As suggested, you may want to replace the .* with [^/]+ but I had issues with non-matches when I did that, and had no time to troubleshoot, so YMMV :-)

Steven Robbins
  • 26,441
  • 7
  • 76
  • 90
  • Please replace `.*` by `[^/]+` and mark the end of the URL path with `$`. – Gumbo Oct 03 '09 at 09:48
  • Hi steve, thanks for the examples! Always find it easier to learn...what is the L parameter at the end of the rewrite rules for? – James Oct 03 '09 at 09:51
  • It just tells Apache to stop processing for that request once it's matched the rule. – Steven Robbins Oct 03 '09 at 09:55
  • I put that rule in but then all my javascripts where giving errors! Taking it back out they run fine. – James Oct 03 '09 at 10:00
  • @Gumbo I had issues with [^/]+ on my box when I was testing, hence the .* - you're probably right on the lack of $ though, my mistake. – Steven Robbins Oct 03 '09 at 10:00
  • Your javascript may be relying on the parameters being on the url string then, it's not always a simple thing to retrofit. – Steven Robbins Oct 03 '09 at 10:01
  • Ah ok, sorry as I said this isn't my website still trying to figure out how it has been put together! – James Oct 03 '09 at 10:05
  • 1
    Using `[^/]` instead of `.` is just more explicit and efficient since it avoids backtracking. – Gumbo Oct 03 '09 at 10:08
  • Yeah, I know what it does, but it matched nothing when I tried it so I took the quick, dirty and working approach :-) – Steven Robbins Oct 03 '09 at 10:09
1

It's not quite clear from your post what the variables are. But assuming that ModuleType, id (x2) and Page are all variables then the following rules with backreferences should work within a .htaccess file.

RewriteEngine On
RewriteRule ^([^/]+)/([^/]+)$ /index.php?m=$1&categoryID=$2 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)$ /index.php?m=$1&categoryID=$2&productID=$3 [L]
RewriteRule ^([^/]+)$ /index.php?page=PageType [L]
RewriteRule ^([^/]+)/detail$ /index.php?page=PageType&detail=yes [L]

The last one didn't really make sense as you've written it. So instead you can add /detail on the end.

These should slip straight over the top of your existing applications without any modifications to the app. Because they aren't redirecting with [R] it will be transparent to your users.

Dan Carley
  • 446
  • 2
  • 5
  • Hi Dan, apologies on the last one, I never thought of having to differentiate the 2! That would be an ideal solution for it tho. I will give them a try. – James Oct 03 '09 at 10:03
  • Hi I entered your rules into the .htaccess file but they don't seem to be doing anything? Do I need to restart anything? Sorry I am a bit of a novice when it comes to PHP. – James Oct 03 '09 at 10:07
  • I've updated it so that it should be suitable to paste straight into an `.htaccess` file. – Dan Carley Oct 03 '09 at 10:18
  • I think you where missing a backslash at the start of each rule, I included this in and the error stopped occurring. However, the rules don't seem to be taking effect. – James Oct 03 '09 at 10:29