Aller au contenu

15 juillet 2010

Fractionner un fichier dans Flex pour l’envoyer à PHP

Sous Flex, pour enregistrer un fichier tel qu’il soit coté serveur, il faut faire appel à PHP. On pourrai utiliser d’autres langages, mais comme il est le plus répandu sur le web et qu’il est très facile à manier, notre choix s’est donc fait très naturellement.

Je rédige cet article, car aujourd’hui dans la boite pour laquelle je travaille, je me suis retrouvé face à un problème de taille, les fichiers volumineux (en terme de poids) ne sont pas correctement envoyés à PHP! Je vous assure que 6Mo est plus compliqué à envoyer qu’il n’y parait, d’où l’idée de fractionner mon fichier en plusieurs parties.

Pour que les choses soient plus simples à comprendre, dans mon exemple, je pars d’un tableau contenant des images que j’ajoute dans une archive ZIP. Donc si vous avez bien suivi, c’est l’archive qui sera fractionnée en plusieurs parties pour l’envoi.

1. Coté Flex

// Fonction qui sera appelee pour l'envoi des fichiers.
// imgArray est une propriete privee de la classe, il s'agit
// tout simplement d'un tableau d'images.

public function sendFile ():void {
    var zip:FZip = new FZip ();

    for (var i:uint = 0; i < imgArray.length; ++i) {
        zip.addFile ("page"+i+".png", imgArray[i]);
    }

    var zip_out:ByteArray = new ByteArray ();
    zip.serialize (zip_out);

    partitionne (zip_out);
} // sendFile ();

var poolByteArray:Array;

// Fonction qui partitionne l'archive ZIP.
private function partitionne (bytes:ByteArray):void {
    var maxSize:uint = 1000000; // 1 MO.
    poolByteArray = new Array ();

    var lengthTotal:uint = bytes.length;

    if (lengthTotal < maxSize) {
        poolByteArray.push (bytes);
    } else {
        // On arrondi volontairement au dessus.
        var max:uint = Math.ceil ((lengthTotal/maxSize));

        var offset:uint = 0;
        var offset_tmp:uint = 0;
        var lenghtByte:uint = maxSize;

        for (var i:uint = 0; i < max; ++i) {
            offset_tmp += lenghtByte;

            // On fait bien attention a ne pas sortir du ByteArray!
            if (offset+lenghtByte > lengthTotal) {
                lenghtByte -= offset+lenghtByte-lengthTotal;
            }

            // On ajoute au pool la partie fractionnee.
            var frac:ByteArray = new ByteArray ();
            bytes.position = offset;
            bytes.readBytes (frac, 0, lenghtByte);

            poolByteArray.push (frac);

            offset = offset_tmp;
        }
    }

    send_part (0);
} // partitionne ();

// Fonction qui envoie toutes les partitions les unes
// à la suite des autres (dans le bon ordre!).
// saveid est aussi une propriete privee de la classe
// il s'agit d'un nom de fichier genere aleatoirement
// par flex.

private function send_part (index:Number):void {
    var bytes:ByteArray = poolByteArray[index];

    var zipEncoded:Base64Encoder = new Base64Encoder ();
    zipEncoded.encodeBytes (bytes);

    var variables:URLVariables = new URLVariables ();
    variables.saveid = saveid;
    variables.zipdata = zipEncoded.flush ();

    var request:URLRequest = new URLRequest ("save.php");
    request.method = URLRequestMethod.POST;

    var loader:URLLoader = new URLLoader ();
    loader.dataFormat = URLLoaderDataFormat.BINARY;

    loader.addEventListener (Event.COMPLETE, function ():void {
        if (++index < poolByteArray.length) send_part (index);
        else Alert.show ("Transfert terminé!");
    });
    loader.addEventListener (IOErrorEvent.IO_ERROR, function ():void {});

    request.data = variables;

    loader.load (request);
} // send_part ();

2. Coté PHP

$file = $_POST['saveid'].'.zip';
$handle = fopen ($file, 'a');
fwrite ($handle, base64_decode ($_POST['zipdata']));
fclose ($handle);

Et voilà! Le plus dur aura été d'élaborer l'algo de fractionnement du fichier.
J'avoue y avoir passer un peu moins de 2 heures (tests compris) pour arriver au résultat souhaité, j'éspère donc au passage aider quelques développeurs!

Donnez votre avis, envoyez un commentaire

(required)
(required)

Note: le code HTML est autorisé. Votre adresse mel ne sera jamais publiée.

S'abonner aux commentaires