<?php
// WebJaxe, Observatoire de Paris, licence GPL
// encodage : UTF-8

function ajouter_fichier($chemin)
{
    $nb=count($_FILES['fichier']['name']); 
    for ($i=0; $i<$nb; $i++) {
        $fichier_temporaire = $_FILES['fichier']['tmp_name'][$i];
        if ( is_uploaded_file($fichier_temporaire) != TRUE)
        {
            erreur(FICHIER_INTROUVABLE);
        }
        // On copie le fichier dans le dossier de destination
        $nom_fichier = $_FILES['fichier']['name'][$i];
        verifie_nom_fichier_upload($nom_fichier);
        // Vérifie que les caractère ( NULL, /, \, etc) ne sont pas présents
        if ( preg_match('#[\x00-\x1F\x7F-\x9F/\\\\]#', $nom_fichier) )
        {
            erreur(NOM_FICHIER_PAS_VALIDE);
        }
        else if ( move_uploaded_file($fichier_temporaire, $chemin."/".$nom_fichier) == FALSE )
        {
            erreur(IMPOSSIBLE_COPIER);
        }
        // Lecture et écriture pour le propriétaire, lecture pour les autres
        chmod($chemin."/".$nom_fichier, 0644); // on ignore le résultat permettant de savoir si l'opération a échoué
    }
    return(true);
}



// vérifie qu'un fichier est bien dans une contribution,
// le déplace vers la poubelle et le supprime
function supprimer_fichier($fichier, $nom_contribution)
{
//ceci est le chemin absolut canonique pour le dossier de la contribution
    $pathcontrib = realpath("../../contribXML/".$nom_contribution);
    if ($pathcontrib == FALSE)
        erreur(PAS_SUPRIMER_FICHIER);
//ceci est le chemin absolut canonique pour le fichier à supprimer
    $pathfichier = realpath($fichier);
    if ($pathfichier == FALSE)
        erreur(PAS_SUPRIMER_FICHIER);
//on verifie que le chemin absolu canonique du fichier à supprimer commence par le chemin absolut canonique pour le dossier de la contribution
    $pos = strpos($pathfichier, $pathcontrib.DIRECTORY_SEPARATOR);
    if ($pos === false || $pos != 0) // opérateur === pour distinguer 0 de false
        erreur(PAS_SUPRIMER_FICHIER);

    $poubelle = "../../poubelle/".basename($fichier).rand(0,500);
    if ( is_file($fichier) == FALSE )
        erreur(PAS_FICHIER);
    if ( is_dir(dirname($poubelle)) == FALSE )
        erreur(POUBELLE_INTROUVABLE);
    if ( rename($fichier, $poubelle) == FALSE )
        erreur(ERREUR_SUPPRESSION);
    else
    {
        supprimer_vraiment($poubelle);
        return(true);
    }
}



function ajouter_repertoire($nom_contribution, $nom_sous_repertoire)
{
    verifie_nom_dossier_creation($nom_sous_repertoire);
    $chemin = "../../contribXML/".$nom_contribution."/";
    if ( is_dir($chemin) )
    {
        if ( is_dir($chemin.$nom_sous_repertoire) )
            erreur(REPERTOIRE_EXISTANT);
        else
            mkdir($chemin.$nom_sous_repertoire);
    }
    else
        erreur(REPERTOIRE_PAS_CREE);
}


