PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/class/upload.class.php

http://adminserv.googlecode.com/
PHP | 526 lines | 276 code | 67 blank | 183 comment | 61 complexity | 4379f9140927c13614aafd10d7719103 MD5 | raw file
  1. <?php
  2. /**
  3. * CLASS UPLOAD
  4. *
  5. * Traite l'envoi de fichier en local ou FTP
  6. *
  7. * @example:
  8. * $path = '/';
  9. * $replaceOldFile = false;
  10. * $allowedExtensions = array('jpg', 'png', 'gif');
  11. * $sizeLimit = 4 * 1024 * 1024;
  12. * LOCAL:
  13. * echo FileUploader::saveUploadedFile($path, $replaceOldFile, $allowedExtensions, $sizeLimit);
  14. * FTP:
  15. * echo FileUploader::saveUploadedFileToFTP($ftp_stream, $path, $replaceOldFile, $allowedExtensions, $sizeLimit);
  16. */
  17. /**
  18. * Permet de traiter le fichier envoyé par XHR (XMLHttpRequest)
  19. */
  20. class UploadedFileXhr {
  21. /**
  22. * Enregistre le fichier en local
  23. *
  24. * @param string $path -> Le chemin complet du fichier avec le filename
  25. * @return bool true si réussi
  26. */
  27. public function save($path){
  28. // Ouverture du flux "input" de PHP et création d'un fichier temp
  29. $input = fopen("php://input", "r");
  30. $temp = tmpfile();
  31. $realSize = stream_copy_to_stream($input, $temp);
  32. fclose($input);
  33. if( $realSize != $this->getSize() ){
  34. return false;
  35. }
  36. // Création du fichier final
  37. $target = fopen($path, "w");
  38. fseek($temp, 0, SEEK_SET);
  39. stream_copy_to_stream($temp, $target);
  40. fclose($target);
  41. return true;
  42. }
  43. /**
  44. * Enregistre le fichier sur un serveur FTP
  45. *
  46. * @param resource $ftp_stream -> La ressource de connexion FTP
  47. * @param string $path -> Le chemin complet du dossier de destination
  48. * @param string $filename -> Le nom du fichier
  49. * @return true si réussi, sinon false
  50. */
  51. public function saveFTP($ftp_stream, $path, $filename){
  52. // Ouverture du flux "input" de PHP et création d'un fichier temp
  53. $input = fopen("php://input", "r");
  54. $temp = tmpfile();
  55. $realSize = stream_copy_to_stream($input, $temp);
  56. fclose($input);
  57. if( $realSize != $this->getSize() ){
  58. return false;
  59. }
  60. // Enregistre le fichier sur le FTP
  61. fseek($temp, 0, SEEK_SET);
  62. return ftp_fput($ftp_stream, $path.$filename, $temp, FTP_BINARY);
  63. }
  64. /**
  65. * Enregistre le fichier sur un serveur FTP
  66. *
  67. * @param resource $ftp_stream -> La ressource de connexion FTP
  68. * @param string $path -> Le chemin complet du dossier de destination
  69. * @param string $filename -> Le nom du fichier
  70. * @return true si réussi, sinon false
  71. */
  72. public function saveMap($client, $path, $filename, $queries){
  73. $out = null;
  74. // Ouverture du flux "input" de PHP et création d'un fichier temp
  75. $input = fopen("php://input", "r");
  76. $temp = tmpfile();
  77. $realSize = stream_copy_to_stream($input, $temp);
  78. fclose($input);
  79. if( $realSize != $this->getSize() ){
  80. return false;
  81. }
  82. fseek($temp, 0, SEEK_SET);
  83. $file = stream_get_contents($temp);
  84. $str64 = new IXR_Base64($file);
  85. if( !$client->query('WriteFile', $filename, $str64) ){
  86. $out = '['.$client->getErrorCode().'] '.$client->getErrorMessage();
  87. }
  88. else{
  89. // Insert
  90. if($queries['type'] == 'insert'){
  91. if( !$client->query($queries['insert'], $path.$filename) ){
  92. $out = '['.$client->getErrorCode().'] '.$client->getErrorMessage();
  93. }
  94. }
  95. // Add
  96. else{
  97. if( !$client->query($queries['add'], $path.$filename) ){
  98. $out = '['.$client->getErrorCode().'] '.$client->getErrorMessage();
  99. }
  100. }
  101. }
  102. if($out == null){
  103. $out = true;
  104. }
  105. return $out;
  106. }
  107. /**
  108. * Récupčre le nom du fichier
  109. */
  110. public function getName(){
  111. return $_GET['qqfile'];
  112. }
  113. /**
  114. * Récupčre la taille du fichier
  115. */
  116. public function getSize(){
  117. if( isset($_SERVER['CONTENT_LENGTH']) ){
  118. return (int)$_SERVER['CONTENT_LENGTH'];
  119. }else{
  120. throw new Exception('Getting content length is not supported.');
  121. }
  122. }
  123. }
  124. /**
  125. * Permet de traiter le fichier envoyé par Formulaire HTML ($_FILES array)
  126. */
  127. class UploadedFileForm {
  128. /**
  129. * Enregistre le fichier en local
  130. *
  131. * @param string $path -> Le chemin complet du fichier avec le filename
  132. * @return bool true si réussi, sinon false
  133. */
  134. public function save($path){
  135. // Si il n'a pas réussi ŕ déplacer le fichier envoyé
  136. if( !move_uploaded_file($_FILES['qqfile']['tmp_name'], $path) ){
  137. return false;
  138. }
  139. return true;
  140. }
  141. /**
  142. * Enregistre le fichier sur un serveur FTP
  143. *
  144. * @param resource $ftp_stream -> La ressource de connexion FTP
  145. * @param string $path -> Le chemin complet du dossier de destination
  146. * @param string $filename -> Le nom du fichier
  147. * @return true si réussi, sinon false
  148. */
  149. public function saveFTP($ftp_stream, $path, $filename){
  150. // Enregistre le fichier sur le FTP
  151. return ftp_put($ftp_stream, $path.$filename, $_FILES['qqfile']['tmp_name'], FTP_BINARY);
  152. }
  153. /**
  154. * Enregistre le fichier sur un serveur FTP
  155. *
  156. * @param resource $ftp_stream -> La ressource de connexion FTP
  157. * @param string $path -> Le chemin complet du dossier de destination
  158. * @param string $filename -> Le nom du fichier
  159. * @return true si réussi, sinon false
  160. */
  161. public function saveMap($client, $path, $filename, $queries){
  162. $out = null;
  163. $str = file_get_contents($_FILES['qqfile']['tmp_name']);
  164. $str64 = new IXR_Base64($str);
  165. if( $client->query('WriteFile', $path.$filename, $str64) ){
  166. $pathTofile = $path.$filename;
  167. // Insert
  168. if($queries['type'] == 'insert'){
  169. if( !$client->query($queries['insert'], $filename) ){
  170. $out = '['.$client->getErrorCode().'] '.$client->getErrorMessage();
  171. }
  172. }
  173. // Add
  174. else{
  175. if( !$client->query($queries['add'], $filename) ){
  176. $out = '['.$client->getErrorCode().'] '.$client->getErrorMessage();
  177. }
  178. }
  179. }
  180. if($out == null){
  181. $out = true;
  182. }
  183. return $out;
  184. }
  185. /**
  186. * Récupčre le nom du fichier
  187. */
  188. public function getName(){
  189. return $_FILES['qqfile']['name'];
  190. }
  191. /**
  192. * Récupčre la taille du fichier
  193. */
  194. public function getSize(){
  195. return $_FILES['qqfile']['size'];
  196. }
  197. }
  198. /**
  199. * Permet de gérer l'enregistrement du fichier uploadé par XHR ou Formulaire
  200. */
  201. class FileUploader {
  202. private $allowedExtensions = array();
  203. private $sizeLimit = 10485760;
  204. private $file;
  205. function __construct(array $allowedExtensions = array(), $sizeLimit = 10485760){
  206. // Ecrase les paramčtres dans les variables de config
  207. $allowedExtensions = array_map("strtolower", $allowedExtensions);
  208. $this->allowedExtensions = $allowedExtensions;
  209. $this->sizeLimit = $sizeLimit;
  210. // Test si le serveur peut accepter la config
  211. $this->_checkServerSettings();
  212. // Test si il y a bien un fichier, si oui, on selectionne le type d'enregistrement (XHR ou Formulaire)
  213. if( isset($_GET['qqfile']) ){
  214. $this->file = new uploadedFileXhr();
  215. }
  216. else if( isset($_FILES['qqfile']) ){
  217. $this->file = new uploadedFileForm();
  218. }
  219. else{
  220. $this->file = false;
  221. }
  222. }
  223. /**
  224. * Vérifie si le serveur peut accepter la taille max configurée
  225. */
  226. private function _checkServerSettings(){
  227. $postSize = $this->_toBytes( ini_get('post_max_size') );
  228. $uploadSize = $this->_toBytes( ini_get('upload_max_filesize') );
  229. if( $postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit ){
  230. $size = max(1, $this->sizeLimit / 1024 / 1024) . 'Mo';
  231. die("{'error':'increase post_max_size and upload_max_filesize to $size'}");
  232. }
  233. }
  234. /**
  235. * Convertie les Go, Mo ou Ko du php.ini en octets
  236. */
  237. private function _toBytes($str){
  238. $val = trim($str);
  239. $last = strtolower($str[strlen($str)-1]);
  240. switch($last){
  241. case 'g': $val *= 1024;
  242. case 'm': $val *= 1024;
  243. case 'k': $val *= 1024;
  244. }
  245. return $val;
  246. }
  247. /**
  248. * Enregistre le fichier envoyé dans un dossier
  249. *
  250. * @param string $uploadDirectory -> Le chemin du dossier de destination
  251. * @param bool $replaceOldFile -> Remplacement des anciens fichiers qui ont le męme nom ? Non par défaut
  252. * @param function $filenameFunction -> La fonction de traitement du filename
  253. * @return array('success' => true) ou array('error' => 'error message')
  254. */
  255. public function handleUpload($uploadDirectory, $replaceOldFile = false, $filenameFunction = null){
  256. // Si on peut écrire dans le dossier de destination
  257. if( !is_writable($uploadDirectory) ){
  258. return array('error' => 'Erreur du serveur. Le dossier de destination des uploads n\'est pas écrivable.');
  259. }
  260. // Si il y a bien un fichier envoyé
  261. if( !$this->file ){
  262. return array('error' => 'Aucun fichier n\'a été uploadé.');
  263. }
  264. // Récuperation de la taille du fichier et test si il n'est pas vide ou supérieur ŕ la taille configurée
  265. $size = $this->file->getSize();
  266. if($size === 0){
  267. return array('error' => 'Le fichier est vide.');
  268. }
  269. if($size > $this->sizeLimit){
  270. return array('error' => 'La taille du fichier est supérieur ŕ la limite autorisé.');
  271. }
  272. // Récuperation du nom et de l'extension du fichier pour tester si l'extension est valide et si le nom du fichier n'existe pas déjŕ
  273. $pathinfo = pathinfo( $this->file->getName() );
  274. if($filenameFunction != null){
  275. $filename = $filenameFunction($pathinfo['filename']);
  276. }else{
  277. $filename = $pathinfo['filename'];
  278. }
  279. $ext = $pathinfo['extension'];
  280. if( $this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions) ){
  281. $these = implode(', ', $this->allowedExtensions);
  282. return array('error' => 'L\'extension du fichier est invalide (extension autorisées : '.$these.').');
  283. }
  284. if( !$replaceOldFile ){
  285. // Pour chaque fichier, on test si il existe, si oui, on rajoute un nombre aléatoire de 10 ŕ 99
  286. while( file_exists($uploadDirectory . $filename . '.' . $ext) ){
  287. $filename .= rand(10, 99);
  288. }
  289. }
  290. // Enregistrement du fichier
  291. if( $this->file->save($uploadDirectory . $filename . '.' . $ext) ){
  292. return array('success' => true);
  293. }else{
  294. return array('error' => 'Le fichier n\'a pas été envoyé. L\'envoi a été annulé ou une erreur du serveur est survenue.');
  295. }
  296. }
  297. /**
  298. * Enregistre le fichier envoyé dans un dossier sur un serveur FTP
  299. *
  300. * @param resource $ftp_stream -> La ressource de connexion FTP
  301. * @param string $uploadDirectory -> Le chemin du dossier de destination
  302. * @param bool $replaceOldFile -> Remplacement des anciens fichiers qui ont le męme nom ? Non par défaut
  303. * @param function $filenameFunction -> La fonction de traitement du filename
  304. * @return array('success' => true) ou array('error' => 'error message')
  305. */
  306. public function handleUploadFTP($ftp_stream, $uploadDirectory, $replaceOldFile = false, $filenameFunction = null){
  307. // Si on peut écrire dans le dossier de destination
  308. if( ! @ftp_chdir($ftp_stream, $uploadDirectory) ){
  309. return array('error' => 'Erreur du serveur. Le dossier de destination des uploads n\'est pas écrivable.');
  310. }
  311. // Si il y a bien un fichier envoyé
  312. if( !$this->file ){
  313. return array('error' => 'Aucun fichier n\'a été uploadé.');
  314. }
  315. // Récuperation de la taille du fichier et test si il n'est pas vide ou supérieur ŕ la taille configurée
  316. $size = $this->file->getSize();
  317. if($size === 0){
  318. return array('error' => 'Le fichier est vide.');
  319. }
  320. if($size > $this->sizeLimit){
  321. return array('error' => 'La taille du fichier est supérieur ŕ la limite autorisé.');
  322. }
  323. // Récuperation du nom et de l'extension du fichier pour tester si l'extension est valide et si le nom du fichier n'existe pas déjŕ
  324. $pathinfo = pathinfo( $this->file->getName() );
  325. if($filenameFunction != null){
  326. $filename = $filenameFunction($pathinfo['filename']);
  327. }else{
  328. $filename = $pathinfo['filename'];
  329. }
  330. $ext = $pathinfo['extension'];
  331. if( $this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions) ){
  332. $these = implode(', ', $this->allowedExtensions);
  333. return array('error' => 'L\'extension du fichier est invalide (extension autorisées : '.$these.').');
  334. }
  335. // Si il ne faut pas remplacer les anciens fichiers
  336. if( !$replaceOldFile ){
  337. // Fonction pour vérifier si le fichier existe sur le FTP
  338. function ftp_file_exists($ftp_stream, $uploadDirectory, $filename){
  339. $files = ftp_nlist($ftp_stream, $uploadDirectory);
  340. if( count($files) > 0){
  341. foreach($files as $file){
  342. if($uploadDirectory.$filename == $file){
  343. return true;
  344. }
  345. }
  346. }
  347. return false;
  348. }
  349. // Pour chaque fichier, on test si il existe, si oui, on rajoute un nombre aléatoire de 10 ŕ 99
  350. while( ftp_file_exists($ftp_stream, $uploadDirectory, $filename.'.'.$ext) ){
  351. $filename .= rand(10, 99);
  352. }
  353. }
  354. // Enregistrement du fichier
  355. if( $this->file->saveFTP($ftp_stream, $uploadDirectory, $filename.'.'.$ext) ){
  356. return array('success' => true);
  357. }else{
  358. return array('error' => 'Le fichier n\'a pas été envoyé. L\'envoi a été annulé ou une erreur du serveur est survenue.');
  359. }
  360. }
  361. /**
  362. * Enregistre le fichier envoyé dans un dossier sur un serveur FTP
  363. *
  364. * @param resource $client -> La ressource du client XMLRPC
  365. * @param string $uploadDirectory -> Le chemin du dossier de destination
  366. * @param bool $replaceOldFile -> Remplacement des anciens fichiers qui ont le męme nom ? Non par défaut
  367. * @param function $filenameFunction -> La fonction de traitement du filename
  368. * @return array('success' => true) ou array('error' => 'error message')
  369. */
  370. public function handleUploadManiaPlanet($client, $uploadDirectory, $queries, $filenameFunction = null){
  371. // Si le client est initialisé
  372. if (!$client->socket || $client->protocol == 0) {
  373. return array('error' => 'Client not initialized.');
  374. }
  375. // Si il y a bien un fichier envoyé
  376. if( !$this->file ){
  377. return array('error' => 'Aucun fichier n\'a été uploadé.');
  378. }
  379. // Récuperation de la taille du fichier et test si il n'est pas vide ou supérieur ŕ la taille configurée
  380. $size = $this->file->getSize();
  381. if($size === 0){
  382. return array('error' => 'Le fichier est vide.');
  383. }
  384. if($size > $this->sizeLimit){
  385. return array('error' => 'La taille du fichier est supérieur ŕ la limite autorisé.');
  386. }
  387. // Récuperation du nom et de l'extension du fichier pour tester si l'extension est valide et si le nom du fichier n'existe pas déjŕ
  388. $pathinfo = pathinfo( $this->file->getName() );
  389. if($filenameFunction != null){
  390. $filename = $filenameFunction($pathinfo['filename']);
  391. }else{
  392. $filename = $pathinfo['filename'];
  393. }
  394. $ext = $pathinfo['extension'];
  395. if( $this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions) ){
  396. $these = implode(', ', $this->allowedExtensions);
  397. return array('error' => 'L\'extension du fichier est invalide (extension autorisées : '.$these.').');
  398. }
  399. // Enregistrement du fichier
  400. if( $out = $this->file->saveMap($client, $uploadDirectory, $filename.'.'.$ext, $queries) ){
  401. return array('success' => true, 'out' => $out);
  402. }else{
  403. return array('error' => 'Le fichier n\'a pas été envoyé. L\'envoi a été annulé ou une erreur du serveur est survenue. ('.$out.')');
  404. }
  405. }
  406. /**
  407. * Enregistre le fichier envoyé en local
  408. *
  409. * @param string $uploadDirectory -> Le chemin du dossier de destination
  410. * @param bool $replaceOldFile -> Remplacement des anciens fichiers qui ont le męme nom ? Non par défaut
  411. * @param array $allowedExtensions -> Les extensions autorisées : array('jpg', 'png', 'gif');
  412. * @param int $sizeLimit -> La taille limite d'envoi (égale ou inférieure ŕ la configuration de PHP)
  413. * @param function $filenameFunction -> La fonction de traitement du filename
  414. * @return array('success' => true) ou array('error' => 'error message')
  415. */
  416. public static function saveUploadedFile($uploadDirectory, $replaceOldFile = false, $allowedExtensions = array(), $sizeLimit = 10485760, $filenameFunction = null){
  417. // Initialisation de la classe et enregistrement du fichier
  418. $uploader = new FileUploader($allowedExtensions, $sizeLimit);
  419. $result = $uploader->handleUpload($uploadDirectory, $replaceOldFile, $filenameFunction);
  420. // Retourne le résultat en json
  421. return htmlspecialchars(json_encode($result), ENT_NOQUOTES);
  422. }
  423. /**
  424. * Enregistre le fichier envoyé sur un serveur FTP
  425. *
  426. * @param resource $ftp_stream -> La ressource de connexion FTP
  427. * @param string $uploadDirectory -> Le chemin du dossier de destination
  428. * @param bool $replaceOldFile -> Remplacement des anciens fichiers qui ont le męme nom ? Non par défaut
  429. * @param array $allowedExtensions -> Les extensions autorisées : array('jpg', 'png', 'gif');
  430. * @param int $sizeLimit -> La taille limite d'envoi (égale ou inférieure ŕ la configuration de PHP)
  431. * @param function $filenameFunction -> La fonction de traitement du filename
  432. * @return array('success' => true) ou array('error' => 'error message')
  433. */
  434. public static function saveUploadedFileToFTP($ftp_stream, $uploadDirectory, $replaceOldFile = false, $allowedExtensions = array(), $sizeLimit = 10485760, $filenameFunction = null){
  435. // Initialisation de la classe et enregistrement du fichier sur un serveur FTP
  436. $uploader = new FileUploader($allowedExtensions, $sizeLimit);
  437. $result = $uploader->handleUploadFTP($ftp_stream, $uploadDirectory, $replaceOldFile, $filenameFunction);
  438. // Retourne le résultat en json
  439. return htmlspecialchars(json_encode($result), ENT_NOQUOTES);
  440. }
  441. /**
  442. * Enregistre le fichier envoyé sur un serveur dédié Maniaplanet
  443. *
  444. * @param resource $client -> La ressource du client XMLRPC
  445. * @param string $uploadDirectory -> Le chemin du dossier de destination
  446. * @param array $queries -> Requętes ŕ executer et le type d'ajout ŕ la liste: array('insert' => 'InsertMap', 'add' => 'AddMap', 'type' => 'add')
  447. * @param array $allowedExtensions -> Les extensions autorisées : array('jpg', 'png', 'gif');
  448. * @param int $sizeLimit -> La taille limite d'envoi (égale ou inférieure ŕ la configuration de PHP)
  449. * @param function $filenameFunction -> La fonction de traitement du filename
  450. * @return array('success' => true) ou array('error' => 'error message')
  451. */
  452. public static function saveUploadedFileToManiaPlanetDedicatedServer($client, $uploadDirectory, $queries, $allowedExtensions = array(), $sizeLimit = 10485760, $filenameFunction = null){
  453. // Initialisation de la classe et enregistrement du fichier sur un serveur dédié Maniaplanet
  454. $uploader = new FileUploader($allowedExtensions, $sizeLimit);
  455. $result = $uploader->handleUploadManiaPlanet($client, $uploadDirectory, $queries, $filenameFunction);
  456. // Retourne le résultat en json
  457. return htmlspecialchars(json_encode($result), ENT_NOQUOTES);
  458. }
  459. }