0

How can all URLs that are plural and followed by /<integer> be redirected to the singular name along with the integer as a parameter. See below for examples. Ideally "users" need not be hardcoded, and "vendors" would redirect to "vendor" the same way. Note that I am not using any server code (i.e. PHP, etc).

users.html (not that this page is plural)

<a href="/users/1">John Doe</a>  <!-- should redirect to user.html?id=1 -->
<a href="/users/2">Jan Doe</a>   <!-- should redirect to user.html?id=2 -->
<a href="/users/3">Baby Doe</a>  <!-- should redirect to user.html?id=3 -->

Current configuration is as follows.

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName admin.facdocs.example.net
        DocumentRoot /var/www/facdocs/frontends/admin/public
        <Directory "/var/www/facdocs/frontends/admin/public">
            #Options Indexes FollowSymLinks MultiViews
            Options Indexes FollowSymLinks
            AllowOverride All
            Order allow,deny
            allow from all
            RewriteEngine On
            LogLevel info rewrite:trace3
            RewriteBase /

            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteRule ^([A-Za-z]+)s/(\d+)/?$ $1.html?id=$2 [L]
            RewriteBase /

            RewriteCond %{REQUEST_URI} !^.*\.html$
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteRule ^(.*)$ %{REQUEST_FILENAME}.html
        </Directory>
        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateFile /etc/letsencrypt/live/api.example.net/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/api.example.net/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/api.example.net/chain.pem
    </VirtualHost>
</IfModule>
user1032531
  • 24,767
  • 68
  • 217
  • 387
  • By _redirect_ do you mean redirect internally without changing the browser's URL from the `/users/3` pattern? Does "plural" always mean "ending in s" or do you have any `/geese/3` with `goose.html`? Or `/switches/4` to `/switch.html` with `es`? This gets very complicated quickly, and that is why frameworks like Ruby on Rails often include a pluralization library – Michael Berkowski Feb 02 '21 at 16:52
  • @MichaelBerkowski Yes, agree it could be complicated but that wasn't my intention. Plural is purely defined by ending with a `s`. And yes, redirect as you stated was my desire. Thanks – user1032531 Feb 02 '21 at 17:18

1 Answers1

2

To handle plurals only as words ending in s and only if a corresponding .html exists, you may match as:

RewriteEngine On
# The actual file does not exist already as a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Alpha excluding final `s` captures in $1
# Numeric value in $2 with optional trailing slash
RewriteRule ^([A-Za-z]+)s/(\d+)/?$ $1.html?id=$2 [L]

A plural word (ending in s) without a corresponding singular .html will resutl in a 404.

Note: The above assumes a <Directory> or .htaccess context. If you put this in a server-level or <Location>, use a leading slash

RewriteRule ^/([A-Za-z]+)s...

And this also assumes case-sensitivity between the input plural and corresponding .html.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
  • Thanks Michael, Always have issues with regex. Any need to make it greedy: `^([A-Za-z]*)s/...`? Tried both in .htaccess as well as in the virtual host file but no luck. No issues if a subdomain such as `foo.bar.mysite.net`, is there? Recommended approach for troubleshooting? I set `LogLevel info rewrite:trace3` and for whatever reason it goes to my error log instead of a rewrite log, but can still see what is happening (or not happening). As far as I can tell, no matches. Thanks – user1032531 Feb 02 '21 at 19:21
  • @user1032531 Are you using it in .htaccess or in a virtualhost? Oh, I did miss a `+` (not `*`) - that is probably it, sorry about that. I don't think recent Apache versions write to a rewrite log anymore, but using rewrite:trace3 should go to the error_log as you have discovered. – Michael Berkowski Feb 02 '21 at 19:24
  • What I had would have probably worked for single letters `ds/1` >> `d.html/1` but needed `+` – Michael Berkowski Feb 02 '21 at 19:25
  • Thanks again Michael. I've tried including both in the virtualhost and in .htaccess but no success for either. Think it has something to do with my main virtualhost setup and I posted it on the original question. While I found much about the specific details, I couldn't find a total example to compare and find my mistake. – user1032531 Feb 03 '21 at 12:38
  • @user1032531 Maybe related to Multiviews. https://stackoverflow.com/questions/25423141/what-exactly-does-the-multiviews-options-in-htaccess Change to `-MultiViews` unless you actually need that for some reason – Michael Berkowski Feb 03 '21 at 16:04
  • Maybe. I changed and the re-writing now works :) Unfortunately, now all the requests to JS and CSS resources don't :( – user1032531 Feb 03 '21 at 19:06
  • @user1032531 MultiViews and ModRewrite are sort of incompatible. What are some example paths for you js and css, where they are in the doc root and what URLs for them look like - please edit your post – Michael Berkowski Feb 03 '21 at 19:28
  • 1
    I wish I could say it was exceptionally complicated. Turned out I just didn't have `/` prefix for the assets. Your approach works perfect. With the removal of MultiViews, my paths without a `html` extension didn't work and I added another rewrite (shown on original post). Appreciate your help! – user1032531 Feb 03 '21 at 20:22