Rewriting an Apache RewriteRule? - apache

In my application's .htaccess file I have the following:
Options -Indexes
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+) index.php
A very lightweight file that puts all unmatched requests through index.php.
However, this application is a social networking website that I've been tasked with making multi-lingual. Therefore, URLs like www.example.com/profile/martin need to be converted in to say, Spanish, and will therefore become www.example.com/perfil/martin.
Therefore, my question is: is it possible to rewrite a RewriteRule? In this instance, I want to rewrite /perfil/martin to /profile/martin, but then have /profile/martin passed to index.php.

Adding the following line before the 'RewriteRule ^(.+) index.php' line should achieve what you want.
RewriteRule perfil/(.*) profile/$1
I'd argue that you should be doing this in your web app's URL routing code though, rather than the htaccess file.

Related

Why htaccess rules in subfolder stops parent htaccess rules from working? [duplicate]

been searching for 2 days and can't quite get the right solution due to my lack of understanding of mod_rewrite and time constraints on this project so hoping someone can help.
The aim
To rewrite all requests to the root index.php if the client doesn't have the correct cookie.
If the client has the correct cookie allow them to browse as they wish.
The problem
The htaccess in my subdirectory is taking precendence over my root htaccess, so requests such as www.mydomain.com/subdir/index.php arn't getting redirected.
My root .htaccess
Options FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_COOKIE} !^.*pass.*$
RewriteCond %{REQUEST_URI} !^/index.php$
RewriteRule ^(.*)$ http://www.mydomain.com/index.php?url=$0 [NC]
My subdir htaccess
RewriteEngine On
RewriteBase /
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?/$1 [L]
Additional info
Ideally I'm trying to create a password protected area, so all requests are routed to index.php where a password can be entered and when verified a cookie is created, allowing free browsing of contents and sub directories. So if there is a better way to accomplish this then please let me know, and I havn't gone for .htpasswd since I need custom login, error and splash pages.
Also, the subdir .htaccess is an ExpressionEngine URL handler.
Thanks.
To allow execution of rewrite rules from parent .htaccess (htaccess from parent folder), you need to explicitly allow it (Apache will treat rewrite rules in current .htaccess as the only one that need to be executed, as long as rewritten URL remains in the same subfolder).
You need to add this line to your .htaccess in sub-folder:
RewriteOptions inherit
Apache manual: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions

mod_rewrite - Removing index.php from URL (in subfolder)

I'm trying to get an API working (locally, for now), which lives in a subfolder. I've been trying every example I can find, but all are ending up in 404 errors.
I have this URL:
http://127.0.0.1/~owner/personal/api/v1/index.php/tasks
I want to be able to use this:
http://127.0.0.1/~owner/personal/api/v1/tasks
Eventually, it will become this:
http://api.mydomain.com/tasks
I just can't seem to get my .htaccess rules setup correctly. This keeps getting suggested, but does nothing:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
What am I missing?
Update
I have setup my virtual hosts to use http://api.local/ instead of the previously used addresses.
Accessing http://api.local/index.php/tasks works.
Accessing http://api.local/tasks does not.
Maybe part of your problem is your development environment. You are using a local server to do this on with several subfolders deep and I think it's messing with your .htaccess depending on the location.
If your .htaccess is in the root of your website http://127.0.0.1/.htaccess then it's not going to work properly.
Make sure it's in the same directory as your index.php file and make sure /~owner/personal/api/v1/ is your document root for your dev environment as specified in your apache config file.
Then you can test out your htaccess rules and see how they work. Your current rule should be ok providing /tasks won't be a real directory in the root.
On another note,
I always suggest using your real domain name so you could see how it works as if it were in production. You can do that by modifying your HOST file on your PC and the site will only available to you and you can access via yoursite.com. This quick easy guide will show you.
Try specifying the rewrite base.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
You are using the parameters of RewriteRule backwards. You need this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?(.*?)/index.php(.+)?$ /$1$2
This means:
if it's not a file
and it's not a directory
and it looks like / (optional), possibly some more characters, then /index.php, then possibly some more characters, go to the URL without the /index.php part.
Note that I deleted the [L] for now -- it means "if the URL matches this rule, don't apply any more rules." You say you want to keep transforming it into http://api.mydomain.com/tasks, so you shouldn't use [L].

Redirect all to index.php using htaccess

