{"id":31520,"date":"2019-06-12T06:18:38","date_gmt":"2019-06-11T21:18:38","guid":{"rendered":"https:\/\/jirak.net\/wp\/a-regular-expression-tester-for-nginx-and-nginx-plus\/"},"modified":"2019-06-12T06:34:24","modified_gmt":"2019-06-11T21:34:24","slug":"a-regular-expression-tester-for-nginx-and-nginx-plus","status":"publish","type":"post","link":"https:\/\/jirak.net\/wp\/a-regular-expression-tester-for-nginx-and-nginx-plus\/","title":{"rendered":"A Regular Expression Tester for NGINX and NGINX Plus"},"content":{"rendered":"<p>A Regular Expression Tester for NGINX and NGINX Plus<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jirak.net\/wp\/wp-content\/uploads\/2019\/06\/regex-tester_location.png\" width=\"780\" height=\"745\"><\/p>\n<p>While working on a regular expression (regex) to use with NGINX, I got an idea for a way to easily test a regex from within an actual NGINX configuration. (The regex tester works just the same for <a href=\"https:\/\/www.nginx.com\/products\/nginx\">NGINX&nbsp;Plus<\/a>, but for ease of reading I&#8217;ll refer to <em>NGINX<\/em>.)<\/p>\n<p>Support for regular expressions is one of the powerful features of NGINX, but regexes can be complex and difficult to get right, especially if you don\u2019t work with them regularly. NGINX allows regexes in multiple parts of a configuration, for example locations, maps, rewrites, and server names. The tester described here is for regexes in locations and maps.<\/p>\n<p>There are other free online regex testers that are good for most regexes, but NGINX uses some non&#8209;standard shortcuts optimized for web applications. For example, you don\u2019t have to escape the forward slash (\/) in a URI as you do in a standard regex. Also, when using a regex in a map, you specify what value to set based on a match. With other regex testers you might have to modify the regex or, in the case of a map, infer what value will be set. In addition, it is always good to be able to test a regex with the actual regex engine in the actual environment.<\/p>\n<h2>Overview<\/h2>\n<p>This post assumes a basic understanding of NGINX and regular expressions. NGINX uses <a target=\"_blank\" href=\"https:\/\/www.pcre.org\/\" rel=\"noopener noreferrer\">Perl Compatible Regular Expressions<\/a> (PCRE).<\/p>\n<p>Before we get into the details of the regex tester, let\u2019s first discuss how regexes can be used in NGINX locations and maps.<\/p>\n<h3>Locations<\/h3>\n<p>NGINX regex locations are of the form:<\/p>\n<pre><code class=\"config\">location <em>regex<\/em> {\r\n    #...\r\n}<\/code><\/pre>\n<p>For example, a <a target=\"_blank\" href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html#location\" rel=\"noopener noreferrer\"><code>location<\/code><\/a> block with the following regex handles all PHP requests with a URI ending with <strong>myapp\/<em>filename<\/em>.php<\/strong>, such as <strong>\/test\/myapp\/hello.php<\/strong> and <strong>\/myapp\/hello.php<\/strong>. The asterisk after the tilde (<code>~*<\/code>) makes the match case insensitive.<\/p>\n<pre><code class=\"config\">location ~* \/myapp\/.+.php$ {\r\n    #...\r\n}<\/code><\/pre>\n<p>NGINX and the regex tester support positional capture groups in <code>location<\/code> blocks. In the following example, the first group captures everything before the PHP file name and the second captures the PHP filename:<\/p>\n<pre><code class=\"config\">location ~* (.*\/myapp)\/(.+.php)$ {\r\n    #...\r\n}<\/code><\/pre>\n<p>For the URI <strong>\/myapp\/hello.php<\/strong>, the variable <code>$1<\/code> is set to <code>\/myapp<\/code> and <code>$2<\/code> is set to <code>hello.php<\/code>.<\/p>\n<p>NGINX also supports named capture groups (but note that the regex tester does not):<\/p>\n<pre><code class=\"config\">location ~* (?&lt;begin&gt;.*myapp)\/(?&lt;end&gt;.+.php)$ {\r\n    #...\r\n}<\/code><\/pre>\n<p>In this case the variable <code>$begin<\/code> is set to <code>\/myapp\/<\/code> and <code>$end<\/code> is set to <code>hello.php<\/code>.<\/p>\n<h3>Maps<\/h3>\n<p>NGINX maps that use regular expressions are of the form:<\/p>\n<pre><code class=\"config\">map <em>variable-from-request variable-to-set<\/em> {\r\n    <em>regex1 value-to-set-if-match<\/em>;\r\n    <em>regex2 value-to-set-if-match<\/em>;\r\n    #...\r\n    <em>regexN value-to-set-if-match<\/em>;\r\n    default <em>value-to-set-if-no-match<\/em>;\r\n}<\/code><\/pre>\n<p>For example, this <a target=\"_blank\" href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_map_module.html#map\" rel=\"noopener noreferrer\"><code>map<\/code><\/a> block sets the variable <code>$isphp<\/code> to <code>1<\/code> if the URI (as recorded in the <code>$uri<\/code> variable) ends in <strong>.php<\/strong>, and <code>0<\/code> if it does not (the match is case sensitive):<\/p>\n<pre><code class=\"config\">map $uri $isphp {\r\n    ~.php$ 1;\r\n    default 0;\r\n}<\/code><\/pre>\n<p>For maps, NGINX and the regex tester support both positional and named capture groups.<\/p>\n<p>For example, these maps both set the variable <code>$fileext<\/code> to the value of the file extension, which is also captured as <code>$1<\/code> in the first block and <code>$ext<\/code> in the second:<\/p>\n<pre><code class=\"config\">map $uri $fileext {\r\n    ~*.+.(.+)$  $1;\r\n    default      '';\r\n}<\/code><\/pre>\n<p>Or:<\/p>\n<pre><code class=\"config\">map $uri $fileext {\r\n    ~*.+.(?.+)$  $ext;\r\n    default            '';\r\n}<\/code><\/pre>\n<h2>The Regular Expression Tester<\/h2>\n<p>The regex tester is implemented in a Docker container with NGINX and <a target=\"_blank\" href=\"https:\/\/unit.nginx.org\/\" rel=\"noopener noreferrer\">NGINX&nbsp;Unit<\/a> installed. NGINX&nbsp;Unit serves two variations of a PHP page, one for regexes in <code>location<\/code> blocks and the other for regexes in <code>map<\/code> blocks. The two pages prompt the user for different inputs:<\/p>\n<ul>\n<li>\n<p>Location page:<\/p>\n<ul>\n<li>The regex<\/li>\n<li>Case sensitivity<\/li>\n<li>The URI<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Map page:<\/p>\n<ul>\n<li>The regex<\/li>\n<li>Case sensitivity<\/li>\n<li>The value to test (the value of the variable that is the first parameter to the <code>map<\/code> directive)<\/li>\n<li>The value to set in the variable specified as the second parameter to the <code>map<\/code> directive<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>After providing the information, the user clicks the <strong>Test<\/strong> button. The tester generates the necessary NGINX configuration file, the configuration is reloaded, and a request is sent to test the regex. The results are then displayed and indicate whether a match was found. If so, on the location page the values of the capture groups are dispalyed, and on the map page the value set by the map is reported.<\/p>\n<h3>Location Page Example<\/h3>\n<p>This example shows the results of a case&#8209;insensitive test of the regex <code>(.*myapp)\/(.+.php)$<\/code> against the URI <strong>\/myapp\/hello.php<\/strong>:<\/p>\n<p><a href=\"https:\/\/www.nginx.com\/wp-content\/uploads\/2019\/06\/regex-tester_location.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.nginx.com\/wp-content\/uploads\/2019\/06\/regex-tester_location.png\" alt=\"\" width=\"780\" height=\"745\" class=\"alignleft size-full wp-image-62485\" style=\"border:2px solid #666666;padding:2px;margin:2px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h3>Map Page Example<\/h3>\n<p>This example shows the results of a case&#8209;insensitive test of the regex <code>.+.(?&lt;ext&gt;.*)$ <\/code> against the value <strong>\/myapp\/hello.php<\/strong>, with the named capture group <code>$ext<\/code> as the value to set:<\/p>\n<p><a href=\"https:\/\/www.nginx.com\/wp-content\/uploads\/2019\/06\/regex-tester_map.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.nginx.com\/wp-content\/uploads\/2019\/06\/regex-tester_map.png\" alt=\"\" width=\"781\" height=\"835\" class=\"alignleft size-full wp-image-62484\" style=\"border:2px solid #666666;padding:2px;margin:2px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>Conclusion<\/h2>\n<p>You can see that the NGINX configuration is quite short and simple. The hard work is done by the PHP page that generates the necessary NGINX configuration file based on the values entered by the user, reloads NGINX, sends a request to NGINX, and displays the results.<\/p>\n<p>You can try out the regex tester for yourself: all the code is available at our <a target=\"_blank\" href=\"https:\/\/github.com\/nginxinc\/NGINX-Demos\/tree\/master\/nginx-regex-tester\" rel=\"noopener noreferrer\">GitHub repo<\/a> (<strong>https:\/\/github.com\/nginxinc\/NGINX-Demos\/tree\/master\/nginx-regex-tester<\/strong>).<\/p>\n<p>To make it easy to get the regex tester up and running, all the necessary files are included. To build the Docker image and build the container, simply run:<\/p>\n<pre><code class=\"terminal\">$ <span style=\"color:#66ff99;font-weight: bold\">docker-compose up -d<\/span><\/code><\/pre>\n<p>Then point your browser to <strong>http:\/\/<em>Docker-host<\/em>\/regextester.php<\/strong>.<\/p>\n<p>I hope you find tester helpful when using regular expressions and that it gives you a glimpse of some of the power, flexibility, and simplicity of NGINX.<\/p>\n<p>To try out the regex tester with NGINX&nbsp;Plus, start your <span><a href=\"https:\/\/www.nginx.com\/free-trial-request\">free 30-day trial<\/a><\/span> today or <a href=\"https:\/\/www.nginx.com\/contact-sales\/\">contact&nbsp;us to discuss your use cases<\/a>.<\/p>\n<p>The post <a rel=\"nofollow\" href=\"https:\/\/www.nginx.com\/blog\/regular-expression-tester-nginx\/\">A Regular Expression Tester for NGINX and NGINX Plus<\/a> appeared first on <a rel=\"nofollow\" href=\"https:\/\/www.nginx.com\">NGINX<\/a>.<\/p>\n<p>Source: <a href=\"https:\/\/www.nginx.com\/blog\/regular-expression-tester-nginx\/\" target=\"_blank\" rel=\"noopener noreferrer\">A Regular Expression Tester for NGINX and NGINX Plus<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>A Regular Expression Tester for NGINX and NGINX Plus While working on a regular expression (regex) to use with NGINX, I got an idea for a way to easily test a regex from within an actual NGINX configuration. (The regex tester works just the same for NGINX&nbsp;Plus, but for ease of reading I&#8217;ll refer to NGINX.) Support for regular expressions is one of the powerful features of NGINX, but regexes can be complex and difficult to get right, especially if you don\u2019t work with them regularly. NGINX allows regexes in multiple parts of a configuration, for example locations, maps, rewrites, and server names. The tester described here is for regexes in locations and maps. There are other free online regex testers that are good for most regexes, but NGINX uses some non&#8209;standard shortcuts optimized for web applications. For example, you <a class=\"mh-excerpt-more\" href=\"https:\/\/jirak.net\/wp\/a-regular-expression-tester-for-nginx-and-nginx-plus\/\" title=\"A Regular Expression Tester for NGINX and NGINX Plus\">[ more&#8230; ]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":31521,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[169],"tags":[652],"class_list":["post-31520","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","tag-nginx"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/31520","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/comments?post=31520"}],"version-history":[{"count":1,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/31520\/revisions"}],"predecessor-version":[{"id":31522,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/31520\/revisions\/31522"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media\/31521"}],"wp:attachment":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media?parent=31520"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/categories?post=31520"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/tags?post=31520"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}