Rewrite by removing duplicate if found - regex

My current .htaccess looks like this
RewriteEngine On
RewriteBase /
# / = /home
RewriteRule ^$ index.php?r=home [QSA,L]
# /example/ = /example
RewriteRule ^(.*)/$ /$1 [L,R=301]
# request, but not pointing to an existing file
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
# pass the whole request as a variable
RewriteRule ^(.+)$ index.php?r=$1 [QSA]
After these rewrites are done, I'd like to make sure that the URL doesn't end up having a duplicated part of a path at the end.
Here are a few test cases to more clearly demonstrate what I'd like to accomplish:
domain.tld/example // No more rewrites
domain.tld/example/example // Rewrite to domain.tld/example
domain.tld/test/example/example // Rewrite to domain.tld/test/example
domain.tld/example/test/test/test // Rewrite to domain.tld/example/test/test
So basically, if the last part of the URL is same as the penultimate, then remove the last part.
I've managed to put together this regex:
\/(.+)\/{1}\1$
which seems to match any duplicated parts of the URL, but I don't know if this is quite right for my needs, or how to implement the actual URL rewrite itself.
Any help with this would be greatly appreciated.

Figured out that I can use the following RewriteRule to accomplish this.
RewriteRule (.+)\/\1$ $1 [L,R=301]

Related

htaccess removing .php extension and pretty urls

Im trying to both remove .php extensions. So for example "http://localhost/timetable/login" instead of "http://localhost/timetable/login.php"
But also have
"http://localhost/timetable/38/" instead of
"http://localhost/timetable/index.php?week=38"
Im able to get one or the other working but not both at the same time. Im assuming its because there is a conflict between them but Im not advanced enough to find it.
Here is my .htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
RewriteRule ^([0-9]+)$ index.php?week=$2
RewriteRule ^([0-9]+)/$ index.php?week=$2
If in the address bar I type "http://localhost/timetable/38" it brings me to "http://localhost/38/" and an Object not Found error.
Does anyone know what the problem is ?
UPDATE: I can now go to the page but
echo $_GET['week'];
Is returning empty result, so its ignroing the 40 in "http://localhost/timetable/40"
Instead of using separate rewrite rule for each input, you should consider routing all of them as a single string to some php file.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?page=$1 [L,QSA]
In you php file, you can then separate the string as input and use them as required.
<?php
$inputs = explode('/', $_GET['page']);
You only have one capture group when you try to get the week. So it should be $1 instead of $2.
According to this test tool, the following should work:
RewriteRule ([0-9]+)/?$ index.php?week=$1
I would do something like this:
# rewrite if url ends with a number and possibly a slash
RewriteRule ([0-9]+)/?$ index.php?week=$1 [QSA,L]
# do not append .php if it already ends with .php, other add .php
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule ^(.*)$ $1.php [QSA,L]

How to do this complicated thing with mod_rewrite?

I'm hopeless when it comes to regex and/or the RewriteEngine, so my hours of researching and trying things have been pretty fruitless so far.
I'm trying to use the RewriteEngine to accomplish behavior that will follow these rules:
If the requested URL...
...points to an existing file e.g. domain.com/existing_file.ext
do no rewrites
...is empty, or contains only trailing slash(es) e.g. domain.com/
rewrite to index.php?var=example
...points to an existing directory that is not root (with or without trailing slashes) e.g. domain.com/existing_directory
rewrite to index.php?var=REQUESTED_DIRECTORY_PATH/example where REQUESTED_DIRECTORY_PATH is everything after domain.com (preferably always without a trailing slash)
...is not empty, but doesn't point to an existing file or directory e.g. domain.com/no_such_file_or_directory
rewrite to index.php?var=REQUESTED_URL, where REQUESTED_URL is everything after domain.com
This is what I've got so far:
# /
RewriteRule ^$ index.php?var=example [QSA,L]
# /directory_name/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ /index.php?var=$0/example [QSA,L]
# /not_a_valid_file_or_dir/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?var=$0 [QSA,L]
Which to me seems to almost do what I want, except for when I try to access domain.com/existing_directory (with or without a trailing slash). In this case I get redirected to domain.com/existing_directory/ (with a slash), while I would like to be end up at domain.com/index.php?var=existing_directory/example.
Thanks to helpful comments from Bananaapple, and a bit of Googling, I managed to accomplish what I wanted.
Firstly, I had to turn DirectorySlash off, and secondly I needed to remove the [^/] from the regex. So the final relevant code would look something like this:
DirectorySlash Off
# /
RewriteRule ^$ index.php?var=example [QSA,L]
# /directory_name/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)$ /index.php?var=$0/example [QSA,L]
# /not_a_valid_file_or_dir/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?var=$0 [QSA,L]
Thanks for the help.

What does RewriteRule ^(.*)/$ ?path=$1 [QSA,L] mean in my .htaccess?