// vérifie qu'un répertoire est bien dans une contribution,
// le déplace vers la poubelle et le supprime récursivement
function supprimer_repertoire($repertoire, $nom_contribution)
{
    if ($nom_contribution == FALSE || $nom_contribution == '') {
        error_log("supprimer_repertoire: nom_contribution=".$nom_contribution);
        erreur(CONTRIBUTION_EXISTE_PAS);
    }
//ceci est le chemin absolu canonique pour le dossier de la contribution
    $pathcontrib = realpath("../../contribXML/".$nom_contribution);
    if ($pathcontrib == FALSE)
        erreur(PAS_SUPRIMER_DOSSIER);
//ceci est le chemin absolu canonique pour le dossier à supprimer
    $pathdossier = realpath($repertoire);
    if ($pathdossier == FALSE)
        erreur(PAS_SUPRIMER_DOSSIER);
    
//on verifie que le chemin absolu canonique du dossier à supprimer commence par le chemin absolu canonique pour le dossier de la contribution
    $pos = strpos($pathdossier, $pathcontrib.DIRECTORY_SEPARATOR);
    if ($pos === false || $pos != 0) // opérateur === pour distinguer 0 de false
        erreur(PAS_SUPRIMER_DOSSIER);
    
    $poubelle = "../../poubelle/".basename($repertoire);
    if ( is_dir($repertoire) == FALSE )
        erreur(PAS_DOSSIER);
    if ( is_dir($poubelle) == TRUE )
    {
        $i=0;
        while ( is_dir($poubelle.$i) == TRUE )
        $i = $i+1;
        $poubelle = $poubelle.$i;
    }
    if ( is_dir(dirname($poubelle)) == FALSE )
        erreur(POUBELLE_INTROUVABLE);
    if ( rename($repertoire, $poubelle) == FALSE )
        erreur(ERREUR_DEPLACEMENT);
    else
    {
        supprimer_vraiment($poubelle);
        return(true);
    }
}


function liste_fichiers($repertoire)
{
    if ( !is_dir($repertoire) )
        erreur($repertoire." ".PAS_DOSSIER_2);
    $repertoire = rtrim($repertoire, "/\\"); // php 4.1.0
    $directory_handle = opendir($repertoire);
    if ($directory_handle == false)
        erreur(IMPOSSIBLE_OUVRIR_DOSSIER." : ".$repertoire);
    $listefichiers = array();
    while ( FALSE !== ($file = readdir($directory_handle)) )
    {
        if (is_file($repertoire.DIRECTORY_SEPARATOR.$file) && $file != '.DS_Store' && $file != 'Thumbs.db')
            $listefichiers[] = $file;
    }
    closedir($directory_handle);
    sort($listefichiers);
    return($listefichiers);
}


function liste_sous_repertoire($repertoire)
{
    if ( !is_dir($repertoire) )
        erreur($repertoire." ".PAS_DOSSIER_2);
    $repertoire = rtrim($repertoire, "/\\"); // php 4.1.0
    $directory_handle = opendir($repertoire);
    if ($directory_handle == false)
        erreur(IMPOSSIBLE_OUVRIR_DOSSIER." : ".$repertoire);
    $listerepertoires = array();
    while ( FALSE !== ($file = readdir($directory_handle)) )
    {
        if (verifie_nom_dossier_liste($file) && is_dir($repertoire.DIRECTORY_SEPARATOR.$file))
            $listerepertoires[] = $file;
    }
    closedir($directory_handle);
    sort($listerepertoires);
    return($listerepertoires);
}



function taille_du_fichier($fichier)
{
    // récupération de la taille du fichier en octets
    $taille = filesize($fichier);
    // détérmination de l'unité
    if ( $taille <= KILO_OCTET )
        $unite = "Octets";
    else if ( $taille > KILO_OCTET && $taille <= MEGA_OCTET )
    {
        $taille = $taille / KILO_OCTET;
        $taille = round($taille, 2);
        $unite = "Ko";
    }
    else if ( $taille > MEGA_OCTET && $taille <= GIGA_OCTET )
    {
        $taille = $taille / MEGA_OCTET;
        $taille = round($taille, 2);
        $unite = "Mo";
    }
    return($taille." ".$unite);
}

// supprime un fichier, ou un dossier récursivement
// à utiliser avec précaution !!!
function supprimer_vraiment($fichier)
{
    if (file_exists($fichier))
    {
        chmod($fichier, 0777);
        if (is_dir($fichier))
        {
            $id_dossier = opendir($fichier);
            while($element = readdir($id_dossier))
            {
                if ($element != "." && $element != "..")
                    supprimer_vraiment($fichier."/".$element);
            }
            closedir($id_dossier);
            rmdir($fichier);
        }
        else
            unlink($fichier);
    }
}

