I have the following rewrite rule in my nginx:
rewrite ^/(.*)/$ /$1 permanent;
to remove trailing slash at the end of any URL. However I wanted to make an exception such that when the URL is /register/ I don't want this rule to be applied. How do I put that into the regex?
You can use a Negative Lookahead.
^/(?!register)(.*)/$
If you don't want register anywhere between such as /exampleregister/, use the following.
^/(?!.*register)(.*)/$
Related
I am redirecting certain urls with path to get variables like the following:
localhost2/post/myTitle => localhost2/post.php?title=myTitle
localhost2/post/123 => localhost2/post.php?id=123
So In my htaccess file, I use
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^post/(\d+) post.php?id=$1
RewriteRule ^post/(.*) post.php?title=$1
</IfModule>
This works no problem. But I want to learn how to write negative of ^post/(\d+), that is ^post/(NEGATE-ONLY-NUMBERS). In other words I want a regex that matches the whole input sting if there is not only numbers after post/. So post/abc, post/a23, post/ab3, post/12c and post/a2c should all pass but not post/123. I refered to this post, which suggest using:
(?!^\d+$)^.+$
I can't use ^post/(?!^\d+$)^.+$, because there can be only one ^ and one $. I don't know what regex anchor specifies first position in a substring. My best guess is
post\/(?!\d++).*
I think (?!\d++), with the ++ would eat all characters followig and check if all are digits. But this fails at post/1ab.
Another guess is:
post\/(?![\d,\/]+$).*
The works the best but it allows: post/3455/X.
Secondly, eventually I need to convert localhost2/post/myTitle/123 => localhost2/post.php?title=myTitle&repeat=123 as well. I ave come up with the following:
^post/(?!\d+($|/))(.+?($|/))(\d+$)?
Note: +? to use lazy quantifier, otherwise multiple slashes will be matched by .
and
^post/(?!\d+($|/))([^/\n\r]+($|/))(\d+$)?
Here I use [^/\n\r] instead of .+?
Patterns inside zero-width assertions like (?!\d++) are non-consuming, they do not "eat" chars, they only check the context while keeping the regex index at the same location as before matching the zero-width assertion pattern.
You can use any of the following:
^post/(?!\d+(?:/|$)).*
^post/(?!\d+(?=/|$)).*
^post/(?!\d+(?![^/])).*
See the regex demo. Details:
^post/ - start of input, post/ literal string
(?!\d+(?=/|$)) - a negative lookahead that fails the match if, immediately to the right of the current location, there are one or more digits followed with / or end of string
.* - the rest of the input.
Do not over complicate things when you can keep things simple by keeping 3 separate rewrite rules and since your query parameters are named differently you will need 3 separate rewrite rules anyway.
Consider:
Options -MultiViews
RewriteEngine On
RewriteRule ^post/(\d+) post.php?id=$1 [L,QSA,NC]
RewriteRule ^post/([^/]+)/(\d+) post.php?title=$1&repeat=$2 [L,QSA,NC]
RewriteRule ^post/([^/]*) post.php?title=$1 [L,QSA,NC]
Take note of Options -MultiViews. If this is not enabled in Apache config you must have it here otherwise it will keep all $_GET parameters empty in your php file.
Option MultiViews (see http://httpd.apache.org/docs/2.4/content-negotiation.html) is used by Apache's content negotiation module that runs before mod_rewrite and makes Apache server match extensions of files. So if /file is the URL then Apache will serve /file.html.
I have these test cases:
/test
/test/
/test/whatever
I would like to write an nginx rewrite rule that only targets /test/whatever
I currently have
rewrite ^/(test/)(.*) /some-other-page; but this targets all the above cases.
Any ideas?
The ^/(test/)(.*) will match /test/ because .* can match an empty string.
You may use
^/test/(.+)
The .+ will require at least 1 char after /test/.
We want nginx to permanent redirect url's with a trailing slash to the non slash url. we found:
https://www.scalescale.com/tips/nginx/nginx-remove-trailing-slash/
So we put:
rewrite ^/(.*)/$ /$ permanent;
In the nginx, but the problem is it must not apply to some folders. so we found:
remove trailing slash in nginx with some certain cases ignored
and we changed it to:
rewrite ^/(?!admin)(.*)/$ /$ permanent;
but then the server wouldn't start:
invalid number of arguments in "rewrite" directive in /opt/www/folder/.nginx:5
And: we want 2 folders excluded.
What is the right regex to exclude the folders from the rewrite rule?
Thanks,
Bart
Edit for who comes here by google:
The answer works... only strange thing is that the standard worked without the $1 :
rewrite ^/(.*)/$ /$ permanent;
and now we made the exclude, it didn't work anymore without the $1.... but this works for now:
# remove trailing slashes
rewrite ^/(?!folder1|folder2)(.*)/$ /$1 permanent;
I suspect this is just a typo. That /$ looks like it should be /$1:
rewrite ^/(?!admin)(.*)/$ /$1 permanent;
If you have more that one URI to exclude, try something like
rewrite ^/(?!admin|secure|raw)(.*)/$ /$1 permanent;
nginx uses the same regular expression library as Perl, so you can test this stuff from a command line with
perl -ple 's#^/(?!admin|secure|raw)(.*)/$#/$1#'
and just typing in example URIs.
I have xxxx's of URLs which are in the following format:
http://www.example.com/sub/worda-wordb-wordc-123456789
However I have external links to my site with the URLs in the following format:
http://www.example.com/sub/worda-wordb-wordc/123456789
I'd like to redirect all URLs from
http://www.example.com/sub/worda-wordb-wordc/123456789
to
http://www.example.com/sub/worda-wordb-wordc-123456789
Please try the following:
RewriteEngine On
# Redirect URI with last slash, replacing with hyphen
RewriteRule ^sub/([\w-]+)/(\d+)/?$ /sub/$1-$2 [R=302,L]
Here, we are checking for letters, digits, underscores, and hyphens with ([\w-]+), digits with (\d+) and an optional slash on the end with /?, just to be sure, and then redirecting it accordingly.
Be sure to make this one of your first rules, and then change 302 to 301 to make the redirect cached by browsers and search engines.
You can use this .htaccess file:
RewriteBase /
RewriteRule ^sub/(.*)/([0-9]+)$ /sub/$1-$2
Now if you go to http://www.example.com/sub/worda-wordb-wordc/123456789 the url will be rewritted to http://www.example.com/sub/worda-wordb-wordc-123456789.
If this is not what you were looking for please add more details to your question.
You can use this rule in your site root .htaccess:
RedirectMatch 301 ^(sub)/(.*)-(\d+)/?$ /$1/$2/$3
I use a RedirectMatch rule which should exclude the following two URLs:
citycards/citycards-locations/munchen/citycards-trachtenvogl-reichenbachstr-47-munchen
citycards/citycards-locations/munchen/citycards-4-you-munchen-hirtenstrasse-18-munchen
I use this rule with regex, but I get a 500 Internal Server Error:
RedirectMatch 301 /citycards/citycards-locations/muenchen/((?!citycards/citycards-locations/munchen/citycards-trachtenvogl-reichenbachstr-47-munchen|citycards/citycards-locations/munchen/citycards-4-you-munchen-hirtenstrasse-18-munchen ).+)$ /citycards/citycards-locations/muenchen/$1
Any ideas why it doesn't work?
Your rule currently is: (broken down to multiple lines for better display/understanding):
RedirectMatch
301
/citycards/citycards-locations/muenchen/((?!citycards/citycards-locations/munchen/citycards-trachtenvogl-reichenbachstr-47-munchen|citycards/citycards-locations/munchen/citycards-4-you-munchen-hirtenstrasse-18-munchen ).+)$
/citycards/citycards-locations/muenchen/$1
Basically, your regex says that:
match /citycards/citycards-locations/muenchen/
which is not followed by either of the following
citycards/citycards-locations/munchen/citycards-trachtenvogl-reichenbachstr-47-munchen,
citycards/citycards-locations/munchen/citycards-4-you-munchen-hirtenstrasse-18-munchen (it has a space after 18-munchen)
match everything until the end of URI
and redirect the matched URI to: /citycards/citycards-locations/muenchen/$1 which is basically the same URL that was matched against.
I see 2 issues.
If the blank space in your negative lookahead is not considered as a part of the pattern, you are essentially passing 4 arguments to RedirectMatch directive, leading to status 500 error
If the pattern is getting parsed correctly, you have an infinite redirection loop.
/citycards-4-you-munchen-hirtenstrasse-18-munchen ).+)$
You have an unescaped space near the end of your RewriteRule pattern. This will certainly cause a 500 error since the space is a delimiter and the arguments will not match up (invalid flags).
It looks like this is a typo and should simply be removed?