Page 1 sur 1

Curl et call back

Posté : 16 févr. 2014, 19:50
par bostak
Bonjour,

Je bloque depuis plusieurs heures sur un problème. J'utilise un script php pour uploader des vidéos sur un service distant (ici vimeo) via la méthode Curl. Tout est ok cependant l'utilisateur n'a pas d'information parlante sur l'état d'avancement de son upload. Pour cela j'utilise la fonction "CURLOPT_PROGRESSFUNCTION" qui me permet d’appeler une fonction callback.
La fonction callback est bien appelé mais je suis incapable d'en faire quoi que se soit pour l'afficher à l'utilisateur.

J'ai essayé d'entrer les données dans la global $_SESSION, et ensuite de faire des appels ajax régulier pour interroger la session mais la requête ne s'exécute qu'une fois l'upload effectué.

Après plusieurs essais infructueux j'espère que vous aller pouvoir m'aider.

Merci d'avance
Bien cordialement,

Re: Curl et call back

Posté : 16 févr. 2014, 22:43
par moogli
salut,

quel est ton code ?

Il y a de fortes chances pour que la fonction de rappel ne soit utilisées qu'une fois l’exécution terminée.

il faut que tu nous donne plus d'info pour que l'on puisse t'aider au mieux (et le code est très pratique pour cela ;) ).

@+

Re: Curl et call back

Posté : 16 févr. 2014, 23:04
par bostak
Bonsoir,

Oui pardon voici le code en question, J'ai mis toute la fonction mais c'est essentiellement la partie curl qui est intéressante :
public function upload($file_path, $use_multiple_chunks = false, $chunk_temp_dir = '.', $size = 2097152, $replace_id = null)
    {
        if (!file_exists($file_path)) {
            return false;
        }

        // Figure out the filename and full size
        $path_parts = pathinfo($file_path);
        $file_name = $path_parts['basename'];
        $file_size = filesize($file_path);

        // Make sure we have enough room left in the user's quota
        $quota = $this->call('vimeo.videos.upload.getQuota');

        if ($quota->user->upload_space->free < $file_size) {
            throw new VimeoAPIException('The file is larger than the user\'s remaining quota.', 707);
        }

        // Get an upload ticket
        $params = array();

        if ($replace_id) {
            $params['video_id'] = $replace_id;
        }
        $rsp = $this->call('vimeo.videos.upload.getTicket', $params, 'GET', self::API_REST_URL, false);
        $ticket = $rsp->ticket->id;
        $endpoint = $rsp->ticket->endpoint;

        // Make sure we're allowed to upload this size file
        if ($file_size > $rsp->ticket->max_file_size) {
            throw new VimeoAPIException('File exceeds maximum allowed size.', 710);
        }

        // Split up the file if using multiple pieces
        $chunks = array();
        if ($use_multiple_chunks) {
            if (!is_writeable($chunk_temp_dir)) {
                throw new Exception('Could not write chunks. Make sure the specified folder has write access.');
            }

            // Create pieces
            $number_of_chunks = ceil(filesize($file_path) / $size);
            for ($i = 0; $i < $number_of_chunks; $i++) {
                $chunk_file_name = "{$chunk_temp_dir}/{$file_name}.{$i}";

                // Break it up
                $chunk = file_get_contents($file_path, FILE_BINARY, null, $i * $size, $size);
                $file = file_put_contents($chunk_file_name, $chunk);

                $chunks[] = array(
                    'file' => realpath($chunk_file_name),
                    'size' => filesize($chunk_file_name)
                );
            }
        }
        else {
            $chunks[] = array(
                'file' => realpath($file_path),
                'size' => filesize($file_path)
            );
        }

        // Upload each piece
        foreach ($chunks as $i => $chunk) {
            $params = array(
                'oauth_consumer_key'     => $this->_consumer_key,
                'oauth_token'            => $this->_token,
                'oauth_signature_method' => 'HMAC-SHA1',
                'oauth_timestamp'        => time(),
                'oauth_nonce'            => $this->_generateNonce(),
                'oauth_version'          => '1.0',
                'ticket_id'              => $ticket,
                'chunk_id'               => $i
            );

            // Generate the OAuth signature
            $params = array_merge($params, array(
                'oauth_signature' => $this->_generateSignature($params, 'POST', self::API_REST_URL),
                'file_data'       => '@'.$chunk['file'] // don't include the file in the signature
            ));

            // Post the file
            $curl = curl_init($endpoint);

            curl_setopt($curl,CURLOPT_NOPROGRESS,false);
            curl_setopt($curl,CURLOPT_PROGRESSFUNCTION, array($this, 'callback'));


            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
            $rsp = curl_exec($curl);
            curl_close($curl);
        }

        // Verify
        $verify = $this->call('vimeo.videos.upload.verifyChunks', array('ticket_id' => $ticket));

        // Make sure our file sizes match up
        foreach ($verify->ticket->chunks as $chunk_check) {
            $chunk = $chunks[$chunk_check->id];

            if ($chunk['size'] != $chunk_check->size) {
                // size incorrect, uh oh
                echo "Chunk {$chunk_check->id} is actually {$chunk['size']} but uploaded as {$chunk_check->size}<br>";
            }
        }

        // Complete the upload
        $complete = $this->call('vimeo.videos.upload.complete', array(
            'filename' => $file_name,
            'ticket_id' => $ticket
        ));

        // Clean up
        if (count($chunks) > 1) {
            foreach ($chunks as $chunk) {
                unlink($chunk['file']);
            }
        }

        // Confirmation successful, return video id
        if ($complete->stat == 'ok') {
            return $complete->ticket->video_id;
        }
        else if ($complete->err) {
            throw new VimeoAPIException($complete->err->msg, $complete->err->code);
        }
    }
