13

I've moved many url in my site from: /folder/page.php to: /folder/page/.

Now I want to redirect old url to new url, so I added in my .htaccess this rule:

RedirectMatch permanent /folder/(.*)\.php https://www.site.it/folder/$1/

But it doesn't work, this rule first redirect to /folder/page/ and then redirect again to /folder/page/index/

So I tried this:

RedirectMatch permanent /folder/(?!index)\.php https://www.site.it/folder/$1/

But it works like the above rule.

I tested also:

RedirectMatch permanent /folder/(?!index)(.*)\.php https://www.site.it/folder/$1/

same again.

I use .htaccess only in the root folder, here is the content before the new rule:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

These rules are required to redirect http traffic to https and are suggested by the web hosting service I use.

I also tested wrong RedirectMatch rule without any other.

How can I redirect all page except index.php?

Here is the list of url and the desired behavior:

/folder/                      not match     no action
/folder/index.php             not match     no action
/folder/subfolder/            not match     no action
/folder/subfolder/index.php   not match     no action
/folder/anindex.php           match         redirect to /folder/anindex/
/folder/indexfile.php         match         redirect to /folder/indexfile/
/folder/anindexfile.php       match         redirect to /folder/anindexfile/
/folder/anotherfile.php       match         redirect to /folder/anotherfile/

Please do not suggest to use mod_rewrite because it is not the best practice as described here.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Lety
  • 2,511
  • 21
  • 25

2 Answers2

9

You may add a new rule below your existing rule:

RewriteCond %{THE_REQUEST} \s(/folder/[\w-]+)\.php[?\s] [NC]
RewriteRule ^ %1/ [L,R=301]

THE_REQUEST matches only original URI sent by client, it won't match modified REQUEST_URI.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • thanks, this, works! I've added / to prevent double redirection: RewriteRule ^ %1/ [L,R=301]. So did you think I can use your regex in RedirectMatch directive? – Lety Nov 01 '20 at 14:04
  • Now I'm curious to know why RedirectMatch doesn't work. If none posts an answer, I'll accept your. Thanks. – Lety Nov 01 '20 at 14:26
  • It is already written in answer actually. `RedirectMatch` only operates on `REQUEST_URI` which may change due to application of other directives. `THE_REQUEST` remains unchanged on the other hand. – anubhava Nov 01 '20 at 14:46
  • this answer does not answer my question, I consider it a workaround, but I'll accept it if none answer. There must be a regular expression that matches any word except index and this is what I would like to know or if the regex used is correct I would like to know why it doesn't work. I see 2 302 responses returned by the server that applied the rule twice and in fact the result of the first is /page/ and the second generate /page/index/. When request arrives with /page/ it is probably converted in /page/index.php before it apply RedirecyMatch and unfortunally the wrong regex match (I suppose) – Lety Nov 01 '20 at 15:32
  • 1
    `RedirectMatch` directive is from `mod_alias` module and your existing `RewriteRule` is from `mod_rewrite` module. Both modules run at different times and it is never a good idea to mix them up. – anubhava Nov 01 '20 at 16:10
  • Have answered dozens of answers on similar topic, can't recall where I read it first :) Will post a link if I find some supporting documentation – anubhava Nov 01 '20 at 16:22
  • Please read headline **Order of Execution** in this doc: http://web.archive.org/web/20131107001958/http://my.opera.com/GreyWyvern/blog/2007/09/12/apache-mod-rewrite – anubhava Nov 01 '20 at 16:39
  • tanks, very good, but it doesn't say that is bad idea to mix them, but that we should know what we are doing. In my case rewrite rule does not affect Redirect rule because simple change protocol. Now I found a solution, can I add the alternative solution to your answer? so we have a complete answer? – Lety Nov 01 '20 at 17:35
  • 1
    Update to `REQUEST_URI` doesn't just happen in `mod_rewrite` rules. It can happen with any other directive like `DirectoryIndex` which is what is causing this issue for you. But feel free to add an answer if it is totally different from what has been posted/discussed here. – anubhava Nov 01 '20 at 17:40
3

I found this question: Match everything except for specified strings that help me to fix regex.

RedirectMatch permanent /folder/(?!.*(index))(.*)\.php https://www.site.it/folder/$2/

This rule match everything except index so redirect /folder/page.php only once to /folder/page/ but unfortunately, as @anubhava pointed out, this rule doesn't match any page name that contains index.

After further dig, I found this solution:

RedirectMatch permanent /folder/(?!index.php$|$)(([\w-]+)\.php$) https://www.site.it/folder/$2/

Anyway thanks to @anubhava that support me.

Lety
  • 2,511
  • 21
  • 25
  • You can discuss regex with me at length :) This is not really correct because it will skip redirect for a file `/folder/anindexedfile.php` – anubhava Nov 02 '20 at 03:48
  • I tested /folder/anindexfile.php, anindex.php, indexfile.php and index.php and it doesn't redirect as you point out, so how can I improve this regex? thank you very much – Lety Nov 02 '20 at 08:26
  • It should be: `^/folder/(?!index\.php$)\.)[\w-]+\.php$` – anubhava Nov 02 '20 at 08:28
  • tested `(?!(index\.php)$\.)([\w-]+)\.php$` and it works in all case except in case of /folder/ and folder/index.php in this case it redirect to /folder/index/ how can I avoid this? I added parenthesis to get $2 token. Tested OK cases are: /folder/subfolder/ - no action, folder/subfolder/index.php no action, folder/file.php redirect to folder/file/, folder/indexfile.php redirect to folder/indexfile/, folder/anindex.php redirect to folder/anindex/, folder/anindexfile.php redirect to folder/anindexfile/ – Lety Nov 02 '20 at 09:18
  • there is a missing parenthesis, I tested (?!(index(\.php)?$)\.)([\w-]+)\.php$ but in case of /folder/ it cause a redirect loop to /folder// – Lety Nov 02 '20 at 10:52
  • 2
    That's why I wrote earlier these hackish solution won't work for all the cases. Only guaranteed solution is based on `THE_REQUEST` matching I have posted. I suspect you may have a `page/` directory inside `folder/` directory – anubhava Nov 02 '20 at 11:09