I've been banging my head off an issue for some time now.
I'm working on a childrens game (flash as3) in which stories, poems, songs, etc are read to the child. There's a voice recording reading/singing the text, the text highlights as the words are spoken/sung. The child may toggle on and off the voice and word highlighting independantly. The child may also opt to make their own recording. Now said recording works fine. I'm able to capture it from the mic and the child may play it back no problem.
The issue lies in that the client wants the child to be able to save this recording to a web server.
I thought I had the issue solved by using a URLRequest and URLLoader object. The mp3 was showing up in the specified folder on the webserver. I played it with a media player and it worked. The child could also load said file no problem.
THEN, when I tried it via browser(instead of flash player) I got the dreaded sandbox error. The only way such an operation with said objects can occur in a browser environment is if it's user initiated via a dialogue window. This is children were talking about and we're not saving locally anyway.
The child is provided 3 save slots which they click on (WSprites). Which technically is user initiated, but flash has no way of knowing that. The 3 save slots hold the sounds in memory and only change when the user records or loads. When the user saves, they get sent off to php to save.
Now I did try using js as a middleman, but I ended up losing my bytes in the process and my js and php are probly the weakest areas of all my programming skills.
My question is, does anyone know a way of sending a byte array off to php without setting off the sandbox. (preferably without js, but if I have to I have to)
Below is the php script:
<?php
$default_path = 'images/';
// check to see if a path was sent in from flash //
$target_path = ($_POST['dir']) ? $_POST['dir'] : $default_path;
if (!file_exists($target_path)) mkdir($target_path, 0777, true);
// full path to the saved image including filename //
$destination = $target_path . basename( $_FILES[ 'Filedata' ][ 'name' ] );
// move the image into the specified directory //
if (move_uploaded_file($_FILES[ 'Filedata' ][ 'tmp_name' ], $destination)) {
echo "The file " . basename( $_FILES[ 'Filedata' ][ 'name' ] ) . " has been uploaded;";
} else {
echo "FILE UPLOAD FAILED";
}
?>
Below is the as3 method that interacts with it:
public function save(slotNum:uint, byteArray:ByteArray, fileName:String,
$destination:String = null, $script:String=null,
parameters:Object = null):void
{
//trace("this happens"); //debug
_curRecordSlot = slotNum; //set slot number
_recorder = _recordSlots[_curRecordSlot]; //set recorder to new slot
_saveFileName = "recording" + _curRecordSlot.toString() + ".mp3"; //set recording file name
var i: int;
var bytes:String;
var postData:ByteArray = new ByteArray();
postData.endian = Endian.BIG_ENDIAN;
var ldr:URLLoader = new URLLoader(); //instantiate a url loader
ldr.dataFormat = URLLoaderDataFormat.BINARY; //set loader format
_request = new URLRequest(); //reinstantiate request
_request.url = $script; //set path to upload script
//add Filename to parameters
if (parameters == null)
{
parameters = new Object();
}
parameters.Filename = fileName;
//add parameters to postData
for (var name:String in parameters)
{
postData = BOUNDARY(postData);
postData = LINEBREAK(postData);
bytes = 'Content-Disposition: form-data; name="' + name + '"';
for ( i = 0; i < bytes.length; i++ )
{
postData.writeByte( bytes.charCodeAt(i) );
}
postData = LINEBREAK(postData);
postData = LINEBREAK(postData);
postData.writeUTFBytes(parameters[name]);
postData = LINEBREAK(postData);
}
//add img destination directory to postData if provided //
if ($destination)
{
postData = BOUNDARY(postData);
postData = LINEBREAK(postData);
bytes = 'Content-Disposition: form-data; name="dir"';
for ( i = 0; i < bytes.length; i++ )
{
postData.writeByte( bytes.charCodeAt(i) );
}
postData = LINEBREAK(postData);
postData = LINEBREAK(postData);
postData.writeUTFBytes($destination);
postData = LINEBREAK(postData);
}
//add Filedata to postData
postData = BOUNDARY(postData);
postData = LINEBREAK(postData);
bytes = 'Content-Disposition: form-data; name="Filedata"; filename="';
for ( i = 0; i < bytes.length; i++ )
{
postData.writeByte( bytes.charCodeAt(i) );
}
postData.writeUTFBytes(fileName);
postData = QUOTATIONMARK(postData);
postData = LINEBREAK(postData);
bytes = 'Content-Type: application/octet-stream';
for ( i = 0; i < bytes.length; i++ )
{
postData.writeByte( bytes.charCodeAt(i) );
}
postData = LINEBREAK(postData);
postData = LINEBREAK(postData);
postData.writeBytes(byteArray, 0, byteArray.length);
postData = LINEBREAK(postData);
//add upload file to postData
postData = LINEBREAK(postData);
postData = BOUNDARY(postData);
postData = LINEBREAK(postData);
bytes = 'Content-Disposition: form-data; name="Upload"';
for ( i = 0; i < bytes.length; i++ )
{
postData.writeByte( bytes.charCodeAt(i) );
}
postData = LINEBREAK(postData);
postData = LINEBREAK(postData);
bytes = 'Submit Query';
for ( i = 0; i < bytes.length; i++ )
{
postData.writeByte( bytes.charCodeAt(i) );
}
postData = LINEBREAK(postData);
//closing boundary
postData = BOUNDARY(postData);
postData = DOUBLEDASH(postData);
//finally set up the urlrequest object //
_request.data = postData;
_request.contentType = 'multipart/form-data; boundary=' + _boundary;
_request.method = URLRequestMethod.POST;
_request.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );
//add listener to listen for completion
ldr.addEventListener(Event.COMPLETE, onSaveComplete, false, 0, true);
//add listener for io errors
ldr.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false, 0, true);
//add listener for security errors
ldr.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError, false,
0, true);
ldr.load(_request); //load the file
}
The above code works great in a flash player, but triggers sandbox error in browser.
Edit:
As requested here is my embed code(i replaced anywhere that had the name of the game with TITLEOFGAME):
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>TITLEOFGAME</title>
<meta name="description" content="" />
<script src="js/swfobject.js"></script>
<script>
var flashvars = {
};
var params = {
menu: "false",
scale: "noScale",
allowFullscreen: "true",
allowScriptAccess: "always",
bgcolor: "",
wmode: "direct" // can cause issues with FP settings & webcam
};
var attributes = {
id:"TITLEOFGAME"
};
swfobject.embedSWF(
"Hub.swf",
"altContent", "900", "506", "10.0.0",
"expressInstall.swf",
flashvars, params, attributes,
{name:"TITLEOFGAME"}
);
</script>
<style>
html, body { height:100%; overflow:hidden; }
body { margin:0; }
</style>
</head>
<body>
<div id="altContent">
<h1>TITLEOFGAME</h1>
<p><a href="http://www.adobe.com/go/getflashplayer">Get Adobe Flash
player</a></p> //this line was just moved down for limitations text input for
//this post
</div>
</body>
</html>