WordPress on .NET 4.0

WordPress logoEDIT: This  is detailed tutorial mainly for Windows. Now there is a package of WordPress with embedded Phalanger which is prepared both for .NET and Mono. You can download directly from http://wpdotnet.com

WordPress is an open-source content management system (CMS) built using PHP and MySQL. It’s one of the most frequently used solutions for blog publishing. In this article I describe how to compile this PHP application to .NET Framework 4.0 using Phalanger.

Contents

Motivation

Why would you want to run WordPress as a .NET application? There are several good reasons:

  • If you are working for a customer who requires using the .NET platform, you can compile WordPress using Phalanger and it will run as a native .NET application.
  • Applications compiled using Phalanger are very efficient. They outperform standard PHP installation. We will write about performance comparison in some later article.
  • Thanks to Phalanger, it is easier to access .NET functionality from your PHP code. Therefore plugins using .NET functions are easily done. In some future article, we will look how to integrate WordPress with ASP.NET.
  • Extending WordPress can be done even in a .NET language like C#.
  • Syntactic and semantic errors may occur in PHP in run time, but compilation process in Phalanger discoveres them right away.

Now let’s look at the steps that are needed to compile and run WordPress using Phalanger.

Requirements

Before you can continue, you need to download and install the following software:

Copy to publishing location

First copy WordPress into its directory in wwwroot of IIS (or any other virtual directory). In this tutorial I will be using c:\inetpub\wwwroot\wordpress\ as a directory for WordPress. Set write and modify permissions for IIS_IUSRS on this folder. This is necessary since WordPress creates wp-config.php file during the installation. Also WordPress needs the write permission to allow auto update feature, downloading themes, plugins,… If you won’t allow this you can create the configuration file manually during the installation. WordPress recognizes that it doesn’t have permissions to create the file and gives you content for this file. Then you can create the file manually.

To set the permissions, open Command Prompt with the Administrator permissions  and run the following command:

 icacls c:\inetpub\wwwroot\wordpress /grant BUILTIN\IIS_IUSRS:(OI)(CI)(M) 

Set-up IIS

As any other ASP.NET application, WordPress compiled with Phalanger will have to run in some application pool. For our purposes we create application pool called Phalanger v3.0 and set it to .NET Framework v4.0. After creating the pool, you need to go to Advanced Settings and set “Enable 32-Bit Applications” to True (if you have 64bit operating system). This is necessary, because Phalanger uses native PHP extensions that are compiled as 32bit DLLs.

Advanced Settings of Application Pool

Then we create a web application from c:\inetpub\wwwroot\wordpress virtual directory and associate it with Phalanger v3.0 app pool. All of this can be done just by running following commands:

%systemroot%\system32\inetsrv\appcmd.exe add apppool /name:"Phalanger v3.0"
%systemroot%\system32\inetsrv\appcmd.exe set apppool "Phalanger v3.0" /managedRuntimeVersion:v4.0 /managedPipelineMode:Integrated /enable32BitAppOnWin64:"true"
%systemroot%\system32\inetsrv\appcmd.exe add app /site.name:"Default Web Site" /path:/wordpress /physicalpath:C:\inetpub\wwwroot\wordpress
%systemroot%\system32\inetsrv\appcmd.exe set app /app.name:"Default Web Site/wordpress" /applicationPool:"Phalanger v3.0"

This script uses Default Web Site for WordPress, but you can create Web Site just for WordPress or use any IIS Web Site you have configured in IIS.

Configure ASP.NET using Web.config

Create web.config file in the root directory of WordPress. In this tutorial the path will be c:\inetpub\wwwroot\wordpress\web.config. Copy the following content into your web.config. I will explain just some parts of this configuration, but for a complete explanation of all configuration elements look at http://wiki.phpcompiler.net/Configuration.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="Phalanger" path="*.php" verb="*" type="PHP.Core.RequestHandler, PhpNetCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=0a8e8c4c76728c71" />
    </handlers>
    <defaultDocument>
      <files>
        <add value="index.php" />
      </files>
    </defaultDocument>
    <httpErrors errorMode="Detailed">
       <clear />
    </httpErrors>
  </system.webServer>
  <system.web>
    <globalization responseEncoding="utf-8" fileEncoding="utf-8" />
    <httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0" />
    <pages validateRequest="false" />
  </system.web>
  <phpNet>
    <compiler>
      <set name="EnableStaticInclusions" value="true" />
    </compiler>
    <classLibrary>
      <add assembly="PhpNetMySql, Version=3.0.0.0,Culture=Neutral,PublicKeyToken=2771987119c16a03" section="mysql" />
      <add assembly="php_xml.mng, Version=3.0.0.0, Culture=neutral, PublicKeyToken=4ef6ed87c53048a3" section="xml" />
      <add assembly="php_image.mng, Version=3.0.0.0, Culture=neutral, PublicKeyToken=4ef6ed87c53048a3" section="image" />
      <add assembly="php_zlib.mng, Version=3.0.0.0, Culture=neutral, PublicKeyToken=4ef6ed87c53048a3" section="zlib" />
    </classLibrary>
    <error-control>
      <set name="DisplayErrors" value="false" phpName="display_errors" />
    </error-control>
    <globalization>
      <set name="PageEncoding" value="utf-8" />
    </globalization>
    <bcl>
      <mailer>
        <!-- SMTP server name used for sending e-mails. -->
        <set name="SmtpServer" value="127.0.0.1" phpName="SMTP" />
        <!-- SMTP server port used for sending e-mails. -->
        <set name="SmtpPort" value="25" phpName="smtp_port" />
        <!-- The default value of "From" header. -->
        <set name="DefaultFromHeader" value="info@phpcompiler.net" phpName="sendmail_from" />
      </mailer>
    </bcl>
  </phpNet>
