/*! * GJframework * model/Finder.class.php * v1.0.0 (03/09/2018) * * Created by Guillaume Juncker on 24/08/2018. * Copyright © Guillaume Juncker. All rights reserved. */ /** * Finder * Classe de gestion de fichiers */ class Finder { public $base_path = "", $capacity = 0, $max_file_size = 0; /*------------------------------------------------------------------------------------------------------------------------------*/ /** * __construct * Construit un objet Finder * * @return void */ public function __construct($base_path) { $this->base_path = $base_path; $this->capacity = $_SESSION['config']['finder']['capacity']; $this->max_file_size = $_SESSION['config']['finder']['max_file_size']; } /*------------------------------------------------------------------------------------------------------------------------------*/ /** * unitsize * Calcule la taille en octet, Ko, Mo, Go * @param int $size: la taille en octets à optimiser * @return string: la taille convertie dans l'unité optimale */ public final function unitsize(int $size) { if($size>= 1000000000) { $size = round($size / 1000000000 * 100) / 100 . " Go";} elseif($size>= 1000000) { $size = round($size / 1000000 * 100) / 100 . " Mo";} elseif($size>= 1000) { $size = round($size / 1000 * 100) / 100 . " Ko";} else { $size = $size." o";} return $size; } /** * unitfilesize * Calcule la taille d'un fichier en octet, Ko, Mo, Go * @param string $path: le chemin du fichier dont on veut afficher la taille * @return string: le résultat de "unitsize" sur le fichier donné */ public final function unitfilesize(string $path) { return $this->unitsize(filesize($path)); } /** * dirsize * Calcule la taille d'un répertoire * @param string $path: le chemin du répertoire dont on souhaite connaître la taille * @return double: la taille totale du répertoire */ public final function dirsize(string $path) { $size = 0; if($dir = opendir($path)) { while($file = readdir($dir)) { if($file[0]!= ".") { $size+= filesize("$path/$file"); if(is_dir("$path/$file")) { $size+= $this->dirsize("$path/$file");} } } return $size; } return FALSE; } /** * filesnb * Calcul le nombre de fichiers et dossiers d'un répertoire * @param string $path: le chemin du répertoire dont on souhaite connaître le nombre de fichiers * @return int: le nombre total de fichiers du répertoire */ public final function filesnb(string $path) { $number = 0; if($dir = opendir($path)) { while($file = readdir($dir)) { if($file[0]!= ".") { $number+= 1;} } return $number; } return FALSE; } /** * filesnb_r * Calcul récursivement le nombre total de fichiers d'un répertoire * @param string $path: le chemin du répertoire de départ dont on souhaite connaître le nombre de fichiers * @return int: le nombre total de fichiers du répertoire et de ses sous-répertoires */ public final function filesnb_r(string $path) { $number = 0; if($dir = opendir($path)) { while($file = readdir($dir)) { if($file[0]!= ".") { $number+= 1; if(is_dir("$path/$file")) { $number+= $this->filesnb_r("$path/$file");} } } return $number; } return FALSE; } /** * percentageStorageUsed * Calcul le pourcentage d'espace utilisé * [@param string $path: le répertoire dont on souhaite connaître le pourcentage qu'il utilise] * @return int: le pourcentage de stockage utilisé par le répertoire donné */ public function percentageStorageUsed($path = self::base_path) { return round($this->dirsize($path) / $this->capacity * 100, 2); } /** * dir_is_empty * Vérifie si un répertoire est vide * @param string $path: le chemin du répertoire à vérifier * @return Boolean: TRUE si le répertoire est vide, FALSE sinon */ public final function dir_is_empty($path) { return (count(scandir($path))<= 2); } /** * explore * Explore le contenu d'un répertoire * @param string $path: le chemin du répertoire à explorer * @return array: un tableau associatif du contenu du répertoire */ public final function explore(string $path) { if($dir = opendir($path)) { $dirs = $files = array(); while($file = readdir($dir)) { if($file[0]!= ".") { if(is_dir("$path/$file")) { $dirs[] = array("name" => $file, "path" => "$path/$file", "size" => $this->unitfilesize("$path/$file"), "last_modified" => date("Y-m-d H:i", filemtime("$path/$file")));} else { $files[] = array("name" => $file, "path" => "$path/$file", "size" => $this->unitfilesize("$path/$file"), "last_modified" => date("Y-m-d H:i", filemtime("$path/$file")));} } } sort($dirs); sort($files); return array("dirs" => $dirs, "files" => $files); } return FALSE; } /** * glob_r * Version recursive de glob() * @param string $pattern: le masque * @param int $flags: le(s) drapeau(x) (ne supporte pas le drapeau GLOB_BRACE) * @return array: un tableau contenant les fichiers et dossiers correspondant au masque, un tableau vide s'il n'y a aucune correspondance, ou FALSE si une erreur survient */ public final function glob_r(string $pattern, int $flags = 0) { $files = glob($pattern, $flags); foreach(glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { $files = array_merge($files, $this->glob_r($dir.'/'.basename($pattern), $flags)); } return $files; } /** * download * Lance le téléchargement d'un fichier * @param string $path: le chemin vers le fichier à télécharger * [@param bool $tmp: TRUE pour supprimer le fichier après téléchargement] * @return void */ public final function download(string $path, bool $tmp = FALSE) { if(file_exists($path)) { header("Content-Description: File Transfer"); header("Content-Type: application/force-download"); header("Content-Type: application/octet-stream"); header("Content-Type: application/download"); header("Content-Disposition: attachment; filename=".basename($path)); header("Content-Transfer-Encoding: binary"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Pragma: public"); header("Content-Length: ".filesize($path)); readfile($path); if($tmp) { unlink($path);} exit; } } /** * upload * Vérifie le(s) fichier(s) à uploader * @param array $file_s: le tableau du/des fichier(s) * @param array $allowed_extensions: le tableau des extentions autorisées * [@param int $max_size: la taille maximale autorisée par fichier] * [@param string $destination_dir: le chemin du répertoire de destination du/des fichier(s) uploadé(s)] * [@param bool $overwrite: TRUE pour écraser le(s) éventuel(s) fichier(s) existant(s) de même nom(s)] * @return CustomError: la/les erreur(s) déclenchée par la vérification */ public final function upload(array $file_s, array $allowed_extensions, int $max_size = self::max_file_size, string $destination_dir = NULL, bool $overwrite = FALSE) { // Simple file if(!is_array($file_s['name'])) { if($file_s['name']) { // Minimisation de l'extention du fichier $file_name = pathinfo($file_s['name'], PATHINFO_FILENAME); $file_ext = strtolower(pathinfo($file_s['name'], PATHINFO_EXTENSION)); $file_s['name'] = "$file_name.$file_ext"; // Erreur de transfert if($file_s['error']!= UPLOAD_ERR_OK) { return new CustomError("danger", "Une erreur s'est produite lors du transfert du fichier \"".$file_s['name']."\" (code: ".$file_s['error']."), veuillez réessayer"); } // Erreur d'extension/type de fichier if(!in_array($file_ext, $allowed_extensions)) { return new CustomError("warning", "L'extension du fichier \"".$file_s['name']."\" n'est pas acceptée, les extensions autorisées sont ".implode(", ", $allowed_extensions)); } // Erreur de taille if($file_s['size'] > $max_size) { return new CustomError("warning", "Le fichier \"".$file_s['name']."\" pèse ".$this->unitsize($file_s['size'])." et dépasse donc les ".$this->unitsize($max_size)." maximum autorisés"); } // Espace insufisant if($this->dirsize($this->base_path) + $file_s['size'] > $this->capacity) { return new CustomError("warning", "Espace insuffisant pour stocker le fichier \"".$file_s['name']."\" de ".$this->unitsize($file_s['size'])); } // Suppression du fichier existant de même nom si demandé if($overwrite AND file_exists($path = "$destination_dir/".$file_s['name'])) { unlink($path);} // Erreur de fichier existant if($destination_dir AND file_exists($path)) { return new CustomError("warning", "Le fichier \"".$file_s['name']."\" existe déjà"); } // Succès return new CustomError("success", "Le fichier \"".$file_s['name']."\" est conforme et peut être transféré"); } else { return new CustomError("warning", "Aucun fichier à vérifier n'a été trouvé"); } } // Mutiple files else { // Réordonnancement du tableau multidimentionnel $_FILES foreach($file_s as $key => $values) { foreach($values as $i => $val) { $files_ordered[$i][$key] = $val; } } // Vérification des upload un à un $uploads_errors = array(); foreach($files_ordered as $file) { $uploads_errors[] = $this->upload($file, $allowed_extensions, $max_size, $destination_dir, $overwrite); } return $uploads_errors; } } /** * rename * Renomme un fichier donné * @param string $old_path: le chemin du fichier que l'on veut renommer * @param string $new_path: le nouveau chemin du fichier (renommé) * @return bool: le résultat du renommage */ public function rename(string $old_path, string $new_path) { $new_path_infos = pathinfo($new_path); $new_path = $new_path_infos['dirname']."/".$new_path_infos['filename'].".".strtolower($new_path_infos['extension']); return rename($old_path, $new_path); } /** * noverwrite * Renomme un élément pour qu'il n'écrase aucun autre élément existant de même nom * @param string $path: le chemin de l'élément à créer/renommer/déplacer * @return string: le chemin de l'élément renommer si besoin */ public function noverwrite(string $path) { $name = $return_name = pathinfo($path, PATHINFO_FILENAME); $i = 2; while(file_exists($path)) { $path = preg_replace("#$return_name#", "$name-$i", $path, 1); $return_name = "$name-$i"; $i++; } return $path; } /** * rm * Supprime un fichier ou un répertoire * @param string $path: le chemin du fichier ou répertoire à supprimer * @return bool: TRUE si le fichier ou dossier n'existe plus après traitement, FALSE sinon */ public final function rm(string $path) { if(is_dir($path)) { foreach(scandir($path) as $file) { if($file!= "." AND $file!= "..") { $this->rm("$path/$file");} } if(file_exists($path)) { rmdir($path);} } else { if(file_exists($path)) { unlink($path);} } return !file_exists($path); } /** * thumbnail * Génère la miniature d'une image * @param string $path: le chemin de l'image originale * @param array $dimensions: le tableau de dimension(s) de la miniature tel que array("width" => X, "height" => Y) * @param string $destination_dir: le chemin vers le répertoire de destination de la miniature * @return bool: le résultat de la création de la miniature */ public final function thumbnail(string $path, array $dimensions, string $destination_dir) { // Récupération des dimensions de l'image originale list($width, $height) = getimagesize($path); // Récupération des dimensions souhaitées $th_height = $dimensions['height']; $th_width = $dimensions['width']; // Calcul de la dimension non fournie pour conserver le ratio original if(!$th_height OR $th_height== "auto") { $th_height = ($th_width / $width) * $height;} elseif(!$th_width OR $th_width== "auto") { $th_width = ($th_height / $height) * $width;} $thumbnail = imagecreatetruecolor($th_width, $th_height); $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); switch($extension) { case "png": $img = imagecreatefrompng($path); imagecopyresampled($thumbnail, $img, 0, 0, 0, 0, $th_width, $th_height, $width, $height); $return_image = imagepng($thumbnail, $destination_dir, 0); break; case "jpg": case "jpeg": $img = imagecreatefromjpeg($path); imagecopyresampled($thumbnail, $img, 0, 0, 0, 0, $th_width, $th_height, $width, $height); $return_image = imagejpeg($thumbnail, $destination_dir, 100); break; case "gif": $img = imagecreatefromgif($path); imagecopyresampled($thumbnail, $img, 0, 0, 0, 0, $th_width, $th_height, $width, $height); $return_image = imagegif($img, $destination_dir); break; default: return new CustomError("warning", "Impossible de créer une miniature de ce type de fichier ($extension)"); break; } imagedestroy($thumbnail); imagedestroy($img); if($return_image) { return new CustomError("success", "La miniature de l'image \"$path\" a bien été générée");} else { return new CustomError("danger", "Une erreur s'est produite lors de la génération de la miniature de l'image \"$path\", veuillez réessayer");} } }