Why deosn't this rewriterule work? - .htaccess

The company I currently work for has a 3+ years live site based on symfony 2.8. Recently it was deployed for testing to a new customer. The images on the original are accessed in the html like "/bundles/bundlename/images/image.png".
On the customers server however the whole thing is under a subfolder, so image url's should be like "/d2s/bundles/bundlename/images/image.png".
We have a .htaccess file in the project's web dir like this:
DirectoryIndex app.php
<IfModule mod_rewrite.c>
RewriteEngine On
FollowSymLinks On
RewriteRule /?bundles/(.*)$ /d2s/bundles/$1 [NC,R=301,L]
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the app.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
[,,,]
All other parts work fine, in apache conf's virtualhost AllowOverride is set to All. But this url rewrite just doesn't work, like if it wasn't there at all.
Any idea what can be wrong?

Set a correct RewriteBase. Don't start your internal RewriteRule patterns or substitutions with a /. If you're going to stick with with the auto determination of a RewriteBase equivalent, it should precede all other rules.

Related

Set up symfony4 URI with ONLY .htaccess

I am launching a symfony website on a server that can't be configured at all. So I can't touch the apache conf and all, I only have access to the drop repository.
So I need to use ONLY htaccess to :
point to the "public/index.php" file
Remove the "public" part from the url
I now have succeded the 1rst part with this in my lowest level .htaccess:
DirectoryIndex public/index.php public/index.html
My second .htaccess is the basic one:
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex index.php
# By default, Apache does not evaluate symbolic links if you did not enable this
# feature in your server configuration. Uncomment the following line if you
# install assets as symlinks or if you experience problems related to symlinks
# when compiling LESS/Sass/CoffeScript assets.
# Options FollowSymlinks
# Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve
# to the front controller "/index.php" but be rewritten to "/index.php/index".
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by Apache
RewriteCond %{HTTP:Authorization} .
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/index.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Rewrite all other queries to the front controller.
RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
# When mod_rewrite is not available, we instruct a temporary redirect of
# the start page to the front controller explicitly so that the website
# and the generated links can still be used.
RedirectMatch 307 ^/$ /index.php/
# RedirectTemp cannot be used instead
</IfModule>
</IfModule>
How can I do the second part ?
I believe you are solving things the other way around. The proper solution is described here https://medium.com/#runawaycoin/deploying-symfony-4-application-to-shared-hosting-with-just-ftp-access-e65d2c5e0e3d
Upload the following folders (and contents) from your application to a new folder in your root of your FTP server named symfony:
bin
config
src
templates
translations
vendor
Note: Only upload the bin folder if you want to run the console, maybe via a cron job, also best to rename console to console.php
Also create the var folder but dont upload its contents.
And upload your composer.json file to this symfony folder — this is needed to help symfony find its application files.
So you should have this on your server:
\symfony
bin
config
src
templates
translations
vendor
composer.json
\public_html
index.php
.htaccess
bundles
build
Dont forget that you will need to modify index.php
Before your application will work you need to modify your index.php file and set your env vars.
First edit your index.php (locally inside your public folder, on the server will be inside your public_html folder).
Edit this line:
require __DIR__.’/../vendor/autoload.php’;
To:
require __DIR__.’/../symfony/vendor/autoload.php’;

.htaccess - add language sub directory by default "sv/" (redirect)

Trying to orientate myself through the .htaccess jungle, I've now narrated down my rewrite problems to one - adding a language suffix upon entering the page / typing in an address that doesn't have such one.
For example: a visitor types mysite.com/kontakt. This should take them to the default language of the site, i.e. mysite.com/sv/kontakt. Or, just typing in mysite.com should take him/her to mysite.com/sv/.
I'm developing this site locally using MAMP, and the site is located in a subdirectory, and here's the tricky part... How do I sort this out in the .htaccess file?
Current code used:
RewriteBase /mysite/
RewriteCond %{REQUEST_URI} !^(sv|en)
RewriteRule ^(.*)$ sv/$1 [L,R=301]
And that takes me from localhost/mysite/ to localhost/sv/. Not exactly right.
Try this one:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /mysite/
RewriteRule ^(?!(?:sv|en)/)(.*)$ sv/$1 [R=301,L]
This needs to be placed into .htaccess file into /mysite/ folder.
If accessing localhost/mysite/sv without trailing slash, the rule will redirect it to localhost/mysite/sv/sv as it expects that the language part (sv or en) will be followed by the slash /.
P.S.
And look into setting up a VirtualHost -- then there will be much less (if none at all) of such "tricky parts" with accessing your website via http://localhost/mysite/sv/kontakt (I'm sure you will agree, that http://mysite.dev/sv/kontakt sounds and looks better).

Making a 301 rewrite from within a folder using relative rewrite URLs

I have the following problem. We used many different URLs to the same page. Now we want to use only one URL for those pages. Here an example:
RewriteRule ^(subfolder1/folder1/|(subfolder2|subfolder3)/folder2/|folder3/)?(name1|name2|name3|name4)$ scriptname.php [QSA,NC]
As you can see it is pretty messy. What I now want to do is the following: Rewrite all URLs to only one of those URLs (e.g. subfolder1/folder1/name1) using a 301 and than using a rewrite on that URL to address the actual script. It might look like this:
RewriteRule ^((subfolder2|subfolder3)/folder2/|folder3/)?(name2|name3|name4)$ /subfolder1/folder1/name1 [R=301,QSA,NC]
RewriteRule ^subfolder1/folder1/name1$ script.php [QSA.NC]
Until here I have no problem. But now comes the tricky part. We use several development machines on UNIX and Windows machines. They all have different host names and folder. Here are some examples:
http://www.example.com (production)
http://test.example.com (testing)
http://localhost/development_folder/ (development WIN)
http://localhost:8888/development_folder/ (development MAC)
The issue is, that as we have subfolders on the development machines, I can't use an absolute URL as /subfolder1/folder1/name1/ as it would e.g. point to http://localhost/subfolder1/folder1/name1/ and not to http://localhost/development_folder/subfolder1/folder1/name1/ so all the rewrites would be broken on the development machines.
Is there any chance to get this issue working? As the folder development_folderis the same on all development machines, would it help to exclude/include that folder to the rewrites afterwards like this:
RewriteRule ^((subfolder2|subfolder3)/folder2/|folder3/)?(name2|name3|name4)$ /development_folder/subfolder1/folder1/name1 [R=301,QSA,NC]
RewriteRule ^development_folder/(.*)$ $1 [QSA.NC]
RewriteRule ^subfolder1/folder1/name1$ script.php [QSA.NC]
Or is there a better way of doing it? Any hint would help a lot.
I would use Apache Include directives to modify the rule set. That way I can test the rules that will be used in production.
I don't remember if there is an issue with resolving the include wildcard to include no files, but if there is you could use an empty file in production and the actual dev rewrite rules one in dev.
RewriteRule ^((subfolder2|subfolder3)/folder2/|folder3/)?(name2|name3|name4)$ /subfolder1/folder1/name1 [R=301,QSA,NC]
Include /etc/apache/conf.d/*_dev.rewrites
RewriteRule ^subfolder1/folder1/name1$ script.php [QSA.NC]
On you dev machines and ONLY on your dev machine have the /etc/apache/conf.d/my_dev.rewrites:
RewriteRule ^development_folder/(.*)$ $1 [QSA.NC]
Wouldn't per-directory RewriteRules (inside an .htaccess) work? Then you can specify either a relative substitution (without a / in front) or, in case you need it, an absolute one (with /).
With the relative one, the base path will be stripped before rewriting and then prefixed again. Perhaps, you'll need to tune RewriteBase for this to work correctly (hmm, differently for your different servers...).
I think there is a more deep problem with that dev/production servers layout but I suppose you have your reasons.
This can help you:
# dev
RewriteCond %{HTTP_HOST} ^localhost$ [NC]
RewriteRule ^((subfolder2|subfolder3)/folder2/|folder3/)?(name2|name3|name4)$ /subfolder1/folder1/name1 [R=301,QSA,NC]
RewriteRule ^subfolder1/folder1/name1$ script.php [QSA.NC]
# production
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^((subfolder2|subfolder3)/folder2/|folder3/)?(name2|name3|name4)$ /dev_folder/subfolder1/folder1/name1 [R=301,QSA,NC]
RewriteRule ^dev_folder/subfolder1/folder1/name1$ script.php?dev=1 [QSA.NC]
The idea is to use the hostname to have a different set of rules. You can use dev1.example.com, dev2.example.com, etc as needed adding that 'fake' domains to /etc/hosts as alias of 127.0.0.1

Redirect all .php traffic to .php5 files

I have a personal website with a MediaWiki installation on a shared host. The Apache configuration treats all .php request with PHP 4, and all .php5 requests with PHP5.
For compatibility reasons I need to be able to use the .php extension, but MediaWiki is only available on PHP5. I tried to use the mod_rewrite engine, but I'm stuck with the rule.
Here's the current file:
DirectoryIndex index.php5
RewriteEngine on
# This rewrites URIs in the form /pages/Article_Name to /index.php5?title=Article_Name.
RewriteCond %{REQUEST_URI} !^/pages/index.php5.*$ [NC]
RewriteRule ^pages/?(.*)$ /index.php5?title=$1 [L]
# This is the broken rule
RewriteCond %{REQUEST_URI} ^index\.php(([^5])(.*))?$ [NC]
RewriteRule ^index\.php(([^5])(.*))?$ /index.php5?$1 [L]
The idea of the rule was "Redirect all content from index.php (not followed by '5') to index.php5".
Any idea?
Edit:
SetEnv PHP_VER 5
works, but I'm still interested on why the rule was not taken into account.
RewriteEngine On
RewriteBase /
RewriteRule ^(.*)\.php $1.php5 [R=301,L]
RewriteRule ^(.*)\.php $1.php5 [L]
I found this on the following web site which may be useful, you could make it more specific and remove the catchall to change only a certain number of .php files if you liked.
You can also customize it to suit only a certain directory using the RewriteBase condition.
I would change hosts, you shouldn't have to have php applications state their version after the extension. It was ghetto with PHP3 and very ghetto and bad practice for php5.
While of course its possible this is bad practice and you will most likely never see an OSS application built around a php5 file extension naming convention.
I would quit while you're ahead and jump ship on a bad host - not try and alter how an application like mediawiki is built to operate. The hosts I've seen that have both php4 and php5 allow you to choose which install you would like to run for the domain - not designate it with a file extension. Thats ghetto.
Try this
AddType x-mapp-php .php5
It might be the other way around, try it though, i cant atm :S
The REQUEST_URI value always starts with a slash but your pattern doesn’t.
This seems to work for me:
AddType application/x-httpd-php5 .php

How does RewriteBase work in .htaccess

I have seen this in a few .htaccess examples
RewriteBase /
It appears to be somewhat similar in functionality to the <base href=""> of HTML.
I believe it may automatically prepend its value to the beginning of RewriteRule statements (possibly ones without a leading slash)?
I could not get it to work properly. I think it's use could come in very handy for site portability, as I often have a development server which is different to a production one. My current method leaves me deleting portions out of my RewriteRule statements.
Can anyone explain to me briefly how to implement it?
Thanks
RewriteBase is only applied to the target of a relative rewrite rule.
Using RewriteBase like this...
RewriteBase /folder/
RewriteRule a\.html b.html
is essentially the same as...
RewriteRule a\.html /folder/b.html
But when the .htaccess file is inside /folder/ then this also points to the same target:
RewriteRule a\.html b.html
Although the docs imply always using a RewriteBase, Apache usually detects it correctly for paths under the DocumentRoot unless:
You are using Alias directives
You are using .htaccess rewrite rules to perform HTTP redirects (rather than just silent rewriting) to relative URLs
In these cases, you may find that you need to specify the RewriteBase.
However, since it's a confusing directive, it's generally better to simply specify absolute (aka 'root relative') URIs in your rewrite targets. Other developers reading your rules will grasp these more easily.
Quoting from Jon Lin's excellent in-depth answer here:
In an htaccess file, mod_rewrite works similar to a <Directory> or <Location> container. and the RewriteBase is used to provide a relative path base.
For example, say you have this folder structure:
DocumentRoot
|-- subdir1
`-- subdir2
`-- subsubdir
So you can access:
http://example.com/ (root)
http://example.com/subdir1 (subdir1)
http://example.com/subdir2 (subdir2)
http://example.com/subdir2/subsubdir (subsubdir)
The URI that gets sent through a RewriteRule is relative to the directory containing the htaccess file. So if you have:
RewriteRule ^(.*)$ -
In the root htaccess, and the request is /a/b/c/d, then the captured URI ($1) is a/b/c/d.
If the rule is in subdir2 and the request is /subdir2/e/f/g then the captured URI is e/f/g.
If the rule is in the subsubdir, and the request is /subdir2/subsubdir/x/y/z, then the captured URI is x/y/z.
The directory that the rule is in has that part stripped off of the URI. The rewrite base has no affect on this, this is simply how per-directory works.
What the rewrite base does do, is provide a URL-path base (not a file-path base) for any relative paths in the rule's target. So say you have this rule:
RewriteRule ^foo$ bar.php [L]
The bar.php is a relative path, as opposed to:
RewriteRule ^foo$ /bar.php [L]
where the /bar.php is an absolute path. The absolute path will always be the "root" (in the directory structure above). That means that regardless of whether the rule is in the "root", "subdir1", "subsubdir", etc. the /bar.php path always maps to http://example.com/bar.php.
But the other rule, with the relative path, it's based on the directory that the rule is in. So if
RewriteRule ^foo$ bar.php [L]
is in the "root" and you go to http://example.com/foo, you get served http://example.com/bar.php. But if that rule is in the "subdir1" directory, and you go to http://example.com/subdir1/foo, you get served http://example.com/subdir1/bar.php. etc. This sometimes works and sometimes doesn't, as the documentation says, it's supposed to be required for relative paths, but most of the time it seems to work. Except when you are redirecting (using the R flag, or implicitly because you have http://host in your rule's target). That means this rule:
RewriteRule ^foo$ bar.php [L,R]
if it's in the "subdir2" directory, and you go to http://example.com/subdir2/foo, mod_rewrite will mistake the relative path as a file-path instead of a URL-path and because of the R flag, you'll end up getting redirected to something like: http://example.com/var/www/localhost/htdocs/subdir1. Which is obviously not what you want.
This is where RewriteBase comes in. The directive tells mod_rewrite what to append to the beginning of every relative path. So if I have:
RewriteBase /blah/
RewriteRule ^foo$ bar.php [L]
in "subsubdir", going to http://example.com/subdir2/subsubdir/foo will actually serve me http://example.com/blah/bar.php. The "bar.php" is added to the end of the base. In practice, this example is usually not what you want, because you can't have multiple bases in the same directory container or htaccess file.
In most cases, it's used like this:
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
where those rules would be in the "subdir1" directory and
RewriteBase /subdir2/subsubdir/
RewriteRule ^foo$ bar.php [L]
would be in the "subsubdir" directory.
This partly allows you to make your rules portable, so you can drop them in any directory and only need to change the base instead of a bunch of rules. For example if you had:
RewriteEngine On
RewriteRule ^foo$ /subdir1/bar.php [L]
RewriteRule ^blah1$ /subdir1/blah.php?id=1 [L]
RewriteRule ^blah2$ /subdir1/blah2.php [L]
...
such that going to http://example.com/subdir1/foo will serve http://example.com/subdir1/bar.php etc. And say you decided to move all of those files and rules to the "subsubdir" directory. Instead of changing every instance of /subdir1/ to /subdir2/subsubdir/, you could have just had a base:
RewriteEngine On
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
RewriteRule ^blah1$ blah.php?id=1 [L]
RewriteRule ^blah2$ blah2.php [L]
...
And then when you needed to move those files and the rules to another directory, just change the base:
RewriteBase /subdir2/subsubdir/
and that's it.
In my own words, after reading the docs and experimenting:
You can use RewriteBase to provide a base for your rewrites. Consider this
# invoke rewrite engine
RewriteEngine On
RewriteBase /~new/
# add trailing slash if missing
rewriteRule ^(([a-z0-9\-]+/)*[a-z0-9\-]+)$ $1/ [NC,R=301,L]
This is a real rule I used to ensure that URLs have a trailing slash. This will convert
http://www.example.com/~new/page
to
http://www.example.com/~new/page/
By having the RewriteBase there, you make the relative path come off the RewriteBase parameter.
AFAIK, RewriteBase is only used to fix cases where mod_rewrite is running in a .htaccess file not at the root of a site and it guesses the wrong web path (as opposed to filesystem path) for the folder it is running in. So if you have a RewriteRule in a .htaccess in a folder that maps to http://example.com/myfolder you can use:
RewriteBase myfolder
If mod_rewrite isn't working correctly.
Trying to use it to achieve something unusual, rather than to fix this problem sounds like a recipe to getting very confused.
RewriteBase is only useful in situations where you can only put a .htaccess at the root of your site. Otherwise, you may be better off placing your different .htaccess files in different directories of your site and completely omitting the RewriteBase directive.
Lately, for complex sites, I've been taking them out, because it makes deploying files from testing to live just one more step complicated.
When I develop, it's on a different domain within a folder. When I take a site live, that folder doesn't exist anymore. Using RewriteBase allows me to use the same .htaccess file in both environments.
When live:
RewriteBase /
# RewriteBase /dev_folder/
When developing:
# RewriteBase /
RewriteBase /dev_folder/
The clearest explanation I found was not in the current 2.4 apache docs, but in version 2.0.
# /abc/def/.htaccess -- per-dir config file for directory /abc/def
# Remember: /abc/def is the physical path of /xyz, i.e., the server
# has a 'Alias /xyz /abc/def' directive e.g.
RewriteEngine On
# let the server know that we were reached via /xyz and not
# via the physical path prefix /abc/def
RewriteBase /xyz
How does it work? For you apache hackers, this 2.0 doc goes on to give "detailed information about the internal processing steps."
Lesson learned: While we need to be familiar with "current," gems can be found in the annals.
This command can explicitly set the base URL for your rewrites. If you wish to start in the root of your domain, you would include the following line before your RewriteRule:
RewriteBase /
I believe this excerpt from the Apache documentation, complements well the previous answers :
This directive is required when you use a relative path in a
substitution in per-directory (htaccess) context unless either of the
following conditions are true:
The original request, and the substitution, are underneath the DocumentRoot (as opposed to reachable by other means, such as Alias).
The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on
the server (this is rare).
As previously mentioned, in other contexts, it is only useful to make
your rule shorter. Moreover, also as previously mentioned, you can
achieve the same thing by placing the htaccess file in the
subdirectory.
I simply delete .htaccess file and it runs perfectly

Resources