Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » .htaccess URL rewrite

Credits go to BAF, CGamesPlay, Matthew Leverton, Thomas Fjellstrom, and X-G for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2   3   4 
.htaccess URL rewrite
Vanneto
Member #8,643
May 2007

Hello everyone!

I have a small issue with URL rewriting in .htaccess. Not that anything is not working, its just the issue with the size of the whole thing.

Here is a sample from my file:

RewriteEngine On

RewriteRule ^/news/([0-9]+)/$ /news.php?news_id=$1
RewriteRule ^/article/([0-9]+)/$ /article.php?art_id=$1
RewriteRule ^/user/([0-9]+)/$ /show_user.php?user_id=$1
RewriteRule ^/login/$ /login.php
...

See? It gets awfully long. What can I do here? Is there anything I can do? I thought of a unified URL structure like NEWS/ACTION/ID so its like news/delete/23 or news/edit/35 but that doesn't work for all of the stuff.

So, is there anything I can do? Or am I cursed to editing the file every time I add or change something?

In capitalist America bank robs you.

X-G
Member #856
December 2000
avatar

RewriteRule ^(.*) index.php?q=$1 [L,QSA]

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Vanneto
Member #8,643
May 2007

OK, this opens up a new problem though, how do I parse the input? Something like this:

index.php?q=/news/edit/45/monkey/5/blah/10

So, the first parameter would always be the file ( news.php ), the second would be the name of a parameter and then the value, the next the name and then the value etc.

So the upper URL would be:

news.php?edit=45&monkey=5&blah=10

Correct?

In capitalist America bank robs you.

CGamesPlay
Member #2,559
July 2002
avatar

I got this from CakePHP:

RewriteEngine on
RewriteRule ^$ engine/index.php [L]
# Translate path into the webroot if not already done
RewriteRule !app/webroot/ - [C]
RewriteRule (.*) app/webroot/$1
# If file doesn't exist in webroot then use Cx
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* engine/index.php

This is cool. It works like this: you have a website at http://www.contoso.com/mysite/. On the server, mysite/app/webroot is the folder where you put things like static HTML pages, CSS files, whatever, and mysite/engine is where CakePHP lives. When a user requests http://www.contoso.com/mysite/style.css, the RewriteRules check mysite/app/webroot/style.css. If it exists, it serves that file. If it doesn't, the rules instead run mysite/engine/index.php, which uses $_SERVER["REQUEST_URI"] to get the name of the requested file (so, if you request http://www.contoso.com/mysite/news/delete/27, it will look like "mysite/app/webroot/news/delete/27", and you can just remove everything up to "app/webroot").

This method is better than X-G's because the query string isn't affected by the rules, and because it allows static documents to co-exist.

[append]

You parse the output by exploding your request (explode("/", $request)), and then parsing the resulting array (array("news", "edit", "45", "monkey", "5", "blah", "10")). If you're using CakePHP or CodeIgniter or something similar, then you have code like this:

class controller_news
{
    function edit($id)
    {
        // news/edit/45 calls this method with $id = 45.
        // You can get all the parameters passed like this:
        $args = func_get_args();
        var_export($args);
        // Prints: array("45", "monkey", "5", "blah", "10")
    }
}

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

BAF
Member #2,981
December 2002
avatar

In one project, I was just passing everything to a file like X-G said, checking a set directory to see if the file existed, if it did I served it up, if not I checked for plugins/pages before 404ing.

Thomas Fjellstrom
Member #476
June 2000
avatar

You should see the stuff I setup for the wiki:

