Home > Net >  How to replace underscores with dashes in URL using htaccess?
How to replace underscores with dashes in URL using htaccess?

Time:03-08

I have URL that looks like this example.com/test-page/now_here, but I want the URL to look like example.com/test-page/now-here.

I have tried the following in my .htaccess file:

RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/_]*)$       $1-$2 [R=301]

But it did not work. I get a 404 error when I goto /test-page/now-here

What am I doing wrong?

Here is my full .htaccess:

Options -Indexes

<IfModule mod_rewrite.c>
    Options  FollowSymLinks
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP_USER_AGENT} ^(. )$
    RewriteCond %{SERVER_NAME} ^example\.com$
    RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
    RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/_]*)$       $1-$2 [R=301]
    Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
    <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
        Header always set Strict-Transport-Security "max-age=31536000"
    </If>
</IfModule>

UPDATE

@MrWhite solution did work, and now when I goto the url test-page/now_here it goes to test-page/now-here, however its not going to my php method in my test page controller, here is the full code:

class TestPage_Controller extends App_Controller {
    function index() {
        $this->smarty->assign('currentPage', 'testpage');
        $this->smarty->assign('pageTitle', 'Test Page');
        $this->smarty->assign('description', "This is a test page.");
        $this->smarty->display(MDCHAT_THEME . '/page_meta.tpl');
        $this->smarty->display(MDCHAT_THEME . '/page_header.tpl');
        $this->smarty->display(MDCHAT_THEME . '/test_page.tpl');
        $this->smarty->display(MDCHAT_THEME . '/page_footer.tpl');
    }

    function now_here() {
        $this->smarty->assign('currentPage', 'testpage');
        $this->smarty->assign('pageTitle', 'Test Page');
        $this->smarty->assign('description', "This is a test page.");
        $this->smarty->display(MDCHAT_THEME . '/page_meta.tpl');
        $this->smarty->display(MDCHAT_THEME . '/page_header.tpl');
        $this->smarty->display(MDCHAT_THEME . '/here.tpl');
        $this->smarty->display(MDCHAT_THEME . '/page_footer.tpl');
    }
}

All I get when I goto test-page/now-here I get a blank white page even after I turned on php errors via php.ini display_errors = on and in my php code:

error_reporting(E_ALL);
ini_set('display_errors', 1);

Still just a white screen.

CodePudding user response:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_USER_AGENT} ^(. )$
RewriteCond %{SERVER_NAME} ^example\.com$
RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
RewriteRule       ^(/?test-page/.*/[^/]*?)_([^/_]*)$       $1-$2 [R=301]

Your rules are in the wrong order, so the directives won't actually be processed for the given URL. But the regex in that rule doesn't match the example URL either, so wouldn't do anything anyway.

The regex you are using would match /test-page/something/now_here, not /test-page/now_here as in your example. The .*/ after test-page/ is extra based on your example.

Your existing (what looks-like) HTTP to HTTPS and non-www to www canonical redirect is also in the wrong place (it needs to go before the rewrite to the front-controller, otherwise it will end up redirecting to index.php), but it would also fail to canonicalise http://www.example.com/ (HTTP www) and https://example.com/ (HTTPS non-www). As written, it only canonicalises http://example.com/ (HTTP non-www).

Try the following instead:

RewriteEngine On

# 1.0 - Replace underscores with hyphens in last path segment
RewriteRule ^(test-page/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]

# 1.1 - Redirect to remove the final underscore
RewriteCond %{HTTP_HOST} ^(?:www\.)?(. ?)\.?$ [NC]    
RewriteRule ^(test-page/[^/]*?)_([^/_]*)$ https://www.%1/$1-$2 [R=301,L]

# 2 - non-www to www AND HTTP to HTTPS
RewriteCond %{HTTP_USER_AGENT} .
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(. ?)\.?$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L]

# 3 - Rewrite to front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/$1 [L]

NB: Test with a 302 (temporary) redirect first to avoid potential caching issues.

I would also question why you are only redirecting (canonicalising) requests from user-agents that pass a ve User-Agent string. (Yes, it's quite possibly a malicious bot.) Yet you are still passing such requests to your front-controller and not blocking it. (?) I've left this condition in the above rule, just simplified it, in case you have some specific requirements.

You probably do not want the <IfModule mod_rewrite.c> wrapper. With this <IfModule> directive in place and mod_rewrite was suddenly not available then your site will no doubt break in a non-obvious way and you'll likely get a ton of 404s, which may not be picked up for a while. Without this <IfModule> directive then the site will break with a detailed error in the server's error log which should potentially trigger an alert/notification. See the following question on Webmasters SE for more info on this: https://webmasters.stackexchange.com/questions/112600/is-checking-for-mod-write-really-necessary

  • Related