Showing posts with label .htaccess. Show all posts
Showing posts with label .htaccess. Show all posts

Friday, December 27, 2019

Htaccess | what does $1 in .htaccess file mean | Check if file exists in subdirectory

$1 is the first captured group from your regular expression; that is, the contents between ( and ). If you had a second set of parentheses in your regex, $2 would contain the contents of those parens and so on. Here is an example:
RewriteRule (js|css|img)/(.*?).(js|css|jpg|jpeg|png|ttf)$ public/$1/$2.$3 [NC,L,QSA]
Will served files as below:

js/app.js will be served from public/js/app.js

css/main.css will be served from public/css/main.css

Friday, September 20, 2013

HTTP Status Codes Handling and Htaccess ErrorDocuments

Error handling using .htacces:

Here are some basic rule, use other rules if you need.

ErrorDocument 404 /Subtitle/php/error-msg.php
ErrorDocument 500 /location/php/error-msg.php
ErrorDocument 400 /location/php/error-msg.php
ErrorDocument 401 /location/php/error-msg.php
ErrorDocument 403 /location/php/error-msg.php

And the error-msg.php like this:

Here are some basic rule, use other rules if you need.

<?php
$HttpStatus = $_SERVER["REDIRECT_STATUS"] ;
  if($HttpStatus==200) {
      echo "Document has been processed and sent to you.";      
  } else if($HttpStatus==400) {
      echo "Bad HTTP request ";      
  } else if($HttpStatus==401) {
      echo "Unauthorized - Iinvalid password";      
  } else if($HttpStatus==403) {
      echo "Forbidden";      
  } else if($HttpStatus==500) {
      echo "Internal Server Error";      
  } else if($HttpStatus==418) {
      echo "I'm a teapot! - This is a real value, defined in 1998";      
  } else if($HttpStatus==404) {
      echo "Page not found here";      
  } else {
      $HttpStatus = 500;
      echo "Internal server Error";
  }
  echo "<BR>Status: ".$HttpStatus;
  exit; 
?>

Error Distribute from php file (named: mac_address.php)

If you need to show error like above one, please see below example php code:

<?php
/* UnCaught error handler */
set_exception_handler('exc_handler');

/* Error handler function */
function exc_handler(Exception $exception) {
    /* Set http status code such 404, 500 etc. */
    header("HTTP/1.1 ".$exception->getCode()." ".$exception->getMessage());
    /**
     * As 'REDIRECT_STATUS' is using in 'error-msg.php' file,
     * so we are providing this manually.
     * But it will automatically set when come from .htaccess
     */
    $_SERVER["REDIRECT_STATUS"] = $exception->getCode();
    /**
     * Including 'error-msg.php' file.
     */
    include './error-msg.php';
}
/**
 * Extentd 'Exception' to my own class 'NotFoundException'
 */
class NotFoundException extends Exception {
    public function NotFoundException($message = "Page not found") {
        throw new Exception($message, 404);
    }
}
/**
 * Throwing 'NotFoundException'
 */
//throw new NotFoundException();

/**
 * Another way to throw exception as bellow, where 
 * 'Server error' is the message and
 * '500' is the error code.
 */
throw new Exception("Server error", 500);
?>

Example output in browser (Custom 500 error using php code):

I wrote the code in mac_address.php to show 500 internal server error.














Example output in browser (404 error using .htaccess):

No file in that location named 'mac.php', .htaccess handling this internally.

Monday, September 9, 2013

Redirect your site to https and www using htaccess

<ifmodule mod_rewrite.c>
   RewriteEngine on

   RewriteCond %{HTTPS} off
   RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
   RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

   RewriteCond %{HTTPS} off
   RewriteCond %{HTTP_HOST} !^www\.(.+)$ [NC]
   RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

   RewriteCond %{HTTPS} on
   RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
   RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

   RewriteRule    ^$ app/webroot/    [L]
   RewriteRule    (.*) app/webroot/$1 [L]
</ifmodule>

Friday, September 6, 2013

Compressed CSS Compression using PHP

Method One

Overview: This method involves adding a small PHP script to your CSS document and replacing its.css extension with a .php extension.
Place the following PHP script into the top of the CSS document that you wish to compress. Then change the .css extension to .php, to arrive at something similar to: compressed-css.php. Remember to use the new name when referencing the file.
<?php 
   ob_start ("ob_gzhandler");
   header ("content-type: text/css; charset: UTF-8");
   header ("cache-control: must-revalidate");
   $offset = 60 * 60;
   $expire = "expires: " . gmdate ("D, d M Y H:i:s", time() + $offset) . " GMT";
   header ($expire);
