Forum Moderators: phranque

Message Too Old, No Replies

MOD REWRITE question

         

nevski

10:39 am on Mar 5, 2016 (gmt 0)

10+ Year Member



Hi guys,first of all I want to thank you because this forum helped me to learn how mod_rewrite works and to understand the logic.

I'm developing MVC website php app.Nothing special just I want to learn the logic and system...

So my question is:

If I want to adapt my former website which has some static urls for example example.com/this-is-old-url-or-something-like-that to MVC approach,how to do it in proper manner:

My existing .htaccess files are looking like this

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !public/
RewriteRule ^(.*)$ public/$1 [L]


That's first which is placed in root folder and it sends the traffic to public folder

Second.
Sends all requests as query string url,which is then parsed in router to get controller,method and params.

RewriteEngine on
RewriteBase /public/
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^this-is-old-url-or-something-like-that$ testing [L]
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]


Is this a proper way?If i would add some query string for example example.com/this-is-old-url-or-something-like-that/?page=2 the rule wouldn't work,

P.S.If there are mistakes(or it could be done better) in code that I've posted besides this question be free to correct it.

Tnx in advance guys!

whitespace

3:54 pm on Mar 5, 2016 (gmt 0)

10+ Year Member Top Contributors Of The Month



I don't think this really has anything specifically to do with MVC. What you are implementing is a front controller that helps you to route the request. Whether your backend uses an MVC or XYZ pattern, it doesn't really matter.

Passing the requested URL through as a URL parameter is OK in my opinion. However, one caveat with this is that you cannot (must not) use the same parameter name for anything else. This might seem obvious, but if a "url" parameter did somehow appear in the request (eg. /foo/bar?url=baz) then suddenly your routing would break (eg. index.php?url=foo/bar&url=baz). For this reason I would a use a URL parameter name that is a bit more unique.

