Mod rewrite rule for optional language in URL - regex

I have a shop URL like this
https://domain.eu/cz/lp/9200
And I'm trying to rewrite it in .htaccess to https://domain.eu/lp/index.php?id=$2&lang=$1
I came really close with
RewriteRule ^/?(hr|sk|pl|cz|ro|it)/lp/(\d+)?$ /lp/index.php?id=$2&lang=$1
which works ok but I can't seem to find a way to handle the situation when there is no lang in URL.
So this is also valid: https://domain.eu/lp/9200 but in that case I want $1 to just be empty (or have a default value when it's not present)
I know "?" means "one or zero" times that's why I tried
RewriteRule ^/?[(hr|sk|pl|cz|ro|it)?]/lp/(\d+)?$ /lp/index.php?id=$2&lang=$1
But it doesn't work as expected. Any point in the right direction would be appreciated.

With your shown samples, attempts; please have your htaccess Rules file in following manner. Make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
##Rewrite rule for uris which have only 1 parameter.
RewriteRule ^lp/(\d+)/?$ /lp/index.php?id=$1 [NC,L]
##Rewrite rule for uris which 2 parameters.
RewriteRule ^(hr|sk|pl|cz|ro|it)/lp/(\d+)/?$ /lp/index.php?id=$2&lang=$1 [NC,L]
OR use following solutions, in case uris you are trying to access are non-existent ones. Make sure either use 1st solution OR this one, once at a time only.
RewriteEngine ON
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^lp/(\d+)/?$ /lp/index.php?id=$1 [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(hr|sk|pl|cz|ro|it)/lp/(\d+)/?$ /lp/index.php?id=$2&lang=$1 [NC,L]

Related

Apache RewriteCond: how to match only top-level requests (no subdirectory)

After banging my head against this for the better part of a week, it turned out to be the same problem, and solution, as in this thread: RewriteCond in .htaccess with negated regex condition doesn't work?
TL;DR: I had deleted my 404 document at some point. This was causing Apache to run through the rules again when it tried to serve the new page and couldn't. On the second trip through, it would always match my special conditions.
I'm having endless trouble with this regex, and I don't know whether it's because I'm missing something about RewriteCond or what.
Simply, I want to match only top-level requests, meaning any request with no subdirectory. For example I want to match site.com/index.html, but not site.com/subdirectory/index.html.
I thought I would be able to accomplish it with this:
RewriteCond %{REQUEST_URI} !/[^/]+/.*
The interesting thing is, it doesn't work but the reverse does. For example:
RewriteCond %{REQUEST_URI} /[^/]+/.*
That will detect when there is a subdirectory. And it will omit top-level requests (site.com/toplevelurl). But when I put the exclamation point in front to reverse the rule (which RewriteCond is supposed to allow), it stops matching anything.
I've tried many different flavors of regex and different patterns that should work, but none seem to. Any help would be appreciated. this Stack Overflow answer seems like it should answer it but does not work for me.
I've also tested it with this .htaccess rule tester, and my patterns work in the tester, they just don't work on the actual server.
Edit: by request, here is my .htaccess. It allows URLs without file extensions and also does something similar to a custom 404 page (although its purpose is to allow filenames as arguments, not be a 404 replacement).
Options +FollowSymLinks
DirectoryIndex index.php index.html index.htm
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
RewriteCond %{REQUEST_FILENAME} =/home/me/public_html/site/
RewriteRule ^(.*)$ index.php
RewriteCond %{REQUEST_FILENAME} !-f # Below this is where I would like the new rule
RewriteRule ^(.*)$ newurl.php
</IfModule>
I want to match site.com/index.html, but not site.com/subdirectory/index.html
You can use:
RewriteRule ^[^/]+/?$
Or using RewriteCond:
RewriteCond %{REQUEST_URI} ^/[^/]+/?$

Simple redirect complicated by rules below it

I want a simple redirect in my .htaccess, with the goal of making a "shortlink" to a long URL.
mydomain.com/short
to take the user to
http://www.mydomain.com/blahblah/foo/bar/foobar/uglylongurl.html
So I tried this:
Redirect /short http://www.mydomain.com/blahblah/foo/bar/foobar/uglylongurl.html
but within the same .htaccess file is:
# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
This is causing my simple redirect to have "short" appended as a query string.
I have tried [R] to redirect immediately and I've also tried [L] to stop processing if the first (simplest) rule is used. Both give me a 500 error.
I hope someone knows what I'm missing here. I am on a tight deadline and this is just killing me :P Thanks in advance for any help.
Many thanks to the responder who got this working. I had the redirect above the other rules, however, I needed to change it to a RewriteRule and add the additional code as in his example.
One more issue arose after this....and with his suggestion, I am adding the next layer of the problem to this question (instead of to the comment reply, where the code tags didn't work and it was hard to read).
So here is my next issue. The first one in the list works just fine, whether redirecting to an internal page or an external URL. But subsequent rules give me a 404 error. Here is what it looks like (and note they are all before the one that appends the query string):
RewriteRule ^short/?$ /ugly/long/url.html [L,NC]
RewriteRule ^/sweet/?$ /another/ugly/long/url.html [L,NC]
RewriteRule ^/offsite/?$ http://www.somewhereelse.com/with/a/long/url.html [L,NC]
# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
Order of rewrite rules in pretty important. First have your desired rule then rest of the rules.
RewriteEngine On
RewriteRule ^short/?$ /blahblah/foo/bar/foobar/uglylongurl.html [L,NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

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.

drupal multisite htaccess: rewrite all languages to default language on one subsite

I have a Drupal 6 multisite, with 2 domains (www.example.com and www.domain.com), sharing some common content.
The domain example.com is in three languages (EN, FR, NL). Languages are set by path prefix (/en, /fr, /nl). The other domain domain.com is just in one language (NL).
The problem: on many occasions domain.com is shown in the wrong language, even if no path prefix is filled in. Somehow it seems to default to EN, though it doesn't always do that - behaviour doesn't seem to be very consistent.
The solution (at least I hope): since I'm not a Drupal developer (I inhereted the site from a former colleague) I have no idea how to fix this in Drupal, so I thought the best way to fix it would be to add some rewrite rules to .htaccess.
I'm no htaccess/regex expert either, and can't get it working. You can find my current rewrite rules below, any help or suggestions are most welcome.
Some examples:
www.domain.com/fr/some-title needs to be rewritten to www.domain.com/nl/some-title
www.domain.com/node/1975 needs to be rewritten to www.domain.com/nl/node/1975
These are the rewrite rules that were already there:
# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
I tried adding this:
RewriteCond %{HTTP_HOST} ^(www.)?domain.com$ [NC]
RewriteRule ^/(.*)$ /nl/$1
and would expect this just to prepend /nl/ to all paths (thus not being a full solution since /fr/some-title would become /nl/fr/some-title) - however, a quick test shows me that:
/fr/some-title is rewritten to /nl/some-title (which is what I need, but not what I expected)
/some-title is not rewritten
The question: any ideas what might be wrong? Or could this be caused by other (Drupal) settings? Or is there a better way to solve my problem?
Just for the sake of completeness: the live website is www.cinemazuid.be
If this rule
RewriteRule ^/(.*)$ /nl/$1
is in your .htaccess file, I am surprised that it works as the leading / is always stripped out, so it should theoretically never match any request.
If your desire is to force a default language of NL for those requests that do not specify a language, then add the following rules to the top of your .htaccess file, before any existing rules
#if request is for existing file or directory
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
#then stop processing
RewriteRule .* - [L]
#replace fr with nl. This rule
RewriteRule ^fr/(.*)$ /nl/$1 [L,R=301]
#if the request does not have a language of en or nl
RewriteCond %{REQUEST_URI} !^/(en|nl)/ [NC]
#redirect with nl as default language
RewriteRule .+ /nl%{REQUEST_URI} [L,R=301]
If you do not want to redirect, just drop the R=301
I edited code above to replace /fr/some-title with /nl/some-title/.
The L flag tells mod_rewrite to stop processing further rules, which is usually what you want, unless you have another rule that needs to further process the current request.
#redirect /fr/* and /en/* to /*
RewriteCond %{HTTP_HOST} ^(www\.)?domain\.com$ [NC]
RewriteRule ^(en|fr)/(.*)$ /$2 [R,L]
#internally rewrite /* to /nl/*
RewriteCond %{HTTP_HOST} ^(www\.)?domain\.com$ [NC]
RewriteCond $1 !^nl/$ [NC]
RewriteRule ^(.*)$ /nl/$1
#drupal code
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

.htaccess issue, existing .php files and search.php

I'm new to playing with .htaccess for nicely formatted urls and I'm just not sure I'm doing it right.
My current .htaccess file looks like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^search/(.*) search.php?query=$1 [L]
RewriteRule !\.(gif|jpg|ico|css|js|txt|xml|png|swf)$ index.php
What I want is for mysite.com/home/56/page-title to go to index.php where I filter out the number and load the correct index page, which works fine.
Before that, I want to check if the url is pointing at search.php, and if so redirect to mysite.com/search/the-search-term, this also works fine.
What isn't working is if I try to visit a specific .php file say mysite.com/control_panel.php - it just takes me to index.php, but I thought that the following line stopped that from happening?
RewriteCond %{REQUEST_FILENAME} !-f
If someone could explain it to me that would be great :)
Thanks!
1. Order of rules matters
2. RewriteCond directives will only be applied to the ONE RewriteRule that follows it. If you need to apply the same conditions to multiple rules you have to write them multiple times or change the rewrite processing logic (multiple approaches available).
Try this one:
RewriteEngine On
RewriteRule ^search/(.*) search.php?query=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(gif|jpg|ico|css|js|txt|xml|png|swf)$ index.php [L]