?>
Here is the same PHP script commented with functional explanations:
<?php

   // initialize ob_gzhandler function to send and compress data
   ob_start ("ob_gzhandler");

   // send the requisite header information and character set
   header ("content-type: text/css; charset: UTF-8");

   // check cached credentials and reprocess accordingly
   header ("cache-control: must-revalidate");

   // set variable for duration of cached content
   $offset = 60 * 60;

   // set variable specifying format of expiration header
   $expire = "expires: " . gmdate ("D, d M Y H:i:s", time() + $offset) . " GMT";

   // send cache expiration header to the client broswer
   header ($expire); 
  
   // output css contents
   readfile("some_location/some_name.css"); 
?>
Functional Summary: The previous PHP function will first check to see if the browser requesting the file will accept "gzip-deflate" encoding. If no such support is detected, the requested file is sent without compression. Next, the function sends a header for the content type and character set (in this case, "text/css" and "UTF-8"). Then, a "must-revalidate" "cache-control" header requires revalidation against currently specified variables. Finally, an "expires" header specifies the time duration for which the cached content should persist (one hour in this case).

Method Two

Overview: This method involves placing the PHP script in a separate .php file and adding a set of rules to an .htaccess file.
A more discrete, unobtrusive method for compressing CSS involves two steps. First, save the script provided in the first method (above) as a seperate gzip-css.php file and place it in a CSS-exclusive directory. Then, add the following ruleset to an .htaccess file located in the same CSS-exclusive directory (i.e., the CSS directory should contain only CSS files):
# css compression htaccess ruleset
AddHandler application/x-httpd-php .css
php_value auto_prepend_file gzip-css.php
php_flag zlib.output_compression On
Here is the same htaccess ruleset commented with functional explanations:
# css compression htaccess ruleset

# process all CSS files in current directory as PHP
AddHandler application/x-httpd-php .css

# prepend the PHP script to all PHP files in the current directory
php_value auto_prepend_file gzip-css.php

# compress all parsed PHP pages from current directory
# this rule is redundantly present as the first line of the PHP script
php_flag zlib.output_compression On
Functional Summary: The .htaccess rules above first instruct Apache to parse all CSS files in the current directory as PHP. After this, Apache is instructed to insert the contents of the "gzip-css.php" file into the beginning of each PHP (i.e., CSS) file parsed from the current directory. And finally, Apache is instructed to compress automatically every parsed document in the current directory.

Confirmed Browsers

  • Internet Explorer 5 and up: works great
  • Netscape Navigator 6 and up: works fine
  • Mozilla/Firefox: all versions seem to work
  • Opera: does not cache compressed CSS

References

Leverage browser caching: How To Control Browser Caching with Apache 2 or htaccess

Examining Your HTTP Headers - The other way of finding out if your site is taking advantage of browser caching is to examine the HTTP headers on any given server response, be it a whole page or a single file. You can do this using the Live HTTP Headers Chrome mentioned above. A common HTTP header response will look something like this.
HTTP/1.1 200 OK
Date: Sun, 19 Feb 2006 16:42:05 GMT
Server: Apache/2.0.55 (Unix) DAV/2 PHP/5.1.1
Last-Modified: Sun, 08 Jan 2006 16:17:25 GMT
ETag: "73049-defc-37c52f40"
Accept-Ranges: bytes
Content-Length: 57084
Cache-Control: max-age=7200
Expires: Sun, 19 Feb 2006 18:42:05 GMT
Connection: close
Content-Type: image/png

What we are looking for in the header are the "Cache-Control" and "Expires" fields. These fields control how long the browser will cache this media or page asset from your server. Having a low value like "1" in "Cache-Control" can be just as bad as no value at all.

If you have those fields present, you've got a head start on the situation. If not, you may need to make sure Apache 2 is loading the mod_expires and mod_headers modules. Most installations and builds of Apache 2 include these modules since they are pretty essential. If you are using the Apache 2 in OS X Server's opt directory, this is the case and you only need to make sure that they are turned on by opening the http.conf file and making sure the following two lines do not have an # sign in front of them.
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so