Alternatively, don't use a parameter name at all. Simply rewrite the request to "index.php" and grab the requested URL from PHP's superglobal $_SERVER['REQUEST_URI']. This is what WordPress does (which isn't MVC btw).

Rather than explicitly checking for the existence of the requested file and only rewriting the request to "index.php" if it doesn't exist, Apache has a single directive that does this:


# All requests for non-existent files should be rewritten to /public/index.php
FallbackResource /public/index.php


Bit of an aside: Why do you have a subdirectory called "public" within your public webspace? Are you unable to access files above the document root?

Is this a proper way?


Well, the "RewriteRule ^this-is-old..." directive smack bang in the middle of your directives is a bit of a clanger! That's going to break your "front controller". RewriteCond directives only apply to the single RewriteRule directive that follows. So, in the code above, your final RewriteRule (that rewrites all requests to index.php) is going to end up run unconditionally, so all your static resources (JS, CSS, images, etc.) are also going to be routed through your framework which is probably not the intention.

What is the intention with requests for "/this-is-old-url-or-something-like-that"? Are you wanting to redirect to a new URL? In which case it should come before your "front controller".

nevski

6:17 pm on Mar 5, 2016 (gmt 0)

10+ Year Member



Thanx for reply and thourough explenation!I really appreciate it!

Well my main goal is to implement MVC on my till now basiclly 5 static pages website to a blog with some static pages.
Basiclly I can do like this to make huge file name for controller test-is-old...blabla and it would not have problems.Just I want to make things more simple like to make controller file product.php rather then product-foo-bar-foo-foo.php.

My idea was to like make rewrite rule that is basiclly keep the old url and in back to short variant that will look more friendly.

To be honest goal is preserving old link structure,because I don't want a new search engine indexing.

Better to ask for an advice from experts,then do something wrong on my own.

lucy24

6:21 pm on Mar 5, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



That's first

By "first", I hope you mean "second to last". That is: the rule you quote goes immediately before the meat-and-potatoes !d and !f rewrite, but it has to go after any RewriteRules involving access control and/or external redirects (basically, any flags other than [L]).

whitespace, didn't you establish just a few days ago that if you declare more than one RewriteBase, only the last is used? Or do they keep changing dynamically?

In any case: if you make a habit of starting all RewriteRule targets with / (for root) you don't ever need to think about the RewriteBase.

:: echoing question about seeming redundancy of /public/ ::

whitespace

7:18 pm on Mar 5, 2016 (gmt 0)

10+ Year Member Top Contributors Of The Month



whitespace, didn't you establish just a few days ago that if you declare more than one RewriteBase, only the last is used?


Yes, that's right.

Sorry, I'd kinda skipped over the first rule block thinking it was being replaced by the second, but I realise now that may not be the intention.

That's first which is placed in root folder and it sends the traffic to public folder


Was the intention to add the second block to the .htaccess file in the root folder, or have a second .htaccess file in the public folder? If the later, then the second .htaccess file would override the first (at least with respect to the mod_rewrite directives).

That "public" folder would seem to add unnecessary complexity.

nevski

11:28 am on Mar 6, 2016 (gmt 0)

10+ Year Member



Yes,I have second .htaccess in public folder.That's because of folder structure of mvc

--public
-------htaccess
-------index.php
-- app
------- controllers
------- core
------- etc
root folder with just .htaccess file which transfers the request to public folder

RewriteCond %{REQUEST_URI} !public/
RewriteRule ^(.*)$ public/$1 [L]


Without RewriteCond it makes infinite loop and 500 errors.

To be honest main goal is to avoid example.com/public/foo/bar/example,and just to give:
example.com/foo/bar/example

then request is sent to public and then it is handled by

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

Then router gets url,I parse it with explode,and then I get url array which is then processed.

Some frameworks separate app to public folder and app(or some other name) folder.Like Laravel,and I did my reaserch on internet and that is pointed as way to pointing to other folder as root.

I must admit that I'm not some kind of expert in mod_rewrite.

If it would stayed like example.com/public/my-article-my-artcile the former url example.com/my-article-my-article will be lost.

lucy24

7:16 pm on Mar 6, 2016 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



It's fine to have multiple htaccess files, where things inherit downward. For example, I've got one in my userspace* that's mainly concerned with access control and some basic headers, and then each site has its individual htaccess with site-specific directives. But you should try very, very hard to avoid using mod_rewrite in more than one htaccess along the same path because it doesn't inherit normally. (That is, ahem: normally it doesn't inherit, and even when you tell it to inherit, its inheritance doesn't follow the pattern of other mods.)

main goal is to avoid example.com/public/foo/bar/example,and just to give:
example.com/foo/bar/example

But then, don't your rules say the opposite? Seems like it should be
RewriteCond %{THE_REQUEST} /public
RewriteRule ^public/(.*) http://www.example.com/$1 [R=301,L]
and then if you're actually serving content from /public/ then you make a rewrite [L] later on to take care of that.

Do you even need the "url=$1" business? This is a rewrite, so your php should be able to fish out the REQUEST_URI without being told all over again. Got a vague notion whitespace only just got through explaining this, but can't see if it was this thread or some other one-- or possibly even some older thread that I happened to be reading yesterday.

[QSA,L]
What's the QSA for? Do your visible URLs also contain query strings? If they don't, there is no need for QSA since you'll never be appending anything.

Without RewriteCond it makes infinite loop and 500 errors.
He didn't mean that you should omit the RewriteCond; it's absolutely essential with this rule. He only meant that a RewriteCond applies only to the immediately following RewriteRule. If you need the same condition to apply to multiple rules, you have to say it all over again each time.


* Explanation for those with a "primary/addon" structure: The "userspace" functions much like the "primary", in that all requests pass through it. But there's no "primary" domain; everything is an "addon".

nevski

11:18 am on Mar 7, 2016 (gmt 0)

10+ Year Member



Thx for the answers,

I've put QSA because I expect to have pagination or maybe some other query.

So the link could be:
http://example.com/?page=2

etc... or ?per-page = 10

I've tested without and it treats that kind of code as ?url=$1 from the rule.
Ofcourse second option could be to make it as http://example.com/page/1
But I think it is easier like this.

I've tested this rule.

RewriteRule ^public/(.*) http://localhost/production/kupbytes/ [R=301,L]


It redirects the requests to root folder.
My goal is to reroot my root folder,because of site structure.

That's .htaccess file in root folder
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !public/
RewriteRule ^(.*)$ public/$1 [L]


My website root folder is public,there I want my visitors to land,but still I want the appearance like the root folder is the default root.

So when visitor lands I want all the requests to be sent in public folder and then later on to be processed.

Of course the structure of website could be classic without public folder but I've read that it's better to separate public(the things that are visable to visittors) and application itself.

I must admit that I'm confused with that kind of approach,and also I don't like public to be visable in url:example.com/public/article/test-article.Just example.com/article/test-article.

Or in my case the links from my old static website would look like example.com/link-from-my-static-website

link-from-my-static-website would be treated as controller part in /$1/$2/$3/ structure and then I must name my controller class something like Link-from-my-static-website.php.So I thought it's better to do something in mod_rewrite lke shortening to a /example or so...and then the controller name would be Example.php.