Toutes les langues

Automatiser le téléchargement de gros fichiers avec une "tâche" (cron) php

Comment gérer au mieux le téléchargement de fichiers gros à partir d' un répertoire ftp distant ?
Ou plutôt, comment scruter un répertoire à distance pour voir si des fichiers sont arrivés, et si ils ont finit d'être livré ? Attention, le script que je propose là n'est pas destiné à un utilisateur de windows, mais est destiné à un public plûtot linux.

Cela présuppose que vous ayez accès à un serveur distant , cela peut etre un serveur publique de données comme par exemple un serveur dans cette liste http://mambo.ucsc.edu/psl/sgiftp.html dont vous avez besoin régulièrement de réceptionner du contenu .
Comment vérifier l'intégrité des fichier de ce répertoire, et surtout comment attendre que ces fichiers si ils sont gros, soient complètement déposés (par exemple , imaginez que vous être en train de télécharger un fichier zippé qui n'est pas encore complètement sur le serveur distant, si jamais vous le récupérez , vous aurez un fichier corrompu .
Pour automatiser le processus, il faut mettre en place un script automatiquement déclenché par votre machine, script qui viendra scruter le répertoire de dépôt, ceci afin de voir si jamais il y a un nouveau fichier et si jamais celui ci est complet, de le télécharger .
Sous linux, c'est le système crontab qui permet de gérer les automatismes . On définit dans ce ficher la fréquence de déclenchement en minutes, heures , jours .. d'un script .Il est tout à fait possible d'utiliser php comme langage de script , surtout si comme dans mon cas vous ne connaissez ni C, ni perl .. Je vous renvoie sur http://fr.wikipedia.org/wiki/Crontab pour plus d'info si vous n'êtes pas familier avec ces notions d'automates et comment les mettre en place sur votre linux .
Mais à présent le script :




// repertoire sur le FTP 
$pathftp = "/home/www/html/wires/efe/import";

//  repertoire sur la machine locale ou on veut récupérer les fichiers
define('TEMPFOLDER','usr/monrepertoire/');


$hostftpdistant = "FTPHOST" ;
$ftp_user_name = 'USER' ;
$ftp_user_pass = 'LOGIN';
$conn_distant = ftp_connect($hostftpdistant);
if(!$login_distant = @ftp_login($conn_distant, $ftp_user_name, $ftp_user_pass)){
        logerror('connexion ftp web distant impossible') ;
        print  "Operation failed Login /connexion pb to $hostftpdistant , please try again or contact support ".$rc;
        die();
}
ftp_chdir($conn_distant,$pathftp) ;

// tableaux : res pour tableau actuel, prev pour le precedente (passage precedent du cron), 
// to_process sera le tableau utilisé qui désigne les fichiers qui sont réelement à traiter.
// Les deux premiers tableaux ont une structure identique pour comparer facilement. 
$res = array() ;
$prev  = array();
$to_process = array();


//  Liste tous les fichiers en attente dans le dossier
$buff = ftp_rawlist($conn_id, '.');
 

..ça renvoie un tableau de ce type..
Array
(
[0] => -rw-r--r-- 1 507 507 7787422 Oct 06 15:04 Envio_1_20091006_1600.zip
[1] => -rw-r--r-- 1 507 507 11020588 Oct 06 15:34 Envio_1_20091006_1630.zip
[2] => -rw-r--r-- 1 507 507 11921288 Oct 06 16:05 Envio_1_20091006_1700.zip

)

ma fonction parse_rawlist_into_array structure ce tableau de résultat pour en faire un tableau de clé-valeurs par élément du tableau..

$res = parse_rawlist_into_array($buff ,$path);

Le resultat donne un tableau dont chaque élément a pour clé le nom du fichier .Je garde le chemin complet du fichier (path), sa taille (qui va me servir pour ma comparaison), et sa date ..

[Envio_1_20091007_0000.zip] => Array
(
[path] => /home/www/html/wires/efe/import
[size] => 7812960
[month] => Oct
[day] => 06
[name] => Envio_1_20091007_0000.zip
)

on lit le fichier 'fichiers_present.txt' qui liste les fichiers du tour precedent qui n'ont pas été traités.

 



$prev = parse_textfile_into_array(FOLDER.'fichiers_present.txt',$path);
//  on compare la taille des fichiers (filesize) . Si équivalents , on les met dans le tableau to_process . 
// Sinon ,  on ecrit le nom du fichier dans fichiers_present.txt .
foreach($res as $filetocheck){
        if($filetocheck['size'] ==  $prev[$filetocheck['name']]['size'] ){
                $to_process[] = $filetocheck['name'] ;
        }
}


foreach($to_process as $file){
        // recuperation de tout fichier XML present sur le site 
        if(substr(trim($file),-3) == 'zip'){
                debugConsole('Recuperation du fichiers ZIP : '.$file) ; 
                if(!$fp = fopen(TEMPFOLDER.$file,'w') ){
                        die('probleme de droits sur le dossier '.TEMPFOLDER);
                }

                if(!ftp_fget($conn_distant,$fp, $file ,FTP_BINARY)){
                        logerror('impossible to retrieve the file '.$file) ;
                        $db_ext->disconnect();
                        $db->disconnect();
                        fclose($fp);
                        die(); 
                } 
                fclose($fp);                         
                // suppression du fichier du repertoire distant une fois recuperes.
                if (!ftp_delete($conn_distant, $file)) {
                        logerror('impossible to delete the file on distant server '.$file) ;                                
                }
        }  
} 

// on réecrit dans le  fichier texte qui sert à previous les fichiers qui n'ont pas été récupérer pour cause de distorsion au niveau de la taille
// avec la fonction ftp_rawlist 
$newbuff = parse_rawlist($buff, $path);
if(!($handle = fopen(FOLDER.'fichiers_present.txt',"w+")))
    die("

Cannot open \"".$file."\".

\n\n");

Et voila ! A présent en fixant une fréquence au cron , par exemple toutes les dix minutes , vous scrutez ce répertoire distant à la recherche de nouvelles vidéos complètes . La fonction logerror(); peux vous permettre de loger les erreurs (par exemple dans une database) .
Voici les trois fonctions nécessaires par ailleurs au fonctionnement de ce script :




function parse_rawlist_into_array($array,$path)
{
    $structure = array();
    foreach($array as $curraw)
    {
        $struc = array();
        $current = preg_split("/[\s]+/",$curraw,10);
        // on prend seulement les fichiers pas les directories
        if($current[4]>0){
            $struc['path'] = $path;
            $struc['size']  = $current[4];
            $struc['month']  = $current[5];
            $struc['day']    = $current[6];
            $struc['name'] = $current[8];
            $structure[$struc['name']] = $struc;
        }
    }
   return $structure;

} 
function parse_textfile_into_array($file,$path){
    if(!($handle = fopen($file,"a")))
            die("

Cannot open \"".$file."\".

\n\n"); $struc = array(); $structure = array(); $lines = file($file); foreach($lines as $Ligne){ $current = preg_split("/[\s]+/",$Ligne,10); $struc['path'] = $path; $struc['size'] = $current[4]; $struc['month'] = $current[5]; $struc['day'] = $current[6]; $current[9] ? $struc['name'] = $current[9] : $struc['name'] = $current[8] ; $structure[$struc['name']] = $struc; } fclose($handle); return $structure ; } function parse_rawlist($array,$path) { foreach($array as $Ligne){ $current = preg_split("/[\s]+/",$Ligne,9); if($current[4]>0){ $buffer .= $Ligne."\n"; } } return $buffer; }
»