PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/core/libs/upload/upload.php

http://github.com/KumbiaPHP/KumbiaPHP
PHP | 385 lines | 162 code | 51 blank | 172 comment | 21 complexity | bd26f32ac405857c6ab23828f3414ab2 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * KumbiaPHP web & app Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.
  9. *
  10. * @category Kumbia
  11. * @package Upload
  12. *
  13. * @copyright Copyright (c) 2005 - 2020 KumbiaPHP Team (http://www.kumbiaphp.com)
  14. * @license https://github.com/KumbiaPHP/KumbiaPHP/blob/master/LICENSE New BSD License
  15. */
  16. /**
  17. * Sube archivos al servidor.
  18. *
  19. * @category Kumbia
  20. * @package Upload
  21. */
  22. abstract class Upload {
  23. /**
  24. * Nombre de archivo subido por método POST
  25. *
  26. * @var string
  27. */
  28. protected $_name;
  29. /**
  30. * Ruta donde se guardara el archivo
  31. *
  32. * @var string
  33. */
  34. protected $_path;
  35. /**
  36. * Permitir subir archivos de scripts ejecutables
  37. *
  38. * @var boolean
  39. */
  40. protected $_allowScripts = FALSE;
  41. /**
  42. * Tamaño mínimo del archivo
  43. *
  44. * @var string
  45. */
  46. protected $_minSize = '';
  47. /**
  48. * Tamaño máximo del archivo
  49. *
  50. * @var string
  51. */
  52. protected $_maxSize = '';
  53. /**
  54. * Tipos de archivo permitidos utilizando mime
  55. *
  56. * @var array
  57. */
  58. protected $_types = array();
  59. /**
  60. * Extensión de archivo permitida
  61. *
  62. * @var array
  63. */
  64. protected $_extensions = array();
  65. /**
  66. * Permitir sobrescribir ficheros
  67. *
  68. * @var bool Por defecto FALSE
  69. */
  70. protected $_overwrite = FALSE;
  71. /**
  72. * Constructor
  73. *
  74. * @param string $name nombre de archivo por método POST
  75. */
  76. public function __construct($name) {
  77. $this->_name = $name;
  78. }
  79. /**
  80. * Indica si se permitirá guardar archivos de scripts ejecutables
  81. *
  82. * @param boolean $value
  83. */
  84. public function setAllowScripts($value) {
  85. $this->_allowScripts = $value;
  86. }
  87. /**
  88. * Asigna el tamaño mínimo permitido para el archivo
  89. *
  90. * @param string $size
  91. */
  92. public function setMinSize($size) {
  93. $this->_minSize = trim($size);
  94. }
  95. /**
  96. * Asigna el tamaño máximo permitido para el archivo
  97. *
  98. * @param string $size
  99. */
  100. public function setMaxSize($size) {
  101. $this->_maxSize = trim($size);
  102. }
  103. /**
  104. * Asigna los tipos de archivos permitido (mime)
  105. *
  106. * @param array|string $value lista de tipos de archivos permitidos (mime) si es string separado por |
  107. */
  108. public function setTypes($value) {
  109. if (!is_array($value)) {
  110. $value = explode('|', $value);
  111. }
  112. $this->_types = $value;
  113. }
  114. /**
  115. * Asigna las extensiones de archivos permitidas
  116. *
  117. * @param array|string $value lista de extensiones para archivos, si es string separado por |
  118. */
  119. public function setExtensions($value) {
  120. if (!is_array($value)) {
  121. $value = explode('|', $value);
  122. }
  123. $this->_extensions = $value;
  124. }
  125. /**
  126. * Permitir sobrescribir el fichero
  127. *
  128. * @param bool $value
  129. */
  130. public function overwrite($value) {
  131. $this->_overwrite = (bool) $value;
  132. }
  133. /**
  134. * Acciones antes de guardar
  135. *
  136. * @param string $name nombre con el que se va a guardar el archivo
  137. * @return boolean|null
  138. */
  139. protected function _beforeSave($name) {
  140. }
  141. /**
  142. * Acciones después de guardar
  143. *
  144. * @param string $name nombre con el que se guardo el archivo
  145. * @return boolean|null
  146. */
  147. protected function _afterSave($name) {
  148. }
  149. /**
  150. * Guarda el archivo subido
  151. *
  152. * @param string $name nombre con el que se guardara el archivo
  153. * @return boolean|string Nombre de archivo generado con la extensión o FALSE si falla
  154. */
  155. public function save($name = '') {
  156. if (!$this->isUploaded()) {
  157. return FALSE;
  158. }
  159. if (!$name) {
  160. $name = $_FILES[$this->_name]['name'];
  161. } else {
  162. $name = $name . $this->_getExtension();
  163. }
  164. // Guarda el archivo
  165. if ($this->_beforeSave($name) !== FALSE && $this->_overwrite($name) && $this->_validates() && $this->_saveFile($name)) {
  166. $this->_afterSave($name);
  167. return $name;
  168. }
  169. return FALSE;
  170. }
  171. /**
  172. * Guarda el archivo con un nombre aleatorio
  173. *
  174. * @return string|false Nombre de archivo generado o FALSE si falla
  175. */
  176. public function saveRandom() {
  177. // Genera el nombre de archivo
  178. $name = md5(time());
  179. // Guarda el archivo
  180. if ($this->save($name)) {
  181. return $name . $this->_getExtension();
  182. }
  183. return FALSE;
  184. }
  185. /**
  186. * Verifica si el archivo esta subido en el servidor y listo para guardarse
  187. *
  188. * @return boolean
  189. */
  190. public function isUploaded() {
  191. // Verifica si ha ocurrido un error al subir
  192. if ($_FILES[$this->_name]['error'] > 0) {
  193. $error = array(UPLOAD_ERR_INI_SIZE => 'el archivo excede el tamaño máximo (' . ini_get('upload_max_filesize') . 'b) permitido por el servidor', UPLOAD_ERR_FORM_SIZE => 'el archivo excede el tamaño máximo permitido', UPLOAD_ERR_PARTIAL => 'se ha subido el archivo parcialmente', UPLOAD_ERR_NO_FILE => 'no se ha subido ningún archivo', UPLOAD_ERR_NO_TMP_DIR => 'no se encuentra el directorio de archivos temporales', UPLOAD_ERR_CANT_WRITE => 'falló al escribir el archivo en disco', UPLOAD_ERR_EXTENSION => 'una extensión de php ha detenido la subida del archivo');
  194. Flash::error('Error: ' . $error[$_FILES[$this->_name]['error']]);
  195. return FALSE;
  196. }
  197. return TRUE;
  198. }
  199. /**
  200. * Valida el archivo antes de guardar
  201. *
  202. * @return boolean
  203. */
  204. protected function _validates() {
  205. $validations = array('allowScripts', 'types', 'extensions', 'maxSize', 'minSize');
  206. foreach ($validations as $value) {
  207. $func = "_{$value}";
  208. if ($this->$func && !$this->$func()) {
  209. return FALSE;
  210. }
  211. }
  212. return TRUE;
  213. }
  214. /**
  215. * Devuelve la extensión
  216. *
  217. * @return string
  218. */
  219. protected function _getExtension() {
  220. if ($ext = pathinfo($_FILES[$this->_name]['name'], PATHINFO_EXTENSION)) {
  221. return '.' . $ext;
  222. }
  223. }
  224. /**
  225. * Valida si puede sobrescribir el archivo
  226. *
  227. * @return boolean
  228. */
  229. protected function _overwrite($name) {
  230. if ($this->_overwrite) {
  231. return TRUE;
  232. }
  233. if (is_file("$this->_path/$name")) {
  234. Flash::error('Error: ya existe este fichero. Y no se permite reescribirlo');
  235. return FALSE;
  236. }
  237. return TRUE;
  238. }
  239. /**
  240. * Convierte de tamaño legible por humanos a bytes
  241. *
  242. * @param string $size
  243. * @return int
  244. */
  245. protected function _toBytes($size) {
  246. if (is_int($size) || ctype_digit($size)) {
  247. return (int) $size;
  248. }
  249. $tipo = strtolower(substr($size, -1));
  250. $size = (int) $size;
  251. switch ($tipo) {
  252. case 'g':
  253. //Gigabytes
  254. $size *= 1073741824;
  255. break;
  256. case 'm':
  257. //Megabytes
  258. $size *= 1048576;
  259. break;
  260. case 'k':
  261. //Kilobytes
  262. $size *= 1024;
  263. break;
  264. default:
  265. $size = -1;
  266. Flash::error('Error: el tamaño debe ser un int para bytes, o un string terminado con K, M o G. Ej: 30k , 2M, 2G');
  267. }
  268. return $size;
  269. }
  270. /**
  271. * Guardar el archivo en el servidor
  272. *
  273. * @param string $name nombre con el que se guardará el archivo
  274. * @return boolean
  275. */
  276. protected abstract function _saveFile($name);
  277. /**
  278. * Obtiene el adaptador para Upload
  279. *
  280. * @param string $name nombre de archivo recibido por POST
  281. * @param string $adapter (file, image, model)
  282. * @return Upload
  283. */
  284. public static function factory($name, $adapter = 'file') {
  285. require_once __DIR__ . "/adapters/{$adapter}_upload.php";
  286. $class = $adapter . 'upload';
  287. return new $class($name);
  288. }
  289. /**
  290. * @param boolean $cond
  291. */
  292. protected function _cond($cond, $message) {
  293. if ($cond) {
  294. Flash::error("Error: $message");
  295. return FALSE;
  296. }
  297. return TRUE;
  298. }
  299. protected function _allowScripts() {
  300. return $this->_cond(
  301. !$this->_allowScripts && preg_match('/\.(php|phtml|php3|php4|js|shtml|pl|py|rb|rhtml)$/i', $_FILES[$this->_name]['name']),
  302. 'no esta permitido subir scripts ejecutables'
  303. );
  304. }
  305. /**
  306. * Valida que el tipo de archivo
  307. *
  308. * @return boolean
  309. */
  310. protected function _types() {
  311. return $this->_cond(
  312. !in_array($_FILES[$this->_name]['type'], $this->_types),
  313. 'el tipo de archivo no es válido'
  314. );
  315. }
  316. protected function _extensions() {
  317. return $this->_cond(
  318. !preg_match('/\.(' . implode('|', $this->_extensions) . ')$/i', $_FILES[$this->_name]['name']),
  319. 'la extensión del archivo no es válida'
  320. );
  321. }
  322. protected function _maxSize() {
  323. return $this->_cond(
  324. $_FILES[$this->_name]['size'] > $this->_toBytes($this->_maxSize),
  325. "no se admiten archivos superiores a $this->_maxSize b"
  326. );
  327. }
  328. protected function _minSize() {
  329. return $this->_cond(
  330. $_FILES[$this->_name]['size'] < $this->_toBytes($this->_minSize),
  331. "Error: no se admiten archivos inferiores a $this->_minSize b"
  332. );
  333. }
  334. }