When these modules are loaded and working, we can then start to use the correct Apache 2 directives to control how browsers cache everything from pages to images across the whole site or in a specific directory.

Using Apache 2 To Control Browser Caching

Now that we are here, I can assume that you have both the mod_expires and mod_headers modules compiled and loaded into your Apache 2 installation. I can also assume that you have examined a few headers from your server's responses and determined that the "Cache-Control" and "Expires" fields are either not set or they are configured at such a low value to be ineffective. Lastly, you may have bypassed some header examinations and just determined that browser caching is not happening by tailing your Apache 2 log file and monitoring redundant requests. Either way, let's get to fixing Apache 2 to control browser caching that is right for you and your particular site.


Here is a code snippet of an Apache 2 directive that we will be using. This directive can be modified to suite your tastes or it can just be used "as is" for most users. The directives here can be placed into the <Directory> directive of your virtual host in http.conf or it can be placed loosely in a .htaccess file in the root of your website.

<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 seconds"
ExpiresByType text/html "access plus 1 seconds"
ExpiresByType image/gif "access plus 120 minutes"
ExpiresByType image/jpeg "access plus 120 minutes"
ExpiresByType image/png "access plus 120 minutes"
ExpiresByType text/css "access plus 60 minutes"
ExpiresByType text/javascript "access plus 60 minutes"
ExpiresByType application/x-javascript "access plus 60 minutes"
ExpiresByType text/xml "access plus 60 minutes"
</IfModule>


Let's examine what is happening here in brief. If you are interested full documentation of the expires directive can be found on Apache's website along with different syntax formats than the ones used here. I like this format since it is inheritably legible. This directive will do the following:
  • Set the default expiration of content in the browser cache to 1 second past the time of accessing that content. This is good for setting a catchall or default if you fail to explicitly define a content type in the following directives.
  • Set the expiration of text/html pages to 1 second. My content management system Drupal does this already in its .htaccess file, but I include it here if you wish to change it. I think this is a good setting since technically most html pages are small and I like to err on the side of caution and always want my page content to be fresh. For instance, I may make changes to my global template and want it to be visible immediately.
  • Set the expiration of standard images like GIFF, JPEG, and PNG to 2 hours.
  • Set the expiration of CSS and JavaScript to 1 hour.
  • Set the expiration of XML files such as RSS feeds to 1 hour.
I usually use rules like this in htaccess, although you can customize them for how you want.
# 1 YEAR
ExpiresActive On
<FilesMatch "\.(otf|ico|pdf|flv)$">
Header set Cache-Control "max-age=29030400, public"
ExpiresDefault "access plus 1 years"
Header unset Last-Modified
Header unset ETag
SetOutputFilter DEFLATE
</FilesMatch>

# 1 MONTHS
<FilesMatch "\.(jpg|jpeg|png|gif|swf)$">
Header set Cache-Control "max-age=2419200, public"
ExpiresDefault "access plus 1 month"
SetOutputFilter DEFLATE
</FilesMatch>

<FilesMatch "\.(xml|txt|css|js)$">
Header set Cache-Control "max-age=604800, public"
ExpiresDefault "access plus 1 week"
SetOutputFilter DEFLATE
</FilesMatch>

# 30 MIN
<FilesMatch "\.(html|htm|php)$">
SetOutputFilter DEFLATE
</FilesMatch>

The entire .htaccess file

Let's take a look at the entire htaccess config file, then go through all the configuration options.
Header unset Pragma
FileETag None
Header unset ETag
 
# cache images/pdf docs for 10 days
<FilesMatch "\.(ico|pdf|jpg|jpeg|png|gif)$">
  Header set Cache-Control "max-age=864000, public, must-revalidate"
  Header unset Last-Modified
</FilesMatch>
 
# cache html/htm/xml/txt diles for 2 days
<FilesMatch "\.(html|htm|xml|txt|xsl)$">
  Header set Cache-Control "max-age=7200, must-revalidate"
</FilesMatch>

Disabiling some of the headers

First, we unset the Pragma value from the server response headers.
Header unset Pragma
This will unset any headers that are created, by, for instance, a php script interpreted during the request. This is needed because browsers may interpret "Pragma: no-cache" as "This content is not to be cached". Then, we turn off the ETags:
FileETag None
Header unset ETag
ETags are a mechanism to determine the origin of the content on the server (such as inode location), providing the browser information to cache objects depending on where they are on the disk. Disabling them not only makes the server work faster, but also allows the browser to rely on the Cache-Control headers, which we will describe next...