Et ici la fonction de callback :
public function callback($download_size, $downloaded, $upload_size, $uploaded) {
        static $last;
        if ($ind = @round($downloaded/$download_size*100, 1)) {
            if($last < $ind) {
                $_SESSION['progress'] = $ind;
                flush();
                $last = $ind;
            }
        } 
    }
Ici la methode que j'appelle en ajax pour interroger la session :
public function ask()
    {
        $this->autoRender = false ;

        $prog = $_SESSION['progress'];

        return $prog;
    }
Et là l'ajax :
[javascript]function checkSession() {
$.ajax({
url: "/perso/lessons/ask",
success: function(data){
console.log(data);
},
error: function(){
console.log("failure");
}
});
}
setInterval(checkSession, 10000);[/javascript]

Et effectivement c'est exécuté qu'une fois l'upload terminé.

Merci d'avance,

@+

Re: Curl et call back

Posté : 16 févr. 2014, 23:43
par moogli
quel est la version de php utilisée ?
si c'est la version 5.5.0 la fonction de callback prendre 5 paramètres et non 4=> http://fr2.php.net/manual/fr/function.curl-setopt.php


Tu semble envoyer des fichiers vers un autre serveur du coup tu réalise un UPLOAD et non un download, donc les variables à utilisées sont plutôt $upload_size, $uploaded.
<?php
public function callback($download_size, $downloaded, $upload_size, $uploaded) {
        $_SESSION['progress'] = round($uploaded / $upload_size * 100, 1);
    }
?>
Par contre round ne retourne pas false donc le if est inutile et en plus si le résultat et zéro cela sera considéré comme false et ton code sera inutile.
Tu peux aussi virer l'arobase, cette fonction ne doit pas retourner d'erreur, tu peux vérifier si les variables sont bien des nombres (filter_var etc) si tu veux être certain de la chose.

le flush est inutile vu que ce n'est pas le but d'envoyer quelque chose à l'affichage (tu n'affiche rien d'ailleurs).

Pour la sauvegarde de la valeur précédente utilise plutôt une propriété de la classe que ta variable de méthode statique.

@+

Re: Curl et call back

Posté : 16 févr. 2014, 23:58
par bostak
Merci de votre réponse rapide, la version utilisé est 5.4.4. C'est exact pour les variables j'ai corrigé comme vous m'avez proposé.
le flush est inutile vu que ce n'est pas le but d'envoyer quelque chose à l'affichage (tu n'affiche rien d'ailleurs).
Je ne sais pas trop en faite pour cette partie, car mon but final est tout de même d'envoyer le résultat à la vue mais je ne sais pas comment faire.
Pour la sauvegarde de la valeur précédente utilise plutôt une propriété de la classe que ta variable de méthode statique.
C'est corrigé et merci pour l'info :).

Je me sens vraiment perdu dans cette partie, est ce que c'est la bonne voie pour arriver à ce que je veux faire ?

Merci,

@+

Re: Curl et call back

Posté : 17 févr. 2014, 16:37
par moogli
Je me sens vraiment perdu dans cette partie, est ce que c'est la bonne voie pour arriver à ce que je veux faire ?
a priori oui, tu n'as pas trop le choix quand tu envoie vers un autre serveur.

pour le reste une variable de session + une requête ajax périodique c'est ce que propose php lorsque tu souhaite indiquer la progression de l'upload => http://fr2.php.net/manual/fr/session.up ... ogress.php

il faut que tu pense que tu as deux temps de chargement différents :
- navigateur => serveur
- serveur => viméo

Du coup le premier temps de chargement n'est pas indiqué, il y a la un blanc, puis, ensuite, tu peux afficher le reste de l'upload sur viméo.

je n'ai pas demandé parce que cela me semble logique, mais tu as bien un session_start() sur ta page ?
idem sur la page "ask" qui reçoit la requête ajax.
cette page est plutôt limitée
<?php
session_start();
if(!empty($_SESSION['progress'])) {
    echo $_SESSION['progress'];
}else {
    echo 0;
}
pas besoin de plus.
tu pourrais utiliser un objet et faire du json mais tu n'auras aucune valeur ajouté à le faire.

@+