1RewriteEngine on
2 
3RewriteCond %{REQUEST_URI} ^/bin/view/.+
4RewriteRule ^/bin/view/[^/]+/(.*) /$1 [R]
5 
6RewriteCond %{REQUEST_URI} ^/bin/view/.+
7RewriteRule ^/bin/view/[^/]+ / [R]
8 
9RewriteCond %{REQUEST_URI} ^/bin/view$
10RewriteRule ^/bin/view$ / [R]
11 
12RewriteCond %{HTTP_USER_AGENT} Ask\ Jeeves/Teoma [OR]
13RewriteCond %{HTTP_USER_AGENT} VoilaBot [OR]
14RewriteCond %{HTTP_USER_AGENT} BecomeBot [OR]
15RewriteCond %{HTTP_USER_AGENT} Exabot [OR]
16RewriteCond %{HTTP_USER_AGENT} Googlebot [OR]
17RewriteCond %{HTTP_USER_AGENT} Yahoo!\ Slurp [OR]
18RewriteCond %{HTTP_USER_AGENT} Google\ Desktop [OR]
19RewriteCond %{HTTP_USER_AGENT} MQBOT/Nutch [OR]
20RewriteCond %{HTTP_USER_AGENT} msnbot [OR]
21RewriteCond %{HTTP_USER_AGENT} YahooSeeker [OR]
22RewriteCond %{HTTP_USER_AGENT} OutfoxBot [OR]
23RewriteCond %{HTTP_USER_AGENT} FreshCrawler [OR]
24RewriteCond %{HTTP_USER_AGENT} robot [OR]
25RewriteCond %{HTTP_USER_AGENT} spider [OR]
26RewriteCond %{HTTP_USER_AGENT} Twisted\ PageGetter [OR]
27RewriteCond %{HTTP_USER_AGENT} yacybot [OR]
28RewriteCond %{HTTP_USER_AGENT} yacy [OR]
29RewriteCond %{HTTP_USER_AGENT} Yahoo-MMCrawler
30RewriteRule ^(.*) $1?useskin=simple [C,QSA]
31 
32# Verifying if user forgot to put trailling slash. If so, we'll rewrite to Main_Page
33RewriteCond %{REQUEST_URI} ^/?$
34RewriteRule ^/?$ /index.php/Main_Page [L]
35 
36# rewrite Actions
37# 'edit', 'watch', 'unwatch', 'delete','revert', 'rollback', 'protect',
38# 'unprotect','info','markpatrolled','validate','render','deletetrackback','print',
39# 'dublincore','creativecommons','credits','submit','viewsource','history','raw', 'purge'
40RewriteCond %{REQUEST_URI} ^/(purge|edit|watch|unwatch|delete|revert|rollback|protect|unprotect|info|markpatrolled|validate|render|deletetrackback|print|dublincore|creativecommons|credits|submit|viewsource|history|raw|purge)/
41RewriteRule ^/(purge|edit|watch|unwatch|delete|revert|rollback|protect|unprotect|info|markpatrolled|validate|render|deletetrackback|print|dublincore|creativecommons|credits|submit|viewsource|history|raw|purge)/(.+) /index.php/$2?action=$1 [L,QSA]
42 
43# Don't rewrite requests for files in MediaWiki subdirectories,
44# MediaWiki PHP files, HTTP error documents, favicon.ico, or robots.txt
45#RewriteCond %{REQUEST_URI} !^/(stylesheets|pub|config|stats|skins|bin|languages|locale|math|images)/
46#RewriteCond %{REQUEST_URI} !^/.+.php
47RewriteCond %{REQUEST_URI} !^/error/(40(1|3|4)|500).html
48RewriteCond %{REQUEST_URI} !^/favicon.ico
49RewriteCond %{REQUEST_URI} !^/robots.txt
50 
51 
52# Do main rewrite
53RewriteCond /var/www/%{REQUEST_FILENAME} !-f
54RewriteCond /var/www/%{REQUEST_FILENAME} !-d
55RewriteCond %{REQUEST_URI} !^/(stylesheets|pub|config|stats|skins|bin|languages|locale|math|images|history|icons)/
56RewriteCond %{REQUEST_URI} !^/(stylesheets|pub|config|stats|skins|bin|languages|locale|math|images|history|icons)$
57RewriteCond %{REQUEST_URI} !^/.+\.php
58RewriteCond %{REQUEST_URI} !^/~.*
59RewriteRule ^(.*)$ /index.php$1 [L,QSA]

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

X-G
Member #856
December 2000
avatar

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

Was also in the file. I just neglected to mention that. :P

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

#RewriteCond %{REQUEST_URI} !^/.+.php

Technically, "!^.+\.php" :)

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Matthew Leverton
Supreme Loser
January 1999
avatar

Perhaps you'd rather have news/edit/35 be news/35/edit, which is hard to do (along with other similar style of URLs) unless you use a global dispatcher.

I use this for my CMS in the /var/www/cms/site directory:

Quote:

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

The document root directory is: /var/www/cms/site/domainname.com/web. I then use an alias in each vhost to point /.dispatcher.php to /var/www/cms/site/dispatcher.php.

That single file just looks at the domain name, loads the configuration file for it, loops through each module that implements IRequestHandler, and lets them determine who gets to serve the request. (First come, first serve.)