Adding static content cache headers

Next we will enable caching for different type of files.
For image files and pdf documents, in this example we set the cache to 10 days (that is 864000 seconds):
<FilesMatch "\.(ico|pdf|jpg|jpeg|png|gif)$">
  Header set Cache-Control "max-age=864000, public, must-revalidate"
  Header unset Last-Modified
</FilesMatch>
The "max-age" value indicates the time difference (in seconds) after which the content will be expired and reloaded from the server. The "public" keyword presence indicates that any system along the route may cache the response. The "must-revalidate" indicates caching systems to obey other header information you may provide at a later time about the cache. This should help preventing stale caching (that is, caching that delivers content that is outdated).
You will notice that we also unset the Last-Modified header. Why are we doing this? Because by eliminating the Last-Modified and ETags headers, you are eliminating validation requests, leading to a decreased response time. This should work fine in most cases when dealing with static, rarely updated content.

Caching files that change more often

<FilesMatch "\.(html|htm|xml|txt|xsl)$">
  Header set Cache-Control "max-age=7200, must-revalidate"
</FilesMatch>
For html, htm, xml, txt, xsl files that we expect are more likely to change, we won't eliminate the Last-Modified header, thus allowing cache systems to verify the last modification date of the document. In case the http document is fresher then the local cached version, the cache will be invalidated.