I am writing a simple PHP-based MVC-ish framework. I want this framework to be able to be installed in any directory.
My PHP script grabs the request uri and breaks it off into segments. It makes segment 1 the controller and segment 2 the action. This goes all fine when I do this:
http://www.example.com/mvc/module/test/
It will go to the specific module controller and method. Now I have a default controller, the home controller, which is in folder home.
Now when I access this folder directly http://www.example.com/mvc/home/
It will display a 403 forbidden , because this folder does exist, instead it should also go back to http://www.example.com/mvc/index.php
If I would have installed the framework in a different folder, lets say folder framework it has to redirect back to http://www.example.com/framework/index.php
I would like to redirect every folder and php file back to the index.php, leaving everything else the way it is.
My first problem I encountered was it never redirects to the right folder, always to the domain root folder.
This is what I tried :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
Your rewrite rule looks almost ok.
First make sure that your .htaccess file is in your document root (the same place as index.php) or it'll only affect the sub-folder it's in (and any sub-folders within that - recursively).
Next make a slight change to your rule so it looks something like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?path=$1 [NC,L,QSA]
At the moment you're just matching on . which is one instance of any character, you need at least .* to match any number of instances of any character.
The $_GET['path'] variable will contain the fake directory structure, so /mvc/module/test for instance, which you can then use in index.php to determine the Controller and actions you want to perform.
If you want the whole shebang installed in a sub-directory, such as /mvc/ or /framework/ the least complicated way to do it is to change the rewrite rule slightly to take that into account.
RewriteRule ^(.*)$ /mvc/index.php?path=$1 [NC,L,QSA]
And ensure that your index.php is in that folder whilst the .htaccess file is in the document root.
Alternative to $_GET['path'] (updated Feb '18 and Jan '19)
It's not actually necessary (nor even common now) to set the path as a $_GET variable, many frameworks will rely on $_SERVER['REQUEST_URI'] to retrieve the same information - normally to determine which Controller to use - but the principle is exactly the same.
This does simplify the RewriteRule slightly as you don't need to create the path parameter (which means the OP's original RewriteRule will now work):
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]
However, the rule about installing in a sub-directory still applies, e.g.
RewriteRule ^.*$ /mvc/index.php [L,QSA]
The flags:
NC = No Case (not case sensitive, not really necessary since there are no characters in the pattern)
L = Last (it'll stop rewriting at after this Rewrite so make sure it's the last thing in your list of rewrites)
QSA = Query String Append, just in case you've got something like ?like=penguins on the end which you want to keep and pass to index.php.
To redirect everything that doesnt exist to index.php , you can also use the FallBackResource directive
FallbackResource /index.php
It works same as the ErrorDocument , when you request a non-existent path or file on the server, the directive silently forwords the request to index.php .
If you want to redirect everything (including existant files or folders ) to index.php , you can use something like the following :
RewriteEngine on
RewriteRule ^((?!index\.php).+)$ /index.php [L]
Note the pattern ^((?!index\.php).+)$ matches any uri except index.php we have excluded the destination path to prevent infinite looping error.
There is one "trick" for this problem that fits all scenarios, a so obvious solution that you will have to try it to believe it actually works... :)
Here it is...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>
Basically, you are asking MOD_REWRITE to forward to index.php the URI request always when a file exists AND always when the requested file doesn't exist!
When investigating the source code of MOD-REWRITE to understand how it works I realized that all its checks always happen after the verification if the referenced file exists or not. Only then the RegEx are processed. Even when your URI points to a folder, Apache will enforce the check for the index files listed in its configuration file.
Based on that simple discovery, turned obvious a simple file validation would be enough for all possible calls, as far as we double-tap the file presence check and route both results to the same end-point, covering 100% of the possibilities.
IMPORTANT: Notice there is no "/" in index.php. By default, MOD_REWRITE will use the folder it is set as "base folder" for the forwarding. The beauty of it is that it doesn't necessarily need to be the "root folder" of the site, allowing this solution work for localhost/ and/or any subfolder you apply it.
Ultimately, some other solutions I tested before (the ones that appeared to be working fine) broke the PHP ability to "require" a file via its relative path, which is a bummer. Be careful.
Some people may say this is an inelegant solution. It may be, actually, but as far as tests, in several scenarios, several servers, several different Apache versions, etc., this solution worked 100% on all cases!
You can use something like this:
RewriteEngine on
RewriteRule ^.+$ /index.php [L]
This will redirect every query to the root directory's index.php. Note that it will also redirect queries for files that exist, such as images, javascript files or style sheets.
Silly answer but if you can't figure out why its not redirecting check that the following is enabled for the web folder ..
AllowOverride All
This will enable you to run htaccess which must be running! (there are alternatives but not on will cause problems https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride)
just in case you were still wondering how to redirect all request either if the directory exists (for core framework folders and files) to the framework index handler, after some error/success attempts just noticed I just needed to change the RewriteCond in the .htaccess file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
the above condition states "not found files" and "not found directories", ok, what if just remove "not found" (!-d) line, and ended with something like the below:
RewriteEngine on
RewriteBase /framework/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /framework/index.php [L,QSA]
It worked for me like a charm
I just had to face the same kind of issue with my Laravel 7 project, in Debian 10 shared hosting. I have to add RewriteBase / to my .htaccess within /public/ directory. So the .htaccess looks a like
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]
After doing that don't forget to change your href in,
home
Example:
.htaccess file
RewriteEngine On
RewriteRule ^about/$ /about.php
PHP file:
about

