2

I realize this question has been beaten to death by a lot of people asking it, but most of the answers appear to be for a very specific case that only suits their needs, and so far I have not found a suitable solution (at least, as far as i can see).

My problem is that I am trying to make my website redirect URL parameters from an ID to an actual string.

For example:

www.example.com/?category=1

would display as:

www.example.com/software

while

www.example.com/?category=2

would be displayed as:

www.example.com/software/desktop

From what I've read up, I'm supposed to be looking into an apache rewritemap, and this is where my confusion comes in. I'd really rather not have to load from a flat txt file, as I'd like to make this as dynamic as possible, and I have read that I can make it read from a php file and read it from a MySQL database, which is what I'd like.

The problem with that is that I'm really not too sure what the proper way is of achieving this. The RewriteMap document only somewhat covers flat .txt files, and not achieving it with MySQL.

So basically what I'm asking is if someone can explain how to achieve what I'm looking for, or at least point me in the right direction. Most of the threads I've found so far have sadly not been too helpful as of yet, but it's possible I might have passed by useful ones.

If it helps, right now, my MySQL data is formatted in an inherited structure like so:

 ID |   Title          |   Link             | Parent
  1 | Software         | /Software/         |  NULL
  2 | Desktop Software | /Software/Desktop/ |   1
  2 | Mobile Software  | /Software/Mobile/  |   2

PS: I should add that most solutions I've found give this as the example:

  RewriteMap examplemap prg:/path/to/file.php
  RewriteRule (.*) ${examplemap:$1}

Yet it never gives information as to what is in that file.php, and how it queries and returns the value.

EDIT I should mention that I am on a shared hosting server, not my own private one, and so I may not have access to all possible options

EDIT 2 Just for the sake of clarity: What I'm trying to do is make it so that a user who accesses 'example.com/software' would be treated as though they are on 'example.com/?category=1'; basically prettying the link and making it more readable. The only thing is, I'm trying to read it from a database

Human-Compiler
  • 11,022
  • 1
  • 32
  • 59

2 Answers2

1

If you don't have access to the server or vhost config, you can't use RewriteMap anyways. The map itself needs to be defined in either the server or vhost config, not in an htaccess file. But apache 2.4 has an option of using mod_dbd to use an SQL query to define a rewrite map.

If you need to access MySQL, you're probably better off doing all of this in PHP instead of using mod_rewrite. You'd use mod_rewrite to route to your php file, which would then redirect. Maybe something like this?

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /file.php?link=$1 [L]

So when someone requests http://example.com/Software/Mobile/, the request gets rewritten to: /file.php?link=Software/Mobile/, and your file.php script would do the lookup.

Or if you actually mean the other way around:

RewriteCond %{QUERY_STRING} category=([0-9]+)
RewriteRule ^$ /file.php?ID=%1 [L]

So when someone requests http://example.com/?category=2, the request gets rewritten to: /file.php?ID=2 and the php script does the lookup.

Jon Lin
  • 142,182
  • 29
  • 220
  • 220
  • Thanks for the response! I'll clarify what I'm looking for a little better; I want it so that someone accessing example.com/software would be internally parsed as example.com/?category=1; basically 'prettying' the links. With what you posted, would it be used like: RewriteCond %{"SELECT link FROM category WHERE id = %s"} ? Or am I understanding it weird? EDIT: Also, how would file.php do the lookup? Does it have to return a value? – Human-Compiler Apr 02 '13 at 15:41
  • Disregard my above post, I understand what you're saying now (I think I just derped at the time). Perfect! Thanks man – Human-Compiler Apr 02 '13 at 16:39
  • is there any way to assure that, when the link is being passed as a parameter, that there is a trailing slash? Because 'software/desktop' is not equivalent to 'software/desktop/' in a query. Would that just be with a PHP script after the $__GET['link']? Or is there an apache-way to do it? – Human-Compiler Apr 02 '13 at 16:48
  • @Bitwize you mean like this? `RewriteRule ^(.*/)$ /file.php?link=$1 [L]` (forces a trailing slash and that it gets passed as the "link" parameter), or `RewriteRule ^(.*)/$ /file.php?link=$1 [L]` (forces a trailing slash but it is not included in the "link" parameter) – Jon Lin Apr 02 '13 at 17:24
  • The first one is what I was trying to accomplish, where it automatically adds a trailing slash if there isn't one there and sends it as the parameter (so someone accessing 'example.com/software' is going to get the same as 'example.com/software/'); the rewriterules you just mentioned only make it so that it doesn't pass the parameter unless it has the final slash. Should this just be done with PHP instead? – Human-Compiler Apr 02 '13 at 17:30
  • @Bitwize If there *isn't* a trailing slash, that won't match, it would have to be `RewriteRule ^(.*[^/])$ /file.php?link=$1/ [L]` – Jon Lin Apr 02 '13 at 17:37
  • Hm, none of the rewrite rules are *quite* doing what I'm looking for. No matter though; I just decided to set it in the php file that it appends a slash if there is not one at the end, and it works fine. Thanks a lot for all the help! :D – Human-Compiler Apr 02 '13 at 19:09
0

My suggestion would be to look at utilizing a front controller pattern. I think that once you start getting into user friendly URL's or the concept of "routes", that the front controller can really simply things since you no longer have to worry about mapping specific URL's to specific controllers at the web server level.

If you have Apache mod_dir enabled (chances are you do), you could do something like this in your Apache config or .htaccess:

FallbackResource /index.php

This simple directive will direct any requests that would otherwise cause a 404 error to be directed to a front controller at /index.php.

This can also be done via mod_rewrite like this:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [L,QSA]

In the front controller, you could evaluate the URI and route the request to whatever logic need to handle the request. You could do this via lookup of routes from a database or a hard-coded array of routes or whatever. (I would suggest however that, if using a database, you have a cached version of the routes available for quick access).

There are a number of different PHP route controllers available such that you don't need to reinvent the wheel (most every modern framework has some sort of routing concept).

Mike Brant
  • 70,514
  • 10
  • 99
  • 103
  • I'm not sure if that's the method I'd like to go. I just did a bit of reading on it, and it looks to be mainly a fallback if a rewrite rule has not been matched. The above database I gave was only a small portion of all the parts of the site, I simplified it for ease of explanation. That's why I'm rewriting the URL parameters. Thank you for your answer though! (If I'm wrong about my understanding of it, feel free to correct me) – Human-Compiler Apr 02 '13 at 16:14
  • @Bitwize You can utilize mod_rewrite to institute a front controller as well (in fact that is away you commonly see it done). I have updated the answer to show this approach. I tend to like to use FallbackResource to route to the front controller but use rewrite rules to actually rewrite/redirect URL's that need to me changed for whatever reason. If you have a number of routes that you might possibly be writing specific rewrite rules for, this is probably even more reason to move to a front controller, as it is more maintainable to only deal with routing logic at the application level. – Mike Brant Apr 02 '13 at 16:21