Deploying PHP + MySQL + Wordpress on Azure

December 18, 2009 19:31 by jasonp

In this entry, I will talk about the steps needed to get PHP + MySQL + Wordpress running on Azure. I will be using Wordpress here as a sample PHP application but once you know this, you will be able to deploy any PHP application on Windows Azure.

 

Pre-requisites:

1. PHP Binaries for IIS (http://windows.php.net/)

2. MySQL Binaries (Without Installer) (http://dev.mysql.com/downloads/mysql/5.1.html )

2. MySQL PHP Solution Accelerator (http://code.msdn.microsoft.com/winazuremysqlphp )

3. VS2008 SP1/VS2010 Beta 2 w/ Windows Azure SDK

4. Wordpress (Or any PHP Application)

5. “The Lazy Man Hello Cloud PHP” ( http://innovativesingapore.com/post/The-Lazy-Mane28099s-e2809cPHP-Hello-Cloude2809d.aspx ) [Optional but Reccomended]

Phase 1 – Setup

1. Install the MySQL PHP Solution Accelerator         

2. Extract the PHP binaries for IIS to the “php” folder in the PhpMyAdminWebRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\php”

3. Extract the Wordpress files to the “wordpress” folder in the PhpMyAdminWebRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\wordpress”

4. Extract the MySQL Binaries to the “mysql” folder in the MySQL_WorkerRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\MySQL_WorkerRole”

Phase 2 – Windows Azure Cloud Service

5. Create a new “Windows Azure Cloud Service” solution in Visual Studio.

6. Add an existing project, “PhpMyAdminWebRole” (From the Solution Accelerator), to the solution you created.

7. Add another existing project, “MySQL_WorkerRole” (Also from the Solution Accelerator,), to the solution.

8. Right click on “Roles” (Found in your “Windows Azure Cloud Service” project) and select “Add-> Web Role Project in solution” and select the project you added in your solution previously.

9. Repeat step 8, but this time, choose “Add -> Worker Role Project in solution” and select the “MySQL_WorkerRole” you added previously.

Phase 3 – Configuring MySQL_WorkerRole

*For learning purposes we shall not touch on the advance features of the MySQL_WorkerRole in the Solution Accelerator. If you do want to do more with it, please watch this video: http://microsoftpdc.com/Sessions/SVC51 .
For now, we are going to configure the worker role to have only 1 instance.

10. Open up the settings for “MySQL_WorkerRole” (Found in the Roles folder at your “Windows Azure Cloud Service” project) and change the following configurations:

Configuration Section
Instance Count: 1

Settings Section [Name, Type, Value]
TableStorageEndpoint, String, http://table.core.windows.net

BlobStorageEndpoint, String, http://blob.core.windows.net

DataConnectionString, ConnectionString, UseDevelopmentStorage=true

DiagnosticsConnectionString, ConnectionString, UseDevelopmentStorage=true

ContainerName, String, mysqlphp11

FullBackupHour, String, 06:00

IncrementalBackupDuration, String, 10

RecycleThreadSleepTime, String, 300

EnableWindowsAzureDrive, String, False

EnableBackup, String, False

*Note, we will be using the Dev Fabric Storage in this walkthrough, feel free to use your cloud storage if any.


Endpoints (Name, Type, Protocol)

PeerEndpointIn, Internal, tcp

MasterElectionService, Internal, tcp

MySQL, Internal, tcp

InstanceManagerEndpontIn, Internal, tcp


Local Storage

MySQLStorage, 200MB

MySQLDatastore, 1024MB

BlobBackup, 500MB

 

Next up, we want to edit the behavior of the worker role such that when the worker role starts, it will update the PHP ini (configuration) file so that our PHP web role will know where is the MySQL database located in the cloud.

11. Open up MySQLAccess.cs in “MySQL_WorkerRole” project and make the following changes:

In the internal class “MySQLClient” add a string constant – relative path to your php ini file.

Code:
 
private const string REL_PATH_TO_PHP_INI = "./../../PhpMyAdminWebRole/approot/php/php.ini";

 

Next find the line “string masterHost = instance.IPEndpoint.Address.ToString();

“ and add the following after the line:

 

Code:

//Set php ini so PHP knows where is the host and port of the MySQL endpoint

FileStream fs = File.OpenRead(REL_PATH_TO_PHP_INI);

StreamReader reader = new StreamReader(fs);

//Read all text in INI File

string php_ini = reader.ReadToEnd();

 

//Closing resources

reader.Close();

fs.Close();

 

//Add in details (Host IP Address and Port)

php_ini = php_ini.Replace("mysql.default_port =", "mysql.default_port = " + port);

php_ini = php_ini.Replace("mysql.default_host =", "mysql.default_host = " + masterHost);

File.WriteAllText(REL_PATH_TO_PHP_INI, php_ini);               

string iniFile = Path.Combine(baseDir, "my.ini");

File.Copy("my.ini", iniFile, true);

 

 

[NEW UPDATE!]

 

I have changed the logic of the codes to use Environment Variables instead of updating the PHP INI file on runtime. Please make sure your function "public bool Start(int id)" looks something like the one below. (: The code is now easier to understand and shorter.

 

public bool Start(int id)

        {

            try

            {

                string baseDir = RoleEnvironment.GetLocalResource("MySQLStorage").RootPath.Replace('\\', '/');

                string dataDir = RoleEnvironment.GetLocalResource("MySQLDatastore").RootPath.Replace('\\', '/');

                string blobDir = RoleEnvironment.GetLocalResource("BlobBackup").RootPath.Replace('\\', '/');

                LogError("MySql Base directory: {0}", baseDir);

                LogError("MySql Data directory: {0}", dataDir);

 

                string command = Path.Combine(baseDir, @"bin\mysqld.exe");

                SetupBlobBackup(blobDir);

                if (!File.Exists(command))

                {

                    SetupAzureMySql(baseDir);

                    SetupAzureMySqlDataDir(dataDir);

                }

                MySqlConnection rootConn = GetConnection(_endpointName);

                if (IsRunning(_endpointName))

                {

                    int currentId = GetMySqlServerId();

                    if (currentId == id)

                    {

                        return true;

                    }

                    command = Path.Combine(baseDir, @"bin\mysqladmin.exe");

                    Process.Start(command, "-u root shutdown");

                }

              

                RoleInstanceEndpoint instance;

 

                //Get the "MySQL" instance

                instance = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MySQL"];

 

                //Get the port of the instance

                string port = instance.IPEndpoint.Port.ToString();

                Environment.SetEnvironmentVariable("MasterPort", port, EnvironmentVariableTarget.Process);

                //Get the IP address of the instance

                string masterHost = instance.IPEndpoint.Address.ToString();

 

                Environment.SetEnvironmentVariable("MasterHost", masterHost, EnvironmentVariableTarget.Process);

 

 

 

                string iniFile = Path.Combine(baseDir, "my.ini");

                //update the my.ini file with mysql server details

                UpdateMyIni(iniFile, baseDir, dataDir, port, id.ToString());

                ProcessStartInfo startInfo = new ProcessStartInfo(command);

                startInfo.RedirectStandardOutput = true;

                startInfo.WorkingDirectory = baseDir;

                startInfo.UseShellExecute = false;

                startInfo.CreateNoWindow = false;

                startInfo.Arguments = "--console";

                Process driver = new Process();

                driver.StartInfo = startInfo;

                driver.Start();

 

 

                StreamReader sr = driver.StandardOutput;

                string output = sr.ReadToEnd();

                while (!IsRunning(_endpointName))

                {

                    Thread.Sleep(TimeSpan.FromSeconds(10));

                }

            }

            catch (Exception ex)

            {

                LogError("Error in MySqlAccess start(): {0}", ex.Message + ex.StackTrace);

                return false;

            }

            return true;

        }

 

Phase 4 – Configuring Wordpress

12. Copy “wp-config-sample.php” in the “wordpress” folder to “wp-config.php” then open up “wp-config.php”

13. You may want to look at http://codex.wordpress.org/Editing_wp-config.php to know more about what each setting does.

 

Under the MySQL hostname section, set it to be “define('DB_HOST', ini_get("mysql.default_host").':'.ini_get("mysql.default_port"));” , without the quotes of course ;)

[NEW UPDATE!]

Under the MySQL hostname section, set it to be “define('DB_HOST', getenv("MasterHost").':'.getenv("MasterPort"));” , without the quotes of course ;)

 

For the rest of the settings, configure it as per normal (refer to:  http://codex.wordpress.org/Editing_wp-config.php)

 

Phase 5 – Deploying

14. We will use the Dev Fabric for now. Hit F5 and wait for all your instances to run.

Important : For those who want to deploy on the cloud,

 

Phase 6 – Database Setup + Testing

15. Navigate to your PhpMyAdmin site. (If you didn’t change any settings, it should be at http://localhost:81/PhpMyAdmin/index.php )

16. Login as root with no password.

17. Create a new database (the name for the database you defined when setting up wp-config.php, lets say “wordpressdb”) called “wordpressdb”.

18. Create new user with the credentials you set in “wp-config.php” previously and give the necessary rights. Remove the root users’ privileges after you created the new user (security concerns here.)

19. You can now proceed to your WordPress app to test! (Default: http://localhost:81/wordpress/index.php)
WordPress will detect whether the app have been set up or not and prompt you accordingly. Enjoy your new PHP Application using MySQL on Windows Azure Cloud!

If you have any queries, feel free to email me at v-japoh@microsoft.com or MSN me @ Jason_scorpio@hotmail.com . ;)

 

You just need to change the storage settings to point to your Windows Azure storage and it will work. Publish the project as per normal and deploy as per normal.

 

---

 

Settings for MySQL:

 

DataConnectionString, ConnectionString, UseDevelopmentStorage=true

DiagnosticsConnectionString, ConnectionString, UseDevelopmentStorage=true

 

Change the above to use Windows Azure Storage.

 

Common Problems Encountered & Solutions

Here I have included some of the problems others faced for the benefit of those who might meet the same problems (:

(1) phpmyadmin folder is empty

     - Could not find file 'C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\PHPMyAdmin\browse_foreigners.php';

     - Could not find file 'C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\PHPMyAdmin\bs_change_mime_type.php';    

- Could not find file 'C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\PHPMyAdmin\bs_disp_as_mime_type.php'.

     Solution: I downloaded the phpmyadmin and paste the folder into the phpmyadmin folder in Accelerator.

 

(2) Cannot load mysql extension.

     Solution: In php.ini, uncomment extension=php_mysql.dll, extension=php_mbstring.dll.

 

(3) HTTP Error 500.0 - Internal Server Error

     Solution: In php.ini, locate the extension_dir setting. Change the value to “./ext” and locate the cgi.force_redirect setting and remove the comment and set the value to 0. Set cgi.fix_pathinfo and fastcgi.impersonate to 1.

 (4)Missing Dlls

     Solution: If the dlls are not found inside the windows php distribution binaries, the dlls belongs to optional add-ons. You can simply delete the missing dll references from the project.

 


Windows Live Messenger Theme Pack

December 14, 2009 21:49 by jasonp

Here are a list of things which you might not know about when creating a Windows Live Messenger Theme Pack:

Known Issues

  • COM Object "MessengerContentInstallerLibrary" does not works on 64-bit machines.
    Seems like you need to target the build to only x86 machines (32-bt machines) that will force the assembly to run in WOW64 instead of 64 bit
  • You need to be signed in to Windows Live Messenger to be able to install a theme pack.
  • A theme pack must be served from a HTTP Server.
  • Therefore, you must be connected to the internet to install a theme pack. (There is a workaround for this, to simulate a http server using Sockets, which I didn't have any success in it.)

 

How to handle Installer events

To notify your application after the installer has finished installing the theme pack use the following event handler, DMessengerContentEvents_OnContentInstalledEventHandler

Example:

mci = new MessengerContentInstaller();

MessengerContentInstaller

 

 

 

mci.OnContentInstalled +=new DMessengerContentEvents_OnContentInstalledEventHandler(mco_OnContentInstalled); } 

private void mco_OnContentInstalled(int lhrResult)

 

 

 

 

 

To identify whether the installation has an error while installing, check the "int lhrResult" param. If the value is = 0, the installation completed successfully. Other than that, the installation has failed and you need to let the user retry the installation.

A theme pack (winter themed pack) which I built is available here: http://jasoncloud.cloudapp.net/ .

{

...

 


The Lazy Man’s “PHP Hello Cloud”

December 11, 2009 02:48 by jasonp

Due to the popular demand on how to actually host a PHP application on Windows Azure, this post teaches you the easiest way to deploy your PHP applications on the Cloud with the least effort and there is no need to use Windows Azure

Resources Needed:

1. PHP Binaries for IIS (http://windows.php.net/)
2. MySQL PHP Solution Accelerator (
http://code.msdn.microsoft.com/winazuremysqlphp)
3. VS2008 SP1/VS2010 Beta 2 w/ Windows Azure SDK

Steps:

1. Install the MySQL PHP Solution Accelerator.

2. Extract the PHP binaries for IIS to the “php” folder in the PhpMyAdminWebRole directory. E.g. “C:\Samples\AzureMySQLPHP_x86\PhpMyAdminWebRole\php”

3. Create a new “Windows Azure Cloud Service” solution in Visual Studio.

4. Add an existing project, “PhpMyAdminWebRole” (From the Solution Accelerator), to the solution you created.

5. Right click on “Roles” and select “Add-> Web Role Project in solution” and select the project you added in your solution previously.

6. Add a new text file in “PhpMyAdminWebRole” and name it “index.php”. The contents of the file is “ <?php echo ‘Hello Cloud’; ?> “

7(Optional). Open Web.config and replace “ <add value="Admin.aspx"/>” to “ <add value="index.php"/>

 

 

And you are all set! Hit F5 in your Visual Studio to see your work in action on the Development Fabric.


ASP.NET MVC hosted on Windows Azure

September 23, 2009 02:35 by eugene

Have you been hearing a lot of buzz around MVC and want to know more? Ever wondered how you can use two technologies at once? Well that's what Huang Sile did in one of his fun projects here at the MIC. Using ASP.NET MVC he used Windows Azure to host his website built on MVC.

Check out the guide he made to get you started on Windows Azure: http://innovativesingapore.com/post/Getting-on-Windows-Azure-in-3-Days-%28Day-1%29.aspx

More resources on ASP.NET MVC: http://www.asp.net/mvc/

Don't be daunted on starting to study these technologies. Once you know ASP.NET, you can easily jump onto ASP.NET MVC. This can be one of your differentiators as well.

Oh, I almost forgot, check out the site Sile built here: http://www.micsg.com (He got a good domain huh :) )


Getting on Windows Azure in 3 Days (Day 1)

September 15, 2009 01:57 by sile

 

For the past few weeks, I have been working on Windows Azure, going through the process of understanding the concepts and structures of windows azure, deploying simple asp.net sites and web services onto the windows azure hosted service account with data stored on the windows azure storage, as well as working out some solutions to the problems that I have encountered in the process. After going through the whole process, let me summarize and share an efficient way of learning Windows Azure.

Currently Windows Azure quires the developer to apply for a token for tryout, and the process will take about 2 or 3 days. Hence, to be efficient, before starting to read up about Azure, you should take a visit to the following page: http://www.microsoft.com/azure/register.mspx, click on the "Register for Azure Services" to register a token. The process involves confirmation email, setting up a profile on Microsoft Connect if you have not previously done so. After completed the whole process, here is our plan for the next 3 days before the token arrives:

Day 1: Reading up on Windows Azure

Day 2: Try out on local Azure Development Fabric

Day 3: Deploy to Azure when the token arrives :)

----------------------------------------------------- Day 1 ------------------------------------------------------

Before going too technical, it will be good to read up something about cloud computing and what Azure is offering to meet the demand: http://www.microsoft.com/azure/whatisazure.mspx There is no need to read the whole page if you're kind of lazy, just pick up tags like "Windows Azure", "Azure Service Platform" for a glance. If you are really interested in understanding it in greater details, you could watch the video http://channel9.msdn.com/pdc2008/BB01/

Currently for every windows azure token, one will get 2 windows azure storage account and 1 azure hosted service.

A Windows Azure storage account comes with 3 endpoints to support different types of data: tables, blobs and queues, and 2 shared keys. A table storage endpoint comes with a table called "Tables". It is a table that keeps track of all the tables under the endpoint. So to start, you need to insert a table into the table of tables before inserting data into the new table. And for each table, rows are considered as objects which are to be inserted into it and the columns are considered as the properties of the objects. A blob storage endpoint does not come with any default settings, but in order to upload a blob (Binary large object, e.g. mp3 files, ppt files or wmv movie files), a container must be set up first. The container acts just like a directory for your files, and you can set the access policy ( public for anyone, or just for yourself) on the container level, so that the files under it will share the same policy.

You can watch the video here: http://channel9.msdn.com/pdc2008/ES04/ to get a better understanding of the structure of the different storage types. Don't worry about the codes in the presentation, we are only gonna deal with them in day 2.

For windows Azure hosting service, there it is just like a place where you upload your asp.net website files excluding the database and blobs. If you went through all the videos above and understand everything, that's all for day 1, like only 3 hrs? :)

Before you go to bed, download the Azure Tools for Visual Studio and install them:

Tools for Visual Studio: http://www.microsoft.com/downloads/details.aspx?FamilyID=8d75d4f7-77a4-4adf-bce8-1b10608574bb&displaylang=en

To confirm that you have successfully installed the tools for visual studio, right click on the visual studio and click on create a new project, check that there is a tag called “cloud service” under project types. FYI, the development fabric installed also requires windows sql server to be installed into the local machine.

SQL 2008 Express: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=58ce885d-508b-45c8-9fd3-118edd8e6fff

After all these are ready, take a rest, and we are good for Day 2.