// renommer un fichier ou dossier
function renommer($nom_contribution, $dossier, $nom1, $nom2)
{
    if ($dossier == '') {
        $cheminf1 = '../../contribXML/'.$nom_contribution.'/'.$nom1;
        $cheminf2 = '../../contribXML/'.$nom_contribution.'/'.$nom2;
    } else {
        $cheminf1 = '../../contribXML/'.$nom_contribution.'/'.$dossier."/".$nom1;
        $cheminf2 = '../../contribXML/'.$nom_contribution.'/'.$dossier.'/'.$nom2;
    }
    
    if (is_dir($cheminf1))
        verifie_nom_dossier_creation($nom2);
    else
        verifie_nom_fichier_upload($nom2);
    
//ceci est le chemin absolut canonique pour le dossier de la contribution
    $pathcontrib = realpath('../../contribXML/'.$nom_contribution);
    if ($pathcontrib == FALSE)
        erreur(PAS_RENOMMER_FICHIER);
//on verifie que le chemin absolu canonique du fichier à supprimer commence par le chemin absolut canonique pour le dossier de la contribution
    $pos = strpos(realpath($cheminf1), $pathcontrib.DIRECTORY_SEPARATOR);
    if ($pos === false || $pos != 0) // opérateur === pour distinguer 0 de false
        erreur(PAS_RENOMMER_FICHIER);
    $pos = strpos(realpath(dirname($cheminf2)), $pathcontrib);
    if ($pos === false || $pos != 0) // opérateur === pour distinguer 0 de false
        erreur(PAS_RENOMMER_FICHIER);
    rename($cheminf1, $cheminf2);
}

// renommer une contribution
function renommer_contribution($nom_contribution, $nom)
{
    $chemin_contribution= '../../contribXML/'.$nom_contribution;
    $chemin_historique = '../../historique/'.$nom_contribution;
    $chemin_sites = '../../sites/'.$nom_contribution;
    
    $chemin_contribution2 = '../../contribXML/'.$nom;
    $chemin_historique2 = '../../historique/'.$nom;
    $chemin_sites2 = '../../sites/'.$nom;

    if (is_file($chemin_contribution.'/'.$nom_contribution.'.xml'))
        rename($chemin_contribution.'/'.$nom_contribution.'.xml', $chemin_contribution.'/'.$nom.'.xml');
        
    rename($chemin_contribution, $chemin_contribution2);
    
    if (file_exists($chemin_historique)) {
        $liste_sous_repertoire = liste_sous_repertoire($chemin_historique);
        for ($i=0; $i<count($liste_sous_repertoire); $i++) {
            $date = $liste_sous_repertoire[$i];
            rename($chemin_historique.'/'.$date.'/'.$nom_contribution.'.xml', $chemin_historique.'/'.$date.'/'.$nom.'.xml');
        }
        rename($chemin_historique, $chemin_historique2);
    }
    
    if (file_exists($chemin_sites)) 
        rename($chemin_sites, $chemin_sites2);
}


// renvoie true si une référence vers le fichier est trouvé dans le document XML de la contribution,ou si le document xml n'existe pas
function fichier_avec_reference($nom_contribution, $nom_fichier) {
    $chemin = '../../contribXML/'.$nom_contribution.'/'.$nom_contribution.'.xml';
    if (!file_exists($chemin))
        return true;
    $lignes = file($chemin);
    // on pourrait optimiser pour ne pas lire plus loin quand on trouve
    foreach($lignes as $ligne) {
        if (strpos($ligne, $nom_fichier) !== false)
            return(true);
    }
    return(false);
}


// crée un dossier unique composé du nom de la contribution et un pseudo-aléatoire
function dossier_unique($dossier_dest, $mode=0755) { 
    do {
        $rep = $dossier_dest.mt_rand(0, 3000);
    } while (!mkdir($rep, $mode));

    return $rep;
}


// Lit les petits et gros fichiers (contraire à readfile)
function lire_un_fichier($fichier) {
    $taille_buffer = 128 * 1024;
    $handle = fopen($fichier, 'rb');
    $buffer = '';
    while (!feof($handle)) {
        $buffer = fread($handle, $taille_buffer);
        echo $buffer;
        ob_flush();
        flush();
    }
    fclose($handle); 
}

?>
