Você está na página 1de 491

Summary of Contents

Foreword

Chapter 1 Introduction

Chapter 2 Flash MX Essentials

Chapter 3 Sessions

Chapter 4 File Uploading

Chapter 5 Advanced MySQL

Chapter 6 Sockets

Chapter 7 PHP and XML

Chapter 8 Ming

Case Study 1 Flash, PHP and MySQL

Case Study 2 e-Commerce Site

Reader's Showcase

Appendix A Securing MySQL

Appendix B Resources Section


J Advanced PHP J
J D D (
for Flash
Steve Webster
Matt Rice
Kev Sutherland
DO jacob Hanson
D james Palmer
D ( Todd Marks
D 8 [ Havard Eide

D
D
0
J D 0
D E S l GN E R T 0 D ES l G N E R"'
Advanced PHP for Flash
2002 Apress
Originally published by friends of ED in 2002

AII rights reserved. Ne part of this book may be reproduced. stored in a retrieval system or transmitted
in any farm or by any means, without the prior written permission of the publisher, except in the case
of brief quotations embodied in criticat articles or reviews.

The authors and publisher have made every effort in the preparation of thi5 book ta ensure the accuracy
of the informatian. However, the informatian contained in this book is sold without warranty. either
express or implied. Neither the authors, friends of ED nor its dealers or distributors witl be held liable
for any damages caused or alteged to be caused either direct!y or indirectly by this book.

First Printed September 2002

Trademark Acknowledgements
friends of ED has endeavored to provide trademark information about ali the companies and products
mentioned in this book by the appropriate use of capitals. However, friends of ED cannot guarantee
the accuracy of this information.

ISBN 978-1-59059-187-1 ISBN 978-1-4302-5205-4 (eBook)


DOI 10.1007/978-1-4302-5205-4
Credits
Authors Commissioning Editors
Steve Webster Alan McCann
Matt Rice Andrew Tracey
Kev Sutherland
jacob Hanson Technical Editors
james Palmer Caroline Robeson
Todd Marks Victoria Blackburn
Havard Eide
Project Managers
Reviewers jenni Harvey
Mark Bowen Simon Brand
Mike Brittan
Matthew Gadd Author Agents
Steve Landis Gaynor Riopedre
John Lyons Chris Matterface
Sam Riggs
jeremy Thomas Graphic Editors
Katy Freer
Managing Editor Chantal Hepworth
Chris Hindley
Cover Design
Index jim Hannah
Simon Collins
Special Thanks
Proof reader Alan McCann
Chris Smith
Advanced PHP for Flash

Steve Webster
Steve Webster is a Professional Freelance Web Developer and Author who
specializes in advanced dynamic web application development using PHP and
MySQL with a Macromedia Flash front-end. He has studied for an HND in
Software Engineering, during which time he lectured C/C ++ programming at one
of the largest colleges in the UK. When he's not neck-deep in chapter
manuscripts he's usually working on client projects or updating his personal site
at http://www.codejunkie.co.uk.

Acknowledgements: I have to say a special thank you to my fiancee Nicki for once
again putting up with the relentless hours I spend in front of the computer.
Without your overwhelming support and encouragement I'm not sure that I could
have made it this far, and I only hope that I can repay the favour one day. I can no
longer imagine my world without you in it. I don't know exactly when or how it
happened, but I'm glad it did.

As always, my thanks to the fine people at friends of ED and the rest of the book
development team who have helped to deliver this book. Alan, Gaynor, Matt, john,
Chris and anyone else that I've forgotten -you guys rock!

Matt Rice
Matt is the co-founder of Ricma Studios, a Flash software company dedicated to
Flash MX development. Ricma Studios can be found on the web at
http://www.ricmastudios.com. He also runs swfnews.com, a popular Flash news
site.

Kevin Sutherland
As a developer for over 10 years I have seen a lot of technologies come and go,
right now has got to be the most exciting era in development history, it really is
great to be a part of it. The elitist attitudes have been banished and we're now
witnessing a new dawn in development. Jump on board there's room for
everyone, just be sure to pack plenty of enthusiasm and a little bit of creativity.

'The simple approach is always the best way to go, the art is in finding a simple
approach to a complex challenge, break them down into their smallest
components and even the greatest of challenges can be resolved"
About the Authors

jacob Hanson
I'm a pixel pusher, baby. Half artist, half programmer, half musician--1 love the
sweet spot when they all come together. Be it video games, the demo scene, or
the supposed new media, it's all good. Nothing makes me happier than pushing
the limits of my world and reaching new heights with my arts. I'm currently the
lead developer of a Flash-centered e-learning platform at a large health benefits
company. My other personalities, inclusively called Electric Lucidity, are knee-
deep in large-scale, bleeding-edge rich-client projects.

A big thanks to those that are close to me.

james Palmer
James graduated in 1998 from the Texas A&M Computer Engineering program.
In 2000 he completed his M.S. degree in Computer Visualization. Deeply
technical and profoundly visual, James has been working professionally both in
print and the web since 1994. James founded Caramba Designs in 2001 to
develop web based applications and end-to-end solutions for unique problems.

james would like to extend his thanks to his beautiful wife, Yaya, who he is madly
in love with, his free-thinking parents, his little sister and her husband and the
entire Tiger Marmalade clan for being the great friends that they are.

Todd Marks
Todd is currently a freelance developer, instructor, and author. In 2000 Todd
moved from teaching Mathematics and Computer Science in the public sector to
VP of Research and Development at digitalorganism (www.digitalorganism.com).
Since then Todd has worked extensively with ActionScript, PHP, Lingo, and
numerous other development languages, placing cutting edge code in several
projects including digitalorganism's showcase site. Todd's contributions have
earned him three Flash Film Festival nominations, Macromedia Site of the Day,
two Addy Awards, and several educational partnerships. Todd is a Macromedia
Certified Developer, Designer, and Subject Matter Expert, and has contributed to
several books about Flash. His personal site can be found at www.mindgrub.com

Havard Eide
Currently "down under" doing Multimedia at uni, coming from Norway I enjoy
the sun and work with what I like most: coding in any flavors using
PHP/Perl/Java/MySQL (whatever I can get my hands on) and integrating them into
various media but I keep coming back to flash.

Must give much respect to my family back home in Norway. And to lain for letting
me borrow the iBook when mine died 3 days before deadline (legend!).

"Several coffee beans was injured making this book"


Advanced PHP for Flash

Foreword 1

1 Introduction 3
The MX connection ........................................................................................................4
Chapter specs-appeal ....................................................................................................4
Chapter 1 - Introduction ......................................................................................4
Chapter 2 - Flash MX Essentials ..........................................................................4
Chapter 3 - Sessions ................................................................................................5
Chapter 4 - File Uploading ....................................................................................6
Chapter 5 - Advanced MySQL ..............................................................................6
Chapter 6- Socket Functions ..............................................................................7
Chapter 7 - PHP and XML ....................................................................................8
Chapter 8 - Ming ......................................................................................................9
Case Study 1: Chat Room ....................................................................................10
Case Study 2: Full E-commerce Site ................................................................ 10
We all need somebody ................................................................................................11
Styles you'll come across in the book .............................................................. 13

Flash MX Essentials 15
LoadVars to the rescue ................................................................................................17
Basic LoadVars ........................................................................................................17
Error detection ........................................................................................................20
Loading JPEG images ....................................................................................................24
Loading Sounds ..............................................................................................................27
SharedObject is your best friend ..............................................................................29

Sessions 37
The "stateless" web ......................................................................................................38
Ordering a pizza ....................................................................................................38
How sessions work ...............................................................................................39
Saving server data ..........................................................................................39
Saving client data ............................................................................................40
Session syntax ..........................................................................................................40
session_start() ..................................................................................................41
session_destroy() .............................................................................................41
session_id() ......................................................................................................41
boolean session _register() ............................................................................41
boolean session_unregister() ......................................................................42
Shopping cart example ................................................................................................42
MySQL database setup ..........................................................................................43
PHP setup ................................................................................................................46
classinfo.php ...................................................................................................47
Contents

startshopping.php ............................................................................................48
clearcart.php ....................................................................................................49
shoppingcart.php ............................................................................................50
checkout.php ....................................................................................................56
The Flash MX file - ShoppingCart.fla ................................................................58
_root ..................................................................................................................59
Cartltem ............................................................................................................61
PlusSign ..............................................................................................................63
MinusSign ..........................................................................................................65
GarbageCan ......................................................................................................66
Totalltem ............................................................................................................67
CheckOut ..........................................................................................................68
All set ........................................................................................................................68
Moving forward ............................................................................................................69

File Uploading 71
HTML ................................................................................................................................72
Flash ..................................................................................................................................73
FTP functions used to create Image Viewer ..................................................73
File types ..................................................................................................................74
MIME types ........................................................................................................75
Ming ....................................................................................................................75
Hidden frames ........................................................................................................76
Client-side communication ..................................................................................79
javaScript methods for Flash objects ..............................................................83
LocalConnection ....................................................................................................83
FSCommands ....................................................................................................84
Shared Object ..........................................................................................................85
The Image Viewer ..................................................................................................85
Adding the code to lmageViewer ....................................................................87
Users ..........................................................................................................................90
Feedback ..................................................................................................................94
FTP access ..............................................................................................................100
Using PHP for the back-end ....................................................................................101

Advanced MySQL 111


Indexes ..........................................................................................................................112
joins ................................................................................................................................114
Inner joins ..............................................................................................................114
Multi-table inner joins ................................................................................ 115
Outer joins ............................................................................................................117
Self joins ................................................................................................................118
Using joins efficiently ................,.......................................................................... 119
Searching ......................................................................................................................120
SQL pattern matching ........................................................................................120
Regular expressions ............................................................................................123
Advanced PHP for Flash

Full-text searching ................................................................................................123


Date and time functions ..........................................................................................126
Common functions ..............................................................................................126
Date arithmetic ....................................................................................................128
Date and time formatting ..................................................................................130
Building the cookbook ..............................................................................................132

Sockets 165
Socket basics ................................................................................................................166
fsockopen() ....................................................................................................166
pfsockopen() ..................................................................................................166
fclose() ...........................................................................................................167
fgets() ..............................................................................................................167
fread() ..............................................................................................................167
fg~tss() ..............................................................................................................167
fputs() ..............................................................................................................168
Feof() ................................................................................................................168
Simple WhoiS Flash MX example ..........................................................................168
Whois.php ......................................................................................................168
Whois.fla ..........................................................................................................169
Email primer ..........................................................................................................171
Sending email with SMTP .................................................................................. 171
SMTP response: ....................................................................................................172
Retrieving email with POP ........................................................................................172
Flash email client ........................................................................................................173
EmailClass.php ................................................................................................174
SendEmail.php ................................................................................................180
ReceiveEmail.php ..........................................................................................181
EmailClient.fla ..............................................................................................................182
Setup tab - frame 2: ..........................................................................................186
lnbox tab - frame 3: ..........................................................................................187
Receive dialog ......................................................................................................188
Compose tab - frame 4 ....................................................................................189
Send button ....................................................................................................190
ComposeDialog ..............................................................................................190

PHP and XML 193


A closer look ................................................................................................................194
What can we do with XML? ..............................................................................196
Here's one I made earlier! ..........................................................................198
Mission accomplished! ......................................................................................206
Where do we go from here? ..................................................................................206
Contents

Ming 213
Introducing... Ming! ....................................................................................................214
Installing Ming ..............................................................................................................214
Strike one ..............................................................................................................215
Windows ................................................................................................................216
Linux ........................................................................................................................217
Troubleshooting ............................................................................................220
The cans and can'ts of Ming ....................................................................................221
Meet the methods ......................................................................................................222
let's get $physical ......................................................................................................223
Your Mom ....................................................................................................................227
guestbook_form.swf ..........................................................................................229
guestbook.php ....................................................................................................242
download.php ......................................................................................................250
Running the application ....................................................................................252

Case Study 1: Chat Room 255


A design for life ..........................................................................................................256
Features ..................................................................................................................256
looks are everything ..........................................................................................2S7
Database design rules! ........................................................................................2S9
User ..................................................................................................................260
Database table specifications ..........................................................................262
Table: chatUsers ............................................................................................262
Table: chatUserlist ........................................................................................262
Table: chatMessages .................................................................................... 262
Flash in the pan ..........................................................................................................263
Strike up a dialog... or four ................................................................................269
Server-side shenanigans ............................................................................................299
db.php ....................................................................................................................301
Improvements? ....................................................................................................32S

Case Study 2: e-Commerce Site 323


What are we going to build? ..................................................................................323
Administrator site ......................................................................................................324
MySQl ....................................................................................................................324
PHP ..........................................................................................................................327
Before we start: ............................................................................................336
File: adminPDF.php ......................................................................................34S
What is PDFLib and what can it do?? ......................................................345
File: adminPreviewlmage.php ..........................................................................3S2
File: addAdminUser.php ....................................................................................3S9
Wrap up ..................................................................................................................361
Interface ..................................................................................................................361
Advanced PHP for Flash

Scene: preloader ..........................................................................................362


Scene: login .....................................................................................................363
What can be done to extend this? ..........................................................365
Scene: main ..................................................................................................366
Scene: categories ..........................................................................................367
Previous button ............................................................................................372
Preview Image button ..................................................................................380
Preview Image button ..................................................................................387
Scene: upload ................................................................................................391
Scene: report ..................................................................................................391
Scene: error ....................................................................................................391
Wrap up ..................................................................................................................392
The client interface ....................................................................................................393
PHP ..........................................................................................................................393
Wrap Up ..........................................................................................................402
Interface ..................................................................................................................403
Scene: error ....................................................................................................426
Wrap up ..................................................................................................................426
What can be done to extend the site ....................................................427

Readers' Showcase 429


john lyons - www.flashbuilder.ch/flash.htm ......................................................430
jeremy Thomas- www.variablelimit.com ............................................................431
Scott Ysebert - scott.ysebert.com .......................................................................... 433
Sam Riggs - www.deadsam.com ............................................................................435
Geoffrey Rowland and Kelly Sponberg - www.cip.ogp.noaa.gov ..................437
josiah j. Williams - www.jjsquared.com ................................................................438
Adrian Ng Chee Wei - www.ngarte.com ..............................................................440
Kevin Menzie I Slice of lime- www.mobilesnow.com ......................................443
Sukral Helmi - www.webmanultraflash.com & toophat.com.my ............... .444
Mark Edwards - www.4d-enter.com ......................................................................445
jacob Bullock - www.kineticz.net ............................................................................446
Sidney de Koning - www.funky-monkey.nl ........................................................447
Benjamin Knigge- www.fxnetworks.com/shows/originals/the_shield ........448
Gary Stasiuk - www.praxisinteractive.com ..........................................................449
james Ellis - www.webqs.com ................................................................................451
Gregg Vivolo - www.greggv.com ............................................................................452
Anthony Onumonu - www.clubsyte.com ............................................................452

Securing MySQL 455


Root of all evil ............................................................................................................455
MySQl built-in Security ............................................................................................456
The verification process ....................................................................................457
Connection level ..........................................................................................457
User level (user table) ................................................................................457
Database level (db table) ............................................................................457
Table level (tables_priv table) ..................................................................458
Contents

Column level (columns_priv) ....................................................................458


Setting permissions ..............................................................................................458
The GRANT statement ........................................................................................459
REVOKE ..........................................................................................................461

Resources 463
Advanced PHP for Flash links ..................................................................................463
Authors' homepages ..................................................................................................463
Software homepages ..................................................................................................464
Setup tools ....................................................................................................................464
PHP editors ..................................................................................................................464
PHP street corners and forums ..............................................................................465
PHP web resources ....................................................................................................465
Hosting companies supporting PHP ......................................................................466

Index 469
Foreword
-
'
1-11111111n

rn D
D
D D

( Foreword )
It seems like only a few months ago that I was putting the finishing touches to
Foundation PHP for Flash. I've just been doing the same for its sequel, polishing off a
neat chat room application which you'll find later on. This time it's not j ust me though!
This new edition gives some other leading PHP and Flash developers a chance to strut
their stuff for your learning pleasure.

This time around we've ramped up the level, picking up where Foundation PHP for Flash
left off, taking you through some of the more advanced features of PHP, showing you D
how to combine them with Flash to create yet more stunning applications. Whether D
you're coming straight from our Foundation book or you've grasped the essentials of
PHP and MySQL from elsewhere, this book is all you need to take your dynamic web
applications to the next leveL

Since we last spoke, Macromedia have also released a new version of Flash. We're all
really excited by the new features afforded by Flash MX and simply couldn't wait to
exploit them in this book. That said, the techniques covered in this book are equally
applicable to other versions of Flash - you can take PHP just about anywhere - but
myself and the other authors like to live life on the bleeding edge and have used Flash
MX to create the applications for this book.

D D
~cPQ
D~cf cfJ
=t=r- I-
_,_
l
l
J
r-
r- I

r-
1
I
~w
- Ll
,__~ IT I I
LJu
I
r;-1
Tl
LJ
1
L
0

r-
I -1-r- ~"~n...., o
I I I C:J
I- - - r--r- -...., r--r- J
~ r-J L~r- c::P ~
Bg
0
.., r- D B o0
........ ......... ...._ ...._ ~:J ~ D
rn 0
D
D
0 D

One last addition is the Reader Showcase. In here you'll find profiled some truly
awesome websites and applications - along with their creators - that were deve loped J C::
J
using the techniques and skills learned from Foundation PHP for Flash. This is a unique
experience to see what your fellow readers have accomplished and to seek some first-
J
rate inspiration. Whether you're developing too ls for skiers on the PDA or database-
driven mega-sites on the good old PC, we've got the goods to help make your web sites t
think for themselves.

I hope you enjoy this second foray into PHP and Flash as much as I have enjoyed being
a part of it, and I can't wait to see how you use the PHP skills you're about to learn in
J
your own real-wor ld applications. Who knows - maybe you'll end up with your work D J
featured in a showcase section of another f ine friends of ED book one day... ?
E1
Regards,
B.rc
oD
- D
a:
i~ D

9 Steve Webster
Author - Foundation PHP for Flash
0

rF(~
D Contributing Author - Advanced PHP for Flash
co-Moderator- www.phpforflash .com
B
%_.:
III[l.
D
Elo~ Eloc:a=J''%
% ~DO Do- 8 El
D B cl""\
o
nrruP
u J
+-+-+++++-~~.....-w--'ocP ~ ~~~u~ q

cfJ ~ D ~

81 ~ B ~cP B~
DD DO_0 r-+-+-+-t-+-+--loolf--f--r-r-1.......,.

~ B ~ cffi:H. Bo ~o- o q
o rn o o~ o rn o B ~~o
a&
I
~ Welcome to Advanced PHP for Flash - the long-awaited sequel to Foundation PHP for
Flash. Here we are again, about to embark on a new journey together.
%
~
The aim of this book is to pick up from where the previous book left off, delivering you
even more PHP knowledge and Flash applications with which to seriously wow visitors
to your sites. This book is packed with more PHP, more Flash, and more applications
than before.

That said this isn't just a book for readers of Fovnootion PHP (or Flash. It's been written
in such a way that it should be useful to anyone with an intermediate level of PHP and
Flash, regardless of how that knowledge was garnered. If you're not quite there yet, you 9:c
might want to take a took at some of the other books on the friends of ED bookshelf.
In particular, Foundation Flash MX would make a superb companion to this book if you
need to brush up on your Flash skills. D

The format stays pretty much the same as that which made the first book a success.
The first section of chapters takes you through new PHP features and shows you how
to combine them with Flash to create some truly useful applications. Following that
~E
we've got two red-hot case studies for you to enjoy, showing you just what can be
[.
accomplished using the knowledge in the book and a bit of hard work.

D
OIC
ITI.C

0
D D D
0 ~ rR r
D D D
1 Advanced PHP for Flash

The MX connection
During the planning stages for this book, we sent out a questionnaire to readers of the first book
asking them what they'd like to see covered. We also asked which version of Flash we should aim
to cover, and the overwhelming majority asked for Flash MX.

Flash MX has given us some exciting new tools to play with, allowing us to create applications
that just weren't possible using previous versions of Flash. We'll be using these new features
extensively throughout the book, and as such we'll spend the next chapter getting to know them
intimately. By the end of that chapter, they should feel like long-lost cousins ... or something like
that anyway.

Having said that, we wanted this book to be accessible for developers who are stuck with Flash 5
for whatever reason, and have endeavoured to make the applications easily portable where
possible. Pointers are given wherever feasible, but you'll have to do the legwork yourself.

Chapter specs-appeal
Since we're moving on to more advanced topics with this book, you can read most of the
chapters in any order you like. This is because each one deals with a different topic that, for the
most part, should not rely on any of the chapters that came before.

With this in mind, I've provided a chapter breakdown below to help you get the most out of this
book. You'll find a brief summary of the topic covered as well as details of any main application
built for each of the chapters, along with a few tantalizing screenshots.

Chapter 1 - Introduction
Well, you should know everything there is to know about this chapter by now... because you're
reading it.

Chapter 2 - Flash MX Essentials


Before we can get cracking into the book properly, we need to know about the new features
available to us in Flash MX and how to use them. This is going to be a whistle-stop tour where
we've only got time to cover the basics of each of the features we're interested in. If you want
a thorough grounding in all the new bits of Flash MX then I'd suggest you get hold of Flash MX
Upgrade Essentials, also from friends of ED.
Introduction 1

The features we'll be covering are ...

The new LoadVars object.

Dynamically loading JPEG and MP3 files.

The SharedObject super-cookie.

Instead of one main application, several smaller ones are going to be built to illustrate the
various new features.

Chapter 3 - Sessions
Sessions can be thought of as temporary server-side cookies in which we can store data, and are
a useful alternative to traditional cookies and Flash MX's new SharedObj ect.

Some may think that this chapter is somewhat obsolete, given that the new SharedObj ect
"super-cookie" in Flash MX allows web developers to store data on the client. However, this
feature of the Flash Player can be turned off, and given the height of scepticism about security
on the Internet it would be dangerous to rely on this facility being available. With PHP's session
feature you can virtually guarantee that, provided your server supports them, they will always be
available to your applications. We will start the chapter by discussing the need for the persistence
of data, introduce sessions, and finally provide a fully functional Flash MX shopping cart that
utilizes sessions.

PI ~ !-- . -. . . .
~ --- w. a

14!:J.co.,..
I:W
...
~~: 1 -.t c....ht.W .. t.-~

--I
Po,f-C-MI
1 Advanced PHP for Flash

Chapter 4 - File Uploading


The ability to accept and process uploaded files from a user's computer is one of the many
feathers that PHP has in its fairly substantial cap. PHP allows us to securely handle file uploads,
to verify that the file is of the type and size expected, and then to copy it to a given directory.

With the new dynamic image and sound loading


capabilities of Flash MX, it's likely that we're going to
see an explosion in the number of gallery and
jukebox-like applications appearing on websites.
While such applications could be developed using
the new features of Flash MX alone, they would
likely be awkward and time-consuming to manage,
and users wanting to upload files on their own would
require FTP access to the site - not something that
you want to go dishing out willy-nilly!

Using the file upload capability of PHP, we can create


a nice Flash-based application to manage the image
gallery that will also be developed in this chapter.

Chapter 5 - Advanced MySQL


This chapter is a little bit of an oddball in that it doesn't actually cover anything new on the PHP
side of things. Instead, we concentrate on flexing our MySQL muscles, going deeper into the
murky underworld of SQL queries to cover such wonderfully sounding topics as table joins and
advanced searching.

If this all sounds a little scary, don't worry, you've actually nothing to be frightened of. It's all just
an extension of what we know already, and you'll be walked through every step of the way!
Introduction 1

We are going to work with quite a few examples in the MySQL monitor and then we'll finish this
chapter off by building a searchable cookbook with recipes and photos.

(J cookbook.swf 1!1~ f3

Yaya's Cookbook

Welcome to Yaya's Cookbook. We've got what .. <previous category>


you want to cook! Select a category or reclpe Chocolate Chip Cookies category>
on theright. Cookies

Search

Sugar Cookies
Copper Cutter July 11. 2002

2 slicks softened butter


1 cup sugar
1 terge egg
1 1 f2teespcons va~a
3 c ups aD-purpose flour
1 114 teaspcons baking powder

Blend buller & sugar until fluffy. Add egg end vanilla. Mix until just
combined. Add tioll' end baking pcwder in intervels. Shape into
disk & wrap in plsstic wrap & put in refrigerator until firm. Preheat
oven to 375f. Roil out dough between 2 sheets ot waxed paper.
Cut out wWh cookie cutters and place on a 6ghtly greased cookie EJ

Chapter 6 - Socket Functions


Like Flash, PHP has some socket-related functions to allow it to connect to servers directly and
interact with them. When Flash developers hear the word 'socket' they tend to think immediately
about chat servers and the like. While that is one example of sockets in action, it is by no means
the be-all and end-all of sockets.

In order to break sockets out of the box in which they find themselves, we're going to use them
for something a little different than a chat system. Indeed, being a web-scripting language rather
than a stand-alone programming language, PHP isn't especially cut out to be a socket server
anyway (though it is possible -just not a pretty sight). Instead we're going to use PHP's socket
functions to see how we can interface with some of the more common web services.
1 Advanced PHP for Flash

By the time we reach the end of this chapter, you'll know more than you ever wanted to about PHP
sockets and have a shiny new Flash-based email client to play with, ready to be the next Hotmait!

Email Client
S.lup 1
'"""" 1 ~ 1
Sending Email s,....
et_u :....
p ------,
SMTP SmYer.

Your Email AddrD:!.$: L___ _ __ _....J

Retrieving Emai l Setup

J
US6ftUlJt10: I

Chapter 7 - PHP and XML


People have been banging on about how great XML is for years now, but the extra time involved
in creating XML documents to use with Flash applications has ted many developers to stick with
traditional formats of data representation - mainly plain name/value pair text.

In this chapter, we'll took at what XML is, and how PHP can ease the burden by creating XML
documents from standard sources (such as a MySQL database) on the fly. We'll also took at the
advantages this affords us from the Flash point of view as opposed to the normal
loadVariables () I LoadVars method of retrieving dynamic data.

Once all that is out of the way, we'll move on to see how we can use this knowledge to enhance
our Flash movies. To this end, we'll create a dynamic menu system that uses XML data to create
a tree-like mpn c\/ct<>m
Introduction 1

Chapter 8 - Ming
No, not the evil bloke from Flash Gordon, but the PHP extension library that allows us to
generate SWF files from your PHP scripts. Back in the days of Flash 5, Ming was mainly used to
wrap an image file up in an SWF jacket so that it could be imported using the loadMovie ()
command. Since that's no longer necessary under Flash MX, we have to find more creative uses
forMing.

The reason that Ming is still useful today is that the ability to dynamically generate SWF files is
a powerful feature to have at your disposal. Imagine a whiteboard application where the user
gets to draw something and then is able to actually download his creation as a stand-alone SWF
file for importing into Flash. While something approaching this is possible with the new Drawing
API in Flash MX, you'd have to record all of the user's strokes in a database, and then play them
back in order to recreate the drawing. Not only could this lead to huge database files, it's not
exactly an elegant solution to the problem since the user would have to have access to the
Internet in order to view their creation because the SWF needs to fetch the data from the server.

With that in mind, we're going to use Ming to create a whiteboard guestbook-style application.
Users will be able to visit the site and record a drawing along with the normal text information
in the guestbook. Other users could then come along, view the entries, and download any that
they particularly like.
1 Advanced PHP for Flash

Case Study 1: Chat Room


According to our questionnaire results, one of the most requested applications for the new book
was some kind of Flash-based chat room. Since we're not dealing with Flash's XMLSocket object
in this book, this is the perfect opportunity to investigate alternative ways of providing a chat
system using PHP and MySQL. This is especially relevant since most third-party hosts will not
allow custom socket servers to run on their systems.

The application will include user-authentication as well as the standard chat features.

Fla1h + PHP + MySQL Chat Syst~m Adviinc::ed PHP for Flash

Matt heh :-) hey 9UYI 1 1 IIETbrHd


1""'1 Matt
Inc fl :IIQ g om g 11"1 he"e fM U'l. W i iii'Jie' Alan

Al~n i$ testing the IRC thing ...


Af~n It .,. _ 'S'

Al"n is:)
Matt thinks John de!ie-rve-!. a mention
UETbreed: Cf oou-v.: it .o::l'rtcs you cneti.)' fell~ :
Al21n b lushes
NETbt~ecl : ::foa'j. nes "'1!!! ~nUn e s-o we II '111VB to gc ..,itncut nlrn E-.,.'l!fy~.

s11y onua~
Alan wa1 Jlotu.illy testing il he could reml!:mber the commilnd for lt from
tht!- chapt@rlt
Matt thinks h should ~dvertise \.VI.VW.phpforfla!h.com to stay in
Steve's and Alan'1 good books :}

I 1( ~ Settings... Log Out

Case Study 2: Full E-commerce Site


The grand finale for the book will be the
building of a full e-commerce Flash site,
with registered customers, shopping
basket, product categories and pictures,
PDF invoice generation, etc. All this will
be backed by an administration
interface allowing the reader to manage
their store.

This is the natural culmination of all the


features covered in the book.
Introduction 1

We all need somebody ...


We all need a little support every now and again. Even I'm up to my ears in reference books on
everything from ASP to Unix Network Programming and am currently fighting them for office
space ... a losing battle if ever there was one!

The good news for you is that this book is fully supported both at the official friends of Ed site
at www . friendsofed. com and at our very own site at www. phpforflash. com. You can
download source files for the book from either, and you can also visit our support forums for
help, inspiration, or just to chat.

The PHP for Flash website also contains additional files and tutorials, errata updates, and plenty
of neat demonstrations of the case studies in the book. Join our mailing list or submit your own
projects for showcasing on the site -we'd love to see what you've achieved!
1 Advanced PHP for Flash

If it's the full designer's breakfast you want, the friends of ED site has interviews with top
designers. information on other books, sample chapters. and much more. The book is just one
part of the experience.

~Q;)I -.o I

..............
.... "........
...-..-
... ~ ,._t

I...,.,.....,.
........
.... J~ l

.., .J.:l

:::::!~!..~11

._.........__.......
-llttt "'"' ....

..............................
_, ~ ~.,
.......... " ) i f:

.,....,"-..,
..
~ ~-
fo:lr.IK~tor.tf..
1a&i.au ..............

~ ~~-
.............
............. _
........ ,.. ~"--
~
t.~ ...... ..a
nu.t , . . . _...., tJ
::-~ ::::.:~:rjo.!"
b

However, if you do run into trouble, and maybe have a problem with a certain file or tutorial or just
-
get plain muddled. we're right here for you. leave a message on the forum, use the online feedback
forum, or drop us a mail to supportfrien dsofed. com- we'll get you sorted in no time.

Even if you don't have problems, let us know what you think. Just send a mail to
feedbackfrie ndsofed . com or fill out the cute little reply card at the back of the book -
that's what it's there for, and we'd love to hear from you!
Introduction 1

Styles you'll come across in the book


We use a few layout conventions to make things clearer throughout the book.

If I introduce a new important term or reference a future Chapter Number, then these
will be in bold.

I'll use different styles to emphasize things that appear on the screen, pieces of code,
illportant pieces of code, as well as hyperlinks and file paths.

If there's something you shouldn't miss, I'll highlight it like this!


When you see the bubble, pay attention!

Lastly, I'll be running you through case studies and examples using worked exercises:

1. If you see the exercise numbers, switch on your computer and get ready for action

2. Follow the steps through and check the screenshots and diagrams for more hints

3. When you get to the end, test it out!

Summary
So, the preamble is complete. You have just seen your future laid out in front of you. You can
see the rewards that you will reap once you reach your destination.

Onwards, friends, onwards ..... .


Flash MX
Essentials

j -~
r ......... ~ T ::_

;,
I I

I I
I I
B
What we'll cover in this chapter:

The LoadVars object and its usage

JDDDD D
Loading JPEGs using loadMovie ()

Loading MP3 files using load.Sound ()

Shared objects and the new SharedObject object


2 Advanced PHP for Flash

Flash MX has some significantly funky new features, especially when it comes to developing web-
based applications. Some of these features make the development easier, like the LoadVars
object, and others allow us to do things that were just not possible in previous versions of Flash.

In addition to this, the authoring environment has been given a serious makeover, with dockable
panels and a souped-up ActionScript editor among the many improvements. However, the major
addition here has to be the all-new Property inspector panel. This gives quick and easy access to
options that are specific to the selected item.

In this chapter we're going to look at a handful of these new features, concentrating on the ones
that we'll be using throughout the book.
Flash MX Essentials 2

LoadVars to the rescue


The first stop on our grand tour is the shiny new LoadVars object. According to the lovely
ActionScript Dictionary, the Loadvars object is ...

" ... an alternative to the loadVariables action for transferring variables between a Flash movie
and a server."

The LoadVars object is very much like the XML object in that we can use it to communicate with the
server using the send, load, and sendAndLoad methods, but it deals with ActionScript name and
value pairs rather than proper XML data. Also, by using LoadVars it is easier to monitor the progress
of the data being loaded and the completion of that process, compared to using loadVariables.

Basic LoadVars
Now, you'd be forgiven for not being exactly ecstatic after that rather low-key introduction, but
hold on to your hats because the LoadVars object affords us a huge benefit over the traditional
loadVariables () command.

For starters, it allows us to have a dedicated area from which to send, and into which we can
load, data. The problem with loadVariables () is that it is unselective, and when called, it
sends all variables on the current timeline. Likewise, when using loadvariables (), any
variables loaded in are created on the current timeline and there is no way of telling which ones
were there already and which ones have been loaded in.

The LoadVars object does away with all that. All we have to do is copy any variables that we
want sent into the LoadVars object and call the appropriate method. For example, look at this
code snippet:

II Create LoadVars object


myData = new LoadVars();

II Copy data
myData.age = 25;

II Send data to server


myData . send('whatever.php');
2 Advanced PHP for Flash

In this instance, only the age variable will be sent to the PHP script regardless of how many other
variables we have on the timeline. This can be a great bandwidth-saver when all you want to send
is, for example, three or four variables, avoiding sending the other 50 or so that you're using for
some animation on the same timeline, as you would have to do if you were using
loadVariables () . Also, the LoadVars object allows you to be more selective about the data
that is being sent to the server. For example, the use of loadVariables might send a variable
to the server that could cause the server to respond with an unexpected result- so you can see
why the selectivity of LoadVars is important.

Playing with event handlers

OK, so that's pretty neat, but hardly worth holding onto your hat for, right? Well, we can also
specify a function to be called whenever a load or sendAndLoad operation has completed. This
is easier to see rather than explain, so we'll jump straight into an example.

1. Create a plain text file with the following contents and save it as test. txt:

&message=Hello from the text file&

2. Now create a new Flash movie and save it as loadtest. fla in the same directory as the
text file above.

3. The first thing we need to do is create our event handler function. All we're going to do
here is to use the trace () command to output the message contained in the text file.
Select the first frame of the new movie and add the following code:

II Event handler function


loadHandler = function()
trace(this.message);
Flash MX Essentials 2

We need to use this. message rather than just message


otherwise Flash would look for a message variable on the current
timeline (where the event handler was defined) rather than inside
the LoadVars object. This is an important point that we'll come
across again in this book in another context, but as long as you
remember that, in an event handler function, the this keyword
represents the object to which the event handler is attached,
you'll be fine!

4. With that done, we create our LoadVars object as before and assign the new function as
the onLoad event handler for the object.

II Create LoadVars object


myData =new LoadVars();

II Set event handler


myData.onLoad = loadHandler;

5. Finally, we use the load method to load the data in our test. txt file.

II Load data
myData.load('test.txt');

If you test this movie in the Flash environment you'll see our message pop up, indicating
that the load operation has been completed.

He ll o from t e text f il e
2 Advanced PHP for Flash

Error detection
An important point to note here is that "completed" doesn't necessarily mean that the data has
been loaded successfully. If we were to remove the test. txt file from the directory and test
again, you'll see that the event handler is still called and we end up with an output looking like this:

Output 'J]....,
Options
undefined
Error opening URL "file : ///EJ/Books/PHP~

The first line tells us that the message variable was not found, and the second is Flash
complaining that it couldn't find the file specified in the load method call.

Thankfully, Flash allows us to determine whether the operation was a success from the event
handler by passing it a Boolean variable. We can use this to output the message in the text file
if everything went OK, or an error message if, for whatever reason, the data hasn't been loaded.

Go back to the loadtest. fla file and edit the event handler function so that it looks like this:

II Event handler function


loadHandler = function(success)
i f (success) {
trace(this.message);
else {
trace('Could not load file');

This time you should see a nice error message rather than the totally cryptic undefined output
that we got earlier, though we haven't managed to stop Flash complaining of its own accord as
you can see from the screenshot to the right...
Flash MX Essentials 2

Output -~~-
Options
Coul d not oad f il e
Error opening OR "fil e: ///E I /Boo ks / PH P ~

We'll use this feature extensively over the coming chapters, and it is one of the main benefits
that LoadVars holds over the loadVariables () command.

Useful undocumented feature

In addition to the onLoad event handler, the LoadVars object has another, undocumented,
event handler: onData. This is called before the data is parsed into individual variables, and
allows us to work with the raw data that is passed to the event handler.

This can be useful if your data source isn't formatted into name and value pairs, but you still
want to load it into your Flash movie. This would save you from having to edit the file to include
the &variableName= at the beginning, which may be impossible or undesirable depending on
your circumstances.

Right, enough chat, let's take a look at this wonderful undocumented feature in action.

1. Change the code in the above application so that it looks like this:

II onData event handler


dataHandler = function(rawData) {
trace(rawData);
}

II Create LoadVars object


myData =new LoadVars();

II Set event handler


myData.onData = dataHandler;

II Load data
myData.load('test.txt');
2 Advanced PHP for Flash

2. If you test this, you'll see that Output , :,!~.

the output window contains


the contents of the text file as &message=Hel lo from the text file

we originally wrote it.

Bear in mind, however, that a LoadVars object has a standard onData event handler. This
handler actually deals with parsing the data into individual variables and calling the
onLoad handler when it has done its job. By overwriting it as we have above we prevent
this from happening.

3. You can try this out for yourself by adding a simple onLoad event handler to the
above application.

II onData event handler


dataHandler = function(rawData)
trace(rawData);

II onLoad event handler


loadHandler = function() {
trace('onLoad called');
}

II Create LoadVars object


rnyData =new LoadVars();

II Set event handlers


myData.onData dataHandler;
myData.onLoad = loadHandler;

II Load data
rnyData.load('test.txt');
Flash MX Essentials 2

4. If you look at the output Output .'i!,


you'll see that the onLoad
event handler is never called. &message=He!lo from t h e text f ile

This obviously isn't a problem if you're loading a simple text file into Flash and therefore
aren't bothered about having the data parsed; but what if you wanted to have both event
handlers? I can't really think of a reason why you'd need to do this, but as things stand it
wouldn't be possible.

5. In order to fix this we need to make a copy of the original onData event handler and then call
that from within our new one. Edit the ActionScript to include the new bits indicated below:

II onData event handler


dataHandler = function(rawData)
trace(rawData)i

II Call old onData handler


this.oldOnData(rawData);
}

II onLoad event handler


loadHandler = function()
trace('onLoad called') i

II Create LoadVars object


myData =new LoadVars() i

II Backup event handler


myData.oldOnData = myData.onData;

II Set event handlers


myData.onData dataHandleri
myData.onLoad = loadHandleri
2 Advanced PHP for Flash

II Load data
myData.load('test.txt');

All we've done here is store a reference to the old event handler in oldOnData and then call
this from our new event handler. Note that we're using this again to refer to the LoadVars
object, and that we have to pass the raw data to the old event handler as it uses this internally.

The output now looks like this:

&message=Hello from c~e cexc f i _e


onLoad cal_ed

That's pretty much it for the LoadVars object for now. We'll return to it in later chapters when
we'll extend it to add a bit more functionality, but now it's time to move on to some of the other
new features of Flash MX.

Loading JPEG images


Probably one of the most talked-about features of Flash MX is the ability to load JPEG image files
using the loadMovie () command as though they were Flash movies. In fact, this isn't so much
a feature of Flash MX as a feature of the Flash 6 player, and can be used by Flash 5 movies
provided the correct version of the player is installed on the client machine.

You do, however, need something to load the image into. A blank movie clip is generally the best
thing for this since you can then reference your image from your ActionScript code should you
need to.

The one thing to note about this new feature that's stumped a lot of people is that it won't load
progressively encoded JPEG images. just in case you're not sure, these are the ones that you see
on the Internet that start off blocky at first and get clearer as more data is loaded. One further
issue with JPEG images to keep in mind is that many web browsers either fail to display or display
incorrectly CMYK JPEGs. So long as you avoid both these, or at least re-encode them, you
shouldn't have any problems loading images into Flash.
Flash MX Essentials 2

This is going to be a relatively short section since there isn't a lot more to say about this new
feature, but I thought you might like a small sample application to go with it. We'll create an
application that can load an image specified by the user in a text field.

Using loadMovie() to load JPEGs

1. Create a new Flash movie and save it as imagetest. fla

2. All I've done in my movie as far as


background is concerned is to create a
raised panel.

3. I've also added an input text field and a button to my movie, with a view to having the
button attempt to load the filename given in the text field.

! sutton Instance o l

l load_btn Swap... II
'IN: 1243.9 X: rw.o- po.9 X: 1258.9

H: rs~ Y: 1271.6 ~ Y: l 271.3


2 Advanced PHP for Flash

As you can see, I've given the text field and button instance names of filename_txt and
load_btn respectively, and I've turned on the border and background attribute for the
text field so that we can see it.

just in case you didn't know, Macromedia recommends the _txt and _btn suffixes, along
with _me, which we'll meet in a moment, in its white paper 'ActionScript Coding
Standards'. This allows the ActionScript editor to bring up only those code completion
items that are relevant to the item being referenced. You can download a copy of the
whitepaper from www.phpforflash.com if you are interested in a complete list of
supported suffixes, along with other assorted recommendations for coding in ActionScript.

4. With that all done, it's time to add the ActionScript. Do this in a separate layer, labelled Actions.

5. The first thing we need to do is to create a blank movie clip into which we can load our
images. We'll do this using the new createEmptyMovieClip () command.

II Create empty movie clip and set location


_root.createEmptyMovieClip("image_mc", 0);
image_mc._x 10;
image_mc._y = 10;

You can see that we're also moving the new movie clip, image_mc, ten pixels in from the
top and left edges of the movie (the new movie clip's registration point is automatically
set to the upper left-hand corner). I've done this so that it fits in with my design, so if
you're using something different then you may want to change these values.

6. All we need to do now is assign an onRelease event handler for our button. We want to
take the filename given in the text field and use that as the target for our loadMovie ()
command.

II Button event handler


load_btn.onRelease = function() {
II Load image
i.mage_mc.loadMOvie(filename_txt.text);
}
Flash MX Essentials 2

In Flash MX, you can now specify button events in the frame
instead of having to have them coded onto the button instance
directly.

That's all there is to it. If you load


your application and give it a little
test, you should be able to load
images into it. I've supplied a couple
of images in the download archive,
but since this file is running locally
you could always feed it the URL of
an image and see how that works.

ltux.jpg

Be wary of loading any large images though, since the movie clip into which the image is being loaded
is not masked and the picture will appear over the top of the interface elements.

Loading sounds
With Flash MX, you can now also load MP3 files directly into your Flash movie at run time using
the loadSound () method. The MP3 files can be located on your computer or externally on
another server. So as long as you know the URL for the sound you want to use, you're free to
add any sounds you like (well, of course only if you have permission to use the sounds; we don't
want to break any copyright laws here). The loadSound () method is useful for playing MP3 files,
as the file is not available to the user, so the user can listen to the music but cannot make a
recording of it.
2 Advanced PHP for Flash

Adding sound using loadSound()

All we're going to do here is add sound to the Flash movie we created in the previous section.
You can use any MP3 file you like but in this example I'm going to add mySound.mp3, which is
available to download. Whatever sound you choose, you need to ensure that it is configured with
a constant bit rate (CBR).

OK, enough background, let's go ...

1. Open imagetest. fla that we just created. Save it as soundtest. fla.

All we have to do is add a few short lines of code and then we will have an MP3 play along
with our movie.

2. The first thing we need to do is create a new Sound object. I've called it soundtest (really
imaginative, I know).

soundtest = new Sound ();

3. To load the sound into our movie, we need to call the loadSound action.

soundtest.loadSound("mySound.mp3", true);

The sound I have loaded is located locally on my hard drive, in the same folder as the
soundtest. fla file. As stated earlier, you can also use sounds located externally by
entering a full URL into this first argument.

In this instance I have loaded my sound as a streaming object (true is the argument used
for a streaming sound and false for an event sound). As it stands right now, if we test
the Flash movie, your sound will play. If we had loaded the sound as an event sound, we
would also have to include the object's start method:

mySound.start ();

4. Test your movie and not only should you be able to load images, you should also have
sound playing along.
Introduction 1

Styles you'll come across in the book


We use a few layout conventions to make things clearer throughout the book.

If I introduce a new important term or reference a future Chapter Number, then these
will be in bold.

I'll use different styles to emphasize things that appear on the screen, pieces of code,
illportant pieces of code, as well as hyperlinks and file paths.

If there's something you shouldn't miss, I'll highlight it like this!


When you see the bubble, pay attention!

Lastly, I'll be running you through case studies and examples using worked exercises:

1. If you see the exercise numbers, switch on your computer and get ready for action

2. Follow the steps through and check the screenshots and diagrams for more hints

3. When you get to the end, test it out!

Summary
So, the preamble is complete. You have just seen your future laid out in front of you. You can
see the rewards that you will reap once you reach your destination.

Onwards, friends, onwards ..... .


2 Advanced PHP for Flash

This is accessible by right-clicking on a Flash movie while it is in your browser window and
selecting Settings ... from the pop-up menu. You then select the tab with the folder icon on it to
get to the Local Storage options. From here you can alter the amount of space available for
shared objects for the current domain (shown as local here) or disable the use of shared objects
for the site altogether.

Another benefit of shared objects is that they are capable of storing all types of data, from
simple numeric variables, through to whole objects, which makes them just a tad more useful
than cookies when creating Flash applications. You can take a Date object and store it straight
into a shared object, and then use it when the movie is reloaded (or another movie from the
same domain as data that is stored using SharedObj ect can only be read by movies originating
from the same domain that created the SharedObject). Cool, huh?

SharedObject in the wild

OK, enough of the sales patter- if you're not sold on just how cool shared objects are by now
then you probably never will be - it's time to get down and funky with a working application

To be perfectly honest, this application isn't all that exciting, but then it's designed to teach you
about shared objects so you can use them yourself rather than stun you into silence. All we're
going to create is a simple visit counter ... it may be small but it's perfectly formed!

1. Create a new Flash movie and save it as sharedobj ect. fla.

Again I've just created a small raised panel as


my background.

2. Next up I've added a simple text title and a


text field that we can use to display our data. SharedObject Test
Flash MX Essentials 2

3. The text field is set to Dynamic and has an instance name of output_txt. It is also
configured as a Multiline text field since the string we'll be displaying is likely to be longer
than the text field.

lA" I Dynamic TeMt

joutput tKt
:::J A 1-sans
;.SvJO .:J A; j Normal
fl
~
[i2.:]
r AutoK'i'rrt
l!.L!J :~.. ==- =-'-='='
~ I
Format...

v:[iSD.S X:fs:O @ JMultiline ...:J ~ ()I[ I Var: I -- Character ... I


H: J45.0 Y:[3"0T ~I Targ~t: I ...:J
With all the good-looking graphics out of the way, it's time to get down to some serious
business with the ActionScript.

4. The first thing we need to do is create our shared object. This is done through the
SharedObject interface using the getLocal () method, so create a new layer and add
the following:

II Create or fetch shared object


localObject = SharedObject.getLocal('test');

The name of our shared object- test in this case - is passed to the getLocal () method,
which returns a reference to that shared object.

If the shared object already exists then a reference to it is returned and stored in
localObj ect. If the given shared object does not exist, it is created and a reference to
the new shared object is returned.

Data for a shared object is stored in the data property, so if, for example, we had a
variable called name stored in our shared object then we could access it using the
following code:

trace(localObject.data.name);

5. With that in mind, I'll tell you that the variable in which we'll store the visit count will be
called, unsurprisingly, visitcount. We can test to see if this variable exists in the data
property of localObject by comparing it to undefined, and if it does exist read it out
into a separate variable. Otherwise we'll initialize our variable with a zero value:
2 Advanced PHP for Flash

II If value exists ...


if (localObject.data.visitCount != undefined)
II Fetch data from shared object
visitCount = localObject.data.visitCount;
else {
II Init the count at zero
visitCount = 0;

6. With that done we can set our output text to contain a message indicating the number of
times the user has been here before.

II Set output text


output_txt.text = "You have been here" + visitCount +
" time(s) before. ";

7. Next we increment our visitCount variable and copy it back to the shared object.

II Increment visit count and copy of shared object


visitCount++;
localObject.data.visitCount = visitCount;

Now I'm no telepath, but I'd be willing to bet that you're asking yourselves why I bothered
to copy visitcount to a separate variable if I was just going to increment it and then
copy it back again.

The reason for this is that you cannot assign literal values to shared object data items. That
is to say, the following would not work:

localObject.data.name = "Joe Bloggs";

Why? Well, your guess is as good as mine, but it really doesn't work so you just have to
remember not to use it that way.

8. Finally, we use the flush () method for our shared object to confirm the update and write
it to the shared object file.
Flash MX Essentials 2

II Write shared object


localObject.flush ();

As an aside, although we're not using it here, the flush () method actually returns some
pretty useful information about the success of the write operation. According to
Macromedia, the permutations are as follows:

If the user has permitted local information storage for objects from this domain, and
the amount of space allotted is sufficient to store the object, this method returns true.

If the user has permitted local information storage for objects from this domain, but the
amount of space allotted is not sufficient to store the object, this method returns
"pending". In this case, the user will see a dialog box asking the user whether they want
to allow more space to be allocated.

M.acromedia Flash Player Setti ngs


Local St age
I cal is eq ue.sti ng pam ission to st e
inf mati n n your com utsr.

Requested: u t 1 MB
Cu ntly U'se.d: 17 KB

I0 Allow II Deny

If the user has permanently denied local information storage for objects from this
domain, or if Macromedia Flash MX is unable to save the object for any reason, this
method returns false.

You can also pass a value to the flush () method indicated the amount of space you
would like in bytes.

9. With all that sorted, you're free to test


the application. After running it several SharedObject Test
times you should see that the visit count
You have been here 12 time (s)
steadily increases.
before.
2 Advanced PHP for Flash

As I said at the beginning of this section, this application hardly pushes shared objects to the
limit, but it does illustrate how easy it is to store persistent information on the client computer.

Summary
That's the end of our merry little jaunt into the new features of Flash MX, though we will be
playing with and expanding upon the things covered in this chapter at various stages in the book.
I hope that this has given you an insight into some of the more exciting additions to Flash MX,
but this is by no means a comprehensive study.

If you really want to know about all of the new features that Flash MX delivers to your fingertips
then you should check out Macromedia Flash MX Upgrade Essentials. Written by Sham Bhangal
and published by friends of Ed, this book focuses on what's new and what's important, describing
the new and enhanced features, demonstrating how to use them effectively, and discussing what
they really mean in the wider Flash MX and web design perspective.
Sessions
What we'll cover in this chapter:

The "stateless" web

Session basics

A Shopping Cart example

DE

D F
IT:
IT
~
J
3 Advanced PHP for Flash

In this chapter we are going to introduce you to the wonderful world of sessions in PHP. Sessions
allow a quick and easy way to persist user data between pages. Sessions are similar in nature to
cookies, which were introduced in Foundation PHP for Flash.

We will start the chapter by discussing the need for the persistence of data, introduce sessions,
and finally provide a fully functional Flash MX shopping cart that utilizes sessions. If you are
coming to this book from Foundation PHP for Flash, you will find this shopping cart much more
advanced and useful than what was introduced in the previous book.

The "stateless" web


Before we embark on learning about sessions, it will be useful to understand why they are
needed. If you are familiar with the need for session management you can probably safely skip
this section.

The "stateless" nature of the Internet historically has been one of the biggest hurdles confronting
web developers. By stateless, we mean that after a web server sends data to your browser the
relationship is over. Web servers simply sit around waiting for requests, and when a request
comes, they send the data and go back to waiting.

While this is not a huge concern when simply serving up static web content, trying to set up an e-
commerce site or subscription service without state is a disaster. To illustrate the problem let's take
a process we should all be familiar with and see how it would change if the process were "stateless".

Ordering a pizza
To order a pizza, you call up your local pizza shop and let them know that you would like a pizza
delivered. The pizza place will proceed to ask you where you live, the size of pizza you want, the
toppings you want, and any beverages you may want with the pizza. In 30 minutes or less you
are eating a delicious cheese and pineapple pizza. Pretty straight forward and simple isn't it?

Now imagine if you had to order a pizza like this:

You call the pizza place and once they answer you immediately hang up.

You call back and tell them you want to have a pizza delivered.

Five minutes later you call them and let them know your address.
Sessions 3

You call back, say "Large" and then immediately hang up.

25 minutes later, you open your door looking for your pizza.

Do you think the pizza will be waiting for you? Probably not. This highlights the problem facing
web developers. While the pizza shop may be able to understand one order like that, it certainly
would not be able to handle any volume. Sessions make developing for the Internet like the first
method of ordering a pizza, where the server "pizza shop" keeps track of the order and keeps
data together. Sessions allow developers to save variables and user information between pages,
therefore creating "state".

Maybe you're thinking that the pizza shop could just check the caller ID and keep track of the
calls that way. Actually, PHP and sessions work pretty similarly. Wow, what a perfect segue. When
a user moves from page to page, aSession ID (SID) helps PHP keep track of who is who. It is the
Session ID that binds a user session together.

How sessions work


PHP4 has native support for sessions, which make them much easier to use than in previous
versions of PHP. In PHP3, developers had to use PHPLib to create sessions. While PHPLib has some
great features. it is hard for beginners to use it effectively. All subsequent examples will use PHP4
syntax and compatible code.

Under the hood, sessions work by associating an SID to a user. For sessions to work properly, PHP
needs to save data about the session on the server, and also needs to keep the client updated about
their session. Below we've given a brief description of the most common methods of both.

Saving server data


Writing text files - PHP writes a text file to the server for each session. By default the files
go in the /tmp folder. The disadvantage of this solution is that your server can get bogged
down quickly with thousands of text files. To combat this you could create a small batch
file that removes old session text files no longer in use, to be used in conjunction with the
advanced garbage-collection features provided by PHP to remove old session text files.

Memory- PHP can keep session data in memory. The benefit of this solution is speed, as
accessing data from memory is faster than accessing data from a hard drive. Unfortunately
the memory needs of your server will increase. You also run the increased risk of losing
3 Advanced PHP for Flash

your session data unexpectedly. A sudden reboot or crashed application will delete all your
session information.

Database- Finally, PHP can write session data to the database of your choice. The benefit
of this solution is control and power, as you can track and distribute session data more
powerfully this way. The cons of this solution are the more complicated setup and
understanding of databases needed to get it working properly.

Saving client data


Cookies - In this case a small cookie holding the SID is stored on the client. This is by far
the easiest method. You can potentially run into problems here if the client does not have
cookies enabled, but there are ways around this.

GET/POST- Here the SID is passed from page to page. Numerous methods can be utilized
to accomplish this, including passing the SID in the URL or posting hidden form values
from page to page. You run the small risk here of "session takeovers", or "session
spoofing", where a user can steal another user's SID and attempt to use it themselves.
Because the SID is being passed from page to page, it is either in clear view of the user in
the URL itself or in a hidden form field. Someone looking over the shoulder of that user
could write down the SID and attempt to introduce it to the website as if they were the
original user. The malicious user could then have access to all the personal information of
the original user. This is obviously bad. To help combat the problem you can write a
validation script that checks the IP address of the user and makes sure all requests using
that SID come from that same IP address. Although more secure, because of the way proxy
servers and routers send IP addresses, two separate users could appear to be running the
same IP address. Because of these security concerns we will concentrate of the use of
cookies for the rest of this chapter.

Session syntax
Sessions are very easy to work with in PHP4. In this part of the chapter, we will look at a few of
the simple functions that we will use in later examples.
Sessions 3

session_start()
You start a PHP 4 session by calling session_start ().Those PHP guys really try to make it easy,
huh? This should be called at the top of your PHP page before any data is written to the client
(for example, before the <IITML> tag) In fact. if you try to call this function after text has been
written to the browser you will get an error message that states that headers were already sent.

session_start () checks to see if a session exists for the current user. If it finds that a session
has already begun for the user, it loads all the variables for that session. If a session has not yet
begun, PHP starts one.

Technically you don't need to call this function. If you start using session variables without
explicitly calling session_start (), PHP will call it behind the scenes. But forget we ever told
you that; it's bad practice to skip session_start () .

session_destroy()
You can explicitly force a session to end by issuing a session_destroy (). If you are using
cookies to store the SID on the client (as we are in our examples), the session will end when the
cookie is destroyed. If you are storing session data in a text file, the text file will be deleted here.

session_id()
This function returns the value of the session ID for the current user.

boolean session_register()
Before you can save variables into the session you need to register them. You can register new
variables or existing ones. This function will return true if the variable is registered correctly and
false if an error occurred. Examples of use are given below:

II creating new variable


<?
session_ start ();
session_ register('intValue');
?>
3 Advanced PH P for Flash

Even though intValue has no value, it can be used as a session variable. Next we will look at
registering existing PHP variables.

session_start ();
$strFirstName = "Matt";
session_register("strFirstName");
II registers strFirstName with the value of 'Matt'
?>

boolean session_unregister()
This function should be fairly self-explanatory; it removes variables from the session.
<?
session_unregister ("strFirstName")

Shopping cart example


To showcase the power of sessions we are going to create a simple PHP/MySQL-based shopping
cart that uses Flash MX to display the current cart items. The final product will look like this:

--
J.IKf~
- --... ~
E.~~ss
~ .....
J:lii.M
~ . --
,.,_ _
... ~a
,_w
l o>'l.lol.ol
Sessions 3

MySQL database setup


First we are going to create the MySQL database. Even though this is a simple example and could
be done without a database, using one will allow you to reuse code and ideas for your real-world
applications.

Create a simple database called bookdb. The bookdb database will have one table - books - and
will hold the data of currently available books that your customers will be able to purchase.

Type the following into your MySQL admin interface. Please note: text in italics is returned from
the interpreter.

mysql> create database bookdb;


Query OK, 1 row affected (0.01 sec)

mysql> USE bookdb;

Database changed

mysql> create table books


-> (

-> bookiD int auto increment not null,


-> bookName varChar(lOO),
-> bookimageLoc varChar(200),
-> bookiSBN varChar(20),
-> bookAuthors varChar(200),
-> bookPrice decimal(5,2),
-> bookPageCount int(5),
-> primary key(bookiD),
-> unique id(bookiD)
-> ) ;
Query OK, 0 rows affected (0.11 sec)

Great, you should now have the database created and ready to go. Below is a basic description
of the fields in the database.

bookid: A unique numeric identifier that gives each book its own ID.
3 Advanced PHP for Flash

bookName: The title of the book.

bookimageLoc: Location on the server of the book's cover image.

bookiSBN: The book's ISBN number.

bookAuthors: A comma-delimited list of authors who contributed to the book.

bookPrice: The book's suggested retail price.

bookPageCount: The number of pages in the book.

Now that the database is completed and ready to go, we need to manually enter some books.
Please enter the following book information.

Book images can be downloaded from www.friendsofed.com.


The third value entered into books is the path to the book image.
If this is in a different location on your web server. please make
the appropriate changes.

INSERT INTO books (bookiD, bookName, bookimage, bookiSBN,


bookAuthors, bookPrice, bookPageCount)
VALUES
(0, 'Foundation Macromedia Flash MX', 'images/FoundationFlashMx.jpg',
'1-903450-10-1', 'Kristian Besley, Sham Bhangal, Amanda Farr', 29.99,
600) i

INSERT INTO books (bookiD, bookName, bookimage, bookiSBN,


bookAuthors, bookPrice, bookPageCount)
VALUES
(0, 'Macromedia Flash MX Express', 'images/FlashMxExpress.jpg', '1-
903450-95-0', 'B J Mace, Glen Rhodes, Leon Cych', 24.99, 340);

INSERT INTO books (bookiD, bookName, bookimage, bookiSBN,


bookAuthors, bookPrice, bookPageCount)
Sessions 3

VALUES
(0, 'Macromedia Flash Upgrade Essentials',
'images/FlashMxUpgradeEssentials.jpg', '1-903450-76-4', 'Sham
Bhangal', 34.99, 450);

INSERT INTO books (bookiD, bookName, bookimage, bookiSBN,


bookAuthors, bookPrice, bookPageCount)
VALUES
(0, 'Macromedia Flash MX Video', 'images/FlashMxVideo.jpg', '1-
903450-85-3', 'Brian Monnone, Hoss Gifford, Kristian Besley, Todd
Marks', 29.99, 300);

Since the database creates a unique ID for bookiD, we do not need


to specify an 10, hence the use of 0 for every example. The 0 is a
personal preference to designate an auto-numbered unique field.

To test to make sure everything went smoothly, enter the following SELECT statement:

SELECT * FROM books

You should see something similar to the following:

f'\] c:\ WINNT \ System32\ command.com


rnys ql> se lect f>oR hooks;
+-------- +--------- ---------- ------------------ +---- ---- ----------- ------------- a
+---- ----- -- --------------- +
: hooklD : bookHrlrne : hooklll'lageLoc
: booklSBH : bookAuthors
: bookPrice : bookPagcCount :
----------------------- -------------- - +--------------- ----- --------- --
-----+--------------- --------------------- ------- ------------------------- -----
-----------+---------------
1 : Foundation Macl~omedii\ Flrt5h MX' : iroages: / Foundat ionFlrt ~ hf"fx.jpg
: 1 - 903450- Hl - 1 : Ktist i..-n Bcsley. Sh..-., Bh ... ng.>l, Ananrla p._.,.,.
29.99 : 600 :
2 ; MnctonerliC\ Fla s h MX Expe!>s : irr..age~/Pl<t s h11xE x pre s~ .jpg
: 1 - 903450 - 95-0 : B J Mace. Glen Rhode ~ . Leon Cych
24.99 : 340 :
3 : Ma c onedia Fla !> l Upg~ade Es~ential~ i~age !>/ Pla s JJM x UpgrarleE ~~ cnti~l ~
: 1 - 903450- 76 - 4 : ShMI Bh ... ngal
34.99 : 450 :
4 : M.,c tornedirl Flash MX Uirleo i"'ages/FlashMxUideo . jpg
: 1 - 903450 - 85 - 3 : B>i<tn Monnone. Ho ss Giffo>d, K>i s tin B~sley. Todd M.u-ks
2 9.99 : 300 :
+ -~--- --- + -------- ------------------ ----------- + ------------------------ --------
----- --------------- +--------------------------- ------------------ ------------ -
--------------------------
3 Advanced PHP for Flash

PHP setup
Now that the database is all set and ready to go it's time to move on to the PHP files. For this
example we are going to create five .php files. The basic flow of the files is:

Brief descriptions of the files we are going to create are given below:

start shopping. php: The start page of the application. This PHP file creates the session
and forwards the user to the main page.

shoppingcart .php: The main page of the app. It shows all the books available to put in
your cart, shows the Flash MX cart, and handles all the back-end PHP for adding and
removing items.

checkout .php: Called after the user is satisfied with their choices and wants to check out.

class info. php: Holds all the class code for the shopping cart. It is included in every
other PHP file.

clearcart .php: Deletes the current session for development purposes.


Sessions 3

classinfo.php
We are going to create two classes, shoppingCart and Cartitem, for use in our shopping cart.
A class is basically a set of variables and functions that describe an object, for instance a 'cart item'.

class shoppingCart {

var $arrBooks =array(};

function addBook($bookiD, $bookPrice, $bookName) {


$this->arrBooks[] =new Cartitem($bookiD, 1, $bookPrice,
$bookName) ;

class Cart Item {


var $bookiD;
var $quantity;
var $bookPrice;
var $bookName;

function Cartitem($bookiD, $quantity, $bookPrice, $bookName) {


$this->bookiD = $bookiD;
$this->quantity = $quantity;
$this->bookPrice = $bookPrice;
$this->bookName = $bookName;

function UpdateQuantity($quantity)
$this->quantity = $quantity;

?>
3 Advanced PHP for Flash

Cartitem is a very basic class that holds four variables: bookiD, quantity, bookPrice, and
bookName. Although you could implement the functionality using simple variables or functions,
using a class here allows you greater power and flexibility in the future. For instance, let's say you
want to create another entity called usedCartitems where you store used items available for
sale. Normally you would have to re-create all the variables and functions for that object. Using
classes allows you to create an inheritance chain borrowing the variable and function definitions
of the parent class.

Let's take a quick look at our functions. Creating a function with the same name as the class
designates that function as the constructor function, as in the case of the cartitem function. A
constructor function is automatically called when the class is created. In this example, when a
cartitem is created, we will pass the function an ID, quantity, price, and name, and our
constructor function will set the class' internal variables to those values. The updateQuantity
function updates the quantity for that cart item.

The shopping cart class simply holds an array of all the cart items in your shopping basket. The
addBook function creates a new array index and sets it equal to a new Cartitem.

startshopping.php
This file starts a session, creates a new shoppingCart class item, and registers it as a session variable.

<?
include("classinfo.php");
session_start () ;

$myCart =new shoppingCart();


session_register ( "myCart") ;
?>
<H'I'ML>
<HEAD>
<TITLE>Flash MX Shopping Cart</TITLE>
</HEAD>
<BODY>
<TABLE WIDTH="lOO%" HEIGHT="lOO%" BORDER=O>
<TR VALIGN="TOP">
<'ID>
<FONT SIZE="+3">Flash MX Shopping Cart Example</FONT><BR>
Sessions 3

<TABLE WIDTH="lOO%" CELLSPACING=O CELLPADDING=O BORDER=O>


<TR><TD BGCOLOR="#CCCCCC">&nbsp;</TD></TR>
</TABLE>
</TD>
<TR VALIGN="MIDDLE">
<TD HEIGHT="lOO%" ALIGN="CENTER">
Welcome to our Book Store<BR><BR>
<A HREF="shoppingcart.php">Start Shopping</A>
</TD>
</TR>
</TABLE>
</BODY>
</H'I'ML>

clearcart.php
Use this file for development purposes when you want to clear your session. It opens up your
session and removes myCart.

<?
session_start();
session_unregister ( "myCart") ;
?>

<H'I'ML>
<HEAD>
<TITLE>Flash MX Shopping Cart</TITLE>
</HEAD>
<BODY>
<TABLE WIDTH="lOO%" HEIGHT="lOO%" BORDER=O>
<TR VALIGN="TOP">
<TD>
<FONT SIZE="+3">Flash MX Shopping Cart Example</FONT><BR>
<TABLE WIDTH="lOO%" CELLSPACING=O CELLPADDING=O BORDER=O>
<TR><TD BGCOLOR="#CCCCCC">&nbsp;</TD></TR>
</TABLE>
</TD>
<TR VALIGN="MIDDLE">
3 Advanced PHP for Flash

<TD HEIGHT="lOO%" ALIGN="CENTER">


Your Session Has Been Cleared<BR><BR>
<A HREF="startshopping.php">Start 0ver</A>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

shoppingcart.php
This file is the meat of the application. It handles the display of available books, passes
appropriate data to the Flash MX application, and handles all the updating of the session
variables. Ready? Let's get started.

<?
include("classinfo.php");
session_start();

i f (isset ($HTTP_POST_VARS ["bookAdd"]))


/* You don't want to attempt to read the values until they are
available . *I

The first time you reach shoppingcart .php, bookAdd will not be anything, so you don't want
to attempt to read the posted value.

i f ($HTTP_POST_VARS ["bookAdd"] "true") {


$bookSame = false;
$tempiD = -1;

for ($x=O; $x < sizeof($HTTP_SESSION_VARS ["myCart"]->arrBooks);


$X++) {
i f ($HTTP_SESSION_VARS ["myCart"]->arrBooks [$x]->bookiD
$HTTP_POST_VARS ["bookid"])
$bookSame true;
$tempiD $x;
}
Sessions 3

i f ($bookSame){
$nextQuantity = 1 +
$HTTP_SESSION_VARS["myCart"]->arrBooks[$tempiD]->quantity;
$HTTP_SESSION_VARS["myCart"]->arrBooks[$tempiD]->
UpdateQuantity($nextQuantity);

else
$HTTP_SESSION_VARS["myCart"]-
>addBook($HTTP_POST_VARS["bookid"],
$HTTP_POST_VARS ["price"], $HTTP_POST_VARS ["name"]);

Here we are checking to see if a user wants to add an item to their shopping cart. The for loop
determines if the item the user is attempting to add has already been added to their cart. It loops
through the arrBooks array and checks to see if the bookiD you are trying to add is already
included. If it finds a match it sets $bookSame equal to true.

The file then checks the $bookSame flag. If it is true (item already exists in cart) it grabs the
current quantity for that item and adds 1. If $bookSame is false (item not in cart), it adds that
bookiD to the cart.

else i f ($HTTP_POST_VARS ["bookSubtract"] == "true")

$nextQuantity = $HTTP_SESSION_VARS["myCart"]->
arrBooks[$HTTP_POST_VARS["arrayid"]]->quantity- 1;
$HTTP_SESSION_VARS["myCart"]->
arrBooks [$HTTP_POST_VARS ["arrayid"]]
->UpdateQuantity($nextQuantity);

If bookSubtract equals true it means the user wants to remove one quantity from their cart
for a specific cart item. The code grabs the current quantity, subtracts 1, and then resets the
quantity using the UpdateQuantity function.

else i f ($HTTP_POST_VARS["bookDelete"] == "true") {


array_splice ($HTTP_SESSION_VARS["myCart"]->arrBooks,
$HTTP_POST_VARS ["arrayid"], 1);
}}
3 Advanced PHP for Flash

Here we are checking if a user wants to delete an item from their shopping cart. This simply
removes the array item for the item they wish to delete.

The getBooks () function queries the database to get the current list of books and displays
them in an html table. First you need to enter information about your MYSQL server.

function getBooks() {
$ServerLoc = "localhost";
$User = "admin" ;
$Password= "adminpass";

$conn= mysql_connect($ServerLoc, $User, $Password);


$connRS mysql_select_db('bookdb', $conn);
$result mysql_query("select * from books");
$numBooks = 0;

If you are familiar with the common. php file introduced in


Foundation PHP for Flash, the above code will change as follows.
Instead of $ServerLoc, $User, and $Password include the
following code:
$server= include('common.php');
$linkage = $link = dbConnect();

Change the beginning of getBooks () as follows:


function getBooks() {
$conn= mysql_connect($server, $linkage);
$connRS = mysql_select_db('bookdb', $conn);

Next, open the database and select all the items from the books table:

while($row = mysql_fetch_array($result))

$numBooks += 1;

if (($numBooks% 2) 1) {
Sessions 3

echo 11 <TR> 11 ;

Since we are going to use two columns, every odd book will need to start a new <TR> tag.

<'I'D WIDTH= 11 50% 11 >


<IMG SRC= 11 <? echo $row[ 11 bookimageLoc 11 ] ; ?> 11 ><BR>
<b><? echo $row[ 11 bookName 11 ] ; ?></b><BR><BR>
<FONT SIZE= 11 -l 11 >ISBN: <? echo $row[ 11 bookiSBN 11 ] ; ?></font><BR>
<FONT SIZE= 11 -l 11 >Authors: <? echo $row[ 11 bookAuthors 11 ] ;
?></font><BR>
<FONT SIZE= 11 -1 11 >Price: <? echo $row[ 11 bookPrice 11 ] ;
?></font><BR>
<FONT SIZE= 11 -l 11 >Page Count: <? echo $row[ 11 bookPageCount 11 ] ;
?></font><BR>
<A HREF= 11 javascript:addToCart('<? echo $row[ 11 bookiD 11 ] ; ?>' 1

'<? echo $row[ 11 bookPrice 11 ] ; ?> ' '<? echo $row[ 11 bookName 11 ] ;
1

?>') 11 ><IMG SRC= 11 images/AddToCart.gif 11 WIDTH=lOO HEIGHT=30


BORDER=O></A>
</'I'D>
<?

if (($numBooks% 2) == 0) {
echo 11 </TR><TR><'I'D><BR><BR></TD><'I'D><BR><BR></TD></TR> 11 ;

Every even book will need an end <TR> tag. For spacing purposes we then skip a row.

The following function will be called to get data into Flash. Here we are using the FlashVars
method of passing values into Flash.

function displayVars() {

for ($x=0; $x < sizeof($HTTP_SESSION_VARS [ 11 myCart 11 ]->arrBooks);


3 Advanced PHP for Flash

$X++) {
echo 11 &book 11 ;
echo $x;
echo "-"
- I

echo urlencode($HTI'P_SESSION_VARS[ 11 myCart 11 ]->arrBooks[$x]->bookiD);


echo 11 &bookPrice 11 ;
echo $x;
echo "-"
- I

echo urlencode($HTI'P_SESSION VARS


[ 11 myCart 11 ]->arrBooks[$x]->bookPri ce);

echo 11 &bookQuantity 11 ;
echo $x;
echo .. _
-
...
I

echo urlencode($HTI'P_SESSION VARS


[ 11 myCart 11 ]->arrBooks[$x]->quantity );

echo 11 &bookName 11 ;
echo $x;
echo n_n.
- I

echo urlencode($HTI'P_SESSION VARS [ 11 myCart 11 ]->arrBooks[$x]->


bookName);

echo 11 &numBooks= 11 ;
echo sizeof($HTI'P_SESSION_VARS [ 11 myCart 11 ]->arrBooks);

?>

An example output is given below:

&book0=2&bookPrice0=39.99&bookQuantity=4&bookName=Advanced+PHP+And+Fl
ash+MX&numBooks=l

For more information on using FlashVars, Robert Hall has a great explanation available at
http://www.impossibilities.com/bloglflashvarstip.php. Later in the chapter we will show how Flash
will use this data to display the contents of the user's shopping cart.
Sessions 3

<HI'ML>
<HEAD>
<TITLE>Flash MX Shopping Cart</TITLE>

<SCRIPT>

function addToCart(bookid, price, name) {


document.forml.bookAdd.value = "true";
document.forml.bookid.value = bookid;
document.forml.name.value = name;
document.forml.price.value = price;
document.forml.submit()

</SCRIPT>
</HEAD>

This is a simple javaScript function that takes values passed to it from the additem HTML button,
inserts those values in hidden fields, flags the bookAdd field, and then submits the page back to itself.
By calling . submit () . the form is submitted to the page in the form's action parameter. Although you
could code this without the document. in Internet Explorer, it will break in many Netscape versions.

<BODY>

<FONT SIZE="+3">Flash MX Shopping Cart Example</FONT><BR>


<TABLE WIDTH="lOO%" CELLSPACING=O CELLPADDING=O BORDER=O>
<TR><TD BGCOLOR="#CCCCCC">&nbsp;</TD></TR>
</TABLE>

<BR>
<TABLE WIDTH="l00%">
<TR VALIGN="TOP">
<TD>
<TABLE WIDTH="lOO%" BORDER=O>
<? getBooks () ? >
</TABLE>
<BR><BR>
3 Advanced PHP for Flash

</'ID>
<'ID WID'I'H=250>
<OBJECT classid="clsid:D27CDB6E-AE6D-llcf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swf
lash.cab#version=6,0,0,0"
WID'I'H="250" HEIGHT="400" id="ShoppingCart" ALIGN="">
<PARAM NAME=movie VALUE="ShoppingCart.swf">
<PARAM NAME=quality VALUE=high>
<PARAM NAME=bgcolor VALUE=#FFFFFF>
<PARAM NAME=FlashVars VALUE="<? displayVars() ?>">
<EMBED src="ShoppingCart.swf" FlashVars="<? displayVars() ?>"
quality=high bgcolor=#FFFFFF WID'I'H="250" HEIGHT="400"
NAME="ShoppingCart" ALIGN="" TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer"></EMBED>
</OBJECT>
</'ID>
</TR>
</TABLE>
<FORM NAME="forml" ACTION="shoppingcart.php" METHOD="POST">
<INPUT TYPE="HIDDEN" NAME="bookAdd" VALUE="false">
<INPUT TYPE="HIDDEN" NAME="bookid" VALUE="">
<INPUT TYPE="HIDDEN" NAME="name" VALUE="">
<INPUT TYPE= "HIDDEN" NAME= "price" VALUE="">
</FORM>
</BODY>
</HI'ML>

checkout.php
This file iterates through every item of the arrBooks array and displays the user's shopping cart
in HTML to give them a final chance to change any items before sending the user off to enter
their credit card information.

include("classinfo.php");
session_start ();

$totalBill 0;
Sessions 3

?>

<H'I'ML>
<HEAD>
<TITLE>Flash MX Shopping Cart - Checkout</TITLE>
</HEAD>
<BODY>

<FONT SIZE="+3">Flash MX Shopping Cart Example - Checkout</FONT><BR>


<TABLE WIDTH="lOO%" CELLSPACING=O CELLPADDING=O BORDER=O>
<TR><TD BGCOLOR="#CCCCCC">&nbsp;</TD></TR>
</TABLE>

<BR>
<TABLE WIDTH="lOO%">
<TR VALIGN="TOP"><TD><B>Book ID</TD><TD><B>Book Name
</B></TD><TD><B>Book Price</B></TD><TD><B>Quantity Ordered
</B></TD><TD><B>Total Cost</B></TD></TR>
<?

for ($x=O; $x < sizeof($HTTP_SESSION_VARS ["myCart"]->arrBooks);


$X++)
echo "<TR><TD>";
echo $HTTP_SESSION_VARS ["myCart"]->arrBooks[$x] ->bookiD;
echo "</TD><TD>";
echo $HTTP_SESSION_VARS ["myCart"]->arrBooks[$x] ->bookName;
echo "</TD><TD>";
echo $HTTP_SESSION_VARS ["myCart"]->arrBooks[$x]->bookPrice;
echo "</TD><TD>";
echo $HTTP_SESSION_VARS ["myCart"]->arrBooks[$x]->quantity;
echo "</TD><TD ALIGN='RIGHT'>";
$totalCost = ($HTTP_SESSION_VARS ["myCart"]->arrBooks[$x]-
>quantity)
*
($HTTP_SESSION_VARS ["myCart"]->arrBooks[$x]->bookPrice);
echo $totalCost;
$totalBill = $totalBill + $totalCost;
3 Advanced PHP for Flash

?>
</TR>
<TR BGCOLOR="#CCCCCC"><'I'D>&nbsp;</'I'D><'I'D>&nbsp;</ 'I'D>
<'I'D>&nbsp;</'I'D><'I'D>&nbsp;</'I'D><'I'D>&nbsp;</'I'D></TR>
</TABLE>
<TABLE WID'I'H="lOO%">
<'I'R>
<'I'D ALIGN="RIGHT" >
<B>Total Cost: </B><? echo $totalBill; ?>
</'I'D>
</TR>
</TABLE>
<BR><BR>
<FORM NAME="forml" ACTION="shoppingcar t.php" METHOD="POST">
<INPUT TYPE="SUBMIT" NAME="ContinueShopping"
VALUE="Continue Shopping">&nbsp;&nbsp;
<INPUT TYPE="BurTON" NAME="BILL" VALUE="Forward to Billing"
onClick="alert ( 1 this is as far as this demo goes . 1 ) ; ">
</FORM>
</BODY>
</HTML>

The Flash MX file- ShoppingCart.fla


Now that the database and PHP files are ready to go we will focus on the Flash MX shopping cart
interface. The basic structure that we are going to create is shown below:

~
Cartlem
,~.\.~; ~
Plus Sign Q1Pf*;

Garbage
~
Cen~

. :
Sessions 3

Try to keep this graphic in mind as we go through the different movie clips and code samples;
it will help you piece everything together in your mind. Even though we use the button and
graphic as names in our file, they simply are used to describe their basic functions; all should be
created as movie clips.

_root
To start, create a 250x400 sized Flash file with a white
background. Next, draw the border and additional graphics for
g ~.<y~con

the shopping cart. The look was achieved using simple lines
and square tools. If you wish to use these graphics for the
example below please refer to the original . fla file.

I CllocO<M
I
Here is what the final timeline will look like:

000

~ Elo ~dit :tJew lfl""t Modify text l:ontroi~I:!<IP I


..5.
a\ ' ' ~ - 35 40
~ ~ II
2$
~ o 1) 1$

/ p IV .. 0
~ A
0 0
[1;1 Ched<W
[1;1-.,.Tol<l .. 0
0
I> D MyCart ~
tf{j
G ~~
~~

..
J'(} v~.t:J E! oj 'tti'Qj ~ !"1]f""ll nDfp [O"ib I"n" .", '~"r'
~ , ~-
~"l Q.
~
/J!l 1'1:7 "'-c""

[ 16 ..

Please note that all graphics for this example are bundled in a folder called MyCart.
3 Advanced PHP for Flash

Create a dynamic text field with an instance name of Status. Position it where you feel most
appropriate (we like the bottom edge of the cart), but you can move it wherever you want, it's
your Flash file after all!

You should also create a movie clip for CheckOut, but you can leave that empty for now; we'll
return to that movie clip later.

Enter the following code in frame 1:

/*
Root Frame 1 AS
*/

movStartCart = createEmptyMovieClip ( "movStartCart", 10)


movStartCart. x 2
movStartCart._y = 27

This creates an empty movie clip called movstartCart into which all cart items will load and
moves the movie clip to the correct x and y location under the My Shopping Cart heading.

if (numBooks == 0) {
Status.text = "There currently is nothing in your cart.";

This code first checks to see if PHP has passed any books to Flash. If numBooks equals 0 it means
the shopping cart is empty. Here the status text is displaying to the user that their cart is empty.

else {
for (var i=O; i < numBooks; i++) {
var tempMC = rrovStartcart.attachMovie("cartitem", "Item" + i, 10 + i)
tempMC.Quantity = eval("bookQuantity" + i);
tempMC.arrayiD = i;
tempMC.bookid = eval ("book" + i);
tempMC.Price = eval ("bookPrice" + i);
tempMC.BookName eval ("bookName" + i);

root.totalCost = root.totalCost + (eval("bookQuantity"+i) *


eval ("bookPrice"+i));
Sessions 3

tempMC._y 20 * i;

totalMC = movStartCart.attachMovie("Totalitem", "Totaltem", 11 +


numBooks)
totalMC.Price _root.totalCost;
totalMC._y = 20 * numBooks;

stop();

If numBooks is greater than 0, it means that there are books in the user's shopping cart. Create a
loop to iterate through all the books in the shopping cart. In each case, attach a Cartitem from
the library and give it a unique instance name. (We will create the Cartitem movie clip later).
Then pass all the variables cartitem needs to display including the quantity ordered, arrayiD,
bookiD, bookPrice, and bookName. Finally determine the total cost of the book and pass that
value to the Cartitem. After sending all variables, we position the cart item to the correct vertical
location.

After every cart item has been displayed, we attach the Totalitem movie clip from the library
and pass it the total cost of books in the cart. We then move the Totalrtem movie clip to the
bottom of the last cart item.

Cartltem
Now that the _root is all set, we will create the
attachable Cartltem movie clip. Our final product
will look like this:

And our frames:


3 Advanced PHP for Flash

Create a new movie clip (give it any name you want). After it is created right-click on it in the
library and select Linkage. Click on the Export for ActionScript check-box and give it an identifier
of Cartltem. Now open up the Cartltem movie clip and draw a gray rectangle. Make the rectangle
245x20.

Next, create three dynamic text fields with instance names of txtPrice, txtQuantity, and
txtBookName. I used _sans 9 pt for the text fields but feel free to use any font. Create two movie
clips, one for the plus sign and one for the minus sign (we will go over the plus and minus signs
a bit later). For now leave those movie clips blank. Finish it off by creating a movie clip for the
garbage can, which you should also leave blank.

To spice the cart up a little I added a small 10-frame animation. I made a simple white rectangle
tween from alpha 0 to 100 to create a zoom in effect. You can choose to leave this effect out if
you desire.

Frame 1 of Cartltem
txtQuantity.text = Quantity;
txtBookName.text = BookName;
txtPrice.text = "$" + Price;

The above code takes the Quantity, BookName, and Price passed to the MC from the root and
places them in their respective text fields.

if (Quantity == 1) {
MinusSign._visible false;

If the quantity is 1 you should not remove another item from that cart item, so hide the MinusSign.

var intCounter = 0
while (txtBookName.textWidth > 130) {
intCounter++

txtBookName.Text BookName.substring(O, BookName.length -


intCounter) + "
Sessions 3

Because book names can sometimes get long, here we have a simple script that checks to see if
the textWidth is greater than 130 pixels. lf it is larger it keeps removing a little at a time and
adds " ... " until the text width is less than 130 pixels.

Frame 10 of Cartltem
stop();

PlusSign
Next we are going to create the plus and minus signs. How else will the user order more of your books?

Here is what the final product will look like:

The frames should be laid out as follows:

First off, create a new movie clip called PlusSignGraphic. Using the square tools draw a simple
6x6 plus sign.

After you are finished, create another movie clip called PlusSign. Put your PlusSignGraphic inside
it and give it the instance name PlusSignGraphic.

Create a 12x12 square under the plus sign, and convert the square into a movie clip called
HitAreaMC. HitAreaMC will be the "hot spot" area for your plus sign. lf you did not specifically
create a custom HitArea movie clip, the user would have to move their mouse exactly over the
plus sign, which would be difficult. Give it the instance name HitAreaMC.
3 Advanced PHP for Flash

Frame 1 of PlusSign MC
hitAreaMC. visible = false;
this.hitArea = hitAreaMC;

/*
Set the hitAreaMC to invisible so the user won't see it. Then set
this ( the "PlusSign" movie clip's) hitArea equal to the hitAreaMC
you just created.
*I

this.onRollOVer = function()
root.Status.text = "Press To Order More Copies";

var myColor = new Color(PlusSignGraphic)


myColor.setRGB(OxFF3300)

this.onRollOut = function()
root.Status.text "";

var myColor = new Color(PlusSignGraphic)


myColor.setRGB(Ox000066)

I*
When rolling over or rolling off of the hitArea, show appropriate
feedback text. Using the color object, you can also programmatically
choose to change the color of the plus sign on rollover which we
have showcased here.
*/

this.onPress = function()
bookAdd = true;
bookSubtract = false;
bookDelete = false;
Sessions 3

bookid = _parent.BookiD;
getURL ( "shoppingcart . php", 1111
I "POST");

/*
There are the bookAdd, bookSubtract, and bookDelete variables that
we used back in the php files. Since the user can choose to either
add an item, subtract an item, or delete an item, we set the flag
for the respective action and send it back to the shoppingcart.php
file .
*I

stop();

MinusSign
Because the steps to create the minus sign are so similar to those for the plus sign, we are going
to skip re-showing you the same steps and simply show you the code needed on frame 1.

Frame 1 of MinusSign
hitAreaMC. visible = false;
this . hitArea = hitAreaMC;

this.onRollOver = function()
root.Status.text = "Press To Order Fewer Copies";

var myColor = new Color(MinusSignGraphic)


myColor.setRGB(OxFF3300)

this.onRollOut = function()
root.Status.text 1111.
I

var myColor = new Color(MinusSignGraphic)


myColor.setRGB(Ox000066)

this.onPr ess function()


3 Advanced PHP for Flash

bookAdd = false;
bookSubtract = true;
bookDelete = false;

arrayid = _parent.arrayiD;
bookid = _parent.BookiD;
getURL("shoppingcart.php", "" "POST");

stop();

GarbageCan
The steps to create the garbage can are very similar to those for creating
the plus or minus sign movie clips. Start out by creating a blank movie clip
and drawing your garbage can. Our home for Oscar is shown to the right:

After creating your garbage can graphic and movie clip, create another movie clip called
GarbageCan and place your previous movie clip within it. Give the garbage can graphic an
instance name of GarbageCanGraphic.

The difference between the garbage can and the plus or minus signs is the way the rollover is
implemented. Because the garbage can has multiple colors, a simple color transformation will
not work properly. What we did here was alter the bb transform property for the rollover to give
the garbage can a slight red tint on rollover, without altering the underlying color structure of
the garbage can.

this.onRollOver = function()
root.Status.text = "Press To Remove From Cart";

var myColor = new Color(GarbageCanGraphic)


var objTrans = new Object()
objTrans.bb = -255
myColor.setTransform(objTrans)
Sessions 3

this.onRollOut = function()
root.Status.text "" ,..

var myColor = new Color(GarbageCanGraphic)


var objTrans = new Object()
objTrans .bb = 0
myColor.setTransform(objTrans)

this.onPress = function() {

bookAdd = false;
bookSubtract = false;
bookDelete = true;

arrayid = _parent.arrayiD;
bookid = _parent.BookiD;
getURL("shoppingcart .php", "" "POST" );

Totalltem
The Totalltem movie clip is a simple display of the total cost of the items in the user's shopping
cart. Create a simple new movie clip with a gray square background like the Cartltem movie clip
you created previously. Put in a dynamic text field almost the entire size of the square with an
instance name of txtPrice. Set the linkage for this movie clip to Totalltem. This movie clip will be
dynamically attached to the root. Make it animate much like the plus and minus signs with a
small 10-frame animation.

1..---- -------- ---- --------- -


:
.:
- -------- ---- ---------

Totalltem MC Frame 1
txtPrice.text = "$" + Price + " Total";

Totalltem MC Frame 10
stop();
3 Advanced PHP for Flash

CheckOut
Almost done! just one more movie clip and we will be ready to test our shopping cart out. Go
back to the _root and open the empty movie clip you made previously for the Check Out
button. We decided to create the button as a movie clip with code similar to the garbage can to
accomplish a rollover effect. Below is the code for the Check Out button:

this.onRollOver = function()
root.Status.text = "Press To Checkout";

var myColor = new Color(CheckoutGraphic)


var objTrans = new Object()
objTrans.bb = -255
myColor.setTransform(objTrans)

this.onRollOut = function()
root.Status.text "",

var myColor = new Color(CheckoutGraphic)


var objTrans = new Object()
objTrans.bb = 0
myColor.setTransform(objTrans)

this.onPress = function() {
getURL("checkout.php", "" "POST");

stop();

All set
That's it! Hopefully it wasn't too painful to get it working. Now point your browser at
startshopping .php and start experimenting. Watch what happens when you add items to your
cart, surf to another site, and then return later.
Sessions 3

If you have any problems, remember to place your images in an image folder in your directory,
and your SWF file in the same directory as your scripts. Please also make sure that your books
table has the correct path to your image folder.

Moving forward
Hopefully our shopping cart example gave you some good ideas to move forward with your own
session-powered Flash MX shopping cart. There are a few things you should keep in mind as you
move forward.

FlashVars may not be the best method for larger shopping sites with more potential cart items.
It may make more sense for a larger site to write the cart out as an XML file and load it into Flash.

Proper security is an absolute necessity when creating an e-commerce site. A good site to learn
more about securing PHP is http://www.phpadvisory.com/.
File
~~File
D D

Uploading
83
1[0 l
JJ D d=S

8 ~
3:b I ~ ~ L.J L..LJ r ,.--~
rrI ...... -~

""'T-r"'1 Fij II ~ ~ EEl:P~ B~ D


I
I


I L
I I I
What we'll cover in this chapter:
DD
D
Client-side JavaScript to Flash, and Flash-to-Flash communication

Creating an Image Viewer in Flash using HTML, JavaScript, and ActionScript as


the front-end

Adding a PHP back-end to our Image Viewer

oD

EfE
[

oD
rriT
~IT
D
o l r...
% B rR cf,r
,
u B
4 Advanced PHP for Flash

The ability to accept and process uploaded files from a user's computer is one of the many
feathers that PHP boldly wears in its fairly substantial cap. PHP allows you to handle file uploads
securely, verify that the file is of the type and size expected, and copy it to a given directory.
While this may sound a little bit simple for a chapter of its own, there are many particularities
that you must look out for when allowing a user to upload files to your server.

HTML
Let's start by discussing the front-end of web-based file uploading. Hands down, HTML is the best
and most cross-browser way to go. Since browsing a user's files requires that the browser opens
the computer's file explorer, Internet Explorer, Netscape, etc. knows that the following line of code:

<input type="file">

is special, in that the browser responds by adding a Browse ... button to the page.

When clicked, the Browse button opens the computer's file explorer. Unfortunately, this
interaction between the browser and HTML is exclusive, so any other language or web-based
application that wants to open the file explorer, must do so by "triggering" the Browse button.
If you want to keep things simple, make your administrative pages using HTML and include the
following form that allows you to select a file and upload it using a PHP script (ftp .php).

<form enctype="multipart/form-data" action="ftp.php" method=post>


<input name="userfile" type="file">
<input type="hidden" name="action" value="upload_file">
<input type="submit" value="Send" name="submit">
</font>
</form>

When using HTML as the front-end for a file upload system, the most direct means of letting the
Flash movie know that the file has been successfully uploaded is to reload the Flash. movie, and
pass in a parameter to let it know what event has taken place. Otherwise you must repetitively
make calls to the server to see if a new file has appeared in the directory, or prompt the user to
File Uploading 4

hit a refresh image-list button. (For more information about passing parameters into a Flash
movie, see Client-side communication later in the chapter)

Flash
With Flash as a front-end, it is far more difficult to trigger the file explorer. As of Flash MX, there
is still nothing inherent that allows it to directly open the file explorer. There are a few
workarounds that allow Flash to be perceived as if it was directly communicating with the file
explorer, although they are just that, workarounds. The most significant thing to try to avoid is
unnecessary Flash server communication.

We are going to look at one Flash solution that triggers


and receives data from the file explorer, without making
any trips to the server, as we create an Image Viewer.

FTP functions used to create Image Viewer


ftp_coimect (host,[, port]): opens up an FTP connection to the specified host. The
default port for FTP connections is port 21, although an alternative port may be utilized if
specified. ftp_connect () returns true on success and false on error.

ftp_delete (ftp_stream, path): deletes a file on the FTP server. ftp_delete ()


returns true on success and false on error.

ftp_login (ftp_stream, username, password): logs in an FTP connection.


ftp_login () returns true on success and false on error.
4 Advanced PHP for Flash

ftp_chdir (ftp_stream, directory): changes directories on an FTP server.


ftp_ chdir () returns t:rue on success and false on error.

W ftp_mkdir (ftp_stream, directory): creates a directory if it does not already exist in


the current location. ftp_ mkdir ( l returns the name of the new directory on success, and
returns false on error.

W ftp_put (ftp_stream, remote_file, local_file, mode): uploads a file to an FTP


server. It stores the local file on the FTP server as the remote file. The file transfer
mode can either be ftp_ASCII or ftp_binary. ftp_put () returns t:rue on success and
false on error.

W ftp_quit (ftp_stream): terminates the FTP connection.

ftp_rawlist ( ftp_stream, directory) : returns a detailed list of files in the given directory.
The results are returned as an array containing information such as the file's total bytes.

ftp_rename (ftp_stream, from, to): renames a file on the FTP server. ftp_rename ()
returns t:rue on success and false on error.

ftp_rmdir (ftp_stream, directory): removes a directory from the FTP server.


Ftp_rmdir () returns t:rue on success and false on error.

File types
Whenever you allow a user to upload files to your server, you are opening up your system to
attacks. For instance, if you allow a user to upload an . exe file to a PC server, and they know
what directory it is being uploaded to, they can trigger the . exe and do anything malicious that
they want- including wiping your entire machine.

Flash, however, can only utilize a finite list of the two primary file types: ASCII or binary.
Specifically, the Flash Player can only include the ASCII file types of HTML, XML, text, and name
and value pairs, and the binary types of . mp3, . jpg, and . swf. If you are creating a Flash
application, then there is little reason to allow a user to upload a potentially malicious file such
as an .exe. To control what a user can and can not upload, you need to check the MIME type
of the file, and then determine whether or not you will allow the upload to occur.
File Uploading 4

MIME types
MIME, or Multipurpose Internet Mail Extensions, is a standard for describing different types of
information. MIME was originally used to encode data into text, such that it could be sent
through email, but is used for any file conveyed across a MIME-based protocol, such as MIME,
e-mail, or HTIP. Knowing a file's MIME type helps tremendously when determining whether or
not to allow the file to be uploaded to your server.

The basic MIME types that exist are:

Application

Audio

Image

Message

Multi-part

Text

Video

Whenever you upload a file it is a good idea to check the MIME type against a list of file types
that you are allowing. Essentially, you need to cross-reference the extension of the file that the
user wishes to upload with the MIME types included in your system mime. types file. For
instance, if a user wishes to upload an . exe file, you can look up . exe in the mime. types file
and see that it is an application type I octet-stream. In this case the look-up would return an
undesirable file type- so you would not allow the transfer. For an example of how to implement
MIME type checks visit: http://www.inebria.com/mime_lookup/.

Ming
As mentioned, the Flash Player alone can only import the media types . jpg, . mp3, and . swf. A
. swf, however, can contain several additional sound, audio, and video file types. That being the
case, it is possible to dynamically load other file types into the Flash Player; they just need to be
wrapped in a . swf. This, fortunately, can be achieved using a tool called Ming- which is a C library
for dynamically generating . swf files. For more information about Ming refer to Chapter 8.
4 Advanced PHP for Flash

Note: To avoid having a user upload a malicious file to your server, check the MIME type
before allowing the file transfer. You can wrap other file types besides .jpg and .rrp3 in a
.swf, although it is not possible to wrap a malicious file in a .swf causing harm to a user's
machine. The Flash player must still read a file wrapped in an .swf, and is not capable of
executing or passing viruses or worms.

Hidden frames
To make Flash interact with the system's file explorer, without making several round trips to the
server, it is possible to use javaScript and a new feature of Flash MX known as localconnection.

Note: This method is only reliable for use on an intranet running


Windows IE 5.5, with Flash Player version 6.0 and greater. It is not
possible to simulate a click of the system Browse button in other
web browsers. An HTML file input field is the most universally
used system for uploading files on the web. This method is only
demonstrated to showcase the possibilities of the new Flash MX
feature local Connection () .

Hidden frames in HTML have long been a means of making events occur "behind the scenes".
In this case, we are using a hidden frame to transfer the name of the selected file within the file
explorer, to the open Flash movie. To make a hidden frame all you need to do is make a frame
that is at least 1 pixel in size, and not viewable to the user. In the case below, the third row in
the frameset is 1 pixel, and will hold the javaScript and . swf that can transfer the name of the
file to the open SWF movie. This frameset can be found in index.html.

<frameset rows="460,*, 1" border="O" framespacing="O"


frameborder="NO">
<frameset cols="*,305,*" border="O" framespacing="O"
frameborder="NO">
<frame src="empty.html" name="left" noresize scrolling="NO"
marginwidth="O" marginheight="O" frameborder="NO">
<frame src="imageViewer.html" name="indexl" noresize
File Uploading 4

scrolling="NO" frameborder="NO" marginwidth="O"


marginheight="O">
<frame src="empty.html" name="right" noresize scrolling="NO"
marginwidth="O" marginheight="O" frameborder="NO">
</frameset>
<frame src="empty.html" noresize scrolling="NO" marginwidth="O"
marginheight="O" frameborder="NO" name="bottom">
<frame src="empty.html" noresize scrolling="NO" marginwidth="O"
marginheight="O" frameborder="NO" name="hidden">
</frameset>
<noframes>

To see how this method of transferring client-side data into the SWF movie works, you can make
the third frameset row 50 pixels high in the HTML. Simply change the beginning of the first line
of index. html to:

frameset rows="460,5, 50"

The file index viewable. html


already has this in place, and is included
with the source files for this chapter.
Browse ...

Let's now look at filesend.html to see one example of how JavaScript can send data to a SWF
file. What filesend.html does first is to start a looping function when the page loads, with the
line of code: onLoad=" loopy () " in the frameset definition.

<FRAMESET COLS="S0%,50%" onLoad="loopy() ">


<FRAME NAME=LEFTFRM SRC=" j avascript: parent. Left() ">
<FRAME NAME=RIGHTFRM SRC= "j avascript: parent. RightBlank () ">
</FRAMESET>

The loopy ( l function checks to see if the user has selected a file using the file explorer. If they
have, then loopy () triggers the function passVars, which sends the string into a . swf movie,
and kills the timeout loop. If the user has yet to select a file, then loopy sets a timeout such that
it will call the function loopy again, 600 milliseconds later. The JavaScript function that allows
you to perform repetitive or delayed actions is setTimeout (code, interval);
4 Advanced PHP for Flash

function loopy() {
i f (LEFTFRM. document. all. FileNamel. value ! = "") {
passVars(escape(LEFTFRM.document.all.FileNamel.value));
II passVars sends the file value to the new .swf
window.clearTimeout(LEFTFRM.document.all.intval.value);
II clearTimeout stops the javaScript loop
else {
LEFTFRM.document.all.intval.value
window.setTimeout ("loopy() ", 600);
II setTimeout calls the function loopy()
II every 600 miliseconds.

The next function, RightBlank () , simply puts a blank HTML page into a second frame to act
as a placeholder for the . swf that will be loaded.

function RightBlank() {
return "<H'I'ML><IHTML>";

The function Left () , however, holds the HTML that is responsible for creating and triggering
the Browse button to explore the computer's local files. The form itself should look close to the
HTML at the beginning of the chapter, with the exception that it is being written out using
JavaScript, so all of the quote marks need to be escaped with a backslash.

function Left() {
II This function creates the "Browse" file button in the
II hidden frame
var strForm = "<html>\n<body
onLoad=\"document.all.FileNamel.click()\">\n<form name=\"forml\"
action=\"\" enctype=\"multipartlform-data\" method=\"post\">\n<input
name=\"FileNamel\" type=\"file\">\n<input name=\"intval\"
type=\"hidden\">\n<lform>\n<lbody>\n<lhtml>"
return strForm;
File Uploading 4

Client-side communication
With any online system there are two types of communication. You can either have your system
pass information around on the client side, or you can have information passed back and forth
to the server. It is always better to have information passed on the client-side, when possible,
because it is less taxing than passing information between two computers.

The last function, passVars (), is used to send the name of the file to a new . swf movie. By
writing out the object and embed tags that house aa . swf file, it is possible to dynamically load
pass variables into a . swf as it loads.

This method is useful not only with Flash as the front-end for File Transfers, but also for letting
the Flash file know that a file has been uploaded using HTML as the front-end for file transfers.
With an HTML front-end, it is still useful to use this method to communicate with the Flash file.
One means of telling your original Flash file that you have completed the file upload is to reload
the Flash movie and pass a variable in that confirms the event. The drawback is that you have to
reload the Flash movie, but the positive side is that you do not have to keep pinging the server
to see when the event has finished.

It is possible, in addition, to use built-in javaScript methods to change the value of a variable in the
Flash Movie to let it know that the file upload has taken place. For more information about JavaScript
methods for communicating with the Flash movie, see }avaScript methods for Flash objects, later in
the chapter.

The other methods of letting the Flash movie know that the file upload has taken place with an
HTML front-end are to have a "reload" button that the user selects to refresh the list of images
on the server, or to have Flash constantly send out a request to the server to see if any additional
files have been added to the directory. Both these methods, however, are less desirable then
automatically updating the Flash movie once the upload has taken place via javaScript.

function passVars(argstring) {
II this function writes the .swf file to the browser using
II JavaScript, so that variables and values can be passed
II in to the .swf
RIGHTFRM.document.write ("<HTML><BODY><OBJECT\n"
+ "CLASSID=clsid:D27CDB6E-AE6D-llcf-96B8-444553540000\n"
+ "WIDTH=lO\n"
4 Advanced PHP for Flash

+ "HEIGHT=lO\n"
+
"CODEBASE=http://download.macromedia.com/pub/shockwave/cabs/flash
/swflash.cab#version=6,0,0,0'>\n"
+ "<PARAM NAME=MOVIE VALUE=getfile.swf?file=" + argstring +
">\nn
+ "<PARAM NAME=PLAY VALUE=true>\n"
+ "<PARAM NAME=LOOP VALUE=false>\n"
+ "<PARAM NAME=QUALITY VALUE=high>\n"
+ "<PARAM NAME=MENU VALUE=false>\n"
+ "<EMBED\n"
+ " SRC=getfile.swf?file=" + argstring
+ "\n WIDTH=lO"
+ "\n HEIGHT=lO"
+ "\n PLAY=true"
+ "\n LOOP=false"
+"\n QUALITY=high"
+"\n MENU=false"
+ "\n TYPE=application/x-shockwave-flash"
+ "\n PLUGINSPAGE=http://www.macromedia.com/shockwave/download
/index.cgi?Pl_Prod_Version=ShockwaveFlash>"
+ "\n</EMBED>"
+ "\n</OBJECT></BODY></HTML>");
RIGHTFRM.document.close();

In this case, the name of our file to upload is stored by the variable argstring, which is
concatenated and passed as a variable and value pair to the . swf file with the line of code:

getfile.swf?file=" + argstring

The complete code of file filesend.html is outlined below:

<HTML>

<SCRIPT LANGUAGE="JavaScriptl.2">
function loader() {
File Uploading 4

MIME types
MIME, or Multipurpose Internet Mail Extensions, is a standard for describing different types of
information. MIME was originally used to encode data into text, such that it could be sent
through email, but is used for any file conveyed across a MIME-based protocol, such as MIME,
e-mail, or HTIP. Knowing a file's MIME type helps tremendously when determining whether or
not to allow the file to be uploaded to your server.

The basic MIME types that exist are:

Application

Audio

Image

Message

Multi-part

Text

Video

Whenever you upload a file it is a good idea to check the MIME type against a list of file types
that you are allowing. Essentially, you need to cross-reference the extension of the file that the
user wishes to upload with the MIME types included in your system mime. types file. For
instance, if a user wishes to upload an . exe file, you can look up . exe in the mime. types file
and see that it is an application type I octet-stream. In this case the look-up would return an
undesirable file type - so you would not allow the transfer. For an example of how to implement
MIME type checks visit: http://www.inebria.com/mime_lookup/.

Ming
As mentioned, the Flash Player alone can only import the media types . jpg, . mp3, and . swf. A
. swf, however, can contain several additional sound, audio, and video file types. That being the
case, it is possible to dynamically load other file types into the Flash Player; they just need to be
wrapped in a . swf. This, fortunately, can be achieved using a tool called Ming- which is a C library
for dynamically generating . swf files. For more information about Ming refer to Chapter 8.
4 Advanced PHP for Flash

+ "HEIGHT=lO\n"
+
"CODEBAS E=http://do wnload.mac romedia.com /pub/shockw ave/cabs/fla sh
/swflash.ca b#version= 6,0,0,0'>\n "
+ "<PARAM NAME=MOVIE VALUE=ge tfile.swf?fi le=" + argstring +
">\nn
+ "<PARAM NAME=PLAY VALUE=true>\n"
+ "<PARAM NAME=LOOP VALUE=fal se>\n"
+ "<PARAM NAME=QUALITY VALUE=high>\n"
+ "<PARAM NAME=MENU VALUE=fal se>\n"
+ "<EMBED\n"
+ " SRC=getfi le.swf?file =" + argstring
+ "\n WIDTH=lO"
+ "\n HEIGHT=lO"
+ "\n PLAY=true"
+ "\n LOOP=false "
+ "\n QUALITY=high"
+ "\n MENU=false"
+ "\n TYPE=app lication/x-s hockwave-f lash"
+ "\n PLUGINSPAGE=http://www .macromedi a.com/shock wave/downl oad
/index . cgi?Pl_Prod _Version=S hockwaveF lash>"
+ "\n</EMBED>"
+ "\n</OBJECT></BODY></HTML>");
RIGHTFRM .document.c lose();

</SCRIPT>

<FRAMESET COLS="S0%,50%" onLoad="lo opy() ">


<FRAME NAME=LEFTFRM SRC="java script:pare nt.Left()">
<FRAME NAME=RIGHTFRM SRC="java script:pare nt.RightBl ank()">
</FRAMESET>
<BODY bgcolor="#5 86C90">
</HTML>
File Uploading 4

javaScript methods for Flash objects


Another means of talking with Flash via javaScript is to use built-in methods that are supported
by the Flash plug-in and ActiveX control. To use these methods you must include an ID attribute
in the <object> tag and a NAME attribute in the <embed> tag for it to be cross-browser. These
methods allow you to perform many of Flash 's built in actions such as Back () ,
CUrrentFrame(), Drag( ) , Forward(), GetVariable(), GotoFrame() , LoadMovie ( ) ,
Pan () , PercentLoaded () , Play () , Rewind () , StopPlay () , SetVari able () , and Zoom () .

It is possible, in addition, to use these methods to pass information into the Flash movie. You can
use the setVariable ( "variableName", "value" ) method to change a value inside of the
Flash movie. For instance, if you wanted to tell the Flash movie that a new file has been successfully
loaded with an HTML front-end, you could trigger setvariable ( "uploadSuccessful",
"true") and have a loop continue in the flash movie, until the uploadSuccessful == "true" .
Then you could update the list of image files within Flash.

Although javaScript methods are not heavily used, due to the fact they double up on many of
Flash's built-in functions, they do represent another means of passing data in to the Flash movie
during runtime. This method would also allow you to send data without having to reload your
Flash movie, as described in the Client-side communication section.

LocalConnection
A new feature of Flash MX is the ability for . swf files to send data back and forth as long as they
are both present on the same HTML page, or opened at the same time on the user's computer.

This first bit of code is the only code present in the movie getfile. swf. Essentially what
happens is the filename selected to upload is sent into get file . swf by concatenating the
argument string to the . swf file name as it is loaded. Then, using local connection, the file
name is passed to our main movie, imageViewer. swf.

lc = new LocalConnection();
lc.send("imageViewer", "getFilename", file);
delete lc;
stop();
4 Advanced PHP for Flash

This next bit of code is present in the movie imageViewer. swf. This movie also creates a new
LocalConnection and creates a function getFilename that receives the name of the file to
be uploaded and sets a local variable, file, to that value.

II make local connection for file upload


lc = new LocalConnection();
lc.getFilename = function(name) {
file = name;
};
lc.connect("imageViewer");

This method of passing an argument string into a . swf when loaded, and then passing that value
into a . swf movie already present using Local Connection is a handy means of getting
javaScript to talk to a Flash movie during runtime. This is a cross-browser method, and keeps
communication on the client-side, so that the Flash movie does not need to make round trip
connections to the server via loadVariables () and a middle-ware script such as PHP.

The reason that this overall method of getting a file name into a . swf movie is not cross-
browser, is that it is not possible to trigger the click of the Browse button in any web browser
except Microsoft Internet Explorer. Another means of javaScript I Flash communication is that
of the FSCommand. It is still not capable of simulating a click of the Browse button, and is not
cross-platform like the method using the argument string and LocalConnection.

FSCommands
The FS commands have been present since the infancy of Flash, when it was called Future Splash.
FS commands are used to communicate with the browser using Netscape's LiveConnect
technology and Microsoft's ActiveX technology. It is also possible to send data back and forth
between Flash and the browser using FS commands, although it is becoming less and less
supported, and is not a cross-browser solution.

Note: FS commands do not work on Netscape version 6.0 and above and Internet Explorer for
Macs, because Netscape excluded LiveConnect in the newer versions of the browser, and the
Active X technology is not supported on Macs. FS commands have also always been very helpful
with stand-alone applications that play locally on a user's computer and not within a browser.
You can use FSCommands to make your stand-alone application full screen, execute other
applications, trap all keystrokes, and quit. These features, however, are not useful for uploading
and manipulating files and directories on a remote server.
File Uploading 4

Shared Object
Flash MX has included one additional feature that allows a Flash movie to store information on
a user's computer; it's known as a Shared Object. The Shared Object has been referred to as the
"super cookie" because it stores data much like a cookie, but does so independent of a browser.
What this means is that a Flash movie could store and access data that is common to any
browser, and even to a stand-alone application.

Shared Objects are not particularly useful for uploading files, but are tremendously useful for
application development. To create a Shared Object you simply need to set an object inside your
Flash movie as such:

_root.sobj = SharedObject.getLocal("mySharedObject");

Where _root. sobj is the name of the object within your Flash movie, and "mySharedObj ect"
is the name of the object information stored locally on the user's machine. You can retrieve any
number of variables from the stored information as follows:

userName = _root.sobj.data.name;

You can store any amount of information in these objects by first setting the variables, and then
writing the information to the user's computer with the flush () method, like so:

_root.sobj.data.name = "mindgrub";
_root.sobj.flush();

The Image Viewer


The code that is present in the Flash movie
ImageViewer. swf receives the list of images from the
server, displays that list in a listbox component, displays
the image when the image name is selected from the list,
and allows the user to upload new images to the server.
4 Advanced PHP for Flash

Creating an lmageViewer with Flash

1. To create imageViewer. swf, start by opening a new Flash movie, and create a new movie
clip called imageViewer. Edit the movie clip and add seven new layers to have seven in
total. Label the layers: actions, buttons, error messages, file field, shell, listBox, image, and
bk.

2. Create a graphic for the shell of your image viewer on the shell layer. Next, drag an
instance of the listBox component out of the components panel on to the listBox layer,
and give it an instance name of irnageList. Now, add a blank movie clip to the image
layer, line it up with the inside top-left corner of the viewer's shell, and give it an instance
name of irnageHolder.
File Uploading 4

3. Next, add a background and dynamic text field to the file field layer, and give the text field
a variable name of file. Then, add a second text field over the top of the first text field
in the error messages layer and give it a variable name of message.

4. Lastly, add any graphics you want displayed when an image is not visible in the
imageHolder movie clip, to the bk layer.

We are going to hold off creating the buttons until we have fully digested the code that needs
to be placed on this timeline. So without further ado, click on the actions layer, open the Actions
panel, and start typing.

Adding the code to lmageViewer


This first function, setStyleFormat (), is used to set the global appearances of Flash's built-in
components. For the lmageViewer we use two components, the listbox and scrollbar. To get
these components to match the look and feel of the rest of the viewer, the following color
settings are used:

function setStyleFormat()
II This function sets all of the color and text properties for
II Flash's built in components used in the image viewer
globalStyleFormat.textFont = "_sans";
globalStyleFormat.textSize = 12;
globalStyleFormat.textColor = OxOOOOOO;
globalStyleFormat.background = Ox88894BO;
globalStyleFormat .backgroundDisabled = OxCOCOCO;
4 Advanced PHP for Flash

globalStyleFormat.selection = Ox010EA3;
globalStyleFormat.selectionDisabled = OxCOCOCO;
globalStyleFormat.selectionUnfocused = Ox88894BO;
II
globalStyleFormat.arrow = OxFFFFFF;
globalStyleFormat.face = Ox7080AO;
globalStyleFormat.shadow = OxOOOOOO;
globalStyleFormat.darkshadow = Ox373F59;
globalStyleFormat.highlight = OxFFFFFF;
globalStyleFormat.highlight3D = OxA8BOC8;
globalStyleFormat.foregroundDisabled = Ox7080AO;
globalStyleForrnat.scrollTrack = Ox7080AO;
II
globalStyleFormat.applyChanges();

The clearResponse () function is used to clear the last message from the message field.

Before clearResponse () is called, a variable, startTime, is set to the current system time
using getTimer () . Then this. onEnterframe is set equal to clearResponse () such that
clearResponse () will continue to loop.

function clearResponse() {
if (getTimer()>(startTime+2000})
message = 11 11 ;
delete this . onEnterFrame;

When the current time is greater than the startTime plus two seconds (getTimer () >
(startTime+2000)), clearResponse () clears the message out of the message text field, and
deletes the this. onEnterframe loop. This method of clearing a response after a set amount
File Uploading 4

of time is useful for any application that requires feedback, such as chat applications, form input
fields, etc.

The displayList () function is used to add the image names and file sizes from the server to
the listbox component. When the names and sizes are returned from the server they are sent as
variable value pairs in the form of:

assetName_ O=Eder-Oberstein. jpg&assetSize_ 0=59279&assetname_1= ...''

displayList () processes these names by looping until the next variable in sequence is not
equal to null. When that occurs, it knows that it has processed all of the images, and terminates
the loop. The displayList () function also pushes the names and file sizes into two arrays,
images and sizes, so that the image name alone can be grabbed when the user has selected an
image to view. These values can also be stored in the data field of the listbox component, but it
is slightly quicker to store them separately in two arrays.

function displayList() {
var t = 0;
images= new Array();
sizes= new Array();
while (this ["assetName_"+t] != null) {
images.push(this["assetName_"+t]);
sizes.push(this["assetSize_"+t]);
imageList.additem(this["assetName_"+t]+"
("+this["assetSize_"+t]+" bytes)");
t++;

getimageList () sends a query to the server via the ftp.php file, requesting the list of images
on the server. On the end of the URL is this string:

"action=list&username="+dir

This tells ftp. php that the Flash movie is requesting the list of images and file sizes, which are
processed by the function displayList () later. This function also sets the aErr = null, which
is the feedback variable from the server, and adds a message to the user in the message text field.
4 Advanced PHP for Flash

function getimageList(dir) {
loadVariables("ftp.php?action=list&username="+dir , "");
aErr = null;
message = "loading image List" ;
startTime = getTimer();
this.onEnterFrame = ftpResults;

Users
In this example the directory variable is called username as a placeholder to allow several
different users to store their own list of images, and to only have access to those images. The
value of username is set to imgs, which is the name of the folder that holds all of the image
files used by the Image Viewer.

Note: To implement different users of the Viewer, all you need to


do is to store usernames and passwords in a database, and simply
have the user login when they start the application, and store
their login name as username .

The PHP code in this example will create and access folders based on the value of username -
which gets passed into the PHP file as dir for directory. When the request is sent to the server,
the value of dir, shown above, is unique for each user, and only their folders are accessed. You
should, in addition, set up a database. to store usernames and passwords to validate the login.

In setting up the folder access in this fashion, you only need to create one FTP account on the
server, and all user-specific files are stored in a corresponding folder, as opposed to individual
FTP access locations. This is a far easier method for allowing different users to use a Flash
application than assigning individual FTP usernames and passwords per individual. Since the FTP
information is stored in the PHP file, it would be difficult for an individual to determine where
the files are stored, and to attempt to access other individuals' files.
File Uploading 4

The checkLoading () function is triggered every time a new image is loaded from the server. This
function simply looks at the bytes currently loaded, and the total bytes for the image to determine
if it should display the percent loaded, or terminate the loop when the image has fully loaded.

function checkLoading()
i f (loop++>=2) {
var per =
int((imageHolder.getBytesLoaded()/imageHolder.getBytesTotal())*lOO);
i f (per>=lOO) {
message= "";
this.onEnterFrame = null;
else {
message "loading image "+per+"%";

Note: checkLoading ( ) does not begin to check how many bytes


have loaded until it has looped at least twice (loop++>=2). This
gives Flash two frames to complete the request to the server using
the loadMovie () function, so that an accurate byte count can
be monitored.

displayimage () is called by the function onChange () when the user selects an image from
the listbox to view. It simply makes a request to the server using the loadMovie command, and
then triggers checkLoading () using the this. onEnterFrame event handler.

function displayimage(num) {
loadMovie(username+"/"+images[num], imageHolder);
loop = null;
this.onEnterFrame = checkLoading;
4 Advanced PHP for Flash

The onChange () function is the default function name that is triggered by the listbox
component when a user selects an image to view. onChange () then makes the "are you sure
you want to delete this image" question box disappear if it is visible, and triggers
display!mage () .

function onChange(imageList)
file = "";
quesBox.gotoAndStop(l);
displayimage(imageList.g etSelectedindex());

deleteimage () makes a request to the server to delete an image. This time, as opposed to
getimageList () , the action equals delete, and the filename to delete is included in the URL string.

function delete!mage(num, dir) {


loadVariables("ftp.php?act ion=delete&username="+d ir+"&delfile="+image
s[num), "");
startTime = getTimer();
deleteNum = num;
this.onEnterFrame = ftpResults;

The areYouSure () function is triggered immediately after an image has been selected from the
listbox, and the user clicks the DELETE button. It is always important to question the user before
deleting anything, just to make sure it wasn't an accidental selection. The function simply makes
the question box visible, by having it go to and stop on the second frame, and includes the name
of the file to delete.

function areYouSure(n) {
quesBox.gotoAndStop(2);
txt = "Are you sure you want to delete image "+images[n)+"?";
quesBox.sure = txt;
yes = false;
no = false;
File Uploading 4

waitForUpload () is called when a user has browsed for a file to upload, and then hits the ADD
button. The function then sets the onEnterFrame handler equal to ftpResults (), which
displays whether the upload was successful or not.

Note: The best-case scenario for determining whether or not a file


has been successfully uploaded is to have the request to upload
come from the Flash file, and have the PHP script return true or
false based on the response from the ftp_put function . In this
manner there is only one round trip call to the server. Even if you
go with the HTML form field to gather the file that the user wishes
to upload, it is still better to pass that value into Flash and have
Flash make the request, or send the results into Flash using
localConnection, as opposed to Flash continuously pinging
the server to see if it has occurred or not.

function waitForUpload() {
startTime = getTimer();
aErr = null;
this.onEnterFrame=ftpResults;
4 Advanced PHP for Flash

Feedback
Feedback is important when it comes to any web-based interaction, but especially significant
when it comes to front-end and server communication. The ftp. php file always sends a value for
aErr when a request has been made. The values that it returns are simply integers between 1 and
8, but the ftpResults () function knows the significance of each value and acts accordingly.

Before any request is made to the server, the value of aErr is set to null. Then, when aErr is
no longer null, ftpResults knows that the file ftp.php has finished its business. The function
also checks to see how tong the request has been taking place, and times-out if it takes any
longer than four seconds. The possibility exists that the server or file could jam while making the
request, and if left to spin, the Flash player would throw up an Alert Box.

The most significant two of the responses from the server are aErr=6 and aErr=7. When the
value equals 6, a file has been successfully added to the server, and the arrays and listBox are
updated by adding the new filename. When the value equals 7, the file has been successfully
deleted and the arrays and listBox are updated, eliminating the filename.

function ftpResults() {
num = deleteNum;
if (getTimer()>(startTime+4000))
message = "ftp actions timed out";
startTime = getTimer();
this.onEnterFrame = clearResponse;

else if (aErr != null)


switch (aErr)
case "0" :
II A value of aERR = "0" is return when list of files
II successfully returned from ftp.php.
message = "directory list obtained";
displayList();
break;
case "1" :
II A value of aERR = "1" is return when the directory
II is empty or there was a problem reading the directoy.
message= "directory empty or not readable";
File Uploading 4

break;
case "2" :
II aERR = "2" if the directory could not be entered.
II Check FTP priveleges for this directory.
message = "could not enter directory";
break;
case "3" :
I I aERR = "3" i f the FTP connection failed. Check to make
II sure that connection to the server has not been lost
message = "connection failed";
break;
case "4" :
II aERR = "4" if a temporary file could not be created
II in the current directory. Consult a network admin to
II find where a temp file can be created on the server.
message "unable to make temp file";
break;
case "5" :
II aERR = "5" i f ftp.php could not log in to the FTP
II server with the given username and password. Username
II and password are stored at the top of ftp.php.
message = "could not log in";
break;
case "6" :
II aERR = "6" is the directory could not be
II entered. Check FTP priveleges for this directory
imagesList.additem(newFile+" ("+newSize+" bytes)");
images.push(newFile);
sizes.push(newSize);
message= "upload successful";
break;
case "7" :
II aERR = "7" when file successfully deleted from server
II item deleted successfully from server
imageList.removeitemAt(num);
unloadMovie(imageHolder);
images.splice(num, 1);
4 Advanced PHP for Flash

sizes.splice(num, 1);
message= "delete successfull";
displayimage(imageList.getSelectedindex());
break;
case "8" :
I I aERR = "8" when file successfully added to server
message "unable to delete file";
break;
default :
break;

file="";
startTime = getTimer();
this.onEnterFrame = clearResponse;

The function selected() is called by all of the onRelease actions within the Browse, Add, and
Delete buttons. Selected () used a case statement similarly to ftpResults (). In this case, the
instance name of the button is passed into selected (), and selected () either calls
filesend.html to pop the Browse button, or calls ftp.php to add a new image. If the Delete
button has been pressed, then selected () opens the "Are you sure" popup to make sure the
user truly wants to delete the file before doing so. If the answer is yes, then the function
delete Image () is called.

function selected(n)
switch (n) {
case "BROWSE"
II opens filesend.html into the hidden frame to pop the
II "Browse" button.
getURL("filesend.html", "hidden");
break;
case "ADD" :
i f (file != "") {
II sends the value of action=upload, the name of the user
II and the name of the file to upload to ftp.php
loadVariables("ftp.php?action=upload&username="+username+"&userfile="
File Uploading 4

+file, "" "POST");


this.onEnterFrame waitForUpload;
} else {
II remind the user to enter a file name to upload first
message= "browse for file or enter path";
startTime = getTimer();
this.onEnterFrame = clearResponse;

break;
case "DELETE"
file= "";
var img = imageList.getSelectedindex();
if (img != undefined)
II i f there is an image in the file textfield then the "are
II you sure" popup window is launched to make sure that the
II user truly wanted to delete the file.
areYouSure (img);
this.onEnterFrame function()
II this handles the reponse from the "are you sure"
I I popup window.
i f (yes) {
delete!mage(img, username);
else i f (no) {
this.onEnterFrame null;

};
else
II if there is no image to delete in the file text field
II then the user is prompted to select a file first.
message "select image to delete";
startTime = getTimer();
this.onEnterFrame = clearResponse;

default
break;
4 Advanced PHP for Flash

Finally, when the Flash movie first loads, after creating the localConnection and storing the
functions to memory, the setStyleFormat () function is called. The username is defaulted to
irrgs, and getimageList () is triggered.

setStyleFormat();
II for individual folders, have login, and grab login name
username = "irrgs";
getimageList(username);
stop();

Adding buttons to the lmageViewer

The final symbols on this Flash front-end are the buttons, and message box.

1. Start by adding a graphic to the Image Viewer for one of the buttons- we are going to
reuse the same button.

2. Now, turn the graphic into a movie clip and label it


'button'. Edit the button, add two additional layers. and
name the three layers actions, text, and bk. Then, add
an image in the bk layer that will represent the up state.

3. In the text layer add a dynamic text field and give it a variable name of 'name'. (We are
going to dynamically populate this text field based on the instance name of the movie
clip.) Add two more keyframes and change the color of the text field and background to
represent the over state (frame 2) and the hit state (frame 3).

4. Now, add the following code on the actions layer to frame 1, and add stop () ; actions to
frames 2 and 3.

this.onPress = function()
this.gotoAndStop(3);
} i

this.onRollOver = function()
this.gotoAndStop(2);
File Uploading 4

} i

this . onRollOut = function()


this.gotoAndStop(l);
} i
this.onRelease = function()
this.gotoAndStop(2);
_parent.selected(this._na me);
} i

this.onReleaseOutside = function()
this.gotoAndStop(l);
}i
name = this._name;
stop();

This button utilizes the new button event handlers for Flash MX. The only potential
mystery to the button is how does Flash knows how to differentiate between the three
buttons. Well, the function literal for the onRelease handler passes the instance name of
the button to the selected () function that sits on the _parent timeline. That function
has a case statement that performs according to the parameter passed in. An abbreviated
version of that exists with the pop-up box, described next.

5. Finally, go back to the timeline of the Image Viewer. and add two more instances of the button
to the viewer. Give the buttons instance names of BROWSE, ADD, and DELETE accordingly.

Creating the pop-up box

1. To create the pop-up box, start by making a graphic


for the shape of the box, add a dynamic text field
labeled 'txt', drag two instances of the button movie
clip out of the library, and give them instance names
of YES and NO accordingly.

2. Then, select everything you have just added and turn it into a movie clip named popup.
4 Advanced PHP for Flash

3. Next, add a second keyframe and move the graphics for that keyframe. In doing this, you
will essentially toggle the popup movie clip between the two frames to make it visible, or
not visible. Add a stop action to the second frame and the following code to the first frame:

function selected(name)
switch (name) {
case "YES" :
_parent.yes true;
break;
case "NO" :
_parent.no true;
break;
default :
break;

this.gotoAndStop (l);

stop();

Since the buttons already trigger to the parent movie clip where they are contained, this
selected () simply needs to perform based on whether or not the user selected YES or NO. A
variable is sent to the main timeline of the Image Viewer movie clip to tell it to delete the file,
or not.

FTP access
The most significant piece to any uploading or deleting of files on a server is having the
permission to do so. This essentially requires that an FTP server be installed and configured
correctly, and that the user has permission to add and delete files. Consult your network
administrator to make sure this ability is in place. If you own your own server and wish to install
your own FTP server, there are many free FTP servers available. You can download several from
www.downloads.com; simply type "FTP server" in the search field. Follow documentation for the
particular server to set up users and passwords.
File Uploading 4

Using PHP for the back-end


Finally, the back-end! To create the file ftp .php, open up your favorite text editor, or an editor
with PHP syntax highlighting such as editPlus, add the following code, and save the file as
ftp.php.

The first significant piece of the PHP file is to establish the global variables used in conjunction
with the FTP server. The most important of these are the phpftp_user and the
phpftp_passwd. These variables are settings of the FTP server that give the user permission to
add and delete files. The other variables are used as follows: phpftp_ dir is set to the
$username variable, which is passed in from the Flash front-end. The functions will manipulate
files in a directory of the same name, which gives you the ability to have only one FTP username
and password, but allows you to have multiple users, each with a unique folder. phpfp_file is
set to the $delfile variable, which is the name of the file to delete, which gets passed in from
the Flash front-end.

<?php
$phpftp_host="localhost";
II If the FTP server you wish to connect to is not located on the
II same server then you must enter the full path to that FTP
II location. This should not be the case for the file used with the
II imageViewer.
$phpftp_version="2.1";
$phpftp_user = "chili-ftp";
II This is the username esstablished on the FTP server that allows
II FTP privileges to the folder containing the image viewer.
$phpftp_passwd = "secret";
II This is the password for the username above.
$phpftp_dir = $username;
II This is the name of the directory where the image files will be
II stored. This name is passed into this file from the Flash Movie
II as $username. If login functionality is added to the Flash
II movie,then this name will be different for all viewers, and will
II store their image files in separate directories. Note: all users
II still utilize the same FTP username and password.
$phpftp_file = $delfile;
II This is the name of the file to delete, passed in from the Flash
I I Movie.
4 Advanced PHP for Flash

The phpftp_connect () function is used by both of the other functions to establish a


connection to the FTP server before any other actions take place. This function uses two built-
in functions, ftp_connect and ftp_login, to establish a connection and returns true if the
connection is achieved.

function phpftp_connect($phpftp_user,$phpftp_passwd)
II This function connects to your FTP server using the username and
II password set at the top of this file. All users of the
II imageViwer share the same FTP settings, but can store their files
II in separate directories based on the value of username.
II (subfolders have the same FTP privileges as their parent folder.)
global $phpftp_host;
$ftp = ftp_connect($phpftp_host);
II $ftp is set equal to true or false depending on whether or
II not the ftp connection was successful
i f ($ftp) {
II if the ftp connection was successful then the following
II statement attempts to login to the FTP server with the
II given username and password, returning true if
II successful.
if (ftp_login($ftp,$phpftp_user,urldecode($phpftp_passwd)))

return $ftp;

phpftp_upload() first attempts to connect to the FTP server using phpftp_connect(). The
function attempts to make a temporary file, using a randomly generated naming convention,
before transferring the file to the correct directory. This is a good check to make sure that the
file is capable of being read and transferred, but will stop the upload dead in its tracks if the
permissions are not set correctly on the FTP server. Make sure that the user has permission to
write to the server. and change the line tmpfile=$userfile_name. 11 11 $randval, to reflect
a path that will give the user access to create a temporary file.

Finally, if the function was able to successfully create a temporary file, and log in to the FTP
server, then it initiates writing the file to the server. First, if required, it changes to the specified
File Uploading 4

directory (in this case the directory name is imgs). It writes the temporary file to the server using
ftp_put () and finally it terminates the FTP connection using ftp_quit ().

function
phpftp_upload($phpftp_user,$phpftp_passwd,$phpft p_dir,$userfile,
$userfile_name) {
$ftp = phpftp_connect($phpftp_user,$phpftp_passwd);
II This makes sure that the function can establish a connection
II to the FTP server using the given username and password.
srand((double)microtime()*lOOOOOO);
$randval =rand();
$tmpfile=$userfile_name . 11 11 $randval;
if (!copy($userfile,$tmpfile)) {
II unable to make temp fileA temp file is first created
II before transfering the file to the server. You might need
II to change the location of this temp file such as
II $tmpfile="l".$userfile_name 11 11 $randval;
echo 11 &aErr=4& 11 ;
else
if (!$ftp = phpftp_connect($phpftp_user,$phpftp_passwd))
unlink($tmpfile);
II could not log in
echo 11 &aErr=5& 11 ;
else {
ftp_chdir($ftp,$phpftp_dir);
II in this case ftp_chdir changes to the username
II folder passed in from the Flash Movie. In this
II case that folder is the "imgs" folder.
ftp_put($ftp,$userfile_name,$tmpfile,FTP_BINARY);
II ftp_put uploads the file to the server.
ftp_quit($ftp);
unlink($tmpfile);
II sucessful upload
echo 11 &aErr=6&newFile= 11 .$userfile_name;
4 Advanced PHP for Flash

The phpftp_delete () function works in a similar fashion to phpftp_put () , in that it first


checks to see that the user can connect to the FTP server using their username and password,
and then it changes directories using ftp_chdir() (in this case it switches to the imgs folder).
Next, it deletes the file (returning aErr = 7 if successful and aErr = s if an error occurs), and
finally closes the FTP connection using ftp_quit ().

function phpftp_delete($phpftp_user,$phpftp_passwd,$phpftp_dir,
$phpftp file) {
global $phpftp_host;
$ftp = phpftp_connect($phpftp_user,$phpftp_passwd);
II This makes sure that the function can establish a connection to
II the FTP server using the given username and password.
i f (!$ftp) {
II ftp connection failed
echo "&aErr=3&";
else
i f (! $phpftp_dir)
$phpftp_dir=ftp_pwd($ftp);

if (!ftp_chdir($ftp,$phpftp_dir))
II can't enter that directory
echo "&aErr=2&";
$phpftp_dir=ftp_pwd($ftp);

if(ftp_delete ($ftp, $phpftp_file))


II file deletion successfull
echo "&aErr=7&";
else {
II file deletion unsuccessfull
echo "&aErr=S&";

ftp_quit ($ftp) i
File Uploading 4

phpftp_list () begins in the same way as all of the preceding functions, but then takes a
drastic deviation. When the function sets $contents = ftp_rawlist ().it creates an array of
all the file information in that directory. This function is currently more robust than we need to
simply see how many . jpg images are in the imgs directory, but the function accounts for all
of the possibilities within a given directory. The potential items in any given directory are: other
directories, symbolic links to other files, files, or in the case of an anonymous FTP server, other
files or directories.

After determining all of the contents of the current directory, the function sorts the contents
and places their names and file sizes in different arrays. Then, since we are only concerned with
files in the given directory, the function increments through the file array, nlist_files, and file
size array, nlist_filesize, and echoes those values back to Flash via variable and value pairs,
like so:

"&assetName_".$i."=".$n list_files[$i] ."&assetSize_".$i."=".$n list_fil


esize[$i];

After successfully sending, or not sending, the file names and sizes, the function sends back the
corresponding values of aErr, so the Flash front-end knows what has occurred on the back-end,
and then quits the FTP connection.

function phpftp_list($phpftp_user,$ phpftp_passwd,$phpftp_di r)


global $phpftp_host;
$ftp = phpftp_connect($phpftp_ user,$phpftp_passwd);
//This makes sure that the function can establish a connection to
// the FTP server using the given username and password.
i f ( !$ftp) {
//connection failed
echo "&aErr=3&";
else
if (!$phpftp_dir)
$phpftp_dir=ftp_pwd($ftp) ;

if (!ftp_chdir($ftp,$phpftp _dir))
II can not enter that directory
echo "&aErr=2&";
$phpftp_dir=ftp_pwd($ftp) ;
4 Advanced PHP for Flash

i f ($phpftp_dir == "I")
$phpftp_ dir= II II j

i f ($contents= ftp_rawlist($ftp 1"")) {


II ftp_rawlist returns the information about each file and
II directory as an array.
$d_i=O;
$f_i=O;
$l_i=O;
$i=O;
while ($contents[$i])
II This loops through each of the items found
II in the particular directory
$item[]= split("[ ]+" 1$contents[$i],9);
$item_type=substr ($item [$i] [O] 0 1);
I I

II $item_type returns either "d"1 "1" 1 "-"~


II "+ 11 1 or "I"~ and the following if-else
II statement repsponds accordingly.
if ($item type == "d") {
li it's a directory
$nlist_dirs [$d_i] =$item[$i] [8];
II adds the name of the directory to the
II directory ar ray.
$d_i++;
elseif ($item type == "l") {
II it's a symlink
$nlist_links[$l_il=$item[$i] [8];
II adds the link to the link array.
$l_i++;
elseif ($item_type == "-")
II it's a file
$nlist_files [$f_i] =$item [$il [8] ;
$nlist_filesize [$f_i] =$item[$i] [4] ;
II adds the file name and file size to the
II filename and filesize arrays.
File Uploading 4

$f_i++;
elseif ($item_type == "+") {
II it's something on an anonftp server
$eplf=split(",",implode(" ",$item[$i]),5);
if ($eplf[2] == "r") {
II it's a file
$nlist_files[$f_i]=trim($eplf[4]);
II adds the file name to the filename
II array.
$nlist_filesize[$f_i]=substr($eplf[3] ,1);
II adds the file size to the filesize
II array.
$f_i++;
elseif ($eplf[2] =="I") {
II it's a directory
$nlist_dirs[$d_i]=trim($eplf[3]);
II adds the directory to the
II directory array.
$d_i++;

II ignore everything else


$i++;

if (count($nlist_files)>O) {
for ($i=O; $i < count($nlist_files); $i++) {
echo "&assetName_". $i. "=". $nlist_files [$i] .
"&assetSize_".$i."=".$nlist_filesize[$i];
II Sends the list of files in the directory
II to the Flash Movie

echo "&aErr=O&";

else
II directory empty or not readable
echo "&aErr=l&";
4 Advanced PHP for Flash

$cdup=dirname($phpftp_dir);
i f ($cdup == "") {
$cdup="l";

ftp_quit ($ftp);

As with the case statements in the Flash front-end, the following lines of code determine what
functions need to be triggered based on the value of action sent in from Flash:

II CALL THE REQUIRED FUNCTIONS


switch ($action) {
case "upload":
phpftp_upload($phpftp_user,$phpftp_passwd,$phpftp_dir,
$userfile,$userfile_name);
break;
case "list":
phpftp_list($phpftp_user,$phpftp_passwd,$phpftp_dir);
break;
case "delete":
phpftp_delete($phpftp_user,$phpftp_passwd,$phpftp_dir,
$phpftp_file);
break;
default:
break;

?>

Summary
With the new dynamic image and sound loading capabilities of Flash MX, there has been an
explosion in the number of gallery and jukebox sections on websites. To keep the content of
these applications fresh and democratic, many individuals have implemented, and will continue
to implement, FTP upload capabilities so that users can contribute to the content of the site, and
have their own locations to post and delete files.
Advanced
MySQL
What we'll cover in this chapter:
D
Creating and using indexes

joins, including Inner, Outer, and Self joins

Searching MySQL using LIKE and REGEXP, and full-text searching

Using the date and time functions

Building a searchable cookbook with recipes and photos

[0

EB
s Advanced PHP for Flash

One of the great things about the SQL language is that its relatively simple syntax makes it easy
to start working on real-world applications right away. A passing knowledge of CREATE, INSERT,
UPDATE, SELECT, and DROP is all that you really need to build a successful database-driven
application. But the SQL language and in particular MySQL's dialect has more depth than the
beginning SQL programmer may realize. By understanding some of the more advanced subtleties
and nuances of MySQL you can improve your application's performance and capabilities and at
the same time shorten your own development time.

This chapter assumes you are already familiar with most of the topics in Foundation PHP for Flash
and introduces more advanced topics such as: indexes, joins, date manipulation, and searching.
We are going to work with quite a few examples in the MySQL monitor and then we'll finish this
chapter by building a searchable cookbook.

Indexes
Indexes make finding values for a particular table column a lot faster. MySQL implements indexes
with a data structure known as a B-tree, which allows MySQL to find a particular value without
iterating across the entire table. Creating good indexes for tables is essential for fast queries.

Creating bad indexes can actually make the access time to your database worse. It takes disk
space and server time to maintain indexes. Indexing everything in all of your tables in the hope
that it will improve the speed of your application will create a lot of space and performance
overhead that will continue to grow as your database grows.

MySQL utilizes indexes in WHERE clauses that match particular rows, table joins, the MAX () and
MIN() functions, and in some cases sorting and grouping. Therefore one should craft the table
indexes with this in mind.

The syntax for creating indexes after the column definitions of a table is:

INDEX [index_name] (columnl, ... )


Advanced MySQL s

The index_name is optional but if no name is given, MySQL will automatically assign a name to the
index. Indexes may span one or more columns and are indexed left to right as this example illustrates:

CREATE TABLE xref (


idl INT UNSIGNED,
id2 INT UNSIGNED,
INDEX xref index (idl, id2)
);

Here a search for values that matched idl and id2 would utilize xref index as well as a search
for values that match only idl. However, a search for values based just on id2 would not use
xref_index because idl is to the left of id2 in the index definition. Index order is important
as the indexes are represented internally in MySQL as B-trees.

In MySQL, KEY is a synonym for INDEX. A special kind of key that you may already be familiar
with is the Primary Key. The primary key is a unique index whose values may not be NULL. Only
one primary key can be defined per table. Like any other index, the primary key index can be
defined after the column declarations:

CREATE TABLE recipes (


id INT UNSIGNED AUTO_INCREMENT,
name TEXT,
PRIMARY KEY ( id)
);

or you can declare a particular column as the primary key in its column definition:

CREATE TABLE recipes (


id INT UNSIGNED AUTO INCREMENT PRIMARY KEY,
name TEXT
);

It is often useful to have a unique number to specifically identify a record; this can be
accomplished by creating a primary key column with the AUTO_ INCREMENT attribute. Each time
we insert data into the above database, id will have a new unique integer value. In PHP we can
retrieve this value from the most recently inserted record with the function
mysql_insert_id().
s Advanced PHP for Flash

joins

Inner joins
The basic idea behind relational databases is that different tables store different kinds of
information and these separate tables can be linked by relationships that we define. One of the
most important tools in exploiting these relationships is the join.

Let's consider an online cookbook. In this particular cookbook, we would like to maintain a name
for each recipe and a category that each recipe belongs to. If we kept all of this information in
a single table there would be an enormous amount of redundant data.

recipe_id category_name recipe_name


1 Chocolate Chocolate Chip Cookies
2 Cookies Sugar Cookies
3 Cakes Lemon Cake
4 Cakes Chocolate Cake

In the previous table, we see that the "Cakes" category name appears twice in the listing. If our
cookbook grows this could add up to a lot of wasted space. This redundancy can also make it
difficult to maintain. For example, if a category name changed we would have to change every
record that uses that category name. In general it's good to avoid redundancy when designing a
database. The process of removing redundancies like this from a database is called normalization.
We can remove the category name redundancy in the previous table by creating two tables:

category_id category_name
1 Cookies
2 Cakes
3 Chocolate

recipe_ id category_name recipe_name


1 3 Chocolate Chip Cookies
2 1 Sugar Cookies
3 2 Lemon Cake
4 2 Chocolate Cake
Advanced MySQL s

This data model reduces the amount of redundant category information but we can no longer use
a single query on a single table to obtain both the recipe name and category name. Without some
mechanism to combine the information in these tables we will increase the number of queries we
have to perform by an order of magnitude. If N recipes were selected in a single query then we
would have to perform N additional queries to determine each recipe's category name.

Fortunately, this task can be accomplished in a single query that incorporates a join. In the
simplest type of join we list all of the tables to be joined in the FROM section, and in the WHERE
clause we define the relationship between those tables. In this example, the relationship between
recipes and categories is based on the category_id column. If we join the tables where the
category_id from the recipes table is equal to the category_id in the categories table, the
resulting table will contain the recipe and category columns where that relationship holds:

mysql> SELECT recipe_id, recipe_name, category_name


> FROM recipes, categories
> WHERE recipes.category_id=categories.category_id;

+-------------+-------------------------+---------------+
recipe_id I recipe_name I category_name I
+-------------+-------------------------+---------------+
2 Sugar Cookies Cookies
3 Lemon Cake Cake
4 Chocolate Cake Cake
1 Chocolate Chip Cookies Chocolate
+-------------+-------------------------+----------------+
4 rows in set (0.00 sec)

A join based on a value in a common field such as this is known as an Inner join. In this example
the common field was the category_id.

Multi-table inner joins


An inner join can be applied to more than one table at once. In this next example I want to point
out a possible shortcoming in the tables we designed in the previous section. There is only one
category_id field per recipe record. This expresses a one-to-one relationship. But after reading
the recipe titles you may feel that some of the recipes actually belong in more than one category.
In the previous example, we might have wanted to include "Chocolate Chip Cookies" in both the
s Advanced PHP for Flash

categories "Chocolate" and "Cookies". What we want to express is a one-to-many relationship. Let's
redefine our tables to enable a single recipe to be associated with several different categories:

category_id category_name
1 Cookies
2 Cakes
3 Chocolate

recipe_id recipe_name
1 Chocolate Chip Cookies
2 Sugar Cookies
3 Lemon Cake
4 Chocolate Cake

xref id recipe_id category_id


1 1 3
2 1 1
3 2 1
4 3 2
5 4 3
6 4 2
7 4 4

This new data model uses a cross-reference table to link recipes with categories. Multiple
categories can now be associated with a single recipe and we can still use a single MySQL
statement with a multi-table join to determine the recipe name and category for every recipe:

mysql> SELECT recipes.recipe_id, recipes.recipe_name,


> categories.category_name
> FROM xref, recipes, categories
>WHERE xref.recipe_id=recipes.recipe_id
>AND xref.category_id=categories.category_id;
Advanced MySQL s

+------------+------------------------+---------------+
I recipe_id I recipe_name I category_name I
+------------+------------------------+---------------+
1 Chocolate Chip Cookies Cookies
2 Sugar Cookies Cookies
3 Lemon Cake Cake
4 Chocolate Cake Cake
1 Chocolate Chip Cookies Chocolate
4 Chocolate Cake Chocolate
+------------+------------------------+---------------+
6 rows in set (0.00 sec)

Outer joins
In the previous example you may have noticed that cross-reference entry number 7 does not
appear in the result from the inner join. That is because there is no category_id equal to 4.
What this means is that there is a Chocolate Cake cross-reference entry pointing to a category
that does not exist. It could be the case that we don't want to ignore these kinds of discrepancies.
This is solved with an Outer Join:

mysql> SELECT recipes.recipe_id, recipes.recipe_name,


> categories.category_name FROM xref
> LEFT JOIN recipes
> ON xref.recipe_id=recipes.recipe_id
> LEFT JOIN categories
> ON xref.category_id=categories.category_id;
+-----------+------------------------+---------------+
I recipe_id I recipe_name I category_name I
+-----------+------------------------+---------------+
1 Chocolate Chip Cookies I Chocolate
1 Chocolate Chip Cookies I Cookies
2 Sugar Cookies I Cookies
3 Lemon Cake I Cake
4 Chocolate Cake I Chocolate
4 Chocolate Cake I Cake
4 Chocolate Cake I NULL
+------------------+-----------------------------------------+--------------------------+
7 rows in set (0.00 sec)
s Advanced PHP for Flash

The syntax of the outer join differs slightly from that of the inner join. Instead of listing each
table that will be joined in the FROM section we use the key words LEFT JOIN or RIGHT JOIN
to join the previous table in the FROM section to the current table. The oo clause then defines
the relationship between the two tables. The oo clause is similar to a WHERE clause and may use
the same conditional forms.

Self joins
When your database uses data that is hierarchical or recursive in nature, it is often useful to join
a table with itself. Consider the following taxonomy:

Desserts

Cakes

Coffee Cakes

Frozen Cakes

Cookies

We could represent this hierarchy of dessert groups with the following table:

category_id parent_id category_name


1 NULL Desserts
2 1 Cakes
3 1 Cookies
4 2
Coffee Cakes
5 2
Frozen Cakes

In order to get a list of every category and each category's parent we would need to do a join
between a table and itself. Since both tables have the same name we will use table aliases to
define the relationship:
Advanced MySQL s

mysql> SELECT child.category_name AS ChildName,


> parent.category_name AS ParentName
> FROM categories AS parent
> RIGHT JOIN categories AS child
> ON child.parent_id=parent.category_id;

+--------------+-------------+
I ChildName I ParentName
+--------------+-------------+
Desserts NULL
Cakes Desserts
Cookies Desserts
Coffee Cakes Cakes
Frozen Cakes Cakes
+--------------+-------------+
5 rows in set (0.01 sec)

Aliases may also be used to keep your queries readable. In the previous example, both resulting
columns were named category_name. Adding the aliases ChildName and ParentName to the
selected columns made the result more understandable.

Using joins efficiently


Indexes are extremely important for efficient joins. Without indexes, MySQL would be forced to
scan through every single record in the queried table to find a single result. In order to make
your joins as fast as possible you should consider creating indexes for the data that your table
will be joined on.

In the xref table we were working with earlier in the chapter we might consider this table definition:

CREATE TABLE xref (


xref id int auto_increment,
recipe_id int,
category_id int,
PRIMARY KEY(xref_id),
INDEX recipe_index (recipe_id, category_id),
INDEX category_index (category_id)
);
s Advanced PHP for Flash

In this example we made xref_ id the PRIMARY KEY. This allows us to quickly identify and
manipulate xref records by their unique ID number. The recipe_index creates a two-column
index that will make all of the multiple joins based on recipe_id and category_id very quick.
I have added a third index in this example, category_index, which provides a category_id
index. Since recipe_index does not make queries that use category_id faster when
recipe_id is not also part of the query, this index is necessary to improve performance for
those cases.

In general, you should attempt to identify what kind of operations will be performed on your
data and how often those operations will be performed to determine whether or not indexing
that column is useful. If a column is not the subject of a join, or WHERE clause, or frequently used
by functions such as MIN ( J and MAX ( l . it may be a poor candidates for indexing.

Searching
MySQL provides several different functions that we can use for pattern matching and searching.
These include standard SQL pattern matching, extended regular expressions, and full-text
searching. Each has its own benefits and drawbacks, which we will discuss.

SQL pattern matching


The SQL LIKE operator allows you to match text using very simple patterns and is by default
case insensitive. LIKE patterns use two special characters. The _ is used to match any single
character and the '%' is used to match an arbitrary number of characters.

To find every record that starts with the word "chocolate" in a recipe database we could write:

mysql> SELECT name FROM recipes


>WHERE name LIKE "chocolate%";

+----------------------+
I name
+----------------------+
chocolate cake
I chocolate pie
I chocolate cream cake
+----------------------+
2 rows in set (0.00 sec)
Advanced MySQL s

Or to find every record that ends with the word "cake" we could write:

mysql> SELECT name FROM recipes


> WHERE name LIKE "%cake";

+----------------------+
I name
+----------------------+
chocolate cake
chocolate cream cake
caramel cake
strawberry cake
+----------------------+
4 rows in set (0.01 sec)

If we wanted to find every record with the terms chocolate and cake in it we could use two LIKE
operators joined by an AND operator:

mysql> SELECT name FROM recipes


> WHERE name LIKE "%chocolate%"
> AND name LIKE "%cake%" ;

+----------------------+
I name
+----------------------+
chocolate cake
I chocolate cream cake I
+----------------------+
2 rows in set (0.01 sec)

In the last example we used the '%' to create a query where any number of arbitrary characters
could precede or follow the terms "chocolate" or "cake". If we wanted to match a specific
number of arbitrary characters we can use _ instead of'%'. We could match every cake recipe
with a seven-letter name by using seven underscores:

mysql> SELECT name FROM recipes


> WHERE name LIKE " - - - - cake";
s Advanced PHP for Flash

+--------------+
I name
+--------------+
I caramel cake I
+--------------+
1 row in set (0.00 sec)

Let's look at how we could use the LIKE operator in a PHP script that needs to search our recipe
database. We will assume the user provides a space-delimited list of search terms in the variable
$search_terms. We will explode this list into an array of terms and match against each one.
Since we want to find all the records that match any of the search terms, we will OR the LIKE
operations together. If we wanted to match only the records that match all of the search terms
we would AND the LIKE operations together.

<?
$search_term_array =explode (" ", $search_terms);
$query = "";
foreach ($search_term_array as $term) {
if ($query != "") $query .= "OR ";
$query .= "name LIKE \"%"
mysql_escape_string($term) . "%\" ";

$query = "SELECT name FROM recipes WHERE " . $query;


$connect = mysql_connect ("hostname", "username", "password");
mysql_select_db ("database");
$result = mysql_query($query);
if (mysql_num_rows($result) > 0)
while (list($recipe_name) = mysql_fetch_row($result))
echo "$recipe_name";

else
echo "No results were found.";

?>
Advanced MySQL s

Regular expressions
If the LIKE operator doesn't seem to give you enough control over how your data is matched,
you may need to use extended regular expressions. Extended regular expressions are more
powerful than LIKE, but they are also more complex. MySQL uses an extended version of the
POSIX 1003.2 specification for regular expressions that was written by Henry Spencer. These are
the same kind of regular expressions that PHP uses in its extended regular expression functions
(not its PCRE-based functions). We introduced these in Chapter 5 of Foundation PHP for Flash,
so we won't cover all the details in this section.

The syntax for using extended regular expressions is similar to LIKE:

expression REGEXP pattern

Regular expressions are useful for finding information that has a very specific structure or
format. To match a telephone number we might write:

mysql> SELECT 11 (310) 555-2345 11


> REGEXP 11 \ \ ( [0-9l{3} \ \) [0-9l{3}- [0-9l{ 4} II
> AS NumberMatches;

+---------------+
I NumberMatches I
+---------------+
1
+---------------+
1 row in set (0.00 sec)

This expression matches an opening parenthesis followed by 3 digits between 0 and 9, a closing
parenthesis, a space, 3 more digits between 0 and 9, a dash, and finally four more digits between
0 and 9. The REGEXP pattern syntax is more complex than the LIKE pattern syntax but it is also
more expressive.

Full-text searching
One deficiency of both the LIKE and REGEXP operators is that there is no sense of relevance to
their searches. A search result listing from the final example in the previous section would not
be returned in any particular order. We would really like to create search results with the best
s Advanced PHP for Flash

matches first. Using the operators we have discussed so far, it is very difficult to tell if one record
matches a set of search terms any better than another record.

Full-text indexing and searching was introduced in MySQL version 3.23.23. This relatively new
feature helps us perform matches more efficiently and effectively for large natural-language data
sets. It also incorporates the concept of relevance, which in turn lets us sort the results in a more
meaningful way.

Let's see how this works by creating a recipe database with the special FULLTEXT index:

rnysql> CREATE TABLE recipes (


> id INT UNSIGNED AUTO INCREMENT NOT NULL PRIMARY KEY,
>name VARCHAR(255),
> instructions TEXT,
> FULLTEXT (name,instructions)
> )i

Creating a FULLTEXT index for the columns you intend to search is necessary for MySQL's full-
text searching to work. Next, let's put some sample data into the recipe database:

mysql> INSERT INTO recipes (name, instructions) VALUES


> ('Chocolate Cake', 'Butter a nine inch round cake pan ... '),
> ('Chocolate Meringue Pie', 'Grate or cut chocolate ... '),
> ('Chocolate Pecan Pie', 'Heat oven to 350 degrees ... '),
> ('Caramel Apple Cake', 'In a nine inch round pan, melt ... '),
> ('Strawberry Short Cake', 'Hull and wash the berries ... ');

The MATCH () function utilizes the FULLTEXT index to perform a natural-language search for a
string. The MATCH () function specifies the columns to search and AGAINST () specifies the
search string.

Let's try a search for the word "round" using the table we created:

mysql> SELECT name, instructions FROM recipes


>WHERE MATCH (name,instructions) AGAINST ('round');
Advanced MySQL s

+--------------------+-- -------------------------- -----------+


I name I instructions
+--------------------+-- -------------------------- -----------+
I caramel Apple Cake I In a nine inch round pan, melt ...
I Chocolate Cake I Butter a nine inch round cake pan ... I
+--------------------+-- -------------------------- -----------+
2 rows in set (0.00 sec)

When the MATCH () function is in the WHERE clause MySQL automatically sorts the results by
relevance so that the best matches come first. Let's put the MATCH function in the SELECT
statement so we can look at the relevance values for this particular search.

mysql> SELECT name, MATCH (name,instructions)


> AGAINST ( round
1 AS relevance FROM recipes;
1 )

+------------------------ +-------------------+
I name I relevance
+------------------------ +-------------------+
Chocolate Cake 10.33673688991751
Chocolate Meringue Pie IO
Chocolate Pecan Pie IO
Caramel Apple Cake 10.37929384084749
Strawberry Short Cake IO
+------------------------ +-------------------+
5 rows in set (0.00 sec)

The relevance value is a non-negative floating-point number that is computed based on the
number of words in the row, the number of unique words in the row, the total number of words,
and the number of rows that contain a particular word. If there is no similarity between the
search pattern and the row, then the relevance is zero.

MySQL doesn't compare your pattern against the actual content in your database. Instead it uses
the faster FULLTEXT index based on your database. One of the reasons the FULLTEXT index is
fast is that it doesn't include every word that is in your database records. Words that are three
characters or smaller are not indexed and words that appear in over 50% of the records are not
indexed either. That poses a problem in our small recipe database. If we do a search for the word
cake, it won't be found!
s Advanced PHP for Flash

mysql> SELECT name FROM recipes WHERE


>MATCH (name,instructions) AGAINST ('cake');

Empty set (0.00 sec)

Cake appears in over 50% of the records and so it was not indexed. If our recipe database had
more entries and most of them weren't for various kinds of cake this wouldn't be a problem.
The MATCH () function was designed for large and diverse text data.

The technique you select to search your data will be dependent on your needs. For small
databases, LIKE or REGEXP may fit your needs. For larger databases, full-text searching with
MATCH () may be more appropriate. There isn't a one-size-fits-all solution to database searching.

You may decide to combine these techniques or to use a third-party indexing and search engine
package to provide the search capabilities you need.

Date and time functions


MySQL provides a very powerful set of functions to manipulate dates and times. Creating
intelligent queries that use MySQL date and time functionality can often prevent unnecessary
and time-expensive post-processing code written in PHP.

Common functions
MySQL provides more date and time functions than you could shake a stick at. Some of the most
common date and time functions are described here:

NOW () : Returns the current date and time.

CORDATE () : Returns the current date.

DAYOFWEEK (date): The day in the week the date falls on (1 through 7) where 1 =Sunday.

DAYOFMONTH (date) : The day in the month the date falls on (1 through 31 ).

WEEKDAY (date): The day in the week the date falls on (0 through 6) where 0 = Monday.

DAYOFYEAR (date): The day in the year the date falls on (1 through 365).
Advanced MySQL s

MONTH (date): The month in the year the date falls on (1 through 12).

DAYNAME (date): The name of the day (Sunday, Monday, Tuesday, etc.).

MONTHNAME (date): The name of the month Oanuary, February, etc.).

QUARTER (date): The quarter of the year the date falls on (1 through 4).

WEEK(date): The week of the year the date falls on (1 through 53).

YEAR (date): The year the date falls on (1000 through 9999).

YEARWEEK(date): The year and the week a date falls on.

HOUR (time): The hour the date or time falls on.

TIME (time): The time the date or time falls on.

SECOND (time): The second the date or time falls on.

TO_DAYS (date): The day number since year 0 the day lands on.

FROM_DAYS (date): The date the given day number lands on.

One simple task we could use these functions for would be to return the year, month, day, hour,
minute, and second components for a DATETIME column. Unaware of MySQL's date and time
functions, one might write this PHP code to extract the date elements from MySQL's default
DATETIME format (YYYY-MM-DD HH:MM:SS):

$query= "SELECT upload_datetime FROM recipes";


$result= mysql_query($query);
list($date_time) = mysql_fetch_row($result);
list($date, $time) =explode(" " . $date_time);
list($year, $month, $day) = explode ("-", $date);
list($hour, $minute, $second) =explode (":", $time);
s Advanced PHP for Flash

Exploding strings into arrays isn't nearly as efficient as getting the data you want in the right
format to begin with. A better way to accomplish the same task would be to write the following
code instead:

$query= "SELECT YEAR(upload_datetime), "


"MONTH(upload_datetime), " .
"DAYOFMONTH(upload_datetime), "
"HOUR(upload_datetime), " .
"MINUTE(upload_datetime), "
"SECOND(upload_datetime) " .
"FROM recipes";
$result = mysql_query($query);
list($year, $month, $day, $hour, $minute, $second)
mysql_fetch_row($result);

It's easy to avoid writing gratuitous and expensive PHP code that extracts the date and time
components from the default MySQL output format by effectively using MySQL's built-in
date functions.

Date arithmetic
MySQL has another powerful set of functions designed for adding and subtracting dates.
Determining what the date was 37 days ago is not a trivial task, but MySQL can make short work
of such chores.

Two important functions we should familiarize ourselves with are DATE_ADD () and DATE_SUB () .

DATE_ADD(date, INTERVAL amount type)


DATE_SUB(date, INTERVAL amount type)

These functions return a new date by adding the given amount of time to the given date. The
type parameter defines the type of amount to add or subtract. A table of valid interval types and
the amount format each type allows is shown to the right:
Advanced MySQL s

type amount format


SECOND SECONDS
MINUTE MINUTES
HOUR HOURS
DAY DAYS
MONTH MONTHS
YEAR YEARS
MINUTE SECONDS "MINUTES:SECONDS"
HOUR MINUTE "HOURS :MINUTES II
DAY HOUR "DAYS HOURS"
YEAR MONTH "YEARS-MONTHS"
HOUR SECOND "HOURS:MINUTES:SECONDS"
DAY MINUTE "DAYS HOURS:MINUTES"
DAY SECOND "DAYS HOURS: MINUTES: SECONDS"

So, to find out what the date was 37 days before Christmas 2002 we could use DATE_SUB () :

mysql> SELECT DATE_SUB('2002-12-25', INTERVAL 37 DAY);

+------------------------------------------+
I DATE_SUB('2002-12-25', INTERVAL 37 DAY)
+------------------------------------------+
1 2oo2-11-1a
+------------------------------------------+
1 row in set (0.00 sec)

Or we could find the date 7 days, 5 hours, and 12 minutes after Christmas 2002 using DATE_ADD () :

mysql> SELECT DATE_ADD('2002-12-25',


> INTERVAL "7 5:12" DAY_MINUTE);

+------------------------------------------------- -----+
I DATE_ADD('2002-12-25', INTERVAL "7 5:12" DAY_MINUTE) I
+------------------------------------------------- -----+
1 2oo3-o1-o1 o5:12:oo
+------------------------------------------------- -----+
1 row in set (0.00 sec)
s Advanced PHP for Flash

There are many applications for using DATE_ADD and DATE_SUB. If the recipe table we were
working with earlier had an upload_date field, we could select all of the recipes uploaded in
the last 15 days by writing:

mysql> SELECT name FROM recipes WHERE


> DATE_ADD(upload_date, INTERVAL 15 DAY) >=
>CORDATE();

Date and time formatting


In almost every application that uses dates you will need to format those dates either for the end
user or to pass on to another function.

MySQL provides a function called DATE_FORMAT () for just this purpose. DATE_FORMAT () is very
similar to PHP's date () function. In many cases it is much more efficient to use DATE_FORMAT ()
instead of date () . This may especially be true if the only reason you are using date () is to then use
that data in another query! DATE_FORMAT's syntax is only slightly different from PHP's date syntax:

DATE_FORMAT (date, format)

This function returns a string formatted for the specified date. When the format string is printed,
special formatting codes are replaced with appropriate values. One should note that while the
formatting codes are similar to both PHP's date formatting codes and the command-line's date
formatting codes, all three are different! MySQL's formatting codes are listed here:

%M: Month name Oanuary, February, March, etc.)


%W: Weekday name (Sunday, Monday, Tuesday, etc.)
%D: Day of the month with English ordinal suffix (1st, 2nd, 3rd, etc.)
%Y: Four digit year (0000 - 9999)
%y: Two digit year (00 - 99)
%X: Year for the week where Sunday is the first day of the week, used with '%v'
%x: Year for the week, where Monday is the first day of the week, used with '%v'
%a: Abbreviated weekday name (Sun, Mon. Tues. etc.)
%d: Day of the month (00 - 31)
%e: Day of the month (0 - 31)
%m: Month (01 - 12)
%c: Month (1 - 12)
Advanced MySQL s

%b: Abbreviated month name (Jan, Feb, Mar, etc.)


%j: Day of year (001 - 366)
%H: Hour (00 - 23)
%k: Hour (0 - 23)
%h: Hour (01 - 12)
%I: Hour (01 - 12)
%1: Hour (1 - 12)
%i: Minutes (00 - 59)
%r: 12-hour time (hh:mm:ss [AP]M)
%T: 24-hour time (hh:mm:ss)
%S: Seconds (00 - 59)
%s: Seconds (00 - 59)
%p: AM or PM
%w: Day of the week (0 .. 6)
%U: Week (00 - 53), where Sunday is the first day of the week.
%u: Week (00 - 53), where Monday is the first day of the week.
%V: Week (01 - 53), where Sunday is the first day of the week. Used with '%X'.
%v: Week (01 - 53), where Monday is the first day of the week. Used with '%x'.
%%: A literal '%'

We can use this function to format DATE, TIME, or DATETIME data types.

mysql> SELECT DATE_FORMAT('1975-09-01 23:24:00',


> '%W %M %e, %Y. ') AS date_format_example;

+------------------------ ---+
I date_format_example
+------------------------ ---+
I Monday September 1, 1975. I
+------------------------ ---+
1 row in set (0.00 sec)

TIME data types can be formatted using the analogous TIME_FORMAT ()function.
TIME_FORMAT() only allows formatting codes related to time and not date. Otherwise it is
almost identical to DATE FORMAT:
s Advanced PHP for Flash

mysql> SELECT TIME_FORMAT('16:30:00', '%1:%i %p')


> AS time_format_example;

+---------------------+
I time_format_example I
+---------------------+
I 4:30 PM
+---------------------+
1 row in set (0.01 sec)

Building the cookbook


In this section we will develop a searchable cookbook that includes photos of each recipe. In
reality our "cookbook" could be any number of things by simply changing some names- it could
be a photo album, a part catalog, or even a reference manual. But I still have food on the brain,
so a cookbook it is.

Since all of this MySQL material is probably still fresh on your mind, let's start by creating a series
of tables for our cookbook. These will include a recipe table, category table, and recipe-category
cross-reference table.

mysql> CREATE TABLE recipes


> id INT UNSIGNED NOT NULL Auro_INCREMENT,
> name VARCHAR(128),
> author VARCHAR(128),
> instructions TEXT,
> upload_date DATETIME,
> PRIMARY KEY ( id) ,
> FULLTEXT(name,author,instructions)
> ) ;

mysql> CREATE TABLE categories (


> id INT UNSIGNED NOT NULL AurG_INCREMENT,
> parent_id INT UNSIGNED NOT NULL
> name VARCHAR(128),
> PRIMARY KEY ( id)
> );
Advanced MySQL s

mysql> CREATE TABLE recipe_category_xref (


> id INT UNSIGNED NOT NULL AUTO_INCREMENT,
> recipe_id INT UNSIGNED NOT NULL,
> category_id INT UNSIGNED NOT NULL,
> INDEX (category_id, recipe_id),
> INDEX (recipe_id),
> PRIMARY KEY (id)
> );

Now that we've created the underlying database tables, let's start writing the PHP and MySQL
queries that will drive the cookbook.

database.php

The first PHP file we are going to write will be called database .php. This file defines a very
simple class named Database. The Database class encapsulates a few frequently used functions
that will save us some time later.

1. The first thing that our database class defines is the connection details for the database.
Defining all the connection details in a single database class allows us to reuse this code
throughout our application.

<?

class Database {
var $hostname "localhost";
var $username "user";
var $password "pass";
var $database "phpforflash";
var $connect;

2. The second thing that we define in our database class is a query function that automatically
takes care of connecting to the database and displaying errors that may occur.

function query ($s) {


s Advanced PHP for Flash

II Connect to the MySQL server if necessary.


if (!$this->connect) {
$this->connect = mysql_connect ($this->hostname,
$this->username, $this->password);

II Select the correct database.


mysql_select_db($this->database);

II Perform the query.


$result = mysql_query($s);

II Check for errors.


i f (!$result) {
echo mysql_error() " " . mysql_errno() . "\n";
exit() ;

II Return the results of the query.


return $ result;

3. Finally we create a quote function to encapsulate the mysql_escape_string () function.


Our function adds quotes around the escaped string to save us some typing.

function quote ($s) {


return "\"" . mysql_escape_string ($s) . "\"";

?>

Now that some of the boilerplate stuff is out of the way, let's move on to the administration tools.
Advanced MySQL s

admin categories.php

When I write admin tools for web-based applications, I usually choose to do it with HTML rather
than Flash. Admin tools rarely need to be as design savvy as the rest of your site and it's often
easier to rapidly develop an application with just PHP rather than both PHP and Flash.

We are going to start with the category administration tool since it's the simpler of the two
admin tools we will be writing.

1. To begin with, we need to include the database class we created in the database. php file.
We'll create an instance of our database class and name it $DB. We'll also set the
$page_size variable here. We'll talk about it towards the end of the script.

<?

require ("database .php");


$DB = new Database;
$page_size = 20;

2. Now we are going to make additions to the categories. If the variable $add is set then we
will insert the posted variables $parent_id and $name into the database.

i f ($add) {
$query = "INSERT INTO categories (parent_id, name) " .
II VALUES ("
$DB->quote($parent_id) . ", "
$DB->quote ($name) . ") ";
$result = $DB->query($query);

3. Then we are going to add the ability to make category updates. If the variable $update is
set then we will update the values for $parent_id and $name for the category record
associated with $id.

i f ($update) {
$query = "UPDATE categories SET " .
s Advanced PHP for Flash

"parent_id=" . $DB- >quote($parent_id ) II

"name=" . $DB->quote($name) .
"WHERE id=" . $DB->quote($id);
$result= $DB->query($quer y);

4. The third and final kind of action we are going to handle is deletion. If the variable
$delete is set then we will delete the category record associated with $id.

i f ($delete) {
$query = "DELETE FROM categories WHERE id=" .
$DB->quote($id);
$result= $DB->query($quer y);

<html>
<head>
<title>Category Admin Tool</title>
</head>
<body>

5. This admin tool has two basic pages. The first page will display a list of all the categories.
The second page will be an editor used to add or update categories. The editor page will
be invoked when the variable $edit is set. Let's look at that case first.

i f ($edit) {

// if the id is > 0 then we are editing this entry


// (not adding a new one) and so we need to retrieve
II the existing values to use as defaults .
i f ($id>O) {
$query = "SELECT parent_id, name " .
"FROM categories WHERE id=" . $DB->quote($id);
$result= $DB->query($quer y);
Advanced MySQL s

list($parent_id, $name) =
mysql_fetch_row($result);

?>
<form name="form" method="post" action="admin_categories.php">
<table cellpadding="6" cellspacing="O" bgcolor="#eeeeee">

6. The first item we can alter from within the editor page is the parent_id field. This field
associates another category record as this record's parent, thus creating a hierarchy of
categories. In the next bit of code we will create a pull-down list of all the categories that
can be used as parents.

<tr>
<td bgcolor="#ffccOO">Parent:</td>
<td>
<select name="parent_id">
<option<? i f ($parent_id==0) echo "selected"; ?>
value="O">None</option>
<?

$query = "SELECT id, name from categories " .


"ORDER BY name";
$result= $DB->query($query);
while ($row= mysql_fetch_row($result))
echo "<option ";
if ($parent_id == $row(O]) echo "selected";
echo "value= "' . $row[O] . "'>" . $row[l]
"</option>\n";

?>
</select>
</td>
</tr>
s Advanced PHP for Flash

7. The next part of the editor provides a simple text input field for setting the category name:

<tr>
<td bgcolor="#ffccOO">Category Name:</td>
<td><input type="text" name="name"
value="<?=$name?>"></td>
</tr>

8. Finally we create a series of submit buttons that will perform various operations on the
record being edited. We have already handled the operations that take place based on
these buttons earlier in the script.

<tr>
<td bgcolor="#ffcc00"> </td>
<td>
<? i f ($id) { ?>
<input type="hidden" name="id" value="<?=$id?>">
<input type="submit" name="update" value="update">
<? else { ?>
<input type="submit" name="add" value="add">
<? ?>
<input type="submit" name="cancel" value="cancel">
<input type="submit" name="delete" value="delete">
</td>
</tr>
</table>
</form>

9. Now that we are finished with the editor page we can move on to the category overview
page. This page will display a listing of all the categories and each category's parent.

<? } else { ?>


<table bgcolor="#eeeeee" cellpadding="6" cellspacing="0">
<tr bgcolor="#ffccOO">
<td width="50">Parent</td>
<td>Name</td>
</tr>
Advanced MySQL s

10. We don't know how many categories we might create, so we are going to create a "pager"
at the bottom of the category listing. The pager will allow us to directly access several pages
of category entries. We will use the variable $page to determine what page we are on.

i f ($page){
if (!is_numeric($page)) $page 0;
} else $page = 0;
$offset = $page * $page_size;

11. For our pager to work correctly we need to know the total number of categories that exist.
We can get this number using the MySQL COUNT () function. We'll use this number a little
bit later in the script.

II Count how many category entries we have.


$query= "SELECT COUNT(id) FROM categories";
$result= $DB->query($query);
if ($row= mysql_fetch_row($result))
$category_count = $row[O];
else $category_count = 0;

12. Next we want to create a listing of each category name, category ID, and the parent
category's name. The joins we learned about previously should come in very handy! We'll
use a RIGHT JOIN to join the category table to itself (a self join).

$query = "SELECT child.id, child.name, parent.name "


"FROM categories AS parent " .
"RIGHT JOIN categories AS child ON child.parent_id "
"ORDER BY parent.name, child.name"
"LIMIT $offset,$page_size";

$result = $DB->query($query) ;
while (list($child_id, $child_name, $parent_name,
$parent_id) = mysql_fetch_row($result))
echo "<tr>";
echo "<td>";
s Advanced PHP for Flash

if ($parent_name) echo $parent_name;


else echo "None";
echo "</td>";
echo "<td>" .
"<a href='admin_categories.php?edit=l&id="
$child_id . "' >" . $child_name . ", (id #"
$child_id . ")</a></td>";
echo "</tr>";

13. If there were no results from the query then we will inform the user:

if (mysql_num_rows($result) <= 0) {
echo "<tr><td colspan='3'>There are no " .
"categories.</td></tr>";

</table>

14. Now that we have finished the category list, we can add a few links for page navigation
and an Add Category link for creating new categories:

<P>
<a href="admin_categories.php?edit=l">Add Category</a>
<? i f ($page > 0) { ? > : :
<a href="admin_categories.php?page=<?=$page-l?>">Pre vious Page</a>
<? } ?>
<?if ($category_count > ($page_size*($page+l))) { ?>::
<a href="admin_categories.php?page=<?=$page+l?>">Nex t Page</a>
<? } ?>

15. Our final task is adding the pager that I promised. We know how many categories there
are, what page we are on, and the page size that was set at the very beginning of the script.
The math is pretty simple. The ceiling of the category count divided by the page size is the
number of pages we should have. Then we just iterate across those numbers creating links.
We won't add a link to the current page to create a visual cue.
Advanced MySQL s

<p>Pages:
<?

$j = ceil($category_count I $page_size);
for ($i=O; $i<$j; $i++) {
i f ($i==$page) echo ($i+l) . "&nbsp;&nbsp;";
else echo "<a href='admin_categories.php?page="
$i . "'>" . ($i+l) . "</a>&nbsp;&nbsp;";

i f ($j 0) echo "None";

</p>
<? } ?>
</body>
</html>

The category editor is complete and should be usable. You can go ahead and start adding some
categories, as shown in the following image:

-
- .. .. . . .. _,
"' .... '""""' '"" ""' -- ~
IO - e~ &l ~ .P - -tr- _,_ I"J .ta 6
-

e l~ ~ gjj
Addrosslilo.oo,l-.w--J.Jloo".<h..5/-__...., 31lGo Li nks TNorton AntiVIrus!iil
.:
p...., Name
N011e ~
Nono <Aokie ~d 11)
N..,. ~
Cookie Cbocoi.Dte g!e; Cookies :6d M4)

P>i< 1

*1""" r r r jD ........ -
s Advanced PHP for Flash

admin_recipes.php

The recipe administration script is going to have a little more to it than the category
administration script did. Its basic structure is going to be very similar though, and have a recipe
list page and an editor page.

1. Once again we will start by including database . php and creating an instance of
Database named $DB. We'll also set the $image_path to the directory where the images
in our cookbook reside. This directory should be accessible via the web and the web server
should have both read and write permissions to this directory.

require ("database. inc");


$DB = new Database;
$page_size = 20;
$image_path = "/path/to/webpage/images/";

2. We will handle the various operations that our script performs at the beginning. The first
action we are going to handle is cross-reference removal. If the variable $remove_xref is
set then we will remove the cross-reference record that corresponds to the ID stored in
$remove_xref.

if ($remove_xref)
$query = "DELETE FROM recipe_category_xref "
"WHERE id=" . $DB->quote($remove_xref);
$result = $DB->query($query);

3. We also want to be able to add cross-references. The next bit of code scans a series of
checkboxes we will create for each recipe later in the script. If the checkbox was checked
then we will add a cross-reference record between that recipe and the selected category.

i f ($add_xref) {
for ($i=O; $i<$page_size; $i++) {
i f ($HITP_POST_VARS["recipe_id_" . $i] > 0) {
Advanced MySQL s

$query = "INSERT INTO recipe_category_xref "


"(recipe_id, category_id) VALUES (" .
$DB->quote ($H'ITP_POST_VARS ["recipe_id_" $i])
", " . $DB- >quote ($category_id) . ") ";
$result= $DB->query($query);

4. The add, update, and delete operations are very similar to those in the category administration
script. The only new feature is that image uploads for additions and updates are also allowed.
When an image is uploaded, it is stored in the images directory and its filename is simply the
lD of the recipe to which it corresponds with . jpg appended to the end.

if ($add) {
$query = "INSERT INTO recipes "
"(name, author, instructions, upload_date) VALUES (" .
$DB->quote($name) . ", " .
$DB->quote($author) . ", " .
$DB->quote($instructions) II

"NOW()) IIi

$result= $DB->query($query);
$id = mysql_insert_id ($DB->connect);

if (is_uploaded_file($H'ITP_POST_FILES['image'] ['tmp_name'] ))
if ($HTTP_POST_FILES['image'] ['size'] > 0 &&
$H'ITP_POST_FILES ['image' J ['size'] < 5000000) {
move_uploaded_file($H'ITP_POST_FILES
[ ' image ' ] [ ' tmp_name ' ] ,
$image_path . $id . ". jpg") ;
else
$err "Warning: Image size was too large or zero.";

~ rno CJ [J

~~~L,~
Dec~ e
s Advanced PHP for Flash

i f ($update) {
$query = "UPDATE recipes SET " .
"name=" . $DB->quote($name) . ", "
"author=" . $DB->quote($author) . ", "
"instructions=" . $DB->quote($instructions) II II

" WHERE id=" . $DB->quote($id);


$result= $DB->query($query);

if (is_uploaded_file($HTTP_POST_FILES['image'] ['tmp_name']))
if ($HTTP_POST_FILES['image'] ['size'] > 0 &&
$HTTP_POST_FILES['image'] ['size'] < 5000000) {
move_uploaded_file($HTTP_POST_FILES
[ ' image ' ] [ ' tmp_name ' l ,
$image_path. $id. ".jpg");
} else {
$err= "Warning: Image size was too large or zero.";

i f ($delete) {
$query = "DELETE FROM recipes WHERE id=" . $id;
$result= $DB->query($query);

?>
<html>
<head>
<title>Recipe Admin Tool</title>
</head>
<body>

5. As I said before, this ad min tool has two basic pages just like the first ad min tool. The first
page we are going to tackle is the editor page that is used when $edit is set. This time
the editor is even more straightforward than the category editor because we aren't going
to create any database-driven pull-down menus. It's just a simple form that we fill with
existing values if available.
Advanced MySQL s

<?

i f ($edit) {

II if the id is > 0 then we are editing this entry


II (not adding a new one) and so we need to retrieve
II the existing values to use as defaults.
i f ($id>O)
$query = "SELECT name, author, instructions "
"FROM recipes WHERE id=" . $DB->quote($id);
$result= $DB->query($query);
list($name, $author, $instructions)
mysql_fetch_row($result);

?>
<form name="form" method="post" action="admin_recipes.php"
enctype="multipartlform-data">
<table cellpadding="6" cellspacing="O" bgcolor="#eeeeee">
<tr>
<tr>
<td bgcolor="#ffccOO">Name:<ltd>
<td><input type="text" name="name" value="<?=$name?>"><ltd>
<ltr>
<tr>
<td bgcolor="#ffcc00">Author:<ltd>
<td><input type="text" name="author" value="<?=$author?>"><ltd>
<ltr>
<tr>
<td bgcolor="#ffcc00">Instructions:<ltd>
<td><textarea name="instructions"><?=htmlentitites($instructions)?>
<ltextarea><ltd>
<ltr>
<tr>
<td bgcolor="#ffccOO">&nbsp;<ltd>
<td>
<? i f ($id) { ?>
s Advanced PHP for Flash

<input type="hidden" name="id" value="<?=$id?>">


<input type="submit" name="update" value="update">
<? else { ?>
<input type="submit" name="add" value="add">
<? } ?>
<input type="submit" name="cancel" value="cancel">
<input type="submit" name="delete" value="delete">
</td>
</tr>
</table>
<? if ($id) { ?>
<p><img src="images/<?=$id?>.jpg" border="l"></p>
<? } ?>
</form>

6. The second part of the script displays the recipes and the categories to which each recipe
belongs. We're also going to include a checkbox for each recipe so we can select the
recipes that will be associated with a particular category.

<? } else { ?>

<form name="form" method="post" action="admin_recipes.php">


<table bgcolor="#eeeeee" cellpadding="6" cellspacing="O">
<tr bgcolor="#ffcc00">
<td>&nbsp;</td>
<td>Name</td>
<td>Author</td>
<td>Categories</td>
</tr>
<?

if ($page) {
if (!is_numeric($page)) $page 0;
} else $page = 0;

$offset = $page * $page_size;


$query= "SELECT COUNT(id) FROM recipes";
Advanced MySQL s

$result = $DB->query($query);
if ($row= mysql_fetch_row($result)) $recipe_count $row[O];
else $recipe_count = 0;

$query = "SELECT id, name, author FROM recipes ORDER BY name LIMIT
$offset,$page_size";
$result= $DB->query($query);
$i = 0;

while (list($recipe_id, $recipe_name, $recipe_author)


mysql_fetch_row($result))
?>
<tr>
<td valign="top"><input type="checkbox" name="recipe_id_<?=$i?>"
value="<?=$recipe_id?>"></td>
<td valign="top">
<a href="admin_recipes.php?edit=l&id=<?=$recipe_id?>">
<?=$recipe_name?></a></td>
<td valign="top"><?=$recipe_author?></td>
<td valign="top">

7. At this point in the script we have displayed most of the information about the current
recipe. We will need to perform another query to look up the categories to which it
belongs. We could have been really clever and written a single query that would join the
recipes, categories, and recipe_category_xref tables together. This would reduce
our task to a single query, but for the sake of this tutorial I'm going to emphasize
readability and keep things simple.

<?
$query= "SELECT xref.id, categories.name FROM categories,
recipe_category_xref AS xref WHERE categories.id=xref.category_id
AND
xref.recipe_id=" . $DB->quote($recipe_id) . " ORDER BY
categories.name";
$result2 = $DB->query($query);
while (list($xref_id, $category_name) mysql_fetch_row($result2))
s Advanced PHP for Flash

echo $category_name . " : ";


echo " <a href= 1 admin_recipes.php?remove_xref=" $xref_id
"&page=" .
$page . " 1 >remove</a><br />";

?>
</td>
</tr>

$i++;

if (mysql_num_rows ($result) <= 0)


echo "<tr><td colspan= 1 4 1 >There are no recipes.</td></tr>";

$result_count = mysql_num_rows ($result) ;


mysql_free_result ($result);

</table>

8. Now we are going to build a database-driven pull-down menu for selecting a category to
associate with a recipe. We just need to write a query that lists all the available categories.

<p>
<select name="category_id">
<?
$query= "SELECT id, name from categories ORDER BY name";
$result= $DB->query($query);

while (list($category_id, $category_name) mysql_fetch_row($result))

echo "<Option " ;


i f ($parent_id == $category_id) echo "selected ";
echo "value= 1 " $category_id . " 1 >" . $category_name
"</option>\n";

</select>
Advanced MySQL s

<input type="submit" name="add xref" value="Add Category">


</p>
</form>

9. Finally we add the page navigation code and the pager at the bottom of the page. It's
pretty much the same as the code from the category administration script.

<P>
<a href="admin_recipes.php?edit=l">Add Recipe</a></p>
<? i f ($page > 0) { ? > : :
<a href="admin_recipes.php?page=<?=$page-l?>">Previo us Page</a><? }

<?if ($recipe_count > ($page_size*($page+l))) { ?>::


<a href="admin_recipes.php?page=<?=$page+l?>">Next Page</a><? } ?>
</p>
<p>Pages:
<?
$j = ceil($recipe_count I $page_size);
for ( $i=O; $i<$j; $i++) {
i f ($i==$page) echo ($i+l) . "&nbsp;&nbsp;";
else echo "<a href='admin_recipes.php?page=". $i. "'>". ($i+l)

"</a>&nbsp;&nbsp;";

if ($j == 0) echo "None";


?>
</p>
<? } ?>
</body>
</html>

~ rno CJ [J

~~~L,~
Dec~ e
s Advanced PHP for Flash

That script was definitely a great deal of work but we should get a lot of mileage out of it. You
can go ahead and start adding recipes. To add the recipe to a category you created in the
category administration tool, click the checkbox associated with that recipe. Select the category
you want it to be linked to from the pull-down list and click Add Category. This creates a cross-
reference record between the selected category and the selected recipe. In the next screenshot
you can see I have already added a few recipes and linked them to appropriate categories.

-"
H.! fdl 1fll!mo Tcds

o- D 8 _Thi t:l J5,..,.. -t:I,.-. -r- e l ~ - ~- ~ _d ~ El


~ ~

Addretsi.-J ...,,,__ "'_-""~-J-'"" .3 mGo


Nome
Joan App!e.secd Pies : ~
~
rC'MROLate Cake Das1 Goo-d CWs: ~
r Ch<>oolm Clip C:O.Iti<s C~ M. Oner Chocolate ~ Cookie : r-emove;
r Chocob.le Chocolate CNP Coobes BriULFud,s:e
r Cc-wbov Co-okic.s: Hank the Cowf>Qy Coolc.ies ; ~

r~ D. l.icio\>s Cok<s: W112!!t

r O!qnell Raisin CookitJ: Fred Quaktr C<>ohes : ~


CGppft Cutter Cookies : remo~oe

P.a,ges. l

Now that we are finished with the admin tools, the next few scripts should be much shorter.

fetch_categories_and_recipes.php

This script fetches a list of all the sub-categories and recipes associated with the category ID that
we will pass to the script in the variable id. If the variable search is passed to the script we will
return a list of recipes that match that instead.
Advanced MySQL s

1. We will start by including database. php and creating an instance of Database named
$DB. It's been a useful class, hasn't it?

require ( "database. inc" ) ;


$DB = new Database;
$cookbook_name = "Yaya's Cookbook";

2. If $search is set then we will perform a full-text search based on the $search string.

i f ($search) {
$query = "SELECT id, name FROM recipes "
"WHERE MATCH (name, author, instructions) AGAINST (" .
$DB- >quote ($search) . ") " ;
else {

3. If $search was not set then we will select all the recipes that are associated to the
category ID, $id. We will do an inner join to look up the recipe-category associations in
the recipe_category_xref table.

$query = "SELECT recipes.id, recipes.name "


"FROM recipes, recipe_category_xref AS xref "
"WHERE recipes.id=xref.recipe_id " .
"AND xref.category_id=" . $DB->quote($id)
" ORDER BY recipes.name";

$result= $DB->query($query);

4. The results are assigned to URL-encoded variables named recipe_id_O, recipe_name_o,


recipe_id_1, recipe_name_1, etc. We will define a variable named recipe_count that
will tell Flash how many different recipes were sent.

$i = 0;
while (list($recipe_id, $recipe_name) = mysql_fetch_row($result))
echo "recipe_id_" . $i . "=" $recipe_id . "&";
echo "recipe_name_" . $i . "=" . urlencode ($recipe_name) . "&";
s Advanced PHP for Flash

$i++;

echo "recipe_count=" . $i . "&";


mysql_free_result ($result);

5. Next we need to return a list of all the categories that are members of category $id. If we
are searching we will set $id=O and return no categories. Otherwise we will return a list
of category names and IDs in a set of URL-encoded variables.

i f ($search) {
echo "cat_count=O&";
$id = 0;
else {
$query "SELEcr id, name FROM categories "
"WHERE parent id=" . $DB->quote($id)
" ORDER BY name";
$result= $DB->query($query);
$i = 0;
while (list($cat_id, $cat_name)
mysql_fetch_row($result)) {
echo "cat id " . $i . "=" $cat_id . "&";
echo "cat name " . $i . "=" urlencode($cat_name)
"&";
$i++;

echo "cat count=" . $i . "&";

6. Finally, we need to send the name of the category associated with $id and that category's
parent ID to our Flash application.

i f ($id==0){
echo "parent_id=O&category_name="
urlencode($cookbook_name);
else {
$query = "SELEcr parent_id, name FROM categories WHERE id=" .
$DB->quote($id);
Advanced MySQL s

$result= $DB->query($query);
$i = 0;
list($cat_id, $cat_name) = mysql_fetch_row($result);
echo "parent_id=" . $cat_id . "&";
echo "category_name=" urlencode ($cookbook_name
" " $cat_name);

?>

You can test this script in your browser by typing the URL of your script and adding ?id=O to the
end. Your browser should display a string that looks similar to this:

recipe_count=O&cat_id_0=2&cat_name_O=Cakes&cat_id_1 = 1&cat_name_l =Cookies&cat_id_2


=3&cat_name_2=Pies&cat_count=3&parent_id=O&this_category_name=Recipe+Archive

fetch_recipe_details.php

Our final PHP script is really simple. It fetches all of the recipe details for the recipe described
by the variable id that we will pass to the script.

1. We will be including our database class one more time:

<?
require ("database. inc");
$DB = new Database;

2. Then we just select the record we are interested in. We're also going to use the
DATE_FORMAT() function to make the recipe's upload date look a little prettier.

$query = "SELECT name, instructions, author, "


"DATE_FORMAT(upload_date, '%M %e, %Y') " .
"FROM recipes WHERE id=" . $DB->quote($id);
$result =$DB->query($query);
if (list($name, $instructions, $author, $date)
mysql_fetch_row($result)) {
echo "recipe_name=" . urlencode($name) . "&";
s Advanced PHP for Flash

echo "recipe_instructions=" . urlencode($instructions) . "&";


echo "recipe_author=" . urlencode($author) . "&";
echo "recipe_date=" . urlencode($date);

mysql_free_result ($result);
?>

That's it! You can test this script in your browser just like you did the last one. Assuming you have
a recipe with an ID equal to 1, add ?id=1 to the end of the URL for this script. You should see
the URL-encoded version of the recipe in your browser.

That should wrap things up for the PHP side of our application. Now we will put together a Flash-
based interface that will utilize the last two scripts.

cookbook.fla

After all that code you are probably glad to be designing something again! Don't worry, the Flash
side isn't going to be too code heavy. We are going to use some Flash MX objects to save us a
lot of work.

To begin with, we will sketch out


COOKBOOK NAME
how the client-side part of our
cookbook is going to work. We are Welcome text ... CATEGORY &
RECIPE NAMES
going to need to be able to select
categories and recipes so let's use a I SEARCH TERMS II SEARCH I
listbox for that. When a category is
RECIPE NAME
selected, our movie will load that AUTHOR DATE
category's recipes and sub-
categories. When a recipe is RECIPE
RECIPE
selected, our movie will load the PHOTO INSTRUCTIONS
recipe's data and a photo for that
recipe. Here's a sketch of what it
should look like:
Advanced MySQL s

1. Let's start by setting up a few static design elements. You can definitely go crazy here. I'm
just going to add a simple background and some explanatory text.

~ fie) !4 co $5 144

}l
6. <$. ~

Yaye's Cookbook
Weleon"'e 10 Yaya'a Cookboc4:. We'w goc wht'l
)'OI;IwantiOcookl SelectacategofyOtrtldPII
onlhel1gtll.

----------------~------~

2. We are going to use the onClipEvent handler to detect when our Flash movie has received
all of the data from our PHP scripts, this means we need to put everything inside a movie
clip. Select Edit> Select All from the main menu. Then Insert> Convert to Symbol from
the main menu to create the new movie clip. Call it "cookbook" and click the OK button.

Yay' Cookbook

We&curoetoY.'S ~ W~I\"'gol:wt\M
vou~nt,gQIOid ~~Otrocipe

............
=-----

_,_
Convert to Symbol

-~::,ao A""""""m
13

~------------~------~
s Advanced PHP for Flash

3. Next drag a ListBox component onto the stage. This is going to be the recipe and category
navigation box. Select the component and then open the Properties window. Set the
instance name to recipe_list and the Change Handler to recipe_list_handler.

Vaya's Cookbook
WeloornetoYrrya'aCoolcbook. WffvegotWhal
1 ~.
_ __ __ _..__ _ _ _ _"Tp::"'.

YDtJ want lo cook! Selec::l a eate;ory or recipe


ontherighl

J
I

4. Use the Text tool to create textboxes for the category name, recipe name, recipe author,
recipe upload date, and recipe instructions. Then set the text properties appropriately
using the diagram below as a guide:

-----.. .................... '''1


l
'-+-
'
!

I
.... ' ~. ~ '~~
~ -1
L fA1~1t~.:J
1---
Al~..o
~:vr;- r : ~! ~
21 r< I I!
r -
B I ,.'ii
~
'~~I
FCfi!I.L I
(!;

-- C:t.1r-. {

,..... r--:::J
0
l:!l
Vll[m:i""~fiil
HE fii"4"'
r.J-... 21 ,. .ol!J
'!"ljm'i"" 11
._;. r.:l+,.ill...:hol
~
,_r--:::J ..
0
Advanced MySQL s

5. Drag a ScrollBar component onto the right side of the recipe_object text field. Flash
will automatically connect the scrollbar to the text field .

Yaya's Cookbook
...........................................................................

J
....................................................... -----;&;

, ,---------------------.--------~
'
:1. --__I
6. Next to the search input box we need to create a Search button. Let's keep using the built
in components to make this easy. Drag the PushButton onto the stage. Set the Label to
"Search" and the Click Handler to search_handler.

WltmnG 1o v... ,.s


Coal<bool< \\,...,.. aot .....,,
yw own1~ ~ ~ 'iJI"V<J'Y""
CO\ U>e rig!
I ----- - . - - -- - ,
! '~ -- - - - - . - -~ -~ -- ---- .. --- - ' ----- ;

~- ~I

~I
I
ti
- ~-P-Mftil1f11 .1.o
I

li
. !
l I
1-.... ..... .... . ..... -..--. . . ......_,,_., .... ,, _______ ,.......... _,,_ .,,...... ...=a
s Advanced PHP for Flash

7. Now we need to take care of the recipe photo. We are going to be using an empty
placeholder for this movie. Create a small box with the Rectangle tool. Select the box and
then Insert > Convert to Symbol. Now delete the box and go back to the cookbook
timeline. You should have an empty symbol in its place (a white circle). Open the
Properties dialog and name this instance recipe_image.

8. Select the first frame and open the Actions panel. We are going to write two handlers for
the listbox and Search button we dragged onto the stage earlier. We are also going to load
some default data here, so add the following:

category_name = "Yaya's Cookbook";


category_id = 0;
recipe_id = 0;
action= "load_recipe_lis t";
this.loadVariables ("http://www.cara mbadesigns.com/p hp_for_flash_ch_ S/
fetch_categories_ and_recipes.php?i d=O");

function search_handler(co mponent){


category_id = -1;
Advanced MySQL s

recipe_list.removeAll();
var tmp = new LoadVars();
tmp.search = search;
action= "load_recipe_list";

this.loadVariables("http://www.carambadesigns.com /php_for_flash_ch_S/
fetch_categories_and_recipes.php?" add tmp.toString());

function recipe_list_handler(component){
d = recipe_list.getSelecteditem() .data;
i f (d[O] == 0) {
action= "load_recipe_list";
category_id = d[l];
recipe_list.removeAll();

this.loadVariables("http://www.carambadesigns.com /php_for_flash_ch_5/
fetch_categories_and_recipes.php?id=" add category_id);

i f (d [0] == 1) {
action= "load_recipe_details";
recipe_id = d[l];

this.loadVariables("http://www.carambadesigns.com /php_for_flash_ch_5/
fetch_recipe_details.php?id=" add recipe_id);

The search_handler function passes a URL-encoded version of the search term entered
by the user to our fetch_categories_and_recipes.php script when the button is
clicked. The recipe_list_handler function checks the selected recipe item's data field
for an array. If the first term in the array is zero then it loads the category specified by the
second term of the array. If the first term of the array is 1 then it selects a recipe based
on the second term of the array. We are using arrays to maximize the amount of
information we can store and retrieve in the listbox item's data field. In this case we are
using the data field to store whether the item is a category or a recipe and its ID number.
s Advanced PHP for Flash

9. Finally, we need to go back to the main timeline and create the onClipEvent handler.
The onClipEvent needs to handle two kinds of data that we will retrieve:

Category and recipe names and IDs

Recipe details

We determine what kind of data we have loaded by checking the value of action. If the user
clicked a category entry then action will be set to load_recipe_list. We would then tell our
movie to clear the recipe_list, add the categories and recipes that were just loaded, and hide
or clear the previously selected recipe's details.

If action has been set to load_recipe_details then we load the appropriate recipe image and
make sure that it is visible. That's a lot of stuff to take care of but I think you will see the code
for it isn't too bad:

onClipEvent (data) {
i f (action == "load_recipe_list")
category_name = current_name;

II Clear the recipe list


recipe_list.removeAll();

II Add a previous category item when appropriate


i f (category_id != 0) recipe_list.additem(" .. <previous
category>", new Array(O, J;>arent_id));

II Add categories to the recipe list


for (i=O; i<cat_count; i++) {
recipe_list.additem(eval("cat_name_" add i) add "
<category>", new Array(O, eval("cat_id_" add i)));

II Add recipes to the recipe list


for (i=O; i<recipe_count; i++) {
recipe_list .additem(eval ("recipe_name_" add i),
new Array(l, eval ("recipe_id_" add i)));
Advanced MySQL s

II Make the last recipe shown invisible


recipe_image._visible = 0;
recipe_scrollbar._visible 0;
recipe_name 1111.
I

recipe_date ""I

recipe_object.text 1111.
I

recipe_author = 1111.
I

if (action == "load_recipe")
II Make the recipe stuff visible again
recipe_image._visible = 1;
recipe_scrollbar._visible = 1;
recipe_object.text = recipe_instructions;

II Load the photo for this recipe

loadMovie("http:llwww.car ambadesigns.comlphp_for_ flash_ch_Siimagesl"


add recipe_id add ".jpg" recipe_image);
I
s Advanced PHP for Flash

Our movie is functionally complete. If you test it you should be able to browse through the
categories and recipes that we created with the admin tools.

-"

r
.........
............... CIIcll8lllai.'IW'etlllwtlll: - "'Jif"""'JUiltP'f
JW.Cba:df--EafiiPY~ft!Ctre CMtliD Cftip.~lllli:U "'4.~ ~
OOWbo!WCKW
~lbi!C;IIJ -CI!Mtt

..._
.-c..o..
r---~~~:=~~, ~~

--
:.uWIINd......

tlr.l _ _ . . _ .

,."" ............ ....,.__..


)C4M~Iklt.J

~~~..,.UtrJ.d4 ... _, ........... t.llll


c:"'**hhd.."'*'IIIJ6.,.,~w~to..,.,.....,,.._ lrwt
.._. """'_.".,..._,_ ,._.,.,~M io .... tt... ~
O'I'OI'b~ Mol:tb.4JIIlhii!:IIRJ#ftll$d.wJHII(liiiiM.
~~ ...... '*'11i~lnljiliU to 6..,.., . . . . .Cidit
Advanced MySQL s

Our cookbook is looking great so far, but it is only the beginning. I can think of a lot I would like
to add at this point, such as:

Recipe photo thumbnails.

Removing images from the image directory if they are removed from the database.

Browsing recipes based on the upload date.

Another exercise for the reader might be to implement a search system based on the LIKE
operator we discussed earlier and note the differences from the full-text implementation we
built here. For a small database, a LIKE-based search would find a lot of matches that MySQL's
full-text search doesn't. But for a larger database, full-text searching will perform much better.

Summary
In this chapter we covered a lot of ground. You should have a new arsenal of tools that can be
used to approach any number of problems. In full, we covered:

How to create good indexes.

How to join tables in a number of useful ways.

Searching text files with LIKE, REGEXP, and full-text searching.

Date manipulation using built in MySQL operators.

Finally, we built a fully functional online cookbook with a number of interesting bells and
whistles. The cookbook used a lot of the techniques we developed earlier in the chapter and is
a good general framework for a number of similar tasks.
D D
OJ

Sockets
0
rn 0
0
0 0

What we'll cover in this chapter:

In this chapter we are going to introduce you to sockets in PHP. At first, sockets may
sound like the realm of "hard-core" developers, but they are fairly easy to use once you
get the hang of them. Sockets allow you to connect and communicate with servers
directly. While most people associate them with chat applications, there are many more
E9
uses to sockets that we will explore in this chapter. c
0
This chapter will cover the following areas:
c
Basics of Sockets

c
~
Whols Flash Example

SMTP Primer

POP Primer

Flash Email Client

co
EB
0 0]

0 ~
6 Advanced PHP for Flash

Socket basics
Let's start out with some basic socket functions to get you started.

fsockopen()
Sockets are opened in PHP using the fsockopen () function. A description is given below:

int fsockopen( string hostname, int port [, int erma [, string


errstr [, float timeout]]])

fsockopen () returns a file pointer that you will use in subsequent file functions. For example,
when opening a socket connection you will set a variable equal to the return value of the
fsockopen function. If the function returns false, the connection failed. Otherwise the
function will return the file pointer. Take the following code snippet:

<?

$remoteFile = fsockopen ("www.mysite.net", 80, $errNo, $errString)

if (!$remoteFile) {
// an error occurred
else {
//start using $remoteFile

?>

If everything goes as planned we will start using the $remoteFile pointer to interact with the socket.

pfsockopen()
Works exactly like fsockopen () except file pointers will remain open even after the script exits.
The "p" stands for persistent.
Sockets 6

fclose()
This function closes a file open by fsockopen (). It returns true on success and false on
failure.

bool fclose ( int fp)

fgets()
This function returns a string of a certain length from a file pointer.

string fgets ( int fp [, int length])

This function stops reading when the passed-in length (-1 bytes) has been read, a newline is
encountered or the file ends. In PHP 4.2, the length parameter is optional. If no length is
specified it defaults to 1024 bytes of text.

Ifyou are developing software for multiple operating systems you


may have problems with fgets () . Operating systems have
different ways of handling new/ines, so software that works on a
PC may not work on a Unix machine. A safer alternative is
fread (). which is explained below.

fread()
This is a safer read function than fgets () . which performs a straight binary read with no server-
specific problems.

string fread ( int fp, int length)

Reading stops when length bytes have been read or the End-Of-File is reached.

fgetss()
This function is similar to fgets () except that it strips out HTML tags.

string fgetss ( int fp, int length [, string allowable_tags])

You can use the optional third parameter to specify tags that should not be stripped.
6 Advanced PHP for Flash

fputs()
This function writes to a file pointer.

int fputs ( int fp, string str [, int length])

Note that the length parameter is optional. If the parameter is omitted, the entire string will be
written.

Note: When writing large amounts of text, the function is much


more stable when given an actual length.

Feof()
This function tests if the file pointer reached the End-Of-File. Returns true if EOF, false
otherwise.

Simple WhoiS Flash MX example


Now that we have a basic understanding with how to pass and get data with PHP sockets, lets
create a quick example showing how to query the Network Solutions WhoiS database from Flash
MX through PHP.

First off we will create the back-end PHP file that Flash MX will communicate through.

Whois.php

<?
$filepointer fsockopen("whois.network solutions.com", 43, $errno,
$errstr, 30);

Here we are opening the socket connection to Network Solution's WhoiS database. Note that we are
connecting using port 43, the WhoiS port.

if (!$filepointer) {
echo "&Resultinfo=";
Sockets 6

echo "$errstr ($errno)";


} else {
fputs($filepointer, "$domainName\r\n");
echo "&Resultinfo=";
while (!feof($filepointer)) {
echo urlencode(fgets($filepointer,128));

fclose ($filepointer);

?>

If the socket connection opens successfully, we write the variable $domainName to the server
($domainName will be sent from Flash). After writing the domain name to the socket, we echo
out our empty Resultinfo Flash variable back to the page. We then create a small while loop
that reads every 128 bytes of text from the socket until the end of file and writes the read text
to the page URL-encoded. After the loop finishes, the code closes the file pointer.

urlencode () is needed because Flash reads URL-encoded variables with sendAndLoad which
we will use later.

Whois.fla
The Flash file for this example will allow
the user to enter the domain name they Whols Socket Example
wish to query and will provide a text area
to show the result. First create a small
plea~<~ entw v.'8b&ile Mme: I
e.g. ~ l wfl'ltlWJii . com'"
I I S..bnol I
text field where the user will enter the
~
domain name. Give it an instance name
of "domainName". Then, create a larger
multiline text area to show the results.
Give this text area an instance name of
"Result". Put a scrollbar next to the
Result text area and give that an instance
name of "ResultScrollbar". Put a small
submit button next to the domainName
text field. When finished, your Flash file
should look like the example shown
!'";
here.
6 Advanced PHP for Flash

Now that the Flash elements are all in place we need to add some simple ActionScript to interact
with the PHP file we just created. Put the following code in Frame 1 on the ActionScript layer of
the main timeline.

_root ActionScript

Result.onChanged = function() {
ResultScrollbar . onTextChanged()
};

This function tells the scrollbar to run the onTextChanged () scrollbar event every time the Resu It
text field contents are changed. Without this function, the scrollbar would not re-draw the scrollbar
with the introduction of new text. The following code should go on the movie clip timeline.

submit Actionscript

this.onPress = function()
_parent.Result.text = Jill
,
a

var loadlnfo = new LoadVars()


loadinfo.domainName = root.domainName.text
loadinfo.sendAndLoad("wh ois.php", loadinfo, "GET")
loadinfo.onLoad = function() {
_parent.Result.text = loadinfo.Resultinfo;

First this function empties the result text in case there was a previous Whols call. Next, it creates
a new LoadVars () object. adds the domainName that the user typed in, and sends that data to
the who is. php file we previously created. When Flash fires the onLoad event (data has come
back), it puts the Resultinfo variable text in the Result text field.

Publish the file and you should be all set. If everything worked according to plan you will be able
to enter a URL, hit submit. and see the Whols information for that website.
Sockets 6

Note: By using the Whols website you are bound to the terms of
use as posted on www.networksolutions.com.

Email primer
Before we embark on creating an email client, we need to learn a little about the protocols used
to communicate with the email sever. The first protocol we will investigate is the Simple Mail
Transfer Protocol (SMTP). SMTP is used to send email messages. How hard can something be with
"Simple" in its name? SMTP is fairly straightforward and easy to use. SMTP is what is called a line-
oriented protocol. This means that both your client and the server talk back and forth with
simple character strings that end with a carriage return.

Sending email with SMTP


Sending email to a server is relatively simple. There are five basic commands that you need to
send to an SMTP server.

HELO - This is the first command sent from your client. After the HELO command you tell the
server which domain you are coming from. For example, the following command tells the server
that I'm going to send a message from swfnews.com:

HELD swfnews.com

MAIL FROM - The next command you issue lets the server know what email address you are
sending the email from. The following code lets the server know you are sending the email from
the address info@swfnews.com:

MAIL FROM: info@swfnews.com

RCPT TO- This command represents the recipient of the email you are sending. This command
is structured like the Mail From command.

RCPT TO: billyourserver.com


6 Advanced PHP for Flash

DATA - This is the command that holds the "meat" of your email. You will pass this command
the body of your email message. Take the following example,

DATA
Hello, isn't email easy ?

Note that the server interprets the email body text as ended when
it finds a single "." on a line all by itself.

QUIT - This is the last command you will send the server; it lets the server know you are done
and the connection ends.

SMTP response:
After entering a command, the SMTP ser~r viii respond with a one-line response. Reponses start
with a 3-digit status number letting the 1l9,necting program know the status of the command
request. The number is then followed by a status description. For example, after entering your
MAIL FROM command, the SMTP server will respond:

250 infoswfnews. com... Sender ok

For those in a hurry, 220 is the successful response code for the initial connection and the HELO
command. 250 is the successful response code for the MAIL FROM and RCPT TO command. 354
is the code for the DATA command and 221 is for the QUIT command. For more information on
response codes please check out http://www.rfc.net/.

Retrieving email with POP


Now we will turn our attention to retrieving email from the server. Retrieving email is a bit more
complicated than sending, but it's not too hard. There are two methods of retrieving emails from
a server, POP and IMAP. The only real difference between the two, as far as the end user is
concerned, is that IMAP servers keep email messages on the server while POP email is delivered
to the client upon checking their mail; afterwards it is deleted from the server.
Sockets 6

In this example we will be concentrating on the POP method of retrieving email. Like sending
email, receiving email uses some simple commands to talk with the server.

USER - The username for your email account.

USER joejohnson

PASS -The password for your email account.

PASS rnypassword

LIST- This command responds all the new messages sent to you. They are sent with a message
number and the size of the email message in bytes. Sample response:

1 1983
2 745
3 614

Here we have three email messages addressed to us that we have not yet viewed. Note that a
single "." on a line by itself signifies the end of the list.

RETR- This command stands for retrieve. You pass it the message ID of the email message you
wish to view. For example

RETR 2

would show you your second email message.

QUIT- This works exactly like QUIT in sending email, it tells the server you are finished and ready
to disconnect.

Flash email client


Now that we have a good baseline knowledge of sockets and email protocols we can create a
simple Flash email client. A Flash email client is often considered one of the "holy grails" of Flash
6 Advanced PHP for Flash

development. This example client should get you well on your way to creating an amazing Flash
email client.

EmailClass.php

<?

class Email

var $to = I I ,
o

var $from I I

var $cc = I I ,
o

var $bee = I I , o

var $subject = I I , o

var $body = I I , o

var $smtp_host I I
,
o

var $smtp_port 25;

var $pop_host I I
, o

var $pop_port 110;


var $usemarne I I
, o

var $password I I
, o

var $emailResponse = I I
,
o

var $emailData = I I , o

var $socket = 0;
var $response_msg I I
,
o

var $numMessages = 0;
var $emailMessages = array();
var $emailHeaders = array();
var $errMessage;
Sockets 6

Here we are setting all the variables we will be using to the default value. Please note the SMTP
and POP port values.

function connect($host, $port)

$this->socket = fsockopen($host, $port, &$err_no, &$err_str);

i f (! $this->socket){
$this->errMessage 'Failed+to+connect+to+the +server';
return false;

$this->response_msg fgets($this->socket, 1024);


return true;

This is a pretty standard connect function and one that we have used a fair number of times in
this chapter so far. The only real difference in this case is that we are passing to this function the
$host and $port number to allow reuse between the SMTP and POP ends.

function sendData($cmd, $arg=' ')

if(!$this->socket) {
$this->errMessage = 'Failed+to+connect+to+the +server';
return false;

switch ($cmd)

case "HELO":
fwrite($this->socket, "HELO $arg\r\n");
$this->response_msg fgets($this->socket, 1024);
break;

case "USER" :
fwrite($this->socket, "USER $arg\r\n");
$this->response_msg = fgets($this->socket, 1024);
6 Advanced PHP for Flash

break;

case "PASS" :
fwrite($this->soc ket, "PASS $arg\r\n");
$this->response_m sg fgets($this->sock et, 1024);
break;

case "LIST":
fwrite($this->soc ket, "LIST \r\n");
$this->response_m sg fgets($this->sock et, 1024);
$this->response_m sg fgets($this->sock et, 1024);

if ($this->response_m sg == ".\r\n") {
$this->emailRespo nse =
"sorry+there+are+n o+new+messages";
$this->numMessag es = 0;
$this->emailData = "nothing";
} else {
$this->emailRespo nse
"Email+Downloade d+Please+Press+Cl ose";

i f ($this->response_m sg != ". \r\n")


$this->numMessag es = $this->numMessag es + 1;
$this->response_m sg = fgets($this->sock et,
1024) i

break;

case "RETR":
fwrite($this->soc ket, "RETR $arg\r\n");
$this->response_m sg fgets($this->sock et, 1024);
$this->response_m sg fgets($this->sock et, 1024);

$begString = "&email$arg=";
$tempString = '';
Sockets 6

while ($this->response msg != ".\r\n") {


$tempString = "$tempString $this->response_msg";
$this->response_msg = fgets($this->socket, 1024);

$tempString = urlencode($tempString);
$this->emailData = "$begString$tempString";
break;

case "MAIL":
fwrite($this->socket, "MAIL FROM: $arg\r\n");
$this->response_msg fgets($this->socket, 1024);
break;

case "RCPT":
$to_emails = explode (", ", $arg);

foreach($to_emails as $email) {
fwrite($this->socket, "RCPT TO: $email\r\n");
$this->response_msg = fgets($this->socket, 1024);

break;

case "DATA" :
fwrite($this->socket, "DATA\r\n");
$this->response_msg = fgets($this->socket, 1024);

fwrite($this->socket, "$arg\r\n" . "" . "\r\n");


$this->response_msg fgets($this->socket, 1024);
break;

case "QUIT":
fwrite($this->socket, "QUIT\r\n");
$this->response_msg fgets($this->socket, 1024);
break;
6 Advanced PHP for Flash

default:
$this->errMessage 'Unrecognized Input';
return false;
break;

return true;

While this function may look intimidating, it's actually pretty simple to follow. This function will
be called whenever we need to send a command to the server. For example, when we discussed
the five basic SMTP commands, we introduced you to a command named "HELO". When this is
sent to the SMTP server, it lets the server know you will be sending more data and wish to send
a message.

This function knows all the possible commands that can be sent to the server, and makes sure it
always sends the correctly formatted text. If you take the "HELO" command for example, you
will see that PHP is writing "HELO $arg" and an endline to the server. The $arg variable stands
for arguments that are passed to this function. If we used this from swfnews.com, "HELO
swfnews. com" would be written to the server.

Note: $this->response_msg = fgets ($this->socket,


1024); is seen often in the code. This line is simply reading the
response from the server. A more robust solution could check
the response code here against the list of all responses to
respond appropriately.
Sockets 6

function send()

$this->headers[] "From: $this->from";


$this->headers(] "Cc: $this->CC";
$this->headers[] "Bee: $this->bcc";

if(!$this->connect($this->smtp_host $this->smtp_port))
1

return false;
if ( ! $this- >sendData ( "HELO" $GLOBALS ["SERVER_NAME"] ) ) return
1

false;
if (! $this->sendData ("MAIL" $this->from)) return false;
1

if(!$this->sendData("RCPT" $this->to)) return false;


1

$this->headers[] "To: $this->to";


$this->headers (] "Subject: $this->subject";

if (! $this->sendData ("DATA" implode ( "\r\n" $this->headers)


I I

."\r\n\r\n" . $this->body)) return false;


if (! $this->sendData ("QUIT")) return false;

fclose($this->socket);

return true;

This function sends an email through SMTP. It should be fairly self-explanatory; it goes through
the normal SMTP process of sending an email by calling the SMTP commands in order. It passes
the command and any argument to the sendData () function we just created.

function receive()

if(!$this->connect($this->pop_host $this->pop_port)) {
1

$this->errMessage = 'Can+not+connect+to+pop+server';
return false;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
6 Advanced PHP for Flash

i f (! $this->talk ("USER" 1 $this->username)) {


$this->errMessage =
'Server+does+not+recognize+username';
return false;

if (! $this->talk ("PASS" 1 $this->password)) {


$this->errMessage = 'Incorrect+Email+Password';
return false;

i f (!$this- >sendData ("LIST") ) return false;

$tempVar = 0;

while ($tempVar < $this->numMessages) {


i f (! $this->sendData ( "RETR" I ( $tempVar + 1))) return
false;
$tempVar = $tempVar + 1;

i f (!$this- >sendData ("QUIT") ) return false;


fclose($this->socket);
return true;

?>

This function is called to receive emails through POP. Take note of the while loop in the center
of the function. It calls RETR for every message it finds from the LIST call.

SendEmail.php

<?

include ("./Email Class. php") ;


Sockets 6

$mail =new Email();


$mail->smtp_host = $EmailSMTP;

$mail->to = $Emai1To;
$mail->from = $Emai1From;
$mail->CC = $EmailCC;
$mail->bcc = $EmailBCC;
$mail->subject = $Emai1Subject;
$mail->body = $EmailBodyText;

if($mail->send()) {
echo("&Resultinfo=Email+Sent+Successfully.
Please+press+close_to+continue. ") ;
else die("&Resultinfo=Error+while+attempting+to+send+e mail. $mail->
errMessage. Please+press+close+to+continue.");

First we create a new class item Email () that we made in the previous file. We set the SMTP
and other email information equal to what Flash passes in. We then attempt to send the email
message and respond with an appropriate message to Flash for display.

ReceiveEmail.php

include("./EmailClass.php");

$mail = new Email();


$mail->pop_host $EmailPS;
$mail->username $EmailUN;
$mail->password $EmailPW;

if($mail->receive()) {
echo("&Resultinfo=$mail->emailResponse&numMessage s=$mail->
numMessages&emailData=$mail->emailData");
} else

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
6 Advanced PHP for Flash

die("&Resultinfo=Error+while+attempting+to+receive +email+$mail->
errMessage");
?>

Again we create a new class item Email() that we made in the previous file. We set pop_host,
username, and password equal to the values Flash passes in. We then attempt to receive ()
the email message and send an appropriate message back into Flash for display.

Upon receiving an email, this program will respond something like:

&Resultinfo=Emails+Downloaded+Please+Press+Close&n umMessages=l&emailD
ata=&emaill=message+l+contents+here

Please note.:

The emailData variable is simply a placeholder for additional values; Flash will eventually
read the email# values.

email# values will be URL encoded and will include email header information and not
simply the message itself.

EmailClient.fla
The Flash email client will use tabs for
each mode of use. The three tabs will be
"Setup", "lnbox" and "Compose". Each
tab will be "active" on its own frame. You
- -
Email Client

can make the tabs as elegant or simple


as you wish. We went with simple Flash
buttons. Make frame 1 of your movie
completely empty and put the tabs on
frames 2, 3, and 4 for "Setup", "lnbox"
and "Compose" respectively.
Sockets 6

After you are finished, your movie frames should


look something like this.

Frame 1 is where we will set up the variables used in


the program and place functions that we will use later.

Frame 1 AS

Email TO 1111 .
I

EmailCC 1111.
I

EmailBCC = "";
EmailSubject = "" I

EmailBodyText = "" . I

EmailSMTP 1111.
I

Email From 1111.


I

EmailPop = "";
EmailUserName ,
1111.

Email Password "" I

First we initialize all the variables in the program to nothing.

function switchTab(mcName)
if (mcName == "SetupTab")
gotoAndStop(2)
else if (mcName == "InboxTab")
gotoAndStop (3)
else {
gotoAndStop(4)
6 Advanced PHP for Flash

Next we create a very simple rudimentary function to move from tab to tab. Each tab we will
create will be given an instance name. Every time a tab is selected, the instance name will be
passed to this function to determine what frame to stop on. Remember that frame 2 is the email
setup, frame 3 is the inbox, and frame 4 is where you compose your email.

function sendMessage() {
ComposeDialog.Result.tex t 1111.
I

var loadinfo = new LoadVars()


loadinfo.EmailTo EmailTo
loadinfo.EmailCC = EmailCC
loadinfo.EmailBCC = EmailBCC
loadinfo . EmailSubject = EmailSubject
loadinfo . EmailBodyText = EmailBodyText

loadinfo . EmailSMTP EmailSmtp


loadinfo . EmailFrom Email From

loadinfo. sendAndLoad ( "SendEmail .php" 1 loadinfo 1 "GET")

loadinfo.onLoad = function() {
ComposeDialog.Result.tex t loadinfo.Resultinfo;

EmailTo ""
EmailCC ""
EmailBCC = ""
EmailSubject = ""
EmailBodyText = ""

This is the function we will use to send the email to our SendEmail.php script we made earlier.
First we create a new LoadVars object and load all the variables from our Flash file into it. We
then issue a sendAndLoad function to send the variables to our PHP file and wait for the
response. Note: we will discuss the compose dialog in a little bit; basically it is a "modal" type
Sockets 6

dialog box that will hold the response. Keep in mind that in this script we first blank it out and
then load it with the response from the server.

function getMessages() {
var loadinfo =new LoadVars()
loadinfo.EmailUN EmailUserName
loadinfo.EmailPW = EmailPassword
loadinfo.EmailPS = EmailPop
loadinfo.ranNum = getTimer()

ReceiveDialog.Result.text = "Sending Login Information. Please


wait, this may take a few seconds.";
loadinfo. sendAndLoad ( "ReceiveEmail. php", loadinfo, "GET")

loadinfo.onLoad = function() {
ReceiveDialog.Result.text = loadinfo.Resultinfo;

for (var i=O; i < loadinfo.numMessages; i++) {


arrEmailMessage[arrEmailMessage.length] = new
EmailMessage (eval ( "loadinfo. email" + ( i + 1) ) )

BuildList ()

This function is called to grab all the new messages off the POP server. Here, we create a new
LoadVars and populate it with the POP address, username, and password, and SendAndLoad ()
the data to ReceiveEmail.php. When the data comes back we grab the number of incoming
messages, and then create that many new instances of our EmailMessage class.

EmailMessage = function(strBody)
this.strBody = strBody;

arrEmailMessage new Array()

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
6 Advanced PHP for Flash

Next we make an object called EmailMessage, which will hold the contents of an email message
that you receive. We then create a new array called arrEmailMessage, which will hold a
dynamic number of EmailMessage objects.

Setup tab - frame 2:


This tab is where the user will enter their
Email Client
email setup information. Information to ..... '""""
be gathered includes basic SMTP and
Sending Em3il
SMTP..-r:
S~ot~up~~~~~
POP-user email information. VCIIrEmailkkfA:tu.:

Retrieving Email Setup

,..,...._~
Uwlloaflllll:

PotWWfd;

Set the variables on the text fields to the following values:

EmaiiSMTP

EmaiiFrom

EmaiiPop

EmaiiUserName

EmaiiPassword

Frame Actionscript:

stop()
Sockets 6

lnbox tab - frame 3:

-
This frame displays the emails received
Email Client
from the server. It utilizes the listbox ..... ,.....
component to display the list of Reeelve'l=m:tll I RC<NE I
subjects. Upon clicking a subject, the
user is shown the body for that message.
I J.

}.,

Frame Actionscript:

BuildList = function()
for (i=O; i < arrEmailMessage.length; i++) {
listEmail.additem("Email" + (i + 1), i)

This function loops through the arrEmailMessage array, and for every item, adds that object
to the listEmail listbox. Note that the label is the email number from the server and the data
item is the array index number.

ListBoxSelection = function()
var currentitem = listEmail.getSelecteditem() .data;
txtEmailMessage.htmlText = arrEmailMessage[currentitem] .strBody;

This function is called on the change handler of the listbox. It grabs the currently selected data
number and displays the EmailMessage object's information.

BuildList ()
stop()
6 Advanced PHP for Flash

To build the list on every trip to this frame we call the BuildList () function. We then issue a stop () .

Receive button AS:

on (release) {
ReceiveDialog.gotoAndStop(2)
getMessages ()

When the user presses the receive button, we move the Recei veDialog popup to the second
frame and call the getMessages () function we created earlier.

Receive dialog
When the user hits receive we want to show
some feedback so they know if any Retreiving Email: Please Wait
messages were received. We decided to go
with the concept of a "modal" dialog box
here. Because Flash does not inherently
, ...................._._____..... ..:.......:........._
..._._...
support "modal" boxes we had to create
one from scratch.

ClOSE

The idea here is simple. On frame 1 of this movie clip, nothing is shown. This movie clip stays on
frame 1 while the user is entering information to mail. Once the email is sent, the "receive" button
moves the play head to frame 2 where the user is shown a "dialog box" that seems to float over
Flash. To prevent the user from clicking in the background, we made a giant empty button "shown
in blue" behind the dialog box. The user must click on the close button to continue.

Make a large multiline textbox in the center of your dialog box on frame 2 and make the instance
name "Result". lf you remember this code from before:

ReceiveDialog.Result.text = loadinfo.Resultinfo;
Sockets 6

The textfield you just made is where the end result of the email sending will display. It will either
tell the user that email was received successfully or display an error message returned by the server.

The close button has the following ActionScript on release to simply "close" the dialog box:

gotoAndStop (1 l

Compose tab - frame 4


This frame/tab is for sending email. Here
Email Client
we will prompt the user for the recipient ..... ,...... ""'-
of the email, optional CC, and BCC Compo~ Email
fields, a subject and a body text. Please TO:

note that the "empty" movie clip circle


=
ace:
SUBJCT!

is the compose dialog box which we will


~
create a little later.

R
I ...., I
Set the variables on the text fields to the following values:

EmaiiTo

EmaiiCC

EmaiiBCC

EmaiiSubject

EmaiiBodyText
6 Advanced PHP for Flash

Send button
The send button here simply moves the ComposeDialog (which we will create in a second) to
frame 2, and calls the SendMessage function we created earlier.

on (release) {
ComposeDialog.gotoAndStop(2)
SendMessage ()

ComposeDialog
The ComposeDialog is an almost exact copy of the Recei veDialog created earlier. The only
difference between the two is the title text. Here the title text is "Sending Email. Please Wait",
while before it was "Receiving Email. Please Wait".

Note: It would make sense to combine the two dialog boxes and
make the title a dynamic text field. We wanted to make this
example as easy to follow as possible, but if you feel you have a
good grasp of what's going on feel free to make the change.
Sockets 6

~ I

r:o
l

BC.C
Sending Email: Please Wail

.:..........................................................................................:

. .
.. . . . . . . . . . . . . . . . . .. . . . . . . .. . . . .. . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . .. .. . . . . . . . . . . . .. . . .1

CLOSE

Summary
Hopefully this chapter opened your eyes to the potentials of sockets in PHP. Using Flash MX as
the presentation layer, sockets allow the creation of powerful dynamic applications.
_ ~ D D ...... ...... 0....

PHP and
XML
T r-
-~""""- rr: fnCn I
I I tJ
-h -"""" [j
D ~
- _j -o
L_r-
D [p D
- Elo~ Elo
~ _._ ~p ~D
I """" D
::~ ~
B
c-
r---.

I
I
r-
J I What we
B: [ _j

J
An introduction to XML and how it is used

Creating a simple Flash drop-down menu and an XML file to populate it

Adding a MySQL database to our application using PHP

D
D

~Et
D
~ r-f:D
0:
7 Advanced PHP for Flash

Unless you've been hiding under a stone, you'll know all about the XML revolution currently
coursing through the veins of the Internet. Where and when to use XML is something that has
been, and will continue to be discussed, inside forums and on message boards all over the
development community for a long time to come.

In this chapter we'll take a look beyond the hype that surrounds XML and put it to good use by
creating a dynamic menu system using XML as the source for our menu structure. Once you're
comfortable with using XML in conjunction with Flash, we'll step things up a gear in the
manageability stakes by adding a MySQL database and some PHP script.

A closer look
Let's start by taking a brief look at what XML is. Below is a simple example of an XML document:

<?xml version="l.O" encoding="iso-8859-1"?>

<XMLmenu>
<menu id="About">
<submenu id="me"></submenu>
<Submenu id="you"></submenu>
<submenu id="us"></submenu>
<submenu id="world"></submenu>
<submenu id="company"></submenu>
</menu>
</XMLmenu>

It looks like plain old HTML right?

Absolutely, XML is very similar in many ways to traditional HTML but it's far more structured
than HTML.

HTML has traditionally focused on a document's layout; adding new tags to the standard to
provide additional formatting functionality as required. XML, however, is focused on document
structure using additional stylesheets for formatting and layout. This means that unlike
traditional HTML, XML content can be used within a multitude of systems supporting the XML
standard with style and layout applied as and when required. This separation of structure from
PHP 8c XML 7

layout makes XML very powerful, especially when dealing with output to a multitude of browsers,
platforms, and devices.

Also, unlike HTML, with XML, we're no longer restricted by a list of predefined tags and
attributes. As long as we ensure our document remains 'well formed' we can create all the tags
and attributes our document structure requires.

Let's take a closer look at our simple XML file.

<?xml version="l.O" encoding="iso-8859-1"?>

The line above is the XML declaration. It tells whatever application is reading it that it's an XML
document and should be treated as such. The version attribute is self-explanatory and the
encoding attribute specifies the character set used in the XML data.

The following line in the code is the root or parent node:

<XMLmenu>

Every XML document must contain a root node that contains all the other XML data. Similar in
function to the <H'I'ML> tag in an HTML document, it must be the first node in the document
and, as with all XML tags, it must be closed at the end of the document.

</XMLmenu>

In HTML there are various ways of writing the same thing, with a variety of results dependent on
the chosen browser and its conformity to the HTML standard. For example, in HTML you don't
always have to close all the tags you open, and in most cases the browser will make an educated
guess at where it thinks the tag should be closed. XML has strict rules about opening and closing
tags. All tags that are opened must be closed and all tags must be nested correctly; the
overlapping of tags, while commonplace in HTML, is not allowed within XML.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
7 Advanced PHP for Flash

<menu id="About">
<Submenu id="me"></submenu>
<submenu id="you"></submenu>
<Submenu id="us"></submenu>
<Submenu id="world"></submenu>
<Submenu id="company"></submenu>
</menu>

This shows correctly nested tags. The <submenu></submenu> tags are all nested within the
<menu> and </menu>, and each <submenu> tag has been closed before the next is opened.

Also, we see various values stored within the nodes, for example, id= "me" . These are called node
attributes and are used for storing multiple values in a single node. The id attribute is
particularly handy because it allows unique identification of a node within the XML document.
This technique is very useful and we'll see it in action later in the chapter.

So far we've briefly covered what XML is, where XML and HTML differ, and the basic structure of
an XML document. I don't want to spend time covering XML in any great detail because there is
a wealth of books on the market that deal solely with XML. Check out Flash XML StudioLab, ISBN
1-903450-39-X, for all the information you'll need to perform the marriage of XML with Flash.

What can we do with XML?


There are thousands of uses for XML documents: News, Guest books, Recipes... the list is endless.
We're going to build a simple XML file and use it to populate a Flash drop-down menu.

Our menu will consist of menu headings, each with a number of submenu items that will link to
various URLs. We could of course just launch Flash and create a drop-down menu, but then we
would need to know in advance what menu headings and sub-items were required - not a
particularly practical method of working. Each time we needed to change any of the menu items
we would have to open the source FLA file, make the changes to the menus, and then re-publish
the file.

To eliminate the need for constant editing of Flash source files, we need to generate our menu
dynamically and that's where XML comes in.

Basically, what we are going to do to create our drop-down menu is:


PHP 8c XML 7

Create the menu structure in an XML file.

Build the menu in Flash.

Read the XML file into Flash to populate our menu.

Where to start?

Before we can do anything else, we need to create a simple XML file that reflects the menu
structure we need.

Let's start with our XML declaration line:

<?xml version="l.O" encoding="iso-8859-1"?>

Next we'll define our root node, which will surround the bulk of our data, remembering that
each time we open a node tag we also close it.

<XMLmenu>

</XMLmenu>

OK, we now have all the required components of an XML document, but it's not much use
without our menu data so let's create some menu headings.

Our menu headings are children of our root node and therefore we need to nest each heading
between the root node tags. We also need some submenu items to link to our various websites,
and, as these are children of the heading nodes, we need to nest them within the heading
opening and closing tags:

<XMLmenu>
<heading id="Book Stores">
<Submenu id="amazon" link="www.amazon.com"></submenu>
</heading>
</XMLmenu>

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
1 Advanced PHP for Flash

The code describes a menu with a heading Book Stores and a submenu item called amazon
with a link attribute pointing to http://www.amazon.com.

Before we dive into creating the Flash menu let's create a few more headings with submenu
items. When you're happy with the menus and items you've added, save the file as menu.xml.

Here's one I made earlier!


To make this a bit easier for you, I've already created an XML file for you. Feel free to use it or
create your own.

<?xml version="l.O" encoding="iso-8859-1"?>


<XMLmenu>
<heading id="Book Stores">
<Submenu id="amazon" link="http://www.amazon.com"></submenu>
<Submenu id="Books Online" link="http://www.bol.com"></submenu>
</heading>
<heading id="Games">
<Submenu id="Quake" link="http://www .quakearena.com"></submenu>
<submenu id="The Sims" link="http://www.thesims.com"></submenu>
</heading>
<heading id="Software">
<Submenu id="Flash" link="http://www.macromedia.com"></submenu>
<submenu id="mySQL" link="http://www.mysql.com"></submenu>
<submenu id="PHP" link="http://www.php.net"></submenu>
<submenu id="Apache" link="http ://www . apache . org"></submenu>
</heading>
<heading id="Flash Sites">
<submenu id="Ultrashock"
link="http://www.ultrashock.com"></submenu>
<submenu id="Flashkit" link="http://www.flashkit.com"></submenu>
<submenu id="were- here" link="http://www.were-
here.com"></submenu>
</heading>
</XMLmenu>

We have our sample XML file so now we can build our menu in Flash. Making the menu after we
have made the XML may seem a little strange at first, but in reality what normally happens is that
PHP 8c XML 7

a client may have obtained an XML feed of some sort from a third-party provider, and now wants
you to integrate it into their website. Because we now know the structure of our XML data we
can write our menu to take advantage of it.

On today's menu

It's time to create the graphical components of our menu in Flash and the code that will make
use of our XML file.

To start with, create a new Flash movie and insert into it a new movie symbol (CTRL+F8). We'll
be using this for our menu headings items. Name the movie clip 'heading', and in the new clip's
Advanced options click the Export for ActionScript checkbox and type 'heading' into the
identifier field.

Selecting the Export for ActionScript option allows us to use the movie clip without having to
place instances of the movie clip onto our root movie. We can now talk directly to our 'heading'
movie using its ActionScript identifier 'heading' directly from the library. Gone are the days of
placing movies on into the root movie but out of sight so that you can use them later.

Nam~: Iheading J
( OK )
Behavior: 0 Movie Clip f Edit \ f Cancel }
0 Button
e Graphic ( Basic ) t Help )

_ Linkage
Identifier: Iheading I
UnkaSJe: [2! Export for ActionScript
0 Export for runtime sharing
E) Import for runtime sharing
(0 Export In first frame
URL: I I
-
_ source
EJ Always update before publishing
( Browse ... '
File:
f" Symbol... }
Symbol Name: ltt!m copy

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
7 Advanced PHP for Flash

Here is an image of our completed heading menu item.

The 'heading' movie is a very simple single frame movie;


a~D
it contains just three layers. One layer is for the button
shape, another for its shadow, and uppermost is our text (9 Text 1!1
layer. The text layer contains a dynamic text field with an
(9 button !!I I
instance name of headingsTitle and a variable name of II (9 shadow 7J 0
title where we'll store our menu title value.
" ......
g ... Ll
;. ~

Once we've created our heading menu we can duplicate this movie clip and rename it submenu.
and use it for our submenu items. Again we want to choose the Export for ActionScript option
with an identifier name of submenu. To make the submenu items different from the headings,
we'll change the background color of the graphics to orange.

We now have a movie menu. fla and it contains two library items, 'heading' and 'submenu'. Each
of the two library items has a linkage name of the same name to make things easier for us when
writing the code later.

Let the coding begin

It's time to take off the designer hat and get into developer mode. We've finished with the
graphical elements of our movie; it's time to get coding.

All our code will be placed into frame one of the main timeline. We'll be entering our code
directly into the Actions window for this, so you'll need to be in Expert Mode.

First we need to load our XML into Flash using the XML object.

II Load XML source


myXML new XML();

II ignore any white space in the XML content


myXML. ignoreWhi te = true;
PHP 8c XML 7

II Load the XML file into our XML object


myXML.load ( ("menu.xml");

II Check that XML file has been loaded successfully


function handleLoad(status)
status ? makeMenu() : trace("Error parsing XML.");

myXML.onLoad = handleLoad;

The code above loads our XML file into Flash. If the file is loaded successfully it executes the
makeMenu function. I think now's a good time to write our makeMenu function.

II Build menu headings


function makeMenu(){

II Linkage name of button movie clip


myitem = "heading";
// Initial X pos of menu
myX = 0;
II initial _y pos of level menu
myY = 10;

II Goto the first heading node and count the number of menu
II heading nodes
for (i=O; i<myXML.firstChild.childNodes.length; i++)
II get the id value of each heading node & assign it to title
I I var
title = (myXML.firstChild.childNodes[i] .attributes.id;
II create a new headings movie for each heading node
this.attachMovie(myitem, title, i+lO);
thisitem = this[title];
II change the heading item to the id value of the heading
thisitem.title = (title);
//Position each heading 2 pixels apart
thisitem. X= myX+= (thisitem._width)+2;
II position each heading item at the top of the movie
thisitem. Y = myY;

'Jmc ~ o

I ~u~
7 Advanced PHP for Flash

//when a heading item is selected


thisitem.onRelease =function(){
II get the x position of the selected heading
xPos=this._x;
II Get y position value of current menu heading
yPos=this._y;
II generate the sub menu associated with the selected heading
II by calling the makeSubMenu function with the position vars
makeSubMenu (this.title,xPos,Ypos);

Let's take a breather and look at what we've got so far.

We start by loading our XML file and after checking it loads successfully we run the code
that creates our menu headings (makeMenu).

When a menu heading is clicked with the mouse we store the selected menu item's X and Y
position and then call the makeSubMenu function, passing it our X and Y position variables.

If it all makes sense so far then well done; however, if you need a little more help, study the code
comments as they pretty much cover every line of code.

Moving on, we need to create our submenu items. We do this when we call the makeSubMenu
function, so let's take a look at the code.

II Build selected heading submenu items


function makeSubMenu(subMenuiD,xPos,yPos){

// Linkage name of our submenu button clip


sub Item= 11 submenu 11 ;

II Unload any previously loaded sub menu items


unloadSubMenu();

II create a new array to hold each sub menu movie we create.


PHP Be XML 7

II later we'll use this to unload menu items


itemsLoaded=new Array;

II Get the number of submenu items for the selected menu heading
for (i=O;i<myXML[subMenuiD] .childNodes.length;i++){

II set title var equal to the id attribute of the submenu node


title= (myXML[subMenuiD] .childNodes[i] .attributes.id);

II set link var equal to the link attribute of the submenu node
link= (myXML[subMenuiD] .childNodes[i] .attributes.link);

//create a new submenu movie for each submenu node


this.attachMovie(subitem, title, i+lOO);

// select the current submenu movie


thisitem = this[title];

// add the name of our current movie to our itemsLoaded array


itemsLoaded.push(title);

// set the name of the item to the current nodes title attribute
thisitem.title = (title);

II set link value of the current item to nodes link attribute


thisitem.link=(link);

II move the current menu item movie below the selected heading
thisitem. x xPos;

II move sub menu item below any previously created items


thisitem._y = yPos+=(thisitem._height);

//Increase the scale of the sub item when rolled over with the
I I mouse
thisitem.onRollOver=function(){
this._xscale=llO;

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
7 Advanced PHP for Flash

//Return to original size when mouse rolls off


thisitem.onRollOut=function(){
this._xscale=lOO;

//When a sub menu item is selected


thisitem.onRelease=function(){

II Open url from data when subitem is selected


openLink(this.link);

Let your keyboard cool down and we'll take a look at what we've achieved with the above code.

First, we check that the selected heading has some submenu items associated with it.

For each of these submenu items, we create an instance of the submenu movie. As with
the heading items, we use the linkage identifier (in this case submenu).

When we create a new instance we also add the name of the movie to our itemsLoaded
array. We do this so that we can unload the movie clips when another menu is selected.

We need the menu items to respond to the user, so for this we create a few simple
responses to mouse events. When the mouse rolls over our items we scale them slightly
to make it clear to the user which item they are currently on. This action is reversed when
the user moves the mouse away from the item.

What happens when a user makes a selection from the sub menu? We take the current
link value of the node and pass it to a function called openLink 0 . The link value is the
URL we want the user to see when they make a selection.
PHP 8c XML 7

Now we have headings and submenus, all the menus and submenus appear but we need the
previous submenus to disappear each time a new one is selected. Remember the itemsLoaded
array we created? We can now put it to good use by creating our unloadSubMenu function below.

II unloads all menu sub items that are currently loaded


function unloadSubMenu(){

II Get the total number of sub items


for (i=O;i<itemsLoaded.length;i++){

II unload each of the menu item stored on the array


unloadMovie(itemsLoaded[i]);

Each of our submenus can now be unloaded, a simple but essential part of our menu's
functionality. We can now move on to our final piece of functionality, which will open a specified
URL when a submenu item is selected. We do this by passing the link value to our openLink ()
function.

II Open a new browser window using the link value of a selected item
function openLink(link){

II if the link value exists for this item


i f (link! =null) {

II open the URL


getURL(link, "_blank");

else { II if link value does not exist then show debug msg
trace ("Link does not contain a URL") ;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
7 Advanced PHP for Flash

Our final piece of code takes care of loading the web pages specified in the link attribute of our
submenu XML nodes. The image below shows our menu in action.

BCMJk S Lore:::; I fl,;t,;h S itof"!":-i

I
I

Mission accomplished!
We now have a dynamic drop-down menu system that is populated by simple XML data. Try
adding new heading and submenu nodes to our XML and see the new items appear in the menu.
We have totally eliminated the need to edit the menu source code. Management of the menu
can now be handed over to our client, assuming that they're capable of editing the XML file.

Where do we go from here?


We now have our dynamic menu and all is well in the world, right? Well not exactly, the example
we have used is fairly simple, but imagine dozens of headings all with dozens of submenu items.
We need a method of maintaining the menu and its contents. The most reliable way of storing
relational information is inside of a relational database such as MySQL.

Although our menu data would be better suited to storage in a database, our menu requires XML
data. Unfortunately as of writing (and for the foreseeable future) there isn't a way querying a
database with Flash alone. We can, however, bridge the gap between our Flash menu and our
database using PHP to retrieve data from our database and present it as an XML document to
use with our menu.

Before we start with PHP, we need to create a database to hold our menu data. We have two
sets of data in our menu: our menu heading data and our submenu item. We can represent this
data with two tables in our database, one for each set of data.
PHP 8c XML 7

Database basics

Open a connection to MySQL and at the command prompt type the following command to
create our menu database:

CREATE DATABASE menu;

In addition to this we need to create two tables in the database, one for the headings data, which
we'll call headings and one for our submenu data called submenu.

CREATE TABLE headings (


headings_id bigint(20) NOT NULL auto_increment,
headings_title varchar(255) NOT NULL default '0',
PRIMARY KEY (headings_id,headings_title),
UNIQUE KEY title (headings_title)
TYPE=MyiSAM;

This creates our headings table!

CREATE TABLE submenu


submenu_id bigint(20) NOT NULL auto_increment,
headings_id bigint(20) NOT NULL default '0',
submenu_link varchar(255) NOT NULL default '',
submenu_title varchar(255) NOT NULL default ''
PRIMARY KEY (submenu_id)
TYPE=MyiSAM;

This creates our submenu table.

We now have our database structure, so we can add our heading and submenu items to it.

INSERT INTO headings (headings_title) VALUES ('Book


Stores'), ('Games'), ('Software'), ('Flash Sites');

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
7 Advanced PHP for Flash

The above code inserts all of our sample headings into the headings table in our database.
Assuming you have entered all the menu headings you require, we can now enter the submenu
items we want.

INSERT INTO submenu ('headings_id', 'submenu_link', 'submenu_title')


VALUES ('1', 'http:llwww.amazon.com', 'Amazon');

The important thing about the command above is the headings_id value. This value tells the
submenu item which of the headings menus it belongs to. For each entry you make in the
submenu table you'll need to enter the headings_id number of the heading you want the
menu item to belong to (in this case 1; yours may differ). You can get the correct headings_id
using the simple query below.

SELECT * FROM headings;

Once we have entered all our headings and submenu items, we're ready to look at getting the
data into the XML format we need for our menu.

Bring on PHP

Using PHP, we'll request the data we need from the database, and then we'll use PHP to format
the results from the database into XML for our Flash menu.

As with the previous code we'll step through the PHP code section by section.

<?
II Connect to our mysql server
$connection= mysql_connect("localhost" ,"myuser","mypassword") or die
("Oops couldn't connect to mysql") ;

II Connect to the menu database


$db= mysql_select_db ("menu",$connection) or die ("Couldn't connect
to DB");

II Select all of the heading table rows in the database


$sql = "select * from headings";
PHP 8c XML 7

II put all of the heading table rows into an array


$result = mysql_query ($sql, $connection) or die ("Couldn't do
query");

NOTE: The inclusion of your username and password directly in


your code is a security risk. However, for the purpose of this
tutorial it has been used to keep all the PHP code within a single

With the aid of the comments, the code above is pretty straightforward; let's take a look at what
it does.

We first open a connection to the MySQL server. This could be on your local machine, as
is the case above, or on a server hosted by your ISP in which case you simply replace
localhost with the address of your server. If the connection fails you'll see the Oops
couldn't connect to mysql message.

Once connected to the server we want to select our menu database. Once again, if this
fails our helpful message Couldn't connect to DB will be displayed. Adding these error
messages is a crucial part of writing PHP scripts; without them, we would find it very
difficult to track down problems with the code.

After we've made a connection to our database we need to select all of the heading entries
from our table.

Once our headings have been retrieved we want to put them into an array so that we can
use them within our PHP.

Now we have all our headings from the database we can start to look at getting them into an
XML format.

II Output the XML declaration tag


echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>";
II Ouput the XML parent node
echo"<XMLmenu>";

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
1 Advanced PHP for Flash

II For each Heading output XML <menu tags with attributes


while ($row= mysql_fetch_array ($result)) {

// Get the value of the title field from each row


$title = $row[ 1 headings_title 1 ] ;
//Get the value of the id filed for each row
$id = $row [ 1 headings_id 1 ] ;

//Output each headings row as XML attributes inside a <menu> tag


echo "<heading id=\"$title\">";

The above section of our script outputs our XML declaration and each menu <heading>
opening tag along with its id attribute value.

//New query to get each sub item for the current heading row id
$sql2 = "select * from submenu where headings_id=$id";

// if the query fails show error message


$result2 = mysql_query ($sql2, $connection) or die ( "Couldn 1 t do
submenu query") ;

II for each sub menu item returned by the query


while ($row2 = mysql_fetch_array($result2)){

//Get the value of the current row title field


$submenu_title = $row2[ submenu_title
1 1 ];

//Get the value of the current row link field


$submenu_link $row2[ submenu_link
1 1 ];

//Output the row values as XML within <submenu> tags


echo "<submenu id=\"$submenu_title\"
link=\"$submenu_link\"></submenu>";

//Output the closing <heading> tag after we've output all sub menu
tags
echo "</heading>";
PHP 8c XML 7

II Output the closing parent node tag


echo"<IXMLmenu>";
?>

The final section of our PHP scripts outputs the submenu nodes complete with attributes. We do
this by creating a second query within our first one, which retrieves the submenu rows for each
of the heading rows that we get from the database. Finally we output the closing tags for our
heading and root nodes, ensuring the XML remains 'well formed'. Save our PHP file as menu.php.
We can test it by opening our Flash menu code and replacing the line shown below:

myXML. load ( "menu. xml" ) ;

with:

myXML.load ("menu.php");

Now instead of our menu loading static XML content from a file, the source file is a PHP script
that queries our database returning the results as formatted XML for use with our Flash menu.

Summary
All this effort may seem like a complete overkill for such a relatively small task, but the principles
of what we've achieved can be applied to all other projects whatever their scale. What we've
created so far is the basis for most modern content-management systems. You should take this
simple tutorial and run with it. Think big and have fun. With Flash, PHP, MySQL, and XML the sky
is your limit.

If you're looking for some ideas, the next logical step in our project would be to build a front-end
to our database, so that the database could be maintained via a Flash interface instead. Good Luck!

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
D D D
n n u u u
D D

[ D DDcfJ
Ming
~D

::::J
1 111~ 11 nn

B
What we'll cover in this chapter:

Installing Ming on Windows and Linux

0
An introduction to dynamic SWF generation using Ming

Practical pros and cons of server-side SWF generation

Putting Ming to use by building a sketch pad guestbook

DO

[
[

DO
CIIT
CIIT
s Advanced PHP for Flash

Introducing... Ming!
Ming is one of the many cool extensions available to PHP developers, like you and me. It
provides an ability not found in competing server-side scripting packages (without commercial
add-ons) - dynamically generating SWF files right from your code. However, Ming is also
currently available or in development for a few more general-purpose languages, such as C++,
Perl, and Python.

Ming is just another way to generate SWFs. Flash is one way, Adobe's Live Motion is another, Swift
3D is another, etc. The difference is, in Flash and most other SWF authoring environments, you
author your work using an intermediate file format, such as FLA. When you're happy with your
work, you compile it to the SWF format and you're done. With Ming, your authoring
environment is your PHP script. Since your PHP script usually produces dynamic output based on
arbitrary data of some kind, Ming can generate dynamic SWFs on the fly. Sounds neat, huh?

Actually, Ming isn't the only PHP extension available for dynamically generating SWFs. There's also
libswf. Unfortunately, libswf has only had one release (in 2000) before development was halted.
Furthermore, it's closed-source and has only been ported to a few platforms (Windows isn't one
of them) . PHP's documentation recommends using Ming instead, and I couldn't agree more.

Ming's author (for our purposes, let's call him "Dave" or "Dave Hayden") set out to build a better
library. And so he did. As of this writing, Ming, which is Chinese for "bright, luminescent, or
beautiful", is still being maintained after over two years of development. While Dave is obviously
a very busy guy these days, there are many neat features and niceties on the development
agenda, and it looks like Ming will be around for a while -getting better all the time.

First things first, we have to make sure you've got a working installation of PHP with Ming. I will
assume that you've installed and tested Apache already. Let's get to it.

Installing Ming
Is Ming already installed? If you're using Windows and one of the latest versions of PHP, Ming
may already be installed. Do you want to find out if it is? I do! Run a simple test script:

1. Create a new file in your favorite text editor and type the following:

<?php phpinfo(); ?>


Ming 8

2. Save the file as phpinfo. php in the root directory of the web server.

3. Then run the script from your web browser.

If Ming is installed, you'll see the following in phpinfo. php's output:

IQ_ '"' .
Elo \)ow

~
'.
flfYQfltes

1l
loob II<'>
Of "" . ..
11
.
' 1,1
~i-M)http:fp\x~o.~ C]Go
gd
GO S1Jppt~t1 tnJbltd
GO Version 1.6.2 011'1ightr
FeeT)Ipe Suppo1t tlltlbiCid
FreeType llllkilglll WlthTTF.bnlry
JPG Support onal>ltd
PHG Suppo1t tniillb!ed
WBMP Support enabled

ming
IM/ng SWF outputllbliUY lthtfvnk in y~XN"Irunk I

!Apl)C:ht for Windows 95/HT


apache
I
l
Apl)c:he Veslon A~>entl\ .3. 23

Apache Relu$e \0323\00


Apache- API Vrslo11 \999(13;l)
Hostu"me:Po11 localhoS100
Tlmeoutll CONitc:tion.: :nJ- Kae-p.NM!I: 15

I Directive Local Value I M....rVlluo

-
0 0
.
lc:hild_te lmlnate
!engine \ \
_1'-_l t.acaiWtM'Iel:

If you've got it, pat yourself on the back and take a sip of a cold drink -you can skip the rest of
this section and get right to the fun stuff. If Ming is not installed, read on.

Ming is currently available for Windows and many flavors of Unix and Linux. Work is being done
to make Ming available for Mac OS X, but it isn't finished yet.

Strike one
So Ming isn't showing up, eh? Well, there is a good possibility, especially if you're using Windows,
that Ming is present in your PHP installation but not enabled. We'll need to look at our php. ini
file to see if the Ming extension has been commented out.
8 Advanced PHP for Flash

1. If you know where your php . ini is, by all means, skip this step and open it up in your
favorite text editor. For the rest of us, we'll need to hunt it down. On Windows systems,
php. ini is usually located in the Windows directory. If it's not, search for it using
Window's Search utility on the Start Menu.

On Linux systems, php. ini will usually reside where PHP was installed. If you're having
trouble, type the following at the command line:

cd I
find -name php.ini

2. Look for the section called Dynamic Extensions. Under this heading in php . ini,
individual dynamic extensions can be enabled or disabled.

For Windows users, look for extension=php_ ming. dll. For Linux users, look for
extension=php_ ming. so. If the line is missing from your php. ini, add it. If it's there
but is commented out (has a semi-colon in front of it), nuke the semi-colon.

3. Once you're done making changes, save the file. Then, restart your web server. Next, rerun
the phpinfo . php we used above. Cross your fingers. Does Ming show up? If so, great! If
not, continue on to the installation instructions.

Windows
If you're using Windows, you're in luck, installation is as easy as installing PHP itself. In fact, the
larger of the two binary Windows distributions offered on http://www.php.net contains Ming and
several other useful extensions, all ready for your use and abuse. Note: In any of the Windows
PHP packages I'll mention, Ming may be installed but not enabled. If you get one of the
recommended packages installed and Ming isn't showing up, try running through the instructions
for enabling Ming in your php . ini file, which we just covered.
Ming a

your own, go to your PHp 4 2 2 (tar bz2l (2,6S4kb) - 2'2 Jufy 2002
dlsbibutlon's download ette 4 2 'oar qzl [3,'319Ktt) - 22 .)Jiy 2002
site. ~aries ~v&Heblt on
extem.al servers:
Patches to latest version
~
Ngn!l NrtWart PHP ? o to 4 2 2 garc;h [3 13Kb) - 2'2 .l.lly 2002
This u!'lllfitd diff will enable you to updatQ yo...- lOcal PHP source to the lat est var~10n
QSL2
from 4.2.0 .
l!IK..llli PHp i 2 1 to 4 2 2 p.atc;b I521Cb) - 22 July 2002
ill.ll!J.lS..A.
T'l'lfi Ul"'lfil<l diff will enable you to update your local PHP 'IOUI"(:e to the latest vers;on
from 4.2. 1.
Other Do wnloads
Windows Binaries
For dowr-.oadable manual
p&dcages, go to the
documentarion dowolo.od All Windows b1nar1es can be used on WLndows 95/9B/Me and oo WIJ1dows NT/2000/XP.
I
page
fHp 4 ?? l!P ruu~\:JQ1 [5,27SKb) 2'2 July 2002
Get some~ for (CCI tnary plus: s:&rvat API vef"iions ffX Apache, Apache2 (expel'irMntil), ISAPI,
NSAPI, Servlet and P'I3Web. MySQL. 'SUI)pOtt built -an, man~ a>:t enS:Ior'l:l .-,dudld,
your site, and some PHP
~lciJ~Jed as z1p)
iCOnS to use on your
oomputer pttp + 2 2 ensrafpr [913Kb]- 22 )4;y 2002
(CCI only, MySQL support budt-ltl, ~CICiJ~Jed as Windows. Installer to IOSt~l nd
configure PHP, and automatteally eonf1QU1"8 liS, PWS and Xltam1, With m~11
To dowrioad the latest eonflgurit ion fOt" oth11r servers. N.6. no t>:temll l>cten-sions r~cluded)
development verSion, see
ttle !nstru<;tjom oo !DLOQ
t nonymow cys File Uploads Sec urity Fix

ztod OOtf!'l!zer for PHP for PHP 4 J 0/i J; 1 {534b) 27 February 2002
(Apply on php-4.1.></mon)
4.0 .3 and later J$ av~ulable
~ l21:b) 27 February 2002
on Zend Tecnnolog.e$' web (Apply in php-4.0.6/main)
Site
~ (443Bb) 27 February 2002
For~ downloads,
<WI'I'" ptlpJ.O.>i/fuocttom:)

Alternatively, there is another PHP installation package that includes Ming, php4win:

http://www.php4win.de

And lastly, there's Foxserv, an installation package that includes recent builds of Apache
webserver, MySQL, PHP, and several useful extensions, all in one package:

http://www.sou rceforge. net/proj ects/foxserv

http://www. foxserv. net

Linux
If you installed PHP using the Appendix in the first book or if you've compiled PHP before, this
is pretty standard fare. These instructions assume that you've compiled PHP before. If not, grab
a copy of the first book and go through Appendix A. At this point, I'll assume that you have
unpacked the latest version (current version 4.2.2) of the PHP sources into a directory, along with
any other extension sources you desire.
s Advanced PHP for Flash

1. Download the Ming source archive, ming-o. 2a. tgz, from the Ming homepage:

http://ming.sourceforge.net

2. Copy the archive to the directory where we want to install to. The first book uses /usr/local/.

cp ming-0.2a.tgz /usr/local/

3. Now, we need to move to the directory where we copied the file to:

cd /usr/local

4. Then, we'll use gzip to uncompress the archive:

gzip -d ming-0.2a.tgz

5. We now have a . tar file in the current directory. Next, we'll use tar to extract the source
files from the . tar file:

tar -xvf ming-0.2a.tar

The files contained in the . tar will now be extracted. A directory called ming-O. 2a will
be created that will contain all of the necessary source files to build Ming.

6. Now let's go into the Ming source directory:

cd ming-0.2a

7. It's time to build Ming:

make

After a couple of minutes and a lot of stuff flying about the screen, we'll be returned to
the command prompt.
Ming 8

8. Now, type:

make install

A few seconds later and we'll be back at the prompt again.

9. At this point, the Ming library has been built on your system. But, before we get too carried
away, we have to recompile PHP to build Ming into PHP. So, change to the PHP source directory:

cd .. /php-4. 2 . 2

10. Now that you're in there, you can configure the PHP sources. If you've compiled PHP with
extensions before, you'll probably be familiar with this step. If you're adding other
extensions, you'll add the required parameters to the following configure command:

./configure --with-ming

11. It's time to build PHP. Type:

make

12. This command will take a few minutes. Might I suggest a cold, refreshing beverage? Once
it's done, it'll put us back at the command prompt. Then, type:

make install

This command will also take a few minutes. How about a tasty snack? Once it's done, we'll
be right back at our prompt.

13. Next, we'll have to restart Apache:

apachectl stop

apachectl start

' 0
1 rn CJ cJ

;\~LC L'
Dec~ e
s Advanced PHP for Flash

14. Now it's time to test our installation of PHP. If you ran the phpinfo.php test script I talked
about earlier in the section, you can go ahead and run it again. If not, open your favorite
text editor and type:

<?php phpinfo(); ?>

15. Save it as phpinfo.php in the root directory of your web server.

16. Run it from your web browser. If it worked, you'll see Ming listed in phpinfo .php's output:

!llo l:dl
-- ..
Iodf 1M>
lO _Q G ID~~ P' ~ .r e!.-
#41tfi~ l)l'ttp:J~.r;q.

gd
~,#
:J !DGo
.!

GO Supp on nab red


GOVt nion 1.6.2 or higher
FruTypt Suppof1
FrttT~pt Linkage
Mt.bled
WJth nFHwary
.
J P G Suppon tnlbled
P HG Suppon tiUibltd
WB MP Suppon tl\lbltd

mlng
IMins SWF output librouy l the funk ift y()IJI" trufl~ I
apache
I
[ Ap<'ldte fo1 Wlndows 9SJHT I
Apaeht VttslOil i'j>oebo/1.3.23
Apache Rt lu u 11l3Zl100
Ap;ftcht API Ve~ sl on lmml
H"'narn t:Pon toctlhost:M
lltl'l t OUI$ ConAeclion: D Ktil!!lp-AIMI: 1S

~ DINc11V T LooaiVIIu M-rVIIue ]


lchlld_lt rnlln aft
eng ine
0
I ,
0
.
llll""" 1111'\<""'"'....

Note: The modules aren't listed in alphabetical order.

Troubleshooting
In the unlikely event that you don't see Ming listed, something is amiss. Typographic errors are
the number one cause of errors. Go back and run through the steps again. Pay special attention
to ensure that your syntax is correct.
Ming 8

If you're sure you've entered everything correctly, visit Ming's homepage. There may be news
and/or tips that pertain to the problem you're experiencing.

You can also check out the online documentation at the official PHP site for support on installing PHP:

http://www.php.net

The cans and can'ts of Ming


By now, you know that Ming can dynamically generate SWF files from PHP code. That's nice. "But,
what does it really amount to?" you might ask. "Can I generate animations? Can I generate text?
Can I generate ActionScript? Can I include images? Can I edit existing SWF files?" These are all
very good questions, and ones I'll answer before we're through.

This information is based on the current release of Ming, 0.2a.

Images and fonts must be converted to special formats to be used with Ming. This was
done so that using Ming wouldn't require additional libraries, such as libpng to use .png
images, for instance. This is on Dave's Ming "To Do" list to fix. When this feature is added,
we should be able to use more file formats with Ming natively.

Ming supports Flash S's dot syntax for ActionScript, although certain functionality such as
defining your own functions is not supported.

It supports streaming sound but not event sounds.

It supports fonts but not in a universal, friendly format, such as TIF. They must be
converted to a special format. Actually, they have to be converted twice, using two
different utilities - once to the old Generator template format, then again to the RDB
format, which makes using fonts a rather unpleasant experience.

Ming can create shapes, frame-based 'movie clips'.

Ming is not able to edit existing SWFs.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
8 Advanced PH P for Flash

Meet the methods


First, two notes:

1. Ming takes advantage of PHP's Object-Oriented programming features. If you aren't


familiar with them yet, you would be wise to read up about them, and a good place is in
Appendix B of Foundation PHP for Flash.

2. You must remember that Ming works with SWF directly, and thus is not as fully featured
or user-friendly as working with SWF via Flash's extensive authoring environment.

So, on to the methods. Ming exists in PHP as 13 objects:

swfmovie(): The basic movie class, where you set basic movie properties, like the frame
rate, the dimensions of the movie, and how many frames the movie will have.

swfshape(): This object allows us to draw basic shapes using: lines, curves, and fills.

swfdisplayitem(): Animates objects, providing such methods as scale and rotate.

swfgradient(): This is for creating gradients that can be applied to shape objects.

swfbitmap(): This object is for using bitmaps (currently limited to JPEGs and DBL files).

swffill(): Transforms fills.

swfmorph(): Performs what we know in Flash as shape tweens.

swftext(): Obviously enough, this object is for adding text to your movie.

swffont(): Allows you to use fonts. Using real fonts is currently a painful process.
Fortunately, the system fonts (_serif, _sans, and _typewriter) are always available.

swftextfield(): Adds textfields to your movie.

swfsprite(): This one is what we all know as the movieclip symbol. Although it works a
little differently here, the basic concept is the same.
Ming 8

swfbutton(): Yes, add buttons to your movie!

swfaction(): Let's you add actions to your movie.

Let's get $physical


That's right, it's time to get down to business and build some stuff.

Hello World

Yes, yes. Now, what tutorial would be complete without a "Hello World" example? None, l say.
Since using fonts currently requires you to do messy font conversions, we'll skip the traditional
"Hello World" and go for something a little more shapely. Let's draw a box!

1. Create a new PHP file in your favorite text editor. Let's call it ming_hello_world.php.
The first thing we've got to do is instantiate the basic SWF object and set up some basic
properties. This is pretty straightforward.

<?php

//ming_hello_world.php

$movie= new SWFMovie();


$movie->setDimension (790, 490);
$movie->setBackground (32, 64, 255);

2. This is where it gets interesting. We're going draw a shape. In Ming, shapes are contained
in the SWFShape object! First we'll instantiate SWFShape, then we'll set up our line style
(1 Opt size, green), then we'll draw a box on our instance. Notice how we start out at 20,20
then draw four lines that will compose our box.

$s =new SWFShape();
$s->setLine (10, 0, 255, 0);
$s->movePenTo (20, 20);
$s->drawLineTo (200, 20);
$s->drawLineTo (200, 200);

' 0
1 rn CJ cJ

;\~LC L
Dec~ e
s Advanced PHP for Flash

$s->drawLineTo (20, 200);


$s->drawLineTo (20, 20);

3. We have a box shape now, but it's not in our movie. To add it, simply use the add method.

$movie->add ($s);

4. Since our script hasn't output anything and we want this little demo to show up as a Flash
movie, we'll output a header for SWF content.

header("Content-type: application/x-shockwave-flash");

5. Lastly, we'll output our movie.

$movie->output();

6. Save this script, place it in a folder on your webserver and run it from your browser. You
should see the following:
Ming 8

Demo 2

Phew! That was exciting! But the best is yet to come. Next, we'll walk on the wild side and create
a filled box.

1. Let's start our script. Yes, yes, we know all about this stuff.

<?php

//ming_demo_2.php

$movie = new SWFMovie();


$movie->setDimension (790, 490);
$movie->setBackground (132, 50, 125);

$s =new SWFShape();

2. This, on the other hand, is new! Here, we're creating a gradient. In Flash, we add colors to
a gradient in the fill editor. Here we do the same thing; it's just in code. The first parameter
is ratio. 0 is the beginning of the gradient and 1.0 is the end. When adding colors to a
gradient, the colors must be added with ratios in ascending order.

$gradient = new SWFGradient ();


$gradient->addEntry (0, 255, 0, 0);
$gradient->addEntry (1.0, 255, 255, 255);

3. Next, we'll apply the fill style to our shape. Notice how the addFill method returns a
reference to the fill, which we aptly save in $fill. This allows us to manipulate the fill
using transform methods.

$fill = $s->addFill ($gradient);


$fill->moveTo (25, 50);
$fill->scaleTo ( .20, .20);

4. Now comes one of the most confusing aspects of Ming. We have to tell our shape how to
use the fill. There are two methods for this, setRightFill and setLeftFill. We're

I;\~~ L'
'
I
D
rn CJ cJ

Dec~ e
s Advanced PHP for Flash

drawing our box in a clockwise fashion, so the right-side of these lines is the interior of the
box. So, in this case, we'll use setRightFill.

$s->setRightFill ($fill);
$s->setLine (5, 100, 155, 255);
$s->movePenTo (20, 20);
$s->drawLineTo (200, 20);
$s->drawLineTo (200, 200);
$s->drawLineTo (20, 200);
$s->drawLineTo (20, 20);

$movie->add ($s);

header ("Content-type: application/x-shockwave-flash");


$movie->output ();

5. Save this as ming_demo_2. php. Put it up on your webserver and run it. You should see
the following in incredibly tacky colors:
Ming 8

Your Mom
It's time to put Ming to real use. But first, allow me to offer some words of advice. Really taking
advantage of Ming is done just as it is with any other tool. You evaluate the strengths of each
tool you'll be working with and use the right tools for the areas they're best suited for. When
working with Ming, this process is really important - especially when Flash has advanced as far
as it has with Flash MX. Flash MX can now handle many of the dynamic tasks that Ming was
previously used for. However, Ming has its advantages and unique capabilities that make it the
best tool for some jobs; or, more often than not, Ming becomes a complement to Flash. In fact
the application that we'll build works this way.

Consider this situation, though. Say you have a website with several pages, some of which are
dynamic. Let's say that you want to have an animated Flash header appear on each one of these
pages. With Flash MX, this task can be accomplished in a dynamic fashion rather easily. However,
you'd wind up including all of your font's outlines in order to be able to display any text that you
so desire, especially since some of the pages are dynamic and you want the header for those pages
also to be dynamic. Using this method will work, however, it'll probably add a good 50-1 OOKB to
your SWF, which is pretty hefty for a crummy animated header! With Ming, this SWF could be
generated on the fly, resulting in a header that only contains outlines for the text that it actually
uses, which really results in tiny file sizes. Since you're as bright as a shimmering star, you know
that tiny file sizes translate into quick user downloads and a joyous browsing experience.

So, the point here is, think through your designs and use the best tool for the job.

Now, on with the good stuff!

We're going to build a sketchpad guest book with Flash MX, Ming, PHP, and MySQL. It's similar
to a traditional guest book, except that in addition to leaving a short message, the user can draw
a color sketch and save it along with their message. Visitors that happen to stop by can view the
entries with the sketches and download any particular sketch they take a liking to. Although Ming
isn't put to extravagant use here, it is a great example of how Ming can add important
functionality to your web applications with just a bit of effort.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
8 Advanced PHP for Flash

Oh, by the way, it's called "Your Mom's Guestbook". Don't ask why, just check it out:

This little project is quite cool and it's practical, too! This is a great base for a project that begs
to be expanded and enhanced in a number of different ways.

Let's get started, but before we get our hands too dirty, I'll give you a quick overview of the
project. We'll be working with three files:

guestbook_form. swf: This SWF will provide the submission form that will allow us to add
an entry to the guest book. It will also contain the sketchpad that we'll be able to draw on.

guestbook.php: This is the server-side brain of the project. Its job is to display guestbook
entries. It also has the task of adding guestbook entries to the database and creating the
actual SWF file based on the data sent by the submission form.

download.php: This little guy's sole purpose in life is to allow us to download sketch SWFs.

As with other projects, we'll start with the SWF before we get to the PHP. Go ahead and get into
Flash MX and create a new movie.
Ming 8

guestbook_form.swf
This is the form we'll be building:

Creating the guest book form

First things first - let's set up the Document Properties ;..


basic properties of our movie. Select
Modify > Document from the menu
Dimensions: ~~ [width) X J220 px [height)

or press CTRL +J to open the Match: Erinte1 !;;ontents I Qefault

Document Properties window. Backg1ound Color: ~


ErameRate: ~ fps

Ruler Units: JPixels 3


.!:!elp Make Default I I OK Cancel

1. Set the resolution to 500 pixels wide and 220 pixels high. Set the Background Color to
#666666. Last but not least. set the Frame Rate to 30. Click the OK button.

2. Now, let's put our interface items onto the stage, starting with the text fields. Create the
name field first. Surprise, this is the text field that users will type their names into! Select
the Text tool (T), and then drag to create a text field roughly 1SO pixels wide.
s Advanced PHP for Flash

3. Next we need to set the properties of our text field just the way we want:

fA llnputTo>t ~ A j_..ns
ASY JO:"" :J
21 fiO _:j ~ ~ ~~ iii:l'll[iil
lnamtTtlllit Af )Normal ~ ~ r ~wKorn ~ F01mll- (

v, J155.0 x: jse.o I
@ Single l ine 21 fli ~ Vat: I Ch.... ,.,_l 0
H:~ Y:[2i6 M>lcknun~Ch>lacttrs: j4'i""' 1!!11

Select Input Text from the Text Type drop-drown. Give the text field an instance name of
nameText. Select _sans for the font face and 10 for the font size. Select Single Line from
the Line Type drop-down and set the Maximum Characters to 48. That should be plenty
of characters for someone's full name. Make sure the Left justify button is selected (the
first of the four Text Alignment buttons). Lastly, set the font color to black or any other
favorite dark color you might have.

4. Copy that text field and paste it below the first one. Give the copy an instance name of
locationText. This is the field that users will input their locations into.

5. Copy the first text field again and paste it below the second one. Give it an instance name
of email Text. This is the field that, you guessed it, will have email addresses input into it.

Once again, copy the first text field and paste it below the third one. Give it an instance
name of msgText. This is where the user will type a short message. It's going to be short,
but not super short, so let's make it Multiline; so select Multiline from the Line Type drop-
down. Set the Maximum Characters to 4000 -that ought to be enough.
Ming 8

~ 1\ .. t, _.. ,
/P
~ A
00
/(/
s~
~~
" (}

$00~::0~ I Bod,.,_...~ Fr...,.Rb- r;- , ._


~ AWI"""'"C I

You should now have three skinny text fields on your stage and one big one. Now we'll
add some text labels to them so our users will know what they're supposed to be.

6. Create a text field on the stage roughly half the width of our input text fields and type
Name: into it. Then, select Static Text from the Text Type drop-down. _sans will be our font
face again, but this time, let's go with white as the font color. Click the Right Justify button,
as this will make it easier to line up the labels next to our input text fields. Finally, move
the text field to the left side of the first input text field we created.
8 Advanced PHP for Flash

7. Copy the text field we just created and paste one next to each of the three remaining text fields:

[.; ~ .. !!. """ '


/ p
t A
00
/(/
E 1~
~~
tl (}

..,.. no~ I &d. gr<oliftt. .. ,,_Ab. r-- Pt


~ FlMJrlfll...,.oo$1

Now it's time to add some components. One of the many niceties of Flash MX is the
inclusion of a powerful set of components. Flash has come with a few pre-built interface
components for a couple of versions now, but never have they been as powerful or as easy
to use as they are in Flash MX. We're going to use the power of the new components to
quickly create some buttons and scrollbars for our form. This will save us the time (and
pain) of having to create them from scratch.

8. If the Components panel isn't already open, select


Window > Components to open it. ~ Components ::=.
(Flash Ul Components ...- )

[@ ChockBox !! ComboBox
~ ListBox 0 PushButton

~ RadioBu t\on ~ ScroiiBar

~ ScroiiPaM
Ming s

9. Drag a PushButton onto the stage and place it underneath msgText. On the Parameters
page of the Properties bar, set Label to Submit and Click Handler to submitBtn.

La btl SIJbmit
Click Handi@J submit8tn

10. Drag another PushButton onto the stage and place it off to the right of our Submit button.
Set the Label to Set Background To Current Color and set Click Handler to setBGColorBtn.
You'll have to scale the width of the button wide enough to show the entire label.

11. Now let's add some scrollbars. These will let users change the brush color by changing RGB
values. We'll add a scrollbar for red, green, and blue values. Drag a scrollbar onto the stage.
Set its height to 125. Give it an instance name of rSlider. Move it to the right side of the
text fields.

12. Copy that scrollbar and paste it to the right of the first one. Give it an instance name of
gSlider.

13. Copy that scrollbar and paste


it to the right of the second
one. Give it an instance name
of bSlider. How does it look?
Something like this?

14. We now have all of our pre-built components in place. Next, we'll need to build a couple
of movie clips. Let's start with the one that will display the current brush color. Select the
Rectangle tool (R). Disable the Stroke Color and select white as the Fill Color.

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
s Advanced PHP for Flash

15. Draw a rectangle underneath the group of scrollbars and set its instance name to
currentColor. Select the Arrow tool M and click the rectangle we just created to select
it. Select Insert > Convert to Symbol from the menu or press FB. Name the symbol
currentColor and make sure Movie Clip is selected. Click OK.

!!ehavior. r. Movie Clip Registration: ~gg


r Button
000

r Graphic
Advanced I

16. Next, we'll draw the sketchpad. Draw another rectangle just like we did before. Make it
exactly 200 by 150 pixels. Convert it to a movie clip, naming it bg (for background). Set its
instance name also to bg and its X value to 290 and Y value to 30.

17. We'll now need to create an empty movie clip. This is where all of the drawing will actually
take place. Select Insert > New Symbol or press CTRL+FB. Movie Clip should still be
checked. Name it drawing.

18. Press the Root button to get back to the root of our movie.

19. Add a layer to the timeline and then drag an instance of drawing to the stage. Name the
instance drawing and set its X value to 290 and its Y value to 30. This will place drawing
in the layer above bg and drawing will be aligned to the upper-left corner of background.

20. All that's left to lay out are some more labels. Copy one of the four already on the stage
and place it above bg. Change the text to "Scribble Pad" or whatever suits your fancy. Place
one above each slider, with the letters "R", "G", and "B". While we're at it, we might as
while add one above the RGB labels that says "Color".
Ming 8

Your stage should now look something like this:

- -- ------- ~-
-~- - - - - --
l l f l ' l t _ -
l h l : .

l!l!l""""'" '.,_.,.,..
~,_ o-
1!]..-- ~ -
iilil--

Form logic

The time has come to put on our thinking caps and output some code, oh yes!

Another nicety of Flash MX is the ability to often place all of your code in one place. This saves
you from hunting down bits and pieces of logic through the many symbols in your library.
Naturally, using this technique, you'll want to keep your code clean and organized or before long,
you'll wind up lost anyway!

let's break it down! Open up the Actions panel on one of the frames of the layers in the root time line.

1. We're going to be dealing with color values, both decimal and hexadecimal. let's add this
method right off the bat. This method is being added to the Number object, which means
it will now be available for all numeric variables, just like toString (). Handy!

//handy decimal to hex conve r s ion funct ion


s Advanced PHP for Flash

Number.prototype.toHex = function ()
i f (this < 16) {
return "0" + this.toString (16);
else {
return this.toString (16);

2. Let's set up our scrollbar components. The first set of methods tell the scrollbars that we
want large scrolls, such as clicking the track, to scroll by 50 and that we want the scroll
range to be 0 to 255. The second set defines a function to call when the value of the
scrollbar changes. In this case, we've set this to be colorChange for all three scrollbars.
We'll write the code for colorChange in a few minutes. The third set of methods tells the
scrollbars that we want small scrolls, such as clicking the up and down buttons, to scroll
by 5.

//set up our sliders


rSlider.setScrollProperties (50, 0, 255);
gSlider.setScrollProperties (50, 0, 255);
bSlider.setScrollProperties (50, 0, 255);
rSlider.setChangeHandler ("colorChange");
gSlider.setChangeHandler ("colorChange");
bSlider.setChangeHandler ("colorChange");
rSlider.setSmallScroll (5);
gSlider.setSmallScroll (5);
bSlider.setSmallScroll (5);

3. Now we'll define a couple of color objects, one for the current brush color and one for
the background color. We'll also define a color transform object that we'll use to modify
the color objects. If you're familiar with color transforms, you'll notice that a few of the
properties are missing. Don't worry, we'll add those later. For now, we'll set those that
won't change.

//define some objects


currentColorCol = new Color (currentColor) ;
bgCol new Color (bg);
trans = new Object();
Ming 8

trans = {ra: 100 1 ga: 1001 ba: 1001 aa: 1001 ab: 0};

4. Let's move on to define some more variables. The first will hold a hexadecimal copy of our
current background color. We're setting this to white initially. The second will hold a
hexadecimal copy of the current brush color. The third will hold data about our drawing.
When we send our data to PHP, we won't actually be sending the picture. Rather, we'll send
data we've collected about how the image was drawn.

//provide an initial background color


currentBGColor = "FFFFFF";
currentColor = "";

//this will hold our line data


drawingData = new Array();

Sure, I hear you; it'd be easier to just send the picture. Unfortunately, Flash can't capture
raster images.

5. Next, we create an empty movie clip called dataMov. Then, define a method for it called
submit, which we'll call when we're ready to submit the data to our PHP page. This contains
a getURL call, which will retrieve guestbook.php, in the current window (_self).

this. createEmptyMovieClip ( "dataMov" 1 10) ;

dataMov.submit = function () {
this .getURL ( "guestbook.php" 1 "_self" 1 "POST");

When you supply a method in a getURL call, all variables in the current timeline are passed
to the target URL. Most of the time, this isn't what you want; usually you'll only want to
send out a certain group of variables. This is where dataMov comes in. When we get ready
to submit our data, we'll place only the variables we want to send to the PHP page inside
dataMov. We'll call getURL from there using our submit method. This way, we have
control over what is getting sent. It saves some bandwidth, too.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
8 Advanced PHP for Flash

6. Here's the colorChange function we specified as the changeHandler for our scrollbars.
This gets called every time a scrollbar changes so that we can display the current color the
user is selecting.

colorChange = function () {
trans.rb _root.rSlider.getScrollPosition() - 255;
trans.gb = _root.gSlider.getScrollPosition() - 255;
trans.bb = _root.bSlider.getScrollPosition() - 255;
currentColorCol.setTransform (trans);

//update the current color variable so we can save it later


currentColor _root.rSlider.getScrollPosition() .toHex();
currentColor += _root.gSlider.getScrollPosition() .toHex();
currentColor += _root.bSlider.getScrollPosition() .toHex();

First, it sets those missing color transform properties I told you about, based on the
current values of the scrollbars. We then apply the transformation to our currentColor
color object, which changes the color of our currentColor movie clip. Cool!

Finally we update our currentColor variable with the hexadecimal version of current
RGB values.

7. This is the function we specified as the clickHandler for the Set Background to Current
Color button. When that button is clicked, it calls this function, which, in turn, changes the
color of our bg movie clip and keeps track of our current bg color.

setBGColorBtn = function () {
//set background color to current color setting
bgCol.setTransform (trans);
currentBGColor = currentColor;

8. This next function is the one we specified as the clickHandler for the Submit button.
This is where we prepare the data before sending it off to the PHP page. It's also the place
Ming a

to add the logic necessary to make sure that the text fields contain valid information
(always a good idea). For example, you'd probably want to make sure that the email
address contains an @ symbol and a period. Or you might want to ensure that a message
is specified. For brevity, though, I'll leave this up to you.

submitBtn = function () {
//submit guestbook entry

//create variables in dataMov movieclip


root.dataMov.name = escape (nameText.text);
_root.dataMov.location = escape (locationText.text);
_root.dataMov.email =escape (emailText.text);
_root.dataMov.msg = escape (msgText.text);
_root.dataMov.bg_color = currentBGColor;

//encode line data arrays into one big string!


var t;
for (i 0; i < drawingData.length; i++)
t += drawingData[i].join("z") + "y";

_root.dataMov.drawing = t;
_root.dataMov.submit();

The first thing we do is encode and place copies of desired variables into dataMov. We
encode them with escape so that they'll transfer (and be database insertable) without any
problems. If the variables contained any funky characters like quotes, it could put toast
crumbs in the butter, if you know what I mean.

Next, we take each array that was created for every line that was drawn and join it into a
string, with the values separated by "z". Why z? We could use a more traditional delimiter
character, such as the comma. However, when we encode the data for transmission, the
comma becomes %2C, or three characters instead of one. That's no good! The letter z
won't be encoded, so it's a good candidate for a delimiter.

So, now we have an array of encoded strings. Next, we'll join that array using "y". Why?
We want to be able to reconstruct our data once it reaches PHP, so we'll need to preserve

' 0
1 rn CJ cJ

;\~LC L
Dec~ e
8 Advanced PHP for Flash

our structure by delimiting these values with a different character than we used before.
Doing so will allow us to split our data into arrays just as easily as we joined it.
And finally, we call the submit method that runs a getURL command. Goodbye data!

9. Here we're adding a method to our bg movie clip. This is the bulk of the brains behind
our drawing logic. When the mouse button is pressed on bg, this method is called
repeatedly. Basically, it grabs the coordinates of the mouse cursor. If it's not within the
boundaries of bg, we'll adjust those coordinates so that it is. After all, we don't want
people drawing off of the pad.

bg.drawControl = function () {
x = this._xmouse;
y = this._ymouse;
i f (x < 0) X = 0;
i f (x > this. _width) X this. _width;
i f (y < 0) y = 0;
i f (y > this. _height) y = this. _height;
i f (this.lastX != "") {
_root.drawing.moveTo (this.lastX, this.lastY);
_root.drawing.lineTo (x, y);
_root.drawingData.push ([this.lastX, this.lastY, x, y,
_root.currentColor]);

this.lastX x
'
this.lastY y;

As the user drags the mouse around, we draw lines that follow the mouse cursor. We know
where the lines should be drawn because we're keeping track of the last place the mouse
was before this method was called (lastX and lastY).

The drawing is accomplished by using Flash MX's new drawing API. Quite handy really. If
we were using Flash 5 for this project. we'd have to resort to some nasty manipulation of
a line contained within a movie clip. It's been done, but it's not simple (or pretty).

You may have noticed that there's an i f statement that says i f this .lastx doesn't equal
an empty string, then. We need this because when you press the mouse button, we haven't
Ming a

drawn anything yet, so we have to establish where the mouse has been once (capture the
lastX and lastY values) before we can draw a line.
Also, you'll notice that we're pushing data into our drawingData array. We're adding an
array that contains the coordinates of the line we've just drawn and the hexadecimal value
of its color.

10. Now we're going to add the code for the button event handlers for our bg movie clip- a
wonderful new Flash MX feature. The first method says that when the user clicks on bg,
we'll set up the line drawing style based on our currentColor hex variable. Then, we'll
grab the current coordinates of the mouse cursor, so that we'll have a place to draw a line
from when drawcontrol runs. The next line uses another great Flash MX addition -
intervals. This statement will run drawControl every 60 milliseconds (or about every
other frame where our movie is set to 30 frames per second) until further notice.

bg.onPress = function () {
_root.drawing.lineStyle (8, "Ox" + _root.currentColor, 100);
this.lastX this._xmouse;
this.lastY = this._ymouse;
root.intiD = setinterval (this, "drawControl", 60);

Further notice just happens to be when the user releases the mouse button. This handled
in the onRelease method:

bg.onRelease = function () {
clearinterval (_root.intiD);

bg.onReleaseOutside = bg.onRelease;

Lastly, we assign onRelease as the event handler for onReleaseOutside. This is so that
when users happen to move the cursor outside of bg, while they're still drawing, and then
release the mouse button, drawing will stop. A good idea, I say!

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
8 Advanced PHP for Flash

Alright, that's it! Publish that SWF to guestbook_form.swf. It should look something like this.

guestbook.php
Phew! We made it. That was indeed a hefty chunk of code, but we got here nevertheless. But
we're not done yet; on to the PHP. Fire up your favorite text-editor, we're going in!

As we've done in the past, we'll start out defining some variables for database access. For your
pleasure, I've used the same information as in previous chapters.

<?php
//your morn's guestbook
//version 1. 0

//define database connection information


$db_host "localhost"i
$db_user "user"i
$db__pass "pass"i
$db_narne "phpforflash" i
$db_table = "guestbook"i

First, we'll output some good ol' HTML to set up our page. We'll define a few different CSS styles.
Style sheets are our friends and will control the look of our guest book. Then we add a table
with all of the entries and the guest book form SWF wrapped up in it. Organized!

//output some good ol' HTML w/sorne styles

<htrnl><head><title>Your Morn's Guestbook</title>


<style type="text/css">
Ming s

<!--
body
font-family "Verdana";
font-size Bpt;
background-color #444444;
color : white;

td {
font-family "Verdana";
font-size Bpt;
background-color #444444;
color : white;

.label {
color : white;
font-size 7.5pt;
font-weight : bold;

hr{
color white;

a:link {
color : white;
font-size 7.5pt;

a:visited
color : white;
font-size 7.5pt;

.header {
font-family "Verdana";

' D
I rn CJ cJ

;\~ic L'
Dec~ e
s Advanced PHP for Flash

font-size : 13pt;
font-weight : bold;
color : #BBFF88;

.pageHeader
font-family : "Verdana";
font-size : 18pt;
font-weight : bold;
color : #DDFFBB;

.formtable
border : lpt solid white;

-->
</style></head>
<body>
<Span class="pageHeader">Your Mom's Guestbook</span><br><br><br>
<table border="O" width="500"><tr><td class="header">Sign The
Guestbook</td></tr>
<tr><td>
<?php

Unsurprisingly, we need to connect to the database. Note the die commands. If either of the
statements fails, die will stop the script and output the message we've specified. Because we've
defined our styles already, if this happens, it should be pretty, at least.

//connect to database
$db = mysql_connect ($db_host, $db_user, $db_pass) or die ("Could
not connect to
DB.");
mysql_select_db ($db_name) or die ("Could not select database.");

In recent versions of PHP, by default, variables that arrive by POST are put in an associative array,
$_POST. This is done for security. For your information, all external variables are put in
Ming 8

$_REQUEST whether they arrive via POST, GET, a cookie, etc. So, we check for a POSTed variable
called name. If there is one, we can assume that form data has been POSTed to us.

//if name is present in our POST variables, then form data has been
sent--process it
i f ($_POST ["name"])

One of the first things we'll do is insert a guest book record into our database. It's a good idea
to encode your data before sticking it in the database. Data with quotes and other miscellaneous
characters can mess up your precious database records. This would be a great place to encode
the data, too, except that we've already done it in our guest book form.

//create record in database


$query= sprintf ("INSERT INTO $db_table SET name= 1 %S 1 ,
location= 1 %S 1 ,
submit_time= 1 %s 1 , email= 1 %s 1 , msg= 1 %s 1 ; " ,
$_POST ["name"],
$_POST["location"],
date("Y-m-d h:i:s"),
$_POST["email"],
$_POST ["msg"]
)i
$result = mysql_query($query);

However, it is good practice to make sure your data is all square here, too. In fact, it would be
really wise to add some data validation logic here, also. That way, you reduce the likelihood of
bad data being inserted into your database. For brevity, I'll leave this up to you.

If the entry was saved successfully, we need to show a message indicating so. This tends to please
the user. On the other hand, if it doesn't save for some reason, we'd better bail out now. We
don't want to save an SWF picture for someone that won't have an entry in our guestbook at
this point.

i f ($result) {
echo "Entry was submitted.<br>";
else
//uh oh!

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
8 Advanced PHP for Flash

echo "ERROR: Could not submit entry.<br>";


exit() ;

First we'll grab our background color and break down the string into three separate decimal values:

//extract RGB values from bg_color


$c $_POST ["bg_color"];
$r hexdec(substr($c, 0, 2));
$g hexdec(substr($c, 2, 2));
$b hexdec(substr($c, 4, 2));

Next, we'll create our SWF object with Ming, setting up its dimensions and background color. We
can leave the frame rate at default, since there's no animation (although that would be cool to
add later...).

//create movie and set background color


$movie = new SWFMovie();
$movie->setDimension (200, 150) ;
$movie->setBackground ($r, $g, $b);

Remember when we joined our drawing data arrays into a giant string? Well, it's time to split it
up! With the next command, the data is returned to an array of encoded strings. We'll split
below, as we go.

//break drawing data down into an array of data for each line
drawn
$drawing= split ("y", $_POST["drawing"]);

This is the brains of our redrawing logic. Basically, we're stepping through our data array and
redrawing the picture just as it was originally drawn. First we split up a line's data. Then we grab
the decimal RGB values from our hex color variables. Then we draw the line and add it to the
movie. Cool!

//draw each line


$1 = sizeof ($drawing) - 1;
for ($i = 0; $i <= $1; $i++)
Ming 8

$linedata =split ( 11 Z 11 1 $drawing[$i));


$c $linedata[4);
$r hexdec(substr($c 0 2)); 1 1

$g hexdec(substr($c 2 2)); 1 1

$b hexdec(substr($C 4 2)); 1 1

$line= new SWFShape();


$line->setLine (8 $r $g $b);
1 1 1

$line->rnovePenTo ($linedata[O) $linedata[l));


1

$line->drawLineTo ($linedata[2) $linedata[3)); 1

$rnovie->add ($line);

Lastly, we save the SWF to a file with a filename based on the ID of the record that we just
inserted into MySQL. rnysql_ insert_id () returns the value of the auto_ increment column
that was used for the last INSERT query we did, which was inserting the guestbook entry.

I /save SWF file


$rnovie->save( 11 drawing 11 rnysql_insert_id() . 11 .swf 11 ) ;

If rnysql_insert_id () returns a value, we can expect to have a SWF that is named according
to the user's guest book entry. "Phew!"

Now, let's display the guestbook.

First, display our guestbook form. This code is based on standard code generated by Flash when
you publish an SWF. Note the bgcolor settings, these will need to be changed should you decide
to play with your styles.

//display add entry form

<OBJECT classid= 11 Clsid:D27CDB6E-AE6D-llcf-96B8-444553540000 11


codebase= 11 http://download.rnacrornedia.com/pub/shockwave/
cabs/flash/swflash.cab#version=6 1 0 1 0 1 0 11 WIDTH= 11 500 11 HEIGHT= 11 220 11
id= 11 guestbook_form 11 >
<PARAM NAME=rnovie VALUE= 11 guestbook_form. swf 11 ><PARAM NAME=quali ty

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
s Advanced PHP for Flash

VALUE=best>
<PARAM NAME=scale VALUE=exactfit><PARAM NAME=bgcolor VALUE=#444444>
<EMBED src="guestbook_form.swf" quality=best scale=exactfit
bgcolor=#444444
WIDTH="500" HEIGHT="220" NAME="guestbook_form"
TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/go/getfla shplayer">
</EMBED></OBJECT><br><br>

Next. we'll grab all of our guestbook entries from the database. The ORDER BY clause will ensure
that the newest guest book entries appear first.

</td></tr><tr><td class="header">Guestbook</td></tr>

<?php

//show all guestbook entries


$query = "SELECT * FROM $db_table ORDER BY id DESC";
$result= mysql_query($query);

Then, we grab a row and loop through all the variables and decode them. This converts all of
our %2Cs back to commas and so forth.

if (mysql num rows ($result)) {


//process each row individually
while ($row= mysql_fetch_assoc($result))
//decode all items in this entry
foreach ($row as $key => $value) {
$row[$key] = rawurldecode ($value);

Now we need to output some HTML to display our data, such as the date the entry was
submitted, who submitted it, etc.

//display HTML part of entry


echo '<tr><td><hr size="l"><span class="label">#' . $row["id"] . "
",
Ming 8

echo 'Submitted </span> ' . $row["submit_time"] . '<br>';


echo '<a href="mailto:' $row["email"] . '">' . $row["name"]
'</a> ';
echo '<span class="label">from</span> ' . $row["location"];
echo ' <span class="label">writes:</span><br><br>';
echo $row["msg"] . "<br><br>";

We also want to show the user's guestbook SWF. There's nothing to draw, it's all saved to an SWF
on the server, ready to display, thanks to Ming!

//display Flash part of entry

<OBJECT classid="clsid:D27CDB6E-AE6D-llcf-96B8-444553540000"

codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swf
lash.cab
#version=6,0,0,0" WIDTH="200" HEIGHT="150">
<PARAM NAME=movie VALUE="drawing<?=$row["id"]?>.swf">
<PARAM NAME=quality VALUE=best><PARAM NAME=scale VALUE=exactfit>
<PARAM NAME=bgcolor VALUE="">
<EMBED src="drawing<?=$row["id"]?>.swf" quality=best scale=exactfit
bgcolor=""
WIDTH="200" HEIGHT="150" TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">
</EMBED></OBJECT><br>

How does Flash know which one to display? It uses the value of the id column from the guest
book entry in the database, which is how we named the SWF that we saved earlier. Again, this
code is based on the HTML that Flash outputs when you publish.

We need to add a link to download this SWF, using our little buddy, download.php, which we
are going to look at in the next section. Again, we'll reference the image based on the ID of the
user's guestbook entry in the database.

<a href="download.php?image=<?=$row["id"]?>">Download SWF</a>

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
s Advanced PHP for Flash

Finally, we clean up. Save that file. Ah, we're getting close.

</td></tr>
<?php

mysql_free_result ($result);
else {
echo '<tr><td>No guestbook entries have been added
yet.</td></tr>';

echo "</table>";

mysql_close ($db);
?>

download.php
As mentioned before, the sole purpose of this file is to allow users to download existing SWF images.

<?php

i f ($_GET ["image"] != "") {


$filename= "drawing" . $_GET["image"] . ".swf";
$filename = basename($filename);
if (file_exists($filename)) {
header("Content-type: application-download");
header("Content-Disposition: attachment; filename=\"$filename\"");
$f = fopen ($filename, "rb");
fpassthru ($f);
else
echo "Sorry, that file is not available.";
Ming 8

First, we look to see if the variable image has a value in the GET array. If it doesn't, we are out of here.
Otherwise, we'll construct a filename based on the ID that was sent. This is good for two reasons:

It lessens the amount of data that is being passed between pages (every little bit counts).

It provides some security. This file basically gives access for users to download files from
your server. If we force construction of the filename, we limit their choices to files that
start with drawing and end in . swf. Furthermore, using the basename function restricts
them to files in the current directory.

It is important to check to see if the file exists, because it would be a disappointment to


download a file that doesn't exist. You'd get a text file containing a PHP error message, actually.
To force the download to start, we send out some HTIP headers.

Finally, we send the file using fpassthru ().

Setting up the database

For our guestbook application, we'll need to add another table to our phpforflash database.
This single table will house all of our guestbook entries.

1. First, you'll need to run the MySQL client, just as you have in previous chapters. Once
you're in, we'll select our phpforflash database.

USE phpforflash;

2. Next, type in the following query, line by line.

CREATE TABLE entries (


id INT NOT NULL AUTO INCREMENT PRIMARY KEY,
name VARCHAR(48) NOT NULL,
location VARCHAR(48) NOT NULL,
email VARCHAR(32) NOT NULL,
msg TEXT NOT NULL,
submit time DATETIME NOT NULL
) ;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
s Advanced PHP for Flash

This query creates a table called entries and defines several columns for our data: a unique ID
for each entry, various text fields for basic user information, such as name and location, and a
great big text field that will contain the message body.

Running the application


That's it! Put guestbook_form. swf, guestbook. php, and download. php into a directory on
your webserver. Note: Since our application writes to the current directory of the webserver, you
must have write permission set up for this folder. If you've made it this far in the book, you'll be
familiar with how to do this.

Then, run guestbook.php from your browser and you should see the following:

lntcmr-tfxplor~' .r
Ming 8

Summary
Welt, you made it. Congratulations!

As you probably realize, this project just scratches the surface of what can be done when you
combine the strengths of powerful tools such as Flash, PHP, and Ming. Your head is probably
buzzing with ideas on how to extend this application and make it even better. Or maybe your
head is just buzzing. In any case, you've got a great base to work from. It would be good for you
to ponder the directions that you could go with this. Think about it and then do it!

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Flash, PHP,
and MySQL
Chat room
I don't know about you, but sometimes there's nothing I like more than a good old-
fashioned chinwag. Ever since I started working from home I've missed the social
interaction of the office environment (though you can keep your office politics, thanks
very much) and I've found myself reaching for the telephone or my instant messaging
gq
client to satisfy that need to gossip about meaningless things.

In this chapter we're going to pander to the gossipmonger in all of us and build a Flash-
based chat client. You've probably seen these all over the shop in various guises, and
probably most notable of all is the slick avatar world at http: I /www. dubit. co. uk.

gq
DO
D
D

ID B~
BB ~~
DO DO
or
or
~ D
J D
::Jr
D BD % B DO
....Jl
u rRdd
Advanced PHP for Flash

Before you get too excited, we're not building anything of that caliber here (stop moaning at the
back) - a case study like that would easily fill this entire book - but we are going for something
a little bit more than a standard text chat.

The majority of the Flash-based chat rooms that you see on the Internet use ActionScript's
XMLSocket object to make a permanent connection to a dedicated chat server program. While
PHP does have socket support (as looked at in Chapter 6), it isn't really geared up to run a chat
server. In addition, most web hosting companies won't let you run a socket server. so we'll have
to find another way to communicate between client and server.

Thankfully we can knock together a useable chat environment using nothing more than your
friend and mine - LoadVars. We're going to store the chat data in a MySQL database and use
PHP as a go-between to fetch and store data as required by the Flash client.

A design for life


Before we can delve headlong into writing our chat room, we need to set out a few clearly
definable goals, as well as give ourselves a clear idea of how the application will run and a rough
sketch of what it will look like.

Features
We've already stated that we want the chat data stored in a MySQL database, but what other
features do we want our chat room to have? I've had a look at other text chat systems. as well
as seeking Zen-style inspiration that only comes from staring at your monitor cross-eyed for
extended periods of time, and ended up with the following list:

User authentication: Many Flash-based chat systems have little or no user authentication,
requiring you just to enter a username to join in the chat. While this is great for the user,
as they don't have to jump through any hoops to log in, this system leaves itself open to
abuse. For example, there's nothing to stop someone going into a chat room that I use
often, logging in as SteveWebster, and pretending to be me. To get around this problem,
we're going to require our users to register to be able to enter the chat room. This will
create a user account for them protected by a password, which they will need to enter
every time they return to the chat room.

Active user list: There's nothing more frustrating than sitting in a chat room with no user
list and having to guess blindly who is in there or whether or not someone who you've just
Case Study 1: Chat Room

been chatting to has logged out or is taking a toilet break. We're going to maintain a list
of active users in the chat room to avoid such confusion.

User-selectable color for text: During my research (read: undercover feature pilfering)
for this chapter I found it extremely difficult in some chat rooms to keep track of who was
saying what. This was because for a lot of the time, every user's messages were in the same
color, so I thought it would be a good idea for our chat room to allow users to select their
own text color.

Clickable URls: This is pretty much a standard feature of text-based chat systems, Flash
or otherwise, and is extremely frustrating when it is absent. The archaic sequence of select-
copy-paste may have been acceptable in the dim and distant past, but we're not happy
today unless we can click things.

IRC /me command: IRC has to be the definitive text-chat environment. It's almost as old
as the Internet itself, has billions of users worldwide, and there are hundreds of chat clients
that use the IRC protocol. One of my favorite little tricks that IRC has is its /me command,
which is used to indicate an action or a state for your user. For example, if I was logged in
as NETbreed, then typing /me is confused would result in the output of NETbreed is
confused. This is officially known as an action message but can be used to great comic
effect, and it's something worth having in the chat room application we're building now.

Stored preferences: Since we're allowing the user to pick their desired text color, it would
be nice if our application remembered this the next time they returned. Rather than having
the burden of storing this on the server, we're going to use a local SharedObject to store
the settings on the user's own computer.

In addition, the application should be fairly quick in operation and not put too great a strain on
the server.

Looks are everything


The main point of interaction between the user and our chat room is the user interface. Though
many users often resort to shouting at their computers, the only effective way to control them
at present is by using input devices such as the mouse and keyboard. As the user is going to
spend so much time interacting with our user interface, it's important that we get it right, and
that's what we're going to be look at now.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

Thankfully this isn't as daunting a task as it may have been due to the fact that chat rooms,
however they were developed, seem to stick to the same basic layout. You have a large area on
the left showing the chat history, a space below that for entering new messages, and an area to
the right that contains the user list.

Chat History User List

Message Entry
I I
Taking this into account, I came up with the following design for our chat client interface:

User Lid

Flo.:n + PHP + My6~L Cnot 6ymo"' AdYonccd PHP fo~ Fl""n


ouches o "'"cost. slu<ty IIC'UC!IIy. ,, o.r< hero
900cHn~you

u>t r wo.s lookong for" onvu>Cltion o '"''" c in lilt auogn


SC"IM ona! dodn' fancy ')l?ong a my <elf m<lkong U? plpi~ OnC
"'tiS<!QtS.
ETb""ed : H~y AI I bo.d ac+oollyl G 1119 a ted 0530
has 11o.d o. dc"rtmen"'al impo en my kcnd-e.y~E. co<~rair10 io.nth1s
"'~rnong. u+ o'her n(ltl hot rm f hng surpros.ngly <hoJ'!'YI
Matt: lot
Swi::l.yoo: : Hello <Y<ryonc
AI"" : Ho John Wt'v<l><:m ~<>o!ong for yo ~.pop on o)
Matt: Ho john
Matt wa~:: at Jokn fr-om aero:.: the room .
ETb""cd Hey Jolu\. Ho or< you on 'hos fin< and Jnny (po.h)
day> Did you 9f!l !11~ cho~er r SUI over last n1gh:>

Sclld I Settings II t.ov 0ut I


Message Entry
Case Study 1: Chat Room

Looking at this, you can see that we've added a few buttons to the basic design that can be used
to bring up the user configuration screen (to allow the user to set their text color, for example,
which comes from our features list) or to log out of the chat room altogether.

In addition to the Settings dialog, we're going to need a few other dialog boxes to capture the
user input for specific purposes. Here is a full list of the dialogs we're going to need, in addition
to the main chat interface:

Login dialog: The Login dialog will capture the user's username and password in order to
log them into the chat room. We will also need an option to bring up the Register dialog
so that users without an account can create one.

Register dialog: As we've just mentioned, the Register dialog will be used to get the user
details necessary to create a new account. For this example we're only going to collect the
user's desired username, a password, and email address, but you can collect as much or
as little information as you like.

Settings dialog: The Settings dialog will allow the user to pick a hexadecimal color value
for their message text as it appears in the chat history. As we discussed earlier, this will
allow the user the easily separate messages from different users, in addition to the fact
that users love being able to customize things!

Message dialog: Finally, we need a dialog to display error messages when appropriate.
This could be because of a system error or simply because the user forgot to fill out all
the required information on one of the above dialogs. Either way, the user needs to be
alerted to the fact that there is a problem, and we'll use this dialog to do so.

Database design rules!


With everything else sorted out, the only part of the design phase left to look at is how we store
the information in the database. I don't mean how it gets into the database - we'll get to that
bit later on when we tackle the PHP scripts. We need to look at what information is stored in the
database and how that information is structured.

Let's have a look at the information we need to store in the database. We'll tackle user
information first and move on to message information in a few pages time.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

User
Username

Password

Email address

User status

As far as each user is concerned, we want to store their chosen username and password in the
database, of course, so that they can log in to the chat room. Also, we want to keep their email
address so that we can contact them if necessary. The last item on the list for the user - the
user's status- is a little more complicated so we'll go into that in a bit more detail.

In order to display the list of active users, we need some way of determining which users are
logged in and which are not. We could do this by setting a value in the database when the user
logs in, and clearing it again when they log out, and query this value to produce the list.
Unfortunately users don't always do what they are supposed to, and some may just close the
browser window rather than logging out properly. This would leave the user's status set as logged
in, and they would still be included in the active user list even though they are anything but active.

Having figured this out, we need to find another way to determine the user's status. If we store
the current time in the database every time the user reads new messages from the server, and
keep track of that value, we could use a cut-off time to determine which users are still in the
chat room. An example will probably make this a little clearer:

Let's suppose that we have a cut-off time of 30 seconds. In order to get the active user list for
the chat room, we simply display all those user accounts with a last-updated timestamp greater
than the current time less 30 seconds. Of course, we'd need to make sure that the chat client
was fetching new messages more frequently than every 30 seconds for this to work, but it
illustrates the concept that we are going to use in our application.

Now, we could store this timestamp value as part of the same table as the rest of the user data.
However, we could have hundreds of registered user accounts and only five users in the chat
room, and querying the whole of the user table to find these five users is less than efficient.
Case Study 1: Chat Room

To get around this problem, we're going to split the user data up again into two smaller logical
groups. The data list would now look something like this:

User

Username

Password

Email address

Active users

Link to user account

Last update timestamp

This would allow us to add and remove rows from the table storing the active user data as users
log in and out. Also, we could weed out those users who haven't logged out properly (and
therefore haven't had their row in this table removed) by only selecting records that have been
updated since the cut-off time.

Next, let's move on to messages and look at the information we want to store in the database.

Message

Message text

Time of message

At first glance you might ask why we don't want to record which user posted a given message.
The answer is that we don't need to because usernames are stored as part of the message text.
This breaks most of the database design rules I was taught while studying Software Engineering,
but sometimes you have to break the occasional law in order to develop the most efficient
application -which is one of the main goals we stated right at the beginning of this chapter.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

Database table specifications


Having loosely discussed the data we need to store, we need to nail that down into a firm
database structure so that we know what information we're dealing with when we come to write
the application in a few page's time.

Table: chatUsers

Column Name Data Type Description


This will enable us to uniquely identify each user and
use riD Integer
to link rows in other tables to a specific user account.
use marne String The user's chosen username.
password String The password for the user's account.
email String The user's email address.

Table: chatUserlist
Column Name Data Type Description
A link to the row in the user's account in the
useriD Integer chatUsers table.
The timestamp of the last time the user's chat
lastActivity Integer client requested an updated message list. Used to
weed out non-active users.

Table: chatMessages
Column Name Data Type Description
The preformatted message text ready to be sent
body String
to the Flash client for display.
The timestamp of when the message was posted
posted Integer
to the database.
Case Study 1: Chat Room

Flash in the pan


Now that I've successfully snuck the most abused Flash-related pun into the book in the form of
the above section header - and more importantly now that we've got the design phase out of
the way- we can move on to coding the Flash side of the application. This is essentially the chat
client, and we'll create the chat server a little bit later in the Server-side shenanigans section.

Funky buttons ahoy

Before we get into the thick of building the Flash movie, we need to make a swanky button
component that we can use to build part of the user interface. Since we haven't covered
component creation in this book this may seem a little bit complicated at first, but the end
results are worth it. Don't forget that you can always check with the source files for this chapter
if you get lost at any point.

At this point I should just mention that we're not going to be doing anything overly fancy with
this component, and that includes not adding it to the Component palette in the Flash MX
authoring environment.

1. OK, first things first. Create a new movie and save it as chatclient. fla. Inside this movie
create a new movie clip and arrange the timeline so that it looks something like the following:

,-- .. "
-~ 0

..0 ll
.. 5 10
0 I
15
I I
20 25
I 0 I'
30
'.
35 40 45 50 Hj

.. ..
COl States _up ol~overol~-down ol~diSablee
CV C~ption
0
[01 State Images 0 ol. ol. ol. 0
i[J.f4Ll - 1!SI +J ~ ~ !]fll1201ps ro:o.- 41 j
Our component uses a new feature of Flash MX to achieve its button-like actions, and the
_up, _over, and _down frame labels play an integral part in this. It is also possible to have
a _hit frame to define the hit area of the button, though we're not using that here.

When a movie clip has an onPress or onRelease event handler assigned to it then it
behaves like a button and will automatically show the appropriate frame from above. This
saves us a little bit of coding so I decided to use it here, though we will have to implement
the disabled state manually since that isn't part of a standard button.

I 0
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

2. While we're here, let's get the graphics out of the way. If you're following my example then
you can copy the graphics from the following screenshot. If you're going it on your own then
go ahead and create whatever graphics you want for each state on the State Images layer.

)
_up _over _down

3. Finally, add a dynamic textfield to the Caption layer with an instance name of
caption_txt. Don't worry about text color (we'll deal with that in the ActionScript code
in a moment) but set the textfield to center justified, ensuring that it covers the whole
width of the button.

4. With all that done, we're finally ready to move on to the code that'll make our button
dance. The first thing we need to do is to create our new button class, which we'll call
FSimpleButton. Add the following code to the frame on the Definitions layer.

#initclip 1

II Constructor
FSimpleButton =function(){
II Initialise component
this. init () ;
};

II Inherit from MovieClip object


FSimpleButton.prototype = new MovieClip();

II Register component class


Object.registerClass("FSim pleButton", FSimpleButton);

If you're not familiar with the way in which components are created in Flash MX, then the
above may seem a little confusing. All we're really doing here is telling Flash that we have
created a new component that is derived from the standard MovieClip object, and that
the component is identified in the Library with a linkage id of FSimpleButton. The
function that we're creating is known as the constructor, which is executed when an
Case Study 1: Chat Room

instance of the component is created and is used to initialize the component so that it is
ready to use.

5. Before we go any further we need to define some component parameters for our
component. Right-click on our movie clip in the Library, select Component Definition ...
from the menu and create the following parameters:

Name !Variable I Value I Type


Button Caption captionTeKt String
Caption Color [Enabled] captionColor #000000 Color
Caption Color [Disabled] captionDisabledColor #999999 Color
onCiick Handler clickHandler String
Show Hand Cursor showHand false Boolean
Status Text status Text String
Status Variable statusVar s:tatusTe~t String

We're not going to use all these parameters in our chat room application, but it's good to
have a fully featured button component that you can drag into your applications.

6. The next thing we want to do is to define our init method, which will be called when a
new instance of our component is created and sets up the component ready for use.

II Initialise component
FSimpleButton.prototype.init =function(){
II Set caption text and color
this.caption_txt.text this.captionText;
this.caption_txt.textColor this.captionColor;

II Setup cursor and disable tabbing


this.useHandCursor = this.showHand;
this.tabEnabled = false;

II Set event handlers


this.onRollOut this.myRollOut;
this. onRollOver this.myRollOver;
this.onPress this.myPress;
this.onRelease this.myRelease;

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

this.onDragOut this.myDragOut;
this.onDragOver this.myDragOver;
this.onReleaseOutside this.myReleaseOutside;
};

You can see here that we're setting the text and text color of the caption_txt textfield.
The variables used for this are among the component parameters that we set in the
previous step.

Next up we set the cursor according to the showHand component parameter (whether or
not we want the cursor to turn into a hand when the mouse pointer rolls over our buttons)
and then disable our button from receiving input focus using the TAB key. I've done this
because I think that nasty yellow focus rectangle spoils the design of the application; it's
up to you if you keep this in or not.

Finally, we set the mouse-related event handlers for our component, and since we're
inheriting from the MovieClip object, we've got quite a few to play with. We won't
actually use all of the ones set here, but I've included them just in case you wanted to do
something a little different with your button component.

7. Next, we're moving on to creating the event handlers that were just mentioned. The first
groups we need to deal with are the onRollOut and onRollOver handlers. We're going
to use these to set a status variable on the parent timeline.

FSimpleButton.prototype.myRollOut = function()
this._parent[this.statusVar] = _global.oldStatusText;
};

SimpleButton.prototype.myRollOver = function() {
_global.oldStatusText = this._parent[this.statusVar];
this ._parent[this.statusVar] = this.statusText;
};

The status variable is specified as another of our component parameters is the actual
status text. We'll use the global variable oldStatusText to store and retrieve the previous
status text. From our initial design sketch of the chat interface, you can see that we aren't
going to have an area to display status text, so this feature will be unused in our application.
Case Study 1: Chat Room

8. Moving on to the onPress and onRelease handlers, you can see from the code below
that the former is actually unused at present. This is one of those "included just in case"
event handlers I mentioned earlier, and would be useful if you wanted to expand the
functionality of the component.

FSimpleButton.prototype.myPress function() {
} i

FSimpleButton.prototype.myRelease = function()
II Execute callback
this._parent[this.clickHandler) (this);

The onRelease handler, on the other hand, is probably the most important event handler
of all in our component. lt is this handler that calls the function specified in the
clickHandler component parameter.

You'll notice here that we're passing a reference for the current object to the callback
function. This is useful if you have a single callback function for several buttons and need
to determine which button initiated the callback. We won't actually use this in our
application, but it's another useful feature to have nonetheless.

9. There is only one event handler left that's actually implemented, and that's onDragOut:

FSimpleButton.prototype.myDragOut = function() {
this.gotoAndStop("_up");

I've used this to correct a small quirk in the way that buttons operate in Flash. In most
common operating systems, when you hold your mouse over a button and then drag the
mouse outside, the button returns to its "up" state, indicating that releasing the button now
will not count as a button press. In Flash, however, the button will remain in its _down state.

To correct this, all I've done is to send the button back to the _up frame when the mouse
is dragged outside of the button area. It's up to you whether you want to implement this
or not, but I like to keep things consistent.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

10. The remaining event handlers are not implemented.

FSimpleButton.prototype.myDragOver function() {
};

FSimpleButton.prototype.myReleaseOutside function() {
};

11. The final thing we need to do for our component is to create some methods to allow us
to enable and disable the button from outside of the component. This is where the
_disabled frame comes into play.

FSimpleButton.prototype .disable =function(){


this.caption_txt.textColor = this . captionDisabledColor;
this .gotoAndStop ("disabled");
' this.enabled =false;
};

You can see that all we're doing here is changing the color of the caption text to that
specified in the captionDisabledColor component parameter, moving to the
disabled frame, and disabling the component. While the component is disabled, no
events will be processed and it will remain on the designated frame.

12. The enable method simple reverses the changes made in the disable method; enabling
the button, moving it back to the _up frame, and resetting the caption text color.

FSimpleButton.prototype . enable =function(){


this.enabled = true;
this .gotoAndStop ("_up" ) ;
this . caption_txt . textColor this.captionColor;
};

13. I've also thrown in an isEnabled method, which will allow the button state to be
determined. Again, this is another feature that we won't be using in our application but
that could be handy in another.
Case Study 1: Chat Room

FSimpleButton.prototype.isEnabled function(){
return this.enabled;

#endinitclip

stop();

That completes our component definition and it's now ready to be used. If you haven't
already done so, rename the component in the library to FSimpleButton and set its
linkage as follows:

Identifier: jFSimpleButton OK
Linkage: P' Export for ActionScript Cancel
r Export for runtime sharing
r Import for runtime sharing Help
P' Export in first frame

URL:

Strike up a dialog ... or four


There's one more aspect to look at before we can start on the main chat interface for our
application. We mentioned a while back that we'd need some dialog boxes to get various bits
of information from our users, and we're going to build them now. Each one is fairly small and
includes very little code, but they are essential to the running of our application, so we're
going to take some time to get them right.

Login dialog

First up, and probably the most used, is our Login dialog. The user will use this to gain entry to
the chat room, and it will be shown automatically when the chat client is first loaded and when
the user logs off.
Advanced PHP for Flash

1. Create a new movie clip in the library, call it Login Dialog and set up the timeline so that
it looks something like this:

All our dialogs have the same timeline structure as they all include the same basic
elements, so you'll want to remember this for the remaining dialogs.

2. On the Background layer, create a


suitable window style of your
choice. I've gone with the one r
shown, and again it's going to be
the same for each of the dialogs,
although it will need resizing to fit
in all the elements on some of
them.

3. On the Header Text layer, we need


to add a textfield to display the
dialog title over the nice gradient
!~~~~ ~~:~i:~:.~:::::::::::: :::::::::::::::::::::::::::::::: J
title bar we've created so that the
user knows what the dialog is for:

4. With that out of the way it's time to move onto the Elements layer. This is where all our
input textfields, field labels, and buttons will go to actually make up the usable parts of
the dialog.
Case Study 1: Chat Room

In terms of input textfields, we're !u~;;~ i.:.~-git~:.~ ------ ----------- ------ -- --------------:
going to need one for the user's ~ ..... -.-- ... -.-- ----- -.--- ---- ---- ...... - ... - ....... - ............. -!

rc,~;;~~:
username and one for their .. ___ -- ----- - ~

password. Each should be labeled


appropriately.

The username and password input fields should be given instance names of use:mame_txt
and password_txt respectively, and should both have the Border option turned on and
be limited to a maximum of 30 characters. For the password_txt textfield, you should
change the Line Type setting to Password so that any input is masked with asterisks.

If the input textfields look a little on the ugly side to you, don't fret as we're actually going
to change the border and background colors via ActionScript in a moment. It's just that
turning them on here saves us two lines of code for each textfield.

5. The final thing we need to do before we move on to the code is to create some buttons.
We'll need one to submit the details entered by the user and one to bring up the Register
dialog so the user can register for an account.

With that in mind, drag two copies of our FSimpleButton component from the Library
on to the Elements layer and set them up as shown below:

!~~~:~ ~~~i!~:.~:::: : : : :: ::::::


:uS"err.;;-,;;e:
::::::::::::::::::::::::::::::
~---.--.-- ... .:

Button Caption Register ... Button Caption login


Caption Color [Enabled] #000000 11111111 Caption Color [Enabled] #000000 11111111
Caption Color [Disabled] #999999 11111111 Caption Color [Disabled] #999999 ~
onCiicl<. Handler doRegister onCiicl<. Handler dologin
Show Hand Cursor false Show Hand Cursor false
Status Text Status Text

All we've changed here, from the defaults, is the Button caption and onClick
Handler parameters for each of our buttons.

o D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

6. At last we come to the ActionScript for our Login dialog. The first thing we need to do is
to set the background and border colors of the input textfields as mentioned earlier. I've
chosen colors that complement the design I'm using, so if you've gone your own way then
you might want to modify the color values given below:

II Set textfield colors


username txt.borderColor = Ox999999;
username_ txt.backgroundColor = OxDBDDE3;
password_txt .borderColor = Ox999999;
password_txt.backgroundC olor = OxDBDDE3;

As you can see, we set the colors using the borderColor and backgroundColor
properties of our textfields.

7. Next we're going to create a show() function for our dialog box. This will perform any
initialization needed and then make the dialog visible. Each of our dialogs will have one of
these functions, though the initialization required will differ from one to the other.

function show() {
password_txt.text - Till.- I

this. visible = true;

All this function does is clear the password field and then to the dialog visible. I've decided
to clear the password for extra security, so that it needs to be entered each time the user
comes to log in.

Now we come to the button functions, doRegister () and doLogin () .

8. Tackling these in order, all the doRegister () function needs to do is to hide the Login
dialog and show the Register dialog (which we're yet to create, but never mind about that).

function doRegister() {
this._visible = false ;
_parent.register_mc.show () ;
Case Study 1: Chat Room

We use the Register dialog's show () function here so that any initialization that is required
can take place before the dialog is shown. The advantage of creating a function like this
can be clearly seen here. We don't have to worry about what the Register dialog needs to
do its job, as it does that all by itself!

9. The final function in our Login dialog is doLogin () . This will need to check that the
required information has been provided in the dialog and then invoke the login procedure
or alert the user to missing information, as appropriate.

function doLogin() {
if (username_txt.length > 0 && password_txt.length > 0)
this._visible = false;
_parent.login(username_txt.text, password_txt.text);
else {
_parent.message_mc.show(null, "Both username and password are
required to log in");

If both a username and password have been given then we hide the Login dialog and call
the login () function from the parent timeline. We'll create this function later on, but
basically all it does is to check the login details with the server and act accordingly.

If the required information is not given then we need to alert the user, and we do this
using the Message dialog, which, again, we'll create later. We're using the show () function
again, but this time it takes some arguments in the function call. The first is used to
designate a dialog box to be displayed after the user confirms the error message, and the
second is the actual error message itself.

You can see that we don't use the first argument (instead passing null), which isn't
necessary in this case, as we won't be hiding the Login dialog. The error message just lets
the user know that both fields are required for the login to proceed.

That's our first dialog box done and dusted - now for the other three. Since the dialog
boxes have a lot in common we'll be skipping through these remaining dialogs fairly quickly,
so make sure you understand all the steps we've just been through with the Login dialog.

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

Register dialog

The next dialog on our hit list is the Register dialog. This is where users can create new accounts
for themselves.

1. The first step is to create a new movie clip in the Library called Register Dialog and to set
up the same timeline as before.

2. Add the necessary items to the


Background, Elements, and
Header Text layers to create : u~~~;;:
------------
something similar to this: :E~~:i;
t.. ......... .

...:::.-~~~i~:
_____ __ ___ ,

From top to bottom, the input textfields have instance names of username_txt,
email_txt, password_txt, and confirm_txt. All but email_txt should have a
Maximum Characters setting of 30, with email_txt being set to 255 instead.

The button components, from left to right have captions of Cancel and OK, and their
onClick Handler set to doCancel and doOK respectively. The rest of the parameters can
be left as default.

3. The ActionScript on the Actions layer is similar to that on the Login dialog we've just
created. First we'll set up the textfield colors and create the show () function used to make
the dialog visible.
Case Study 1: Chat Room

II Set textfield colors


username txt.borderColor = Ox999999;
username_txt.backgroundColor = OxDBDDE3;
email_txt.borderColor = Ox999999;
email_txt.backgroundColor = OxDBDDE3;
password_txt.borderColor = Ox999999;
password_txt.backgroundColor = OxDBDDE3;
confirm_txt.borderColor = Ox999999;
confirm_txt.backgroundColor = OxDBDDE3;

function show ()
this. visible true;

The docancel ( l function simply hides the Register dialog and redisplays the Login dialog:

function doCancel() {
this._visible = false;
_parent.login_mc.show();

Finally we come to the doOK() function, which checks that the required information has
been filled out, and that the given passwords match. It then invokes the register procedure
or displays an error message, as appropriate.

function doOK() {
if (username_txt.length > 0 &&
email_txt.length > 0 &&
password_txt.length > 0 &&
confirm_txt.length > 0)

if (password_txt.text == confirm_txt.text) {
_parent.register(username_txt.text, email_txt.text,
password_txt.text);
this._visible = false;
else {
_parent.message_mc.show(null, "The supplied passwords do not

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

match.");

else {
_parent.message_mc.show(null, "All fields are required for user
registration. ") ;

Message dialog

Since we've been using it a fair bit we'd better create the Message dialog, which is used to display
any error messages while the application is running.

1. Create a new movie clip called Message Dialog and copy the timeline from previous dialogs.

2. Add the necessary items to the


.---------------------------- ---- -----,:
Background, Elements, and :Error...
~- - - ------ - ---- -- -
Header Text layers to create
something similar to the one
.;---- ---------------------- ------------ --- ;
shown: .
~--------- - -- - ---- - - - ---------------------
-------------- ..
o I

: :
:................ ----- -- ---

The large dynamic textfield has an instance name of message_txt and its Line Type set
to Multiline. The textfield is also center-aligned, although that's more a matter of personal
taste than necessity.

The button has a caption of OK and an onCl ick Handler of doOK.

3. The code on the Actions layer is simpler than the previous two dialogs. We have a show ()
function and a doOK() function, and that's it since we don't have any input textfields that
need their colors set.

function show(callback, message) {


Case Study 1: Chat Room

this.callback = callback;
this.message_txt.text = message;
this. visible = true;

This show () function is a little bit special in that this one actually takes some arguments,
as we noted when we encountered it being used earlier. Here we store the callback
argument, which is a reference to the dialog box to be opened once the user hits the OK
button. For future use, set the message text and then make the dialog visible.

function doOK() {
if (this.callback)
this.callback.show();

this. visible false;

The doOK() function checks to see if callback has been set, and if it has, then it calls
the show () function for the dialog referenced. Either way, the dialog box is hidden and
the application continues as normal.

Settings dialog

In the Settings dialog we're going to allow the user to pick a color for their text in the chat
window. Rather than give them a limited choice, I thought it would be good to allow them to
enter a color value of their choice. We also want the user to be able to see what their chosen
color would look like without having to go back into the chat. As such, this dialog is going to be
a little more complicated than the previous ones.

1. Once again, create a new movie clip called Settings Dialog and recreate the now familiar
timeline from previous dialogs.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

2. Add the necessary items to the


Background, Elements, and
:u~~~ s~iii;;fi~~~.- )
------ ----- ---------------------- ------------- ........................
Header Text layers to create :;;~ic;;b--#:
:.... -------- .. -~--:
something similar to this:

f-------------n
'i-...-...-.. ............ ..... ....-..-

The input text field has an instance name of textcolor_txt and a Maximum Characters
setting of 6, while the dynamic text field with Sample Message Text in it has an instance name
of sarrple_txt and is set to display HTML using the toggle button on the Property Inspector.

The button has a caption of OK and an onClick Handler set to doOK. The rest of the
parameters can be left as default.

3. Now we get to the interesting bit - the ActionScript. This is where we will limit the
characters that textcolor_txt accepts and handle changing the color of the
sample_txt textfield text to reflect what the user has entered in textcolor_txt.

So, first up we set the textfield colors:

textcolor_txt.borderColor = Ox999999;
textcolor_txt.backgroundColor = OxDBDDE3;

sample_txt.background = true;
sample_txt.backgroundColor = OxDBDDE3;

Notice that we're only setting a background color for the sample_txt textfield so that
the user knows visually that it is not editable. Because the sample_txt textfield does not
have its Border set at design-time, we specifically need to turn on background rendering
by setting the background property to true.

4. Next we restrict the characters that can be entered into our textcolor txt textfield
using the restrict property.

textcolor txt.restrict "0-9A-Fa-f";


Case Study 1: Chat Room

We do this because only numerals and the letters A to F are valid in a hexadecimal color
value; we don't want the user entering anything else and confusing our poor application.

5. Then we set up an onChanged handler for the textcolor_txt textfield. This is where the
color of the sample text will be changed.

textcolor_txt.onChanged = function()
if (textcolor_txt.length == 6) {
sample_txt.htmlText = "<font color=\"#" + textcolor txt.text +
"\">Sample Message Text</font>";

You can see that we're using HTML to set the color of the text by using our value as the
color attribute value of the <font> tag. We only do this if a full color (in other words,
six characters) has been entered into the textfield.

6. Next up is the show () function for this dialog.

function show() {
this.textcolor txt.text _parent.textColor;
this. visible = true;

What we're doing here is copying the textColor value from the parent timeline to the
textcolor_txt textfield and making the dialog visible.

7. Finally we have the doOK () function.

function doOK() {
if (textcolor_txt.length == 6) {
_parent.textColor = textcolor_txt.text;
_parent.storeUserSettings();

this. visible false;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

If a full color has been entered then we copy the color value back to the textColor variable
on the parent timeline and call the StoreUserSettings () function. This function will store the
settings on the user's machine so that they can be restored when they return. Either way, the
dialog box is hidden.

That's the last of the dialog boxes out of the way, so it's time to move on to the Flash movie proper.

Main chat view

So now we come to the main chat view. This is where the received chat messages will be shown
and where the user can enter a new message to be added to the chat. It will also contain the list
of active chat users.

Our users are going to spend a lot of time here so we need to get the interface right. This is
where our design phase comes in especially handy since we already have a fair idea of what we
need and where everything is going to go.

1. The first thing we need to do is to set out the timeline for the application. The timeline
I'm using looks like this:

] 5 'ro ,5 2o 25 3o 35 '41l 45 5o Hj
Gil Actions . . DlIll ~
.-~ I I < I I> 0 I 0

(U Message Dialog .. .
Gil Re!jister Dialog
Gil Settings Di.!!log .. ..
III

Gil Lo!jin Dialog


[iiJ User Ust .. ..D
D
[iii Chat Area
[iii Background . .D -;
fV+"it::l @ u lill_taj ~ [~r--T [I2.0fPs" ro:o;- 4j _ J J

You can see that we've got the usual Actions and Background layers, but that the user
interface elements are split over several layers grouped in a layer folder. Inside this folder
there's one layer for each of the dialogs we created earlier, plus one for the user list and
one for the chat area.
Case Study 1: Chat Room

With regards to the dialog layers, it doesn't really matter what order they are in, except
that the Message Dialog layer should be above all the others as it needs to pop up on top
of the others if they are still visible. The User List and Chat Area layers should be below
all of the dialog layers so that the dialogs are visible above the main interface.

2. While we're here, drag a copy of each dialog from the Library to its appropriate layer. They
should be given instance names, top to bottom, of message_me, register_me,
settings_me, and login_me and each should be centered about the main stage.

You'll probably want to hide all of the dialog layers so that you can see what you're doing
through the remaining steps.

3. On the Background layer, carry over your styling from the dialogs we created earlier to
create the main window background for the application.

4. With that done we move on to the Chat Area layer, where we will create all the elements
that allow the user to send and receive messages and to control the application.

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

First up is the history window, which will display all the messages in the chat since the
user joined.

5. This is a simple dynamic textfield with a scrollbar component attached. Make the textfield
a decent size as the user will want to keep track of conversations.

The textfield should be given the following settings in the Property Inspector:

fA Jo~namicTe~t :::J A ]_sans

ro--- .:1
:::J ro .:J M IB~ ~~ =I. = I==I
..:.) r P.uto Kern
Jhistor!L t~t ASv A! JNormal
~ I Format ...

IV: J354 9 X: fiO:O [B J Multiline ..:J r;;m ro~ Var: J Character ... I
H: fmO V: f26.0 ~I Target: r ..l

As you can see we've geared the textbox up to render HTML. This is necessary so that each
user's messages are rendered in their chosen color.

If you attached the scrollbar before changing the instance name of the textfield than you'll
need to edit the scrollbar properties so that its Target textfield is set to history_txt.
Case Study 1: Chat Room

6. Next we need somewhere for the user to enter their messages, and some way of sending
the message. Add a single line input textfield and one of our button components to the
layer just below the textfield we created in the previous step. Your stage should now look
something like this:

El
I
I

The input textfield should have an instance name of message_ txt, and its Line Type set
to Single Line. The button should have an instance name of sendBtn, a caption of Send,
and an onClick Handler of onSend.

The reason we have given this button an instance name when we didn't with any of the
others is that we'll want to disable this button under certain conditions (like when the user
isn't logged in, for instance). Because we need to reference it from ActionScript, we need
to give it a suitable instance name.
Advanced PHP for Flash

7. Add two more buttons to the right of the Send button. One of these will be used to bring
up the Settings dialog and the other will enable the user to log out of the chat room.

IL ___ __ _ _ _ __
---
_____jl r::::.: ::J c::::::::J c:::::::::J

These new buttons, from left to right, should be given instance names of settingsBtn
and logoutBtn, captions of Settings ... and Logout, and onClick Handler settings of
doSettings and doLogout respectively.

8. Moving on to the User List layer, we want to create another dynamic textbox with a
scrollbar attached to display the list of active users in the chat room. There's a convenient
slot left for it, so throw it in the space to the right of the history_txt textfield.

R R
1:================::::::::;:-;:; [;:;:.:::; ::::
; :;:;~
:J '-;;
ll:;:;:;:;:
::.::_;:;:;:;:
: : .::;:;:;:;::::
.:;;-;;;:
1 [;;;;:;
_:::::;:;:;:;::::::;;;;:)
Case Study 1: Chat Room

Again we need to set the properties of the textfield:

rA jo9namlcText ..:J A j_sans


:::1 JW .:J-IB_1 ~~ =I==J=J
..:_l r
juserlist_txt !v jO _:1 A~
A jNormal Auto Kern
~ I Format ..

W: fi3i.O X: j390.0 0. JMultiline ..:J !!]~ Var: J


-
Character...j
H: f252.0 Y: [26.0 ~I Target: I "J

I've set it so that the text in the textfield is unselectable because I don't want the mouse pointer
changing to a text insertion cursor if the user happens to drag their mouse across it. I can't see
any reason why someone would want to select the user list, but this can always be left on if you
want it to be!

Code is your friend

That's it for the graphical portion of the main application view. Everything is now in place for us
to start writing the ActionScript that will glue everything together. Here we'll finally implement
the functions we touched upon earlier, such as login () and register () , as well as many more
that we've yet to encounter.

Most of these functions will be concerned with communication to or from the server for which
we've yet to write the PHP scripts, so I'll be asking you to take some things on faith -everything
will fit together in the end!

1. To begin with, we need to add a small extension to the LoadVars object. This will allow
us to clear all variables out of the object so that it can be used again without fear of it
"remembering" any information from the previous use.

I actually found it hard to believe that this isn't a standard method of the LoadVars
object, but it appears that Macromedia decided that we didn't need anything like that. Still,
at least they gave us the ability to extend the functionality ourselves.

LoadVars .prototype.clear = function() {


for (element in this) {
i f (typeof(this[element]) != "function")
delete this[element];
Advanced PHP for Flash

}
} i

As you can see, we're using a for...in loop to go through each element of the Loadvars
object and remove anything that is not a function. We need to check to make sure that
what we're about to delete isn't a function since both the onLoad handler and our new
clear method will be included in the elements processed, and we certainly wouldn't want
to delete those!

2. Next up, we need a function to initialize all the user interface elements and to create or
set up everything else as necessary. We could do away with the function and just shove all
this code at the top of the script, but it's good to be tidy about these things.

function init() {
II Stylize Flash Components
globalStyleFormat.background = OxDBDDE3;
globalStyleFormat.backgroundDisabled = OxDBDDE3;
globalStyleFormat.arrow = Ox8A9AAA;
globalStyleFormat.scrollTrack = OxB3B8C6;
globalStyleFormat.face = OxDBDDE3;
globalStyleFormat.highlight3D = Ox999999;
globalStyleFormat.darkshadow = Ox999999;
globalStyleFormat.applyChanges();

The first thing we do here is to set the style of the original Flash components that we're
using (that'll be the scrollbars then) using the globalStyleFormat object. If you haven't
encountered this before they it may seem a bit strange, but basically all of the standard
Flash components will obey styles set using globalStyleFormat.

3. From there we move on to do the same thing with our TextField objects so that they
match with our overall design.

II Stylize Textfields
history_txt.borderColor = Ox999999;
history_txt.backgroundColor = OxDBDDE3;
message_txt.borderColor = Ox999999;
Case Study 1: Chat Room

message_txt.backgroundColor = OxDBDDE3;
userlist_txt.borderColor = Ox999999;
userlist_txt.backgroundColor = OxDBDDE3;

4. Then we create the LoadVars objects that we're going to use to communicate with the
server. We're actually going to use two separate objects to separate message data being
sent to the server from message data being loaded, and a third that can be used for
sending non-message data to the server.

II Create Data Handlers


sendHandler = new LoadVars();
loadHandler = new LoadVars();
commandHandler'= new LoadVars();

II Initialize onLoad Event Handlers


loadHandler.onLoad = buildMessageList;
sendHandler.onLoad = function() {
sendBtn.enable();

We also set up the onLoad event handlers for two of our LoadVars objects. The event
handler for the loadHandler object is set to a function that we will create a little later in
this section, as it is quite a large function and would be messy to declare inline. The
handler for sendHandler, on the other hand, is declared inline since it is quite a small
function, which simply enables the Send button. We need to do this because we'll disable
the button once the send process is started, ensuring that the server handles the first
message before we try and send it another one.

If you're wondering why I've left out commandHandler here, the reason is that it is a
multipurpose data handler so we'll need to set the onLoad event handler to one of a
choice of functions depending on which command is invoked.

5. Now we need to create an object that will be used as a keyboard listener to detect when
theENTER key has been pressed and send the current message text to the server. This is an

extra feature to our original list, but having to grab the mouse and click the Send button
every time you want to send a message you've just been typing isn't very user friendly.

< D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

II KB Handler
kbHandler = new Object();
kbHandler . onKeyDown = fnnction ()
if (Key . getAscii() == 13) {
if (message_txt.length > 0)
sendMessage () ;

So we're creating a new object and creating an onKeyDown event handler for it. This is the
event that we'll need to respond to when we finally set this object up as a listener for the
keyboard. We check to make sure that the ENTER key (which has an ASCII value of 13) was
pressed and that there is actually something to send before invoking the sendMessage ()
function, which will actually submit the message to the server.

6. From there we need to hide any unnecessary dialog boxes on the stage (all except the
Login dialog) and disable the chat interface using the disableForm () function so that it
is inaccessible until the user has logged in correctly.

II Hide dialogs and disable chat interface


settings_mc._visible = false ;
register_mc._visible = false;
message_mc._visible = false ;
disableForm();

7. Finally, for the init () function, we need to take care of any other initialization business, which
in this case is clearing the history_txt textfield and setting a default text color of black.

II Mise Initialization
history_txt . htmlText = "".,
textColor = "000000";

8. Now we need a couple of utility functions that we can use to enable and disable the chat
interface. This includes the user interface elements as well as other things such as keyboard
listeners and the timers necessary to run the whole show.
Case Study 1: Chat Room

function enableForm() {
II Enable text fields
history_txt.selectable = true;
history_txt.border = true;
message_txt.selectable = true;
message_txt.border = true;
userlist txt.border = true;

II Enable buttons
sendBtn.enable();
settingsBtn.enable();
logoutBtn.enable();

II Create Timers
fetchMessagesint = setinterval(fetchMessages, 3000);
userListint = setinterval(fetchUserList, 60000);

II
Setup keyboard listener
Key.addListener(kbHandler);

Most of the enableForm () function should be fairly self-explanatory; visually enabling


textfields and making them selectable, enabling the buttons (you see now why they
needed instance names), and setting up the keyboard listener.

However, it's worth paying special attention to the section where we create the timers,
which can be used to perform specific actions at predefined intervals. In our case this
means periodically fetching new messages form the server and doing a complete refresh
of the user list every minute via the fetchMessages () and fetchUserList () functions
respectively. We store the return values from the calls to set Interval () so that we can
switch off the timers.

9. Moving on, we have the companion disableForm () function, which basically reverses
everything that enableForm () has done.

function disableForm() {
II Disable text fields

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

history_txt.selectable = false;
history_txt.border = false;
message_txt.selectable = false;
message_txt.border = false;
userlist txt.border = false;

II Disable buttons
sendBtn.disable();
settingsBtn.disable(};
logoutBtn.disable();

II Clear timers
clearinterval(fetchMessagesint);
clearinterval(userListint);

II Clear keyboard listener


Key.removeListener(kbHandler);

10. Next up comes our register() function that we talked about while creating the
Register dialog.

function register(username, email, password) {


commandHandler.clear();
commandHandler.username username;
commandHandler.password password;
commandHandler.email = email;
commandHandler.onLoad = checkRegister;

commandHandler. sendAndLoad ( "chatregister. php", commandHandler,


"POST");

This function takes the information passed to it and forwards it on to the


chatregister. php script, which will actually check that the username is unique and
then insert the data into the chatUsers database table.
Case Study 1: Chat Room

Notice that we're using the commandHandler object for this since it isn't a chat message
that we're sending. Also, we've set it so that the checkRegister () function is called to
handle the PHP script's response.

We also clear the data handler before we use it to remove any leftover information from
previous uses. It wouldn't break anything if we didn't bother to clear it, but the excess
information would be sent to the server, and that's inefficient!

11. Since we've just used it, we may as well go ahead and create the checkRegister ()
function. Remember that this function is invoked once the chatregister. php script has
done its business, and that it's used as an onLoad event handler.

function checkRegister() {
i f (this. result == "Okay")
login(this.username, this.password);
else {
message_mc.show(register_mc, this.errorMsg);

Here we check to see if the PHP script returned a positive result. If this is the case then
the user account has been successfully created and inserted into the database, and we can
go ahead and log the user in.

If an error was encountered, most likely due to the username already existing in the
database, then the Message dialog is displayed with the error message returned from the
PHP script. Here we're making use of the callback argument for the Message dialog's
show () function to redisplay the Register dialog once the user has acknowledged the
error, so they can try again.

12. Now we create the login () function. This will pass the user's details either from the Login
dialog or, after the user has successfully registered an account, to the server in an attempt
to gain access to the chat room.

function login(username, password)


commandHandler.clear();
commandHandler.username = username;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PH P for Flash

commandHandler .password = password;


commandHandler.onLoad = checkLogin;

commandHandler. sendAndLoad ( "chatlogin.php", commandHandler,


"POST");

This looks almost identical to the register () function, except that we're only sending
the username and password this time, and that we're sending them to the
chatlogin.php script. We're also setting the onLoad event handler to a different
function, checkLogin, to handle the information returned by the PHP script.

13. I'm sure you can guess what's coming next? Yep, the checkLogin () function, which we use
to make sure that the login was successful before we let the user loose in our chat room.

function checkLogin() {
if (this.Result == "Okay")
username = this . username;
useriD = this . useriD;

loadUserSettings();
fetchUserList();
enableForm();
else {
message_mc.show(login_mc, this.errorMsg) ;

Here again we check that we received a positive result from the PHP script. If that is the
case then we store the username and user ID, the latter of which is returned by the PHP
script, and load the settings from the user's computer. In order to allow several users to
use the same computer and have their own settings, we will use the stored username in
loading the settings, so it's important that the user has been authenticated before we do
this. We then perform an initial load of the user list and enable the chat interface so that
it can be used.
Case Study 1: Chat Room

If the PHP script did not return a positive result then something went wrong with the login
process. This is most likely a case of the incorrect user details being entered, so we use the
Message dialog's show() function to display the error message returned and to redisplay
the Login dialog when it's done.

14. At last we're getting down to the real stuff, and we're just about ready to tackle the
message handling functions. First up on our hit list is the sendMessage () function, which
is used to submit messages to the database.

function sendMessage() {
if (message_txt.length > 0) {
sendHandler.user = this.username;
sendHandler.message = message_txt.text;
sendHandler.textColor = textColor;

sendHandler.sendAndLoad("chatpost.php", sendHandler, "POST");

sendBtn.disable();
message_txt.text = 11 II
I

This function first checks to see if there is anything in the message_txt textfield to send.
If there isn't then the function doesn't do anything, and this stops those annoying users
who would amuse themselves by posting hundreds of blank messages.

If, however, there is something to send then the details are copied to the sendHandler
object ready for sending. This includes the username and their textColor setting, as well
as the actual message itself. This data is then sent to the chatpost. php script to be
inserted into the database.

Once that's finished, the Send button is disabled and the message_txt textfield is cleared,
ready for the next message.

15. We also need a function to fetch the messages from the server, which I've cunningly named
fetchMessages () . This timer we set up earlier in the enableForm () function invokes this
function, so all we need to worry about is requesting the messages from the server.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

function fetchMessages() {
lastCount = loadHandler.lastCount;

loadHandler.clear();
loadHandler.lastCount = lastCount;
loadHandler.useriD = useriD;

clearinterval(fetchMessagesint);
loadHandler.sendAndLoad("chatfetch.php", loadHandler, "POST");

The first thing we do is to back up the lastcount variable from the loadHandler object
before we clear lt. This variable is returned from the chatfetch.php script and used to
keep track of which messages we've already loaded from the server so that we can just
load the new ones since last time.

The data handler is then cleared and the lastCount variable copied back, along with the
user's useriD (used to update the lastActivity timestamp for the user in the
chatUserList table to let the system know that the user is still logged in and connected).
We then clear the timer that calls this function (we'll enable it again once we've received
all the data from the PHP script) before the chatfetch.php script is invoked.

16. The final message-handling function is buildMessageList (), which is invoked when the
new message data had been loaded from chat fetch. php. If you remember way back to the
init () function, this function is used as the onLoad event handler for the loadHandler
object. We're going to look at this one piece at a time as it's quite a large function.

function buildMessageList(success) {
fetchMessagesint setinterval(fetchMessages, 3000);

i f ( ! success){
history_txt.htmlText += "<font color=\"#ffOOOO\">Connection
Error</font><br>";
return;
Case Study 1: Chat Room

The first thing we do is to reset the timer that is used to fetch new messages. We'd turned
it off as a precaution against the fetch routine being invoked before the previous one had
been completed. We then see whether the PHP script was successfully called using the
success argument that is passed to onLoad event handlers. We use this here because it
is possible on a busy server for the connection to be refused, and if this is the case we
insert an error message into the chat history window and exit the function.

var newMessages ,
1111.

var getUserList false;

Next we create two local variables that will be used through the course of this function.
The first, newMessages, will contain the new messages to be appended to the chat history
window, so we initialize this to a blank string here.

The second, getUserList, will be set to true if a special message is found in the new
message list that should cause the user list to be refreshed. These special messages are
inserted whenever a user logs in or out of the chat room so that the user list is updated
instantly rather than waiting for the timer to update it.

for (count = 0; count < this.messageCount; count++) {


switch (this["message" +count]) {
case "<<login>>":
case "<<logout>>":
getUserList = true;
break;

default:
newMessages += this["message" + count] + "<br />";
break;

We then loop through all the messages returned using a for( ... ) loop and check to see if
the message is one of those special messages we just mentioned or whether it's a normal
message. If the former, getUserList is set to true and we move on to the next message.
If the latter, then the message is appended to the newMessages string with a line break
added on at the end.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

Next we look to see if the user's chat history window is scrolled right to the bottom or
whether they're looking at previous messages a little further up the page.

if (history_txt.scroll == history_txt.maxscroll)
history_txt . htmlText += newMessages;
history_txt.scroll = history_txt.maxscroll;
else {
history_txt.htmlText += newMessages;

If the user is scrolled right to the bottom, then the new messages are appended to the
chat history and the textfield's scroll property is updated so that the chat history is once
again scrolled right to the bottom. Without this, the chat history window would need to
be scrolled manually by the user every time new messages were appended.

If the user isn't scrolled right to the bottom, then the new messages are appended without
changing the scroll property. This feature was born out of frustration when using other
chat rooms, where I'd be trying to look at earlier messages but the client kept scrolling me
all the way to the bottom when new messages were appended.

if (getUserList == true) {
fetchUserList();

Finally, for this function, we check to see if getUserList is set to true. If it is then we
call the fetchUserList () function, which will take care of updating the user list for us.

17. Speaking of fetchUserList (),we may as well knock that one up while we're at it.

function fetchUserList()
commandHandler.clear();
commandHandler.onLoad = buildUserList;

commandHandler. sendAndLoad ( "chatuserlist .php" 1 commandHandler 1

.,. "POST");
Case Study 1: Chat Room

This function simply uses the commandHandler object to invoke the chatuserlist .php
script and to set the buildUserList () function to process the returned information.

18. It's companion function, buildUserList (), takes the output of the PHP script and
creates the list of active users.

function buildUserList()
if (this. result == "Okay")
userlist_txt.text = "";
for (count = 0; count < this.userCount; count++) {
userlist txt.text += this["user" + count + "Usemame"];
userlist txt.text += "\n";

As you can see, there's nothing too special here. If the PHP script gave a positive result
then the user list is first cleared before being repopulated with the new user information.

19. We're nearly at the end of the ActionScript for this movie now. Before we can rejoice in
happiness and let our fingers cool off in a bucket of ice, we've got a few more steps to go... the
first of which is to write the storeUserSettings () and fetchUserSettings () functions.

Since these functions are fairly simple we'll tackle both of them in one go:

function storeUserSettings() {
var settings_so = sharedobject.getLocal(usemame);
settings_so.data.textColor = textColor;
settings_so.flush();

function loadUserSettings() {
var settings_so = sharedobject.getLocal(usemame);
textColor = settings_so.data.textColor;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

We're using a SharedObj ect named after the user's username to store the user settings
- which in this case is just the chosen text color.

20. Finally we come to our last batch of functions, which are used as the onClick Handler
parameters for the three buttons in our main chat interface. The first two, for the Send
and Settings ... buttons, are so simple they require little explanation.

function doSend ()
sendMessage () ;

function doSettings()
settings_mc.show();

The first simply calls the sendMessage () function to post the message to the server, and
the second invokes the Settings dialog's show () method to make it visible.

21. The final stop on our magical mystery tour of functions is doLogout () :

function doLogout() {
commandHandler.clear();
commandHandler.useriD = useriD;
commandHandler. sendAndLoad ("chat logout. php" 1 commandHandler I

"POST");

sendHandler.clear();
loadHandler.clear();

history_txt.text = 1111.
I

message_txt.text = ,
1111.

userlist txt.text 1111.


I

disableForm();

login_mc.show(};
Case Study 1: Chat Room

This function clears and then uses the corrunandHandler object to invoke the
chatlogout .php script, which posts a logout notification to the server. The useriD is
sent along with the logout request so that the user's entry in the chatUserList table can
be removed.

Next the Loadvars objects are cleared so that no message data is remembered between
sessions. If we didn't do this and were to log in again without closing the browser window,
we would see all messages since we left the chat. It's always a good idea to clear things up
before exiting anyway!

The history, message, and user list textfields are then cleared, and the form is disabled
before the Login dialog is once again displayed.

22. One final thing to do before we leave. Although we wrote the init () function way back
at the start of this section, it actually needs to be called from somewhere. Do this at the
bottom of the script:

init ();

You'll probably be glad to hear that we're done with the Flash movie now and can turn
our attention towards the PHP script. Before we do, go outside and grab some fresh air-
you've earned it!

Server-side shenanigans
Now that we've dispensed with the Flash movie (at least until we come to test our application)
it's time to move on to the PHP scripts that will act as a layer between the Flash movie and the
MySQL database.

The chat system is run by six main PHP scripts:

chatregister.php

chatlogin.php

chatpost.php

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

chatfetch.php

chatuserlist.php

chatlogout.php

We also need a PHP script- setup . php- to set up the database structure to start with, and
there are a couple of utility scripts that are used by all of the above:

cormnon .php

db.php

Rather than deal with them in the order in which they're listed, we're going to take each one as
they would logically be created when writing the application.

common.php

cormnon.php contains the variables and functions that will be used in most or all of the other
scripts for this application.

1. First are the database connection details. This is the standard fare of host address.
username, password, and database name.

<?
II cormnon.php

$dbHost 11 localhost 11 ;
$dbUser 11 youruser 11 ;
$dbPass 11 yourpassword 11 ;

$dbName 11 advancedphp 11 ;

You will need to modify the values of these variables to suit your particular server. If you're
unsure of the details then contact your hosting company's technical support people or
consult the FAQ section of their website.
Case Study 1: Chat Room

2. The only function in the common.php file is fail(), which is used to report error
messages back to the Flash movie and halt the script.

function fail($errorMsg = "") {


print "&result=Fail&errorMsg=" . urlencode($errorMsg);
exit;

?>

You can see that the function takes a single argument, which is a description of the error that
occurred, reports the error along with the error message to the Flash movie, and then exits.

db.php
The db.php script contains a class that I wrote a while ago for handling MySQL database
interactions in an object oriented manner. I did this to simplify the main scripts of any application
that I write and because I found that I was using a lot of the same code over and over again.

Unfortunately we don't have space to go over this script in detail but it is basically an object
wrapper for the standard PHP mysql_xxxx functions. What I can do, however, is give you a quick
rundown of how it's used.

Once db.php has been included in another script using the require() function, the first thing
you'll want to do is to create an instance of the DB class that's contained inside. I should mention
here that it's common programming practice to name classes using a capital letter for the first
character of each word in the name, unlike variables where the first word is all lower-case.

Anyway, we create our instance of the DB class using the new operator. The constructor for this
class (that is, the method that is called when the class is instantiated) takes four arguments- host
address, username, password, database name- which are used to connect to the database server.

Using the variables we set out in common.php, we could create a new DB object using the
following code:

$myDB =new DB($dbName, $dbUser, $dbPass, $dbHost);

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

Now that the object has been created, we will want to make a connection to the database server.
We can do this using the connect () method of our new object:

$myDB->connect();

The connect () method will return t:rue or false depending on whether a successful database
connection was established, so we can use this to handle an error situation intelligently in our scripts.

Once we've established a connection, it's likely that we'll want to query the database. There are
two methods provided for this, and each has its specific use.

Firstly we have the standard query () method, which will take a single argument containing the
query string and run it through the database. It will return t:rue or false depending on whether
the query was successfully executed or not, and again we can use this to intelligently handle
errors in our scripts. The result identifier for the query, which we would use to get at any
information returned from a SELECT query, is stored internally and used by some of the
functions that we'll meet later on.

An example of the query () method in use might look something like this.

$myDB->query("SELECT * FROM news ORDER BY posted");

The other method we can use to query the database is queryFirst () . I added this method
because it is quite common to perform a SELECT query where only a single row will be returned.
What this method will do is to run the query through the database and then return the first row
as an associative array, or false if there was an error.

Obviously you could use this method for handling queries that will return more than a single row,
but it makes more sense to use the standard query () method in that case. An example of where
this method might be used is when picking a single user from the database:

$user = $myDB->queryFirst("SELECT * FROM users WHERE useriD = 7");

We could now use the $user array to get at all the information for the selected user.

In order to handle SELECT queries that may return more than a single row, we will need some
way to actually get at that information once the query has been executed by the query ()
Case Study 1: Chat Room

method. You have several methods to choose from here, depending, what format you want the
data returned in.

The fetchObject () method can be used to return the next row from the query result as an
object. The method doesn't do anything more fancy than call the mysql_fetch_object ()
function and return the object returned from the function.

The fetchAssoc () function will fetch the next row as an associative array. This is a simple
wrapper for the mysql_fetch_array() function, returning the resultant array.

Finally we have the fetchArray () method, which returns the next row in a standard numerically
indexed array and is again a simple wrapper for the mysql_fetch_array() function.

The only other methods of note are numRows (),which will return the number of rows contained
in the result set after a SELECT query, and the cunningly named close () , which is used to drop
the connection to the database.

setup.php

Before we can write the rest of our PHP scripts, we need to actually create the database structure
for them to use. Since we sorted out the structure a while back (like, waaay back at the beginning
of the chapter) all we need to do here is to knock up a script to create it for us.

1. The first thing we need to do is establish a connection with the database, and we can do
this using our shiny new DB class.

II setup.php

require ( 11 common. php 11 ) ;

require ( 11 db.php 11 ) ;

$myDB =new DB($dbHost, $dbUser, $dbPass);


$myDB->connect();

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

After importing the necessary PHP scripts, we create a new DB object and obtain a
connection to the server using the connect () method. Notice here that we've left off the
database name argument from the call to connect () , and the reason for this is that we
may need to actually create the database before it can be used.

2. We then attempt to create the database using the following code:

print "Attempting to create $dbName database<br>";

II Attempt to create database


i f ( $myDB- >query ( "CREATE DATABASE $dbName" ) )
print "Database $dbName created<br>";
else {
print "Warning- Failed to create database $dbName<br>";

The reason that only a warning is given if the database could not be created is that it may
already exist (for example, if you only have one database allocated to your hosting
account), so we couldn't consider it an error as such.

3. Next we verify that the database exists by attempting to select it as the active database.
This is a necessary step in order to create the tables anyway, and would be handled in
normal PHP scripts by the connect () method.

II Select database
if (!mysql_select_db($dbName))
print "Error selecting $dbName database";
exit

If the database cannot be selected, whether it has just been created or existed already,
then we need not bother trying to create the tables. If this is the case then we output a
descriptive error message and exit from the PHP script.
Case Study 1: Chat Room

4. Once that's done we can start creating the database tables.

print "<br>Setting up database structure<br>";

II Create chatUsers table


$query = "CREATE TABLE chatUsers
useriD INTEGER AUTO INCREMENT PRIMARY KEY,
username VARCHAR(30),
email VARCHAR (2 55) ,
password VARCHAR(30))";

if (!$myDB->query($query)) {
print "Error creating chatUsers table<br>";

II Create chatMessages table


$query = "CREATE TABLE chatMessages
body TEXT,
posted INTEGER)";

if (!$myDB->query($query)) {
print "Error creating chatMessages table<br>";

II Create chatUserList table


$query = "CREATE TABLE chatUserList
useriD INTEGER NOT NULL UNIQUE,
lastActivity INTEGER)";

if (!$myDB->query($query)) {
print "Error creating chatUserList table<br>";

This section of code just runs through each of the tables we need and attempts to create
them using the query () method. If for some reason a particular table isn't created then
the PHP script will output an error message and carry on to the next table.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

The only point of note here is that the useriD column for the chatUserList table is
declared as being UNIQUE. This means that no two rows in this table can have the same
value for this column, as is appropriate for a user list table. It also allows us to use the
MySQL-specific REPLACE command to either insert a new row or update an existing one
as appropriate, but more on that later!

5. Finally we print a message to tell us that the script has finished what it was doing, close
the database connection, and exit our script.

print "All done";

$myDB->close();

That's all there is to it. The setup. php script should be uploaded to your web server
(along with cornmon.php and d.b.php) and executed through your web browser. Provided
you don't get any error messages then the tables were created fine and we can move on
to the next script. If you did get errors then you'll need to check your database connection
details and ensure that tables of the same name don't already exist in your database.

For the hard core propeller-heads among you who like to do things the hard way, I've
included a setup. sql file in the download archive that contains just the raw SQL
commands to recreate the database structure. If you don't know what to do with this file
then you should probably stick with the PHP script above!

chatregister.php

The first of the main scripts that we need to tackle here is the registration script. This will allow
new users to create accounts for themselves so that they can access the chat room. As you can
tell from the Register dialog we created a while ago, we're only interested in a few bits of
information about the user - username, email, and password.

1. The first thing we need to do is to open up the PHP script and import our cornmon.php
and d.b.php scripts.
Case Study 1: Chat Room

<?
I I chatlogin.php

require ("common.php");
require ("db.php");

2. Before we go any further, we should check that the required information has been passed
to the PHP script. Although we're already making this check in the Flash movie before the
script is invoked, it's always good to be double sure.

II Check data
i f (!isset($username) II ernpty($username) II
!isset($password) II empty($password) II
!isset($email) II empty($ernail)) {
fail ("Necessary details not supplied") ;

If the necessary data isn't supplied then we bail out, with a suitable error message being
returned to the Flash movie. This error message will be displayed by the Message dialog
so that the user knows what has happened.

3. Once we've established that we've got all the data we need to create the user account, it's
worth making sure that the email address given is in a valid format. We can do this using
a regular expression.

II Check email validity


$pattern= ""( [a-zA-Z0-9._-]+)( [a-zA-Z0-9-] )+(\. [a-zA-Z0-9-]+)+$";
if (!ereg($pattern, $email)) {
fail ("Email address is not valid. Please enter a valid email
address.");

If you read Foundation PHP for Flash then you should recognize the regular expression
we've used above - it was the subject of almost half a chapter and it was used to check
the validity of an email address. If the email address is not correct then we exit, with an
appropriate error message returned to the Flash movie.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

4. Having checked that we have all the data we need, and that the email address is valid,
we're ready to connect to the database. As in setup . php, we'll use an object of our DB
class to do the hard work for us.

II Connect to database
$myDB = new DB($dbHost, $dbUser, $dbPass, $dbName);
$myDB->connect() ;

We've seen this before so it shouldn't require any more explanation. If you're still not sure,
then flip back a few pages and refresh your memory.

5. Next we need to check to see if there is already a user in the database with the same
username as the one chosen.

II Check for duplicate username


$query = "SELECT useriD FROM chat Users WHERE username=' $username' " ;
$user = $myDB->queryFirst($query);
$useriD = $user['useriD'];

if ($useriD != "") {
fail("Username $username already registered . Please try another . ") ;

If a user with the chosen username is found in the database then an error message is
returned to the Flash movie and the script exits. Notice that we're using our
queryFirst () method here since the SELECT query we're employing should only ever
return one row, if any.

6. Finally, once we've completed all the checks, we can create a new user account in the
chatUsers table.

II Create user account


$query = "INSERT INTO chatUsers (username, password, email)
VALUES ( '$username' , '$password' , ' $email ' )
$myDB->query($query);
Case Study 1: Chat Room

7. Once the user account has been created, we can return a success message to Flash, close
the database connection, and exit the PHP script.

print "&result=Okay";

$myDB->close();

?>

The Flash client will respond to the success message by initiating the login procedure for the new
account, allowing the user to get straight into the chat room.

chatlogin.php

The chatlogin.php script is used to authorize the user for access to the chat room. Its main
purpose is to check the username and password against the user accounts in the database and
create an entry in the user list table for the user.

1. As per usual, we'll start by importing the common.php and db.php scripts, and checking
to make sure that the required data has been passed from the Flash movie.

<?
I I chatlogin. php

require ( "common.php");
require ("db.php");

I I Check details
i f (!isset($username) II empty($username) II
!isset($password) I I empty($password)) {
fail ("Necessary details not supplied") ;

If either the username or the password has not been supplied, then the script sends an
appropriate error message back to the Flash movie and exits.

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

2. Next we create a connection to the database server and check to see if the supplied details
match up with any of the accounts in the database.

II Connect to database
$myDB = new DB($dbHost, $dbUser, $dbPass, $dbName);
$myDB->connect();

II Check username and password


$query = "SELECT useriD FROM chatUsers WHERE username='$username'
AND password='$password'";
$user = $myDB->queryFirst($query);
$useriD = $user['useriD'];

if ($useriD == "")
fail("User $user not registered with the supplied password");

Again we're using queryFirst () to query the database, and if no match is found then
the script is halted, with an error message sent back to the Flash movie so that we can
inform the user what happened.

3. Once the user has been authenticated, we need to create an entry for them in the
chatUserList table.

II Create entry in user list for user


$timestamp = time();
$query = "REPLACE INTO chatUserList (useriD, lastActivity) VALUES
( ' $useriD' , '$timestamp' ) " ;
$myDB->query($query);

Here we use the REPLACE command that we mentioned earlier to either update an
existing row with the same useriD, or to create a new row if no such row exists already.
This is necessary because the row for a specific user in this table will not be deleted unless
the user logs out properly (doesn't just close the browser window). While the user's name
will now show up on the user list because its lastActivity timestamp isn't being
updated, the row won't actually be removed from the table.
Case Study 1: Chat Room

4. Having done that, we need to let the other chat users know that someone has just logged
in so that chat clients can request an updated user list form the server.

II Insert special message into message list


$myDB->query("INSERT INTO chatMessages (body) VALUES
(I <<login>> I ) II) i

If you remember back to when we were creating the Flash movie, we created a special
message for this, so all we need to do is to insert this special message into the
chatMessages table and the client will take care of the rest.

5. Finally we let the Flash movie know that the user has logged in successfully, close the
database connection, and exit the script.

print "&result=Okay&useriD=$useriD";

$myDB->close ();

?>

The only thing special to notice here is that in addition to returning a success message, we're
also returning the useriD for the user's account. We'll use this in subsequent PHP scripts to
quickly identify the user's entry in the chatuserList table without having to consult the
chatUsers table, so that it can be updated or deleted as required.

chatlogout.php

Having just dealt with the script that logs the user into the chat room, we may as well move on
to its counterpart- the logout script. The operation of this script is fairly simple, as there is no
information to validate and no information needs to be returned to the Flash movie.

1. It should be no surprise to you by now that the first thing we need to do is import the
common. php and db. php files and establish a connection with the database server.

<?
II chatlogout.php

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

require ( "common. php" ) ;


require ("db.php");

II Connect to database
$myDB = new DB($dbHost, $dbUser, $dbPass, $dbName);
$myDB->connect();

2. Next, and finally (I told you this was a simple script), we remove the user's entry in the
chatUserList table and post a special logout message in the chatMessages table.

II Remove user list entry for user


$myDB->query("DELETE FROM chatUserList WHERE useriD=$useriD");

II Post logout message


$myDB->query("INSERT INTO chatMessages (body) VALUES
('<<logout>>')");

$myDB->close();

All that's left to be done after that is to close the database connection like the good little
developers we are, and exit the PHP script.

chatuserlist.php

The chat client, to fetch or update the list of active users in the chat room, uses the
chatuserlist. php script. While this script isn't much bigger than the ones we've written
already, it is a little more complex in that it queries values from two tables at the same time. It
uses a natural join to get the usernames of the users in the chatuserList table when all that
is stored in there is the useriD.

1. Everything has to start somewhere, so we'll begin by importing the usual PHP scripts and
connecting to the database server.
<?
II chatuserlist.php
Case Study 1: Chat Room

require ( "common. php" ) ;


require ("db.php");

II Connect to database
$myDB = new DB($dbHost, $dbUser, $dbPass, $dbName);
$myDB->connect();

Move along please, there's nothing new to see here!

2. Now we come to the semi-complicated bit. The rather long SELECT statement may look
intimidating at first, but I promise you it's nothing to get too worried about.

II Get active user usernames


$timeout = time() - 30;
$query = "SELECT chatUsers.username FROM chatUsers, chatUserList
WHERE chatUsers.useriD = chatUserList.useriD
AND lastActivity >$timeout";
$myDB->query($query);

The first thing we do here is to determine a threshold below which we will consider a
user's connection to have timed out. Since the chatfetch.php script is responsible for
updating the lastActivity value. and considering that this script is invoked once every
three seconds, it's safe to assume that if you haven't heard from the user within 30
seconds, then they haven't bothered to log out properly and so not to include them in the
user list.

Next we build the monstrous SELECT query that queries both the chatUsers and the
chatUserList tables at the same time, cross-referencing them so that we get the data
that we need - the usernames of the logged in users. It may look scary, but it can be put
quite simply into English:

Select the username from the chatUsers table of only those users who have a
corresponding entry in the chatUserList table (as identified by common useriD values)
and with a lastActi vi ty value of greater than $timeout.

If you now re-read the query you'll see that it makes sense. Cool, huh? We could have done
this using a single query to fetch the useriD values of each active user and then ran a

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

separate query on the chatUsers table for each user, but this way is more efficient and
it give me an excuse to show you joins in action.

All that was left to do was to execute the query using the query 0 method.

3. Now that we've got a list of active users, we need to pull them out of the result set and
return them to the Flash movie.

II Output usernames
for ($count = 0; $count < $myDB->numRows(); $count++)
$user = $myDB->fetchAssoc();
$username = stripslashes($user['username']);
print "&user" . $count . "Username=" . urlencode ($username);

You can see that we do this using a for( ... ) loop, and note that we're stripping any
escaping backslashes from the username before sending it to the Flash movie.

4. Finally we output a success message to Flash along with the total number of active users,
before closing the database connection and exiting the script.

print "&result=Okay&userCount=$count";

$myDB- >close () ;

?>

chatpost.php

So far we've dealt with the scripts that allow us to set up the database, register new accounts,
log in and out, and fetch a list of active users. What we haven't got yet is any scripts for handling
the sending and receiving of the messages themselves (without which our application is about as
useful as a chocolate fireguard).

The first of these scripts, chat post. php, is used to format the messages sent from the Flash
movie and to add them to the database. Summing up the job of this script in half a sentence is
actually a little deceptive since it's going to be the most involved script we've met so far.
Case Study 1: Chat Room

1. I'm certain that you know what I'm going to say here even before your eyes read this part
of the page. The first thing we need to do is to import the usual suspects and establish a
connection with the database server.

<?
II chatpost.php

require ("common.php");
require ( "db.php");

II Connect to database
$myDB =new DB($dbHost, $dbUser, $dbPass, $dbName);
$myDB->connect();

Again, there's absolutely nothing new here save a different comment at the top, so we may
as well move right along to the next step.

2. Next we need to make some small changes to the username and message variables that
were passed in by the Flash movie.

//Translate angular brackets in message to HTML entities


$message = str_replace(Array("<", ">"), Array("&lt;", "&gt;"), $message);
$user = str_replace(Array("<", ">"), Array("&lt;", "&gt;"), $user);

Here we're using the str_replace () function to replace any angular brackets in either
string with the relevant HTML entity string. This prevents the Flash movie from trying to
interpret these as HTML tags when inserting the data into a textfield set up to render HTML
(such as history_txt on the main interface). If we didn't do this, these angular brackets
could cause entire conversations to disappear, so it's best to chop them out.

3. In this next section we implement the IRC-style /me command, and if it sounded quite
complex when we first spoke about it, then you'll be amazed at how simple it really is.

II IRC /me command parsing


i f (strpos($message, "/me") === false) {
$message = "<b>$user</b>: <font color=\"#$textColor\">"
'- $message . "</font>";

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

else {
$message str_replace("/me", $user, $message);
$message "<font color=\"#$textColor\"><b>$message</b></font>";

If there is not a /me command somewhere in the string, then we just create an ordinary
chat message with the username in bold and the message text rendered using the user's
textColor setting.

If, on the other hand, the /me command is present, we use str_replace() to insert the
user's name in its place and to format the message differently. Here we use the user's
chosen text color to display the whole message in bold text.

If you are familiar with IRC and wanted to implement some of the other commands, you
could use the same or similar technique to do so.

4. The final thing we need to do before we're ready to insert the message into the database
is to hunt for any URLs in the message and to make them clickable links.

II URL parse
$message = ereg_replace ("(http Iftp) :I I ( [A-Za-z0-9/?&#. -] *) ",
"<font color=\"#0000ff\"><U><a href=\"\\0\"
target=\"blank\">\\2</a></U></font>", $message);

If you're familiar with regular expressions then you should be able to follow this one quite
easily. If you're not so familiar, accept that it works and move on, and have a look at the
Looking for Patterns chapter in Foundation PHP for Flash when you get spare few minutes.

5. OK, so now we can go ahead and insert the message into the chatMessages table:

// Insert message into database


$timestamp = time();
$query = "INSERT INTO chatMessages (body, posted)
VALUES ( ' $message' , ' $timestamp' ) " ;
if (!$myDB->query($query)) {
fail("Failed to insert message into database");
Case Study 1: Chat Room

print 11 &result=Okay 11 ;

$myDB->close();

?>

The message is inserted into the database and either a success or failure message is given before
the PHP script exits.

Again, there's nothing here that you won't have seen before so there's no need to dwell on it-
on with the final (yes, I said FINAL) PHP script.

chatfetch.php

Once we've added messages into the database, it's only logical that we might want to fetch them
out again at some point, and that's the job of the chatfetch.php script. In addition to fetching
new messages from the database and returning them to the Flash client, this script also needs
to update the user's entry in the chatUserList table so that they continue to appear in the
active user list.

1. Yet again (though this is the last time, honest), we start out by importing the common. php
and db. php scripts and creating a connection to the database server.
<?
II chatfetch.php

require ( 11 common. php 11 ) ;

require ( 11 db.php 11 ) ;

II Connect to database
$myDB = new DB($dbHost, $dbUser, $dbPass, $dbName);
$myDB->connect();

2. Then we update the user's lastActivity timestamp in the chatUserList table. We do


this using the REPLACE command we mentioned earlier, but there's an added twist here,
as we'll see in a moment.

' 0
1 rn CJ cJ

;\~LC L
Dec~ e
Advanced PHP for Flash

II Update user lastActivity timestamp


$timestamp= time();
$query = "REPLACE DELAYED INTO chatUserList (useriD, lastActivity)
VALUES ( ' $useriD' , ' $timestamp' ) " ;
$myDB->query($query);

We're using DELAYED in this statement, which causes the update to be deferred until a
quieter period if the database is busy. This allows us to get on and fetch the messages while
letting MySQL worry about its workload.

3. Once that's done, we need to find out how many messages are currently in the database.

II Fetch number of massages in table


$messages = $myDB->queryFirst("SELECT COUNT(*) AS messages
FROM chatMessages");
$messages = $messages['messages'];

We do this using MySQL's COUNT () function, as this is more efficient than selecting every
row in the table and getting the number of messages using the numRows () method.

Doing this allows us to determine whether or not any new messages have been added
since the last time the database was checked. We'll return this value to the Flash movie
when we exit so that it can pass it back as $lastCount when it next invokes this script.

4. Speaking of $lastCount, if this is the first time that the script has been invoked in this
chat session, then this variable will not exist. In this case, as well as if $lastCount does
exist but equals the message count we've just pulled out of the database, we don't want
to attempt to fetch any new messages from the database because there won't be any.

II If this is the first fetch, or no new messages have been added


II since the last check, return current message count and exit

if (!isset ($lastCount) II empty($lastCount) II $lastCount ==


$messages) {
print "&result=Okay&lastCount=$messages";
exit;
Case Study 1: Chat Room

If this is the case, we return a positive result but no message data back to the Flash movie.
We also send the total number of messages in the database as mentioned previously,
before exiting the PHP script altogether.

5. If we get this far then we know that there are new messages in the database, so we need
to query the database to fetch the new messages to output to the Flash movie.

II Fetch new messages (from lastCount =>messages) from database

$query= "SELECT* FROM chatMessages LIMIT $lastCount," .


($messages - $lastCount);
if (!$myDB->query($query)) {
fail("Error fetching information from database");

Here we're using the LIMIT clause, with both offset and number of rows given, to ensure
that we only get new messages since our last check. How this works is probably best
explained by an example.

Let's assume there were 15 messages in the database on the previous visit and that there
are now 20 messages. That would leave us with a $lastCount value of 15 and a
$messages value of 20. The query produced with those values would be as follows:

SELECT * FROM chatMessages LIMIT 15,5;

...which, in English, means ...

Return all data from the chatMessages table, starting at row 75 for 5 rows .

... so we only get the five new messages since our last check returned in the result set.

6. We then use a for( ... ) loop to output the new messages to the Flash movie

II Output the new messages


for($count = 0; $count < $myDB->numRows(); $count++) {
$message = $myDB->fetchAssoc();
$body= stripslashes($message['body']);
print "&message" . $count . "=" . urlencode ($body);

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

7. Finally we output a success message, the number of new messages returned, and the new
total message count to the Flash movie, before closing the database connection and
exiting the PHP script.

print "&result=Okay&messageCount=$count&lastCount=$messages";

$myDB->close ();

?>

That's all the PHP scripts we need to worry about, and our chat room is now ready to go.
Upload all the PHP and Flash files to your server and give some friends a call and ask them
to check out your shiny new chat room. Don't forget to tell them where it came from!

Summary
Well, you probably feel like you've gone a few rounds with whichever heavyweight boxer is
top of the tree at the moment, but we've finally finished creating our application. It's time to
sit back and admire our handiwork.

Once you've uploaded all the necessary PHP scripts, you can create yourself a user account
and log in. You might want to grab some friends and get them to log in too though, else you'll
feel mighty silly in a chat room all by yourself (trust me - been there and done that enough
times today).

When you're up and running, Flnh + PHP + MySQL Ctuol Syt.r.m . A.d\l'anCMI PWP fof Flnh -
you'll get something like the t.4Jl!l ,.,~
IIE'Tbn>od
ltl t1:1 1 U)~ I

...,..
following: l":t.;)".,~~~,~br~

~~!I tUti'"'SJ ChCP lqc_ ~ng


A.I.JI.n. t~

f'-Lonl I
lhott 11'111\k& ..klhn Mu.rv m.ntic.ln..
ru~=~ o eo.. 1 ..,~fetii?W"

At.n wn ~Uy .. slinv Jllw c;ould r~ rnbet' ttM COIM"'UUd for it fr'OI'1
~ .;h...ptef"
Ma!ltfunk hi! '!ohauld a.dVMtiH www.pbplpf11ub ggm lD ~Illy "
~s .1-lld Abn'!i good b()QJI:c "-I

r.ETllned h~

;:=:================-===:.,
I
- . "'=--
~ 1- ....... J~

Case Study 1: Chat Room

This is actually part of the book development team from Foundation PHP for Flash having a
good old-fashioned gossip session as I write this, so you can see that we're already getting
plenty of mileage out of this application.

Improvements?
As usual with one of my case studies, I want to leave you with a few thoughts as to how you could
improve the application we've just spent precious hours building. There are so many things that you
could add that I'm sure you already have some ideas of your own, but here are some suggestions:

Alert sounds: The one big thing that is missing from this chapter is noise. There are no
fancy sounds to alert you when a new message has been received or when a user logs in
or out, and adding these could really improve the application.

User icons: The main failing of non-verbal communication is that it's very hard to express the
tone of the message or the emotion of the user. Most instant messaging clients these days use
emoticons to get around this, and you could try similar functionality in the chat room here.
Enabling users to select an icon from a set list of moods, or even to upload their own using
other techniques covered earlier in the book, will greatly enhance the user experience.

Private messages: My final, and definitely most ambitious, suggestion for you to try and
implement is private messages. At the moment all users in the chat room can see anything
you type, and that's not good if you wanted to say something privately to just one of the
users. Private messages (also known as whispering) will allow you to send a target message
to just one user.

Well, that's just about it for this application, except to say that I look forward to seeing what you
come up with using the code in this chapter. If you can stand any more coding after this
behemoth then you're in for a treat as we've got one more doozy of a case study for you. If
you're feeling brave, flip over the page and crank up those coding fingers!

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
e-Commerce
Site
So, your boss hangs over you and needs a Flash interface for your company's e-
commerce site, and needs it yesterday! Or you just want to bring together everything
you have learned throughout this book and its predecessor in one big site to get all the
elements to work together. Well, that's just what we are going to cover now: an e-
D commerce site with an administrator interface and a front-end for your customers.

When building an e-commerce shop we first need to think about a few things: how do
you perceive the shopping sites out there? What's good, and what's bad about them?
Take a look around and pick up what you find annoying and what's good, and take
these thoughts with you as we develop this site.

What are we going to build?


Let's sit back and look at what is needed to make an e-commerce shop. We need to DO
present our items to the user, and allow them to browse through the content of our
site, and we definitely need to let them add items as they go to a shopping basket! But
we also need to back this up with an administrator page where you can send your
client(s) to update this "next revolutionary website". (OK, the truth is, I can't promise
you that, but we'll have a look into the way to get there.)
[ D
First we'll go through the making of the administrator part of the page. Since this is
where all the content is going to be, we need to get it up and running before we can
start on the front-end. g~
Next we will make the front-end of the site, but we'll have a closer look at that when DIT
we come to that part.
DO
Advanced PHP for Flash

After all these chapters I assume that you by now are fairly confident with Flash and PHP (has it
been a good ride so far?), so for someone skipping ahead to this chapter straight after getting
this book (what are you doing here anyway?): you might find that I jump around a bit quickly.

Let's waste no time and get started!

Administrator site
Before we start to build the administrator site, let's have a look at what's required from it. We want to:

Log in and authenticate the administrator

Add, edit, and delete a category

Add, edit, and delete an item

Upload images to the server

Generate a report of the current state of the site in PDF format

To achieve this, we'll first have a look at the database that drives both the administrator and the
client interfaces. Then we'll go through all the PHP files, test them, and make sure that they are
all working before we start integrating them into Flash. When we are happy with that we'll use
the output of the PHP files to build up the administrator interface. So put on a pot of coffee,
unplug the phone, and let's get started!

MySQL
Before we can do anything with the site we need to have a look at the tables that drive the site.
We want to store the following information in MySQL:

category

Name

item

The item name


Case Study 2: e-Commerce Site



Parent category

A description of the item

A image to go with the item

The price of the item



A counter of how many items we have in store
image

Image name to use within flash

A path to the image on the server

ad min
The name of the administrator
The username

A password for logging in

customers


The name of the user

A username to log the user in


A password to authenticate the user

let's look into how we are going to build this up: the SQL file, econunerce. sql, can be found
in the download files in the sql folder; insert that into MySQL via either phpMyAdmin or the
command-line program you get with MySQL.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

Looking over the requirements of what we need to store we come up with the following structure:

ID Integer Each category will have a unique ID to identify it.


name String The name of the category

ID Integer A unique ID for each item


item String The name of the product
parent Integer A reference to the category where this item belongs
description String The "about this item" content
image String The path to the image that we will choose for it
price Float Each item needs a price
count Integer Keeps count of how many of this item are in stock

ID Integer A unique ID for each item


name String The name we are going to display within Flash
path String The path to the image on the server

ID Integer Each administrator has a unique ID


name String The actual name of the administrator
username String The username that the administrator logs in with
(Several people can have the same name, but a
username is unique)
password String The 'about this item' content

ID Integer Each customer has a unique ID


name String The actual name of the customer
username String The unique username the user logs in with
password String An MDS ( ) sum of the password
Case Study 2: e-Commerce Site

That sums up the MySQL tables. You can of course add as much as you want to each of these
tables, and I'll suggest some improvements as we go along that can be made to extend this to
make it a bit more interesting. When you have inserted the tables, take a look around and make
yourself familiar with the structure, add some items and categories to it so that we have
something to work with when we come to the next section on PHP.

PHP
It is now time to write up the core of the program; the PHP files that make up the administrator
site. We'll write all of them out and test them so that we don't need to bother with that when
we come to the integration.

Shake loose, fire up your favorite editor and let's get started!

The files that we will cover are:

settings.inc.php
MySQL connection and variable definition.

functions.inc.php
Common functions used throughout the site; these will include an email address validator,
an error function, and some extra functions that you can use to take the site a bit further.

adminAddCategory.php
Adds a new category to the table.

adminDeleteCat.php
Deletes a category and all of its belonging items.

adminDeleteitem.php
Deletes an item.

adminFetchitem.php
This will take care of pulling in all the information available on one item, so that we can
edit it.

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

adminFetchitems.php
This file will get all items belonging to one particular category.

adminGetCategory.php
Gets all the categories in the database.

adminGetimages.php
Gets all the image paths and names we have in the database.

11 adminLogin. php
This will authenticate an administrator before we let them into the movie.

adminPDF . php
This file will provide us with a way to generate a PDF document of the current state of the
site we are developing: what categories we have and what's in each of them.

adminPreviewimage.php
Preview an image before adding it to an item.

adminSaveitem.php
Saves a new item.

adminUpdateCat.php
Updates the name of a category.

adminUpdateitem.php
Updates the information on an item.

adminUpload.php
This file will take care of uploading images to the server and add its path to the database
for the administrator to use when inserting new items.

Some of the scripts presented here are quite easy, and should, by now, be no problem for you
to decipher, so I'll go through them quickly and not dwell on them too much.
Case Study 2: e-Commerce Site

File: settings.inc.php

The first thing we need to do is to make a file with all the settings for the site, this will be one
of two common shared files that will be used throughout the site. We will create about 20 PHP
files. so we need this to avoid too much typing and changing if you move host (or you send this
off to your client).

1. Create a new file called settings. inc. php and enter the following lines for the database
settings for your host. Even though they are not shown here, don't forget to enclose your
PHP scripts in <? ?> tags at the beginning and end of the complete script.

define(DB_HOST, "localhost");
define(DB_USER, "root");
define(DB_PASSWORD, "whateverYourPasswordis");
define(DB_DB, "ecolffilerce");

2. Set the following variable to true. This will cause all mysql_error () to be output in the
error scene inside Flash; that way we can debug what's happening much more easily (of
course, when the site goes live you need to set it back to false).

define(SHOW_MYSQL_ERRORS, true);

$link = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);


$db = mysql_select_db(DB_DB);
i f ( 1$link II 1$dbl {
echo "status=error&error=" . urlencode("A fatal error occured.
Please try again later.");
if(SHOW_MYSQL_ERRORS) {
echo urlencode ( "\n\nMySQL reported the following: \n" .
'- mysql_error() ) ;

exit() ;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

3. Fill in your settings for MySQL, open up your browser. and point it to this file; you
shouldn't see anything. If you do get a message then something went wrong, so you need
to look over your define () statements and check them against your settings.

File: functions.inc.php

The other file that will be shared among almost all the files is functions. inc .php. This will
contain commonly accessed functions for the site, and if you haven't gotten into the habit of
doing this then this is a good time to start. Awell-built function library can save you a lot of time
when you start developing large sites.

The first function will be firstWords (); this function will take a string as the first parameter
and a number as the second. But what does it do? When we pull in items and present them in
a category overview, we don't want the entire description field in the item table, we only want
to get the first ten words from the description field as a teaser for the user.

I**
* Retrieves $nmbr of words from $string
* param $string The string to extract the words from
* param $nmbr The number of words to get
*return A string of maximum $nmbr of words with' . ... ' appended
* if there are more than$nmbr words in $string
*I
function firstWords($string, $nmbr){
II Split the string on spaces and dump the result into $arr
$arr =explode(" " $string);
$ret = "";
II If the string has less words than we want: return it
directly
if(count($arr) < $nmbr){
return $string;
}else{
II Build up the return string
for($i = 0; $i < $nmbr; $i++){
$ret .- " " . $arr[$i];
Case Study 2: e-Commerce Site

$ret .= 11 ,
II

return $ret;

We then need a function to check the validity of the email address the user gives when signing
up. The following is a lightweight validator of email addresses; you can find a lot of different ones
on the web if you want to investigate further into it.

/**
* Check if the email supplied is well formatted
* param $email The email to check
* return true if the email is well formatted, if not: false
*I
function checkEmail($email){
$regExp = 11 /"[\w]+[\w\-]+[\w\-\.]+(\. [\w] {2,4})$/ 11 ;
if(preg_match($regExp, $email)){
return true;
}else{
return false;

Regular expressions were covered in the first book, but if you haven't read it or need a quick
reminder read on.

This function takes an email address as an argument and checks that it is correctly formatted; if
it is it will return true, and if it is an invalid email address it will return false. For example:
your_namedomain. com will return true, but your_namedomain will return false. This
function also checks for the length of the domain extension: .uk, .com, and .info will all match
as valid domain names.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

PHP comes with two regular expression packages: one that is Perl
compatible, and one POSIX-compatible (take a look in the
manual for more information on them). preg_match () is in the
Perf-compatible package and its syntax is close to that of Perl. If
you want to learn more on regular expressions there are entire
books dedicated to it, so if you're interested I would suggest
picking up one of those or searching the net for a vast amount of
regular expression tutorials.

Now for a quick walk through of the syntax:

preg_match ( "/ [a-z] /" 1 $string) will return true if the $string has any of the
characters 'a' to 'z' in it.

If you want to test for something at the start of a string you can use '"'
preg_match("/"a/" 1 $string) will return true if the $string starts with 'a'.

To test what's at the end of a string you can use '$'. preg_match ('/a$/" I $string)
will return true if $string ends in 'a'.

Normal escaping of special characters as in PHP applies. To check for a '$' you need to
precede it with a'\': \$.

Now, for all our scripts to catch the errors that happen we will use a function called fail () .
Inside Flash we will be looking for the variable-value combination status=ok for anything that
we get from the server, but when something fails we need a way to display it. An error scene in
both the movies we will be making will handle all the errors.

I**
* Outputs a error message if something went wrong.
* Will provide a 'status=error' variable/value pair for you to work
* with
* The actual error message will be provided in 'error=msg'
* param $message The message you want to display
Case Study 2: e-Commerce Site

* param $mysq1Error Optional, pass 'mysql_error()' to debug if


* needed
*I
function fail($message, $mysq1Error ""){
echo "status=error";
echo "&error=" . $message;
if(SHOW_MYSQL_ERRORS) {
echo "\n MySQL reported the following: \n" .
urlencode($mysq1Error);

exit() ;

Here we see the need for the define() we made earlier. If we set SHOW_MYSQL_ERRORS to
true, we will return a urlencode () of the current MySQL error that we pass this function. That
way we can easily set what we want to report and the development can be sped up since we get
the MySQL error directly in Flash.

These next three functions will not be used in this program, but I've included them here to let
you have an idea of what can be done to extend the program when you are finished with the
entire application.

First we are going to parse a possible URL in the description field so that these automatically turn
up as links in the description field inside Flash.

/**
* Get all URL's and put them into <a></a> tags
* param $string The string to change
* return The changed $string with <a></a> applied to all URL's
*I
function text2url($stringl{
$regExpWWW = "/\swww\. ( [\w_] +) \. ( [\w] {2, 4})
([\w\1\-_\.\?&\=]+)\s/";
$regExpHTTP = "/\shttp:\1\/([\w_\.]+)\. ([\wl{2,4}l
( [\w\1-_\.?&=]+)\s/";
$exchangeWWW = " <a href=\"http://www.\\1.\\2\\3\"
target=\"_blank\">www. \\1.\\2\ \3</a> ";

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

$exchangeH'ITP = 11 <a href= \ http://\\ 1.\\2\\3\


11 11

target=\ _blank\ >http:/ /\\1.\\2\ \3</a>


11 11 11 ;

$string = preg_replace($regExpWWW, $exchangeWWW, $string);


$string = preg_replace($regExpH'ITP, $exchangeH'ITP, $string);
return $string;

If you haven't looked at many regular expressions before, you might think, "What was that?" But
wait a bit and I'll explain.

$regExpWWW = 11 /\swww\. ( [\w] +) \. ( [\w] {2, 4}) ( [\w\/\-_ \. \?&\=] +) \s/ 11 ;

This expression tests for a address that looks like www.friendsofed.com/index.php?id=9, or just
www.friendsofed.com. It can be broken up as follows:

\swww\. We want a whitespace character followed by 'www.'

( [\wl +) \. Then we want any word I number combination followed by a dot.

( [\w] {2,4}) Is this a valid domain extension? (.uk, .com, .info)

( [\w\/\-_ \. \ ?&\=] +) \sMatch anything after the domain extension


(/index.php?id=9) followed by a space.

$regExpH'ITP = 11 /\shttp: \/\/ ( [\w_\ .] +) \. ( [\w] {2, 4}) ( [\w\/ -_\. ?&=] +) \s/ 11 ;

This expression is almost the same as the above, but here we check the URL in a
http://www.friendsofed.com format

When we get a match, we need to exchange it with a value. We want the URL to appear as <a
href=http://www.friendsofed.com>www.friendsofed.com</a>.

This will be managed with the following exchange:

$exchangeWWW = 11 <a href=\ 11 http:/ /www. \\1.\\2\ \3\ 11 >WWW. \\1.\\2\ \3</a> 11 ;
Case Study 2: e-Commerce Site

Take a look at $regExpWWW, and remember that any character set enclosed in () will be saved
and can be referenced at a later point, so:

( [\wl +)\will be placed in\ \1.

( [\wl {2,4}) will be placed in \\2.

( [\w\1\-_ \.\ ?&\=] +) will be placed in \\3.

By using these references we can build up a link that can be used in an HTML rendered field.

just to make it a bit more interesting I've put together the reverse of what we just did; we now
want a fully working URL in <a> tags taken back to the www.friendsofed.com format.

/**
* Reverse text2url() so that we only see the URLs without <a></a>
.*.tags
* surrounding them
* param $string The string to work on.
* return The changed $string with all <a></a> tags stripped out.
*I
function url2text($string){
$regExp = "/\s<a href=\" ( [\w\.\1:]+)\. ( [\w] {2,4})
( [\w\1-_\.?&=]+)\">(.*)<\/a>\s/";
$exchange= " \\1.\\2\\3 ";
$string= preg_replace($regExp, $exchange, $string);
return $string;

This function will take in a string as an argument, and return a string that is stripped of links. It
builds on the same pattern that we used in the previous function, so you should be able to figure
out what's happening here.

If you want, at a later time, to include a way for the customers to get a new password in case
they have forgotten theirs, I've also included a function that will generate a random string that
you can send via email to the customer on request:

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

/**
* Create a new password that is randomly chosen.
* param $length The length of the new password, defaults to 10
* return The new password
*/
function newPassword($length = 10){
$in = array("a", "A", llbll "B" "c", "C", "d", "D", "e", "E", "f",
1 I

"F" "g", "G", "h", "H", "i", "!", "j


I "J", "k", "K", "1", "L",
II I

"m", "M", "n", "N", "o", "0", "p", "P", "q", "Q-", "r", "R", nsn,
"8", "t", "T", "u", "U", "v", "W", "x", "X", "y", "Y", "z", nzn,
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0");
for($i = 0; $i < $length; $i++) {
srand ((double) microtime() * 1000000);
$val .= $in[rand(O, count($in)-1)];

return $val;

The function defaults to a new password with a length of 10 characters, but you can change that
when you call the script.

What we do is to loop $length times and pull out a random letter from the $in array to build
up a random string that you can supply to your customers. You will of course need to MDS () it
and insert it into the database to make it compatible with the rest of the program, but that
should not be a problem.

To make it more interesting (or frustrating), you can add more to the $in array like'_-+*&"%$#@'
and so on, although random letters and numbers should create a good enough password.

Before we start:
Before we start I'd like to point out that we don't actually protect these scripts with a session or
cookie. But I figure you would have written some protection functions when we have come this
far. I would suggest a function called validateAdmin () or something like that to include on
each page to see that the user is who they claim to be whenever someone calls up a script.
Case Study 2: e-Commerce Site

File: adminAddCategory.php

First up will be to add a category to the category table. There's not much information we need
on a category, in fact only a name will do to add it.

1. Include the two common files:

include_once("settings.inc.php");
include_once("functions.inc.php");

2. We want to make sure that the category we are inserting is not in the database, so we
query the category field for any names that are the same as the one passed to this script:

$catQuery = "SELECT* FROM category WHERE name= 111

$_GET [ 1 categoryName 1 ] " 1 " ;


$catResult = mysql_query($catQuery);

3. If the query returns any rows, then there is a category with the same name already in the
database so an error message is output.

if ($catResult) {
if(mysql_num_rows($catResult) > 0){
fail("The category is in the database. Try another name.");
}else{

4. That's it. We then try to insert the category and return the appropriate message:

$query = "INSERT INTO category (name) VALUES ( 1 "


$_GET [ 1 categoryName 1 ] " 1 ) " ;
$result = mysql_query($query);
if($result) {
echo "status=ok";
}else{
fail("Could not insert the category. Please try again
later. " , mysql_error () ) ;

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

else{
fail("There was an error getting the categories, please try again
later.", mysql_error{));

You should now have a fully functioning script that adds categories. Browse to the script and add
a couple of categories with adminAddCategories .php?categoryName=test007.

File: adminDeleteCat.php
When you have played with the previous script, and added a couple of test categories, it's time
to delete the categories from the database.

1. Include the common files.

include_once ("settings. inc .php");


include_once ("functions. inc. php") ;

2. When we are going to delete a category we need to delete all the items that belong to
that category first. So, if we manage to delete all the children of the parent category, then
we proceed to delete the actual category.

$itemQuery = "DELETE FROM item WHERE parent I II


$-GET [ id l
I I
IIIII.
,
$itemResult = mysql_query($itemQuery);
if($itemResult) {

3. We have deleted all the children to the category:time to delete the category itself:

$query = "DELETE FROM category WHERE ID I II


$-GET [ I id I l ,
Ill II

$result= mysql_query($query);
i f ($result) {
echo "status=ok";
}else{
fail ("Could not delete category." , mysql_error());

}else{
fail("Could not delete the items.", mysql_error());
Case Study 2: e-Commerce Site

4. Have a look in phpMyAdmin or do a query in the MySQL client (SELECI' * FROM


categories) and find the IDs of the temporary categories you created with the previous
file. Then call the script with: adminDeleteCat .php?id=l to delete some of the categories.

A problem that can occur here is if we succeed in deleting the items belonging to a category and
then fail (for some reason) to delete the category itself. One approach to solve this could be to
first query the items, insert them into an array and then if the deletion of the category failed
insert the items back into the table. That way we would ensure that we didn't end up with an
empty category.

File: adminDeleteltem.php

We follow up the deletion of categories with deletion of individual items. This script is quite short
and shouldn't be any problem to decipher.

1. Include the common files:

include_once ("settings. inc .php");


include_once ("functions. inc .php");

2. Delete the item:

$query = "DELETE FROM item WHERE ID I II


$-GET [ I id I l II I I I .
I

$result = mysql_query($query);
if($result) {
echo "status=ok";
}else{
fail("There was an error deleting the item, please try again
later.", mysql_error());

No magic with this script; it deletes an item based on its ID field in the item table.

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

File: adminFetchltem.php

The following file will be called when we request an individual item and present it in its full glory
to the administrator, so now we need to pull out all the information available on the item and
bring it back into Flash.

1. Include the standard shared files:

include_once ( "settings . inc . php" ) ;


include_once("functions.inc.php");

2. The id variable we pass this script is the gCurrentitemid inside Flash that we set when
the user requests an item. Have a look further down to see how we do this.

$query = "SELECT * FROM item WHERE ID = $_GET [ id


1 " Ill II
, 1 1 ]
a

$result= mysql_query($query);
if($result) {
$item= mysql_fetch_array($result);
echo "status=ok";
echo "&itemName=" . urlencode($item["item"]);
echo "&itemParent=" . $item["parent"];
echo "&itemDescription=" . urlencode($item["description"]);
echo "&itemimage=" urlencode($item["image"]);
echo "&itemPrice=" $item["price"];
echo "&itemCount=" $item["count"];
echo "&itemid=" . $item["ID"];
}else{
fail ("There was an error getting information on the item.",
mysql_error() ) ;

3. Call up your browser with adminFetchitem.php?id=l (or an ID that you actually have
there), and you should see something like this:

status=ok&itemName=FiashMX&itemParent=1 &itemDescription=A+test+item+on+flash&i
temlmage=images%2FflashMX.jpg&itemPrice=499&itemCount=2&itemld=1
Case Study 2: e-Commerce Site

File: adminFetchltems.php

This file will populate a drop-down box when we edit items, so we only need the item's name
and its unique ID to reference it. When we select the item in the drop-down box, the
gCurrentitemid will be set to the item's ID.

1. Include the common files.

include_once ("settings. inc .php");


include_once("functions.inc.php");

2. Get all the items that have the particular parent ID we send to this script.

$query= "SELECT ID, item FROM item WHERE parent= 1 "


$_GET [ parent
1 1 ] " 1 " ;

$result = mysql_query($query);
if($result){
echo "status=ok";
$i = 0;
while($item = mysql_fetch_array($result)){
echo "&itemName" . $i "=" . urlencode($item["item"]);
echo "&itemid" . $i . "=" . $item ["ID"];
$i++;

3. We will use itemcount inside Flash to loop through the itemName and itemid to
populate the drop-down box.

echo "&itemCount=" $i;


}else{
fail("There was an error with getting the items for the
category.", mysql_error());

If you go to your browser and call adminFetchitems .php?id=l you should see something like this:

status=ok&itemName0=test+item&itemld0=19&itemName1 =test+ltem+2&itemld1 =20&itemCount=2

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

File: adminGetCategory.php

When we are going to edit the items we need an overview of what category we are going to put
it in. This file will be called to populate a categories drop-down box for the administrator to
select from.

1. Include the common files.

include_once("settings.inc.php");
include_once("functions.inc.php");

2. We want all the categories, and we want the latest category first. You can of course order
by name, but for now we are doing it this way to always get the latest category to show
when we present the categories.

$query= "SELECT * FROM category ORDER BY ID DESC";


$result = mysql_query($query);
if($result) {
$i = 0;
echo "status=ok";
while($cat = mysql_fetch_array($resultll{
echo "&catName" . $i "=" . urlencode ($cat ["name"]);
echo "&catid" . $i . "=" . $cat["ID"];
$i++;

3. catCount will be used to loop through the result set back in Flash to populate the drop-
down box.

echo "&catCount=" . $i;


}else{
fail("I could not get the categories, please try again later.",
mysql_error() ) ;

If you call this script from your browser, you will see an output similar to this:

status=ok&catNameO=test&catld0=55 &catName 1=Code&catld 1=3 &catName2 =Software&catld


2=1 &catCount=3
Case Study 2: e-Commerce Site

File: adminGetlmages.php
When we edit or insert an item we need to get all the images that we have uploaded previously
and populate a drop-down box for the administrator to select from. We need to get the image
name and the image path, which we then are going to insert into the item table.

1. Include the common files and validate the administrator.

include_once("settings.inc.php");
include_once("functions.inc.php");

2. We want to get all the images from the database.

$query= "SELECT * FROM image";


$result = mysql_query($query);
if($result) {
$i = 0;
echo "status=ok";
while($img = mysql_fetch_array($result)){
echo "&imageName" $i "=" urlencode ($img ["name"]);
echo "&imagePath" . $i . "=" . urlencode ($img ["path"]);
$i++;

3. imageCount will be used to loop through the results inside Flash to populate the drop-
down box.

echo "&imageCount=" . $i;


}else{
fail("There was an error fetching the images, please try again
later. " , mysql_error () ) ;

If you had added some images to your database and you browse to this script, you should see
an output similar to this:

status=ok& i mageNameO=fi reworks+i mage& i magePathO=i mages%2 Ffi reworks. jpg& i mageName
1=Maya+image&imagePath1 =images%2Fmaya.jpg&imageName2=test&imagePath2=images%2
Fmaya.jpg&imageCount=3

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

File: adminlogin.php

A valid username and password has to be provided by the administrator entering the actual
administrator site. The following script is called in scene login, and provides us with a way to set
the status of the administrator.

1. Include the common files.

include_once ("settings . inc. php" ) ;


include_once("functions.i nc.php");

2. Create an MDS () hash of the password provided. This will ensure that the passwords in the
database will remain hidden even if there is unprivileged access to it (hopefully that will
never occur, but you can never be paranoid enough!).

$password= md5($_GET[ 1 userPassword 1 ] ) ;

3. Query for both the username and the password. Since the username is unique, but the
password is not, we can be sure that we will get the correct answer back.

$query = "SELECI' * FROM admin WHERE username = 1 "

$_GET [ 1 userName 1 ] " 1 AND password = 1 $password 1 " ;

$result = mysql_query($query);
i f ($result) {
4. If we get one row back we can happily say that the user is who they claim to be, and we
can grant access to the site.

if(mysql_num_rows($result ) 1){
echo "status=ok";
}else{
fail("The user name and password could not be validated.");

}else{
fail ("There was an error getting information on the admin. ",
mysql_error());
Case Study 2: e-Commerce Site

File: adminPDF.php
Now for a quick side note on the use of PDFLib: if you have played with this before you can
probably miss this part and go ahead to the actual script, but for now we are going to see what
this extension to PHP can give us.

What is PDFLib and what can it do??


PDFLib is created by Thomas Merz, and can be found at http://www.pdflib.com/. It has several
language bindings besides PHP. There are also several other packages that can create PDF
documents for you but right now we'll focus on PDFLib and its use.

PDFLib is used to create, guess what: PDF's! You might find the process of learning the PDF
functions a bit cumbersome at first, but when you start realizing what potential there is for
creating PDF documents on the fly, you will see that there definitely is a vast amount of things
you can achieve with it.

Hello World!

To demonstrate the easiest PDF document possible, we are going to create the ever-so-popular
"Hello, World!" example. Create a new document called helloWorld.pdf (make it a blank file,
chmod it to 666 and save it). Then create the following helloWorld.php file.

A note when you start with this: it's wiser to create a empty file and then work with it and save
the result back to that file than to go ahead and output the PDF directly to the browser. The
reason I choose to do it this way is that some errors are bound to sneak their way in; when you
start with new functions there will undoubtedly be errors such as "Wrong parameter count" or
the like, so it's better to get the error messages in the browser and debug them. When you are
confident with this and don't get any errors you can output the PDF directly to the browser.

1. We start by opening the file we just created in a file pointer.

echo "generating the document.... <br>";


$fp = fopen("helloWorld.pdf", "w");
i f ( !$fp} {
echo "Error: could not open the PDF file ... ";
exit() ;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

2. We now use the file pointer to create a new pdf object to work with. Almost all the pdf_*
functions require a pdf object as a first parameter.

$pdf= pdf_open($fp);

3. We continue by preparing a font for use later with pdf_set font () . This function takes
the following parameters: int pdf object, string fontname, and string encoding.
Encoding can be one of the following: builtin, macroman, winansi, host, or a user-
defined encoding name We can also choose to embed a font with a last, optional,
parameter: int embed.

$font= pdf_findfont($pdf, "Times-Roman", "host");

4. You can set the size of the page as large, or small, as you want, but the following is a
standard A4 page's width and height in pixels (which is the unit of measurement with the
PDFLib functions).

$pageWidth = 595;
$pageHeight = 842;

5. Set up some information about the document. "Author", "Title", "Creator", "Subject" and
"Keywords" are the normal keys you can use, but you can add any user defined keys here
if you want to.

pdf_set_info($pdf, "Author", "Havard Eide");


pdf_set_info($pdf, "Title", "Hello, World!");
pdf_set_info($pdf, "Creator", "It's me again!");
pdf_set_info($pdf, "Subject", "Say it loud!");
pdf_set_info($pdf, "Keywords", "hello, world");

6. Each page starts with the pdf_begin_page () function. You need to give it the dimensions
of the page you are creating, and the pdf object we created as a first parameter.

pdf_begin_page($pdf, $pageWidth, $pageHeight);


Case Study 2: e-Commerce Site

7. We proceed to set the font we are going to use with the output. We are here using the
font we prepared earlier. You have to call this function each time you are changing font.

pdf_setfont($pdf, $font, 20);

8. The following function outputs our desired string. It takes the pdf object as the first
parameter, then the string we are outputting, and last of all you have to decide on where
to put the string. This particular string will be displayed 50 points from the left part of the
document and 20 points down from the top of the document. This is special formatting
practice for PDFLib; the lower left corner is defined as point 0,0. So keep that in mind if
you are getting some weird results!

pdf_show_xy($pdf, "Hello, World!", 50, $pageHeight - 20);

9. Finally we end the page, close the pdf object, and close the file pointer that we have been
working on.

pdf_end_page($pdf);
pdf_close($pdf);
pdf_delete($pdf);
fclose($fp);

echo "<a href;\"helloWorld.pdf\">get the hello</a>";

If you now open the helloWorld.pdf in Acrobat Reader and go to File> Document Info>
General, you'll see the information we entered with the pdf_set_info() function.

That was it for a quick introduction to PDFLib. We'll continue our PDF exploration by creating an
overview of what's in our database: items, cost, and how many are left of each item.

Let's go back to the file we want to create with adminPDF. php:

1. Include the common files.

include_once ("settings. inc .php");


include_once ("functions. inc .php");
<html>

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

<head>
<title>Generating PDF ... </title>
</head>
<body bgcolor="#617C58">
Generating PDF now ...
<?php

2. Open up a PDF document to work with; you need to create a blank PDF .pdf file and
chmod it to 666 to make this work.

$fp = fopen("PDF.pdf", "w");


if(!$fp){
echo "Error: could not create the PDF file ... ";
exit() ;

3. Create a new PDF object to work with.

$pdf= pdf_open($fp);

4. Next, go on to prepare the fonts we are going to use:

$normalFont = pdf_findfont($pdf, "Times-Roman", "host");


$boldFont = pdf_findfont($pdf, "Times-Bold", "host");

5. Set the information about the document.

pdf_set_info($pdf, "Author", "Havard Eide");


pdf_set_info($pdf, "Title", "Innvoice report fore-commerce");
pdf_set_info($pdf, "Creator", "Havard Eide");
pdf_set_info($pdf, "Subject", "Innvoice report");
pdf_set_info($pdf, "Keywords", "e-commerce, shop, PHP, PDFLib");
Case Study 2: e-Commerce Site

6. The next thing is to set up the size of the document. We are going to use an A4 page, but
you can use whatever size you want. These are the sizes defined at www.php.net:

Name Size
AO 2380 X 3368
A1 1684 X 2380
A2 1190 X 1684
A3 842 X 1190
A4 595 X 842
AS 421 X 595
A6 297 X 421
BS 501 X 709
Letter (8.5" x 11 ") 612 X 792
Legal (8.5" x 14") 612 X 1008
Ledger (17"x 11 ") 1224x792

$pageWidth = 595;
$pageHeight 842;

$pageNumber = 1;

7. To do anything with a document. or move to the next page we need to start a new page
with the pdf_begin_page () function:

pdf_begin_page($pdf, $pageWidth, $pageHeight);

8. Set the font for the header, and display it:

pdf_setfont($pdf, $norma1Font, 20);


pdf_show_xy($pdf, "Report for MyCompany (tm) ", 100, $pageHeight - 20);

9. Draw a line underneath the header:

pdf_moveto($pdf, 100, $pageHeight - 30);


pdf_lineto($pdf, 400, $pageHeight - 30);
pdf_stroke($pdf);

' 0
1 rn CJ cJ

;\~LC L'
Dec~ e
Advanced PH P for Flash

10. Next set up a string underneath the header to tell when the document was created:

pdf_setfont($pdf $norma1Font
1 1 16);
pdf_show_xy($pdf "Generated
1 " . date("d/m/Y") I 1751
$pageHeight - 50);

11. Time to loop through the categories and items and print them out. $ypos will be used to
track how far down from the TOP of the document we are.

$ypos = 50;
$query = "SELECT * FROM (category INNER JOIN item ON
item.parent=category . ID) ORDER BY item.parent";
$result= mysql_query($query);
if($result){
$currentCat 1111.
I

while ($item mysql- fetch- array($result)){

12. Check if there is enough space on the page for a category (50) + item (30):

if($ypos >= $pageHeight- 85){

13. We are at the end of the page, so print out the page number:

pdf_show_xy($pdf "Page : " . $pageNumber++ 10 10) ;


1 1 1

II end a page
pdf_end_page ($pdf) ;
II and start a new one:
pdf_begin_page($pdf $pageWidthl $pageHeight);
1

/ /reset the $ypos so that we start at the top of thepage:


$ypos = 25;

pdf_setfont($pdf 1 $norma1Font 1 18);

14. Test for a category heading:

if ($currentCat != $item["name"]) {
$ypos += 50;
Case Study 2: e-Commerce Site

pdf_setfont($pdf, $normalFont, 20);


pdf_show_xy ($pdf, "Category : " , 3 0, $pageHeight - $ypos) ;

15. Set the color, which requires the use of floating-point values:

pdf_setcolor($pdf, "both", "rgb", 0.45, 0.65, 1);


pdf_setfont($pdf, $boldFont, 20);
pdf_show_xy($pdf, $currentCat = $item["name"], 120,
$pageHeight- $ypos);
pdf_setcolor($pdf, "both", "rgb", 0, 0, 0);
pdf_setfont($pdf, $normalFont, 14);

16. Set up a header for each category. This will follow the category name just printed out, all
with a line underneath it.

pdf_show_xy($pdf, "Price", 300, $pageHeight - $ypos);


pdf_show_xy($pdf, "Items left", 420, $pageHeight -
$ypos);
pdf_setfont($pdf, $normalFont, 18);
pdf_moveto($pdf, 30, $pageHeight- $ypos- 10);
pdf_lineto($pdf, 510, $pageHeight - $ypos - 10);
pdf_stroke($pdf);
$ypos += 30;

17. Time to show each item:

pdf_show_xy($pdf, "* " . $item["item"], so, $pageHeight -


$ypos);
pdf_setfont($pdf, $normalFont, 14);
pdf_show_xy($pdf, $item["Price"] . "\$", 300, $pageHeight -
$ypos);
pdf_show_xy($pdf, $item["count"], 450, $pageHeight - $ypos);
$ypos += 30;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

18. Finally we close the page, print the final page number, and close the file pointer and the
$pdf object.

pdf_show_xy($pdf, "Page " . $pageNumber, 10, 10);


pdf_end_page($pdf);
pdf_end_page($pdf);
pdf_close($pdf);
fclose ($fp) ;
?>
<br>
<a href="PDF.pdf">get the file</a>
</body>
</html>

If you want to show an image, do the following:

$img = pdf_open_image_file($pdf, "jpeg", "images/flash.jpg");


pdf_place_image($pdf, $img, 50, $pageHeight- 350, 1);
pdf_close_image($pdf, $img);

Have a closer look in the manual if you want to dig deeper into PDF file generation.

File: adminPreviewlmage.php
Since we do plan to scale this movie for future enhancements, we need to be able to preview any
of the images that an administrator has uploaded, sort:~etimes it might not be enough to have a
name to decide if the image fits the item, so we need a script to preview it. We will be calling this
with a popup javaScript we will create later, and it will bring the image up in a new browser window:

<html>
<head><title> Image preview </title></head>
<body bgcolor="#617C58">
<img src="<?php echo $_GET ['image'];?>">
</body>
</html>
Case Study 2: e-Commerce Site

File: adminSaveltem.php
Next on the agenda is to actually input the various items that will make up the most important
aspect of our site: the merchandise that your users will buy.

1. Start up by including the common files.

include_once("settings.inc.php");
include_once("functions.inc.php");

2. Build up the query from the variables we send to PHP:

$query = "INSERT INTO item (item, price, parent, description, image,


count)";
$query . = " VALUES ( 1 " $_POST [ 1 itemName 1 ]
Ill
I
II.
I

$query . = " 1 " $_POST [ 1 itemPrice 1 ] Ill I II

$_POST [ 1 itemCategory 1 ]
Ill II
I I

$query .= II Ill
. $_POST [ 1 itemAbout 1 ] II I 1 " $_POST [ 1 itemimage 1 ]
... 111 1 Ill
$_POST [ itemCount
1 1] " 1 ) ";

$result = mysql_query($query);

3. Finally ensure that we actually managed to save the item.

i f ($result) {
echo "status=ok";
}else{
fail ("There was an error inserting the item.", mysql_error ());

If you wanted to make sure that this script actually works you'd need to set up a new file with a
<form> pointing to this file with all the appropriate input fields in it.

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

File: adminUpdateCat.php

When the administrator of the site has entered a category, and over time comes to realize that
it needs a different name, we have to supply a method for updating it. This is a pretty
straightforward script: we get a name and an ID from Flash, and then update the name of the
item that has that ID.

1. Include the common files.

include_once("settings.inc.php");
include_once ("functions. inc .php");

2. Set the new name of the category.

$query = "UPDATE category SET name = ' " $_GET ['name'] Ill

WHERE ID = I II $-GET [ I id I l II I II ;

$result = mysql_query($query);
if($resultl{
echo "status=ok";
}else{
fail("Could not update the category. " mysql_error());

File: adminUpdateltem.php

We also have to provide a function for updating an item; the price might change, the parent
category could be wrongly inserted, or a typo could be present in the item's description.

1. Include the common files.

include_once("settings.inc.php");
include_once ("functions. inc .php");

2. Build up the query for the update.

$query = "UPDATE item SET item Ill


$_POST [' itemName'] ,
11 , ,
Case Study 2: e-Commerce Site

$query .- " parent = I l l . $_POST [ iternParent


I
1 1 ] " 1 ";

$query description = $_POST [ i temDescription l


1 " 1 1 II I l l .
I

$query .- " image Ill


$_POST [ itemimage 1 1 ] " 1 ";

$query .- price Ill


$_POST[ 1 iternPrice 1 ] "'" I

$query .- II
count
I
Ill
$_POST[ 1 itemCount 1 ] IIIII.
I

$query . - " WHERE ID = 1 " $_POST [ itemid



IIIII.
1 1 ]
I

$result = mysql_query($query);

3. Finish up by validating the result from MySQL.

if($result) {
echo "status=ok";
}else{
fail("There was an error updating the item.", mysql_error());

The itemid of the item we are updating is identical to the gCurrentitemid in Flash.

File: adminUpload.php

There is no way to upload an image from within Flash without any external means, so we will
pop up a new window to let the administrator handle that. To actually be able to upload an
image to the server you need to have a writable directory; make a new directory called images,
and chmod it to 777.

1. Include the common files.

include_once("settings.inc.php");
include_once("functions.inc.php");

2. Escape out to HTML and print the header for the document:

?>
<html>
<head>
<title>File uploading for e-commerce</title>

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

</head>
<body bgcolor="#617C58">
<?php

3. When we upload the file we will call the same script, but with a ?do=upload at the end
of the URL: if there is a do defined we've got an upload and have to process it:

if(isset($ GET['do']ll{
?>
<a href="adminUpload.php">ba ck</a><br>
<?php

4. We are going to do several tests before we can call it a successful upload. First check if we
have a name for the file. The administrator-given name for the file we upload is in
fileName as we define a bit further down; this is the name that will go into the database
and show up in the drop-down box within Flash.

if($ POST['fileName'] == "") {


echo "You have to name the file before you can upload it!";
exit() ;

5. The next check is for the size of the file. Here we test to see if it is an empty image that
the administrator is trying to upload.

if ($_FILES [ 'uploadFile '] ['size'] 0) {


echo "File empty ... ";
exit();

6. We are only going to allow JPEG images to be uploaded, so we check for that as well.
There are some issues with this concerning what the image type is: either "image/jpg" or
"image/pjpg". Please have a look at http://www.php.net/manual/en/features.file-
upload.php if you run into any problems with this.

if($_FILES['uploadFile'] ['type'] != "image/jpeg") {


echo "You can only upload jpg images.";
exit() ;
Case Study 2: e-Commerce Site

7. Time to check that the file is under our size limit.

i f ($_FILES [ 'uploadFile '] ['size'] > 1024 * 100) {


echo "File is too large, max size is : 100 KB.";
exit();

8. We never assume anything about the administrator, so check that we don't override an
already existing image.

i f (file_exists ("images/". $_FILES [ 'uploadFile'] ['name'])) {


echo "Image exists. Change the name of the image and retry.";
exit();

9. Is the file an uploaded file? We have to make sure that we don't have any pranksters trying
to con us.

if (is_uploaded_file($_FILES['uploadFile'] ['tmp_name']))

10. Try to move the uploaded image to its destination.

if(!move_up1oaded_fi1e ($_FILES['up1oad.Fi1e'] ['tmp_name'], "images/".


$_FILES['uploadFile'] ['name'])){
echo "Could not upload image .... ";
exit();
}else{
$query= "INSERT INTO image (name, path) VALUES ('" .
$_POST ['fileName'] . "', 'images/" .
$_FILES['uploadFile'] ['name'] . "')";
$result = mysql_query($query);
i f ($result) {
echo "Image uploaded and name saved.";
}else{
echo "There was an error with uploading the image.
(database failure) ";

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

11. If we can't insert the image name to the database, delete it from the server.

unlink ("images/" . $_FILES [ 1 uploadFile 1 ] [ 1 name 1 ] ) ;

}else{
echo "There was an error, please try again.";

12. If we come to this file directly without a ?go=upload attached to it, it means that a upload
has not been performed, and we need to display the upload form to the user.

}else{
?>
<form enctype="multipa rt/form-data"
action="adminUplo ad.php?do=upload"
method="post">
<input type="hidden" name="MAX FILE SIZE" value="1000000">
- -
<table>
<tr>
<td>
Upload this file:
</td>
<td>
<input name="uploadFile" type="file">
</td>
</tr>
<tr>
<td>
Your name of this file:
</td>
<td>
<input type="text" name="fileName">
</td>
</tr>
<tr>
<td>
Case Study 2: e-Commerce Site

&nbsp;
</td>
<td>
<input type="submit" value="Send File">
</td>
</tr>
</table>
</form>
<?php

</body>
</html>
</head>

If you get into any problems, check for the permission on the folder we are uploading to
(images/ relative to the current directory). It is also important that the form is set up as follows:
form enctype="multipart/form-data" and that you include the input type="hidden"
name="MAX FILE SIZE" field.

File: addAdminUser.php
just before we start integrating PHP with Flash, you might want to add a user to the administrator
table so that you can log into your site later on. The following script is a quick one that doesn't
check for duplicate entries etc. but should be a starting point for you to expand on later.

<?php
include_once("settings.inc.php");

if(isset($ GET[ 1 do 1 ] ) ) {
i f ($_POST [ password
1 ! = $ POST [ password2
1 ] 1 1 ] ) {

echo "The passwords did not match. Please try again.";


die();

$password= md5($_POST[ 1 password 1 ] ) ;


$query = "INSERT INTO admin (name, userName, password) VALUES
(I II $_POST [ 1 name 1 ] II I II
I

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

$query . = " 1 " $_POST [ userName


1 1 ] " 1 1 "$password . "
1 ) " ;

$result= mysql_query($query) or die(mysql_error());


i f ($result) {
echo "The administrator $_POST [ 1 userName 1 ] was
added.";
}else{
echo "There was an error adding the administrator. Please
try again later.";

}else{
?>
<form name="addAdmin" method="POST"
action="addAdminUser . php?do=insert">
<table>
<tr>

Name
</td>
<td>
<input type="text" name="name">
</td>
</tr>
<tr>
<td>
User name:
</td>
<td>
<input type="text" name="userName">
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
<input type="password" name="password">
</td>
Case Study 2: e-Commerce Site

</tr>
<tr>
<td>
Re-write password
</td>
<td>
<input type="password" name="password2">
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
<td>
<input type="Submit" value="Insert
administrator">
</td>
</tr>
</form>
<?php

Wrap up
Now you should have a set of PHP scripts that are fully functioning before we start to integrate
them into Flash. Hopefully all of them are working correctly and you should now have some
categories with items in them so that when we start to load the files into Flash, we will have items
and categories to work with.

That's it for the PHP: next on the agenda is to pull the information into Flash.

Interface
When we now start to build up the interface for the administration page, we will try to
accomplish an easy-to-use and intuitive interface whose elements will work together in a smooth
fashion to make the updating and adding of items and categories an easy task for you and your
client. We are going to build parts of the interface in a component-based style, this will be done

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

to save development time and to make the transition between elements smoother and quicker.
It's important that the elements we develop can work independently and request action from
other components in the interface; you will see this a bit further on when we come to them.

Open up the administrator-noCode. fla and take a look


around it. As you can see it is stripped of all code except for t~ y Scene ==--...

the menu buttons at the top. ~ preloader


~login
~ main
~ categories
~ addltem
'&! editltems
~upload
~ report
~error
ll,jgl + "'

The movie is divided into one scene for each task that we are going to implement. We are now
going to walk through each scene and add the ActionScript that will take care of the loading,
parsing, and building of the final administration movie.

Scene: preloader
The final SWF will not weigh in at much. so it is not necessary to implement an extensive
preloader. Of course. if you do want to set up a more elaborate preloader there should be no
problem implementing it, but for now we are just going to look at the PHP integration side of
the page.

There are only two frames in this scene. On the second frame in the actions layer apply the
following script:

if (_root.getBytesLoaded() _root . getBytesTotal())


gotoAndPlay ("logi n", 1) ;
else {
gotoAndPlay ( 1) ;

There's not too much to say about this: if the bytes loaded are the same as the total number of
bytes in the movie, go to the login scene.
Case Study 2: e-Commerce Site

Scene: login.
In the screenshot, the timeline is divided into four parts: loglnStart, loglnload, loglnTest, and
loglnEnd. This is a structure we are going to stick with both in this movie and the client interface
we are going to build later.

administrator.fla

u;linpulfl~lds
,._ CJ backgrouncJ 0 FF------""
1+1i:J 12.0 Ips O.Os

We have two input fields: userName and userPassword, where the password field is set to type
password. We are using a separate layer called actions to hold all the actions. This is where all
future actions will be put unless otherwise pointed out.
Advanced PHP for Flash

In the loginStart frame attach the following:

userName = 11 11 ;
userPassword = 1111. I

login= new LoadVars();


stop();

This will clear out the two input fields and create a new LoadVars () object that we will use to
log the user into the administration area.

Then on the Log In button, attach the script that will query the admin table:

on(release){
login.load( 11 adminLogin.php?userName= 11 + userName + 11 &userPassword= 11 +
userPassword, login) ;
gotoAndPlay ( 11 loginLoad 11 ) ;

This will load the adminLogin.php script with userName and userPassword as parameters.

Note : You might wonder why I use the .load () function and
not the . sendAndLoad () function with the LoadVars () object.
This is a matter of taste and what you are sending and loading.
For small loads like this I will continue to use the . load ()
function; this will be apparent as we go on. Ifyou do want to use
the . sendAndLoad () there is no problem doing it, but as I said,
this is just my preferred style, so choose whatever you like!

This is also true when it comes to the ActionScript that we will write later, if you do have issues
with what's there, change it! (I tend to go more towards an "old-school" style of writing
ActionScript) If you have a style other than the one applied during this movie, change it! Actually,
I challenge you to do it! Copying scripts from this book might help you understand it, but to
really understand and have a deeper knowledge of what we are doing, it would actually be better
if you challenge what I show you and redo the entire movie, when we are finished with it!
Case Study 2: e-Commerce Site

Back to the timeline. When the administrator clicks the button, the play head is sent forward to
the loginLoad frame, this is a technique you will see applied as we dig deeper into the movie.
When the play head reaches the loginTest frame, we check if we have loaded the script by
applying the following script:

if(login.loaded){
gotoAndPlay( 11 loginEnd 11 ) ;
}else{
gotoAndPlay ( 11 loginLoad 11 ) ;

When the login object has loaded the script, we go ahead to the loginEnd frame where we
apply the following script:

if(login.status == 11 0k 11 ) {
_root.gLoggedin = true;
gotoAndPlay( 11 main 11 , 1);
}else{
outputArea = login.error;

stop();

What can be done to extend this?


One thing you could do is to set up a new field in the admin table called level, and then apply
different levels to different administrators of the site. You do want to make sure that only highly
approved administrators can delete a category, but anyone can insert an item. You would then
have a _root. gAdminLevel that controls the timeline further on in the movie.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

Scene: main
This scene consists of just a greeting for the user, describing what can be done within the movie.
There are no actions in this screen, so nothing to be done here!

,
~8 0 0 a administrator.fla
Jl!iy Tlmeline I
... ' .. .. ... '. . . . . . . . . . . ... .. . I,
lf.I D , ,s , , , .1 ~ , , , 1~ , , . 2~ , , , .2~ , , ,3~ . , , ,3s , , .4~ , , .4~ , , , I ~

~ Ll background 11

I '1110
I
I 1&J
@I
-
~ [~ 1 1 Z.O fps O.Os
-
[ .:- I

~ main 10

..,.
~----------------~~~------------------~~~~~ d

Well, actually there are actions on the buttons in the menu at the top, but I've included these
on all scenes. These are the same for all of the scenes, so there is no need to do that repetitive
task over and over again.
Case Study 2: e-Commerce Site

Scene: categories
Now it's time start to pull in the categories we have in the database and do the following things
to them: add, update, and delete a category.

As you can see, the screen is divided into two parts: the right part takes care of inserting a new
category and the left takes care of updating and deleting the categories.

r @ {) 0 " admlni~tra.tor.fla
TTimellne

. 1!1
.-~ o 1
0

I
I

I
0

I
010

I
5
I I
I

0
o

I
0

I
I

o
0

10
I
0

I
<

I
o.

0 0
IS
<'
I 0
0

o
f

I
I

20
0

0
I

I
0

0
010

o
25
I 0
I

o
0

I
I

0 ~::: :3 ~ ::: :4?.:: :4~ ::: :s"!


[U actions jg"editStart 0r., .att.oad ~ ,.ti11t Tut 0 itEnd _j
[U
[U
buttons
loadtr .. 1!1
1!\ iJ
_. ,;
rio
[

:J
[
[
[U oddCat 1!\ D ~-:' _j

. 1!1
;_.
[U catMC I!I D o' _j

.. ~
0

[U text 0 0 _l _j
~ LJ top ~
~
UHJ
a background Iii
m I 'ii'O . [) !0 t l .Ofpo z. I ~- . ~ I
I ~ utegorits 1 ~ ~ rsz;-:u!l
Advanced PHP for Flash

When we enter the editStart frame we load in the categories we have in the database for
editing in the left part of the screen. In the editStart frame, attach the following ActionScript
to load the categories we have:

_global.gSaveCat =new LoadVars();


_global.gDeleteCat =new LoadVars();
_global.gUpdateCat =new LoadVars();
_global.gEditCategory = new LoadVars();
_global.gCategoriesPage = 1;
gEditCategory .load ( 11 adminGetCategory .php 11 ) ;

gotoAndPlay ( 11 edi tLoad 11 ) ;

The four LoadVars () objects are used on different levels and depths in this scene. They are
used and reused, so we need different objects to maintain state and reload the same objects
several times when they are needed.

We could probably use only two objects, but it's wise to declare
several of them to make the code we write clearer and more
maintainable as the movie grows (and when, or it the next
developer takes over your project).

The gCategoriesPage is set to 1. This variable will be used to cycle through several pages if we
have a lot of categories in the database; we'll look at this shortly.

We then proceed to load the categories we have in the database into the gEditCategory object
and send the play head to editLoad.

The editLoad frame contains no ActionScript, but when we reach editTest we apply the
following to test if we have received a result from the server:

if(gEditCategory.loaded){
gotoAndPlay ( 11 editEnd 11 ) ;
}else{
gotoAndPlay ( 11 edi tLoad 11 ) ;
Case Study 2: e-Commerce Site

The next thing to do is in the editEnd frame. As the previous screenshot showed, there are ten
instances of categoryEditCatMC placed on the left part of the screen, named cato to cat9
and we will take care of the updating and deleting of the categories. First we need to fill the MCs
with the code from the server in frame editEnd.

I made the instances directly on the screen before any querying


was done. You could of course use the duplicateMovieClip ()
function to achieve the same thing, but I prefer to do it this way
to visualize the layout of the screen before any parsing of the
returned result.

1. Since we don't know how many categories the query returns we must set all MCs'
visible to false.

if(gEditCategory.status == "ok"){
for(i = 0; i < 10; i++l{
_root["cat"+i] ._visible = false;

2. Also, set the previous page and next page buttons _visible to false (there is no need
to have all of these showing if there are less than 10 categories in the database).

_root.nextButton._visible = false;
_root.previousButton._visible = false;

3. Now assign gEdi tCategory. cat Count to rnaxLoop. rnaxLoop is used to loop through the
result set from the query. There are only 10 MCs available on screen; if rnaxLoop exceeds
10 we assign 10 to rnaxLoop to ensure we only loop through the correct number when we
hit this frame.

rnaxLoop = gEditCategory.catCount;
if(rnaxLoop > 10){
rnaxLoop = 1 0 ;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

4. We then proceed to loop from 0 to maxLoop; in each round we show the correct cat MC
and assign a Name and an Id to it pulled from the gEditCategory.

for(i = 0; i < maxLoop; i++l{


_root["cat"+i] ._visible= true;
_root["cat"+i] .name = gEditCategory["catName"+i];
_root["cat"+i] .Id = gEditCategory["catid"+i];

5. Finally we set the next page buttons visible to true if there are more than 10
categories returned from the query.

if(gEditCategory.catCount > 10){


root.nextButton. visible = true;

stop();
}else{
_root.gErrorString gEditCategory.error;
gotoAndPlay("error", 1);

Next page button

If there are more than ten categories returned from the query we have to have a next page and
a previous page button that will loop through the result set and display the categories for each
page. On the nextButton we'll assign the following code:

1. We start off by setting each of the MCs' _visible to false (there could only be one
category on the next page).

on(release){
for(i = 0; i < 10; i++l{
_root["cat"+i] ._visible false;
Case Study 2: e-Commerce Site

2. We now apply the same technique as above. We have an upperLimit assigned to 10; if
gCategoriesPage (initially set to 1) * 10 + 10 is less than the number of categories we
got back from the database, then the upperLimi t is set to gCategoriesPage * 10 + 10.

Example: if gCategoriesPage is 1 and gEditCategory. catCount is 30, then we will get


the following:

If(20 < 30){


upperLimit 20;

This will result in the next page looping from 10 to 20, which is exactly what we want.

upperLimit = 10;
if((gCategoriesPage * 10) + 10 < gEditCategory.catCount){
upperLimit = (gCategoriesPage * 10) + 10;
}else{

3. Should the if statement be false, we assign gEditCategory. catCount to upperLimit


and hide the next page button. If there are less than 20 items in the result set there is no
third page, so there is no need for the button to show.

upperLimit = gEditCategory.catCount;
root.nextButton. visible = false;

4. Next we put up a temporary variable J, which will be used to target the cato to cat9 MCs.

j = 0;

5. We then proceed to loop from gCategoriesPage * 10 to the upperLimit we just


found. In each loop we show the MC and assign the correct Name and Id to the MC as we
did when we hit the editEnd frame script.

for(i = gCategoriesPage * 10; i < upperLimit; i++){


_root["cat"+j] ._visible = true;
_root["cat"+j] .name = gEditCategory["catName"+i];

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

_root["cat"+j] .Id gEditCategory["catid"+i];


j++;

6. Finally we add 1 to the gCategoriesPage and set the previous page button to show (if
we have gone one page ahead there is always one page back).

gCategoriesPage++;
II if we click "next" there is always a previous.
_root.previousButton._visible = true;

Previous button
The previous page button script follows exactly the same pattern as the next page button. The
change is that we subtract one from the gCategoriesPage and we don't check for a limit to
loop through (if we have gone one page ahead we know that there must be at least ten
categories on the previous page).

on(release){
for(i = 0; i < 10; i++){
_root["cat"+il ._visible false;

gCategoriesPage--;

j = 0;
for(i = (gCategoriesPage * 10) - 10; i < (gCategoriesPage * 10);
.. i++) {
_root["cat"+j] ._visible =true;
_root["cat"+j] .name= gEditCategory["catName"+i];
_root["cat"+j] .Id = gEditCategory["catid"+i];
j++;

II i f we click "previous", there is always a next.


_root.nextButton._visible = true;
if(gCategoriesPage == 1){
_root.previousButton._visible = false;
Case Study 2: e-Commerce Site

Categories update/delete MC
Now we'll have a look at the cato to cat9 MCs that we have been targeting with the script so
far. Each of these MCs is capable of editing and deleting the category name we assigned it, so
double-click one of them and have a look inside. The timeline is quite long, so I won't show it
here, but by now you should have seen the pattern we are working on.

As you can see we have a text field called Name, an Update button, and a Delete button. Let's
begin with the Delete button:

1. In the start frame we have to assign the following action to the Delete button:

on(release){
gotoAndPlay ( 11 edi tConf irm 11 ) ;

This will not delete the category, but take us to a confirmation screen where the user has
to click the Delete button again to actually delete it. We have to get a confirmation from
the user; to delete the category means that not only the category is gone, but also all the
items belonging to it. (Always cover your back when you do something like deleting a
category; then, when a customer comes and says "I deleted the category by accident!", you
know that they had to press the button twice to actually do it.)

2. Back to the button; to delete the category we need to assign a new script to the Delete
button in the editConfirm frame:

on(release) {
gDeleteCat.load( 11 adminDeleteCat.php?id= 11 + this.Id);
gotoAndPlay ( 11 editLoad 11 ) ;

3. This will use the Id we assigned to the MC in the editEnd frame of the categories scene. We
then go ahead and loop until we get the result back. In the editTest frame, assign the following:

if(gDeleteCat.loaded) {
gotAndPlay ( 11 edi tEnd 11 ) ;
}else{
gotoAndPlay ( 11 edi tLoad 11 ) ;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

4. Then finally in editEnd attach the following script:

if(gDeleteCat.status == "ok"){
with(_root){
gotoAndPlay ( " "edi tStart") ;

}else{
_root.gErrorString gDeleteCat.error;
gotoAndPlay("error", 1);

stop();

If we succeed in deleting the category the play head is sent back to the initial frame of the
categories scene. This way we witt toad in all the categories again, and we witt end up with
a fresh, updated overview of the categories. If we fait in deleting the category, we are sent
to the error scene.

Now that we have the possibility to delete a category, we need to be able to update a
category's name as well.

5. Go back to the start frame and attach the following to the Update button:

on(release) {
gUpdateCat.load("adminUpdateCat.php?id=" + this.Id + "&name=" +
this.name);
gotoAndPlay ( "updateLoad") ;

The name field is an input field, so when the user has changed the name of the category
and hit the Update button we send the Id of the category together with the new name to
the server and go ahead to the updateLoad frame. A routine check for a return from the
server in updateTest is then carried out (believe me, this is a normal routine that you
probably witt be able to write in your steep when we are finished with this chapter):

if(gUpdateCat.loaded) {
gotoAndPlay ( "updateEnd") ;
}else{
gotoAndPlay ( "updateLoad") ;
Case Study 2: e-Commerce Site

6. Finally in updateEnd we want to check that we actually got the response that we wanted:

if(gUpdateCat.status == "ok") {
gotoAndPlay ("categories", 1) ;
}else{
gotoAndPlay ("error", 1) ;

Again, if we get a positive result back from the server, the play head is sent back to the first frame
of the categories scene so that we can get a freshly updated category list from the server.

That's it for updating and deleting the categories.

Inserting a new category

Now for inserting a new category.

00 admlnlstrator.fla
1. Go back to the main ., Tlmeline

timeline in the categories


scene. In the addCat layer
you'll find an instance of
categoryAddMC. This is
an MC that has all its
behavior within it, so
double-click it and look at
the following timeline:
Advanced PHP for Flash

2. In the addStart frame add the following ActionScript:

gAddCategory = new LoadVars();


newCategory 1111.
I

stop();

3. Next we want to actually add the category, so put the following on the Add button:

on(release) {
gAddCategory.load("adminAddCategory.php?categoryName=" +
newCategory);
gotoAndPlay ( "addLoad" ) ;

The name of the new category is found in the newcategory input field, so load the name
and send the play head to addLoad.

4. Next move on to the addTest frame and add the following check, which will move the
play head to addEnd when the results are back from the server:

if(gAddCategory.loaded) {
gotoAndPlay ( "addEnd" ) ;
}else{
gotoAndPlay ( "addLoad" ) ;

5. Add the following code to addEnd:

if(gAddCategory.status == "ok"){
outputArea = "The new category was added.";
gCategoriesPage = 1;
with(_root){
gotoAndPlay ( "edi tStart") ;

gotoAndStop ("addS tart" ) ;


}else{
_root.gErrorString = gAddCategory.error;
gotoAndPlay("error" 1); 1
Case Study 2: e-Commerce Site

When the server returns a positive result we reset the gCategoriesPage to 1, and send
the play head of the movie back to the first frame of the categories scene. That way we
will get a fresh list from the server (that starts at page 1). and the newly created category
will be available for editing.

6. Finally add the following code to the Back button so that we can create a new category:

on(release) {
gotoAndPlay ( 11 addS tart 11 ) ;

That's it for creating, editing, and deleting categories. Next we'll have a look at inserting items
into the categories we have.

Scene: add Item

Go to the additem scene and have a look around. The timeline we use is as follows:

i dmlnlstrator.fla
[. . TTimoiiM

U,) Ktlot~1o
[V lo>dO< 0
[V -'""'""" ~-------__jl!f----nr-------:r--~
lhmnu
.g ..-;CJ

:I
Advanced PHP for Flash

1. We want to get all the categories and pictures (names and paths, not the actual images)
from the database and put them into a drop-down box, so go to the additernStart frame
and add the following start script:

_global.gSaveitem = new LoadVars();


_global.gimages = new LoadVars();
_global.gitemCategory = new LoadVars{);
gitemCategory .load ( 11 adminGetCategory .php 11 ) ;

gimages .load ( 11 adminGetimages .php 11 ) ;


gotoAndPlay ( 11 additemLoad 11 ) ;

This will load all the categories into the gitemcategory object and all the image names
and paths- into the gimages object.

2. In additemTest we have to check for the return result before we play ahead:

if(gitemCategory.loaded && gimages.loaded){


gotoAndPlay ( 11 additemEnd 11 ) ;
}else{
gotoAndPlay ( 11 additemLoad 11 ) ;

This will ensure that both of the objects are loaded before we go any further.

Now we need to parse the return result back into the drop-down components on the
stage, so in frame additemEnd we need to add the following script.

3. First, make sure that we have a positive result from the server.

if(gitemCategory.status == 11 0k 11 && gimages.status == 11 0k 11 ) {

4. Loop through the gitemcategory and insert the Name and Id into the itemCategory
drop-down component. This will display the name of the file to the administrator, and we'll
use the Id to target the parent of the item.

for(i = 0; i < gitemCategory.catCount; i++l{


_root.itemCategory.additem(gitemCategory[ 11 catName 11 +i],
Case Study 2: e-Commerce Site

gitemCategory[ 11 catid 11 +i]);

5. We then need to add the image name and image path to the itemimage drop-down
component. The administrator will see the name of the image, but we'll use the path when
it's time to insert the item into the item table.

for(i = 0; i < gimages.imageCount; i++l{


_root.itemimage.additem(gimages[ 11 imageName 11 +i],
gimages[ 11 imagePath 11 +i]);

6. The following drop-down component gives our predefined number of items to initially
insert into the database. Set this to whatever you want (it is kind of restrictive to only be
able to insert five items).

for(i = 5; i <=50 i+= 5){


_root.itemCount.additem(i, i);

7. Remember to reset the input names so that we don't have those hanging around when the
administrator comes back here for a second insert:

_root.itemName = 1111 ;

root.itemPrice 1111.

'
root.itemAbout 1111.

'
stop();

8. Finally, if we get a negative result from the PHP script we send the movie to the error scene:

}else{
_root.gErrorString gitemCategory.error + 11 \n\n 11 +
g!mages.error;
gotoAndPlay( 11 error 11 , 1);
stop();

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

Preview Image button


Next to the image drop-down component there is a "Preview Image" button, in case the
administrator doesn't remember which image goes with what name. We will pop up a new
browser window with the image in its full size, so all we need to do to utilize the
adminPreviewimage .php script we made earlier is to add the following action to the button:

on(releasel{
getURL ( 11 j avascript: launch ( 'adminPreviewimage. php? image= 11 +
i temimage. getSelecteditem () . data + 11 ' , ' Image Preview' ,
'resizable,width=500,height=500,left=50,top=50') 11 ) ;

However, to make this work we need to add a JavaScript function to our HTML file. Now go into
the publish settings and uncheck the HTML option so that you don't overwrite this function later
on. Then open up the administrator. html file and add the following JavaScript between the
<head> </head> tags:

<script language="JavaScript">
function launch(url, title, settings) {
window.open(url, title, settings);

</script>

This function takes three parameters and will open up a new window based on the settings in
the on (release) function inside Flash

Add Item Button

1. We need to add a script to the Add Item button to send the information to the server:

on(release){
gSaveitem.itemName = itemName;
gSaveitem.itemPrice = itemPrice;
gSaveitem.itemAbout = itemAbout;
gSaveitem.itemCategory = itemCategory.getSelecteditem() .data;
gSaveitem.itemimage = itemimage.getSelecteditem() .data;
Case Study 2: e-Commerce Site

gSaveitem.itemCount = itemCount.getSelecteditem() .data;


gSaveitem.sendAndLoad("adminSaveitem.php", gSaveitem, "POST");
gotoAndPlay ( "saveitemLoad") ;

You might have discovered by now that I haven't implemented


too many checks. Like the previous page button script, there are
no checks to see whether the user has entered anything. By now,
you should have an extensive knowledge, and can figure this out
by yourselt

2. The next thing to do is to check for the result from the server in the saveitemTest frame:

if(gSaveitem.loaded) {
gotoAndPlay ( "saveitemEnd") ;
}else{
gotoAndPlay("saveitemLoad");

3. Finally in the saveitemEnd frame:

if(gSaveitem.status == "ok"){
outputArea = "The item was inserted.";
}else{
_root.gErrorString = gSaveitem.error;
gotoAndPlay("error", 1);

stop();

Now you should also have the capability to add an item to your newly created categories. Next
we are going to look at editing the items.

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

Scene: editltem

Whenever there is something entered into the database, it's inevitable that something could go
wrong. We need to provide a facility to edit any item we have inserted. This would mean that
any aspect of the item has to be editable, including the image and parent category it belongs in.

administrator.fla
Case Study 2: e-Commerce Site

As you can see, the main timeline only consists of three elements. The drop-down component
in the top right corner is where we will load in all our categories initially. Next the MC
underneath that will load the items from the category selected in the drop-down box. Finally
there is the MC in the larger, left, part of the screen, this will be targeted from the second drop-
down box, and will give us editing capabilities.

1. But first for the main timeline, head over to editCatStart. The first thing we need to do
is to load in a fresh list of all the categories in the database to populate the drop-down
list, so attach the following to editCatStart:

_global.gEditCatCategories = new LoadVars();


_global.gFetchitems = new LoadVars();
_global.gDeleteitem =new LoadVars();
_global.gSaveitem =new LoadVars();

gEditCatCategories.load("adminGetCategory.php");
gotoAndPlay ( "editCatLoad") ;

2. No magic here; let's move right on and check for the return from the server in the frame
editCatTest:

if(gEditCatCategories.loaded){
gotoAndPlay ( "editCatEnd") ;
}else{
gotoAndPlay ( "editCatLoad") ;

3. And finally in the frame editCatEnd we need to populate the drop-down component we
have set up:

if(gEditCatCategories.status == "ok"){
for(i = 0; i < gEditCatCategories.catCount; i++){
_root.categories.additem(gEditCatCategories["catName"+i] 1

gEditCatCategories["catid"+i]);

stop();
}else{
_root.gErrorString gEditCatCategories.error;
gotoAndStop ("error" 1 1) ;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

When we get a positive return from the server we add all the categories with their ID as
data into the categories component.

4. We will now use this to target the edititemMC instance named items underneath it; but
we need a way to target it. Attach the following code to the Fetch items button:

on(press, release){
gFetchitems.load("adminFetchitems.php?parent=" +
_root.categories.getSelecteditem() .data);
_root . i terns . gotoAndPlay ( "i terns Load" ) ;

Here we get the parent ID by getting the selected item's data, then proceed to load in the
adminFetchitems .php script, which will be used inside the items MC.

5. Double-click on the items MC and have a look around. Inside the MC you'll see that the
first frame is in a dormant state, waiting for the user to select an item from the items
component and click the Fetch items button. When the user clicks it, we play ahead to the
itemsLoad and check for the return from the server in itemsTest:

if(gFetchitems.loaded){
gotoAndPlay ( "i terns End" ) ;
}else{
gotoAndPlay ( "i terns Load" ) ;

6. Finally we go over the result and populate the component with the following piece of code
in itemsEnd:

if(gFetchitems.status == "ok"){
for(i = 0; i < gFetchitems.itemCount; i++){
_root.items.itemBox.additem(gFetchitems["itemName"+i],
gFetchitems["itemid"+i]);
}
stop(};
}else{
_root.gErrorString gFetchitems.error;
gotoAndStop ("error", 1)
Case Study 2: e-Commerce Site

Again, this should stop the play head and wait for another selection; this time it's time to edit
the selected item when the user clicks the Edit item button, which has the following action
attached to it:

on(press, release){
gFetchitems.sendAndLoad("adminFetchitem.php?id=" +
_root. i terns. i temBox. getSelecteditem () . data, gFetchitems, "GET") ;
_root.edititemMC.gotoAndPlay(2);

This time we target the edititemMC placed in the left part of the screen; this is where the actual
action will take place. Double-click it and have a look at the timeline, it's quite long: it has 12
target frames, instead of the normal four we have been using.
Advanced PHP for Flash

This MC will encapsulate all the actions you can do on an item: edit all aspects of it and delete
it. At first it is in a dormant state, waiting for the drop-down component to be selected in the
right part of the screen. When the Edit item button is clicked on the right side of the screen we
go ahead and play from the second frame in this MC.

1. We first reach the editlteminit frame. We already have a LoadVars () object with all
the categories in it, but we also need all the images we have uploaded to the server, so
attach the following to the edititeminit frame:

gimage =new LoadVars();


gimage .load ( "adminGetimages .php");
gotoAndPlay ( "edititemLoad");

2. We then go ahead and check for the return from both the gimage and the gFetchitems
object we loaded from the above button in edititemTest:
if(gFetchitems.loaded && gimage.loadedl{
gotoAndPlay("edititemEnd");
}else{
gotoAndPlay ( "edititemLoad") ;

Finally we head over to edititemEnd and parse out the result from the server:

3. Check the status and assign the values of the item into the textboxes on the stage.

if(gFetchitems.status == "ok" && gimage.status == "ok"l{


itemName = gFetchitems.itemName;
itemAbout gFetchitems.itemDescription;
itemPrice = gFetchitems.itemPrice;
itemCount = gFetchitems.itemCount;
itemid = gFetchitems.itemid;

4. We could not have gotten here without gEditCatCategories, so this time we use it to
fill up the box with all our categories.

for(i = 0; i < gEditCatCategories.catCount; i++l{


_root.edititemMC.itemCategory.additem(gEditCatCategories["catName"+i],
gEditCatCategories["catid"+i]);
Case Study 2: e-Commerce Site

5. For each time around the loop we test if the current category ID from the server matches
the item's parent field. If it does we set the selected item in the drop-down box to the
current category. This way we know that when we go ahead and save the item, and if the
administrator didn't change the parent category, the item will stay in the original category.

if(gEditCatCategories[ 11 catid 11 +i] == gFetchitems.itemParent){


_root.edititemMC.itemCategory.setSelectedindex(i) ;

6. Then we loop through the images and their paths and fill the drop-down box. We use the
same technique here: we test for the item's image name and pre-select that image for the
item so that we maintain the state of the item when we save it.
for(i = 0; i < gimage.imageCount; i++){
_root.edititemMC.itemimage.additem(gimage[ 11 imageName 11 +i] 1

gimage[ 11 imagePath 11 +i]);


if(gimage[ 11 imagePath 11 +i] == gFetchitems.itemimage){
_root.edititemMC.itemimage.setSelectedindex(i);

stop();
}else{
_root.gErrorString gFetchitems.error;
gotoAndStop ( 11 error 11 1 1) ;

Preview Image button


As previously, there is a "Preview Image" button for the administrator to use in case they forgot
what the picture looked like. It has the same code as before:

on(release){
getURL ( 11 j avascript: launch ( 1 adminPreviewimage. php? image=" +
i temimage. getSelecteditem () . data +11 1 1 1 ImagePreview 1 1
1 resizable width=500 height=500
1 1 1 left=50 1 tOp=50 1 ) " ) ;

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

Update item button

By now the administrator should be able to fiddle around with the item's setting, its parent
category, image, and all the rest. We can now do two things with this item. either update it or
delete it. Let's first be non-destructive and look at the actions that take place when the user hits
the Update item button.

1. On that button apply the following piece of code:

on(release) {
gSaveitem.itemName = itemName;
gSaveitem.itemParent = itemCategory.getSelecteditem() .data;
gSaveitem.itemDescription = itemAbout;
gSaveitem.itemimage itemimage.getSelecteditem() .data;
gSaveitem.itemPrice = itemPrice;
gSaveitem.itemCount = itemCount;
gSaveitem.itemid = itemid;
gSaveitem.sendAndLoad("adminUpdateitem.php", gSaveitem, "POST");
gotoAndPlay ( "editSaveLoad") ;

There shouldn't be a mystery about what's going on here (I do have to say that the drop-
down box getSelecteditem () . data is a time saver deluxe!).

2. Anyway: the play head moves on and we do the (sometimes tedious, but always necessary)
check for return from the server in frame editSaveTest:

if(gSaveitem.loaded){
gotoAndPlay ( "edi tSaveEnd" ) ;
}else{
gotoAndPlay ( "edi tSaveLoad") ;

3. When the server returns an answer we apply the following to editsaveEnd:

if(gSaveitem.status == "ok"){
Case Study 2: e-Commerce Site

outputArea = "The item was updated.";


}else{
_root.gErrorString = gSaveitem.error;
gotoAndPlay("error", 1);

_root.items.gotoAndStop("itemsStart");
stop();

Not only do we tell the user that everything was successful, but we also send the play head of
the items MC in the right part of the screen to the start frame and stop it there. Why? Well,
when we edit the item we might have changed the parent category, so we need to get a fresh
list from the server to place the item into its correct parent category the next time we select
from the category list.

Delete button

Anyway, we need to be able to take this item out of our database. This task is quite easy and is
not a problem to implement, but as I said earlier; always cover your back and ask the
administrator if they really want to delete the item.

1. So, head back to edititemEnd and attach the following to the Delete button:

on(release) {
gotoAndStop ( "confi:rnlDelete") ;

2. Then move on to the frame mentioned, play around with the warning given there (don't
be too harsh on them, but do give them a warning).

3. The Delete button now needs a different action:

on(release){
gDeleteitem.load ( "adminDeleteitem.php?id=" + itemid) ;
gotoAndPlay ( "confirmLoad") ;

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

4. We then have to make sure that the server responded in frame confimTest:

if(gDeleteitem.loaded) {
gotoAndPlay ( "confirmEnd") ;
}else{
gotoAndPlay ( "conf irmLoad" ) ;

If you haven't thought about it before, stop and think about the
amount of code we write to make sure that the user does what
we want to, or test for anything to return from the server, or test
for any errors that occur. Also, take a look back at the PHP code
we wrote and the number of tests that had to be caught and
warned about. Coding is not only about coming up with the good
stuff (even though we all want to just do that), it's also about
making sure that the user never sees anything that resembles a
glitch in the program.

5. Back in the time line it's time to check for what the server responded with. confirmEnd
should have the following action to make sure anything is covered:

if(gDeleteitem.status == "ok"){
outputArea = "Item was deleted";
}else{
_root.gErrorString = gDeleteitem.error;
gotoAndPlay("error", 1);

with(_root) {
gotoAndPlay ( "edi tCatStart") ;

stop();

When we have deleted an item we send the play head to the start of the edititems scene to
make sure that we have everything freshly sent back to us from the server.
Case Study 2: e-Commerce Site

Scene: upload
Welcome to the easiest scene so far, except for the "main" scene that is. In the previous PHP
section we created an upload script that we'll use to upload images to the server, all you need
is to add the following script to the Upload image button:

on(release) {
getURL ( 11 j avascript: launch ( 1 adrninUpload. php 1 1 1 upload 1 1
1 resizable width=500 height=150
1 1 1 left=50 1 tOp=50 1 ) 11 ) ;

Scene: report
Again, this scene is not big; it consists of only a brief text and a button to open up a window
with the adrninPDF. php file we created earlier. The button utilizes the same JavaScript function
as in the upload scene:

on(release) {
getURL ( 11 j avascript: launch ( 1 adrninPDF. php 1 1 1 upload 1 1
1 resizable width=200
1 1 height=100 1 left=50 1 top=50 1 ) 11 ) ;

Scene: error
The final scene we are going to look at is the error screen where all the errors from the server
will be redirected. If you look back you'll see that we set _root. gErrorString to whatever the
error reported back was, so here we have a dynamic text field named gErrorString, so that
the message will be displayed automatically.

No code, display the message and hopefully this scene will never be played! But, of course, that
would be in a perfect world! Take one of the PHP scripts you created earlier and change it so that
it creates an error: take a file and change anything that MySQL will complain about. Load up the
movie in your browser and you should see that we automatically get redirected to this screen.

During development it's recommended that you have SHOW_MYSQL_ERRORS set to true in
settings. inc .php, that way you will see just what MySQL complains about if you have typed
something wrong. This is one of the disadvantages to working with Flash and backend scripting;
you have to pull up all information that normally would be displayed in a browser and manually
display it. By setting a flag to say that you want to show any MySQL errors generated, you save
a lot of time during development on debugging, and when its time to make the site go live all
you have to do is to flag it back to false.

' 0
1 rn CJ cJ

;\~LC L
Dec~ e
Advanced PHP for Flash

Wrap up
This entire Flash movie is targeted to be in a pop-up window with no buttons or scrollbar. So,
make a new file called adminFrame. html and write the following in it:

<frameset rows="lOO%,*" border="O" frameborder="O" framespacing ="0">


<frame src="administrator.html" marginwidth="O" marginheight="O"
noresize scrolling="no">
<frame src="blank.html" noresize scrolling="no">
</frameset>

In addition you need a blank page called blank.html; then proceed to make a popup.html
and write the following script in it:

<script language="JavaScript">
function launch(url, title)
window.open(url, title,
"resizable,width=580,height=465,left=50,top=50");

</script>
<a href="javascript:launch(adminFramehtml', 'admin');">admin</a>

If everything has gone well you should now have a fully functioning administrator page that does
all that we set out to do. Hopefully you have managed to follow the structure I have used thus
far, and you have a clear view of what an administrator movie in Flash needs to function
correctly. Maybe you are fed up with all the error checking and retyping of the checks for every
scene, but it's necessary to make the use of the interface as smooth as possible (and make our
clients as happy as possible!).

Here are a few things you might want to include to make your site even better:

An addAdmin scene to add administrators (with different administrator levels).

A forgotPassword scene in case the administrator forgets their password. Since we use
MD5 () to store the password, you would need to generate a new password with the
newPassword () function I showed you earlier.

Sub categories.

Well, that was a bit of a marathon session; why not put your feet up and take a break before we
head on to develop the client interface?
Case Study 2: e-Commerce Site

The client interface


We have now ventured through the administrator backend and interface. How is it going? Ready
for another session with code? OK, good, we'll now look into the client interface for our e-
commerce site.

When developing an interface for any users it's important that you, as a developer and a (long
time) user of various websites, draw upon your own experience. Think about the impact that these
sites have had on you when you start developing an e-commerce site. We have to have a clear
navigation that even your grandparents could understand. The number of clicks from one end of
the site to the other should be kept to a minimum and more importantly we have to give the user
what they want! A lot of sites utilize the newest and most funky interfaces that are supposed to
give the user a wonderful experience; this might be a good showcase for you as a developer, but
coming from a multimedia/coding background, I too often see violations of common user
interface design principles. Be aware, don't fall into that trap, but keep your site streamlined to
what you want to achieve; in our case it is to sell items from the MyCompany website.

Enough about that; but keep these points in mind when you start to develop this site further
than we can cover in this book!

Now, what are we going to cover in this section? We will build up the client interface for our
website. First, a reminder, and a confession, before we start: I do come (mainly) from a coding
background. The interface might not be as slick and clean as you want it to be, but I leave that
up to you when we are finished concentrating on what we are here for: integrating Flash with PHP.

The database we are using is the same as the one we used previously to build up the
administrator page, so let's not dwell on that. Instead, let's first have a look through the PHP files
used for this section, then build up the interface with the results from those files. If you need
some rest, do it now! Make another pot of coffee and run one time around the house, settle
down, and let's start!

PHP
Before we start on developing the scripts that will drive the client interface we need to take a
quick overview of what we want to achieve with it. If we look at the database we developed, and
filled, there are two main things we need to focus on for a start: the categories and the items
belonging to each of them. Any e-commerce site needs a clear structure for the customer to
navigate around in; we will have a look at this when we come to building it, but we need to be

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

aware of this now and clearly separate the scripts for the ease of integration later on. We could
have loaded the entire database structure in one go and worked with that inside Flash, but that
is not a desirable way to go when you start thinking about scaling your site and the ease of
integration and maintainability, which should always be on your mind when you start developing
something like we are here.

Before you go on and read about the files we are developing in this case, sit down and structure
out the files on a piece of paper: what do we need to fetch from the database, how would you
structure the files to consider scalability and ease of maintenance, how would you link the
different scripts together? You might be thinking that this is not necessary because there are only
a couple of tables with items and categories, but think again: after you are finished with this
chapter you will probably want to expand the site and add several extra tables that will
accommodate the extra features you want. These then have to be tied together with the files you
already have created, and by looking ahead you will save yourself a lot of issues down the road.

If you have had a look at how you would structure your scripts, lets have a look at how I did it: I
made up the files that will pull information on items and categories; these are divided into three
scripts: I started with categories. php, this will get all the categories from the database, the
results from this will again call up a categoryOverview. php file that will fetch all the items
belonging to that category, and this will again feed the item.php script to get information on one
item. With this I have a hierarchical structure where each piece builds on another's information.

Now: let's see what we will develop in this section:

random6.php
When the user first loads the movie we want to present six random items from the
database. This way we achieve a dynamic rather than static feeling.

item.php
item.php will give us all the information that we have stored in the table on an item. This
is the only script that feeds Flash with a total overview of an item; that way we can expand
it later on to accommodate future needs.

categories.php
categories .php will stand at the top of our hierarchical structure and will feed Flash
with all the categories available.
Case Study 2: e-Commerce Site

categoryOverview.php
categoryOvervew .php will stand between categories .php and item.php to give an
intermediate and small amount of information on all items belonging in each category.

signUp.php
A feature we will deploy is to require all customers to sign up before they can add anything
into the basket. this file will give us the ability to have the user sign up for and account
before they can proceed.

login.php
After a sign up we also need to accommodate a log in feature, so this will provide us with
the functionality to do just that.

We are also going to reuse the settings. inc .php and functions. inc .php files we created
earlier, so make sure to put the files we are now creating in the same directory as you used
previously. Hopefully you should by now have a structure in your mind of how we want to
achieve the client interface, so: lets get started with the PHP!

File: random6.php

When the user first arrives at our site we need to provide them with some items on the front
page to get them interested in some of our products. We could of course go with the six latest.
but we are going to pull in six randomly chosen items from the database, and present a button
to load in six new random items.

1. Include all the common files we are using:

include_once ("settings. inc .php");


include_once ("functions. inc .php");

2. Order by RAND () gets random items out of the table. Limit the query to six items to make
it fit the layout of our screen.

$query = "SELECT * FROM i tern ORDER BY RAND ( ) LIMIT 6" ;


$result= mysql_query($query);

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

3. We'll use $counter to append itemName, itemDescription, itemimage, and itemid


so we can loop through them inside Flash when we start presenting them.

$counter = 0;
i f ($result) {
echo 11 Status=ok 11 ;
while($item = mysql_fetch_array($result)){
echo 11 &itemName 11 $counter . 11 =11
'- urlencode ($item[ 11 item 11 ] ) ;
/** firstWords() : take a look in functions.inc.php */
echo 11 &itemDescription 11 $counter . 11 = 11
urlencode(firstWords($item[ 11 description 11 ] , 10));
echo 11 &itemimage 11 $counter . 11 = 11 $item[ 11 image 11 ] ;
echo 11 &itemid 11 $counter . 11 =11 $item[ 11 ID 11 ] ;
$counter++;

}else{

4. Make sure to catch any errors:

fail( 11 There was an error getting the items, please try again
later. 11 , mysql_error() ) ;

File: item.php

When the user has pressed the More button either on the front page, in the category overview,
or the basket we need to get the all the information about the product back into Flash.

1. Include the common files. (I told you earlier that this would be a repetitive task!)

include_once( 11 settings.inc.php 11 ) ;
include_once( 11 functions.inc.php 11 ) ;
$query = 11 SELEcr * FROM i tern WHERE ID Ill
$-GET [ I id I ]
II I II
I

$result= mysql_query($query);
Case Study 2: e-Commerce Site

2. Make sure we got a result back from MySQL and print out the information on the item.

if ($result) {
$item= mysql_fetch_array($result);
echo "query=ok" ;
echo "&itemName=" . $item["item"];
echo "&itemDescription=" . urlencode($item["description"]);
echo "&i temPrice=" . $i tern ["price"] ;
echo "&itemSize=" . $item["size"];
echo "&itemimage=" . $item["image"];
echo "&itemCount=" . $item["count"];
echo "&itemDbNumber=" . $item["ID"];
echo "&query=finished";
}else{
fail("There was an error getting the item, please try again
later. " , mysql_error() ) ;
}

File: categories.php

The categories .php script will be used to pull all the categories into Flash. We will then use
the information collected to call the items. php script with catid as a parameter to get all the
items that have that particular parent ID.

1. Include the common files:

include_once("settings.inc.php");
include_once("functions.inc.php");

2. Query the category table for all the entries. I ordered this with the newest created
category first (always easier to look at what we created last inside Flash). You can easily
change this to ORDER BY name to get the names in right order if you prefer that.

$query = "SELECT * FROM category ORDER BY ID DESC";


$result = mysql_query($query);
if($result) {
$i = 0;

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

3. You've seen this before; loop through the results from MySQL and print out a formatted
string to ease the parsing when we load it into Flash.

echo "categories=loaded";
while($cat = mysql_fetch_array($result)){
echo "&catName" . $i "=" . $cat["name"];
echo "&catid" . $i . "=" . $cat["ID"];
$i++;

4. catCount will be used to loop through the results back inside Flash:

echo "&catCount=" . $i;


}else{
fail("There was an error getting the categories, please try
again later. " , mysql_error() ) ;

If you browse to this script you'll see a format like this: &catNameO=PHP&catidO=B. that will say
that we have a PHP category with a unique ID of 8.

File: categoryOverview.php

When the user has clicked the category we just pulled in with the previous script, we need to
present the items in that category to the user. We will also do another trick: inside Flash there is
a global variable keeping track of the current category clicked on, but when we come to the
category overview there is no category clicked. We then call this script with no ?id= at the end
of the URL. This will get the latest category into Flash so that when the user comes to the
category overview theywill see the items belonging to the latest category entered by the
administrator instead of giving them a message to click on a category to pull in anything.

1. Include the common files:

include_once ("settings .inc.php");


include_once("functions.inc.php");
Case Study 2: e-Commerce Site

2. Flash did not request a particular ID from the script. We have to first query the database
to get the latest category entered, and then proceed to get that category's ID and use that
to query the item table for the corresponding items.

if(!isset($_GET[ id 1 1 ] )) {

$catQuery = "SELECT * FROM category ORDER BY ID DESC LIMIT 1";


$catResult = rnysql_query($catQuery);
if($catResult) {
$cat= mysql_fetch_array($catResult);
$query = "SELECT * FROM item WHERE parent 1 " $cat ["ID"]
... II I ORDER BY ID DESC";
}else{
fail("There was an error getting the categories.",
mysql_error() ) ;

}else{

3. If an ID is requested, get the items that have id as a parent:

$query= "SELECT* FROM item WHERE parent= 1 " $-GET [ I id I l


. . II I ORDER BY ID DESC";

$result= mysql_query($query);
if($result) {
$i = 0;
echo "query=ok" ;

4. This should be fairly standard to you now. We loop through the results from MySQL and
use a counter, $i, to append the itemName, itemDescription, and itemid so that we
can loop through the results back in Flash and present them nicely to the user. Here we
use the first Word () function developed earlier to get only the first 10 words of the
item's description back into Flash:

while($cat = mysql_fetch_array($resultll{
echo "&itemName" . $i . "=" . $cat["item"];
echo "&itemDescription" . $i . "="

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

urlencode (firstWords ($cat ["description"], 10));


echo "&itemid" . $i . "=" . $cat["ID"];
$i++;

echo "&itemCount=" . $i;


}else{
fail ("There was an error getting the items.", mysql_error ());

File: signUp.php

A shopping site (or any site) is nothing without its users. Our users in particular will have to sign
up and supply a username and password to be able to do anything with the basket we are
making. So; let's start collecting a name, username, password, and email address.

1. Start by including the common files:

include_once ("settings. inc .php");


include_once ("functions. inc .php");

2. Test that the two supplied passwords are identical. We could of course do this inside Flash,
but hey; this is a PHP book!

if($_POST['userPassword'] != $_POST['userPassword2']){
fail ("The passwords you supplied did not match, please try
again.");
exit;

3. Here we are checking the validity of the email address's structure, if this fails we have to
give the user a prompt that it's not a valid email address.

if(!checkEmail($_POST['userEmail'])){
fail ("The email supplied was not correctly formatted, please try
again.");
exit;
Case Study 2: e-Commerce Site

4. Now we need to check that the username has not been taken (people can have the same
name, but the username has to be unique).

$userNameQuery = "SELECT * FROM customers WHERE userName Ill

$_POST [ 1 userUserName 1 ] " 1 " ;


$userNameResult = mysql_query($userNameQuery);
if($userNameResult) {

5. If the username is taken, MySQL returns a row:

if(mysql_num_rows($userNameResult) > 0){


fail ("The username chosen is busy, please try again with a
different one. ") ;
exit;

$password= md5($_POST[ 1 userPassword 1 ] ) ;

6. Time to insert the user:

$insertQuery = "INSERT INTO customers (name, userName, password,


email) VALUES ( 1 " . $_POST[ 1 userName 1 ] 111 , 111
$_POST [ 1 userUserName 1 ] " 1 , 1 " $password . " 1 Ill

$_POST [ 1 userEmail 1 ] " 1 ) " ;

$insertResult = mysql_query($insertQuery);
if($insertResult){
echo "status=ok";
}else{

7. And finally, warn the users about errors:

fail("There was an error inserting your new account, please


try again later. " , mysql_error () ) ;

}else{
fail("There was an error with the database, please try again
later.", mysql_error ());

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

File: login.php

After the user has successfully signed up, they need to be able to log into the site to actually use
it, so here is the script for logging in a person:

1. Include the common files.

include_once("settings.inc.php");
include_once("functions.inc.php");

2. Make sure that we do an MDS () sum of the password supplied since that is the format we
stored the password in the first place.

$password= md5($_GET[ userPassword


1 1 ]);

$query = "SELECT * FROM customers WHERE username = 1 "

$_GET [ 1 userName 1 ] " 1 AND password = 1 " $password . II T 11.


I

$result= mysql_query($query);
if($result) {

3. If we get only one row back after querying a username and password, we can be sure that
the user is who they claim to be.

if(mysql_num_rows($result) 1){
echo "status=ok";
}else{
fail("Could not log you in, please try again.");

}else{
fail("There was an error with logging in, please try again
later.", mysql_error());

Wrap Up
Those were the files that will provide us with all the information we need to develop this
particular site. Before you go on, think about what can be done to expand this site before we
come to the integration: a "lost password" section could be good to incorporate, an email
Case Study 2: e-Commerce Site

feature that sends the order to both the administrator and the client, a PDF generator that would
print a bill to the user when they make the order.

There are unlimited possibilities with an e-commerce site like this, but this book does not have
unlimited space. So, take some time and write down what you would like to add into a future
expansion of your web site and bear it in mind when you start developing the interface; that way
you can save yourself some time when you are expanding later on.

Interface
Well, we have now covered the client setup and you should have a fully working administrator
page. I assume that you have played with it and gotten familiar with its function and what we are
doing. I also assume that you have at least six items in your items table: who would set up a shop
with less than six items? The reason for this number will come up later.

We will use a lot of the same styles as in the administrator part, but there will be some slight
modifications. so, open up e-commerce-noCode. fla, and let's get started!

Scene: preloader

As with the administrator interface, we don't extend the preloader much. The final SWF is again
quite small, so the amount to download is minimal. But we do set up a Basket object to keep
track of what the user enters into the basket, so go to the second frame of the actions layer and
enter the following code.

1. First check if we have finished loading in the movie:

if (~root.getBytesLoaded() == _root.getBytesTotal())

2. Since we have loaded in the entire movie it's time to set up some common elements that
we will use throughout the movie. loggedin will (surprisingly) keep track of whether the
user is logged in or not. gCategoriesLoaded will be used to keep track of whether we
have loaded the categories, and hence not load them in again. gCurrentCategory will
keep track of what category we want to display in the overview section and
gCurrentitemid keeps track of the item we display in the item scene.

' 0
1 rn CJ cJ

;\~LC L
Dec~ e
Advanced PHP for Flash

_root.loggedin = false;
_root.gCategoriesLoaded = false;
_root.gCurrentCategory = -1;
_root.gCurrentitemid = -1;

_global.gCategories =new LoadVars();

3. As stated earlier, we are going to use a Basket object to keep track of what the user has
added to the shopping cart. This will store the name, price, size, unique ID table reference,
and image path assigned to it.

function Basket(){
this.sum = 0;
this.items =new Array();

4. We need a function to add an item to the basket. This will add the item to the basket and
add its sum to the total sum so we can display it.

Basket.prototype.insertitem = function(name, price, size, dbNumber,


image) {
temp= new Array(name, price, size, dbNumber, image);
II add the new item to the end of the array:
this.items.push(temp);
II Add the price to the total sum.
this.sum += price;

5. We also need a function to remove an item from the basket. This will subtract the item's
sum from the total sum and remove the item from the array that we use to hold the items.

Basket.prototype.removeitem = function(number){
II Subtract the items's price from the total.
this.sum -= this.items[number] [1];
II Remove the item from the array.
II splice(start, numberOfitemsToDelete);
this.items.splice(number, 1);
Case Study 2: e-Commerce Site

6. Create a new object to keep track of the items and proceed to the main scene:

_root.basket =new Basket();


gotoAndPlay("main", 1);
}else{

7. Return to the first frame. You can of course build up a prettier preloader that will give
some feedback on percentage loaded or an animation, but I'll leave that up to you.

II go back to frame 1 and check the loading status.


gotoAndPlay (1) ;

Scene: main

As you can see in the following image,


i1e-commetct.fla
there are two main sections for this
scene: a greeting on the right side and
some items on the left. The greeting is
hard coded, but there should be no
problem for you by now to make this an '
extra table and load it in when the user
first arrives at the site. Another thing
you could add in the right side is a news
section with maybe the 10 latest news
items from a database, but remember
to add such a feature to the
administrator interface as well!

You can see that I've placed six instances of the itemShortMC on the stage and lined them up.

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

Again, you can use the duplicateMovieClip () function to achieve


the same, but as Isaid earlier, this is a matter of style and preferences.

1. Let's start up by going to the first frame in the actions layer and attaching the following script:

if(_root.loggedin) {
_root.loginStatus "You are logged in";
}else{
_root.loginStatus Till.

'

_global.random6 = new loadVars();


random6 . load ( "random6 . php" ) ;
goto.AndPlay ( "randomLoad") ;

This will load in six randomly generated items from the database for us to work with when
we get a bit further down.

2. Next we need the ever so recognizable test script in the frame randomLoadTest:

if(random6.loaded) {
goto.AndPlay ( "randomEnd" ) ;
}else{
gotoAndPlay ( "randomLoad") ;

3. Finally we need to do something with the result we got back in theframe randomEnd. We
assume that there are at least six items in the database by now. We loop through the result
set from the server and add the correct values to each itemShortMC instance we have on
screen:

if(gRandom6.status == "ok") {
for(i = 0; i < 6; i++){
_root["item"+i] .description= "<b>" + gRandom6["itemName"+i] +
"</b> : " + gRandom6 ["itemDescription"+i];
_root["item"+il .Id = gRandom6["itemid"+i];
Case Study 2: e-Commerce Site

loadMovie(gRandom6[ 11 itemimage 11 +i],


eval ( 11 _root.item 11 +i+ 11 .imageHolder 11 ) ) ;

stop();
}else{
_root.gErrorString random6.error;
gotoAndPlay( error
11 11 , 1);

4. But to actually be able to do something with the item we need to double-click one of the
itemShortMC instances and apply some action to the More button within it:

on (release) {
with(_root){
gCurrentitemiD = this.Id;
gotoAndPlay ( itemStart 11 )
11 ;

We are using the gCurrentitemid to keep track of which item we want to show up when
the play head comes to the item scene, so keep that in mind until we get there.

5. As you could see earlier, we loaded an image into an imageHolder MC to get a preview
of the image before we went to the actual item itself. This image has to be scaled down
to fit in the small place we have available. The problem we run into here is that we don't
know how big this image is and we can end up loading in 1OOKB just to get a SOxSO
thumbnail. This is not an ideal situation, but I'll get into a solution for that problem a bit
later on. For now you need to apply the following script to the imageHolder MC to make
it scale down:

onClipEvent (data) {
setProperty( 11 " , _width, 50);
set Property ( 1111 , _height, 50) ;

6. Now go back to the root of the main scene and have a look at the bottom of the screen:
I've placed a button there to load in six new random items from the database. We use this

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PHP for Flash

to make the experience a bit more interesting on the front page. All we need to make this
work is to apply the following action to the button:

on(release){
gotoAndPlay(l);

That's it for the main scene; the main menu that follows throughout the movie has already been
made (no need to repeat that for all the scenes!).

Scene: category

Now, let's have a look at the category overview. Again, this consists of two parts: a right side with
all the categories in a menu and a left side with all the items belonging to each category.

'eo e ,.,_ e-commerce.fla


T Timellne

~actions; .. . o \ :: :s::::olb:1?::: .1 ~ :: :zo'


.-.1!1
0 Q
25 ..
CalegOJiesLoacf][~l" categorieslefl{: ,.
p 3~ ' :::4?::: ~~ : :::s?::: ~
c:a.t e-gori~!ii End

~
0 0
[p left 1!1 D
[V loader
[V title .. 1!1..
0
0 ol. 0 D

7J .
0 0
~UUte:mi 0

. . ..
0 D
11>,- Lltop ':'
... Lli>ackground 0 f.
_tv+)jJ_ ttl I ii!Q [) 30 I Z.O Ips Z.4s I ~ -~~., ~
~"

I Ej category
I~ 41 f73Xl 0
Case Study 2: e-Commerce Site

If you remember from the PHP scripts that we made earlier, you know that we load in the
categories in the right menu with the newest category at the top, and that we load in the items
from the same category when we don't pass the script a parameter. That way we end up with the
items from the category at the top on the left side. That way we have a natural mapping of our
menu-item relationship. Remember that if you changed the order of the categories we load, you
would also want to change which items you load in when the script is not passed a parameter.

Let's do the right side first.

1. ln the first frame we'll load in the categories available, so apply the following code to it:

gCategories =new LoadVars();


gCategories.sendAndLoad("categories.php", gCategories, "GET");
gotoAndPlay ( "categoriesLoad") ;

2. Head over to categoriesTest and attach the check code that we know so well:

if(gCategories.loaded){
gotoAndPlay ( "categoriesEnd") ;
}else{
gotoAndPlay ( "categoriesLoad") ;

3. Finally do the check and parsing of the result we get back from the server in frame
categoriesEnd. Test that we got a positive result from the server:

if(gCategories.status == "ok"){

4. When we get the categories back from the server we don't know how many will go on to
the display, so first hide all the MCs:

for(i = 0; i < 10; i++) {


_root["cat"+i] ._visible false;;

5. Proceed to loop through the result set and attach the name and ID to the MCs on stage.
If you look over the code for this frame you'll notice that there is no previous or next page

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

for the categories. Relax, I haven't forgotten it, but go back to the identical script we wrote
in the administrator section and apply it to this menu. (Or can you do it by memory?)

for(i = 0; i < gCategories.catCount; i++){


_root[ 11 cat 11 +i] ._visible = true;
_root [ 11 cat 11 +i] .name = 11 11 + gCategories [ 11 catName 11 +i];
_root[ 11 cat 11 +i] .ID = gCategories[ 11 catid 11 +i];

stop();
}else{

6. Something happened, so send the user to the error scene and give them the bad news:

_root.gErrorString = gCategories.error;
gotoAndPlay( 11 error 11 , 1);

That should get the categories we made in the administrator section and display them each
in one button. Take the code I told you to apply to this as an exercise on how much you
have picked up by now.

7. But we can't do anything with the information we just assigned without adding some
actions to the buttons we targeted. Each button is in fact a MC with a button and a
dynamic text field where the name of the category goes, so double-click one of the
buttons on the left side and attach the following code to the button:

on(release){
_root.gCurrentCategory = this.ID;
_root.overviewMC.gotoAndPlay( 11 overviewStart 11 ) ;
Case Study 2: e-Commerce Site

But to have something useful come out of this menu we need to get the items that have the
same parent ID as the category's ID. If you head over to the left part of the screen you'll see
instances of the categoryOverviewMC. Double-click this to get inside it; it should look
something like this:

When the user first comes to this scene, we need to display something for them. We could go
with a "Please select a category from the screen", but we'll use the gCurrentCategory variable
we created in the preloader to decide on what we are loading in. So in the first frame attach the
following script:

1. We need a new LoadVars ( ) object to load the overview.

gOverview =new LoadVars();


Advanced PHP for Flash

2. Remember that we set gCurrentcategory to -1. When the user first comes here we'll
load in the categoryOverview .php script without an ID attached to it. If you also
remember from that script that when we don't send an ID to the script, we load in the
overview of the items in the newest created category. (This will correspond to the fact that
we load in the newest category first and will be at the top with its items displayed in the
left part of the screen.)

if(_root.gCurrentCategory == -1){
gOverview. load ( 11 categoryOverview. php 11 ) ;

}else{

3. If we have clicked on a category button in the menu we will have a gCurrentCategory


not being -1.

g0verview.load( 11 category0verview.php?id= 11 +
_root.gCurrentCategory);

4. Reset the gCurrentCategory back to -1 so that if the user clicks the category button
one more time they will get the initial screen again.

_root.gCurrentCategory = -1;
_root.gCurrentOverviewPage = 1;
gotoAndPlay ( 11 overviewLoad 11 ) ;

5. We can't go on without the check script, so go to overviewTest and attach the following script:

if(gOverview.loaded) {
gotoAndPlay ( 11 overviewEnd 11 ) ;

}else{
gotoAndPlay ( 11 0verviewLoad 11 ) ;

The MC we are inside now is named overviewMC, so that's what we have to target when we start
parsing the result from the server in the frame overviewEnd. There are seven instances of
itemShortMC that we also used earlier to show quick info on the item; these are named
consecutively itemo to item6.
Case Study 2: e-Commerce Site

1. Make sure that we got a positive result from the server.

if(gOverview.status == "ok"){

2. Make sure that all the overview MCs are hidden before we start to show them:

for(i = 0; i < 7; i++){


_root.overviewMC["item"+i]. visible = false;

_root.overviewMC.nextButton._visible = false;

3. Loop through the results from the server and add the correct information on each item
to the MCs on the screen.

for(i = 0; i < gOverview.itemCount; i++l{


_root.overviewMC["item"+i] ._visible = true;
_root.overviewMC["item"+i] .description = "<b>" +
gOverview["itemName"+i] + "</b> " +
gOverview ["itemDescription"+i];
_root.overviewMC["item"+i] .Id = gOverview["itemid"+i];

4. Inside the itemShortMC there is an imageHolder MC that we will target to load in the
image to show in the left side.

_root.overviewMC["item"+i] .imageHolder.loadMovie(gOverview["itemimage"+
i]) ;
}

5. If we have more than seven items it means that we have to show the Next page button so
the user can cycle through all the items we got in this category. We also set the previous page
button's _visible to false (there are no previous pages when we are on the first page).

if(gOverview.itemCount > 7){


root.overviewMC.nextButton. visible true;

_root.overviewMC.previousButton._visible false;

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

stop();
}else{
_root.gErrorString gOverview.error;
gotoAndPlay("error", 1);

Now, if there are more than seven items returned in a category we need to cycle through the
result to show them to the user. Did you do the little exercise concerning next and previous page
buttons for the category menu above? We'll not do the exercise this time, but show you again
how to accomplish this.

On the Next page button on the screen you need to apply the following code to walk through
the result:

1. Loop through the MCs and set their_visible to false.

on(release){
for(i = 0; i < 7; i++){
_root.overviewMC["item"+i]. visible false;

2. We use j to target the MCs and i to target the correct item in the result from the server.
As before, find out what the upper limit is for this page:

j = 0;
upperLimi t = 0;
if((_root.gCurrentOverviewPage * 7) + 7 < gOverview.itemCount){
upperLimit (_root.gCurrentOverviewPage * 7) + 7;
}else{
upperLimit gOverview.itemCount;

3. Time to loop over a maximum of seven times and assign the variables to the MC:

for(i = (_root.gCurrentOverviewPage * 7); i < upperLimit; i++){


_root.overviewMC["item"+j] ._visible = true;
_root.overviewMC["item"+j] .description = "<b>" +
Case Study 2: e-Commerce Site

gOVerview[ 11 itemName 11 +i] + 11 </b> 11 + gOVerview[ 11 itemDescription 11 +i];


_root.overviewMC[ 11 item 11 +j] .Id gOVerview[ 11 itemid 11 +i];
j++;

4. Add one page to the total so that we can proceed to the next page if there are more pages
in the result we have, and find out if we actually have enough items in the result to go to
a next page:

_root.gCurrentOVerviewPage++;
if(gOVerview.itemCount < (_root.gCurrentOVerviewPage * 7)){
root.overviewMC.nextButton. visible = false;

5. There is always a previous page if we have gone one page ahead:

_root.overviewMC.previousButton._visible = true;

6. Next we need to apply a script to the previous page button in case we have several pages.
I won't explain this script since we have gone through the build up of it before:

on(release) {
for(i = 0; i < 7; i++l{
_root.categoryOverviewMC[ 11 item 11 +i] ._visible false;

_root.gCurrentOVerviewPage--;
j = 0;
for(i = (_root.gCurrentOVerviewPage * 7) - 7; i <
(_root.gCurrentOVerviewPage * 7); i++l{
_root.categoryOverviewMC[ 11 item 11 +j] ._visible = true;
_root.categoryOverviewMC[ 11 item 11 +j] .description = 11 <b> 11 +
g0Verview[ 11 itemName 11 +i] + 11 </b> 11 + gOVerview[ 11 itemDescription 11 +i];
_root.categoryOverviewMC[ 11 item 11 +j] .Id = gOVerview[ 11 itemid 11 +i];
j++;

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

if(_root.gCurrentOverviewPage == 1){
_root.categoryOverviewMC.previousButton._visible false;

_root.categoryOverviewMC.nextButton._visible true;

The itemo to item6 MCs we've been targeting are the same as in the main scene, and we applied
the action to them there, so there is no need to change them since they should work now.

Scene: item

So far we have only looked at a brief overview of each item; now it's time to present the item
to the user with all the information we have about it in the database. Go to scene item, it looks
like this:
Case Study 2: e-Commerce Site

1. All the textboxes are set up, so let's go to frame iternStart and begin loading in the item:

gitem = new LoadVars();


gitem.load("item.php?id=" + _root.gCurrentitemid);
gotoAndPlay ( "i temLoad" ) ;

2. As you remember from scene main, we applied the following action to the iternShortMC
button, which we also used in scene category:

on (release) {
with (_root) {
gCurrentitemiD = this.Id;
gotoAndPlay("iternStart");

Now we are going to use the gCurrentitemid we set when the user clicks the button to
load the item of choice into the gitem object.

3. Before we can use this object we need the check script in frame itemTest:

if(gitem.loaded){
gotoAndPlay ( "itemEnd") ;
}else{
gotoAndPlay ( "i temLoad" ) ;

4. Finally in frame itemEnd, we assign the correct values to the text fields we have on the
screen and load in the corresponding image to the imageHolder MC we have at the right
part of the screen in layer right:

i f (gitem. status == "ok") {


header= "<b>" + gitem.itemName + "</b>";
description = gitem.itemDescription;
priceField = "Price : " + gitem. itemPrice;
count = "Number in stock : " + gitem.itemCount;
loadMovie(gitem.itemimage, "_root.ItemimageHolder");
outputArea ,
1111.

stop();

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
Advanced PH P for Flash

}else{
_root.gErrorString gitem.error;
gotoAndPlay("error", 1);

S. There is an issue with the images we load in; we never know how large they are. I'll come
back to this at the end of this chapter, but for now we'll attach a script to the
imageHolder MC that you'll find in the top right side of the movie to make sure it doesn't
go beyond the limits of our movie:

onClipEvent (data) {
if(this._width > 186){
w = this._width;
setProperty("", _width, 186);
set Property ( " " , _height, this . _height - (w - this . _width) ) ;

if(this._height > 253){


h = this._height;
set Property ("" , _height, 253) ;
setProperty( 1 1 , _width, this. width - (h - this._height));

It's not an extensive script; it just makes sure that we don't have an image that is only half
shown inside the movie.

6. The only thing left to do is add this item to the basket we created earlier. On the Add to
basket button in the lower right corner we need to attach the following:

on(release) {
if(_root.loggedin) {
price= new Number(gitem.itemPrice);
_root.basket.insertitem(gitem.itemName, price.valueOf(),
gitem.itemSize, gitem.itemDdNumber, gitem.itemimage);
gotoAndPlay("basket", 1);
}else{
outputArea = "Please Log in first!";
Case Study 2: e-Commerce Site

Here we use the loggedin variable defined in the preloader scene to make sure that you are
logged in before you can do anything. If the user is not logged in we just display a message to
them, otherwise we add one item to the basket and send the play head to the basket scene to
show the state of the current basket, which we will cover next.

Scene: basket

As you can see, there are only two frames that are used here, an initial frame to check if we have
anything in the basket and one that displays the items if there are any.

1. In the basketstar t frame we need to check if we have anything in the basket:


Advanced PHP for Flash

if(basket.items.length == 0){
_root.outputArea "There are no items in the basket.";
}else{
_root.outputArea ,
1111.

gotoAndPlay ( "basketEnd") ;

Then in frame basketEnd we loop through the basket and display the items for the user.

2. Hide all the MCs that hold the items:

for(i = 0; i < 8; i++){


_root["item"+i] ._visible false;

3. Loop through the length of the basket and assign the correct values to the MC. Of course,
we should have next page and previous page buttons here, but that should be no problem
for you to implement by now.

for(i = 0; i < _root.basket.items.length; i++){


_root["item"+i] ._visible = true;
_root["item"+i].name = "<b>" + _root.basket.items(i] [0] + "</b>
Price : " + _root .basket. items [i] [1] ;
_root["item"+i] .itemid = i;
_root["item"+i] .itemimage = _root.basket.items[i] [4]

_root.imageHolderText = "<center>Click on the <b>image</b> <br>button


to <br>display the Image here</center>";
root.totalSum = "Total sum : <b>" + root.basket.sum + "$</b>";

stop();

4. Now, you'll see that there are instances of the basketitemMC laid out on the screen; these
can either show the image corresponding to the item or delete the item from the basket.
Double-click one of them and attach the following code to the image button:

on(press) {
_root.imageHolderText = "Loading image";
_root.imageHolder.loadMovie(this.itemimage);
Case Study 2: e-Commerce Site

Since we assigned the image path to the instance, we can use it to display the image in a
large version on the right part of the screen.

We also want to delete the item, but we're not going to worry about making sure that the
user is absolutely sure since it's easy to go back and add the item to the basket again.

5. To delete the item we need the following action added to the Delete button:

on(release) {
with(_root) {
basket.removeitem(this.itemid);
gotoAndPlay ( "basketStart") ;

Here we go back to the start of the basket scene to make sure that we display a correct and
updated overview of the basket.

Now, you might be missing a button to actually send the order in to the administrators of the
site for processing. I have not included this here, but take that as an exercise; mail the current
order to the administrator and a confirmation to the customer. You could also provide a bill in
PDF format to the customer to print out. But this should be an easy job for you by now.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

Scene: signUp

When dealing with customers we need a place to let them sign up as a member, and we have to
collect the following from them: name, username, email address, and password.

e- commerce.fla
E TliiH!Iin<

Looking at the screen you can see that there are two password fields. We definitely need to make
sure that the user puts in the correct password when they sign up since we are going to MDS ()
it before we store it in the database.

1. So, let's start by adding some ActionScript to the signUpStart frame:

_root.signUpName = "";
_root.signUpUserName "". I

_root.signUpPassword 1111.
I
Case Study 2: e-Commerce Site

_root.signUpPassword2 = "";
_root.signUpErnail = "";
gSignUp =new LoadVars();
stop();

Clearing out all the input fields is one way to do it; you could also let the fields maintain
state if the user doesn't enter the correct information and has to come back, but that's up
to you to implement.

2. To actually sign the user up we need some code attached to the Sign up! button:

on(release){
gSignUp.userName = signUpName;
gSignUp.userUserName = signUpUserName;
gSignUp.userPassword = signUpPassword;
gSignUp.userPassword2 = signUpPassword2;
gSignUp.userErnail = signUpErnail;
gSignUp.sendAndLoad("signUp.php", gSignUp, "POST");
gotoAndPlay ( "signUpLoad") ;

3. Next there is the check for a server response in frame signUpTest:

if(gSignUp.loaded){
gotoAndPlay ( "signUpEnd") ;
}else{
gotoAndPlay ( "signUpLoad") ;

4. Finally we proceed to take the result and give the user appropriate feedback in frame
signUpEnd:

if(gSignUp.status == "ok"){
outputArea = "You are now a member of MyCompany! <br> Enjoy! " ;
}else{
_root.gErrorString = gSignUp.error;
gotoAndPlay("error", 1);

stop();

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

This is the bare minimum of what you need to implement a customer sign up, but you should
look into expanding this; maybe collect a quick survey of what the customer wants in the future,
or input fields for phone number, the address and so forth. Implement what you want, but take
into consideration the customer's privacy and leave the non-required fields optional for the
customer to fill out be very careful not to demand too much from them. Alienating the
customers is not a good idea if you want to keep a good relationship with them.

Scene: login

We are coming towards the end, but first we need to sign people in to the site so that they can
use the shopping cart we have built.

00 e- commerce.fla
nmellne

'il 0 .. [! 12.0 fp
Case Study 2: e-Commerce Site

So, go over to scene login and find the form for signing up ready to be filled in by the user.

1. We start by setting up a test in frame loginStart to see if the user is already signed in,
if they are, we don't need to provide the log in form, but we can send the user to the
loginLoggedin frame:

if(_root.loggedin) {
gotoAndPlay ( "loginLoggedin" ) ;

loginUserName = "";
loginPassword = "";
gLogin = new LoadVars();
stop();

2. The button that sends the fields needs some action as well:

on(release) {
gLogin.load("login.php?userName=" + loginUserName +"&userPassword="
+ loginPassword) ;
gotoAndPlay ( "loginLoad" ) ;

3. Then there is the check for the server reply in loginTest:

if(gLogin.loaded){
gotoAndPlay ( "loginEnd") ;
}else{
gotoAndPlay ( "loginLoad") ;

4. Finally we get the result back in frame loginEnd:

if (gLogin.status == "ok")
_root.loggedin = true;
_root.loginStatus = "You are logged in.";
outputArea = "You are now logged in.";
else {

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

_root.gErrorString = gLogin.error;
gotoAndPlay ("error", 1);

stop();

The loginStatus is the field just under the logo at the top right corner: this is just an indication
that the user is logged in.

Scene: error
This generic error scene has no action and consists, as before, of one element: a dynamic text
field named gErrorString. We set this text field throughout the entire movie if we encounter
any errors, so there is no need to mess around with that unless you want to format it differently.

Make sure to make a couple of errors in one of your PHP scripts to trigger the error scene to
see that everything works as it should.

Wrap up
That should wrap up the client interface for our site, and the entire site itself, except for one thing.
Apply the same technique as we did with the administrator pop-up window with the client movie.

Breathe out, sit back, and relax. You should by now have a fully functional site with both an
administrator and client interface. Now comes the real job; to redesign whatever you have done,
or integrate the code into your existing site.

There has indeed been a lot of code in this chapter, I would have loved to dig deeper into the
site, but there are limitations on what we can get into one chapter. In fact: if we wanted to, this
chapter could have filled an entire book by itself! But for now you need to analyze what your
needs are when it comes to this site: what can be done to make this a site that your user will
come back to? A feedback system for each item, perhaps? Streaming media for appropriate
items? You name it and it can (most likely) be incorporated into this site. But take this with you
before you close up this chapter: be aware of your customer and always think about the fact that
you have a broad range of possible customers for a site like this.

Hopefully everything went well, and you are happy with what you have accomplished so far, good
luck, and thanks for the ride!
Case Study 2: e-Commerce Site

What can be done to extend the site


Create a drop-down box for the size. For this you need to give a special format to a new
size field in the database (for example: S_M_L_XXL) and then use the split() function
to cycle through this to make a drop-down box.

The size of the images is a potential issue. We let the administrator upload an image
without knowing its dimensions. Loading these images in when we only need a thumbnail
of them is highly excessive when it comes to download size. I would suggest reading up on
GD and making thumbnails via its methods. Have a look around the Web at
www.zend.com, www.google.com, and other sites to find out more about GD.

Issue a new password with the function we made back in the beginning of the administrator
section. Also, making new administrators and changing passwords should be possible.

Add a feedback system for each item where customers can read reviews of their
experience with the item.

Add streaming media for appropriate items.

Add a PDF preview of any text-based items that you sell.

' 0
1 rn CJ cJ

;\~ic L'
Dec~ e
J D D D D
DuuLJ

Reader's
Showcase

~~LtJ~
R FfE I ;-b fli 4-n
0 L4-l--+-l FtJi n B~ 0 ~:::::+~~-+-~~--+-
0 .1-+-W--11-+.J
o_[] E ~

rn
0 [J ElEl
~~[
0
0
0
D 0

B
cq
Flash]
r
friends of ED make books for you, but we've often wondered what some of you do with
them after you leave the bookstore: what kind of applications do you build, what kind
cq
of sites, portals, communities, do you come up with?

The release of Advanced PHP for Flash has given us a unique opportunity to look out
[ 0
0 into the PHP I Flash community and see what readers have created with a little help
0 from this book's predecessor, Foundation PHP for Flash. From Malaysia to Canada,
EE
B~
Holland to Switzerland, UK to USA, readers around the globe have been delving into
the world of opportunities the fusion of PHP and Flash creates.
0
[ 0

~~ [0
[[I

~
[[I

0 cq
0 Bo [0

D rrf
Advanced PHP for Flash

john Lyons - www.flashbuilder.ch/flash.htm


Zurich, Switzerland

john is a Professional Web Designer currently living and working in Switzerland after moving
from Chicago, USA two years ago where he worked as Senior Web Designer at a top promotional
marketing company. john used Foundation PHP for Flash to help him extend his knowledge of
Flash and integrate it with PHP and MySQL to make his site interactive and engaging.

Adding user polls, a community messageboard, guestbook, and mailing list helped make John's
site, www.flashbuilder.ch, a place that averages about five new member sign ups a day. He has
also contributed greatly to the community at www.phpforflash.com.

John says about PHP for Flash, "This book and user community has been the best resource for me
to learn to build dynamic data-driven Flash applications, and I have met a lot of really great folks
on the messageboard at www.phpforflash.com, which makes it entertaining to collaborate
together on modifications and new ideas."
Showcase

jeremy Thomas - www.variablelimit.com


Richmond, Virginia, USA

jeremy, a Telecommunications Engineer and Freelance Web Designer and Programmer, has used
Foundation PHP for Flash to learn the skills needed to enhance his growing web design business.
As "germboy" he has also been one of the regulars on the book's support site at
www.phpforflash.com/board, helping out other readers and writing tutorials.

Most recently, jeremy was invited to be a technical reviewer on Advanced PHP for Flash, helping
friends of ED to deliver a whole new level of PHP I Flash tuition to web developers around the world.

~s a web design student and freelance Web Designer, I was looking for ways to bring new levels
of interactivity to my web pages. I picked up the book Foundation PHP for Flash one day and have
yet to put it down. The knowledge that I gained from the book has been tremendous. Since reading
it, I have created my business site, using many of the applications that I created from the book
examples and have even built my own applications. These days it is very rare for me to construct
a website without using at least one thing that I learned. Foundation PHP for Flash has changed
the way that /look at web development!"

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

HOmE

nEUJS / EV50T5

( .nEws
PERSOnAL .EUEnTS PREU. YEAR OEH:T YEAR

BUS tnESS
JRnUARY FEBRUAR~ mARt:H APRil
STAFF

EvEnTs: EvEnTs: EUEOTs : EUEnTs :

WEE: 0 0 0

UIOEC

GRAPHICS
mRY .JUnE JU L...,. AUGUST

;:;.
EUEOTS: EUEOTS: e:ue:nrs: e:us:nrs :
WEB SITES
0 0 0 0
WEB PAGE LA ... CUTS

PF:C..JECTS

WEe RPPLICATtCnS SEPTEmBER CCTCS:ER ncuEmee:R oe:ce:mBER

e:uEnrs: EUEnrs: EUEnrs: EUEnTs:


tnFo
0 0 0 0
on SITE mAIL.
FO F: Um

.CI..tEOT lOUin
Showcase

Scott Ysebert - scott.ysebert.com


London, Ontario, Canada

Scott is the creator of Project MX, the first community attempt to adapt the Chapter 12 Flash
Forum into Flash MX. But he didn't stop there, adding countless new features to the board,
including avatars, e-mail notifications, and a comprehensive search function!
Advanced PHP for Flash

Scott has also recently redesigned his homepage at scott.ysebert.com, which now features news
and features, a mailing list and a great "latest posts from the forums" section. He has also been
a major player in the PHP for Flash community, helping others and taking the content of the
book leaps further!
Showcase

"What can I say? This book has taught me everything I know about PHP I MySQL and has
increased my knowledge of Flash a tremendous amount. I found PHP as a solution for my site as
it allows me to create a dynamic experience for my users/clients, and allowing it to work alongside
Flash makes the content sparkle! Steve's easy to understand writing style and practical projects
made this book very enjoyable and I find myself referring it to everyone that asks 'How did you do
that?!' Foundation PHP for Flash has become my new bible for writing Flash-based web
applications."

Sam Riggs - www.deadsam.com


Toronto, Ontario, Canada

A computer artist and coder, Sam (Deadsam to his friends) has been one of the most prominent
members of the PHP for Flash community, taking time to help other readers and also
participating with other PHP Flashers to upgrade the forum to Flash MX and add more and more
functionality to the book's case studies.

"I always want to work strictly with Flash 100% if I can get away with it. Being an artist, Flash holds
a lot of things I desire in it. When I saw the book Foundation PHP for Flash at the bookstore, it blew
me away. I was in the bookstore looking for a book to learn PHP with, but didn't realize this book
was out until I opened it up.
Advanced PHP for Flash

"Two other people were looking through the books at the same time (looking through the Flash
section) and I started suggesting friends of ED books on Flash, because I have yet to find anything
better. Well they walked out the store with friends of ED books and I walked out with PHP for Flash.

"I heard that Flash and PHP were probably the best combination to put together, so I was
determined to learn more. What I found was a book that was easily understandable, very
informative, and the case studies were extremely useful in the real world. The one project I can't
seem to get away from is the forum case study. I completed it long ago within a few weeks of
buying the book, but there is a group of us coders now determined to put as many add-ons to the
Flash forum as possible. I think we have succeeded in making a Flash forum as good as an
HTML I PHP forum, and hopefully soon might even surpass it.

"I have plans to use most if not all the case studies from Foundation PHP for Flash. These case
studies in the book also open doors for a lot more opportunities in other areas as well, that I will
be integrating later on. This is by far one of the best (if not the best book) I have seen so far on the
topic. It fulfils the requirement needed by programmers and designers to cross the gap between
having a fun flashy site created in Flash, and having a fully integrated website where there are very
few limits, if any. I highly recommend it."
Showcase

Geoffrey Rowland and Kelly Sponberg - www.cip.ogp.noaa.gov


Silver Spring, Maryland, USA

Geoffrey Roland is Technical Officer with the Climate Information Project, responsible for the
PHP I MySQL interaction you see there. Kelly Sponberg is the project's manager, and created the
Flash design which was integrated with Geoffrey's server-side pages. Together they used
Foundation PHP for Flash to create an innovative new climate information application which
allows the user to view information on major weather events by clicking on a dynamic map.
Weather reports are then loaded straight from the CIP database into the Flash movie.

"The book was a great help and really got us thinking about all the crazy dynamic things you
could do with PHP I MySQL and Flash. I came into the book knowing a little PHP, and very little
Flash. The book really helped me understand how Flash works with outside scripting languages.
There really is no better combination for dynamically generated content! Our site features lots of
content that has been dynamically generated using PHP and MySQL. One of our next projects?
Creating a Geographic Information System using Flash, GML, and PHP. Wish us luck!"

__ :_ ------- ~~~-~-_1
l O.m.!lte lnfoun.aL!aol) PIO\CCt J011ltl}l S.uppl)lled By NDM DGP <Jrwl USI\JI) OHh'\ lol:ielo&.llo11 Inlier net E);[liolf"r ' ,. ' ~:' ' -: '~;.~ ~~~.:. ..._ rr-=~

!- ~ 2) :~ -~--=- '.,._,-.c. :-;~- -~~ (::~~~e:CD~~ ~ - ~: ~- ~~---


Climate Information Project, Soinl ~~t at ~.ot NDAA- O.O P :wnd~.~t6.I O. otM
RETURIITOMMIPAO~I~ I ~

2ttMMI) 0 $
MU-U-21
0 1
Hi ~-aM.t

lHZ-H-21 0 -1
lH2-K -U 0 -5

Related Unks:

NAS A fatth Obtt rv.'l tOI)' Naw r.a l Haz.1uds M11p


hJID'/IUd~Obtety&fON 0111 gO't'INjl!!f.IIHeUrdtJ
Sa1tlii1 imt~try associated wilh eurrtnl hazNd l'tenta.

o D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

josiah J. Williams - www.jjsquared.com


Pittsburgh, Pennsylvania, USA

Foundation PHP for Flash aided Web Developer Josiah Williams in developing a powerful Flash
website with a strong PHP back-end. The book's easy to follow tuition walked him through the
processes, which enabled him to build a guestbook, a mailing list, and a referral system. He then
used his new-found knowledge to create a custom streaming MP3 player and a program that
allows users to send a text message to his cell phone instantly from his site.

"Overall the book is very helpful for beginners. The book includes access to an online message
board, where a team of moderators will answer your questions almost immediately. This book
helped me overcome my fear of PHP and I'm looking forward to the release of the next edition!"

a month
-1.OOOMB of server space
50 emalllltp addresses
-5GB data transfer a month _
Platnlum Plan
Showcase

view lntro mailing list

lllew lntro llalllngllst


Advanced PHP for Flash

Adrian Ng Chee Wei - www.ngarte.com


Singapore

Adrian, a Freelance Multimedia Programmer and Designer, read Foundation PHP for Flash and
used it to upgrade his static Flash portfolio site. Instead of manually updating information on the
site by altering the source FLA. Adrian can now manage his site content using databases and text
files which dynamically load information into Flash.

"I was attending the Fresh Conference Singapore


and saw a friends of ED store selling this PHP for
Flash book and bought it. I began to follow
through all the tutorials and at the same time
thought of how I can combine the knowledge
learned from the book into my site."

Adrian explains "From the first image


you can see my left news I blog Mcccn 2002 ~ ABOUT
My ous:tom
section using PHP and MySQL. Prior made ~ PORTFOLIO
evir"ob usin"iil
to this book, I was manually c lc y
~ COLLECTIONS
uploading SWF files to my web server
~ PHOTOGRAPHY
everyday and it was taking up so
Tnu 25/07/02 ~ LINKS
much time. I created an interface for
This ni'wi s~c t ion is; now
me to input news, based on what I running on php o"Cf mysql to
store new.s items. This enables
have learn from the book. Nowadays, dynamio updating From o
control pone! ond does: not
I can input news online from require the US@- oF my otlglnol
fklsh fil~s. Updating will bG> so
much e-asier now.
anywhere in the world.
Showcase

"The second screen grab shows my guestbook constructed based on knowledge I gained from the
book. Basically it was modified from the dynamic news tutorial in Chapter 9 to become the
guestbook. I added some extra fields like URL, country, e-mail. I also modified the PHP file so that
the URL and e-mail work as clickable links.

..Jun" 2002 .1 PORTFOLIO


Oust~ 12 31/07102 00:43
.cos. tom hl lp://\I.IIUW-junkfr.tG..com
.J COLLECTIOHS
flljlur:J; ll!'mo ll
GIVE JT W F OR NGAA:'tE!! ! !
"" PHOTOGA"APHY

Fhdr'fN.II KUtrmN" okCI Hac t'klraud .. ~


.J LINKS
c-do
30/07102 23-10
l'lll tp!//r-Mmbft'"S.r~$.(.(M'I"I/M~\ofMmol k>

Addedgliyf-~intSoootion.fl "' Htuooo


am b"oMom:llntjJ ~music, Adl'iocn.

-
vou wit! bll' oUo to s" th& ll"l
r o-Quir'..cl lo h.a.- ~ rodlo.. ltw m.nu kid!;~ sliok. OJ d-tS IM
~..s;lbook. Ke+p enH;kng OPsigf'IE:motiorls
F~fi.K'i'drOI,l,lftgc:IOnstcrls kw"~ t s.....

lntroductlor'\
<GOOGL > cleWjru - HEL.I..
Con tOQt '30/07/021S'S4
1\t lp://t.WNJ.dmftrv.com
T\K'! 30/07102
H!t,,~~r;.OI\U..,o.ur
1'11.1 ~s:rbook is: "Pond~ 9Uf'Sfbook. :). er.d OIIC
Crop mo o nott - a .....stbook Is .J ABOUT
kleo~d unck!or 'about' u:ubMih

"This next image features the mailing list tutorial from Chapter 7. The contact form is also based
on PHP. Those reddish square buttons actually move the screen in the box and by clicking the
bottom second button, it reveals my shoutbox. This section allows users to type in anything they
want by clicking on 'shout it out'.

JUI'It" 2002 .J PORTFOLIO


Dul-I 'JI 12 -
I!nst.om .J COL.L.ECT IONS
~l9u r J &mail
J PMOTOU.R"F\F'HY

J LINKS

leSI.O'EVIL .JIRU
2 Au9ut:l 2002
VCVO ..... ENJOY YOUR
WEEKEND M~N . )

1 SS .s<:~ i 'i)onoppl
lnlroduOi ion
1 AU9UIJ I 2002
hopp.., drawln9l. :) <:llubm i t ,
CCJ.MOCI

1B7.DE\JIL..JIRU
1 AUOlU I 2:002
J ABOUT cm o llln9ll~ h
<a&: hout it ou lh

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

"The last image shows my live radio indicator. I have created an interface for me to enter my
computer's IP address so that people can connect to my computer using Windows Media Player to
listen to my live music broadcast. The interface I created allows me to input my IP so that it
updates on my website. Users visiting my site will be able to see the URL needed. When I stop
broadcasting my music, I just return to the interface and turn off the function and my web page
will then display 'radio offline'.


Horch 2002 .J FIBOUT
M'-11 custom
mod'" J CO LLE CTIONS
virob usin9

II
CIO\f
J PHOTOGRAPH Y

LINKS

II
.J


Fri02108102

ThuOtloe/02

Ft"d laJ:on In fi9t.a" dro.uh; Is


fnaii!J o ......... Cl'tor'"cool con b.~
mH:J';W..,...,.nov.to.do Anirnohons I Gom
SOI"'"'e' ex...-dJH ond strt~
bto'or class SIOI"IS.. Thl:lit o Mulllm~Ciio- I Wob
v+rv I'Q"d subJ-ot Jo t.om anc1
I'T'IOSIH' bul ~ll... lt>$1~"" :)
.J PORTFOLIO

'---=..:.Orolno------"=--'U'-;.;W::..;O..:.u'_w;;_rn-'d"-o"-w' ;..m_.;...--loplo\,11' ond post th follow ing uri to hor mvtlv radio hllp l/t23.43.1.2o4030

"I can't wait till the new book is out."


Showcase

Kevin Menzie I Slice of Lime-


www.mobilesnow.com/pocketpc/index.html
Golden, Colorado, USA

Slice of Lime used Foundation PHP for Flash to effectively


pull dynamic snow data from ski resorts worldwide onto
the Pocket PC version of their application, Mobile Snow.

Founder and Creative Director Kevin Menzie explains,


"Slice of Lime specializes in creating practical applications
for wireless devices. This includes web-enabled phones,
Palm Pilots. and Pocket PCs. Our most recent application,
'Mobile Snow', delivers up-to-the-minute snow report
information to these devices.

"In building our Flash-driven Pocket PC version of Mobile


Snow, Foundation PHP for Flash was a key resource. It
served not only as a valuable tutorial-style book, but also
as a great reference book. Foundation PHP for Flash
helped us build Mobile Snow for the Pocket PC extremely
fast by staying focused on the dynamic capabilities of
Flash when combined with PHP."

@ MohileSnow @ MohileSnow

Colorado Thredbo Alpine Village


Arapahoe Basin Ski Are.a Updoted: Aug Sth. 2002
Aspen High l and ~
A s p e n t1ountain
tlew Snow: o
Beav"'r Cl'"ee k Bo~e Depth: 10
Br eckcru idge
Butte rmilk
lop Depth: 10
Copper Mounta in R esmt lihs Open: !3
Crested Butte Mountain Re s ort
Eldor"' Mountain Resort
Runs Open: o
Keystone Uotes: Tratl Pecks Bo ll roorn o:~nd
Loveland F r 1da~ Fli!l t S
Advanced PHP for Flash

Sukral Helmi- www.webmanultraflash.com & toophat.com.my


Kuala Lumpur, Malaysia

Sukral (webmanflash), a Multimedia Designer from Malaysia, implemented almost all the
tutorials inside the book, such as the Forum, News Panel, and Mailing List, in his personal site at
www.webmanultraflash.com. Meanwhile, at Toophat, his entertainment site, he implemented
the Calendar, Feedback Form, and News Panel.

~1/WER'DITE OF net OAY '-1

I
~ flARf SlUOIOS_

lob\OriM!Wl; 10 liO'fW(!bmz.nl'fi:im

,.,.,.
Jcllhu" C'rtt1Mtt! I'IIJ newlntero~cti'Jt bo~~

w holsa damklno
fli 0?..(;8.:t1 001") l>y ~1\rtMI\
Jodi Um vrtlo~ ohr"'Qo!OS'tmljlpg lfiJittritt A l>il
~-

dmk : a 'k.u m
webm .anflash : updata llnkJ,.
nana_U.an a : akuM
woi
mox_~ v .!l h 1
amoy : pa r nl HH??U?
. Je K I df~ df.s df

J.ufian :~
S UfiA tf l U> BA
s uf .a.n 1 .us:a l;:~mu alil l um :
~$d 1 .1 d c- O jj k~ d im nf

Monday S Auous:t 2'0 02 t 7 sS sl-4

"Yeah ... what can I say ... It helped me learn how to use PHP with Flash. Before this I had tried
website tutorials but failed. When I bought and started reading Foundation PHP for Flash, 'VOILA!'
- in just a week it helped me build my website!"
Showcase

Mark Edwards - www.4d-enter.com


Oneida, New York, USA

Mark, a Web Designer I animator at the Oneida Indian Nation in Oneida, NY, used the resources
in the book to build the website for the nation's new film company, Four Directions
Entertainment.

Mark says, "The book was extremely helpful in using PHP with Flash. I had been using PHP and
MySQL for a while and needed to pull data from the database into my Flash site so I picked up the
book and had my site up and running in no time. The book is great. Definitely one of the easiest
to follow books I've ever encountered."

""'""'
,.,...,..,Mlll't!:lil ~r.d tliilnt rcr
~ ~L1 llnO[Ib)M~ntM:It'ln'an,lf'o(JI'I!
l>'.~l:Oll"'tur TV
C.JNT"AII (:'N"lCI;J~CO~
C-HC6'd1) rri)MG1n.]Jim<c-i~alndl~r.alll~eu~ur,1111.,:f'ro.:~JII
~.-. IM,f.,:IIIICfW"'flltl I /1n I ntwwtt-stc., 1l"IK"tDS.-41io

..,.
i'l'')lil cum pn;ttf.'li Llw ~..""'' .~~~li.U 1 ~ Nwtlenn a,.Jte '~~a11
....:t~.J a cu4lol:t.-Qrm~:w~ ~ ,~ 111 ~"!(\~ '7 ~ Oni! ~ tl.:!Jo:I/Vl! "'d::!..*-1
~

IIJI,:rQ~ntttW.M~~~ Fo~~ (]fill fr~ma- ~ ~ lhla


3k'fOJ,,.Nh1'_..,,ro;,"ntrnrnu,.., r&l'fUr t~~~~JI"IJ~CI='*',
Col'l'1nt!S;I'ntrfnOitt~.MilllHO!jl."tCd:lnd~"'r....f.. IIIJitJf
11an t~r ~- -"'~ totr', :Jttlfi':!IIJ~.~~~~C h n '~'1:1111 <lfWI " " O)larxu:or

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

jacob Bullock - www.kineticz.net


Downey. California, USA

jacob. a full-time student and part-time freelance Designer, used Foundation PHP for Flash to add
some dynamic content to his personal site - specifically e-mail subscription panel, news posting
system, user poll, and the login page for the admin section. He also used the book to set up the
admin section where he can send e-mails, post news, and update the polls. His next challenge
will be to develop a Flash forum using the Chapter 12 case study.

He adds, "/ first off want to say how much /love this book and can't wait for the sequel. I've
had the book for only two weeks and I have already gone through 77 chapters. I have great
use for PHP in the future and its compatibility with Flash is amazing."
Showcase

Sidney de Koning - www.funky-monkey.nl


Amsterdam, The Netherlands

A full-time technofreak and part-time Web Developer and Designer, Sidney is currently working
on several projects including server-side scripting in combination with Flash and devices. He is
putting the knowledge he gained from the book to good use in designing his latest website,
which features dynamically loading images, a mailing list, and updateable news section.

Sidney contact friends of ED when he was working on a college project, and we helped out by
supplying him with a sample chapter and some original full-colour artwork from the book which
he was able to use in his presentation. Foundation PHP for Flash author Steve Webster also
penned a foreword for Sidney's write-up!

"This book is definitely the best of its kind - the material explained is straight to the point, with
real life examples, in such a way that you can easily understand it, yet the book is very in-depth."

IN THIS EDITION CF FUNKV PLACES


WE FEATURE ZAK'T'NTHCS,UIIIICH IS
LOCATED IN GREECE
MORE>>>

One of Sidney's developmen ts for the POA

' D
lmCl cJ

;\~u u~
c ~dJ
0 L,
Advanced PHP for Flash

Punky monkey
cliNe

Benjamin Knigge -
www.fxnetworks.com/shows/originals/the_shield
Los Angeles, California, USA

A freelance Software Developer, Ben used Foundation PHP for Flash as the inspiration for a
message board system that he developed for FX Networks, which they use on many of their
websites. He modified the PHP message board replacing MySQL with a flat XML document, which
he edits utilizing Perl. He also developed a simple administrative tool, which allows for the
management of the message boards. With this architecture, creating a new message board is as
simple as uploading a few files and no database is required.
Showcase

Gary Stasiuk - www.praxisinteractive.com


Richmond, British Columbia, Canada

Gary, an Interactive Designer, has been using Flash to produce rich websites for several years, but
only recently starting integrating real PHP functionality and MySQL into his projects.

"Your book has been one of THE best resource books that I have. (I have almost every single one
of the friends of ED books concerning Flash). Foundation PHP for Flash has been clear and concise,
with tutorials and projects that I have been using as base models for components to my own
website as well as for some of my client websites. I am utterly waiting for the next edition to come
out, and how it will use some of the new elements from Flash MX.

"For the poll, mail list, and various e-mail apps, Istarted with your projects and kept on adding.
These all came about through needs from client projects, but your book showed me the path.

-'""""- .....
u.ntact: (nrotaPr.ncislntcnl"fte.com
l_.a. ......d_
0

'
Praxi 1ntcractivc.com.

Pr.axii Interactive
8080 Spi~s Ro.ad
mond. British Columbia
Cttnada V6Y \V'I

I ........ I 604.274.7780

......... ~-
I ....,, II ...,, II ......,, II .....,, .IL

undcd as a vehicle for crc-alive expression

I I ~ tnnovatove and unu..,al t!'xpeon~nc~ lor the1r auchence.


~11e content that il funct ional. interactive and dynamic.'
gner & Princpl~e, Prads lnttractive

L-------------~====~
I ~ubmt J
~
Our 1 i lep Approach...
I :l 3 .1. S 6o 1
Advanced PHP for Flash

"The one I am most proud of is the Quiz I Assessment tool. I used parts from three different projects
within the book to build the base for the project. For the rest of the project, I just kept pushing. The
quiz has six questions, three info questions and three decision questions. After submitting the
answers, Flash sends them to MySQL. PHP processes a wide variety of comparison queries and sends
them back to Flash. The statistics are shown in Flash as bar graphs, as well as hard numbers."

Flash Stati!>tlr:al OuesUonsi~ or Assessmll!nl Form~ 0


Age Group: ll'llt:oml!:

lo "''" o'""'"l
When driving, by hCIW muth do you usuillly eltcc~:d t h41 post11d spell!d limlt7
I0 only 10 km/h 0 '-'P to 20 lcmlh 0 up to ''IJ kmlh 0 grc-~IC!r tfl.ln 40 lnn/h I
Per yt<lr. how oh~n have" you ~~n cau;ht ncc:l!ding IM speC!d limit?
O Stlm~:'CoorgrC'o:~tc-r I
By how much do you feel the posted s.pced limits. ' hould be- increased?
I0 no incrt.ne nll!cdl!d 0 Jdd10km/h 0 20km/h 0 odd 30 km/h" grottr II---

l lhis style of qu~rlon;:.rre tolletts dJ\411rom t hose th.ll sul:lmltJ complet~Cd form . .)t\d eomp.3rc-s. thl! intormo:~tlon 3go:~ins.t :t
d.at:. bast of tabul.ltld ruponce,, On<t l hi dtala comp;uis.on i$ compl.e1111, I hll u pplico11 ion producu ol ~Suil l re-prnent;~t.ion ol
t~ do1ta. Fl!~b.1Ck is immll!diatl!'.
I

131 4 5 7

II Hom II About II "''"' II Oown!O>d II Oovotopm " rr S.r<icH 1'1

Fll-5:1'1. Sta~i~tlul 011astionakc orAssC!s.smant Form: 0

_,.
(uam~C! q_u~stionsl

\ ..,,.,,,.,
,. ...
\
-
OJilabyOttollr JDat.II~AJI"~p \ Daib'ti"-C~

B
1111'11krH
Oua~ tl onl :
By t'low much do ye~u lcC!I HH!
posted sp!!ed Umlts 1:koul d be t-
lncrc3Jed? r--

....._
... ... _.,.,.
--
fOil @] @] -
10 r:;-
I ~~b OJ: Ck
I "
I Thl< "'toot q, .. ,.,.,;,. oo!l<d<d>!o from thoS< toot .ubmot compt<tcd fm. ond com""'''' tho int.,mation , 9,;,,.,
da1abaH- ol tabulated r Hponce'!i. Once the d.1Ta comparison rsc.amplete, th~appticaUon p4'0ducesa visu.JI re.presentJilkmor
thc-d.n~t . Fc<b.ltkls.lm.med13!C!.
I
WrbAppl UIO" l l 13) 4 5
7

II Home- II About
II Portfolio
II Download II o........,." lj S<M,.. =n llf'tll &
II ConTact I
Showcase

james Ellis- www.webqs.com


Sydney, Australia

james is an Australian Web Designer and Developer, who used Foundation PHP for Flash to add
a new dynamism to his already creative web portfolio.

james tells us, "One of the most helpful sections was Steve's explanation of regular expressions-
probably the first one I have understood clearly. I found the forum a very good study of how to
implement a Flash I PHP app in a 'real-world' situation. A lot of the code can be used in other
situations.

"My site at www.webqs.com is the only project so far where I have used PHP and Flash together in
a major way ... but I've also managed to use the book toscare some ASP coders... "


CorltKtform:
AtcHIIIW rrWill bUll Oil oil I tht bottom of !.hip WHfl lb $!Art
t~~teoe~tfetrorm.

'"'''"
.a. tttqtritiH iMIM 1 dirKtfd to intltfttt:<'wttOS.c.om.
PhoNIF ;
~/C~ 0412 lZ211J(A~.Kull only).
ru: 61Z 9456 6967.

This Is wOifl;lnt;l 'ttl~ of Ol'ltrj)ffi'I'IIHLt.l ~- PtiP


...o nuh uen tnqlnlo.
UH tN SHI(.il Window to iN rNYan.t ltt1'M (M"'Ihf
wiOOS.~;om Silt. COtM'!Oft WOdS lfflqnotfd W onl~ Ullt
most tllitvant rt~m~ rounc~.
Prf'U "fiKlMt on u. SHI'-h wfnclow to do tnou.tf
SHtCI\. wNit ttninq ell(tf' wfl clOW UW SNf(.l) ~w.
Wmertt.rn scmpotlf!'!t
Advanced PHP for Flash

Gregg Vivolo - www.greggv.com


Wayne, New Jersey, USA

Running Gregg Vivolo Web Design alongside his day job as an Electronic Technician for the
US Postal Service, Gregg has used Foundation PHP for Flash to take his first leaps into
dynamic Flash design.

"Prior to reading PHP For Flash I knew absolutely nothing about PHP or MySQL and was only a
'ham & egger' at Flash. A client of mine wanted a 'simple' website created which quickly turned
into a monster (as you can imagine)."

"Being a Web Designer I had to learn the development stuff real quick. That's about the time
I found Steve's book. !literally worked the book and the tutorials to death 10 - 12 hours per
day for 3 weeks and then started developing the site for my client.

The client site is a catalog of pharmaceutical and medical specialty advertising products. It's
pretty intense and to this day I can't believe I actually accomplished it, thanks to Steve and
friends of ED! It dynamically loads about 300 jpegs, uses cookies and has a content
management page which is purely PHP. If it weren't for Foundation PHP for Flash I never
would have put this site together. I can't wait for the next release."

Anthony Onumonu - www.clubsyte.com


London and Leicester, UK

Anthony is one of the founder members and Project Manager of Tsuma Design. Tsuma builds
bespoke multimedia web solutions for Entertainment Specific clients. They improve the cost-
effectiveness of web marketing by developing solutions that integrate online delivery with
traditional print media. This is where Foundation PHP for Flash came in.

Anthony describes, "Tsuma Design were commissioned to build a number of content manager I
web portals. We played around with the idea of using ASP I SQL but came across the friends of ED
title Foundation PHP for Flash. We had used both technologies before (PHP and Flash), but not
together alongside a database (MySQL). Foundation PHP for Flash gave us the grounding we
needed to make our ideas a reality."
Showcase
Securing
MySQL
n

Upon completion of your MySQL installation there are very few security measures in
place; in fact you could say that the door to your database is well and truly wide open.
Put your database onto the Internet in its post installation state and every spotty-faced,
teenage, wannabe hacker the world over will be queuing up to destroy all your hard work.
D
We can't make your database totally safe, but with a little thought and a few helpful
administration basics we can significantly reduce the risks.

Root of all evil


A fresh installation of MySQL leaves the 'root' user without a password. Root is the god cq
of your database, so leaving it without a password is a big NO-NO. It's like leaving your
car unlocked with the keys in the ignition!
[0
0 Our first task is to give the 'root' user a password. We can do this using the command below:

mysqladmin - u root password 'new-password';


EE
In addition to the 'root' user, two additional default users are created. These default
10 users are created to allow access to the database without specifying a password. No
points for spotting that access to your database without a password is a bad thing.
[0
DD First we are going to make sure we're using the MySQL database; we do this by issuing
[0:
BEl the use command at the mysql command prompt.
[0:
mysql> use mysql;

0 Elo
A Advanced PHP for Flash

The command below will remove these potentially dangerous users from our MySQL database:

mysql> DELETE FROM user WHERE User= '';

Now we're rid of our rogue users, you may or may not have noticed that a database by the name
of 'test' has also been installed. It's good practice to remove this database, which can be done
with this command:

mysql> DELETE FROM db WHERE Host= '%';

We now have a clean installation. We've eliminated all the test data, users, and tables that were
created during our installation. It's worth mentioning that people who have either been told the
password or have found it on a note pad or a note stuck to the edge of the administrator's
monitor marked "database password" make the majority of malicious attacks.

There's not much point in having a password if it's readily available to anyone with even a hint
of curiosity. Keep it simple and keep it safe.

MySQL built-in Security


MySQL has a security system above and beyond that of the operating system. This means that it
does not rely on users and privileges created by the operating system itself.

Your system's 'root' user for example, has nothing to do with the MySQL 'root' user; they simply
share the same title. In order for users to access the data in our database, in MySQL,we need to
create entries for them in our 'mysql' database.

The tables that make up the 'mysql' database are known as the Grant tables. Below is the list
of the Grant tables:

user

db

host

columns_priv

tables_priv
Securing our MySQL Installation A

func

By modifying the data stored in these tables we can restrict access to our databases and tables.
The Grant tables are an administrator's greatest friends; we can control everything that goes on
in our database by making simple modifications to them.

The safest way to tackle user access is to lock everything down at first and then only open up
access as it's required, thus avoiding any inappropriate permissions being left granted.

The verification process


Before we dive into making modifications to our Grant tables, let's take a look at the process of
verification in MySQL. Knowing how the permissions work will help you decide what
modifications need to be made and where.

Every interaction with MySQL requires a connection. To make a connection to MySQL we must
provide the following information: username, password, and hostname. The hostname is the
name of the computer making the connection. If you were working on the same one as the
MySQL server itself, this would be localhost. The MySQL security model not only allows you to
restrict users but also computers and even entire domains.

Connection level
MySQL checks the incoming connection request against the information in the user table. If
there's a match then the connection is made, if not then the connection will fail.

User level (user table)


Following a successful connection, MySQL is ready to process the user queries. MySQL must
verify each request for data even though the initial connection has already been verified.

The query request is verified at user level first; a successful login here would give the user access
to every MySQL database and table. You would only expect the administrator to have this level
of access.

Database level (db table)


If the verification process fails at the user level, MySQL checks the db table to see if the user
details supplied can be verified. A successful login here would mean access to the database
specified in the query. Access at this level is seldom dangerous, however, if you wish to
permission individual tables you can set the permissions in the tables_priv table.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
A Advanced PHP for Flash

Table level (tables_priv table)


Users not verified at a database level will be passed down to verification at a table level. If the
user is verified here, access may only be to the tables specified in the query, not to the entire
database.

Column level (columns_priv)


Finally, user details verified at column level will allow access on a per column basis. A failed
verification here is the end of the road and the query request will fail.

Setting permissions
Now that we know the roles of our Grant tables, let's take a look at how we set these permissions
to secure our database.

We'll start by creating a new user:

mysql> INSERT INTO user (Host, User, Password) VALUES ("localhost",


"David", PASSWORD ("lollypop"));

What exactly have we just done?

We have created a new user in the user Grant table called David. His Host permissions have
been set to localhost so David can only connect to the MySQL server from the local machine
itself. We have also set a password for David, which we have encrypted using the PASSWORD
function. This will ensure that his password, lollypop, will be stored in the database as an
encrypted text string preventing prying eyes from reading it.

So we have a new user, but as it stands he has no access rights to anything. Let's give our user
the rights to see any of our MySQL databases:

mysql> INSERT INTO db (Host, User ,Db, Select_priv) VALUES


( "localhost", "David", "Y");
11~11
0 ,

We have now given our user, David, SELECT rights to all of the MySQL databases. The % is used
as a wildcard, which means all. This is not a wise move so let's quickly look at removing the access
rights for David.
Securing our MySQL Installation A

If you need to remove permissions from a user, you do so using the UPDATE statement. Earlier
we gave our user SELECT permission to all our databases, this was an administration error so we
now want to reset his permissions with the command below:

mysql> UPDATE db SET Select_priv="N" WHERE User="David" AND


Host="localhost" AND Db="%";

This has now undone our previous command and we have now removed all David's SELECT
permissions from all the databases right? Well no, not exactly. You see, since all the Grant table
information is loaded into memory when you start MySQL, our changes to the permissions may
not have taken effect.

To ensure that the tables are up to date, we need to issue the FLUSH privileges command to
force MySQL to reload the Grant tables.

mysql> Flush privileges;

The GRANT statement


As with most things, there's more than one way to manage access to your databases. Most people
are uncomfortable with editing the Grant tables directly so we'll take a look at the GRANT
command, which makes life a little clearer.

GRANT [privileges] (columns) ON database.tablename TO


usernamehostname IDENTIFIED BY "password" [grant option] ;

"You said it would be easier!" I hear you cry. Well although it looks a little complicated it's
actually quite simple. Lets' take a closer look; below is a list of privileges we can use with our
GRANT command:

ALL: Gives specified user full privileges.

ALTER: Allows user to alter columns, tables, and indexes.

CREATE: Allows user to create tables and databases.

' 0
1 rn CJ cJ

;\~ic L
Dec~ e
A Advanced PHP for Flash

DELETE: Allows user to delete records from tables.

DROP: Allows user to delete tables and databases.

FILE: Allows the user to read and write files on the server.

INDEX: Allows user to add or delete indexes.

INSERT: Allows user to add records to the database.

PROCESS: Allows user to view and kill MySQL system processes.

RELOAD: Allows user to invoke the FLUSH statement.

SELECT: Allows user to perform SELECT queries.

SHUTDOWN: Allows user to shut down MySQL.

UPDATE: Allows user to edit existing records.

USAGE: Allows user to connect to the server.

mysql> GRANT SELECT ON News.* TO Davidlocalhost IDENTIFIED BY


"lollypop";

Here we have granted SELECT privileges for David on all the tables in the News database.

mysql> GRANT SELECT ON News.images TO Davidlocalhost IDENTIFIED BY


"lollypop";

This time we've changed the privilege to apply only to the images table in the News database.
See l told you it was easy!

We now know how to use GRANT to set access to our databases for users but how do we take
access permissions away?
Securing our MySQL Installation A

REVOKE
We simply use the REVOKE command. For example, let's say David was misusing the permissions
we have just set for him; we can remove them entirely using the REVOKE command, as below:

mysql> REVOKE ALL ON** FROM Davidlocalhost;

It's actually the same syntax as that used for GRANT but instead we use the REVOKE command.

As you can see. MySQL has a very powerful yet equally flexible security model. Modifying the
Grant tables is the bread and butter work of many database administrators. It's important to
familiarise yourself fully with the Grant tables and their uses.

Please be aware that on UNIX-based systems such as LINUX and


Mac OSX, the MySQL server is configured to run as 'root'. Running
services in this way is not good practice, as anything running as
root has the potential for a serious breach in security. Instead of
using 'root', create a MySQL user and group and run the service
as that user by making the appropriate file permission and
ownership modifications.

Summary
We identified a number of inherent problems with a freshly installed MySQL and looked at how
to clear out our installation and prepare it for use.

Also, we examined the MySQL security model and the verification processes in detail. We went
on to create new database users and set access permissions by editing the Grant tables directly
with queries and also using the much simpler GRANT and REVOKE statements.

All in all I think you're ready to move your database out into the big wide world, remembering
that no matter how strong your security, your data is still open to attack and therefore it's
important to make regular backups of your data so that you can restore your database if required.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Resources
D D rR rt=.J

If so, take yourself to some of the following places and look for web pages with the file
extension .php.

Advanced PHP for Flash links


www.phpforflash.com

www.friendsofed.com

Authors' homepages
D ITJ D
Steve Webster- www.codejunkie.co.uk

ooo.B_ larnh Hanc;nn - www i::.rnhh::m<:nn rnm

Todd Marks - www.mindgrub.com

James Palmer - www.carambadesigns.com

Matt Rice- www.ricmastudios.com


B Advanced PHP for Flash

Software homepages
www.php.net

www.mysql.com

www.apache.org

www.macromedia.com

www.zend.com

Setup tools
www.firepages.eom.au/dev4.htm

This site offers special installation and setup packages, installing PHP, MySQL and Apache on your
system with a minimum of fuss.

Also try http://mysql.com/doc/1/n/lnstalling.html for installation instructions for MySQL on Unix.

PHP editors
http://soysal.free.fr/PHPEd

www.phpide.de

Easy to use (and free) PHP code editors.

www.editplus.com

EditPlus isn't free, but it is extremely useful. It color codes all the PHP functions for you, meaning
that your PHP code is a lot easier to follow (and nicer to look at).
Resources B

PHP street corners and forums


Know that you are not alone in your newfound PHP patronage. If you want to check out the
development patterns of like-minded souls, and perhaps take on a few hints and tips about
where to go from here, check out some of the following links:

www.phpbui lder.com

http://phphead.com

http://thephploft.com

PHP web resources


www.phpworld.com

Newsy, comprehensive PHP site, offering articles, information, and feedback.

http://back-end.org

This site offers a separate application aimed at intermediate PHPers (that's you!).

http://php.resourceindex.com

Bringing attention to everything that's new in the PHP world, with plenty of complete scripts and
useful tips.

http://scream i ng-pengu in .com

Ah, the Temple of the Screaming Penguin - a valuable site dedicated to open content, open
information, and open source, which is exactly where we have pitched ourselves by getting
involved with PHP and MySQL!

http://sourceforge.net

More commitment to open source development, claiming the largest repository of open source
code and applications.

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
B Advanced PHP for Flash

www.scriptsearch .com

A great resource for all code-loving designers, offering scripts on every language in the coding
rainbow. with an extensive section on PHP.

www. webmonkey.com/programm i nglphp

Resources on everything web-related. including a great PHP section, with tutorials and tips.

www.phphelp.com

Quite a few forums here, which I have found of great help in the past.

Hosting companies supporting PHP


To publicly display your new piece of dynamic art, you'll need a web host that supports PHP and
MySQL (support for these usually comes as a pair). They can also supply you with the user
information you'll need to insert into your scripts to access the database. There are any number
of companies out there that offer PHP-inclusive web space.

The PHP for Flash web site at www.phpforflash.com is hosted by Xca/ibre Communications, who
have built up many of their back-end systems using PHP. They also fully support MySQL and can
be found at www.xcalibre.co.uk.

XCalibre Communications
QUALITY INTERNET SERVICES

You could also try the following:

www.successfu Ihosting. net

www.l stcom.com
Resources B

www.phphost.com

www. hostrocket.com

www.hostroute.com

For a comprehensive list, plus some reviews of the services, check out:

http://hosts.php.net/msgboard/

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Index

E3
[

oJ
aj
a
Advanced PHP for Flash

B dologout function 298


doOK function 275, 276, 277, 279
Bullock, jacob 446 doRegister function 272
do5end function 298
c do5ettings function 298
Elements layer 270, 271
chat room Flash (case study 1 part 1) 256-299
email variable 262
active user list 256, 260-261
email_txt instance 274
Background layer 270, 281
enableform function 289
background property 278
enabling and disabling buttons 268
backgroundColor property 272
fetchMessages function 289, 293, 294
body variable 262
fetchUserlist function 289, 296
borderColor property 272
fetchUser5ettings function 297
buildMessagelist function 294
F5impleButton component 264, 269, 271
buildUserlist function 297
getUserlist variable 295
Button Caption component parameter 271
global5tyleformat object 286
button graphics 264
Header Text layer 270
Cancel button 274
init function 265, 286, 288, 294, 299
Caption layer 264
init method 265
captionDisabledColor component
input text field background and border
parameter 268
colors 272
caption_txt text field 264, 266
IRC /me command 257
Chat Area layer 281
isEnabled method 268
chatclient.fla 263
lastActivity variable 262
chatfetch.php 294
lastCount variable 294
chatlogout.php 299
loadHandler object 294
chatMessages table 262
loadUser5ettings function 297
chatregister.php 290, 291
loadVars object 285-287, 299
chatUserlist table 262, 299
login dialog 259, 269-273
chatUsers table 262, 290
login function 273, 291
checklogin function 292
logout button 284
checkRegister function 291
logoutBtn instance 284
clickable URls 257
main chat view 280-285
clickHandler component parameter 267
Message dialog 259, 276-277
commandHandler object 291, 299
message history window 282
confirm_txt instance 274
me~sage_mc, register_mc, settings_mc, and
constructor function 264
logm_mc instances 281
creating button component 263-265
message_txt instance 276, 283, 293
creating button component event
newMessages variable 295
handlers 266-268
OK button 274, 278
creating login dialog buttons 271
old5tatusText global variable 266
database design 259-261
onChanged event handler 279
database table specifications 262
onClick Handler component
defining button component parameters 265
parameter 271, 274, 276, 278, 284
Definitions layer 264
onDragOut event handler 267
disableform function 289, 290
onKeyDown event handler 288
doCancel function 275
onload event handler 287, 294
dologin function 272, 273
Index

onPress event handler 267 chatMessages table 316, 319


onRelease event handler 267 chatpost.php 299, 314, 315, 316
onRollOut event handler 266 chatregister.php 299, 306, 307, 308, 309
onRollOver event handler 266 chatUserlist table 311, 312, 317
password input text field 271 chatuserlist.php 300, 312, 313
password variable 262 chatUsers table 308
password_txt instance 271, 274 checking email address validity 307
posted variable 262 clickable URLs 315
Register dialog 259, 274-276 close method 303
register function 290, 292 common.php 300, 301
restrict property 278 connect method 302, 304
sample_txt instance 278 COUNT MySQL function 318
scroll property 296 creating database tables 305
Send button 283, 287 db.php 300, 301, 302, 303
sendBtn instance 283 fail function 301
sendMessage function 293, 298 fetchArray method 303
setlnterval function 289 fetchAssoc function 303
Settings button 284 fetchObject method 303
Settings dialog 259, 277-279 IRC /me command 315
settingsBtn instance 284 lastActivity timestamp 31 0, 313, 317
show function 272-277, 279, 291, 293 mysql_fetch_array function 303
showHand component parameter 266 numRows method 303, 318
State Images layer 264 query method 302, 305, 314
stored message information 261 queryFirst method 302, 308, 310
stored user preferences 257 REPLACE command 310, 317
storeUserSettings function 297 require function 301
textcolor_txt instance 278, 279 SELECT statement 313, 319
user authentication 256 setup.php 300, 303, 304, 305, 306
user interface 257-259 setup.sql 306
User List layer 281, 284 str_replace function 315
user-selectable text color 257 useriD variable 311, 312, 313
useriD variable 262 client-side communication 79
username input text field 271 common.php file 52
username variable 262 cookbook Flash front-end (tutorial) 154-163
username_txt instance 271, 274 adding background and explanatory text 155
chat room PHP (case study 1 part 2) 299-321 cookbook movie clip 155
$dbHost variable 300 cookbook.fla 154
$dbName variable 300 creating interface text boxes 156
$dbUser variable 300 creating space for recipe photo 158
$lastCount variable 318, 319 interface design 154
$message variable 315 ListBox component 156
$messages variable 319 load_recipe_details function 160
$user array 302 load_recipe_list function 160
$user variable 315 onCiipEvent handler 160, 161
chatfetch.php 300, 313, 317, 318, 320 PushButton component 157
chatlogin.php 299, 309, 31 0, 311 recipe_image instance 158
chatlogout.php 300, 311, 312 recipe_list instance 156

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

recipe_list_handler function 156, 159 drawing API 240


ScroUBar component 157 duplicateMovieClip function 369, 406
Search button 157
search_handler function 158, 159 E
cookbook PHP back-end (tutorial) 132-154
$add variable 135, 143 e-commerce admin interface: PHP (case study
$DB instance 135, 142, 151, 153 2 part 1) 323-361
$delete variable 136 $exchangeWWW regular expression 334
$edit variable 144 $regExpHTIP regular expression 334
$id variable 135, 136, 151 $regExpWWW regular expression 334, 335
$name variable 135 addAdminUser.php 359, 360
$page variable 139 adding category to table 337-338
$page_size variable 135 adding users to administrator table 359-360
$parent_id variable 135, 137 adminAddCategory.php 327, 337
$remove_xref variable 142 adminDeleteCat.php 327, 338
$search variable 151 adminDeleteltem.php 327, 339
$update variable 135, 143 adminfetchltem.php 327, 340
adding page navigation links 140, 149 adminfetchltems.php 328, 341
adding pager 140-141, 149 adminGetCategory.php 328, 342
adding recipe cross-references 142 adminGetlmages.php 328, 343
admin categories.php 135 administrator site requirements 324
admin recipes.php 142 adminlogln.php 328, 344
category overview page 138-140 adminPDF.php 328, 345, 347
COUNT function 139 adminPreviewlmage.php 328
creating category administration adminSaveltem.php 328, 353
tool 135-138 adminUpdateCat.php 328, 354
creating pull-down category selection menu 148 adminUpdateltem.php 328, 354
creating recipe administration tool 142 adminUpload.php 328, 355, 356, 357, 358
creating submit buttons 138 catCount variable 342
creating tables 132, 133 checkEmail function 331
creating URL encoded variables 151 debugging MySQL 329
database class 133, 135 deleting category from table 337-339
database.php 133, 135, 142, 151 deleting individual items 339
DATE_FORMAT function 153 ecommerce.sql 325
displaying recipes and categories 146-147 fail function 332, 333
fetch categories and recipes.php 150 firstWords function 330
fetch recipe details.php 153 functions.inc.php 327
query function 133, 134 imageCount variable 343
quote function 134 images directory 355
recipe editor page 144, 145 inputting merchandise items 353
recipe_category_xref table 151 MySQL storage requirements
recipe_count variable 151 (list) 326
RIGHT JOIN function 139 MySQL tables (list) 324-325
newPassword function 336
pdf_begin_page function 349, 350
D pdf_close function 352
de Koning, Sidney 447 pdf_close_image_file function 352
Index

pdf_end_page function 350 categories scene 367-371. 375


pdf_findfont function 348 categories update/delete movie clips 373
pdf_lineto function 349, 351 confirmDelete frame 389
pdf_moveto function 349, 351 confirmEnd frame 390
pdf_open function 348 confirmTest frame 390
pdf_open_image_file function 352 delete button 373-374, 389
pdf_place_image_file function 352 edit item button 385-386
pdf_setcolor function 351 editCatEnd frame 383
pdf_setfont function 349, 350, 351 editCatStart frame 383
pdf_set_info function 348 editCatTest frame 383
pdf_show_xy function 349, 350, 351 editEnd frame 369, 373
pdf_stroke function 349, 351 editltem scene 382
populating categories drop-down box 342 editltemEnd frame 386, 389
populating images drop-down box 343 editltemlnit frame 386
populating items drop-down box 341 editltemTest frame 386
preg_match function 332 editload frame 368
requesting individual items 340-341 editSaveEnd frame 388
setting administrator status 344 editSaveTest frame 388
setting PDF document size 349 editStart frame 368
setting PDF page size 346 editTest frame 373
settings.inc.php 327, 329 error scene 391
SHOW_MYSQL_ERRORS variable 329, 333 fetch items button 384
text2url function 333 gCategoriesPage variable 368
updating category names 354 gEditCatCategories object 386
updating item details 354 gErrorString dynamic text field 391
uploading images to server 355-359 inserting new categories 375-376
ur12text function 335 itemCategory drop-down component 378
validateAdmin function 336 itemlmage drop-down component 379
e-commerce admin interface: Flash (case load function 364
study 2 part 2) 361-392 LoadVars object 364, 368, 386
add button 376, 377 Log In button 364
add item button 380, 381 login scene 363, 365
addEnd frame 376 loglnEnd frame 365
adding, updating, and deleting loglnload frame 365
categories 367-370 loglnStart frame 364
addltem scene 377-378 loglnTest frame 365
addltemEnd frame 378 main scene 366
addltemStart frame 378 maxloop variable 369, 370
addltemTest frame 378 next page button 370-372
addStart frame 376 popup.html 392
addTest frame 376 preloader scene 362
adminFetchltems.php 384 preview image button 380, 387
adminFrame.html 392 previous page button 372
administrator-noCode.fla 362 report scene 391
adminlogln.php 364 saveltemTest frame 381
adminPreviewlmage.php 380 settings.inc.php 391
blank.html 392 SHOW_MYSQL_ERRORS variable 391

' D
1 rn CJ cJ

;\~ic L'
Dec~ e
Advanced PHP for Flash

update button 374 itemShortMC movie clip 405, 406, 407, 412, 413
update item button 388 itemStart frame 417
upload scene 391 itemTest frame 417
userName input field 363 loggedln variable 403, 419
userPassword input field 363 login scene 424-425
e-commerce client interface: PHP (case study loglnEnd frame 425
2 part 3) 393-402 loglnloggedln frame 425
bringing categories into Flash 397 loglnStart frame 425
categories.php 394, 397, 398 loglnStatus field 426
categoryOverview.php 394, 395, 398, 399, 400 loglnTest frame 425
collecting name, username, password, and main scene 405-407
email400 next page button 414
displaying six random items from database 395 overviewMC movie clip 412,413
functions.inc.php 395 overviewTest frame 412
item.php 394, 396 preloader scene 403-405
logln.php 395, 402 previous page button 415
PHP files structure 394 randomEnd frame 406
random6.php 394, 395, 396 randomloadTest frame 406
settings.inc.php 395 removeltem function 404
signUp.php 395, 400, 401 sign up! button 423
web site usability issues 393 signUp scene 422-423
e-commerce client interface: Flash (case study signUpStart frame 422
2 part 4) 403-427 signUpTest frame 423
add to basket button 418 suggested modifications to site 426-427
Basket function 404 Edwards, Mark 445
basket scene 419, 421 Ellis, James 451
basketEnd frame 420 email172-173. See also Flash email client
basketltemMC movie clip 420 (tutorial); SMTP (Simple Mail Transfer
basketStart frame 419 Protocol)
categoriesEnd frame 409
categoriesTest frame 409 F
category scene 408-412
categoryOverviewMC movie clip 411 file uploading 6
collecting name, username, password, and client-side communication 79
email422 detection 79-82
delete button 421 Flash 73
e-commerce-noCode.fla 403 hidden frames 76
error scene 426 HTML 72
gCategoriesloaded variable 403 MIME file types (list) 74-75
gCurrentCategory variable 403, 411, 412 Ming 75
gCurrentltemld variable 403, 407, 417 Flash
gErrorString dynamic text field 426 chat room Flash (case study 1 part 1) 256-299
gltem object 417 cookbook Flash front-end (tutorial) 154-163
imageHolder movie clip 407, 413, 418 e-commerce admin interface: Flash (case study
insertltem function 404 2 part 2) 361-392
item scene 416-419 e-commerce client interface: Flash (case study 2
itemEnd frame 417 part 4) 403-427
Index

exchanging data between .swf files 83 EmailClient.fla 182


file upload detection 79-82 emailData variable 182
file uploading 73 EmailMessage object 186
Flash MX 4-6, 9 getMessages function 185
FS commands 84 HELO command 178
lmageViewer Flash front-end (tutorial) 86-100. inbox tab 187
javaScript methods for Flash movies 79, 83 initializing variables in Flash 183
localConnection method 76, 83-84 LoadVars object 184
Shared Objects 85 receive button 188
shopping cart (tutorial) 42-69 ReceiveDialog 188
Flash drop-down menu (tutorial) 197-211 ReceiveEmail.php 181, 185
adding heading and submenu items to RETR command 180
database 207 send button 190
creating menu headings 197-198 send function 179, 180
creating mySQL database 206-207 sendAndLoad function 184
creating submenu headings 202-204 sendData function 175-179
defining root node 197 SendEmail.php 180, 184
Export for ActionScript option 199 sendMessage function 184
heading movie clip 199-200 setup tab 186
headings table 207 setup, inbox and compose tabs 182
headingsTitle dynamic text field 200 SMTP and POP port values 175
headings_id value 208
itemsloaded array 204, 205 H
loading XML into Flash 200-201
makeMenu function 201-202 Hall, Robert 54
makeSubMenu function 202 Hayden, Dave 214
menu.fla 200 Helmi, Sukral 444
menu.php 211 HTML
menu.xml 198 file uploading 72
openlink function 204-205 hidden frames 76
outputting submenu nodes 211
outputting XML declaration 210
PHP connection to mySQL database 208-209 lmageViewer 85
submenu movie clip 200 ftp functions (list) 73-74
submenu table 207 lmageViewer Flash front-end (tutorial) 86-100.
unloadSubMenu function 205 See also lmageViewer PHP back-end (tutorial)
XML declaration 197, 209 adding buttons to lmageViewer 98
XML object 200 adding code to lmageViewer 87
Flash email client (tutorial) 173-191 areYouSure function 92
$arg variable 178 BROWSE, ADD, and DELETE buttons 99
arrEmailMessage array 186-187 button movie clip 98, 99
close button 189 checkloading function 91
compose tab 189 clearResponse function 88
ComposeDialog 190 creating pop-up box 99
connect function 175 deletelmage function 92, 96
Email class item 181-182 displaylmage function 91
EmailClass.php 174 displaylist function 89

' D
1 rn CJ cJ

;\~~ L'
Dec~ e
Advanced PHP for Flash

file text field 87


file upload detection 93
J
front-end/server feedback 94-96 javaScript
ftpResults function 94, 95 FS commands 84
getlmagelist function 89, 98 methods for Flash movies 79, 83
imageHolder movie clip 86-87 joins. See also cookbook (tutorial)
imageViewer movie clip 86, 100 indexes 119-120
imageViewer.swf 86 inner joins 114-115
listBox component 86-87 multi-table inner joins 115-117
message text field 87 outer joins 117-118
name text field 98 self joins 118-119
onChange function 91, 92 JPEG files S
scroiiBar component 87 loading JPEG images (tutorial) 25-27
selected function 96-1 00
setStyleFormat function 87, 98 K
startTime variable 88
Knigge, Benjamin 448
username directory variable 90
waitForUpload function 93
YES and NO buttons 99 L
lmageViewer PHP back-end (tutorial) 101-108 libswf 214
$delfile variable 101 loadMovie command 9, 24
$username variable 101 loading JPEG images (tutorial) 25-27
ftp.php 101 loadSound method 27
ftp_chdir function 104 adding sound (tutorial) 28-29
ftp_login function 101 loadVariables command 17, 18
ftp_put function 102, 103 LoadVars object 5, 16-17, 256. See also chat
ftp_quit function 104 room Flash (case study 1 part 1)
ftp_rawlist function 105 error detection 20
phpfp_file variable 101 onData event handler (tutorial) 21-23
phpftp_connect function 101 onload event handler (tutorial) 18
phpftp_delete function 104, 108 Lyons, John 430
phpftp_dir variable 101
phpftp_list function 105, 106, 107, 108 M
phpftp_passwd variable 101
phpftp_upload function 104, 107 Menzie, Kevin 443
phpftp_user variable 101 MIME (Multipurpose Internet Mail Extensions)
installing Ming in Linux (tutorial) 217-221 file types (list) 75
building Ming 218 Ming 9, 75. See also installing Ming in Linux
building PHP 219 (tutorial); Your Mom's Guestbook (tutorial)
ming-0.2a directory 218 capabilities of application 221, 227
ming-0.2a.tgz 218 creating a gradient (tutorial) 225-226
phpinfo.php 220 Hello World (tutorial) 223-224
recompiling PHP 219 installation 214-215
restarting Apache 219 installation in Windows 216-217
testing PHP installation 220 methods (list) 222-223
uncompressing archive 218 operating system compatibility 215
Internet 38-39 MP3 files 5
Index

MySQL 6. See also chat room Flash (case chat room PHP (case study 1 part 2) 299-321
study 1 part 1); cookbook (tutorial); e-com- cookbook PHP back-end (tutorial) 132-154
merce admin interface: PHP (case study part e-commerce admin interface: PHP (case study 2
1); Flash drop-down menu (tutorial) part 1) 323-361
AND operator 121-122 e-commerce client interface: PHP (case study 2
B-tree data structure 112 part 3) 393-402
built-in security 456 file structure 394
columns_priv table 458 lmageViewer PHP back-end (tutorial) 101-108
date and time formatting 130-131 shopping cart (tutorial) 42-69
date and time functions (list) 126-127 PHPLib 39
date arithmetic 128-129 Property inspector panel16
db table 457
default users 455 R
full-text searching 123-124
regular expressions 332
FULLTEXT index 124-125
Riggs, Sam 435-436
GRANT command 459-460
Rowland, Geoffrey 437
Grant tables (list) 456-457
indexes 112-113, 119-120
LIKE operator 120-122, 126 s
MATCH function 124-126 security issues 69
primary key 113 sendAndload function 364
REGEXP operator 123, 126 sessions 5, 38-42. See also shopping cart (tuto-
regular expressions 123 rial)
removing test database 456 SharedObject object 5, 29, 30, 85
REVOKE command 461 (tutorial) 30-34
root user passwords 455 shopping cart (tutorial) 42-69
setting permissions 458 $book5ame flag 51
SQL pattern matching 120-121 addToCart function 55-56
tables_priv table 458 arranging books in table using <TR> tags 53
UNIX-based operating systems 461 arrayiD variable 61
user table 457 arrBooks array 56
verification processes 457-458 bookAuthors database field 44
mysql_insert_id function 113 bookdb database 43
bookiD variable 48, 51, 61
N bookName variable 48, 61, 62
bookPrice variable 48, 61, 62
Network Solutions WhoiS database 168
bookSubtract variable 51
Cartltem class 47, 48, 61
0 Cartltem movie clip 61, 62
Onumonu, Anthony 452-453 CheckOut movie clip 68
checkout.php 46, 56, 57
p classinfo.php 46-47
clearcart.php 46, 49
PDFLib 345. See also e-commerce admin inter- creating plus and minus signs 63
face: PHP (case study part 1) displayVars function 53
(tutorial) 345-347 entering book details 44
PHP GarbageCan movie clip 66

' 0
1 rn CJ cJ

;\~LC L'
Dec~ e
Advanced PHP for Flash

getBooks function 52 X
HitAreaMC movie clip 63-64
MinusSign movie clip 65 XML 8, 194-196. See also Flash drop-down
movStartCart movie clip 60 menu (tutorial)
MyCart folder 59 XMLSocket object 256
MYSQL database setup 43
numBooks variable 60 y
PlusSign movie clip 63
Your Mom's Guestbook (tutorial) 227-252
PlusSignGraphic movie clip 63
$_POST array 244
quantity variable 48, 61, 62
$_REQUEST array 245
SELECT statement 45
add~ng labels to scrollbars and scribble pad 234
shopping cart Flash interface 58
addmg labels to text fields 231-232
shoppingCart class 47
adding table to phpforflash database 251
shoppingcart.php 46, 50-51
basename function 251
startshopping.php 46, 48, 68
bg movie clip 240
Status dynamic text field 60
colorChange function 236, 238
Totalltem movie clip 67
connecting to database 244
txtBookName dynamic text field 62
creating guest book form 229
txtPrice dynamic text field 62
creating SWF object 246
txtQuantity dynamic text field 62
currentBGColor variable 237
Slice of Lime 443
currentColor movie clip 234, 238
SMTP (Simple Mail Transfer Protocol) 171-172.
currentColor variable 237, 238, 241
See also Flash email client (tutorial)
dataMov movie clip 237, 239
sockets 7, 166-167. See also SMTP (Simple Mail
defining brush and background color
Transfer Protocol)
objects 236
WhoiS Flash MX (tutorial) 168-170
defining color transform object 236
sound 27-29
defining CSS styles 242, 244
Sponberg, Kelly 437
defining database access variables 242
SQL 112
die command 244
Stasiuk, Gary 449-450
displaying guestbook entries 248
'stateless' web 38-39
displaying guestbook form 247
displaying user's guestbook SWF 249
T document size and color settings 229
this keyword 19 download.php 228, 250, 252
Thomas, jeremy 431-432 drawControl function 240
drawing API 240
v drawing movie clip 234
drawingData array 237, 241
Vivolo, Gregg 452 email text field 230
entries table 252
w 'entry saved' message 245
fpassthru command 251
Wei, Adrian Ng Chee 440-442
GET array 251
Williams, josiah j. 438-439
getURL command 240
guestbook.php 228, 237, 242, 252
guestbook_form.swf 228, 229, 242, 252
joining array 239
Index

locations text field 230 www.friendsofed.com 11-12, 463


message text field 230 www.funky-monkey.nl 447
Ming 246, 249 www.fxnetworks.com 448
MySQL 251 www.google.com 427
mysql_insert_id command 247 www.greggv.com 452
name text field 229 www.hostrocket.com 467
name variable 245 www.hostroute.com 467
Number object 235, 236 www.impossibilities.com 54
onRelease event handler 241 www.inebria.com 75
outputting data display HTML 248 www.jacobhanson.com 463
RGB scrollbars 233 www.jjsquared.com 438-439
Set Background To Current Color www.kineticz.net 446
button 233, 238 www.macromedia.com 464
setBGColorBtn function 238 www.mindgrub.com 463
setting up scrollbar components 236 www.mobilesnow.com 443
Submit button 233, 238 www.mysql.com 464
submit method 237, 240 www.networksolutions.com 171
submitBtn function 239 www.ngarte.com 440-442
Ysebert, Scott 433-435 www.pdflib.com 345
www.php.net 216, 221, 349, 464
URLs www.php.net 356
www.php4win.de 217
back-end.org 465 www.phpadvisory.com 69
hosts.php.net 467 www.phpbuilder.com 465
ming.sourceforge.net 218 www.phpforflash.com 11, 463
mysql.com 464 www.phphelp.com 466
php.resourceindex.com 465 www.phphost.com 467
phphead.com 465 www.phpide.de 464
scott.ysebert.com 433-435 www.phpworld.com 465
screaming-penguin.com 465 www.praxisinteractive.com 449, 450
sourceforge.net 465 www.ricmastudios.com 463
soysal.free.fr 464 www.scriptsearch.com 466
thephploft.com 465 www.sourceforge.net 217
www.1stcom.com 466 www.successfulhosting.net 466
www.4d-enter.com 445 www.variablelimit.com 431, 432
www.apache.org 464 www.webmanultraflash.com 444
www.carambadesigns.com 463 www.webmonkey.com 466
www.cip.ogp.noaa.gov 437 www.webqs.com 451
www.clubsyte.com 452-453 www.zend.com 427, 464
www.codejunkie.co.uk 463
www.deadsam.com 435-436
www.downloads.com 100
www.dubit.co.uk 255
www.editplus.com 464
www.firepages.com.au 464
www.flashbuilder.ch/flash.htm 430
www.foxserv.net 217

' 0
I rn CJ cJ

;\~ic L
Dec~ e

Você também pode gostar