Question

I'm trying to have nginx intercept a url like this:

http://website.dev/results?livesearch=bill+clinton

and have it show up like:

http://website.dev/results/bill-clinton

I'm using Laravel as my PHP framework. When I type in the url manually (http://website.dev/results/bill-clinton) I get the correct page.

What I'm trying to do is have a user type in a name in a text input field; once they click submit, I would like the url to show up as http://website.dev/results/bill-clinton instead of http://website.dev/results?livesearch=bill+clinton

I've tried looking around the internet for some help but have not had any success.

My nginx virtual server is below.

server {

    listen       80;
    server_name  website.dev;

    access_log  logs/host.access.log  main;
    error_log   logs/host.error.log;
    rewrite_log     on;

    root   /path/to/www;
    index  index.php;

    #error_page  404              /404.html;
    error_page   500 502 503 504  /50x.html;

    location = /50x.html {
        root   html;
    }

    location / {
        # Pretty URLs. Allows removal of "index.php" from the URL.
        # Useful for frameworks like Laravel or WordPress.
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Added cache headers for images, quick fix for cloudfront.
    location ~* \.(png|jpg|jpeg|gif)$ {
        expires 30d;
        log_not_found off;
    }

    # Only 3 hours on CSS/JS to allow me to roll out fixes during
    # early weeks.
    location ~* \.(js|css|ico)$ {
        expires 3h;
        log_not_found off;
    }

    # Turn off logging for favicon and robots.txt
    location = /robots.txt      { access_log off; log_not_found off; }
    location = /favicon.ico    { access_log off; log_not_found off; }   

    # Removes trailing slashes (prevents SEO duplicate content issues)
    if (!-d $request_filename)
    {
        rewrite ^/(.+)/$ /$1 permanent;
    }

    # Removes trailing "index" from all controllers.
    # Useful for frameworks like Laravel.
    if ($request_uri ~* index/?$)
    {
        rewrite ^/(.*)/index/?$ /$1 permanent;
    }

    # Unless the request is for a valid file (image, js, css, etc.), 
    # send it to index.php
    if (!-e $request_filename)
    {
        rewrite ^/(.*)$ /index.php?/$1 last;
        break;
    }

    location ~ \.php$ {
        include                         fastcgi.conf;
        fastcgi_split_path_info         ^(.+\.php)(/.+)$;
        fastcgi_pass                    127.0.0.1:9000;
        fastcgi_index                   index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
       deny  all;
    }
}
Was it helpful?

Solution

Regex and if = almost always bad in nginx.

Almost all of your regex rewrites in nginx are going to seriously impact performance here.

For your initial routing for pretty URLs, you can actually use this:

location / {
         try_files $uri $uri/ /index.php?$query_string;
}

Laravel is smart enough to look in $_SERVER["PATH_INFO"]. It also handles trailing slashes.

Routing

You can then route the search you plan to do like so:

Route::any("/results/{search?}", "Search@results"); // ? = optional

This notation is Class@method. It's not static.

In app/controllers/Search.php, you'd have the following:

<?php

class Search extends BaseController {

    public function results($search = null) {
        if (!$search) {
            if (Input::has("q")) {
                // This is where you'd do SEO cleanup to remove special chars.
                return Redirect::to("/results/" . Input::get("q"));
            }
        } else {
            // do stuff with the $search variable here
        }

    }

}

When you do rewrites in nginx, you actually redirect the user anyways. (via a 301, 302 or 308 redirect).

You can avoid this extra request with javascript (send the browser to /request/search-term on submit), and you'd have a decent chunk of requests saved without impacting the experience of people who browse with noscript, too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top