6

I have a video player built in AS3. I take a snapshot of the video player using this code:

var uploadUrl = 'http://localhost:8000/assets/uploadframegrab';
var bitmap = new Bitmap();        
var graphicsData : Vector.<IGraphicsData>;
graphicsData = container.graphics.readGraphicsData();
bitmap.bitmapData = GraphicsBitmapFill(graphicsData[0]).bitmapData;

var jpgEncoder:JPGEncoder = new JPGEncoder(85);
var jpgStream:ByteArray = jpgEncoder.encode(bitmap.bitmapData);

var loader:URLLoader = new URLLoader();
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var csrf:URLRequestHeader = new URLRequestHeader("X-CSRF-Token", csrfToken);        
var request:URLRequest = new URLRequest(uploadUrl);
request.requestHeaders.push(header);
request.requestHeaders.push(csrf);
request.method = URLRequestMethod.POST;
request.data = jpgStream;
loader.load(request);

I need to upload the encoded to JPG using one of my Laravel routes. My route looks like:

Route::post('assets/uploadframegrab', 'AssetController@uploadFramegrab');

When I run the AS3 code, it calls the laravel route, but my $request variable appears to be empty. The Request Payload property on the network info tab that shows all my headers and stuff contains what looks like the source of the image file.

If I do a return Response::json(['filedata' => $request]); all I get is this:

filedata: {
  attributes: {},
  request: {},
  query: {},
  server: {},
  files: {},
  cookies: {},
  headers: {}
}

My uploadFramegrab function is simply this for now:

public function uploadFramegrab(Request $request)
{
  if ($request)
  {
    return Response::json(['filedata' => $request]);
  }
  else
  {
    return Response::json(['error' => 'no file uploaded']);
  }
}

I've searched online but I cannot find anything specifically for uploading from flash to laravel. I've done it javascript to laravel no problem. Anyone know what this could be? If you'd like more information please ask.

akmozo
  • 9,829
  • 3
  • 28
  • 44
Ronnie
  • 11,138
  • 21
  • 78
  • 140
  • You can [exclude your route from CSRF protection](http://laravel.com/docs/master/routing#csrf-excluding-uris). – akmozo Sep 18 '15 at 18:29
  • Yes, that's of course better, using a `X-CSRF-TOKEN` header. – akmozo Sep 18 '15 at 18:41
  • @akmozo I've updated my question to reflect where I am currently at with this issue – Ronnie Sep 18 '15 at 19:09
  • Should content type be `multipart/form-data` instead? – approxiblue Sep 21 '15 at 21:20
  • @approxiblue I've tried using that as the content type but still no luck. `$request` is still empty. I am curious as to why the image is being shown in a `Request payload` format. I haven't seen data POSTed that way before. – Ronnie Sep 21 '15 at 21:25

2 Answers2

2

To do that, you can use the Multipart.as ( AS3 multipart form data request generator ) from Jonas Monnier. It's really very easy to use it, take a look on this example ( using the basic example from the github project's page ) :

var upload_url:String = 'http://www.example.com/upload';

// create an orange square
var bmp_data:BitmapData = new BitmapData(400, 400, false, 0xff9900);

// compress our BitmapData as a jpg image   
var image:ByteArray = new JPGEncoder(75).encode(bmp_data);

// create our Multipart form
var form:Multipart = new Multipart(upload_url);

    // add some fields if you need to send some informations
    form.addField('name', 'bmp.jpg');
    form.addField('size', image.length.toString());

    // add our image
    form.addFile('image', image, 'image/jpeg', 'bmp.jpg');

var loader:URLLoader = new URLLoader();
    loader.load(form.request);

Then, in the PHP side, you do as you have usually did :

public function upload(\Illuminate\Http\Request $request)
{        
    if($request->hasFile('image'))
    {            
        $file = $request->file('image');            
        $upload_success = $file->move($your_upload_dir, $file->getClientOriginalName());

        if($upload_success)
        {
            return('The file "'.$request->get('name').'" was successfully uploaded');
        } 
        else 
        {
            return('An error has occurred !');
        }

    }        
    return('There is no "image" file !');
}

Hope that can help.

akmozo
  • 9,829
  • 3
  • 28
  • 44
  • This is it! Worked great. I had to modify the Multipart.as file to allow me to add the X-CSRF-Token header, but other than that, this is exatly what I was looking for. I'll award the bounty when it allows me. – Ronnie Sep 22 '15 at 16:30
  • @Ronnie For the CSRF Token, I think that you can try : `form.addField('_token', your_csrf_token);` without editing the class. – akmozo Sep 22 '15 at 17:31
  • There's absolutely no _need_ to use multipart encoding. The `_token` parameter can be added to the url and it works fine too. Kind of disappointed that my answer got no love at all. – bernie Sep 23 '15 at 14:01
0

Based on the doc for AS3 (emphasis mine):

The way in which the data is used depends on the type of object used:

  • If the object is a ByteArray object, the binary data of the ByteArray object is used as POST data. For GET, data of ByteArray type is not supported. Also, data of ByteArray type is not supported for FileReference.upload() and FileReference.download().
  • If the object is a URLVariables object and the method is POST, the variables are encoded using x-www-form-urlencoded format and the resulting string is used as POST data. An exception is a call to FileReference.upload(), in which the variables are sent as separate fields in a multipart/form-data post.

You're clearly in the first case here.

From the Laravel Requests doc:

To obtain an instance of the current HTTP request via dependency injection, you should type-hint the Illuminate\Http\Request class on your controller constructor or method. The current request instance will automatically be injected by the service container.

The Request class API:

string|resource getContent(bool $asResource = false)

Returns the request body content.

Putting it together:

public function uploadFramegrab(Request $request) {
    $content = $request->getContent();
    $fileSize = strlen($content);
}

In Laravel 4:

$csrf = Request::header('X-CSRF-Token');  
// Add a header like this if you want to control filename from AS3
$fileName = Request::header('X-File-Name');  
$content = Request::getContent(); // This the raw JPG byte array
$fileSize = strlen($content);

Last time I checked Laravel uses php://input to read the request body. See this answer for more info.

Community
  • 1
  • 1
bernie
  • 9,820
  • 5
  • 62
  • 92
  • I actually just figured it out. Using `php://input` allows me access to the byte array. At that point, I create a new file using `fopen()`, `fwrite()`. I swear I tried using `php://input` earlier and it wasn't working. `Request::getContent()` presented an error stating `Request::getContent() should not be called statically`. Using php://input doesn't seem like a great solution when using laravel. I hope to see if someone else has a different solution – Ronnie Sep 21 '15 at 21:44
  • I copied that code from my working Laravel 4.2 code. I'll have a look at what changed in Laravel 5 – bernie Sep 22 '15 at 00:41
  • I think you just need to replace the static method call with an instance method call. See my edit and let me know if that works. – bernie Sep 22 '15 at 01:51