I have a problem with showing images and css files on my site when using RewriteRule on .htaccess file:
RewriteEngine On
RewriteRule ^home/?$ page.php?id=home [L,QSA]
RewriteRule ^stats/?$ statspage.php?id=abcd [L,QSA]
...but the images and css files not loaded.
Add a RewriteCond before each RewriteRule:
RewriteEngine On
RewriteCond %{REQUEST_URI} !\.(gif|jpe?g|png|css)$ [NC]
RewriteRule ^home/?$ page.php?id=home [L,QSA]
RewriteCond %{REQUEST_URI} !\.(gif|jpe?g|png|css)$ [NC]
RewriteRule ^stats/?$ statspage.php?id=abcd [L,QSA]
RewriteCond provides more detailed qualifications for a particular RewriteRule.
%{REQUEST_URI} is a server variable. It provides the requested URL path, i.e, the portion after the domain name, but not including the query string.
The condition I added to your rules allows all URLs that end in the listed extensions to skip that particular rewrite. Which means Apache can send the resource as it is requested.
The exclamation mark ! means NOT.
Periods have a special meaning in regular expressions so if you want to match an actual period they need to be escaped with a backslash: \..
The combination of parenthesis: () and pipes: | create alternating lists: (gif|jpe?g|png|css). So here any extension will match: gif OR jpeg OR jpg OR png OR css. The question mark after the e in jpe?g makes the e optional, hence jpeg OR jpg.
The dollar sign $ means "end of string", so the matched pattern must be the last thing in the URL path.
In English: Apache mod_rewrite is instructed to match URL paths that do NOT end in a period followed by either "gif", "jpeg", "jpg", "png", or "css". Therefore URLs that do match (images and css) skip the rule.
Related
I am new to .htaccess and I don't understand it well. Recently I have built the following code:
RewriteEngine On
RewriteCond %{HTTP_HOST} (.*)
RewriteCond %{REQUEST_URI} /api/v2/
RewriteRule ^api/v2(.*) /api/v2/api.php?input=$1
This was in the root public folder (example.com/.htaccess). But now I have to create second Rewrite and I want to make .htaccess file in example.com/api/v2/ folder. I tried to remove /api/v2/ part in each Rewrite Rule, but only thing I got was error 500.
What I want to achieve:
If someone uses this link: https://example.com/api/v2/test/test/123, I'd like to make it into https://example.com/api/v2/api?input=test/test/123 with .htaccess located in example.com/api/v2 folder.
Addressing your existing rule first:
RewriteCond %{HTTP_HOST} (.*)
RewriteCond %{REQUEST_URI} /api/v2/
RewriteRule ^api/v2(.*) /api/v2/api.php?input=$1
The first RewriteCond (condition) is entirely superfluous and can simply be removed. The second condition simply asserts that there is a slash after the v2 and this can be merged with the RewritRule pattern. So, the above is equivalent to a single RewriteRule directive as follows:
RewriteRule ^api/v2(/.*) /api/v2/api.php?input=$1 [L]
This would internally rewrite the request from /api/v2/test/test/123 to /api/v2/api.php?input=/test/test/123 - note the slash prefix on the input URL parameter value.
However, unless you have another .htaccess file in a subdirectory that also contains mod_rewrite directives then this will create a rewrite loop (500 error).
Also note that you should probably include the L flag here to prevent the request being further rewritten (if you have other directives).
If someone uses this link: https://example.com/api/v2/test/test/123, I'd like to make it into https://example.com/api/v2/api?input=test/test/123 with .htaccess located in example.com/api/v2 folder.
I assume /api? is a typo and this should be /api.php?. Note also that the slash is omitted from the start of the URL parameter value (different to the rule above).
I tried to remove /api/v2/ part in each Rewrite Rule, but only thing I got was error 500.
This is the right idea, however, you need to be careful of rewrite loops (ie. 500 error response) since the rewritten URL is likely matching the regex you are trying to rewrite.
Try the following instead in the /api/v2/.htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_URI} !api\.php$
RewriteRule (.*) api.php?input=$1 [L]
The preceding RewriteCond directive checks that the request is not already for api.php, thus avoiding a rewrite loop, since the pattern .* will naturally match anything, including api.php itself.
You could avoid the additional condition by making the regex more specific. For example, if the requested URL-path cannot contain a dot then the above RewriteCond and RewriteRule directives can be written as a single directive:
RewriteRule ^([^.]*)$ api.php?input=$1 [L]
The regex [^.]* matches anything except a dot, so avoids matching api.php.
Alternatively, only match the characters that are permitted. For example, lowercase a-z, digits and slashes (which naturally excludes the dot), which covers your test string test/test/123:
RewriteRule ^([a-z0-9/]*)$ api.php?input=$1 [L]
Or, if there should always be 3 path segments, /<letters>/<letters>/<digits>, then be specific:
RewriteRule ^([a-z]+/[a-z]+/\d+)$ api.php?input=$1 [L]
I am making a website builder an I would like to make urls prettier.
The url would be for example:
https://ccc-bb.example.com => https://example.com/project/show/ccc/bb
This is my .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
# prevents files starting with dot to be viewed by browser
RewriteRule /\.|^\.(?!well-known/) - [F]
# front controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\-(.*)$ https://example.com/project/show/$1/$2 [L]
When I use above (https://ccc-bb.example.com) it sends me to the subdomain empty folder. The folder has only the .htaccess file.
What am I missing? I've never edited an .htaccess file and Google didn't help me (or I don't know what should I looking for).
Your first rule for dotfiles is okay but would be better the other way around, since the second part can only match the start, but the first can only match in subdirectories.
RewriteRule ^\.(?!well-known/)|/\. - [F]
Your other rule's problem is that you are expecting it to match the subdomain. RewriteRules do not operate on the entire string you see in your browser's address bar, only the path part, and in .htaccess they see even less as the leading directory is stripped off, too. To access the info you want, use a RewriteCond:
RewriteCond %{HTTP_HOST} ^([^-]++)-([^-.]++)\.example\.com$
RewriteRule ^(?!project/show/).* project/show/%1/%2/$0 [L,DPI]
(You don't need to include \.example\.com$ if your main domain contains no hyphens.)
I have an old site where I have underscores and an html extension which I want to redirect in the following way
http://example.com/news/this_is_a_test.html -> http://example.com/post/this-is-a-test
http://example.com/portfolio/another_test.html -> http://example.com/project/another-test
There are other folders apart from news and portfolio and clearly the final segment of the url has an unknown number of underscores.
Here is the .htaccess I am using at the moment (based on my original question htaccess file to remove folder, and replace underscores with dashes). It works for the news example, but breaks if I try for portfolio.
Any idea where I'm going wrong?
RewriteEngine on
# redirect "/news_bar" to "/foo_bar"
RewriteRule ^news/(.+)$ /$1 [L,R]
#2 replace underscore with hypens
RewriteRule (.*)_(.*) $1-$2 [N,E=uscores:yes]
RewriteCond %{ENV:uscores} yes
RewriteRule ^(.+)$ /post/$1 [L,R]
RewriteRule ^portfolio/(.+)$ /$1 [L,R]
RewriteRule (.*)_(.*) $1-$2 [N,E=uscores:yes]
RewriteCond %{ENV:uscores} yes
RewriteRule ^(.+)$ /project/$1 [L,R]
# remove .html from end of url
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]
Many thanks!
I had a solution for this before, but it is breaking on my current setup (Apache crashes), and so it would be unwise of me to recommend it for your case. (It could be an issue with my setup, but I'd prefer to give you a more straight-forward route.)
This solution involves sending the relevant requests to a PHP file that will do the necessary replacements, and redirect once only. Note that your current implementation will send multiple redirect instructions to the browser. This is not only bad from a user experience point of view, but also from an SEO one.
To implement the solution, start by replacing your .htaccess directives with this:
RewriteEngine On
# Rewrite news and portfolio links to redirect.php
RewriteRule ^(news|portfolio)/(.+).html /redirect.php [L]
Then, create a redirect.php file in the same directory as your .htaccess file (in this case, your document root), and fill it with this simple replacement method and redirect instruction:
<?php
$path = $_SERVER['REQUEST_URI'];
# Perform the necessary replacements. The first array contains
# what we're searching for, bit by bit, and the second array
# contains the relevant replacements.
$path = str_replace(
['_', '/news/', '/portfolio/', '.html'],
['-', '/post/', '/project/', ''],
$path);
# Now, simply redirect to the new path.
# Change 302 to 301 use a "Moved Permanently" header,
# resulting in browsers and search engines caching
# the redirect.
header("Location: $path", true, 302);
For example:
google.com/en/game/game1.html
should be
google.com/index.php?p1=en&p2=game&p3=game1.html
how can i split URL and send index.php the part of "/" ?
You can only achieve this if the query parameters are of a fixed length. Otherwise there is an other way but requires parsing of the path in the application.
Fixed length implementation
The following rule matches all three URL parts then rewrites them as named query arguments to index.php.
RewriteRule ^([^/]+)/([^/]+)/(.+)$ index.php?p1=$1&p2=$2&p3=$3
This rewrites:
/en/game/game1.html
To:
/index.php?p1=en&p2=game&p3=game1.html
Unknown length implementation
# Don't rewrite if file exist. This is to prevent rewriting resources like images, scripts etc
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php?path=$0
This rewrites:
/en/game/game1.html
To:
/index.php?path=en/game/game1.html
Then you can parse the path in the application.
Edit:) To make it so the rewrite rule only matches if the first level of the URL consists of two characters do:
RewriteRule ^([a-zA-Z]{2})/([^/]+)/(.+)$ index.php?p1=$1&p2=$2&p3=$3
You can also do it for the unknown length implementation so:
RewriteRule ^[a-zA-Z]{2}/ index.php?path=$0
Well lets say I have this follow code in my htaccess file,
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^/]+)$ $1.php
RewriteRule ^forums/([0-9]+) forums.php?category=$1 [NC]
I was wondering how would I, with the above code, redirect certain extensions in a url to my websites 404 page.
For instance, if this link mywebsite.com/forums has any extension at the end of it such as .asp, .php, .html, and so forth it then would get redirected to my 404 page.
And on a quick side note how can I limit the last RewriteRule to only a certain forward slash where mywebsite.com/forums/2 would show the page fine and anything after that certain limit such as mywebsite.com/forums/2/so on... would be redirected to my 404 page.
Anyone have any ideas?
If I understand the question properly, then you need to firm up the regular expressions to only match the patterns you really want - at the moment, they're a bit too lenient for your needs.
For example:
RewriteRule ^([^/]+)$ $1.php
This will match anything without a trailing slash, whereas if you wanted to restrict it to only match, say, things without a trailing slash and consisting of alphanumeric characters, then you might do this:
RewriteRule ^([a-zA-Z0-9]+)$ $1.php
(You could achieve the same effect for certain extensions only by using a lookahead assertion, but that complicates your regular expression. I feel it's probably saner (and easier on the mind) to think about the patterns you really want matched, and then express those up-front.)
Likewise, your latter example:
RewriteRule ^forums/([0-9]+) forums.php?category=$1 [NC]
will match anything which starts with the string forums/, followed by one or more digits, whether or not there's anything after that. Adding an end anchor ($) as you have above
RewriteRule ^forums/([0-9]+)$ ...
will assert that the string ends after the digits.
This relies on the fact that if mod_rewrite can't find a match, it won't attempt any rewrites, and will (in the absence of any explicit resource at that path) fall through to Apache's 404 handling, which is then up to you to override.