</configuration>

First we have to set IIS to recognize *.php files and send all the requests for these files to Phalangers request handler. This is done in system.webServer/handlers section.

In system.web section we have to turn off default ASP.NET request validation. Usually this prevents script injection attacks, but also prevents sending html during posts and pages editing. We have to leave these controls for WordPress to handle.

All the other Phalanger related configurations are child elements of phpnet element. Class library section defines what PHP extensions WordPress needs (Phalanger installer already adds some of them into machine.config, but you can list them again, to have a track of all the extensions that application needs). The extensions we have in this sample configuration file are basic extensions that WordPress needs. If you install some plugin make sure to add necessary PHP extensions to this configuration.

We set DisplayErrors to false because this web.config is not intended for development, but for production. We don’t want to show warnings (potentially containing sensitive information) to our users. If you enable errors, you can see that Phalanger does more checks than normal PHP. Many possible run-time errors are prevented just by looking at the warnings given during the compilation so you can fix them immediately.

MySQL configuration

The web.config file we discussed uses managed MySql extension (available at http://phalangermysql.codeplex.com), which we strongly recommend to use. It provides around 30% performance benefit over native PHP extension (taken from PHP distribution). However if you decide to use native PHP extension you will have to set password through OLD_PASSWORD not PASSWORD function. To initialize the WordPress database and create a user, you need to run the following command from MySQL Command Line Client as root:

CREATE DATABASE wp;
CREATE USER 'wp_user'@'localhost';
SET PASSWORD FOR 'wp_user'@'localhost'= PASSWORD('password');
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON wp.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;

Precompilation

Phalanger compiles the source code to a .NET assembly that is then compiled to native code by the .NET runtime and executed.  It is not necessary to precompile the web page; sigle scripts will be compiled during first requests subsequently. However it is recommended to precompile the application to make sure the application is errors free and to lower response time during first request. Create build.bat in the wordpress directory with the following content:

C:\Program Files\Phalanger 3.0\Bin\phpc /target:web /root:. /recurse:. /out:Bin /static+ /debug-
This batch file runs the Phalanger compiler to perform the pre-compilation. Detailed documentation for each of phpc option can be found at http://wiki.phpcompiler.net/Phpc.exe (Don’t worry, it is not link to a virus :-) ) Just to briefly explain the options we used:
  • /target:web Phalanger compiles whole page into WebPages.dll module
  • /recurse:. Phalanger will precompile recursively whole directory and its subdirectories
  • /static+ means to use static includes optimization
  • /debug- tells the compiler to generate more optimized code and not to generate debugging information (pdb files) WordPress installation

WordPress Installation

Type http://localhost/wordpress and follow the installation. After installation of WordPress (when wp-config.php file is created) we recommend to recompile it again (using the batch file we created). The same applies if you download new theme or a new plugin. Generally, re-compiling the source code is useful when some files are changed or added (for same reasons as explained in precompilation section). Then type the URL again, wait a moment (during the first request JIT compiles the application to native code and Phalanger loads all the extensions, so it takes some time) and here is your “Just another WordPress site” on .NET 4.0.

WordPress screen

Settings permalinks (nice  URLs)

Permalinks allow you to use a nice URL such as http://www.php-compiler.net/blog/2011/wordpress-on-net-4-0 instead of http://www.php-compiler.net/?p=113. To get nice URLs in WordPress (http://codex.wordpress.org/Using_Permalinks)  it is necessary to install Microsoft URL Rewrite Module (http://learn.iis.net/page.aspx/460/using-url-rewrite-module/). The module is available for x64 and x86 systems. When installed add the following rule to system.webServer element of your web.config:

    <rewrite>
      <rules>
        <rule name="Main Rule" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="index.php/{R:0}" />
        </rule>
      </rules>
    </rewrite>

After this is done go to Dashboard of administration section of WordPress, section Settings – Permalinks, and set the URL you want, e.g. “/%category%/%year%/%postname%”

36 thoughts on “WordPress on .NET 4.0

  1. Nice first step running php code.

    But if you update wordpress or any plugins/themes how to setup the server to enable that on needed compileing so that you dont need to use terminal services connection to the server?

    • Good point! Phalanger automatically recompiles the changed scripts. So no need to configure something on the server. The precompilation is recommended to avoid errors during runtime and lower response time duing first request on the page. But after that performance is equvivalent as without precompilation.

  2. I followed all these instructions but I continually get this error message when trying to access http://localhost/wordpress

    Could not load file or assembly ‘PhpNetMySql, Version=2.1.0.0, Culture=neutral, PublicKeyToken=2771987119c16a03′ or one of its dependencies. The system cannot find the file specified.

    I’ve followed all the instructions for installing the managed MySQL extension for Phalanger 2.1

    Would you mind pointing me in the right direction? Thanks!

    • Thanks for trying Phalanger! The error above means, the file PhpNetMySql.dll or its dependency (MySql.Data.dll) could not be loaded. Navigate to your GAC (C:\Windows\Microsoft.NET\assembly\GAC_MSIL) and ensure you have these assemblies there. If you don’t, reinstall the DLLs by running the install-mysql.cmd command and ensure it succeeded. The command simply installs the DLLs into the GAC using the gacutil.exe tool which is distributed together with the Phalanger.
      If the assemblies are installed, we recommend to restart the ApplicationPool from within the IIS Management Console.

      Let us know your progress! Cheers

      • I really appreciate the quick response! I will try and let you know how it goes.

      • Jakub, all the required assemblies are where they should be and I restarted the application pool but I’m getting the exact same message.

        Could not load file or assembly ‘PhpNetMySql, Version=2.1.0.0, Culture=neutral, PublicKeyToken=2771987119c16a03′ or one of its dependencies. The system cannot find the file specified.

        • You can also try to copy “Mysql.Data.dll” and “PhpNetMysql.dll” into the /Bin subfolder of your WordPress directory. .NET should be able to load them from this location. I’m actually running out of ideas. Ensure you have downloaded 2.1 version of the managed MySQL extension, not 2.0. Your configuration seems to be ok.

        • Moving the dependent files to the bin folder within the WordPress folder did it! I really appreciate your help! Couldn’t have done it without you

          • Glad to hear it! Still I think you probably didn’t have the assemblies in your GAC :-) But I’m really happy that you solve the problem.

  3. Have you ever tested the performance of WordPress on .net vs traditional php? How much slower is your .Net PHP version? I assume it’s written with the Dynamic Language Runtime in C#.

    Cheers

  4. makes me wonder if this could be a stepping stone to slowly converting wordpress to be a native .Net (mvc?) application ;) Swap out one part at a time perhaps.

    • yes, can be done. Also with managed extensions wordpress runs completly managed…so php code can be compiled and left untact ( to have wordpress always up-to-date) and extended with classic .net language as C#.

        • Good point!:) After next Phalanger release (expected in a few days) we’ll publish detailed article exactly about this. To be notified follow us on twitter or facebook.

  5. Hi

    I have followed it to get phpinfo(); showing Phalanger 2.1 is working on a test php file but when I am trying to install WordPress I am getting a white screen (of death) on http://www.mysite.com/index.php/wp-admin/install.php – any ideas?

    Background…

    I am using Phalanger instead of standard fast cgi PHP as I am wanting to slowly migrate several sites from asp, asp.net and plain html files over to a Multi Site (network) install of WordPress on a Windows 2003 box running IIS 6.

    http://www.mysite.com is set up as a standard web site running under .NET App Pool but the only way I believe I can install WordPress in the root as a multi site (network) install so I can have http://www.mysite.com/subsite1 http://www.mysite.com/subsite2 etc whilst still running the old sites is to use Phlanger within this same app pool – is this correct?

    Thanks in advance!

  6. any data on running phpbb? I also noticed that phpbb has a version on the ms web platform installer which is supposed to support sql server… might be nice too.

  7. Great tutorial – I got wordpress on Phalanger up and running straight away, and even appear to have a working multisite going.

    Now, the real reason I am testing is to see if it’s easier to extend wordpress working in Visual Studio and C# – I’d love for your next post to be a beginner’s tutorial (or a series?) – creating a new plugin in c# for example, best practices for integrating wordpress with custom c# pages (within the admin console? if possible, that would be sweet)

    Great work!

    • Thanks! WP Multisite works with 2.1 (October) too, but i’ll recommend you to update to upcoming release when it’s available.

      Our intention is to make developing plugins easier and more eficient with Phalanger than traditionaly. .NET platform with VS as IDE has certainly lot of advantages. I’m going to publish an article about writing plugins for WP in C# soon.

  8. Followed all the steps, installed all the programs and patches and in the end, I get this when loading the page:

    Could not load file or assembly ‘PhpNetCore, Version=2.1.0.0, Culture=neutral, PublicKeyToken=0a8e8c4c76728c71′ or one of its dependencies. The system cannot find the file specified.

    • This article was written some time ago when there was Phalanger 2.1, newest release is 3.0. Please change any 2.1 to 3.0, then it should find the assembly.

  9. I install the latest version 3.0 and successfully compiled wordpress to the WebPages.dll. But when I try to navigate to the local wordpress install I get a HTTP Error 503. The service is unavailable. I can see then that the Phalanger Application Pool was stopped in the process of trying to load the wordpress page. I guess there is a fatal error happening somewhere, but setting DisplayErrors to true in the web.config doesn’t help in getting any more detailed information. Whatever I try I end up with a HTTP Error 503.