So you want to create a guestbook but you don't
have a database like MySQL at your disposal? Then this tutorial might
come in handy. The things you'll need are Flash, a PHP script and the
XML file that will hold your data.
XML Guestbook
with PHP
by Arjen
Gosman aka Flashmatazz: 18 april 2004
So you want to create a guestbook but you don't have a
database like MySQL at your disposal? Then this tutorial
might come in handy. The things you'll need are Flash, a PHP
script and the XML file that will hold your data.
Setting up the Flash movie
Let's start by creating a new Flash movie. Or,
alternatively, you could just read through the tutorial and
download the ZIP file at the end ;)
Below I've described how the movie is setup exactly:
- On the main stage create e dynamic textfield with
instancename myGuestbook which will hold all our
text. In this textfield's properties, make sure it's a
multiline textfield and that the Render text as HTML
option is active.
- Drag the scrollbar component onto this textfield, or
create your own custom scroller.
- Create a dynamic textfield with instancename
myCount which is used to show the total amount of
messages in our guestbook.
- Create an "Add a message" button with instancename
createButton.
- Still on the main stage, create 2 buttons with
instancenames previous and next which
are used to walk through all pages of our guestbook.
- Create a dynamic textfield with instancename
nowShowing.
- Create 2 buttons with instancenames previous
and next.
- Create a movieclip with instancename createMessage.
- Inside this movieclip, create two input textfields:
nameField and messageField.
- Also within this mc, create two buttons:
closeButton and sendButton.
- Finally, still within this mc create a dynamic
textField called errorField.
Now that we have all the elements we need, we can go and
spice it up a bit with some actionscript. Let's continue to
the next page.
Actionscript
First you will have to get a basic understanding on how to
handle XML data within Flash.
If you feel like you're ready for it already, then take a
look at the following actionscript. This needs to go into
the first frame of the flash movie:
- var
currPage
= 0;
- var
showAmount
= 10;
// set this to the amount of entries
you want to view at a time
- previous._visible
= false;
- createMessage._visible
= false;
- createButton.onRelease
=
function(){
- this._visible
=
false;
- this._parent.createMessage._visible
=
true;
- if
(createMessage.nameField.text
== ""){
- Selection.setFocus(createMessage.nameField);
- }
- else
if (createMessage.messageField.text
== ""){
- Selection.setFocus(createMessage.messageField);
- }
- }
- // **** Load XML
****************************
- myXML
= new
XML();
- myXML.ignoreWhite
= true;
- receiverXML
= new
XML();
- myXML.onLoad
=
function(success){
- myXML.contentType
=
"text/xml";
- if
(success){
- this.showXML();
- }
- else{
- trace("Error
loading XML file");
- }
- }
- myIdentifier=Math.round(Math.random()*10000);
- myXML.load("guestbook.xml?uniq="+myIdentifier);
- receiverXML.onLoad
=
function(){
- this.contentType
=
"text/xml";
- _root.currPage
= 0;
- this.showXML();
- }
- createMessage.closeButton.onRelease
=
function(){
- this._parent._visible
=
false;
- createButton._visible
=
true;
- }
- createMessage.sendButton.onRelease
=
function(){
- var
myName
= this._parent.nameField.text;
- var
myMessage
= this._parent.messageField.text;
- if
(myName
== ""){
- this._parent.errorField.text
=
"please fill out your name";
- Selection.setFocus(this._parent.nameField);
- }
- else
if (myMessage
== ""){
- this._parent.errorField.text
=
"please leave a message";
- Selection.setFocus(this._parent.messageField);
- }
- else
{
- myXML.firstChild.appendChild(myXML.createElement("entry"));
- myXML.firstChild.lastChild.attributes.myName
=
myName;
- myXML.firstChild.lastChild.appendChild(myXML.createElement("myText"));
- myXML.firstChild.lastChild.lastChild.appendChild(myXML.createTextNode(myMessage));
- myXML.sendAndLoad("processXML.php",
receiverXML);
- this._parent._visible
=
false;
- createButton._visible
=
true;
- }
- }
- XML.prototype.showXML
=
function(){
- myGuestbook.scroll
= 1;
- myGuestbook.htmlText
= "";
- var
numItems
= this.firstChild.childNodes.length;
- var
firstItem
=
numItems -
(currPage*showAmount);
- if
(currPage
== 0)
previous._visible
=
false;
- var
lastItem
=
firstItem -
showAmount ;
- if
(lastItem<=0)
{
- lastItem
= 0;
- next._visible
=
false;
- }
- myCount.text
=
"Total messages: " +
numItems;
- if
(firstItem
==
lastItem+1)
nowShowing.text
=
"Showing message " +
firstItem;
- else
nowShowing.text
=
"Showing message " +
firstItem
+ " to
" +
(lastItem
+ 1);
- for
(i=(firstItem-1);
i>=
lastItem;
i--){
- myGuestbook.htmlText
+=
"<B>" +
this.firstChild.childNodes[i].attributes.myName
+
"</B> wrote:\n";
- myGuestbook.htmlText
+=
this.firstChild.childNodes[i].firstChild.firstChild.nodeValue
+
"\n\n";
- }
- }
- previous.onRelease
=
function(){
- currPage--;
- myXML.showXML();
- next._visible
=
true;
- }
- next.onRelease
=
function(){
- currPage++;
- myXML.showXML();
- previous._visible
=
true;
- }
Are you still here? I didn't scare you away
now did I? Alright, onto the next page then because I owe
you a bit of an explanation.
Actionscript explained
I'm not going to explain every singe line of actionscript,
beause a lot of it speaks for itself. Instead, I'm going to
focus on the main functionality of the guestbook, namely the
XML.sendAndLoad() function which has the
following usage (taken from the Flash Actionscript
dictionary):
myXML.sendAndLoad(url,targetXMLobject)
This method encodes the specified XML
object into a XML document, sends it to the specified URL
using the POST method, downloads the server's response and
then loads it into the targetXMLobject specified in the
parameters. The server response is loaded in the same manner
used by the load method.
Now what does this mean exactly? Obviously
it means that we need two XML objects in our script: the
object that is sent to the specified URL - which in our case
is a PHP script - and a target object that receives data
back from this PHP script. The following lines create those
two XML objects:
- myXML
= new
XML();
- myXML.ignoreWhite
= true;
- receiverXML
= new
XML();
Our guestbook.xml file initially is
loaded into the myXML object. After it has been successfully
loaded the showXML() prototype is called:
- if
(success){
- this.showXML();
- }
This prototype fills our main textfield with
the data from the XML file, starting with the last entry
that has been added to the guestbook. It only shows the
number of entries that are defined in the variable
showAmount, defined in line 2, which in our case equals
10:
- var
showAmount
= 10;
We also want to keep track of the number of
pages we need for all of our guestbook entries. Let's say we
have 12 entries and only want to show 10 per page. Obviously
our entries should then be divided over 2 pages. The
currPage variable is used for this, together with the
firstItem and lastItem variables. The
first item we'd like to see is entry #12, the entry that was
last added to the guestbook. So:
- var
firstItem
=
numItems -
(currPage*showAmount);
and because currPage initially
equals 0 (the first page) this gives us:
- var
firstItem
= 12
- (0*10);
// equals 12
the last item shown on this page should then
ofcourse be 12 minus 10 = 2 which is done by:
- var
lastItem
= firstItem
-
showAmount ;
Further, we don't want the previous button
to be visible when we're already viewing the first page so
therefore:
- if
(currPage
== 0)
previous._visible
= false;
Now, if we press the next button,
the currPage variable is increased by 1. After
this, the showXML() function is called again. Now
firstItem will equal 2:
- var
firstItem
= 12
- (1*10);
// equals 2
Subsequently, lastItem will equal 2
- 10 = -8. Obviously, in such a case where the last page
would not contain the amount of entries as defined in the
showAmount variable, if we would only write:
- var
lastItem
= firstItem
-
showAmount ;
we'll end up with a negative value for
lastItem which would mess up the for-loop that fills
our textfield. Therefore we also need the following, which
sets lastItem to 0 and also hides the 'next' button
when viewing the last page.
- if
(lastItem<=0)
{
- lastItem
= 0;
- next._visible
=
false;
- }
Having said all this, I think it will be
quite clear what the previous.onRelease and
next.onRelease event handlers do.
Intermezzo: the XML file
So how exactly is the XML file setup? We start out with an
'empty' file, meaning that there are no guestbook entries
yet. The file looks like this:
<?xml version="1.0"?>
<guestbook>
</guestbook>
Actionscript continued
Now that we know how the XML file is setup and how the
showXML() function works we come to the part where we
want to add a message to our guestbook. By clicking the "add
a message" button, the createMessage movieclip
becomes visible. After filling out the name and
message fields and clicking the send button,
the following happens:
- The values from the two input textfields are assigned
to the variables myName and myMessage:
- var
myName
= this._parent.nameField.text;
- var
myMessage
= this._parent.messageField.text;
- The code checks if both textfields are actually filled
out. If one of them is left blank an errormessage is shown
in the errorField and the cursor is placed inside
the empty textfield.
- if
(myName
== ""){
- this._parent.errorField.text
=
"please fill out your name";
- Selection.setFocus(this._parent.nameField);
- }
- else
if (myMessage
== ""){
- this._parent.errorField.text
=
"please leave a message";
- Selection.setFocus(this._parent.messageField);
- }
- If both fields are filled out (the else statement), a
new <entry> node is added to the myXML object.
Note that this node is added to myXML's firstchild, which
is the <guestbook> node:
myXML.firstChild.appendChild(myXML.createElement("entry"));
The myXML object now looks like this:
<?xml version="1.0"?>
<guestbook>
<entry>
</entry>
</guestbook>
- After that, a myName attribute is added to
this new <entry> node and assigned the value of
the myName input textfield:
myXML.firstChild.lastChild.attributes.myName
=
myName;
Resulting in:
<?xml version="1.0"?>
<guestbook>
<entry myName="Flashmatazz">
</entry>
</guestbook>
- Then a new <myText> node is created as a
childnode of the newly created <entry> node:
myXML.firstChild.lastChild.appendChild(myXML.createElement("myText"));
Giving us the following:
<?xml version="1.0"?>
<guestbook>
<entry myName="Flashmatazz">
<myText> </myText>
</entry>
</guestbook>
- A new text node, containing the value of the
myMessage input textfield is added to this newly
created <myText> node:
myXML.firstChild.lastChild.appendChild(myXML.createElement("myText"));
which finally gives us:
<?xml version="1.0"?>
<guestbook>
<entry myName="Flashmatazz">
<myText>Here goes the text that the user wrote in the
message textfield </myText>
</entry>
</guestbook>
- And now, finally, this updated myXML object is sent to
the PHP script which resides on the server:
- myXML.sendAndLoad("processXML.php",
receiverXML);
The PHP script
Now that Flash has sent our updated myXML object to the PHP
script on the server, we'll have a look at how this script
works. As you could see on the previous page, the script is
named processXML.php and here is how it looks:
- <?php
- $xmlString
=
$HTTP_RAW_POST_DATA;
- if
(is_null($xmlString))
{
- print
"No data was sent";
- }
- else
{
- $file
=
fopen("guestbook.xml",
"w+")
or
die("Can't
open XML file");
- if(!fwrite($file,
$xmlString)){
- print
"Error writing to XML-file";
- }
- print
$xmlString."\n";
- fclose($file);
- }
- ?>
Explanation:
- In the first line, the data that was sent from Flash
is retrieved and assigned to the $xmlString
variable. Data sent using the XML object is not URL
encoded. Therefore PHP won't parse the data into variables
and you will need to use $HTTP_RAW_POST_DATA to access the
raw data directly. $xmlString now contains one
long string where the new guestbook entry is already
inserted.
- The if statement then uses the is_null()
function to check if the $xmlString variable really
contains a value. If for some reason the data is not
retrieved correctly or the PHP script is called directly
from the browser, we could at the end of the script end up
with an empty XML file.
- In the else statement, if $xmlString does
contain data, we use the fopen() function to open
the file guestbook.xml using the w+ mode. This
mode opens the file for reading and writing, places the
file pointer at the beginning of the file and truncates
the file to zero length, meaning that all content is
erased. If the file does not exist, it will attempt to
create it. The result of the fopen() action is
assigned to the $file variable, meaning that
$file can now be used as a pointer to our XML file.
Note that the file must be accessible to PHP, so you need
to ensure that the file permissions allow this access.
This means that you must set (CHMOD) permissions to 777,
which you can do with your FTP program for example.
- Within the following if-statement the script attempts
to write this 'xml-string' back to our guestbook.xml
file.
- After that the $xmlString variable is sent
back to Flash where it is received in our receiverXML
object.
- Finally a bit of cleaning up is done to free up the
used file descriptor: our XML file is closed using the
fclose() method.
And now we're almost done. By sending our
data back to Flash, the receiverXML.onLoad handler
is invoked. Within this handler the showXML() prototype is
called again, just as it was when the flash movie first
loaded. This function again loops through our - now updated
- XML file and shows all entries in our textfield so we can
read what we've just written in the guestbook
|