ecception to this .htaccess rule specific pdf link are allowed - apache

I added this .htaccess rule to a WordPress website
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} (.*)
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_([a-zA-Z0-9_]*) [NC]
RewriteRule \.(zip|doc|docx|pdf)$ – [NC,F,L]
</IfModule>
This rule work right but I want to give an exception.
https://example.com/wp-content/uploads/2022/11/name-of-pdf.pdf
must be visible even if your not logged in.

RewriteCond %{REQUEST_FILENAME} (.*)
Change this condition to:
RewriteCond %{REQUEST_URI} !=/wp-content/uploads/2022/11/name-of-pdf.pdf
The ! prefix negates the expression, so it is successful when it does not match.
The = prefix operator makes this an exact string match, not a regex, so just use the complete URL-path as-is.
must be visible even if your not logged in
Just to clarify (concern raised in comments)... this code does not check that the user is "logged in" (it does not authenticate the WP auth token). This simply checks for the existence of a cookie (ie. a Cookie HTTP request header that contains the value wordpress_logged_in_).
This might stop the casual user, but it is easily circumvented by the determined user so cannot be used to protect sensitive media.

Related

htaccess redirect outcome not as expected

I hope someone can help me with the following problem.
I have a multiple language site with the language as a folder like
example.com/se/post
I want to get the language separated by domain like example.se.
So far no problem with a DNS alias and WPML plugin.
The problem I have is that I want to redirect example.com/se/post to example.se/post. I try to use this rule in the .HTACCESS file but it changes the URL to example.se/se with the /se that I do not need. I'm not very familiar with the rewrite engine in .HTACCESS file.
<IfModule mod_headers.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www\.)?nofairytales\.nl$ [NC]
RewriteCond %{REQUEST_URI} ^/sv(/.*)?$ [NC]
RewriteRule ^(.*)$ http://www.nofairytales.se%{REQUEST_URI} [L,R=301]
</IfModule>
RewriteCond %{HTTP_HOST} ^(www\.)?nofairytales\.nl$ [NC]
RewriteCond %{REQUEST_URI} ^/sv(/.*)?$ [NC]
RewriteRule ^(.*)$ http://www.example.se%{REQUEST_URI} [L,R=301]
This is close... you are capturing the URL-path (/post part) in the preceding condition but not using it in the substitution string. Instead, you are using REQUEST_URI which contains the full root-relative URL-path.
You are also matching sv in the URL-path, but redirecting to se in the TLD. The following should resolve the issue (with minimal changes):
RewriteCond %{REQUEST_URI} ^/se(/.*)?$ [NC]
RewriteRule ^(.*)$ http://www.example.se%1 [L,R=301]
Where %1 is a backreference to the captured subpattern in the preceding condition (the /post part).
However, You don't need the second (or even the first) condition(s), as it can be all done in the RewriteRule directive. There wouldn't seem to be a need to check the requested hostname, since if the language subdirectory is in the URL-path then it would seem you should redirect anyway to remove it.
For example, the following should be sufficient to redirect a single language code:
# Language "se"
RewriteRule ^se(?:/(.*))?$ https://www.example.se/$1 [R=301,L]
The non-capturing group that contains the slash delimiter ensures that we always have a trailing slash on the target URL (after the hostname). The first rule above requires the user-agent to "correct" the redirect response when the slash after the hostname is omitted (which it does).
For multiple languages you can modify the same rule with regex alternation. For example:
# All supported languages
RewriteRule ^(se|uk|us|au|id)(?:/(.*))?$ https://www.example.$1/$2 [R=301,L]
This assumes all language codes map to a TLD using the same code. If not then you can implement a "mapping" (lang code -> TLD) in the rule itself or use a RewriteMap if you have access to the server config. This could also provide a "default" TLD.
You could be more generic and allow any two-character language code in the regex. eg. ^([a-z]{2})(?:/(.*))?$. And simply pass this through to the TLD. However, a request for an unknown language (eg. /xx/post) - which might have resulted from an error on your site - will now result in either a malformed redirect (since the domain won't resolve) or worse, a redirect to a competitor lying in wait. And this might go undetected unless you run an analysis of your redirects. So, being more restrictive with the regex/rule may be advisable.

.htaccess RewriteRule from long url to show short url

Im trying to rewrite url from long to short but cant wrap my head around this.
My survey rewrite works wonderfully but after completing my survet php redirects to www.example.com/survey_thank_you.php?survey_id=1
but I would like to show url like www.example.com/thank_you
Im not even sure if this is possible.
Im new with .htaccess and i have tried almost everthing
.htaccess
Options +FollowSymLinks
Options -MultiViews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^survey_thank_you.php?survey_name=([0-9a-zA-Z]+)/?$ Thank_you [L,NC,QSA]
RewriteRule ^([0-9a-zA-Z]+)/?$ survey_form.php?survey_name=$1 [L,NC,QSA] #works like charm.
Any help or directions will be highly appreciated.
Solution:
Options +FollowSymLinks
Options -MultiViews
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^survey_id=([0-9a-zA-Z]+)/?$
RewriteRule ^survey_thank_you\.php$ /%1/thank_you [R,L,QSD]
RewriteRule ^([0-9a-zA-Z]+)/thank_you$ survey_thank_you.php?survey_id=$1 [L,NC,QSA]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([0-9a-zA-Z]+)/?$ survey_form.php?survey_name=$1 [L,NC,QSA]
but after completing my survet php redirects to www.example.com/survey_thank_you.php?survey_id=1
You need to "correct" the URL that PHP is redirecting you to after the survey. If the desired URL is /thank_you (or /Thank_you?) then PHP should be redirecting to that URL.
You then use mod_rewrite in .htaccess to internally rewrite /thank_you back into the URL that your application understands. ie. /survey_thank_you.php?survey_id=1. However, therein lies another problem, where does the 1 (survey_id) come from in the query string? Presumably you don't want to hardcode this? So this would need to passed in the requested URL. eg. /1/thank_you or perhaps /thank_you/1?
However, is this really necessary? The resulting "thank you" page is not a page that should be indexed or a page that is normally navigated to by the user, so implementing a user-friendly URL here doesn't seem to be a worthwhile exercise?
RewriteRule ^survey_thank_you.php?survey_name=([0-9a-zA-Z]+)/?$ Thank_you [L,NC,QSA]
RewriteRule ^([0-9a-zA-Z]+)/?$ survey_form.php?survey_name=$1 [L,NC,QSA] #works like charm.
You are using a survey_name URL parameter (referencing an alphanumeric value) in your directives, but a survey_id ("numeric"?) URL parameter in your earlier example? So, which is it? Or are these rules unrelated?
You state that the second rule "works like charm", but how? What URL are you requesting? That would seem to rewrite /Thank_you to survey_form.php?survey_name=Thank_you - but that does not look correct?
As mentioned in comments, the RewriteRule pattern matches against the URL-path only. To match against the query string you need an additional condition that matches against the QUERY_STRING server variable. This would also need to be an external 3xx redirect, not an internal rewrite (in order to change the URL that the user sees). Therein lies another problem... if you don't change the URL that your PHP script is redirecting to then users will experience two redirects after submitting the form.
You also need to be careful to avoid a redirect loop, since you are internally rewriting the request in the opposite direction. You need to prevent the redirect being triggered after the request is rewritten. ie. Only redirect direct requests from the user should be redirected.
So, to answer your specific question, it should be rewritten something like this instead:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^survey_name=[0-9a-zA-Z]+/?$
RewriteRule ^survey_thank_you\.php$ /Thank_you [QSD,R,L]
The check against the REDIRECT_STATUS environment variable ensures that only direct requests are processed, not internally rewritten requests by the later rewrite. REDIRECT_STATUS is empty on the initial request and set to the string 200 (as in 200 OK status) after the first successful rewrite.
The QSD flag (Apache 2.4) is necessary to discard the original query string from the redirect response.
So the above would redirect /survey_thank_you.php?survey_name=<something> to /Thank_you.
But this is losing the "survey_name" (or survey_id?), so should perhaps be more like the following, in order to preserve the "survey_name":
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^survey_name=([0-9a-zA-Z]+)/?$
RewriteRule ^survey_thank_you\.php$ /%1/Thank_you [QSD,R,L]
Where %1 is a backreference to the value of the survey_name URL parameter captured in the preceding CondPattern.
However, you would then need to modify your rewrite that turns this back into an understandable URL.
(But you should probably not be doing this in the first place without first changing the actual URLs in the application.)

Safeguard files from direct access through .htaccess and php to check for session + user group

I currently have the task of coding a way to ensure that non-logged in, as well as specific user-groups on my wp-installation do not have access to files in a folder.
For that I tried using an .htaccess file that redirects all requests to a checkUser.php (which itself checks for the active session of the user as well as its role).
Then it opens the link that is given through readFile()
Unfortunately this creates a loop as a new request goes to the .htaccess file and redirects it back to checkUser.php
I tried:
Creating a Cookie for the first redirect, when that Cookie exists - delete it
<IfModule mod_rewrite.c>
RewriteEngine On
#RewriteCond %{HTTP_REFERER} !^https://adress.com/checkUser.php [NC]
RewriteCond %{HTTP_COOKIE} !transfer [NC]
RewriteCond %{REQUEST_URI} (.*)
RewriteRule ^(.*)$ https://adress.com/checkUser.php?url=$1 [R=301,CO=transfer:1:adress.com:1]
RewriteCond %{HTTP_COOKIE} transfer [NC]
RewriteRule https://adress.com/wp-content/uploads/folder_to_protect/{REQUEST_URI} [R=301,CO=transfer:1:adress.com:0]
</IfModule>
Cookie Creation works - deletion does not and I am not quite sure why
Additionally this is a not too safe way to go as you could catch on to the cookie creation and make one yourself to access the files even if it in theory would only be existent for a second or less.
Any input would be greatly appreciated.
Have a good day!

htaccess set cookie then use skip rule flag in same line

I am writing some code that redirects to a mobile verision of a website UNLESS a cookie has been set.
There is a link on the mobile site, "Go to desktop site". It's target is the desktop site with the GET variable, "noredirect=1".
The following is the code in the root .htaccess file on the desktop site. It checks for the GET variable and then sets a cookie if it exists, then skips the next rule.
# Check if this is the noredirect query string
RewriteCond %{QUERY_STRING} (^|&)noredirect=1(&|$)
# Set a cookie to say we want to stay on the desktop site
# and skip the next rule so
# that the below mobile rule does not redirect
# (cookie cannot be set AND read in one request)
RewriteRule ^ - [CO=mredir:1:%{HTTP_HOST},S=1]
The skip flag does not seem to be working. Below this code I have a few RewriteConds and one RewriteRule:
# Check to make sure we haven't set the cookie before
RewriteCond %{HTTP:Cookie} !\smredir=1(;|$)
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|iphone|ipod|iemobile|opera|mobile|palmos|webos|googlebot-mobile" [NC,OR]
RewriteCond %{HTTP:Profile} !^$
RewriteCond %{HTTP_HOST} ^(?:www\.)?((?!www\.)[^.]+)\.([^.]+\.[^.]+)$ [NC]
RewriteRule ^$ http://m.%1.%2 [L,R]
Is the skip flag meant to still work when the next rule has conditions preceding it?
Also, my main question: Is the syntax for the skip flag correct and can it be done in the same line as where one is setting a cookie?
I've tried these 2 combinations:
RewriteRule ^ - [CO=mredir:1:%{HTTP_HOST},S=1]
and
RewriteRule ^ - [CO=mredir:1:%{HTTP_HOST}] [S=1]
Neither give any errors but the skip flag still does not work.
Help would be appreciated, thanks.
See my Tips for debugging .htaccess rewrite rules for general tips on how to chop this problem. You also need to differentiate response cookies (output) from request cookies (input). The CO flag sets a response cookie, but this isn't necessarily visible in %{HTTP:Cookie} on the current pass. Either use the skip chain correctly or also set an environment variable as well and use it because this is immediately visible.

What's going on with my mod_rewrite?

I have a simple mod_rewrite system set up on my site which basically converts
http://site.com/file -> http://site.com/file.php
Here's the .htaccess file
Options -MultiViews
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.site.com
RewriteRule ^(.*)$ http://site.com/$1 [R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-z]+)/?$ http://site.com/$1.php [L]
This was working for a long time and then a couple of days ago I realized that while the RewriteRule was working, it was actually changing my URL in the status bar.
For instance, it would redirect /photos to /photos.php, but it would also change the URL to show the .php. This has never happened before and I'm not sure what happened to trigger the change.
Any ideas?
The first rewrite rule needs the [L] flag. From the mod_rewrite documentation for the [R] flag:
You will almost always want to use [R] in conjunction with [L] (that is, use [R,L]) because on its own, the [R] flag prepends http://thishost[:thisport] to the URI, but then passes this on to the next rule in the ruleset, which can often result in 'Invalid URI in request' warnings.
In this case, you don't get a warning, but appending the ".php" extension happens before issuing the redirect rather than when the second, redirected request comes in.
Also, remove the scheme and domain name from the substitution in the second rewrite rule. A full URL can cause an implicit redirect. From the documentation for RewriteRule:
The Substitution of a
rewrite rule is the string that replaces the original URL-path that
was matched by Pattern. The Substitution may
be a:
[...]
Absolute URL
If an absolute URL is specified,
mod_rewrite checks to see whether the
hostname matches the current host. If it does, the scheme and
hostname are stripped out and the resulting path is treated as
a URL-path. Otherwise, an external redirect is performed for
the given URL. To force an external redirect back to the
current host, see the [R] flag below.