why doesn't this .htacess file prevent users from accessing content I want secured?

I am trying to accomplish several things with this .htacess file, but cannot seem to
get it to serve the rewrites I need, while preventing unathorized access to files I want
hidden. My goal is to allow any file located in /sections/section_name/webroot/ to be accessed through /section_name/. So, /admin/images/kittens/cat.jpg would serve up /sections/admin/webroot/images/kittens/cat.jpg if it existed. I want to be able to have multiple sections. If a section is not specified, but the file exists in /sections/default/webroot, then I'd like for that to be served. Any other request should
go to /dispatcher.php. I thought I had this working, until I requested a configuration
file in /config and was able to see it. Then I realized I could basically view any file
if I knew that path.
How can I fix this security issue while still keeping the rewrites working?
Here is my .htacess file:
Options +FollowSymlinks -MultiViews -Indexes
RewriteEngine On
# If a file is requested in the admin webroot, and it exists, allow it to pass through
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^admin(/.*)$ sections/admin/webroot/$1 [L,QSA]
# if the requested url begins with /customers and it is located in /sections/customers/webroot
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^customers(/.*)$ sections/customers/webroot/$1 [L,QSA]
# if the requested url begins with /resellers and it is located in /sections/resellers/webroot
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^resellers(/.*)$ sections/resellers/webroot/$1 [L,QSA]
# if the requested file does not begin with /admin, /customers, or /resellers, and is in /sections/default/webroot, then serve it
RewriteCond %{DOCUMENT_ROOT}/sections/default/webroot/$1 -f
RewriteRule ^(.*)$ sections/default/webroot/$1 [QSA,L,NC]
# Send everything else to the dispatcher
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ dispatcher.php [QSA,L]
I know this isn't quite a solution, but have you tried cutting it all the way down and then adding the rules back one by one, testing each one along the way? For starters, if you can get files in /config that you're not supposed to, I'd try cutting everything except the final rule (which is supposed to send requests in /config to dispatcher) and see if that works. If it does, keep adding things back slowly until you see which specific rule is allowing /config files to be seen. Then you know what to fix.
Adding this to the end worked. Anything that wasn't a valid file requested in one of the
webroot folders, and that wasn't a call to dispatcher.php, was redirected to dispatcher.
RewriteCond %{REQUEST_URI} !=/dispatcher.php
RewriteCond %{REQUEST_URI} !^/sections/[a-zA-Z0-9_-]+/webroot/
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule ^(.*)$ dispatcher.php [QSA,L]

How would I go about creating a mod_rewrite that redirects to launch.php?i=/the/url/that/they/want?

So if the user types mydomain.com/dashboard, the document the server actually sends them is /launch.php?i=/dashboard.
The one caveat is that I would like to leave requests for
/flags
/people
/posters
/css
/icons
/images
/libraries
/patterns
alone, and they should request the actual folder.
How would I create such a mod_rewrite?
This is the .htaccess file for the CakePHP Framework.
Please replace the index.php and ?url= to fit your needs.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
The "!-d" tells Apache to follow existing folders and "!-f" to follow existing files.
Everything else is channelled through index.php
As suggested in a comment, you have to be aware that if it's not working it could be because mod_rewrite is not enabled and you'll not get an error stating that fact, you'll probably only have a HTTP 404.