Nibbleblog: Converting .htaccess to IIS

In this post I will share with you on how to convert the .htaccess provided with Nibbleblog when SEO Friendly URLs are enabled into the equivalent IIS web.config configuration.

For those unfamiliar with NibbleBlog:

Nibbleblog is a powerful engine for creating blogs, all you need is PHP to work. Very simple to install and configure (only 1 step).

Before we begin here is a brief overview of the .htaccess and web.config files.

What is .htaccess and what is it used for?

Wikipedia explains the .htaccess file as follows:

"In several web servers (most commonly Apache), .htaccess (hypertext access) is the default name of a directory-level configuration file that allows for decentralized management of web server configuration. The .htaccess file is placed inside the web tree, and is able to override a subset of the server's global configuration; the extent of this subset is defined by the web server administrator. The original purpose of .htaccess was to allow per-directory access control (e.g. requiring a password to access the content), hence the name. Nowadays .htaccess can override many other configuration settings, mostly related to content control."

What is web.config and what is it used for?

Wikipedia explains the web.config file as follows:

Web.config is the main settings and configuration file for an ASP.NET web application. The file is an XML document that defines configuration information regarding the web application. The web.config file contains information that control module loading, security configuration, session state configuration, and application language and compilation settings. Web.config files can also contain application specific items such as database connection strings.

Default .htaccess file

Here is the default .htaccess file as used by nibbleblog when SEO Friendly URLs are enabled:

# Disable directory browsing
Options -Indexes

# Disable Magic Quotes
<IfModule mod_php5.c>
  php_flag magic_quotes_gpc off
</IfModule>

# Secure .xml files
<FilesMatch ".(xml)$">
  Order Allow,Deny
  Deny from all
</FilesMatch>

# Secure shadow.php
<Files shadow.php>
  order allow,deny
  deny from all
</Files>

# Secure keys.php
<Files keys.php>
  order allow,deny
  deny from all
</Files>

ErrorDocument 404 /index.php?controller=page&action=404

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteBase /
  RewriteRule ^admin/$ admin.php?controller=user&action=login [L]
  RewriteRule ^category/([^/]+)/page-([0-9]+)$ index.php?controller=blog&action=view&category=$1&number=$2 [L]
  RewriteRule ^category/([^/]+)/$ index.php?controller=blog&action=view&category=$1&number=0 [L]
  RewriteRule ^tag/([^/]+)/page-([0-9]+)$ index.php?controller=blog&action=view&tag=$1&number=$2 [L]
  RewriteRule ^tag/([^/]+)/$ index.php?controller=blog&action=view&tag=$1&number=0 [L]
  RewriteRule ^page-([0-9]+)$ index.php?controller=blog&action=view&number=$1 [L]
  RewriteRule ^post/([^/]+)/$ index.php?controller=post&action=view&post=$1 [L]
  RewriteRule ^post-([0-9]+)/(.*)$ index.php?controller=post&action=view&id_post=$1 [L]
  RewriteRule ^page/([^/]+)/$ index.php?controller=page&action=view&page=$1 [L]
  RewriteRule ^feed/$ feed.php [L]
  RewriteRule ^([^/]+)/$ index.php?controller=page&action=$1 [L]
amp;lt;/IfModule>

In the following sections I will attempt to cover each of the entries in the Nibbleblog default .htaccess and provide the equivalent for IIS.

NOTE: I have only tested this on a demo system running Nibblebog 4.0.3 with Windows 7 and IIS 7.5

Directory Browsing

Many web server configurations will let users see a listing of files in a directory that does not contain one of the default document files. In the Nibbleblog .htaccess file this is disabled using the Options directive:

# Disable directory browsing
Options -Indexes

The equivalent for ISS would be

<directoryBrowse enabled="false" />

Magic Quotes

When the magic quotes directive is enabled, PHP automatically escapes data from HTTP GET and POST requests and cookie data. In the

# Disable Magic Quotes
<IfModule mod_php5.>
 php_flag magic_quotes_gpc off
</IfModule>

I have not found the equivalent under ISS, with the exception of modifying the php.ini file:

; http://php.net/magic-quotes-gpc
magic_quotes_gpc = Off

FilesMatch

Nibbleblog uses the FilesMatch directive in the .htacess file to limit browser access to files that are components of the application.

# Secure .xml files
<FilesMatch ".(xml)$">
 Order Allow,Deny
 Deny from all
</FilesMatch>

# Secure shadow.php
<Files shadow.php>
 order allow,deny
 deny from all
</Files>

# Secure keys.php
<Files keys.php>
 order allow,deny
 deny from all
</Files>

IIS uses the Request Filtering module to limit browser access to files that are components of the application. So to convert the above for nibbleblog the web.config entry would look like:

<security>
  <requestFiltering>
    <denyUrlSequences>
      <addsequence="shadow\.php" />
      <addsequence="keys\.php" />
    </denyUrlSequences>
    <fileExtensions>
      <addfileExtension=".xml" allowed="false" />
    <fileExtensions>
  </requestFiltering>
</security>

Error Page Redirects / Handling

The ErrorDocument directive in the .htaccess file tells the web server to load the error page for any 404 or “File Not Found” errors.

ErrorDocument 404 /index.php?controller=page&action=404

IIS uses the httpErrors directive for this functionality:

<httpErrors>
  <remove statusCode="404" subStatusCode="-1" />
  <error statusCode="404" prefixLanguageFilePath="" responseMode="ExecuteURL" path="/index.php\?controller\=page\&action\=404" />
</httpErrors>

However, because the capability to set this at the application level is turned off by default for IIS, this section should be commented out.

<!-- HTTP Errors section should only be enabled if the "Error Pages"
 feature has been delegated as "Read/Write" at the Web Server level.
  <httpErrors>
  <remove statusCode="404" subStatusCode="-1" />
  <error statusCode="404" prefixLanguageFilePath="" responseMode="ExecuteURL" path="/index.php\?controller\=page\&action\=404" />
  </httpErrors>
-->

URL Rewriting (Friendly URLs)

The mod_rewrite section in Nibbleblogs .htaccess file provides a rule-based rewriting engine to rewrite requested URLs on the fly

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteBase /

  RewriteRule ^admin/$ admin.php?controller=user&action=login [L]
  RewriteRule ^category/([^/]+)/page-([0-9]+)$ index.php?controller=blog&action=view&category=$1&number=$2 [L]
  RewriteRule ^category/([^/]+)/$ index.php?controller=blog&action=view&category=$1&number=0 [L]
  RewriteRule ^tag/([^/]+)/page-([0-9]+)$ index.php?controller=blog&action=view&tag=$1&number=$2 [L]
  RewriteRule ^tag/([^/]+)/$ index.php?controller=blog&action=view&tag=$1&number=0 [L]
  RewriteRule ^page-([0-9]+)$ index.php?controller=blog&action=view&number=$1 [L]
  RewriteRule ^post/([^/]+)/$ index.php?controller=post&action=view&post=$1 [L]
  RewriteRule ^post-([0-9]+)/(.*)$ index.php?controller=post&action=view&id_post=$1 [L]
  RewriteRule ^page/([^/]+)/$ index.php?controller=page&action=view&page=$1 [L]
  RewriteRule ^feed/$ feed.php [L]
  RewriteRule ^([^/]+)/$ index.php?controller=page&action=$1 [L]
</IfModule>

Under IIS, the rewriter module can read these rules and translate them. The translated URL Rewriter rules are:

<rewrite>
  <rules>
    <rule name="nbadmin" stopProcessing="true">
      <match url="^admin/$"  />
      <action type="Rewrite" url="/admin.php?controller=user&amp;action=login"  />
    </rule>
    <rule name="nb1" stopProcessing="true">
      <match url="^category/([^/]+)/page-([0-9]+)$" />
      <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;category={R:1}&amp;number={R:2}" />
    </rule>
    <rule name="nb2" stopProcessing="true">
      <match url="^category/([^/]+)/$" />
      <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;category={R:1}&amp;number=0" />
    </rule>
    <rule name="nb3" stopProcessing="true">
      <match url="^tag/([^/]+)/page-([0-9]+)$" />
      <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;tag={R:1}&amp;number={R:2}" />
    </rule>
    <rule name="nb4" stopProcessing="true">
      <match url="^tag/([^/]+)/$" />
      <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;tag={R:1}&amp;number=0" />
    </rule>
    <rule name="nb5" stopProcessing="true">
      <match url="^page-([0-9]+)$" />
      <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;number={R:1}" />
    </rule>
    <rule name="nb6" stopProcessing="true">
      <match url="^post/([^/]+)/$" />
      <action type="Rewrite" url="/index.php?controller=post&amp;action=view&amp;post={R:1}" />
    </rule>
    <rule name="nb7" stopProcessing="true">
      <match url="^post-([0-9]+)/(.*)$" />
      <action type="Rewrite" url="/index.php?controller=post&amp;action=view&amp;id_post={R:1}" />
    </rule>
    <rule name="nb8" stopProcessing="true">
      <match url="^page/([^/]+)/$" />
      <action type="Rewrite" url="/index.php?controller=page&amp;action=view&amp;page={R:1}" />
    </rule>
    <rule name="nb9" stopProcessing="true">
      <match url="^feed/$" />
      <action type="Rewrite" url="/feed.php" />
    </rule>
    <rule name="nb10" stopProcessing="true">
      <match url="^([^/]+)/$" />
      <action type="Rewrite" url="/index.php?controller=page&amp;action={R:1}" />
    </rule>
  </rules>
