DevX HomePage

PHP Developers Don't Need Silverlight—Or Do They?

Think PHP developers don't need Silverlight? Think again. By dynamically generating XAML (Extensible Application Markup Language), PHP developers can buff their skills with some very cool Microsoft® Silverlight™ tricks, adding a whole new responsive visual element to their PHP pages. This walkthrough goes through the details of building a simple Silverlight app just using XAML code, JavaScript, and PHP.

Silverlight gives a lot of love to .NET coders, especially those versed with Microsoft® development tools like Microsoft® Visual Studio® 2008 and the new Microsoft® Expression® Studio. But PHP developers have a lot to benefit from, as well. In fact, using the Silverlight runtime, XAML, PHP code, and a touch of JavaScript, you can add a lot of splash to your PHP apps.

To demonstrate the versatility of Silverlight as a browser plug-in, I'm going to walk through the development of a simple app without using Microsoft development tools. This demo will focus on the Silverlight runtime's role as a XAML interpreter. Since it doesn't get into .NET development, you can do this with the Silverlight 1.0, as well as Silverlight 2.0 alpha.

The walkthrough will cover a few key principles that you can build on to create more robust PHP applications:

  • The use of XAML in a Silverlight application.
  • Delivering dynamic XAML using PHP.
  • Adding mouse events to XAML code to create a highly responsive UI.

    Note: the work here can be done in any text editor, including Notepad if that's your thing. Personally, I prefer Editplus—something nice and simple.

    Step One: Create a Simple Page with a XAML Component
    The first step will be the most complicated. Your goal here is just to get something up and running without using the Expression Studio.

    First, make sure you have the latest Silverlight runtime installed. You can use the recent Silverlight 1.0 release, but since other articles on this site require Silverlight 2.0 alpha, you might as well install the latest 2.0 refresh.

    Next, create a control panel in XAML format. Make a row of colored dots, such as Figure 1. (Confession #1: a variety of WYSIWYG XAML editors are in various stages of production and release. But for this demo I used Microsoft® Expression® Design. After drawing a series of colored dots, I used the Export function, set it to Silverlight, and accepted all other defaults.)

    Figure 1. XAML Control Panel

    Or, if you want, just copy and paste Listing 1 into a file called controlPanel.xaml.

    Listing 1: controlPanel.xaml

    <?xml version="1.0" encoding="utf-8"?> 
    <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="controlPanel_design">
    <Canvas x:Name="Layer_1" Width="640" Height="80" Canvas.Left="0" Canvas.Top="0">
    <Ellipse x:Name="Ellipse" Width="71" Height="71" Canvas.Left="99.5133"
    Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3" StrokeLineJoin="Round"
    Stroke="#FF000000" Fill="#FFFF0000"/>
    <Ellipse x:Name="Ellipse_0" Width="71" Height="71" Canvas.Left="192.86"
    Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3" StrokeLineJoin="Round"
    Stroke="#FF000000" Fill="#FFFFFF00"/>
    <Ellipse x:Name="Ellipse_1" Width="71" Height="71"
    Canvas.Left="286.207" Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3"
    StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF00C800"/>
    <Ellipse x:Name="Ellipse_2" Width="71" Height="71"
    Canvas.Left="379.553" Canvas.Top="5.5"
    Stretch="Fill" StrokeThickness="3" StrokeLineJoin="Round"
    Stroke="#FF000000" Fill="#FF230FD2"/>
    <Ellipse x:Name="Ellipse_3" Width="71" Height="71"
    Canvas.Left="472.9" Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3"
    StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFC80FA0"/>
    </Canvas> </Canvas>

    A couple of things to note about the XAML, because it'll come into play later:

  • As you can see, it's just XML. As such, it can be delivered as any other XML document, as long as the document type is defined as such.
  • Note how the image in Figure 1 is translated into nothing more than a series of Ellipse tags nested with a Canvas tag. As one might imagine, it shouldn't be too hard to generate something like this programmatically.

    The key to using XAML on your page and making it a Silverlight application is the Silverlight.js file, which will be called on your page. Both Visual Studio 2008 and Expression Studio tools automatically create this file for inclusion in your web project. For this demo, you'll need to download it here. You can read more about this file and some of the Silverlight plumbing that goes with it on MSDN's "Instantiating a Silverlight Plug-in."

    Note: using this file independently like this is generally not advised because Microsoft frequently updates the JavaScript. In fact, Confession #2, to create this file, I started up a dummy Microsoft ® Expression® Blend 2 project and copied its Silverlight.js into this demo.

    You'll also need some additional JavaScript to instantiate the Silverlight object on your page. So create a new file called createSilverlight.js and include the code in Listing 2.

    Listing 2: createSilverlight.js

    function createControlPanel()
    {
    	Silverlight.createObjectEx({
    		source: "controlPanel.xaml",
    		parentElement: document.getElementById("dotControlPanel"),
    		id: "slControlPanel",
    		properties: {
    			width: "100%",
    			height: "100%",
    			inplaceInstallPrompt:true,
    			version: "1.0"
    		}
    	});
    }
    
    
    if (!window.Silverlight) 
    	window.Silverlight = {};
    
    Silverlight.createDelegate = function(instance, method) {
    	return function() {
    		return method.apply(instance, arguments);
    	}
    }

    Take a closer look at Listing 2 and you'll see a few things going on.

    • The createSilverlight.js page is the standard file name for the instantiation code. It also usually holds the createSilverlight function. But as you can see here, the naming is up to you.
    • Look at the Silverlight.createObjectEx call. For now, the source is a XAML file—the file you just created. But that source can actually be anything that returns XAML code, including a compiled library or a PHP script.
    • parentElement specifies the DOM object in which the results will appear. You'll get to that in just a moment.
    • id is the ID for this Silverlight control. When creating multiple controls, be sure this is a unique name.
    • Especially take a look at the properties attribute—you can specify actual dimensions or just use 100% like I am here. But you should be very particular about your choice for "inplaceInstallPrompt" and the version. The install prompt is covered in more detail in the above-referenced MSDN article. As to the version, as stated earlier this will work with the Silverlight 1.0 runtime, so you can specify 1.0 here. But when you build some .NET code, which is where the real power of Silverlight comes unleashed, be sure to specify 2.0 here instead.

    To pull it all together, make your test page. Create a new file called PHPdemo.htm and add the code in Listing 3.

    Listing 3: PHPdemo.htm

    <html> 
     <head>
      <title>Silverlight PHP Demo</title>
    	<script type="text/javascript" src="Silverlight.js"></script>
    	<script type="text/javascript" src="createSilverlight.js"></script>
    	<style type="text/css">
    		.controlPanel {
    			height: 80px;
    			width: 640px;
    		}
    		.XAMLCanvas {
    			height: 480px;
    			width: 640px;
    		}
    	</style>
     </head>
    
     <body>
    	<div id="dotControlPanel" class="controlPanel">
    		<script type="text/javascript">
    			createControlPanel();
    		</script>
    	</div>
    	<div id="dotDisplayCanvas" class="XAMLCanvas">
    	</div>
     </body>
    </html>
    Figure 2. Simple Silverlight Page

    Nothing too fancy here. You'll see a few things that aren't being used yet but for the most part, it's self-explanatory. You're pulling in the two JavaScript files, setting some dimensions via CSS, and then adding two divs, one for the control panel and one for the results. Within the div, you have a JavaScript call to the function that instantiates the Silverlight object.

    Run this in a Web browser and you should see some Silverlight in action. Hopefully it'll look something like Figure 2.




    Step Two: Add XAML Mouse Events
    The bulk of the work is done. Now things get really interesting. The next few steps will be taken in pieces, each building on the last, so you can make sure everything's working before you get too far along. In this step, you'll add some mouse events to the XAML code from Listing 1.

    Silverlight supports several events that you can raise in your XAML and handle via code, in this case JavaScript. For this demo, you'll play with one mouse event in particular: MouseLeftButtonUp, though it'd be good to review the others, such as MouseMove, MouseEnter, etc. These are described in more detail in "Silverlight Mouse Support."

    Go back to the control panel XAML code in Listing 1. At the end of each ellipse tag, add the following:

    MouseLeftButtonUp="dropDots"

    In your createSilverlight.js file, add a new function:

    function dropDots(sender, mouseEventArgs)
    {
    	alert('dots dropped!');
    }

    Reload the page. Now, when you click on one of the colored dots, you should see a popup.

    Next, get a little fancier. Replace the alert statement you just wrote with the following:

    sender.fill = "red";

    This is just a quick demo to show how easy it is to interact with XAML. Reload the page and you should be able to turn each dot red by clicking on it. The "Scripting and Mouse Events" QuickStart on the Silverlight site walks you through a lot more of this type of thing.

    Now replace the sender.fill assignment with a new statement:

    alert(sender.Fill.Color); 

    This returns the fill color of the circle as a Long value. That's good enough for now.

    Step Three: Add PHP as XAML Source
    So where does PHP come into play? As mentioned earlier, you can use it as the source for a Silverlight object. In fact, for now, just to get a working example up and running, use the same XAML source as the control panel you've already created.

    Save the code in Listing 4 to "drawDots.php".

    Listing 4: drawDots.php

    <?
    header('Content-type: text/xml');
    ?>
    <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="controlPanel_design"> <Canvas x:Name="Layer_1" Width="640" Height="80" Canvas.Left="0"
    Canvas.Top="0"> <Ellipse x:Name="Ellipse" Width="71" Height="71" Canvas.Left="99.5133"
    Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3" StrokeLineJoin="Round"
    Stroke="#FF000000" Fill="#FFFF0000"/> <Ellipse x:Name="Ellipse_0" Width="71" Height="71"
    Canvas.Left="192.86" Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3"
    StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFFFFF00"/> <Ellipse x:Name="Ellipse_1" Width="71" Height="71"
    Canvas.Left="286.207" Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3"
    StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF00C800"/> <Ellipse x:Name="Ellipse_2" Width="71" Height="71"
    Canvas.Left="379.553" Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3"
    StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF230FD2"/> <Ellipse x:Name="Ellipse_3" Width="71" Height="71"
    Canvas.Left="472.9" Canvas.Top="5.5" Stretch="Fill" StrokeThickness="3"
    StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FFC80FA0"/> </Canvas> </Canvas>

    Next, add a new function to createSilverlight.js:

    function createDisplayCanvas()
    {
    	Silverlight.createObjectEx({
    		source: "drawDots.php",
    		parentElement: document.getElementById("dotDisplayCanvas"),
    		id: "slDisplayCanvas",
    		properties: {
    			width: "100%",
    			height: "100%",
    			inplaceInstallPrompt:true,
    			version: "1.0"
    		}
    	});
    }
    Figure 3. PHP as XAML Source

    Last, in PHPDemo.htm, replace

    <div id="dotDisplayCanvas" class="XAMLCanvas">
    	</div>

    Load the page and you should see a double row of colored dots, as in Figure 3. with

    <div id="dotDisplayCanvas" class="XAMLCanvas">
    		<script type="text/javascript">
    			createDisplayCanvas();
    		</script>
    	</div>

    Not particularly inventive, but it gets the point across.




    Step 4: Create Dynamic XAML with PHP
    Now that all the pieces are in place, you can add the final code. In Step 2 you created some mouse events. In Step 3 you created some PHP that displays to your canvas area. You can probably guess what will happen next.

    For this demo, your control panel will have one and only one function: add colored dots. You have many options for doing this, but the one I'll cover here is the use of a URL string to pass a concatenated JavaScript variable. In summary:

  • Every time you click on a dot, the JavaScript will add a new value to a string.
  • That string will then be passed to your PHP script.
  • The PHP script explodes the string into an array.
  • Based on the array length and values, it will return a set of dots.

    To start, the createSilverlight.js file needs a bit of code. While colors can be passed as common names, I prefer working with hex values, which takes a little more work. As you saw earlier, the Fill.Color value returns a long. To convert that value to hex, add the following function (credit goes to Suyog Kale for posting this routine):

    function getFillColor(color)
    {
    	var fill = color;
    	if (fill < 0) {
    		fill = (16777216 + parseInt(fill));
    	}
    	fill = fill.toString(16);
    	if (fill.length > 6) {
    		fill = fill.substr(fill.length - 6);
    	}
    	while (fill.length < 6) {
    		fill = "0" + fill;
    	}
    	fill = "ff" + fill;
    	return fill;
    }

    Note the last addition to the string: "ff". Silverlight works with 8-digit hex values for color, comprised of the 6-digit value preceded by "ff".

    Replace the dropDots() function entirely with the following:

    var dotColors="";
    
    function dropDots(sender, mouseEventArgs)
    {
    	if (dotColors != "")
    	{
    		dotColors += ",";
    	}
    	dotColors += getFillColor(sender.Fill.Color);
    	createDisplayCanvas();
    }

    Note the new global var "dotColors".

    In the createDisplayCanvas() function, replace

    source: "drawDots.php",
    with
    source: "drawDots.php?colors=" + dotColors, 

    At this point, createSilverlight.js should look something like Listing 5.

    Listing 5: Completed createSilverlight.js

    function createControlPanel()
    {
    	Silverlight.createObjectEx({
    		source: "controlPanel.xaml",
    		parentElement: document.getElementById("dotControlPanel"),
    		id: "slControlPanel",
    		properties: {
    			width: "100%",
    			height: "100%",
    			inplaceInstallPrompt:true,
    			version: "1.0"
    		}
    	});
    }
    
    
    if (!window.Silverlight) 
    	window.Silverlight = {};
    
    Silverlight.createDelegate = function(instance, method) {
    	return function() {
    		return method.apply(instance, arguments);
    	}
    }
    
    var dotColors="";
    
    function dropDots(sender, mouseEventArgs)
    {
    	if (dotColors != "")
    	{
    		dotColors += ",";
    	}
    	dotColors += getFillColor(sender.Fill.Color);
    	createDisplayCanvas();
    }
    
    function createDisplayCanvas()
    {
        Silverlight.createObjectEx({
    	source: "drawDots.php?colors=" + dotColors,
    	parentElement: document.getElementById("dotDisplayCanvas"),
    	id: "slDisplayCanvas",
    		properties: {
    			width: "100%",
    			height: "100%",
    			inplaceInstallPrompt:true,
    			version: "1.0"
    		}
    	});
    }
    
    function getFillColor(color)
    {
    	var fill = color;
    	if (fill < 0) {
    		fill = (16777216 + parseInt(fill));
    	}
    	fill = fill.toString(16);
    	if (fill.length > 6) {
    		fill = fill.substr(fill.length - 6);
    	}
    	while (fill.length < 6) {
    		fill = "0" + fill;
    	}
    	fill = "ff" + fill;
    	return fill;
    }

    Replace the contents of drawDots.php entirely with Listing 6.

    Listing 6: Completed drawDots.php

    <?
    header('Content-type: text/xml');
    ?>
    
    <?
    	$arrColors = explode(",",$_GET["colors"]);
    	srand(time());
    ?>
    
    <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="resultCanvas">
    <Canvas x:Name="Layer_1" Width="640" Height="80" Canvas.Left="0"
    Canvas.Top="0"> <? $n = 0; foreach ($arrColors as $c) { $n++; $lft = (rand()%530); $top = (rand()%370); echo('<Ellipse x:Name="Ellipse_' . $n . '" Width="100" Height="100"
    Canvas.Left="' . $lft . '" Canvas.Top="' . $top . '" Stretch="Fill" Fill="#' . $c . '"/>'); } ?> </Canvas> </Canvas>

    As you can see, mouse events in the XAML file trigger a JavaScript routine which concatenates a global variable with the fill color of the selected dot. It then redraws the canvas by calling the createDisplayCanvas() function, which passes this string via GET to the PHP page.

    The new PHP script explodes the GET string into an array, which can then be looped through via foreach. As an added bonus, I've added a bit of randomness to the equation by also setting Canvas.Left and Canvas.Top to random values within the Ellipse XAML echo. This serves no practical function whatsoever other than, hopefully, to stimulate the imagination a bit and induce more creative and interesting demonstrations of the technique.

    The final result can be viewed here: www.justinwhitney.com/slphpdemo/PHPdemo.htm. You can also download a zip of the final source code here.

    Where to Go From Here
    This walkthrough barely scratches the surface of what you can do with Silverlight and PHP. Below are a few additional resources for investigating the topic further. If you come up with something cool, post it and send us a link.

  • Silverlight Downloads

  • Delivering Parameterized Silverlight Content with PHP

  • Silverlight with PHP

  • Flickr Example

  • Silverlight / PHP / MySQL / Linux / Firefox Demo

  • Instantiating a Silverlight Plug-in (Using CreateSilverlight.js and Silverlight.js)

  • Silverlight QuickStart: Scripting and Mouse Events

  • Binding a XAML Application to DataBase Data

  • * This article was commissioned by and prepared for Microsoft Corporation. This document is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.


    Justin Whitney is a regular contributor to DevX.com and Jupitermedia. He currently lives in San Francisco, where he consults for leading high-tech firms and writes about emerging technologies.