picture of Bryan Mattern

Introduction to SWF and Flash

SWF is the file format used by Macromedia Flash to deliver graphics, animation and sound to users on the Internet. Flash enables you to provide a very rich and dynamic interface to the user. Almost 90% of web users can view SWF content without having to install a browser based plug-in, and over 200 million people have downloaded the Flash player. Macromedia opened the specifications for SWF in April 1998 and SWF support was added to PHP in PHP 4(rc2).
PHPs built-in ability to dynamically create images is one feature that impresses me. It makes reports and interfaces look much more professional and visually pleasing. Initially, I used the various GD code floating around the net to create the graphs I needed to better represent data for various projects I had done. I got really sick of the aliasing and choppyness of the generated images, so decided to try and see if it could be done with vector graphics instead. I think you will agree that the result looks much better. If a picture is worth a thousand words, wonder what a Flash movie is worth?
In this example, I try to keep things simple and just present the basics. My goal was basically just create a drop in for GD generated GIFs and PNGs. You can choose to add enhancements, such as any of the visual effects Flash is famous for. For example, you could make the graph fade in, fly around into place when the page is loaded or pull pieces of the pie out dynamically. Your imagination is the only limitation to what can be done with the PHP SWF functions.
How you get the data you choose to graph is an exercise best left up to the reader. Since this article is about dynamic creation of flash files, I will be using an imaginary table as a data set to create a graphical representation for this example. You will need to intelligently look at your data and decide what the best way to present this data will be. In most of the cases, I have found a pie graph to fit the bill, so this is the example I will use. A line, bar or area graph could easily be created in a similar manner.
Assume we are trying to see what proportion of cities we shipped our packages of jumbo nightcrawlers to. We decide to store this data in a table called "city" in our database called "world". Let's get to work setting up a database table and enter data for the example.
#
# Table structure for table 'city'
#

DROP TABLE IF EXISTS city;
CREATE TABLE city (
   city_id int(14) NOT NULL auto_increment,
   city_name varchar(255) NOT NULL,
   city_timestamp timestamp(14),
   PRIMARY KEY (city_id)
);

#
# Dumping data for table 'city'
#

INSERT INTO city VALUES( '1', 'London', '20000917122625');
INSERT INTO city VALUES( '2', 'London', '20000917122626');
INSERT INTO city VALUES( '3', 'London', '20000917122626');
INSERT INTO city VALUES( '4', 'London', '20000917122627');
INSERT INTO city VALUES( '5', 'Paris', '20000917122631');
INSERT INTO city VALUES( '6', 'Paris', '20000917122632');
INSERT INTO city VALUES( '7', 'New York', '20000917122644');
INSERT INTO city VALUES( '8', 'New York', '20000917122645');
INSERT INTO city VALUES( '9', 'New York', '20000917122646');
INSERT INTO city VALUES( '10', 'New York', '20000917122646');
INSERT INTO city VALUES( '11', 'New York', '20000917122647');
INSERT INTO city VALUES( '12', 'Hong Kong', '20000917122654');

Setting up your system for SWF

I use RedHat Linux 6.2, Apache 1.3.12 and PHP 4.0.2, compiled as an Apache module. If you are using PHP on Windows, some things will be different, you will need to get or build a Flash DLL, but the code should work without modification.
PHP offers the ability to create Shockwave Flash files via Paul Haeberli's libswf module. You need to download libswf at http://reality.sgi.com/grafica/flash/. Once you have libswf all you need to do is to configure PHP --with-swf[=DIR] where DIR is a location containing the directories include and lib. The include directory has to contain the swf.h file and the lib directory has to contain the libswf.a file. When the libswf distribution is unpacked, the two files will be in one directory. Consequently you will have to move the files to the proper location. The resulting direcory structure should look the following:
/usr/local/swf/
		/include/
			swf.h
		/lib/
			libswf.a
		/fonts