</rewrite>

Completed WEB.CONFIG file

And here is the completed ISS web.config file converted from the Nibbleblog .htaccess file:

<?xml version="1.0" encoding="UTF-8"?>
<!--
     sample NIBBLEBLOG web.config CONVERTED FROM .htaccess
     http://www.nibbleblog.com
-->

<configuration>

  <configSections>
    <sectionGroup name="system.webServer">
      <sectionGroup name="rewrite">
        <section name="rewriteMaps" overrideModeDefault="Allow" />
        <section name="rules" overrideModeDefault="Allow" />
      </sectionGroup>
    </sectionGroup>
  </configSections>

  <system.webServer>
    <security>
      <requestFiltering>
        <denyUrlSequences>
          <addsequence="shadow\.php" />
          <addsequence="keys\.php" />
        </denyUrlSequences>
        <fileExtensions>
          <addfileExtension=".xml" allowed="false" />
        <fileExtensions>
      </requestFiltering>
    </security>

    <directoryBrowse enabled="false" />

    <caching>
      <profiles>
        <add extension=".php" policy="DisableCache" kernelCachePolicy="DisableCache" />
        <add extension=".html" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod" duration="14:00:00:00" />
      </profiles>
    </caching>

    <!-- For Magic Quotes, modify the php.ini file
    ; http://php.net/magic-quotes-gpc
    magic_quotes_gpc = Off
    -->

    <rewrite>
      <rules>
        <rule name="nbadmin" stopProcessing="true">
          <match url="^admin/$" />
          <action type="Rewrite" url="/admin.php?controller=user&amp;action=login" />
        </rule>
        <rule name="rule 1i" stopProcessing="true">
          <match url="^category/([^/]+)/page-([0-9]+)$" />
          <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;category={R:1}&amp;number={R:2}" />
        </rule>
        <rule name="rule 2C" stopProcessing="true">
          <match url="^category/([^/]+)/$" />
          <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;category={R:1}&amp;number=0" />
        </rule>
        <rule name="rule 3C" stopProcessing="true">
          <match url="^tag/([^/]+)/page-([0-9]+)$" />
          <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;tag={R:1}&amp;number={R:2}" />
        </rule>
        <rule name="rule 4C" stopProcessing="true">
          <match url="^tag/([^/]+)/$" />
          <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;tag={R:1}&amp;number=0" />
        </rule>
        <rule name="rule 5C" stopProcessing="true">
          <match url="^page-([0-9]+)$" />
          <action type="Rewrite" url="/index.php?controller=blog&amp;action=view&amp;number={R:1}" />
        </rule>
        <rule name="rule 6C" stopProcessing="true">
          <match url="^post/([^/]+)/$" />
          <action type="Rewrite" url="/index.php?controller=post&amp;action=view&amp;post={R:1}" />
        </rule>
        <rule name="rule 7C" stopProcessing="true">
          <match url="^post-([0-9]+)/(.*)$" />
          <action type="Rewrite" url="/index.php?controller=post&amp;action=view&amp;id_post={R:1}" />
        </rule>
        <rule name="rule 8C" stopProcessing="true">
          <match url="^page/([^/]+)/$" />
          <action type="Rewrite" url="/index.php?controller=page&amp;action=view&amp;page={R:1}" />
        </rule>
        <rule name="rule 9C" stopProcessing="true">
          <match url="^feed/$" />
          <action type="Rewrite" url="/feed.php" />
        </rule>
        <rule name="rule 10C" stopProcessing="true">
          <match url="^([^/]+)/$" />
          <action type="Rewrite" url="/index.php?controller=page&amp;action={R:1}" />
        </rule>
      </rules>
    </rewrite>

    <!-- HTTP Errors section should only be enabled if the "Error Pages"
    feature has been delegated as "Read/Write" at the Web Server level.
    <httpErrors>
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" prefixLanguageFilePath="" responseMode="ExecuteURL" path="/index.php\?controller\=page\&action\=404" />
    </httpErrors>
    -->

  </system.webServer>

</configuration>

This should work pretty well as long as the newest Nibbleblog does not utilize php file names in the friendly urls (from my testing, it no longer does that).

SEO Friendly URLs

By default, SEO Friendly URLs are not enabled in Nibbleblog, you need to enable it under SEO tab under settings.

To enable friendly URLs:

  1. Logon to your nibbleblog admin/dashboard
  2. Select Settings from the left-hand pane,
  3. Select SEO Settings tab, at the top,
  4. Scroll down the list of options, until to reach Friendly URLs,
  5. Select the Enable friendly URLs optiong(as we are using IIS we can ignore the instructions regarding .htaccess)
nibbleblog SEO friendly urls