Welcome Guest, Not a member yet? Register   Sign In
$routes->addRedirect with regex?
#1

I'm trying to deprecate the use of .html suffixes for my urls. I'm trying to redirect old urls like this:
Code:
https://www.example.com/subdir/some-item-title/page-specifier-15-1132.00.html
to the new identical URL but minus the .html at the end:
Code:
https://www.example.com/subdir/some-item-title/page-specifier-15-1132.00

NOTE: the some-item-title and page-specifier change and can be almost anything depending on the item. I added this addRedirect line to my Config/Routes.php file:
PHP Code:
$routes->addRedirect('subdir/([a-z\-]+)/([a-z\-]+)-(\d{2}-\d{4}\.\d{2})\.html''subdir/$1/$2-$3'); 
However, the addRedirect function apparently doesn't work with the backreferences. I do get a redirect but, rather than containing the patterns matched in the original url, the new url just has literally $1, $2, and $3:
Code:
https://www.example.com/subdir/$1/$2-$3

Does addRedirect not support backreferences? If so, it might be helpful to clarify this in the documentation. How should I go about solving this problem? NOTE: I do *not* want to redirect all urls ending in .html.
Reply
#2

The addRedirect() method does not support replacement.

You can use this hack
PHP Code:
$routes->any('subdir/([a-z\-]+)/([a-z\-]+)-(\d{2}-\d{4}\.\d{2})\.html', function(){
    $router Services::router();
    $request Services::request();
    $path preg_replace(
        '#^' $router->getMatchedRoute()[0] . '$#u',
        $router->getMatchedRouteOptions()['redirect'],
        $request->uri->getPath()
    );
    throw new RedirectException($path);
}, [
'redirect' => 'subdir/$1/$2-$3']); 

Or create your own class that extends the Router class and implement a replacement in it.
Or post a new issue on github or PR with fixes or comment in the documentation about the inability to use regex.
Reply
#3

(02-11-2021, 03:37 AM)iRedds Wrote: The addRedirect() method does not support replacement.
Thanks for the clarification. Thanks also for the code. That hack is not pretty.
Reply
#4

(02-11-2021, 11:23 AM)sneakyimp Wrote: Thanks for the clarification. Thanks also for the code. That hack is not pretty.
Yes, it looks ugly.
The simplest, and probably better in this case, is to make a redirect at the web server level
Reply
#5

(This post was last modified: 02-15-2021, 12:13 PM by sneakyimp.)

(02-11-2021, 11:36 PM)iRedds Wrote: The simplest, and probably better in this case, is to make a redirect at the web server level

OK I think I will make a redirect method in my BaseController that works like the old CI3 redirect function..

Does anyone know why CI3 used the refresh method for Microsoft-IIS?

Does anyone know why CI3 would check for HTTP/1.1 and then use 307 for GET requests and 303 for everything else? It looks like 303 and 307 were added for HTTP/1.1 and did not exist before.

EDIT: I'm not sure, but it looks like a 307 redirect would encourage the client to re-POST any data that was posted. This does not sound like the behavior I'd be after. E.g., if someone's session had expired and they attempt to POST a form, I'd be redirecting them to a login page first, and it would not be ideal to have an immediate POST applied there.

Also, it looks like we have HTTP/2 as of 2015, so we'll probably need a > comparison, and possibly additional logic. Any tips/hints/thoughts very much appreciated.
Reply
#6

I have added this function to my BaseController class. It's simpler than the CI3 function in a few ways, but works for apache 2.4.41.
PHP Code:
        /**
         * CI4 lacks a redirect() function, and its recommended redirect approach does not work
         * in either __construct or initController functions, so I've added this, loosely based on
         * the CI3 redirect() function but some differences: doesn't bother using site_url for force FQDN
         * uri, cannot specify redirect method, doesn't use 307 for non-GET requests unless you explicitly specify
         * that code via parameter, doesn't allow empty uri param, only uses location header, no refresh method
         * 
         * @param string $uri
         * @param int $code
         */
        
public function redirect($uri$code NULL)
        {
            if (!
$uri) {
                throw new \
Exception("You must specify a non-empty uri");
            }
            if (!
is_null($code) && !is_int($code)) {
                throw new \
Exception("If you specify an HTTP code, value must be an integer");
            }
            
            if (!
$code)
            {
                
// default code to 302
                
$code 302;
                
                
// upgrade code to 303 if HTTP/1.1 or greater
                
$matches NULL;
                if (isset(
$_SERVER['SERVER_PROTOCOL'], $_SERVER['REQUEST_METHOD']) && preg_match('#^HTTP/([0-9\.]+)$#i'$_SERVER['SERVER_PROTOCOL'], $matches))
                {
                    
// HTTP/1.1 introduced more specific redirect response codes
                    
$version = isset($matches[1]) ? $matches[1] : "1.0";
                    if (
version_compare($version"1.1"">="))
                    {
                        
$code 303;
                    }
                }
            }

            
header('Location: ' $uriTRUE$code);
            exit;
        } 
Reply




Theme © iAndrew 2016 - Forum software by © MyBB