D&Dでファイルをアップするの法

http://d.hatena.ne.jp/end0tknr/20110106/1294288753
を参考。
ほぼコピペですよね
プレビュー機能は必要なかったのでカット。
Amon2向けにトークン取得とかしたり。

function FileUpload(elm_id){
    var url = "save_image";

    var TEXT_ENCODING = 'UTF-8';

    this.init = function(elm_id){
        if( $("#" + elm_id).size() == 0 ){
            alert("can't find drop to element id : " + elm_id);
            return;
        }

        var this_obj = this;
        document.getElementById(elm_id)
            .addEventListener('drop',
                    function(e){this_obj.do_drop_file(e);},false);

        $("#" + elm_id)
            .bind('dragenter',
                    function(e){e.preventDefault(); e.stopPropagation();})
            .bind('dragover',
                    function(e){e.preventDefault(); e.stopPropagation();});
        $("html")
            .bind('drop',
                    function(e){e.preventDefault(); e.stopPropagation();})
            .bind('dragenter',
                    function(e){e.preventDefault(); e.stopPropagation();})
            .bind('dragover',
                    function(e){e.preventDefault(); e.stopPropagation();});
    };

    this.do_drop_file = function(e){
        var files = e.dataTransfer.files;
        
        var post_files = {};

        for(var i = 0 ; i < files.length ; i++){
            var binary = files.item(i).getAsBinary();
            var file_name  = files.item(i).fileName;
            post_files[file_name] = binary;
        }

        //amon2の仕様でpostを送る時はトークンが必要
        var token_name = 'csrf_token';
        var my_token = $('input[name=' + token_name + ']').attr('value');

        post_files[token_name] = my_token;
    
        $.post(url,
            post_files,
            function(json,textStatus){
                for(var i = 0; i < json.length ; i++){
                    if(json[i].status == 'success'){
                        $('#images').append(
                            $('<option value="' + json[i].image_id +'">' + json[i].image_name + '</option>'));
                        $('#div_images').append(
                            $('<option value="' + json[i].image_id +'">' + json[i].image_name + '</option>'));
                    }else{
                        alert(json[i].image_name + 'はアップロードできません');
                    }
                }
            },
            'json');
    };

    //初期化実行
    this.init(elm_id);
}

サーバサイドの受け側は以下

any '/save_image' => sub {
    my ($c) = @_;
    my $req_hash = $c->req->parameters;

    my $sql = SQL::Abstract->new();
    my $table = 't_image';

    my @return_json;
    for(keys %{$req_hash}){
        undef $@;
        my $image_id;
        my $file_name = $_;
        if($file_name eq 'csrf_token'){next;}

        eval{

            use MIME::Base64;
            my $file = encode_base64($req_hash->{$_});

            my $insert_values = {
                'user_id' => $c->session->get('id'),
                'name' => $file_name,
                'image' => $file,
            };

            {
                my ($stmt , @bind) = $sql->insert($table , $insert_values);
                my $sth = $c->dbh->prepare($stmt);
                $sth->execute(@bind);
            }

            {
                my ($stmt , @bind) = $sql->select($table , ['id'] , $insert_values);
                my $sth = $c->dbh->prepare($stmt);
                $sth->execute(@bind);
                $image_id = $sth->fetchrow_array;
            }
        };
        if(!$@){
            push @return_json, {
                'status' => 'success',
                'image_id' => $image_id,
                'image_name' => $file_name,
            };
        }else{
            push @return_json , {
                'status' => 'error',
                'image_name' => $file_name,
            };
        }
    }

    use JSON::XS;
    my $json = JSON::XS->new->utf8->encode(\@return_json);

    my $res = Plack::Response->new(200);
    $res->content_type('text/json');
    $res->body($json);
    return $res;
};

こんな感じ