view release on metacpan or search on metacpan
Revision history for Perl extension AMF::Perl.
0.15 Sun Sep 19 13:01:35 EDT 2004
Converted examples (except for Petmarket) to ActionScript 2.0 under Flash MX 2004.
Patches from Kostas Chatzikokolakis about error checking of input data length.
WriteUTF() writes the string length as long for lengths > 65535.
Also, check for (defined $s) and not just ($s) in writeUTF.
0.14 Sun Jul 11 18:59:36 EDT 2004
Really fixed the number 16 issue (forgot to include the change in 0.13).
Added Richard Boulton's change to readDouble() and writeDouble() to take into account endian-ness.
Changed the behavior of amf_throw() to enable die() to work.
0.13 Sun Jun 20 15:52:57 EDT 2004
Started duplicating changes in this file.
doc/code.html
doc/encoding.html
doc/cpu.pl
doc/index.html
doc/orn5.gif
doc/examples/README.txt
doc/examples/cpu/cpu.pl
doc/examples/cpu/cpu.fla
doc/examples/cpu/cpu.swf
doc/examples/cpu/cpu.html
doc/examples/dataGrid/dataGrid.pl
doc/examples/dataGrid/dataGrid.swf
doc/examples/dataGrid/dataGrid.html
doc/examples/basic/README.txt
doc/examples/basic/basic.fla
doc/examples/basic/basic.swf
doc/examples/basic/basic.html
doc/examples/basic/basic.pl
doc/examples/basic/basicservices/DataEcho.pm
doc/examples/sql/DataGlue.as
doc/examples/sql/README.txt
doc/examples/sql/park.fla
doc/examples/sql/park.html
doc/examples/petmarket/README.txt
doc/examples/petmarket/petmarket.pl
doc/examples/petmarket/petmarket.sql
doc/examples/petmarket/petmarket/api/cartservice.pm
doc/examples/petmarket/petmarket/api/catalogservice.pm
doc/examples/petmarket/petmarket/api/dbConn.pm
doc/examples/petmarket/petmarket/api/orderservice.pm
doc/examples/petmarket/petmarket/api/stringresourcesservice.pm
doc/examples/petmarket/petmarket/api/userservice.pm
doc/updates.html
META.yml Module meta-data (added by MakeMaker)
doc/code.html view on Meta::CPAN
sub new
{
my ($proto)=@_;
my $self={};
bless $self, $proto;
return $self;
}
sub echoNormal
{
my ($self, $data) = @_;
return $data;
}
sub echoDate
{
my ($self, $data) = @_;
return $data;
}
sub echoXML
{
my ($self, $data) = @_;
return $data;
}
sub methodTable
{
return {
"echoNormal" => {
"description" => "Echoes the passed argument back to Flash (no need to set the return t
ype)",
"access" => "remote", # available values are private, public, remote
},
doc/encoding.html view on Meta::CPAN
<h2>Using non-standard encoding</h2>
Kostas Chatzikokolakis submitted a patch with the following explanation:
<br>
All data in flash remoting are sent as unicode. However, database data
and scripts are usually in a local encoding. I made some enhacements to
AMF::Perl so that it automatically converts all strings to utf8 when sending
and back to the given encoding when receiving. The usage is:
<pre>
my $gateway = new AMF::Perl;
$gateway->encoding("iso-8859-7");
$gateway->setBaseClassPath("Services/");
$gateway->service();
</pre>
doc/examples/README.txt view on Meta::CPAN
AMF::Perl: Flash Remoting in Perl.
See http://www.simonf.com/amfperl for more information
Version: 0.09
Date: March 13, 2004.
1. The "cpu" directory contains an example of simple object registration that returns a complex data structure (array of hashes). The Flash movies shows a bar chart of the current server load as reported by uptime.
2. The "datagrid" directory is an example of using an advanced GUI control in a Flash movie.
3. The "basic" directory shows how data is passed from the client to the server and back. This example employs the advanced service registration when you register a directory and all Perl packages in that directory are automatically considered as ser...
It also shows how to throw exceptions via amf_throw.
4. The "sql" directory is the Parkservice example (borrowed from AMFPHP). It
uses SQL queries.
5. The "petmarket" directory is the Perl implementation of the Macromedia
Petmarket.
Simon Ilyushchenko
doc/examples/basic/basic.html view on Meta::CPAN
<body>
<center>
<table cellspacing=10><tr>
<td align=left width=400 valign=top>
<H2>This is an example of <a href=http://www.simonf.com/amfperl/>AMF::Perl</a> in action.</H2>
<br>
<p>
Download Flash 7 player from <a href="http://www.macromedia.com/shockwave/download/alternates/">here</a> if you don't have it. It even works on Linux!
<p>
This shows various data types passed through AMF to the perl backend and sent back.
The most interesting this is not so much what it does, but how it works. The Perl script utilizes the "service discovery" approach - you simply put Perl modules into a certain directory, and they are automatically registered as services.
<br><br>
This example also shows how to throw exceptions, handled by functionName_onStatus in the Flash client (as opposed to functionName_onResult, which is called normally). Simply include in your Perl code
<pre>
use AMF::Perl qw/amf_throw/;
</pre>
and then call <em>amf_throw()</em> with a string or an arbitrary object as a parameter.
<br><br>
If you call <em>die "Error message"</em>, it will be also caught in the same way and sent as an error to Flash.
doc/examples/basic/basicservices/DataEcho.pm view on Meta::CPAN
},
"generateError" => {
"description" => "Throw an error so that _status, not _result on the client side is called",
"access" => "remote", # available values are private, public, remote
},
};
}
sub echoNormal
{
my ($self, $data) = @_;
return $data;
}
sub echoDate
{
my ($self, $data) = @_;
return $data;
}
sub echoXML
{
my ($self, $data) = @_;
return $data;
}
#This function will NOT return the value, because the call to amf_throw() will interrupt
#the control flow and cause the _Status function on the client to be called.
sub generateError
{
my ($self, $data) = @_;
amf_throw("An error!!!");
return "No error";
}
1;
doc/examples/dataGrid/dataGrid.html view on Meta::CPAN
<center>
<table cellspacing=10><tr>
<td align=left width=400 valign=top>
<H2>This is an example of <a href=http://www.simonf.com/amfperl/>AMF::Perl</a> in action.</H2>
<br>
<p>
Download Flash 7 player from <a href="http://www.macromedia.com/shockwave/download/alternates/">here</a> if you don't have it. It even works on Linux!
<p>
This is an example of a GUI control (Data Grid) that would be non-trivial to implement in straight HTML. Note that by clicking on column headers the values are sorted by that column, and the columns can be resized. Click on a grid row to open the bro...
<br>
The datagrid component is not freely available, unfortunately. You can buy it <a href=http://www.macromedia.com/software/drk/productinfo/all_volumes/>here from Macromedia</a>.
<br><br>
<a href=dataGrid.pl>This is the server-side Perl script dataGrid.pl.</a>
</td>
<td width=600>
<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" id="DataGrid" width=550 height=350>
<PARAM NAME=movie VALUE="dataGrid.swf">
<PARAM NAME=quality VALUE=high>
<PARAM NAME=bgcolor VALUE=#FFFFFF>
<EMBED src="dataGrid.swf" quality=high bgcolor=#FFFFFF width=550 height=350
NAME="DataGrid" ALIGN="" TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">
</EMBED>
</OBJECT>
</td>
</tr></table>
</center>
</body>
</html>
doc/examples/petmarket/README.txt view on Meta::CPAN
There are a few steps to get it working - you need to compile each movie separately, for example.
To make thing easier, a fully precompiled client side is provided at the AMF::Perl web site:
http://www.simonf.com/amfperl/examples/petmarket/index.html
(Unlike other examples, the client is NOT included into the AMF::Perl distribution due to its size.)
2. Usage.
You need to load the data in petmarket.sql into a database and configure
the database server, name username and password in dbConn.pm.
You HAVE to set your server URL in initFunction/mainInit.as and then recompile main.fla in order to point your
client to your server.
3. Notes about implementation.
You HAVE to have these files in the directory petmarket/api relative to your Perl gateway script,
because this is what the Flash client assumes.
doc/examples/petmarket/petmarket.sql view on Meta::CPAN
-- Table structure for table 'cart_details'
--
CREATE TABLE cart_details (
cartid varchar(100) default NULL,
itemid varchar(10) default NULL,
quantity int(11) default NULL
) TYPE=MyISAM;
--
-- Dumping data for table 'cart_details'
--
--
-- Table structure for table 'category'
--
CREATE TABLE category (
catid varchar(10) NOT NULL default ''
) TYPE=MyISAM;
--
-- Dumping data for table 'category'
--
INSERT INTO category VALUES ('BIRDS');
INSERT INTO category VALUES ('REPTILES');
INSERT INTO category VALUES ('DOGS');
INSERT INTO category VALUES ('FISH');
INSERT INTO category VALUES ('CATS');
--
doc/examples/petmarket/petmarket.sql view on Meta::CPAN
CREATE TABLE category_details (
catid varchar(10) NOT NULL default '',
name varchar(80) NOT NULL default '',
image varchar(255) default NULL,
descn varchar(255) default NULL,
locale varchar(10) NOT NULL default ''
) TYPE=MyISAM;
--
-- Dumping data for table 'category_details'
--
INSERT INTO category_details VALUES ('BIRDS','Birds','birds_icon.gif','','en-US');
INSERT INTO category_details VALUES ('REPTILES','Reptiles','reptiles_icon.gif','','en-US');
INSERT INTO category_details VALUES ('DOGS','Dogs','dogs_icon.gif','','en-US');
INSERT INTO category_details VALUES ('FISH','Fish','fish_icon.gif','','en-US');
INSERT INTO category_details VALUES ('CATS','Cats','cats_icon.gif','','en-US');
--
-- Table structure for table 'item'
--
CREATE TABLE item (
itemid varchar(10) NOT NULL default '',
productid varchar(10) NOT NULL default ''
) TYPE=MyISAM;
--
-- Dumping data for table 'item'
--
INSERT INTO item VALUES ('EST-3','FI-SW-02');
INSERT INTO item VALUES ('EST-15','FL-DSH-01');
INSERT INTO item VALUES ('EST-19','AV-SB-02');
INSERT INTO item VALUES ('EST-7','K9-BD-01');
INSERT INTO item VALUES ('EST-27','K9-CW-01');
INSERT INTO item VALUES ('EST-26','K9-CW-01');
INSERT INTO item VALUES ('EST-6','K9-BD-01');
doc/examples/petmarket/petmarket.sql view on Meta::CPAN
image varchar(255) NOT NULL default '',
descn varchar(255) NOT NULL default '',
attr1 varchar(80) default NULL,
attr2 varchar(80) default NULL,
attr3 varchar(80) default NULL,
attr4 varchar(80) default NULL,
attr5 varchar(80) default NULL
) TYPE=MyISAM;
--
-- Dumping data for table 'item_details'
--
INSERT INTO item_details VALUES ('EST-3',0.00,12.00,'en-US','fish4.gif','Salt Water fish from Australia','Toothless','Mean','','','');
INSERT INTO item_details VALUES ('EST-15',0.00,12.00,'en-US','cat3.gif','Great for reducing mouse populations','With tail','','','','');
INSERT INTO item_details VALUES ('EST-19',0.00,2.00,'en-US','bird1.gif','Great stress reliever','Adult Male','','','','');
INSERT INTO item_details VALUES ('EST-7',0.00,12.00,'en-US','dog2.gif','Friendly dog from England','Female Puppy','','','','');
INSERT INTO item_details VALUES ('EST-27',0.00,90.00,'en-US','dog4.gif','Great companion dog','Adult Female','','','','');
INSERT INTO item_details VALUES ('EST-26',0.00,92.00,'en-US','dog4.gif','Little yapper','Adult Male','','','','');
INSERT INTO item_details VALUES ('EST-6',0.00,12.00,'en-US','dog2.gif','Friendly dog from England','Male Adult','','','','');
doc/examples/petmarket/petmarket.sql view on Meta::CPAN
--
-- Table structure for table 'product'
--
CREATE TABLE product (
productid varchar(10) NOT NULL default '',
catid varchar(10) NOT NULL default ''
) TYPE=MyISAM;
--
-- Dumping data for table 'product'
--
INSERT INTO product VALUES ('K9-RT-01','DOGS');
INSERT INTO product VALUES ('K9-DL-01','DOGS');
INSERT INTO product VALUES ('FI-SW-01','FISH');
INSERT INTO product VALUES ('FI-FW-02','FISH');
INSERT INTO product VALUES ('K9-BD-01','DOGS');
INSERT INTO product VALUES ('K9-PO-02','DOGS');
INSERT INTO product VALUES ('FL-DLH-02','CATS');
doc/examples/petmarket/petmarket.sql view on Meta::CPAN
CREATE TABLE product_details (
productid varchar(10) NOT NULL default '',
locale varchar(10) NOT NULL default '',
name varchar(80) NOT NULL default '',
image varchar(255) default NULL,
descn varchar(255) default NULL
) TYPE=MyISAM;
--
-- Dumping data for table 'product_details'
--
INSERT INTO product_details VALUES ('K9-RT-01','en-US','Golden Retriever','dog1.gif','Great family dog');
INSERT INTO product_details VALUES ('K9-DL-01','en-US','Dalmation','dog5.gif','Great dog for a Fire Station');
INSERT INTO product_details VALUES ('FI-SW-01','en-US','Angelfish','fish1.jpg','Salt Water fish from Australia');
INSERT INTO product_details VALUES ('FI-FW-02','en-US','Goldfish','fish2.gif','Fresh Water fish from China');
INSERT INTO product_details VALUES ('K9-BD-01','en-US','Bulldog','dog2.gif','Friendly dog from England');
INSERT INTO product_details VALUES ('K9-PO-02','en-US','Poodle','dog6.gif','Cute dog from France');
INSERT INTO product_details VALUES ('FL-DLH-02','en-US','Persian','cat1.gif','Friendly house cat, doubles as a princess');
doc/examples/petmarket/petmarket.sql view on Meta::CPAN
shippingcity varchar(50) default NULL,
shippingcountry varchar(50) default NULL,
shippingzip varchar(10) default NULL,
shippingphone varchar(20) default NULL,
creditcardnumber varchar(50) default NULL,
creditcardtype varchar(50) default NULL,
creditcardexpiry varchar(50) default NULL
) TYPE=MyISAM;
--
-- Dumping data for table 'user_details'
--
doc/examples/petmarket/petmarket/api/dbConn.pm view on Meta::CPAN
# under the same terms as Perl itself.
#This is server side for the Macromedia's Petmarket example.
#See http://www.simonf.com/amfperl for more information.
use warnings;
no warnings "uninitialized";
use strict;
my $dbhost = "localhost";
my $dbname = "database";
my $dbuser = "user";
my $dbpass = "password";
use DBI;
use AMF::Perl::Sql::MysqlRecordSet;
sub new
{
my ($proto) = @_;
my $self = {};
doc/examples/petmarket/petmarket/api/stringresourcesservice.pm view on Meta::CPAN
$strings{"VALIDATE_SELECT_CC_MO_ERROR_MSG_str"}="Please select a credit card expiry month from the list.";
$strings{"VALIDATE_SELECT_CC_YR_ERROR_MSG_str"}="Please select a credit card expiry year from the list.";
$strings{"VALIDATE_CC_EXPIRED_ERROR_MSG_str"}="Please select a credit card expiry date that is not in the past.";
$strings{"VALIDATE_INVALID_CC_ERROR_MSG_str"}="Invalid credit card number. Please enter valid credit card number.";
$strings{"VALIDATE_PAYMENT_ERROR_TITLE_str"}="Payment Method Error";
$strings{"CREATE_USER_PROGRESS_TITLE_str"}="Creating account";
$strings{"CREATE_USER_PROGRESS_MSG_str"}="Account creation in progress, please wait.";
$strings{"LOGIN_USER_PROGRESS_TITLE_str"}="Logging in";
$strings{"LOGIN_USER_PROGRESS_MSG_str"}="Login in progress, please wait.";
$strings{"SUBMITTING_ORDER_PROGRESS_TITLE_str"}="Submitting order";
$strings{"SUBMITTING_USER_PROGRESS_MSG_str"}="Order submission in progress: sending user data.\n\nPlease wait.";
$strings{"SUBMITTING_ORDER_PROGRESS_MSG_str"}="Order submission in progress: sending order info.\n\nPlease wait.";
$strings{"CONFIRM_ORDER_TITLE_str"}="Thank You";
$strings{"CONFIRM_ORDER_MSG_str"}="Thank you for shopping at Pet Market. If this were a real pet store, your order would be completed.";
$strings{"AFFILIATE_BTN_LBL_str"}="affiliate program";
$strings{"LEGAL_NOTICES_BTN_LBL_str"}="legal notices";
$strings{"ABOUT_US_BTN_LBL_str"}="about us";
$strings{"HOME_BTN_LBL_str"}="home";
$strings{"EXP_MONTH_CHOOSE_str"}="Month...";
$strings{"EXP_YEAR_CHOOSE_str"}="Year...";
doc/examples/sql/DataGlue.as view on Meta::CPAN
// test w/ combobox, listbox, tree, chart?
_global.DataGlue = function(dataProvider)
{
this.dataProvider = dataProvider;
}
// specify a format string for each line of text
_global.DataGlue.bindFormatStrings = function (dataConsumer, dataProvider, labelString, dataString)
{
var proxy = new DataGlue(dataProvider);
proxy.labelString = labelString;
proxy.dataString = dataString;
proxy.getItemAt = _global.DataGlue.getItemAt_FormatString;
dataConsumer.setDataProvider(proxy);
}
// let a user-supplied function handle formatting of each data record
_global.DataGlue.bindFormatFunction = function (dataConsumer, dataProvider, formatFunction)
{
var proxy = new DataGlue(dataProvider);
proxy.formatFunction = formatFunction;
proxy.getItemAt = _global.DataGlue.getItemAt_FormatFunction;
dataConsumer.setDataProvider(proxy);
}
_global.DataGlue.prototype.addView = function(viewRef)
{
return this.dataProvider.addView(viewRef);
}
_global.DataGlue.prototype.getLength = function()
{
return this.dataProvider.getLength();
}
_global.DataGlue.prototype.format = function(formatString, record)
{
var tokens = formatString.split("#");
var result = "";
for (var i = 0; i < tokens.length; i += 2)
{
result += tokens[i];
result += (tokens[i+1] == "") ? "#" : record[tokens[i+1]];
}
return result;
}
_global.DataGlue.getItemAt_FormatString = function(index)
{
var record = this.dataProvider.getItemAt(index);
if (record == "in progress" || record==undefined)
return record;
return {label: this.format(this.labelString, record), data: (this.dataString == null) ? record : this.format(this.dataString, record)};
}
_global.DataGlue.getItemAt_FormatFunction = function(index)
{
var record = this.dataProvider.getItemAt(index);
if (record == "in progress" || record==undefined)
return record;
return this.formatFunction(record);
}
_global.DataGlue.prototype.getItemID = function(index)
{
return this.dataProvider.getItemID(index);
}
_global.DataGlue.prototype.addItemAt = function(index, value)
{
return this.dataProvider.addItemAt(index, value);
}
_global.DataGlue.prototype.addItem = function(value)
{
return this.dataProvider.addItem(value);
}
_global.DataGlue.prototype.removeItemAt = function(index)
{
return this.dataProvider.removeItemAt(index);
}
_global.DataGlue.prototype.removeAll = function()
{
return this.dataProvider.removeAll();
}
_global.DataGlue.prototype.replaceItemAt = function(index, itemObj)
{
return this.dataProvider.replaceItemAt(index, itemObj);
}
_global.DataGlue.prototype.sortItemsBy = function(fieldName, order)
{
return this.dataProvider.sortItemsBy(fieldName, order);
}
doc/examples/sql/README.txt view on Meta::CPAN
Installation notes on the ParkServices example.
1. Make sure you have access to a mysql database and that the DBI and DBD::Mysql modules are installed.
2. Import the park.sql script into your database.
3. Don't forget to put DataGlue.as in the same directory as the Flash movie.
4. Recompile the Flash movie to point to the location of your park.pl script.
Note that normally AMF::Perl tries to guess whether you are sending a number.
And if the database used is Mysql, AMF::Perl will retrieve column types
from the statement handle. This is done so that the server could send back
primitive data types in a recordset as numbers or strings avoiding the
guessing (which may be wrong if you do intend to send a number as a string).
doc/examples/sql/park.html view on Meta::CPAN
<body>
<center>
<table cellspacing=10><tr>
<td align=left width=400 valign=top>
<H2>This is an example of <a href=http://www.simonf.com/amfperl/>AMF::Perl</a> in action.</H2>
<br>
<p>
Download Flash 6 player from <a href="http://www.macromedia.com/shockwave/download/alternates/">here</a> if you don't have it. It even works on Linux!
<p>
This is an example accessing a mysql database on the server side (taken from AMFPHP).
<br><br>
<a href=park.pl>This is the server-side Perl script park.pl.</a>
<a href=parkservices/ParkService.pm>This is a sample service ParkService.pm.</a>
</td>
<td width=600>
<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" id="park" width=550 height=350>
<PARAM NAME=movie VALUE="park.swf">
<PARAM NAME=quality VALUE=high>
doc/examples/sql/park.sql view on Meta::CPAN
ZIPCODE text,
COMPHONE text,
REGION text,
SUPTMGR text,
OFFHRS text,
DATEESTB text,
PARKTYPE text
) TYPE=MyISAM;
--
-- Dumping data for table 'tblparks'
--
INSERT INTO tblparks VALUES ('ARAHAM LINCOLN BIRTHPLACE NHS','2995 LINCOLN FARM ROAD','','','HODGENVILLE','KY','42748','502-358-3874','Southeast Region','Link, Carolyn E.','8:00 AM TO 4:45 PM','07/17/1916','National Historical Site');
INSERT INTO tblparks VALUES ('ADAMS NATIONAL HISTORIC SITE','P.O. BOX 531, 135 ADAMS STREET','','','QUINCY','MA','02269-0531','617-773-1177','NORTH ATLANTIC REGION','Peak, Marianne Potts','9:00 AM TO 5:00 PM','12/09/1946','NATIONAL HISTORICAL SITE');...
INSERT INTO tblparks VALUES ('AGATE FOSSIL BEDS NATIONAL MONUMENT','C/O SCOTTS BLUFF NATIONAL MONUMENT','P.O. BOX 27','','GERING','NE','69341-0027','308-668-2211','MIDWEST REGION','LARRY D. REED','8:00 AM TO 5:00 PM','09/26/1970','NATIONAL MONUMENT')...
INSERT INTO tblparks VALUES ('ALAGNAK WILD RIVER','C/O KATMAI NATIONAL PARK','P.O. BOX 7','','KING SALMON','AK','99613','907-246-3305','Alaska Region','BILL PIERCE','','12/02/1980','National (Wild/Senic River (Way)');
INSERT INTO tblparks VALUES ('ALASKA PUBLIC LANDS INFO CTR - ANCHORAGE','605 W. 4TH AVENUE, SUITE 105','','','ANCHORAGE','AK','99501','907-271-2737','Alaska Region','Morris, John, Acting','','08/01/1987','Miscellaneous');
INSERT INTO tblparks VALUES ('ALASKA PUBLIC LANDS INFO CTR - FAIRBANKS','250 CUSHMAN ST., SUITE 1A','','','FAIRBANKS','AK','99701','907-456-0527','Alaska Region','ROSSINI, ELIZABETH','10:00 AM TO 7:00 PM','10/13/1982','Miscellaneous');
INSERT INTO tblparks VALUES ('ALASKA REGIONAL OFFICE','NATIONAL PARK SERVICE','2525 GAMBELL STREET, ROOM 107','','ANCHORAGE','AK','99503','907-257-2690','Alaska Region','Robert D. Barber','7:30 AM TO 4:30 PM','12/03/1980','Regional Office');
doc/examples/sql/parkservices/ParkService.pm view on Meta::CPAN
package ParkService;
use warnings;
use strict;
use AMF::Perl::Sql::MysqlRecordSet;
my $dbhost = "localhost";
my $dbname = "database";
my $dbuser = "user";
my $dbpass = "password";
use DBI;
sub new
{
my ($proto) = @_;
my $self = {};
bless $self, $proto;
doc/index.html view on Meta::CPAN
<br>
September 19, 2004. <a href="AMF-0.04.tar.gz">An alpha implementation of AMF in <B style="color:black;background-color:#A0FFFF">Python</B>. Version 0.04.</a>
<br><br>
<a href="code.html">Usage instructions and code samples.</a><br>
<br>
<h2>What is this?</h2>
<h3> Short version<br>
</h3>
<a href="http://www.macromedia.com/software/flashremoting/">Flash
Remoting</a> is a way for Flash movies running in a web browser to
request structured data from the web server. The following data types
are supported - strings, numbers, dates, arrays, dictionaries/hashes,
objects, recordsets. Flash clients talk with the server using the AMF
protocol, which is proprietary to Macromedia. However, it's not that
hard to decode. <br>
<br>
Using AMF::Perl, it is possible to send arbitrary
data between client and server using very few lines of code. There is no
need to pack complicated data structures into CGI form parameteres or
XML strings. The coding time can be spent on better things - data
preparation and graphical presentation, not data delivery.<br>
<br>
<h3>Long version</h3>
<p>HTML forms are ugly. HTML itself is not well suited for presenting
data. Everybody knows that but still uses them. However, the Rich
Internet Client is back and it gets adopted more and more. In
part this has to do with Macromedia's eforts. <br>
<br>
<p>Macromedia Flash has matured enough to <br>
a) allow developers to build rich, visually attractive user interfaces
and <br>
b) receive data from the server in a convenient way.<br>
<p>But if you believe in the idea of more and more programmers
taking a shot at developing clients in Flash, you must also see the need
for a good data gateway between web clients (the Flash movie) and web
servers. Macromedia offers just that in Macromedia Flash Remoting,
available for ColdFusion, JRun, .NET, J2EE. </p>
<p>The Macromedia development tools are neither free nor
open-source. The server costs go into thousands. (There are
fully-fuctional trial versions available, though.)<br>
However, by using Perl to implement the server-side part of the
gateway, that part of the solution becomes free.<br>
</p>
<p> <a href="http://www.macromedia.com/software/flashremoting/">Flash
Remoting</a> protocol (AMF) is similar to SOAP, but the protocol
complexities are hidden from the developer. On the client side you call
a local function, and your call is passed to the corresponding function
on the server. Another function, a callback, is invoked by the framework
when the data is received. On the server side you provide a handler
with a certain name that registers certain functions, available to be
used by the client. Everything on the server side is within the syntax
of the server language. The client side uses ActionScript. <a
href="code.html">This is what the code looks like.</a><br>
To build/export .swf files with Flash Remoting, you need to install
Flash Remoting MX Components for free at:<br>
http://www.macromedia.com/software/flashremoting/downloads/components/
<br>
This will install the scripts "NetServices.as" and "NetDebug.as" that are
used in the ActionScript.
doc/index.html view on Meta::CPAN
<p>Please respond if you are interested either in using AMF::Perl or in
contributing to it.<br>
<br>
<br>
</td>
<td style="vertical-align: top;width: 400px">
<h2>Examples</h2>
<ul>
<li><a href="examples/cpu/cpu.html">CPU Usage</a>
<br><br>
<li><a href=examples/dataGrid/dataGrid.html>Data grid</a> that gets its data from the server as an array of objects.
<br><br>
<li><a href=examples/basic/basic.html>Service discovery example</a>. It sends data from client to server and back. Now with exception handling!
<br><br>
<li><a href=examples/sql/park.html>Accessing a Mysql database</a>
<br><br>
<li><a href=examples/petmarket/index.html><font color=red>PETMARKET!!!</font></a>
</ul>
<h2>Applications</h2>
<ul>
<li>AMF::Perl is used for <a href=http://www.dnai.org/geneboy/>Geneboy</a>, a genetics educational tool written in Flash.
<li><a href=http://www.artificially-intelligent.com/lyrics/
>Collaborative music lyrics editor</a> by Dave Waller
<li><a href=http://www.greetme.com>Animated greetings</a> by Jonathan Buhacoff.
</ul>
doc/updates.html view on Meta::CPAN
<br><br>Jul 06, 2004. Version 0.13 uploaded. Small bug fixes, exception handling.
<br><br>Apr 29, 2004. Version 0.12 uploaded. Changed "use Apache2" to "require Apache2".
<br><br>Apr 24, 2004. Flash::FLAP renamed to AMF::Perl. Version 0.11 uploaded (0.10 was an interim release). Hopefully complete mod_perl 1 and 2 handling. Mysql column type determination.
<br><br>Mar 13, 2004. Version 0.09 uploaded. Fixed a couple of "uninitialized" warnings, accepted patches for POD documentation, smarter detection of numbers and dates in Serializer and text encoding.
<br><br>Aug 3, 2003. Version 0.08 uploaded. Petstore example implemented!!! Also, rewrote Flash::FLAP::new() to accept both Flash::FLAP->new and $flap->new.
<br><br>Jul 26, 2003. Version 0.07 uploaded. Fixed a bug that would wrongly detect end-of-file in the input data on Windows and replaced the "our" keyword that is not backwards-compatible. Created pseudo_query() in Util::Object that encapsulates th...
<br><br>Jun 22, 2003. Version 0.06 uploaded. Added an example that talks to a database on the server side. This is implemented via Flash::FLAP::Sql::MysqlRecordSet.pm. Got rid of a couple of "uninitialized" warnings.
<br><br>Apr 29, 2003. Version 0.05 uploaded. It supports Windows and mod_perl 1.
<br><br>Apr 14, 2003 - FLAP renamed to Flash::FLAP. Version 0.03 uploaded. Added ser
vice discovery - now you can register a directory and put Perl packages in it. Every
package will be considered a service. Macromedia Service Browser support added.
<br>
<br>
Mar 11, 2003 - FLAP-0.02 uploaded. Verified trasfer of basic data types from Flash to Perl. Parameters are now sent to Perl functions as an array, not an array ref.
</tr>
</tbody>
</table>
</div>
<br>
<br>
</body>
</html>
lib/AMF/Perl.pm view on Meta::CPAN
$gateway->service();
=head1 ABSTRACT
Macromedia Flash Remoting server-side support.
=head1 DESCRIPTION
This file accepts the data and deserializes it using the InputStream and Deserializer classes.
Then the gateway builds the executive class which then loads the targeted class file
and executes the targeted method via flash remoting.
After the target uri executes the the gateway determines the data type of the data
and serializes and returns the data back to the client.
=head2 EXPORT
None by default.
=head1 SEE ALSO
There is a mailing list for AMF::Perl. You can subscribe here:
http://lists.sourceforge.net/lists/listinfo/flaph-general
lib/AMF/Perl.pm view on Meta::CPAN
=head1 COPYRIGHT AND LICENSE
Copyright (c) 2003 by Vsevolod (Simon) Ilyushchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
The code is based on the -PHP project (http://amfphp.sourceforge.net/)
ORIGINAL PHP Remoting CONTRIBUTORS
Musicman - original design
Justin - gateway architecture, class structure, datatype io additions
John Cowen - datatype io additions, class structure
Klaasjan Tukker - modifications, check routines, and register-framework
==head1 CHANGES
=head2 Sun Jul 11 18:45:40 EDT 2004
=item Chaned eval{} and amf_throw() to enable die() to work as well (instead of amf_throw()).
=head2 Sun Jun 20 13:32:31 EDT 2004
lib/AMF/Perl.pm view on Meta::CPAN
=item Another patch from Kostas Chatzikokolakis fixing MP2 issues.
=back
=head2 Sat Mar 13 16:25:00 EST 2004
=over 4
=item Patch from Kostas Chatzikokolakis handling encoding.
=item Changed non-mod_perl behavior for reading POST data from using <> to using read()
to work around a bug in IIS
=item Joined code for mod_perl 1 and 2. Separated the output code for the mod_perl and non-mod_perl
cases.
=back
=head2 Sat Aug 2 14:01:15 EDT 2003
=over 4
lib/AMF/Perl.pm view on Meta::CPAN
sub _service
{
my ($self, $content) = @_;
if($self->debug)
{
# WATCH OUT, THIS IS NOT THREAD SAFE, DON'T USE IN CONCURRENT ENVIRONMENT
# temporary load the contents from a file
$content = $self->_loadRawDataFromFile($self->debugDir."/input.amf");
# save the raw amf data to a file
#$self->_saveRawDataToFile ($self->debugDir."/input.amf", $content);
}
# build the input stream object from the file contents
my $inputStream = new AMF::Perl::IO::InputStream($content);
# build the deserializer and pass it a reference to the inputstream
my $deserializer = new AMF::Perl::IO::Deserializer($inputStream, $self->{encoding});
# get the returned Object
lib/AMF/Perl.pm view on Meta::CPAN
# save the result in our amfout object
$amfout->addBody($body->{"response"}.$self->{"response"}, "null", $results, $returnType);
}
# create a new output stream
my $outstream = new AMF::Perl::IO::OutputStream ();
# create a new serializer
my $serializer = new AMF::Perl::IO::Serializer ($outstream, $self->{encoding});
# serialize the data
$serializer->serialize($amfout);
if(0)
{
# save the raw data to a file for debugging
$self->_saveRawDataToFile ($self->debugDir."/results.amf", $outstream->flush());
}
# send the correct header
my $response = $outstream->flush();
#Necessary on Windows to prevent conversion of 0a to 0d0a.
binmode STDOUT;
$self->output($response);
lib/AMF/Perl.pm view on Meta::CPAN
}
sub encoding
{
my $self = shift;
$self->{encoding} = shift if @_;
return $self->{encoding};
}
# usefulldebugging method
# You can save the raw data sent from the
# flash client by calling
# $self->_saveRawDataToFile("file.amf", $contents);
sub _saveRawDataToFile
{
my ($self, $filepath, $data)=@_;
# open the file for writing
if (!open(HANDLE, "> $filepath"))
{
die "Could not open file $filepath: $!\n";
}
# write to the file
if (!print HANDLE $data)
{
die "Could not print to file $filepath: $!\n";
}
# close the file resource
close HANDLE;
}
sub _appendRawDataToFile
{
my ($self, $filepath, $data) = @_;
# open the file for writing
if (!open (HANDLE, ">>$filepath"))
{
die "Could not open file $filepath: $!\n";
}
# write to the file
if (!print HANDLE $data)
{
die "Could not print to file $filepath: $!\n";
}
# close the file resource
close HANDLE;
}
# get contents of a file into a string
sub _loadRawDataFromFile
lib/AMF/Perl/IO/Deserializer.pm view on Meta::CPAN
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
# The code is based on the -PHP project (http://amfphp.sourceforge.net/)
=head1 NAME
AMF::Perl::IO::Deserializer
=head1 DESCRIPTION
Package used to turn the binary data into physical perl objects.
=head1 CHANGES
=head2 Sun Sep 19 13:01:35 EDT 2004
=item Patch from Kostas Chatzikokolakis about error checking of input data length.
=head2 Sat Mar 13 16:31:31 EST 2004
=item Patch from Kostas Chatzikokolakis handling encoding.
=head2 Sun Mar 9 18:17:31 EST 2003
=item The return value of readArray should be \@ret, not @ret.
=head2 Tue Mar 11 21:55:41 EST 2003
lib/AMF/Perl/IO/Deserializer.pm view on Meta::CPAN
sub floor
{
my $n = shift;
return int($n) - ($n < 0 ? 1: 0) * ($n != int($n) ? 1 : 0);
}
#******************** PUBLIC METHODS ****************************/
# constructor that also dserializes the raw data
sub new
{
my ($proto, $is, $encoding)=@_;
my $self = {};
bless $self, $proto;
# the object to store the deserialized data
$self->{amfdata} = new AMF::Perl::Util::Object();
# save the input stream in this object
$self->{inputStream} = $is;
# save the encoding in this object
$self->{encoding} = $encoding;
# read the binary header
$self->readHeader();
# read the binary body
$self->readBody();
return $self;
}
# returns the instance of the Object package
sub getObject
{
my ($self)=@_;
return $self->{amfdata};
}
#******************** PRIVATE METHODS ****************************/
sub readHeader
{
my ($self)=@_;
# ignore the first two bytes -- version or something
$self->{inputStream}->readInt();
# find the total number of header elements
lib/AMF/Perl/IO/Deserializer.pm view on Meta::CPAN
# loop over all of the header elements
while($self->{header_count}--)
{
my $name = $self->{inputStream}->readUTF();
# find the must understand flag
my $required = $self->readBoolean();
# grab the length of the header element
my $length = $self->{inputStream}->readLong();
# grab the type of the element
my $type = $self->{inputStream}->readByte();
# turn the element into real data
my $content = $self->readData($type);
# save the name/value into the headers array
$self->{amfdata}->addHeader($name, $required, $content);
}
}
sub readBody
{
my ($self)=@_;
# find the total number of body elements
$self->{body_count} = $self->{inputStream}->readInt();
# loop over all of the body elements
while($self->{body_count}--)
{
my $method = $self->readString();
# the target that the client understands
my $target = $self->readString();
# grab the length of the body element
my $length = $self->{inputStream}->readLong();
# grab the type of the element
my $type = $self->{inputStream}->readByte();
# turn the argument elements into real data
my $data = $self->readData($type);
# add the body element to the body object
$self->{amfdata}->addBody($method, $target, $data);
}
}
# reads an object and converts the binary data into a Perl object
sub readObject
{
my ($self)=@_;
# init the array
my %ret;
# grab the key
my $key = $self->{inputStream}->readUTF();
for (my $type = $self->{inputStream}->readByte(); $type != 9; $type = $self->{inputStream}->readByte())
{
die "Malformed AMF data, no object end byte" unless defined($type);
# grab the value
my $val = $self->readData($type);
# save the name/value pair in the array
$ret{$key} = $val;
# get the next name
$key = $self->{inputStream}->readUTF();
}
# return the array
return \%ret;
}
# reads and array object and converts the binary data into a Perl array
sub readArray
{
my ($self)=@_;
# init the array object
my @ret;
# get the length of the array
my $length = $self->{inputStream}->readLong();
die "Malformed AMF data, array length too big" if $length > $self->{inputStream}{content_length};
# loop over all of the elements in the data
for (my $i=0; $i<$length; $i++)
{
# grab the type for each element
my $type = $self->{inputStream}->readByte();
# grab each element
push @ret, $self->readData($type);
}
# return the data
return \@ret;
}
sub readCustomClass
{
my ($self)=@_;
# grab the explicit type -- I'm not really convinced on this one but it works,
# the only example i've seen is the NetDebugConfig object
my $typeIdentifier = $self->{inputStream}->readUTF();
# the rest of the bytes are an object without the 0x03 header
lib/AMF/Perl/IO/Deserializer.pm view on Meta::CPAN
# see debugger readout ???
return $self->{inputStream}->readInt();
}
sub readASObject
{
my ($self)=@_;
#object Button, object Textformat, object Sound, object Number, object Boolean, object String,
#SharedObject unflushed, XMLNode, used XMLSocket??, NetConnection,
#SharedObject.data, SharedObject containing 'private' properties
#the final byte seems to be the dataType -> 0D
return undef;
}
# main switch function to process all of the data types
sub readData
{
my ($self, $type) = @_;
my $data;
#print STDERR "Reading data of type $type\n";
if ($type == 0) # number
{
$data = $self->readNumber();
}
elsif ($type == 1) # boolean
{
$data = $self->readBoolean();
}
elsif ($type == 2) # string
{
$data = $self->readString();
}
elsif ($type == 3) # object Object
{
$data = $self->readObject();
}
elsif ($type == 5) # null
{
$data = undef;
}
elsif ($type == 6) # undefined
{
$data = undef;
}
elsif ($type == 7) # flushed SharedObject containing 'public' properties
{
$data = $self->readFlushedSO();
}
elsif ($type == 8) # array
{
# shared object format only (*.sol)
# only time I saw it was the serverinfo value in a ColdFusion RecordSet
# It was just four zeroes - skip them.
for (my $i=0; $i<4; $i++)
{
$self->{inputStream}->readByte();
}
}
elsif ($type == 10) # array
{
$data = $self->readArray();
}
elsif ($type == 11) # date
{
$data = $self->readDate();
}
elsif ($type == 13) # mainly internal AS objects
{
$data = $self->readASObject();
}
elsif ($type == 15) # XML
{
$data = $self->readXML();
}
elsif ($type == 16) # Custom Class
{
$data = $self->readCustomClass();
}
else # unknown case
{
print STDERR "Unknown data type: $type\n";
}
return $data;
}
1;
lib/AMF/Perl/IO/InputStream.pm view on Meta::CPAN
# under the same terms as Perl itself.
# The code is based on the -PHP project (http://amfphp.sourceforge.net/)
=head1 NAME
AMF::Perl::IO::InputStream
=head1 DESCRIPTION
InputStream package built to handle getting the binary data from the raw input stream.
=head1 CHANGES
=head2 Sun Sep 19 13:01:35 EDT 2004
=item Patch from Kostas Chatzikokolakis about error checking of input data length.
=head2 Tue Jun 22 19:28:30 EDT 2004
=item Improved the check in readDouble to append "0" to the string instead of skipping
the value. Otherwise the number 16 did not go through.
=item Added defined($thisByte) in readInt, otherwise the character "0" (say, in string length of 30)
did not go through.
=head2 Sat Mar 13 16:39:29 EST 2004
=item Changed calls to ord() in readByte() and concatenation readDouble()
lib/AMF/Perl/IO/InputStream.pm view on Meta::CPAN
#InputStream constructor
sub new
{
my ($proto, $rd )=@_;
my $self={};
bless $self, $proto;
$self->{current_byte}=0;
# store the stream in this object
my @array = split //, $rd;
$self->{raw_data} = \@array;
# grab the total length of this stream
$self->{content_length} = @{$self->{raw_data}};
if (unpack("h*", pack("s", 1)) =~ /01/)
{
$self->{byteorder} = 'big-endian';
}
else
{
$self->{byteorder} = 'little-endian';
}
return $self;
}
# returns a single byte value.
sub readByte
{
my ($self)=@_;
# boundary check
die "Malformed AMF data, cannot readByte\n"
if $self->{current_byte} > $self->{content_length} - 1;
# return the next byte
my $nextByte = $self->{raw_data}->[$self->{current_byte}];
my $result;
$result = ord($nextByte) if $nextByte;
$self->{current_byte} += 1;
return $result;
}
# returns the value of 2 bytes
sub readInt
{
my ($self)=@_;
# boundary check
die "Malformed AMF data, cannot readInt\n"
if $self->{current_byte} > $self->{content_length} - 2;
# read the next 2 bytes, shift and add
my $thisByte = $self->{raw_data}->[$self->{current_byte}];
my $nextByte = $self->{raw_data}->[$self->{current_byte}+1];
my $thisNum = defined($thisByte) ? ord($thisByte) : 0;
my $nextNum = defined($nextByte) ? ord($nextByte) : 0;
my $result = (($thisNum) << 8) | $nextNum;
$self->{current_byte} += 2;
return $result;
}
# returns the value of 4 bytes
sub readLong
{
my ($self)=@_;
# boundary check
die "Malformed AMF data, cannot readLong\n"
if $self->{current_byte} > $self->{content_length} - 4;
my $byte1 = $self->{current_byte};
my $byte2 = $self->{current_byte}+1;
my $byte3 = $self->{current_byte}+2;
my $byte4 = $self->{current_byte}+3;
# read the next 4 bytes, shift and add
my $result = ((ord($self->{raw_data}->[$byte1]) << 24) |
(ord($self->{raw_data}->[$byte2]) << 16) |
(ord($self->{raw_data}->[$byte3]) << 8) |
ord($self->{raw_data}->[$byte4]));
$self->{current_byte} = $self->{current_byte} + 4;
return $result;
}
sub readDouble
{
my ($self)=@_;
# boundary check
die "Malformed AMF data, cannot readDouble\n"
if $self->{current_byte} > $self->{content_length} - 8;
# container to store the reversed bytes
my $invertedBytes = "";
if ($self->{byteorder} eq 'little-endian')
{
# create a loop with a backwards index
for(my $i = 7 ; $i >= 0 ; $i--)
{
# grab the bytes in reverse order from the backwards index
my $nextByte = $self->{raw_data}->[$self->{current_byte}+$i];
$nextByte = "0" unless $nextByte;
$invertedBytes .= $nextByte;
}
}
else
{
for(my $i = 0 ; $i < 8 ; $i++)
{
# grab the bytes in forwards order
my $nextByte = $self->{raw_data}->[$self->{current_byte}+$i];
$nextByte = "0" unless $nextByte;
$invertedBytes .= $nextByte;
}
}
# move the seek head forward 8 bytes
$self->{current_byte} += 8;
# unpack the bytes
my @zz = unpack("d", $invertedBytes);
# return the number from the associative array
return $zz[0];
}
# returns a UTF string
sub readUTF
{
my ($self) = @_;
# get the length of the string (1st 2 bytes)
my $length = $self->readInt();
# boundary check
die "Malformed AMF data, cannot readUTF\n"
if $self->{current_byte} > $self->{content_length} - $length;
# grab the string
my @slice = @{$self->{raw_data}}[$self->{current_byte}.. $self->{current_byte}+$length-1];
my $val = join "", @slice;
# move the seek head to the end of the string
$self->{current_byte} += $length;
# return the string
return $val;
}
# returns a UTF string with a LONG representing the length
sub readLongUTF
{
my ($self) = @_;
# get the length of the string (1st 4 bytes)
my $length = $self->readLong();
# boundary check
die "Malformed AMF data, cannot readLongUTF\n"
if $self->{current_byte} > $self->{content_length} - $length;
# grab the string
my @slice = @{$self->{raw_data}}[$self->{current_byte} .. $self->{current_byte}+$length-1];
my $val = join "", @slice;
# move the seek head to the end of the string
$self->{current_byte} += $length;
# return the string
return $val;
}
1;
lib/AMF/Perl/IO/Serializer.pm view on Meta::CPAN
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
# The code is based on the -PHP project (http://amfphp.sourceforge.net/)
=head1 NAME
AMF::Perl::IO::Serializer
=head1 DESCRIPTION
Class used to convert physical perl objects into binary data.
=head1 CHANGES
=head2 Sun May 23 12:35:19 EDT 2004
=item Changed deduceType() to return the value too, as it may be changed inside, and to
handle empty string ('') as a string.
=head2 Wed Apr 14 11:06:28 EDT 2004
=item Made basic data type determination work for both scalars and scalarrefs.
=item Now we check if we are sending a recordset and setting column types accordingly.
=head2 Sat Mar 13 16:25:00 EST 2004
=item Patch from Tilghman Lesher that detects numbers and dates in strings
and sets return type accordingly.
=item Patch from Kostas Chatzikokolakis handling encoding and sending null value.
=head2 Sun May 11 16:43:05 EDT 2003
=item Changed writeData to set type to "NULL" when the incoming data is undef. Previously
it became a String, just like other scalars.
=item Changed PHP's writeRecordset to a generic writeAMFObject. Verified Recordset support.
=head2 Sun Mar 9 18:20:16 EST 2003
=item Function writeObject should return the same as writeHash. This assumes that all meaningful data
are stored as hash keys.
=cut
use strict;
use Encode qw/from_to/;
use DBI;
# holder for the data
my $data;
sub new
{
my ($proto, $stream, $encoding) = @_;
# save
my $self={};
bless $self, $proto;
$self->{out} = $stream;
$self->{encoding} = $encoding;
return $self;
lib/AMF/Perl/IO/Serializer.pm view on Meta::CPAN
sub writeBody
{
my ($self, $i)=@_;
my $body = $self->{amfout}->getBodyAt($i);
# write the responseURI header
$self->{out}->writeUTF($body->{"target"});
# write null, haven't found another use for this
$self->{out}->writeUTF($body->{"response"});
# always, always there is four bytes of FF, which is -1 of course
$self->{out}->writeLong(-1);
# write the data to the output stream
$self->writeData($body->{"value"}, $body->{"type"});
}
# writes a boolean
sub writeBoolean
{
my ($self, $d)=@_;
# write the boolean flag
$self->{out}->writeByte(1);
# write the boolean byte
lib/AMF/Perl/IO/Serializer.pm view on Meta::CPAN
# grab the total number of elements
my $len = scalar(@$d);
# write the numeric array code
$self->{out}->writeByte(10);
# write the count of items in the array
$self->{out}->writeLong($len);
# write all of the array elements
for(my $i=0 ; $i < $len ; $i++)
{
#If this is a basic data type in a recordset, consider the column type.
if (!(ref $d->[$i]) && $self->{__writingRecordset__})
{
my $type = $self->{__columnTypes__}->[$i];
$self->dispatchBySqlType($d->[$i], $type);
}
else
{
$self->writeData($d->[$i]);
}
}
}
sub dispatchBySqlType
{
my ($self, $data, $type) = @_;
if ($type && ($type == DBI::SQL_NUMERIC) || ($type == DBI::SQL_DECIMAL) || ($type == DBI::SQL_INTEGER) || ($type == DBI::SQL_SMALLINT) || ($type == DBI::SQL_FLOAT) || ($type == DBI::SQL_DOUBLE) || ($type == DBI::SQL_REAL))
{
$self->writeNumber($data);
}
else
{
$self->writeString($data);
}
}
sub writeHash
{
my ($self, $d) = @_;
# this is an object so write the object code
$self->{out}->writeByte(3);
# write the object name/value pairs
$self->writeObject($d);
}
# writes an object to the stream
sub writeObject
{
my ($self, $d)=@_;
# loop over each element
while ( my ($key, $data) = each %$d)
{
# write the name of the object
$self->{out}->writeUTF($key);
if ($self->{__columnTypes__} && $key eq "initialData")
{
$self->{__writingRecordset__} = 1;
}
# write the value of the object
$self->writeData($data);
$self->{__writingRecordset__} = 0;
}
# write the end object flag 0x00, 0x00, 0x09
$self->{out}->writeInt(0);
$self->{out}->writeByte(9);
}
# write an AMF object
# The difference with regular object is that the code is different
# and the class name is explicitly sent. Good for RecordSets.
sub writeAMFObject
{
my ($self, $object)=@_;
# write the custom package code
$self->{out}->writeByte(16);
# write the package name
$self->{out}->writeUTF($object->{_explicitType});
$self->{__columnTypes__} = $object->{__columnTypes__} if $object->{__columnTypes__};
# write the package's data
$self->writeObject($object);
delete $self->{__columnTypes__};
}
# main switch for dynamically determining the data type
# this may prove to be inadequate because perl isn't a typed
# language and some confusion may be encountered as we discover more data types
# to be passed back to flash
#All scalars are assumed to be strings, not numbers.
#Regular arrays and hashes are prohibited, as they are indistinguishable outside of perl context
#Only arrayrefs and hashrefs will work
# were still lacking dates, xml, and strings longer than 65536 chars
sub writeData
{
my ($self, $d, $type)=@_;
$type = "unknown" unless $type;
# **************** TO DO **********************
# Since we are now allowing the user to determine
# the datatype we have to validate the user's suggestion
# vs. the actual data being passed and throw an error
# if things don't check out.!!!!
# **********************************************
# get the type of the data by checking its reference name
#if it was not explicitly passed
if ($type eq "unknown")
{
if (!defined $d) # convert undef to null, but not "" or 0
{
$type = "NULL";
}
else
{
my $myRef = ref $d;
lib/AMF/Perl/Sql/MysqlRecordSet.pm view on Meta::CPAN
my $columnNames = $sth->{NAME};
my $columnTypes = $sth->{TYPE};
# grab all of the rows
# There is a reason arrayref is not used - if it is,
#the pointer is reused and only the last element gets added, though many times.
while (my @array = $sth->fetchrow_array)
{
# add each row to the initial data array
push @initialData, \@array;
}
return AMF::Perl::Util::Object->pseudo_query($columnNames, \@initialData, $columnTypes);
}
1;
lib/AMF/Perl/Util/Object.pm view on Meta::CPAN
# returns the body element at a specific index
sub getBodyAt
{
my ($self, $id)=@_;
$id=0 unless $id;
return $self->{_bodies}->[$id];
}
sub pseudo_query
{
my ($self, $columnNames, $data, $columnTypes) = @_;
my $result = new AMF::Perl::Util::Object;
# create the serverInfo array
$result->{"serverInfo"} = {};
# create an initialData array
my (@initialData, @columnNames);
$result->{serverInfo}->{initialData} = $data;
$result->{serverInfo}->{columnNames} = $columnNames;
$result->{serverInfo}->{totalCount}= scalar @$data;
# create the id field --> i think this is used for pageable recordsets
$result->{"serverInfo"}->{"id"} = "AMF::Perl";
$result->{"serverInfo"}->{"cursor"} = 1; # maybe the current record ????
$result->{"serverInfo"}->{"serviceName"} = "doStuff"; # in CF this is PageAbleResult not here
# versioning
$result->{"serverInfo"}->{"version"} = 1;
$result->{_explicitType}='RecordSet';