It's beautiful because URLs can be anything and every site can share the same exact PHP module code.

Each module can implement any URL how it sees fit. So the news module could see /news/2008/01/01/newyear and decide to handle the request by loading up the news item and calling $tpl->display('News/view') which would first load up the website's specific news template.

The CMS module can look at URLs in a database and display HTML as entered via a WYSIWYG online editor. And anything in the /var/www/cms/site/domainname.com/template directory automatically gets viewed as a last resort (if the name matches the URL) so you can easily add one-off pages per each site.

Those are just examples of a couple modules; there are plenty of ways to do this. The key thing is, though, that "one PHP file per page" based websites are not good.

Vanneto
Member #8,643
May 2007

I'll think about the modules idea. I think its a pretty good idea. But I only have one site, so isn't it kinda pointless?

Quote:

Those are just examples of a couple modules; there are plenty of ways to do this. The key thing is, though, that "one PHP file per page" based websites are not good.

Hmm... I am getting something wrong here. Don't you do "one file per page" anyway? Isn't the difference in the fact that you hide it?

In capitalist America bank robs you.

Matthew Leverton
Supreme Loser
January 1999
avatar

You're right that it is a lot of overhead if never reused. But one site becomes two sites ... and so on until you are sick of writing the same stuff over and over again.

And no, my approach is far from page based. The entire module sits inside of a class. For instance, a "pretend" module:

1<?php
2 class Module_News extends Module implements IRequestHandler
3 {
4 public function handleGetRequest(HTTPRequest $req)
5 {
6 // /news/view/$id
7 if ($req->path[0] != 'news') return FALSE; // doesn't handle the url
8 
9 switch ($req->path[1])
10 {
11 case 'view':
12 $tpl->news = DBO_News::find($req->path[2]);
13 $tpl->display('news/view');
14 return TRUE;
15 
16 case 'foo': // other logic, etc
17 }
18 
19 return FALSE;
20 }
21 }
22?>

All of the logic goes inside the class. That's the stuff you don't ever want to rewrite. If I have a second website that needs something a little bit different, I first try to add the functionality via configuration. If that fails to be practical, I just extend the class module and use it for that particular website.

The template stuff is per page, but that's fine. The basic news "view" template might look like:

<mef:template container="default">
  <html>
    <h1>{news.title}</h1>
    <div>{news.body}</div>
  </html>
</mef:template>

Then for a particular website, I'll probably end up copy/pasting it into the website's local template directory and editing it to look like however I want.

The key is that I can easily build a new website without having to write a line of duplicated PHP. I expect to write custom template files ... that's what makes web sites unique. But the "business logic"? It's mostly reusable.

This is my approach that works great for me, and you may find something you like better. But never resort to spaghetti PHP code. It's never worth it.

Vanneto
Member #8,643
May 2007

Now I get it. So, this is just theoretical, you have modules in a directory, like modules and when someone requests the page the request is send to index.php or whatever the main file is.