If you have multiple file types that should expire after the same time after they have been accessed (let's say in one week), you can use a combination of the FilesMatchand the ExpiresDefault directives, e.g. as follows:
[...]
<IfModule mod_expires.c>
          <FilesMatch "\.(jpe?g|png|gif|js|css)$">
                      ExpiresActive On
                      ExpiresDefault "access plus 1 week"
          </FilesMatch>
</IfModule>
[...]
This would tell browsers to cache .jpg, .jpeg, .png, .gif, .js, and .css files for one week.

Instead of using FilesMatch and ExpiresDefault directives, you could also use the ExpiresByType directice and set an Expires header (plus the max-age directive of theCache-Control HTTP header) individually for each file type, e.g. as follows:
[...]
<IfModule mod_expires.c>
          ExpiresActive on

          ExpiresByType image/jpg "access plus 60 days"
          ExpiresByType image/png "access plus 60 days"
          ExpiresByType image/gif "access plus 60 days"
          ExpiresByType image/jpeg "access plus 60 days"

          ExpiresByType text/css "access plus 1 days"

          ExpiresByType image/x-icon "access plus 1 month"

          ExpiresByType application/pdf "access plus 1 month"
          ExpiresByType audio/x-wav "access plus 1 month"
          ExpiresByType audio/mpeg "access plus 1 month"
          ExpiresByType video/mpeg "access plus 1 month"
          ExpiresByType video/mp4 "access plus 1 month"
          ExpiresByType video/quicktime "access plus 1 month"
          ExpiresByType video/x-ms-wmv "access plus 1 month"
          ExpiresByType application/x-shockwave-flash "access 1 month"

          ExpiresByType text/javascript "access plus 1 week"
          ExpiresByType application/x-javascript "access plus 1 week"
          ExpiresByType application/javascript "access plus 1 week"
</IfModule>
[...]
You might have noticed that I've set three ExpiresByType directives for Javascript files - that is because Javascript files might have different file types on each server. If you set just one directive for text/javascript, but the server recognizes the Javascript file as application/javascript, then it will not be covered by your configuration, and no cache headers will be set.
You can use the following time units in your configuration:
  • years
  • months
  • weeks
  • days
  • hours
  • minutes
  • seconds
Please note that Apache accepts these time units in both singular and plural, so you can use day and days, week and weeks, etc.
It is possible to combine multiple time units, e.g. as follows:
ExpiresByType text/html "access plus 1 month 15 days 2 hours"

What to add in your .htaccess file

Open your .htaccess file. (be smart: make a copy of your original .htaccess file, in case you accidentally make a mistake and need to revert)
Now it’s time to enable the Expires headers module in Apache (set the ‘ExpiresActive’ to ‘On’), so add this to your .htaccess file:
<IfModule mod_expires.c>

# Enable expirations
ExpiresActive On 

</IfModule>
It might be useful to add a “Default directive” for a default expiry date, so that’s the 2 rows you’ll add now:
<IfModule mod_expires.c>

# Enable expirations
ExpiresActive On 

# Default directive
ExpiresDefault "access plus 1 month"

</IfModule>
That’s the base. Now add all the lines for each of your file types (you know, the ones you created earlier for your favicon, images, css and javascript). You’ll end up with a code snippet that looks something like this:
<IfModule mod_expires.c>

# Enable expirations
ExpiresActive On

# Default directive
ExpiresDefault "access plus 1 month"

# My favicon
ExpiresByType image/x-icon "access plus 1 year”

# Images
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"

# CSS
ExpiresByType text/css "access 1 month”

# Javascript
ExpiresByType application/javascript "access plus 1 year"

</IfModule>
That’s it.
References
If you are interested in knowing ALL about caching including proxy caching and CDNs, please read Mark Nottingham's article "Caching Tutorial for Web Authors and Webmasters". Also included below are links to Apache's website manuals for each of the modules discussed here.
How To Control Browser Caching with Apache 2
Caching Tutorial for Web Authors and Webmasters
Apache Module mod_expires
Apache Module mod_headers

Thursday, August 1, 2013

How to Run PHP Scripts in *.html or *.htm Files

One of the most common questions hitting our support inbox is how to get PHP working in *.html and *.htm files. With this blog we try to provide a practical guide for our users and thus kill two birds with one stone figuratively.

Question One: Does my web host support PHP?

At first you should try to find our whether PHP is supported by your webhost or not. If you already know that PHP works please continue to read at Question Two. If you don't know you could either ask your hosting company or you could just try it by following these steps:
First, create a file named "phptest.php". At this stage it is important to use the file extension ".php". Open the file in a simple text editor (for example the "Editor" in Windows) and write the following line:
<?php echo "hello world"; ?>
After saving the file please upload it to the root directory of your webspace. Open your browser and direct it to the file you just uploaded: "http://www.your-domain.com/phptest.php" (Needless to say, you should use your own domain here...)
It's the moment of truth now. What does the browser say? If you see the words "hello world" everything is fine, PHP is working. However, if you don't see these words please contact your hosting provider because PHP is not working (yet). Most hosting companies provide packages including PHP. So perhaps you just have to switch to another hosting plan.

Question Two: How to get PHP working in HTML files

If PHP is working there is only one step left to use PHP scripts in files with *.html or *.htm extensions as well. The magic word is ".htaccess". Please see the Wikipedia definition of .htaccess to learn more about it. According to Wikipedia it is "a directory-level configuration file that allows for decentralized management of web server configuration."
You can probably use such a .htaccess configuration file for your purpose. In our case you want the webserver to parse HTML files like PHP files.
First, create a blank text file and name it ".htaccess". You might ask yourself why the file name starts with a dot. On Unix-like systems this means it is a dot-file is a hidden file.
(Note: If your operating system does not allow file names starting with a dot just name the file "xyz.htaccess" temporarily. As soon as you have uploaded it to your webserver in a later step you can rename the file online to ".htaccess")
Next, open the file with a simple text editor like the "Editor" in MS Windows. Paste the following line into the file:
AddType application/x-httpd-php .html .htm
If this does not work, please remove the line above from your file and paste this alternative line into it, for PHP5:
AddType application/x-httpd-php5 .html .htm
Now upload the .htaccess file to the root directory of your webserver. Make sure that the name of the file is ".htaccess". Your webserver should now parse *.htm and *.html files like PHP files.
You can try if it works by creating a HTML-File like the following. Name it "php-in-html-test.htm", paste the following code into it and upload it to the root directory of your webserver:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
	<HEAD>
	<TITLE>Use PHP in HTML files</TITLE>
	</HEAD>
 
	<BODY>
		<h1>
		<?php echo "It works!"; ?>
		</h1>
	</BODY>
</HTML>
 
Try to open the file in your browser by typing in: http://www.your-domain.com/php-in-html-test.htm (once again, please replace your-domain.com by your own domain...)
If your browser shows the phrase "It works!" everything works fine and you can use PHP in .*html and *.htm files from now on. However, if not, please try to use the alternative line in the .htaccess file as we showed above. If is still does not work please contact your hosting provider.