I need to create rewrite in nginx as is done in my .htaccess and there are some lines which I don't completely understand.
DirectoryIndex index.php
RewriteEngine on
RewriteCond % !-f
RewriteRule ^(.*)/$ ?path=$1 [QSA,L]
Can someone explain it to me?
RewriteCond % !-f seems incorrect rule condition and is always evaluating to true.
This rule:
RewriteRule ^(.*)/$ ?path=$1 [QSA,L]
Is matching any URI with trailing slash and internally rewriting to /?path=uri-without-slash
So for ex: an URI /foo/ will be rewritten to /?path=foo
QSA - Query String Append
L = Last rule
Reference: Apache mod_rewrite Introduction
UPDATE: Change that incorrect condition to:
# request is not for a file
RewriteCond %{REQUEST_FILENAME} !-f
# request is not for a directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ ?path=$1 [QSA,L]
It means if the request isn't to a file, then rewrite everything before a trailing / into index.php?path= followed by what was previously matched.
It should be the last rule (L) and it should append the query string (QSA), as opposed to discarding it because of the replacement's query string.

Htaccess rewrite GET request to another GET request and another with 2 GET variables

I have two url's I'm trying to rewrite, for the past... 4-5 hours (headache now).
I am trying to rewrite
/arts/tag/?tag=keyword
to
/search/art?keywords=keyword
Looking at other questions I formulated my rewrite like this
RewriteRule /arts/tag/?tag=([^&]+) search/art?keywords=$1 [L,R=301,NC]
and
RewriteRule ^arts/tag/?tag=$ /search/art\?keywords=%1? [L,R=301,NC]
I tried with backslashes and without, no luck.
Also tried
RewriteCond %{QUERY_STRING} /arts/tag/?tag=([^&]+) [NC]
RewriteRule .* /search/art\?keywords=%1? [L,R=301,NC]
The second one is similar,
/arts/category?id=1&sortby=views&featured=1
to
/art/moved?id=1&rearrange=view
The reason I change the get variable name is for my own learning purpose as I haven't found any tutorials for my purpose. I also changed category to moved since the categories have changed and I have to internally redirect some ID #'s.
RewriteCond %{QUERY_STRING} id=([^&]+) [NC] // I need the path in there though, not just query string, since I'll be redirecting /blogs/category and /art/category to different places.
RewriteRule .* /art/moved/id=%1? [L,R=301,NC]
Any help will be appreciated. Thank you.
Assuming the queries in the original URLs have nothing in common with those in the substitution URLs, maybe this will do what you want, using the first keyin the query as a condition and to identify the incoming URL:
RewriteEngine On
RewriteBase /
# First case
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} \btag\b
RewriteRule .* http://example.com/search/art?keywords=keyword? [L]
Will map this:
http://example.com/arts/tag/?tag=keyword
To this:
http://example.com/search/art?keywords=keyword
# Second case
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} \bid\b
RewriteRule .* http://example.com/art/moved?id=1&rearrange=view? [L]
Will map this:
http://example.com/arts/category?id=1&sortby=views&featured=1
To this:
http://example.com/art/moved?id=1&rearrange=view
Both are mapped silently. If the new URL is to be shown in the browser's address bar modify the flags like this [R,L]. Replace R with R=301 for a permanent redirect.

Removing index.php from url using .htaccess even if the user requests it

I never want index.php to show up in my URL, even if the user inputs it. Is this possible?
This is variation whatever after several tries. I've come close a few times but this is where it's at for now.
RewriteEngine On
RewriteBase /sub-dir/
RewriteCond %{REQUEST_URI} index\.php$ //If URL ends in index.php
RewriteRule (.*)index\.php $1 //Somehow remove index.php from the url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
Currently I have permalink set up where if the user enters domain.com/sub-dir/my-perma-lin/ it generates a string on the page based on my-perma-link to look like My Perma Link. What I'd like is if the user submits any URL ending in index.php it just removes that from the URL but leaves everything else as is.
domain.com/sub-dir/index.php --> domain.com/sub-dir/
domain.com/sub-dir/my-perma-link/index.php --> domain.com/sub-dir/my-perma-link
I've written quite a few rules in http://htaccess.madewithlove.be/ that work perfectly but when I upload it (to Dreamhost) nothing works.
This for example should work according to the the tester
RewriteEngine On
RewriteBase /sub-dir/
RewriteCond %{REQUEST_URI} \.php //Not needed but thought it would/should help
RewriteRule (.*)(index\.php)+ $1 [L,R=301,NC]
But it just removes everything after /sub-dir/
I'm either missing something super obvious or it's not possible ...
You need to add some flags to your rule:
RewriteEngine On
RewriteBase /sub-dir/
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)index\.php(\?|\ )
RewriteRule ^ /%1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
You can ditch the RewriteCond %{REQUEST_URI} index\.php$ condition, as that's being checked by the regex in the RewriteRule. You need to include a $ at the end of the regex, and include the flags L to stop rewriting and R=301 to redirect.