How to match everything after slash to use as an nginx rewrite? - regex

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/.

Related

How to match string if it doesn't contain only numbers after slash?

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.

remove first folder in nginx

I have some URLs like:
http://example.com/username/file.zip
http://example.com/username/videos/aaa.avi
http://example.com/username/videos/abc/asdfdef/aaa.avi
the real path of files are:
/file.zip
/videos/aaa.avi
/videos/abc/asdfdef/aaa.avi
so basically I need to remove first folder in the URL
I tried to use this rewrite rule :
rewrite ^/.*/(.*)$ /$1 last;
but its remove all folders and grep just the filename, it's work just for first URL and i get 404 error for rest of them
- P.S: the username could be anything
i didnt test it but based on that nginx uses pcre library i think
rewrite ^/.*?/(.*)$ /$1 last;
would work.
.*? matches any character between zero and unlimited times, as few times as possible, expanding as needed (lazy)

Redirect Match with excluding URLs doesnt work

I use a RedirectMatch rule which should exclude the following two URLs:
citycards/citycards-locations/munche‌​n/citycards-trachtenvogl-reichenbachst‌​r-47-munchen
citycards/citycards-location‌​s/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/munche‌​n/citycards-trachtenvogl-reichenbachst‌​r-47-munchen|citycards/citycards-location‌​s/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/munche‌​n/citycards-trachtenvogl-reichenbachst‌​r-47-munchen|citycards/citycards-location‌​s/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/munche‌​n/citycards-trachtenvogl-reichenbachst‌​r-47-munchen,
citycards/citycards-location‌​s/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?

remove trailing slash in nginx with some certain cases ignored

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)(.*)/$

Apache rewrite rule - regex help

I have 7 urls:
url: /v/3b89441db7986135e5eb9e1debf0cc23
url: /v/3b89441db7986135e5eb9e1debf0cc23/login
url: /v/3b89441db7986135e5eb9e1debf0cc23/logout
url: /v/3b89441db7986135e5eb9e1debf0cc23/access
url: /v/3b89441db7986135e5eb9e1debf0cc23/delete-attendee/:id
url: /v/3b89441db7986135e5eb9e1debf0cc23/edit-attendee/:id
url: /v/3b89441db7986135e5eb9e1debf0cc23/finalise
How could I write a rewrite rule that if these URLS are not matched, I redirect the user to another domain?
For example the part after /v/ is always a 32 character MD5 string. the :id part is always a number.
If you could give me a regex (regex has alas never been my forte) example for
/v/3b89441db7986135e5eb9e1debf0cc23
and
/v/3b89441db7986135e5eb9e1debf0cc23/edit-attendee/:id
that would be excellent.
This regex matches your urls:
/v/[a-f0-9]{32}(/[a-z-]+(/\d+)?)?
In english...
/v/ is a literal
[a-f0-9]{32} means 32 hex digits
/[a-z-]+(/\d+)? means "/" then at least 1 of (any lowercase letter or a dash) then "/" then some digits
surrounding a regex in (...)? means either one or none of them
FYI, this regex matches all urls given in question reasonably tightly
If you want to not match, use this:
^(?!/v/[a-f0-9]{32}(/[a-z-]+(/\d+)?)?$)
How about this:
\/v\/[a-f0-9]{32}(\/(login|logout|access|delete-attendee\/:\d+|edit-attendee\/:\d+|finalise)?
This will only match your accepted urls. You should adjust for your flavor or regex and appropriate escape chars.
You said that you want to redirect if URLs do not match, so first you must make a rule that matches all valid URLs, then prepend ! to negate the match.
RewriteEngine On
RewriteRule !^v/[0-9a-f]{32}(/(login|logout|access|delete-attendee/\d+|edit-attendee/\d+|finalise))?$ http://your-other-domain/ [R]
The above rule should be placed in the .htaccess file present in the root directory of your website.