Then the modules directory ( or database, don't really know ) is scanned for modules. And since every module is derived from Module you can just do:

$request = new IRequest();
$request->page = ...;

while(!EndOfModules())
{
    $module = new Module($data["module_name"]);
    $module->handleGet($request);
    
}

Wow, even if this is not exactly what you use, its pretty darn good. This way you can easily add way more modules without any hassle. No hard-coding... Real flexible. Hehe I'm all excited now! ;D

Just one more thing, how do you handle where the stuff gets displayed. The website has a certain structure. Header, footer, navbar etc. How do you know where each module will go? It could have a $type member var in it... Or is there a better way to handle this?

In capitalist America bank robs you.

Matthew Leverton
Supreme Loser
January 1999
avatar

I have an ini file per website (domain) that says which modules to load:

[modules]
News=true
AutoTemplate=true

Those are looped through and added to a modules array within the base Application class.

I have a function called something like Application::callInterface('IRequestHandler', 'handleRequest', $args) and that is responsible for looping through each module, calling 'handleRequest' until one of them returns TRUE. It's been a while since I've looked at my base classes, so I don't remember exactly what I'm doing.

Regarding your second question, I'm not sure exactly what you are talking about. But I use "containers." One might look like:

<html>
<head><title>Default Container</title></head>
<body>
 
{html} 

</body>
</html>

The {html} correlates to the <html> field in the template file. Same goes with any other field you want to pass as a tag or as a parameter (in the <mef:container /> tag).

Also note that templates can also pull in data as long as a recognized object is used.

// loop through recent threads
<mef:loop collection="news.recent(count: 5)" item="n">
  {n.title}
</mef:loop>

For instance, that would call DAO_News::recent() inline. (The DAO class of objects are just read-only interfaces from a template to the more general purpose DBOs.)

That allows templates files to do more than what they might originally have been intended to do by the module writer. (e.g., maybe on your News/View template page you also want to show something from a different module.)

Vanneto
Member #8,643
May 2007

Seems pretty logical. But, there is one line I do not understand as I do not have so much experience in the OOP world:

class Foo extends Bar implements Baz

So, what does this mean? That Bar implements Baz and that Foo extends Bar? That would mean that Baz is an abstract class and that Bar implements it and Foo extends the implemented class Bar?

Regarding the HTML thing, I think there was a misunderstanding. I maybe just talking garbage but anyway. Allegro.cc has two sidebars and the center where the content is. Now, I am speculating, but I reckon that the sidebars are constant ie. are not tied to modules? You know what I mean? Sure, the content is tied to a module, but what about the sidebars etc.? Guess theres not much need for that anyway... Just asking.

In capitalist America bank robs you.

BAF
Member #2,981
December 2002
avatar

Baz is an interface, so class Foo inherits from Bar and implements everything required by the Baz interface.

Vanneto
Member #8,643
May 2007

OK, I thought it was something like that. Thanks for destroying my doubts. :)

In capitalist America bank robs you.

Fladimir da Gorf
Member #1,565
October 2001
avatar

Looking at the PHP code Matthew posted, does PHP really look almost like Java these days?

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

Looking at the PHP code Matthew posted, does PHP really look almost like Java these days?

Yes. A horrible mix of Perl and Java. I still wonder why people like it.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Vanneto
Member #8,643
May 2007

Don't make me laugh! Even PHP at its worst isn't nearly as bad as perl! Yuck! :-X

In capitalist America bank robs you.

BAF
Member #2,981
December 2002
avatar

Good PHP isn't bad. Bad PHP is horrible. cough*zencart*cough.

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

Don't make me laugh! Even PHP at its worst isn't nearly as bad as perl! Yuck! :-X

You obviously haven't seen actual live PHP applications then. Right now I'm doing a small job working with ZenCart, if you feel like going out of your mind, take a look at all the template files. Almost every PHP program I've ever seen is made the same way.

However, my Perl programs are much much cleaner.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Vanneto
Member #8,643
May 2007

Look at it this way, PHP is the most popular scripting language currently. So naturally there will be more people that write ugly code. Its also very simple, contributing to people writing said bad code.

Perl is scary, thats why beginners don't use it*. :P But PHP code can be very clean, readable and efficient if written in the right way. Works for any language.

* At least not as much as PHP IMHO.

In capitalist America bank robs you.

ImLeftFooted
Member #3,935
October 2003
avatar

PHP is pretty fast and has an enormous amount of junk that makes web development easy. That junk is really invaluable.

(more on other bad coders coding in php): You shouldn't judge your language choices by the stupidity of other coders.

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

Look at it this way, PHP is the most popular scripting language currently. So naturally there will be more people that write ugly code

Clueless much? There area actually still more usefull sites that run perl than PHP. Well known fact, php was once implemented with Perl.

Quote:

Perl is scary, thats why beginners don't use it. :P

Its the same syntax as php! Except theres three separate special datatypes and BUILT IN regexes. I don't see much of a difference.

Quote:

But PHP code can be very clean, readable and efficient if written in the right way.

Oh sure, apply that to your precious php, and not perl? :P

Perl was my first programming language. Taught it to myself by reading a book and playing with scripts. If I can do it, anyone can.

Quote:

PHP is pretty fast and has an enormous amount of junk that makes web development easy. That junk is really invaluable.

Junk is indeed the right term. And it dumps it all in the global namespace. hundreds of functions you're likely to not use in most apps!

Quote:

(more on other bad coders coding in php): You shouldn't judge your language choices by the stupidity of other coders.

Except when most of the apps are coded in that way, then its more of a language issue. PHP was created to write spagetty <?php code ?> crap.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

BAF
Member #2,981
December 2002
avatar

If you want to learn how not to write something, look at Zencart.

 1   2   3   4 


Go to: