How to check time spent by mod_rewrite when rewrite urls? - apache

My question is simple:
Is it possible to know the time elapsed when apache mod_rewrite rewrite urls ?
My site has about 20 million requests/month.
In this case, I want to know the time spent in these rules.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# Remove Multiple slashes in betweeen
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
# Send everything to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ some_path/index.php/$1 [L]
</IfModule>
Thanks in advance

Move rewriting to VirtualHost configuration if possible, so regular expressions are not compiled for each request in .htaccess.
For example, for Apache, in httpd.conf place your content of .htaccess like this:
<Directory /www/htdocs/example>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# Remove Multiple slashes in betweeen
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
# Send everything to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ some_path/index.php/$1 [L]
</IfModule>
</Directory>

You could check the "waiting" time in Firebug or other Browser tools to check how much time is spent between the request and your browser actually receives data.
Redirecting to static ressources would of course be better to avoid evaluating the time PHP takes to process the request.
Of coure it will still include the time Apache normally spends treating the request and you probably want to test both scenarios: with redirect and without.
BTW, if you're looking to optimize these, you could try replacing this :
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
With this :
RewriteRule ^(.*)//(.*)$ $1/$2 [R=301,L]
There's no real need to use this kind of rewritecond alone, a more complex rewrite rule is enough.
Also,
RewriteRule ^(.*)$ some_path/index.php/$1 [L]
Can be replaced with
RewriteRule (.*) some_path/index.php/$1 [L]
Starting and ending character won't be sent in $1 so it can be included in the rule, hence simplifying it.

Related

Apache RewriteRule not working – page not found

I have no idea why it doesn't work, /spelling/30000 gives the Not Found page. Please help.
RewriteEngine On
RewriteBase /
RewriteRule ^/([0-9]+)$ /?mod=spelling&word=$1 [PT]
RewriteRule ^$ /?mod=spelling [PT]
With your shown samples please try following .htaccess rules file. Considering that index.php file is the one which is taking traffic in backend for internal rewrite rules. Please make sure to keep your .htaccess file along side with index.php file.
Also make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteBase /
RewriteRule ^/?$ index.php?mod=spelling [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/([^/]*)/?$ index.php?mod=$1&word=$2 [QSA,L]

.htaccess 301 redirect with exclusion does not work

I try to use a simple 301 redirect
from domain1.com/folder/ to domain2.com/
but excluding domain1.com/folder/subfolder
I use the following code in .htaccess:
RedirectMatch 301 ^/folder/((?!subfolder).*)$ https://domain2.com/$1
but it simply redirects all the requests, including the requests to subfolder.
Please, help to fix the line to make it work as described. Thank you!
here is the complete code of .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /folder/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]
</IfModule>
RedirectMatch 301 ^/folder/((?!subfolder).*)$ https://domain2.com/$1
Try it like this using mod_rewrite instead:
(NB: This assumes the .htaccess file is located in the document root.)
# /.htaccess
# Redirect all direct requests, except "subfolder"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $1 !^subfolder($|/)
RewriteRule ^folder/(.*) https://domain2.com/$1 [R=301,L]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /folder/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]
</IfModule>
It is important that the redirect goes before the rewrite to your front-controller.
You will need to ensure your browser cache is cleared before testing and test with a 302 (temporary) redirect to avoid potential caching issues.
UPDATE:
Yes, /folder has it's own .htaccess (this is the file I am working at all this time). Yes, /folder is where Wordpress is installed.
In that case you would need to change the above redirect to read as follows (it won't do anything otherwise):
# /folder/.htaccess
# Redirect all direct requests, except "subfolder"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $1 !^subfolder($|/)
RewriteRule (.*) https://domain2.com/$1 [R=301,L]
Basically, you need to remove folder/ from the start of the regex that matches the URL-path. The URL-path that the RewriteRule pattern matches against is relative to the directory that contains the .htaccess file.
The addition of the check against the REDIRECT_STATUS env var is to ensure that rewritten requests to the WP front-controller (when subfolder is requested) are not redirected.
You can also "simplify" the WordPress directives that follow (although if these are enclosed in # BEGIN WordPress / # END WordPress comment markers then you should leave the directives as they are since they are maintained by WordPress). For example:
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
The RewriteBase directive is not required. And neither is the <IfModule> wrapper. (But as I said above, only change this if you are hand-coding the .htaccess and not letting WordPress maintain it.)

.htaccess rewrite for a specific subfolder

My goal:
every url http://www.domain.tld must be served by http://www.domain.tld/www/frontend/web
AND
every url http://www.domain.tld/backend must be server by http://www.domain.tld/www/backend/web
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} ^/backend
RewriteRule ^backend(.*)$ /www/backend/web/$1 [L]
RewriteCond %{REQUEST_URI} !^public
RewriteRule ^(.*)$ /www/frontend/web/$1 [L]
</IfModule>
The first goal is ok, but the second no.
The server redirect my /backend to /www/frontend/web/backend/.
I tested even it using an htaccess tester online and it give me the same results.
For precision, even if i used [L], the first rewrite rule is ignored or, at minimum, the execution is not stopped.
You need to exclude rewritten backend URI from 2nd rule:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteRule ^backend/(.*)$ www/backend/web/$1 [L,NC]
RewriteCond %{REQUEST_URI} !^/(public|www/(backend|frontend)/) [NC]
RewriteRule ^(.*)$ www/frontend/web/$1 [L]
</IfModule>
It turned out to be a weird server configuration. After going through pretty much every other method of checking for SSL including but not exclusively:
RewriteCond %{SERVER_PORT} !=443
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{SERVER_PORT} !=443
The only one that worked on the clients host was:
RewriteCond %{ENV:HTTPS} !=on
Thanks to #anubhava for pointing me in the right direction. Hopefully this will save someone else wasting half a day of their lives.

RewriteRule not working fine

I wrote the following rule in .htaccess
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)/$ profile.php?business=$1
When i enter the URL like
http://www.abc.com/mujeeb/
page is correctly transfered to profiles page and page looks fine.
But i enter this in URL
http://www.abc.com/mujeeb
page doesn't show.
Can you please tell why? Or write the rule for this? i tried many times but not sucessful.
Mujeeb.
page doesn't show. because you specified that you RewriteRule is applied to the URL's ending with / at the end. Rewrite it as
RewriteRule ^(.*)/?$ profile.php?business=$1 [L]
And I hope that you have additional RewriteCond statements in order to prevent the infinite loop with redirects.
ps: basically you can prevent loop in two way
1) checks that requested url does not correspond to the existing file or directory. it is, probably, the best way to do (read comments to the second method)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/?$ profile.php?business=$1 [L]
2) checks that you are requesting not the file from RewriteRule. This method is not good, because for each request, even for existing files and directories, it calls profile.php script
RewriteCond %{REQUEST_URI} !profile\.php$
RewriteRule ^(.*)/?$ profile.php?business=$1 [L]
It is because you check for the trailing slash with ^(.*)/$. If you add a question mark, the trailing slash will be optional.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)/?$ profile.php?business=$1
The RewriteCond is neccessary to make sure the Rule will only be applied once. Otherwise Apache will be caught in an infinite loop.
Try this:
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)[/]?$ profile.php?business=$1
That makes the last slash optional.
Well you rule is checking for a trailing slash in URI and that's the reason /mujeeb/ works but /mujeeb does not. Change your code to:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
# If the request is not for a valid file
#RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid directory
#RewriteCond %{REQUEST_FILENAME} !-f
# your rule without trailing slash
RewriteRule ^(.*)$ profile.php?business=$1 [L,QSA]
Plenty of good answers already. My answer is a bit different.
This is what I usually do. If the requested URL doesn't end with a /, I make the browser redirect to a URL with the trailing /. This is consistent with the default behaviour of Apache (due to mod_dir). So, this is how I solve this problem.
RewriteEngine On
# Canonicalize http://example.com/mujeeb to http://example.com/mujeeb/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)([^/])$ /$1$2/ [R=307,L]
# Let profile.php process http://example.com/mujeeb/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ profile.php?business=$1

removing www and index.php from url in symfony

I've been searching for like 3 or 4 hours without any result(before searching I played with rules for an hour but couldn't do it)
I don't know if you've noticed or no but google uses www like this
when it has no subdomain it will be www.google.com/blabla and
when there is a subdomain it will be earth.google.com/blabla
This is the first part
And the second part, as you know in symfony urls are like domain.com/index.php/test and thanks to the symfony .htaccess file you can access it via domain.com/test
So here is what I tried so hard to achieve
domain.com/test redirect to www.domain.com/test
www.sub.domain.com/blabla redirect to sub.domain.com/blabla
www.sub.domain.com/ redirect to sub.domain.com (without any index.php XD)
One of the annoying problems I had was redirecting from domain.com/ to www.domain.com was that after redirect it was like www.domain.com/index.php (And I hate index.php :P)
So is there any way with one redirect solve this problem?
I'm sure I'm not the only one who needs something like this and might be an idea for other people who are going to have their site with symfony or other frameworks
Thanks
Here is my complete htaccess file
Options +FollowSymLinks +ExecCGI
<IfModule mod_rewrite.c>
RewriteEngine On
# The admin subdomain returns to the backend
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^admin\.mydomain\..*
RewriteRule ^(.*)$ backend.php [QSA,L]
# uncomment the following line, if you are having trouble
# getting no_script_name to work
#RewriteBase /
RewriteCond %{HTTP_HOST} !^www.mydomain.com$
RewriteRule ^(.*)$ http://www.mydomain.com/$1 [R=301]
# we skip all files with .something
RewriteCond %{REQUEST_URI} \..+$
RewriteCond %{REQUEST_URI} !\.html$
RewriteRule .* - [L]
# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
In your VHOST config:
RewriteCond %{HTTP_HOST} ^www.domain.com$ [NC]
RewriteRule ^/(.*) http://domain.com/$1 [R=301,L]
Also note that from a esthetical point of view you might prefer to remove the www., looking from the technical angle (DNS, cookies, ...), it is always better to prefix with www., and redirect in the opposite way.