3

Why both rules don't work together and how can i fix it? Only the first one works... I think that there's a conflict between the two rules, but i did not found a solution yet

?p= is the querystring i use to access the files that are into the main directory of my website, and ?page= is for a sub-directory.

My current URLs are:

https://example.com/?p=home
https://example.com/?page=article
https://example.com/?page=article&tab=2

And i want it to become:

https://example.com/home
https://example.com/article
https://example.com/article/2

.htaccess:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ index.php?p=$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ index.php?page=$1 [L]
3
  • (I'm sure I've seen the exact same question somewhere else recently, but I can't seem to find it?!)
    – MrWhite
    Commented Dec 11, 2018 at 16:09
  • Your rewrite rules won't know if a file is in the directory or the subdirectory. It might be simpler to put all your pages into one directory. Otherwise you'll have to make a list of pages in one of the directories in your rewrite rules. Commented Dec 11, 2018 at 16:23
  • @StephenOstermiller Your title edit doesn't seem correct. They appear to be arbitrarily wanting to rewrite some "first path segments" to ?p= and some "first path segments" to ?page=. That's the primary conflict that needs resolving before the additional tab parameter.
    – MrWhite
    Commented Dec 11, 2018 at 16:30

1 Answer 1

4

Yes, you have a conflict.

  • Both your .htaccess rules have exactly the same conditions, so the first one is always going to win. The second is never going to be executed.
  • Your URL structure is ambiguous.

You need to take a step back, before trying to write any code, how would you resolve the following URLs:

  • https://example.com/home
  • https://example.com/article
  • https://example.com/foo

How do you know that home should resolve to ?p=home and article should resolve to ?page=article? What about foo? You can only "see" what's in the URL.

You need to either:

  • Have some discernible difference between the URLs, so you know how to rewrite it. For example: example.com/p/home vs example.com/pg/home
  • If the number of URLs rewritten to ?p= (or ?page=) is limited then you can literally list the URL patterns in your directive. And everything else goes to ?page= (or ?p=). For example:

    RewriteRule ^(home|about)$ index.php?p=$1 [L]
    :
    RewriteRule ^([^/]+)$ index.php?page=$1 [L]
    
  • Rewrite everything to a single URL parameter (eg. ?page=) and decide in your PHP how the page should be served. This would seem to be the more logical solution since you are rewriting to index.php in both scenarios anyway and you don't want to keep having to edit .htaccess. This could also handle the additional tab "parameter".

The additional "tab" parameter

If all URLs that have a second path segment should be rewritten to ?page= then that could be a "discernable" difference. However, that currently fails when the second path segment is omitted, as in /article. How should this be handled?

the files to ?page= are into a sub-directory, and the URL could be this: https://example.com/news-folder/article

Your question made no reference to a subdirectory. This would be enough to differentiate the "type" of URLs and to be able to rewrite the URLs differently.

For example:

RewriteEngine On

# Stop processing if the request looks like it maps to a physical resource
RewriteCond %{REQUEST_URI} \.(?:gif|jpg|png|css|js)$ [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

# Single path segment rewrite to ?p=
RewriteRule ^([^/]+)$ index.php?p=$1 [L]

# Requests for files in the subdirectory rewrite to ?page=
RewriteRule ^news-folder/([^/]+)$ index.php?page=$1 [L]

# Requests for files in the subdirectory with additional numeric "tab"
RewriteRule ^news-folder/([^/]+)/(\d+)$ index.php?page=$1&tab=$2 [L]

The last two rules could be combined if you are OK having an empty tab parameter. eg. example.com/news-folder/article would be rewritten example.com/index.php?page=article&tab=. As it stands, the directives are separate, so the tab parameter is not present at all when /2 (for example) is not appended.

UPDATE: The filesystem checks (for static resources and to prevent a rewrite loop) could be omitted entirely if you are more restrictive with the regex you use to target your article pages. For example:

RewriteEngine On

# Single path segment rewrite to ?p=
RewriteRule ^([^/.]+)$ index.php?p=$1 [L]

# Requests for files in the subdirectory rewrite to ?page=
RewriteRule ^news-folder/([^/.]+)$ index.php?page=$1 [L]

# Requests for files in the subdirectory with additional numeric "tab"
RewriteRule ^news-folder/([^/.]+)/(\d+)$ index.php?page=$1&tab=$2 [L]

This just means that your URLs to your pages cannot contain . (dot). You could be more restrictive and only allow word characters (plus hyphen) and change [^/.]+ to [\w-]+. This then allows article names that only consist of the characters: 0-9, a-z, A-Z, _ and -.

You can make the subdirectory /news-folder entirely generic and match any subdirectory. For example:

RewriteRule ^\w+/(\w+)$ index.php?page=$1 [L]

Now, any request for /<something>/article would be rewritten to index.php?page=article.

11
  • So you meant that it's impossible to use a friendly url to more than 1 querystring? The number of URLs to ?p= is limited, and i can list it on the directive as you said, but to ?page= the URLs is not limited. You asked me how could i have a "discernable" difference between the URLs, the files to ?page= are into a sub-directory, and the URL could be this: https://example.com/news-folder/article. Could it be possible to use a friendly URL to both querystrings? Sadly i don't think i can rewrite everything to a single URL paramenter...
    – mario
    Commented Dec 11, 2018 at 18:14
  • It's impossible if there is nothing to differentiate the URLs. Only the URLs to one would need to be limited, everything else would rewrite to the other parameter (I've updated my example). "the files to ?page= are into a sub-directory" - the example(s) in your question do not show a subdirectory. If that is the case then that completely changes your question. Yes, that is enough to differentiate the URLs.
    – MrWhite
    Commented Dec 11, 2018 at 18:24
  • I did not put anything about the sub-directory on my examples because it was working fine, but only one rewriterule as i said. Could you tell me what i'm doing wrong? pastebin.com/hMaAtV4M This return a Error 500.
    – mario
    Commented Dec 11, 2018 at 18:37
  • 1
    Finally i solved this thanks a lot! No my URLs don't contain the sub-directory, i was able to access them only using the querystring.
    – mario
    Commented Dec 11, 2018 at 18:50
  • 1
    It looks like you are using relative URL-paths to your CSS. See this question: webmasters.stackexchange.com/questions/86450/… "checked the file path and it's correct" - make sure that what the browser sees is correct.
    – MrWhite
    Commented Dec 11, 2018 at 19:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.