...
In order to make the SWF functions work properly, you will have to copy the /usr/local/swf/fonts/ directory so it is accessable to your web server (The best way to do this with Apache and mod_php, is to use absolute paths and copy the directory to your Apache installation's DocumentRoot). A small C program is provided in the libswf distibution to convert Type 1 fonts so they can be use with Flash. Because we will be dynamically creating and writing SWF files, the user the web server runs as will have to have write permission wherever you store the files.

Lets Bake Some Pies

Once you've successfully installed PHP with Shockwave Flash support you are ready to create Shockwave files using PHP. The easiest way to learn is to jump straight into the code. The first file contains example code of how to use the class. It also shows you how to embed a Flash file in an HTML document.

<?php

// include class needed for flash graph
include("class.pie.flash.php");

mysql_connect ("localhost""root""");

$query "SELECT DISTINCT city_name, COUNT(city_id)
    FROM city
    GROUP BY city_name;"
;

$result mysql_db_query ("hermes",$query);

while (
$row mysql_fetch_array ($result)) {
    
$city_counts[] = $row["COUNT(city_id)"];
    
$city_names[] = $row["city_name"];
}

mysql_free_result ($result);

// Instantiate new object
$graph = new flash_pie($city_counts"city.swf");

// set graph title (should not exceed about 25 characters)
$graph->pie_title("City Results"30);

// set graph legend
$graph->pie_legend($city_names);

// show graph
$graph->show();

// free resources
$graph->close();

?>

<?php
<html>
<
head>
<
meta http=equiv="Expires" content="Fri, Jun 12 1981 08:20:00 GMT">
<
meta http=equiv="Pragma" content="no-cache">
<
meta http=equiv="Cache-Control" content="no-cache">
<
meta http=equiv="Content-Type" content="text/html; charset=iso-8859-1">
</
head>
<
body bgcolor=white>
<
div align=center>
<
embed src="city.swf" quality=high loop=false pluginspage="http://www.macromedia.com/
shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"
type="application/x-shockwave-flash" width=600 height=300></embed>
</
div>
</
body>
</
html>
?>

<?php

class flash_pie {

// class variables

// setup some global colors
var $r_arr = array(0.1,  101010.3882352940.40.3882352940.929411765);
var 
$g_arr = array(1,    001100.8,         0.40.8,         0.439215686);
var 
$b_arr = array(0.25010111,           0.41,           0.043137255); 

var 
$percents;

function 
flash_pie($values$this_file) { //begin constructor
    // to write out code directly to browser, set content header and use "php://stdout"
    //swf_openfile ("php://stdout", 700, 250, 30, 1, 1, 1);
    //header("Content-type: application/x-shockwave-flash");

    
swf_openfile ($this_file100045030111);
    
    
// set up viewport for flash movie
    
swf_ortho2 (-400300 , -90250); 

    
// choose the font we will use for pie graph
    
swf_definefont(10"Mod");

    
// get sum of array for percents/slices
    
while(list($key,$val) = each($values)) { 
        
$sum $sum $val
    }

    for (
$i=0$i<count($values); $i++) {
        
// calculate how big they need to be and then
        // draw all of our slices
        
if ($i == 0) { 
            
// setup parameters for first slice
            
$begin 0;
            
$val $values[$i]/$sum;
            
$end $val*360;
            
swf_translate(-20000);
        } else {
            
// setup parameters for every other slice
            
$begin $end;
            
$val $values[$i]/$sum;
            
$end $end $val*360;
        }

        
// function call to add slice
        
$objID 1+$i*10;
        
$this->show_slice($i$objID$begin$end);

        
// put together percent array for all labels
        
$this->percents[$i] = round($values[$i]/$sum*100);           
    }
    
}  
//end flash_pie

function show_slice($i$objID$begin$end) {
    
// draws a slice and places it in our frame
    
swf_addcolor($this->r_arr[$i], $this->g_arr[$i], $this->b_arr[$i], 1);

    
swf_startshape($objID);
    
swf_shapefillsolid(0001);
    
swf_shapearc(00100$begin$end);
    
swf_shapecurveto(0000);
    
swf_endshape($objID);

    
swf_pushmatrix();
    
swf_placeobject($objID1);
    
swf_popmatrix();
    
swf_showframe();
}


function 
pie_legend($labels) {
    
// draws the legend and labels and places it in our frame
    
for ($i=0$i<count($labels); $i++) {
        
swf_addcolor($this->r_arr[$i], $this->g_arr[$i], $this->b_arr[$i], 1);

        
swf_definerect($i+10001020200);
        if (
$i == 0) {
            
swf_translate(120750);
        } else {
            
swf_translate(0200);
        }
        
swf_placeobject($i+10001);

        
swf_translate(050);
        unset(
$label);
        
$label $labels[$i];
        
$label .= " (";
        
$label .= $this->percents[$i];
        
$label .= " percent)";
        if (
$i==0) {
            
$width = (swf_textwidth($label)/4)+30;
        } else {
            
$width round(swf_textwidth($label)/2)+30;
        }
        
$this->pie_text($i-1000"$label"15$width0);
        
swf_translate(-$width00);
    }
    
swf_translate($width30*count($labels), 0);
}               


function 
pie_text($id$text$size$x$y) {
    
// simple function to draw text ($text) at ($x,$y) with font size ($size)
    // set color of text to black
    
swf_addcolor(0,0,0,0);

    
// set font size and slant
    
swf_fontsize($size);
    
swf_fontslant(0);

    
// define, position and place text in frame
    
swf_definetext($id"$text"1);
    
swf_translate($x$y0);
    
swf_placeobject($id1);
}

function 
pie_title($text$size) {
    
// simple function to draw title and set lineup
    // $text should not exceed about 25 characters
    
$this->pie_text(99$text$size0150);
    
swf_translate(0, -3000);
}       

function 
show() {
    
// show the frame
    
swf_showframe();
}


function 
close() {
    
// flush our buffer and return movie
    
$data swf_closefile(1);
}               

// end class flash_pie

?>
Note that you can also feed the resulting SWF file out to the browser instead of writing it out to a file as I present in the tutorial. While this may be useful for testing purposes, you will rarely use just a flash file, most often, you will want to embed the flash file in an HTML document. If you choose to output the Flash file directly to the browser, you can do so by setting the header content type with:
header("Content-type: application/x-shockwave-flash")
and changing swf_openfile("filename", ...) to swf_openfile("php://stdout", ...)

Links to More Information

You can read up on the swf_* PHP functions at: http://www.php.net/manual/ref.swf.php
You can download the swf library used by PHP at: http://reality.sgi.com/grafica/flash/
You can find more Flash tools and information at: http://openswf.org
You can find out more about the Macromedia Flash SDK at: http://www.macromedia.com/software/flash/open/licensing/