Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 150 |
| iaUploadFile | |
0.00% |
0 / 1 |
|
0.00% |
0 / 12 |
4290.00 | |
0.00% |
0 / 150 |
| get_result | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
| __construct | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 6 |
|||
| uploadToDir | |
0.00% |
0 / 1 |
72.00 | |
0.00% |
0 / 25 |
|||
| fileTypeRegExp | |
0.00% |
0 / 1 |
12.00 | |
0.00% |
0 / 4 |
|||
| fileExtension | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 2 |
|||
| process | |
0.00% |
0 / 1 |
132.00 | |
0.00% |
0 / 44 |
|||
| alternativeName | |
0.00% |
0 / 1 |
12.00 | |
0.00% |
0 / 5 |
|||
| fileError | |
0.00% |
0 / 1 |
380.00 | |
0.00% |
0 / 34 |
|||
| putError | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 3 |
|||
| files_normalize | |
0.00% |
0 / 1 |
42.00 | |
0.00% |
0 / 12 |
|||
| filename_sanitize | |
0.00% |
0 / 1 |
12.00 | |
0.00% |
0 / 9 |
|||
| path_exists | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 2 |
|||
| dirnameNoTrailingSlash | |
0.00% |
0 / 1 |
20.00 | |
0.00% |
0 / 4 |
|||
| <?php | |
| namespace ia\Lib; | |
| use ia\Util\Str; | |
| /** | |
| * upload files | |
| * | |
| */ | |
| /* | |
| https://www.b4x.com/android/forum/threads/how-to-sync-a-remote-db-with-sqlite.21298/ | |
| https://stackoverflow.com/search?q=%5Bandroid-sqlite%5D+Sync | |
| https://www.youtube.com/watch?v=sKFLI5FOOHs&list=PLl-K7zZEsYLlP-k-RKFa7RyNPa9_wCH2s&index=4 | |
| *** https://stackoverflow.com/questions/14069421/show-an-image-preview-before-upload | |
| **** https://stackoverflow.com/questions/37205438/image-upload-with-preview-and-delete-option-javascript-jquery | |
| start letter | |
| // $arr = ['jpg', 'png', 'gif'] + ['jpg', 'png', 'gif', 'pdf', 'xlsx', 'docx'];print_r($arr); da ok | |
| php settings | |
| php_value max_input_time 10800 | |
| php_value max_execution_time 10800 | |
| php_value upload_max_filesize 110M | |
| php_value post_max_size 120M | |
| php_value memory_limit | |
| php_value max_file_uploads // maximum number of files that can uploaded in one reques | |
| <input type="hidden" name="MAX_FILE_SIZE" value="20000"> | |
| MAX_FILE_SIZE item cannot specify a file size greater than the file size that has been set in the upload_max_filesize | |
| //@TODO checar prblm con: max_file_uploads // maximum number of files that can uploaded in one reques | |
| */ | |
| class iaUploadFile { | |
| public $ACCEPT_IMAGES = ['jpg', 'jpeg', 'png', 'gif']; | |
| public $ACCEPT_PDF = ['pdf']; | |
| public $ACCEPT_XLSX = ['xlsx']; | |
| public $ACCEPT_CSV = ['csv']; | |
| public $ACCEPT_OFFICE = ['docx','xlsx','pptx']; | |
| public $ACCEPT_DOCUMENT = ['docx','xlsx','pptx','csv','pdf','doc','xls','ppt','jpg', 'jpeg', 'png', 'gif']; | |
| protected $allowOverwrite; | |
| // http://php.net/manual/en/features.file-upload.errors.php | |
| protected $error_messages = array( | |
| 1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini', | |
| 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', | |
| 3 => 'The uploaded file was only partially uploaded', | |
| 4 => 'No file was uploaded', | |
| 6 => 'Missing a temporary folder', | |
| 7 => 'Failed to write file to disk', | |
| 8 => 'A PHP extension stopped the file upload', | |
| 'unknown_error' => 'unknown error', | |
| 'accept_file_types' => 'Filetype not allowed', | |
| 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini', | |
| 'max_file_size' => 'File is too big', | |
| 'min_file_size' => 'File is too small', | |
| 'max_number_of_files' => 'Maximum number of files exceeded', | |
| 'max_width' => 'Image exceeds maximum width', | |
| 'min_width' => 'Image requires a minimum width', | |
| 'max_height' => 'Image exceeds maximum height', | |
| 'min_height' => 'Image requires a minimum height', | |
| 'abort' => 'File upload aborted', | |
| 'image_resize' => 'Failed to resize image', | |
| ); | |
| protected $fsWebroot; | |
| protected $result; | |
| public function get_result() {return $this->result;} | |
| public function __construct($fsWebroot=null, $allowOverwrite=false) { | |
| if($fsWebroot == null) { | |
| global $gConfig; | |
| $this->fsWebroot = $this->dirnameNoTrailingSlash($gConfig['FS_WEB_ROOT']); //@TODO | |
| } else { | |
| $this->fsWebroot = $this->dirnameNoTrailingSlash($fsWebroot); | |
| } | |
| $this->allowOverwrite = $allowOverwrite; | |
| } | |
| public function uploadToDir($uploadKeys, $webDir, $fileTypes, $generateUniqueName=false) { | |
| $this->result=['ok'=>true, 'uploaded'=>0, 'originalName'=>[], 'fileBaseName'=>[], 'webPath'=>[], 'errormsg'=>[]]; | |
| if(empty($_FILES)) { | |
| return $this->result; | |
| } | |
| $webDir = $this->dirnameNoTrailingSlash($webDir); | |
| $acceptFilesRegExp = $this->fileTypeRegExp($fileTypes); | |
| $this->result['regexp']=$acceptFilesRegExp; | |
| $this->result['uploadKeys']=$uploadKeys; | |
| $this->result['webdir']=$webDir; | |
| $this->result['fs']=$this->fsWebroot; | |
| if(empty($uploadKeys)) { | |
| $keys = []; | |
| } | |
| if(!is_array($uploadKeys)) { | |
| $keys = [$uploadKeys]; | |
| } else { | |
| $keys = array_flip($uploadKeys); | |
| } | |
| $this->result['keys']=$keys; | |
| $files = $this->files_normalize(); | |
| $this->result['normalized files']=$files; | |
| foreach($files as $fileKey => $fileData ) { | |
| if(!empty($keys) && !array_key_exists($fileKey, $keys)) { | |
| continue; | |
| } | |
| $this->result['va'][]=$fileKey; | |
| $iLen = count($fileData); | |
| for($i=0; $i < $iLen; $i++) { | |
| $this->process($fileData[$i], $webDir, $acceptFilesRegExp, $generateUniqueName); | |
| } | |
| } | |
| return $this->result; | |
| } | |
| protected function fileTypeRegExp($fileTypes) { | |
| foreach($fileTypes as &$f) | |
| if($f[0] === '.') | |
| $f = substr($f, 1); | |
| return '/\.'.implode('|', $fileTypes).'$/iU'; | |
| } | |
| protected function fileExtension($fileName) { | |
| $ipos = strripos($fileName,"."); | |
| return $ipos > 0 ? trim(substr($fileName,-$ipos)) : ""; | |
| } | |
| protected function process($file, $webDir, $acceptFilesRegExp, $generateUniqueName=false) { | |
| if($generateUniqueName) { | |
| $file['newName'] = PushId::generate().'.'.$this->fileExtension($file['name']); | |
| $file['newName'] = str_replace('-','ia',$file['newName']); | |
| } else | |
| $file['newName'] = $this->filename_sanitize($file['name']); | |
| if($this->fileError($file, $acceptFilesRegExp)) { | |
| $this->putError($file['name'], "Extension inválida"); | |
| return; | |
| } | |
| $path = $this->fsWebroot.'/'.$webDir; | |
| clearstatcache(true, $path); //@TODO clear only file | |
| // umask(0644); | |
| if(!$this->path_exists($path)) { | |
| if(!mkdir($path, 0665, true)) { // duda group 6 o 4, other 4 o 0? | |
| $this->putError($file['name'], "Can't create web directory"); | |
| return; | |
| } | |
| } | |
| chmod($path, 0777); | |
| clearstatcache(true, $path); //@TODO clear only file | |
| if(!is_dir($path)) { | |
| $this->putError($file['name'], "Invalid web directory"); | |
| return; | |
| } | |
| $fullFileName = $path . '/' . $file['newName']; | |
| clearstatcache(true, $fullFileName); | |
| if($this->path_exists($fullFileName)) { | |
| if(is_dir($fullFileName) ) { | |
| $this->putError($file['name'], "invalid file name, renombrelo!"); | |
| return; | |
| } | |
| if(!$this->allowOverwrite) { | |
| $alternateName = $this->alternativeName($file['newName'], $path); | |
| if($alternateName == false) { | |
| $this->putError($file['name'], "Ya existe un archivo con ese nombre, renombrelo!"); | |
| return; | |
| } | |
| $file['newName'] = $alternateName; | |
| $fullFileName = $path . '/' . $file['newName']; | |
| } | |
| } | |
| if(!@move_uploaded_file( $file['tmp_name'] , $fullFileName)) { | |
| $err = error_get_last(); | |
| $this->putError($file['name'], "Error al copiar al website: $fullFileName ". | |
| print_r($err,true)); | |
| return; | |
| } | |
| chmod($fullFileName, 0666); | |
| clearstatcache(true, $fullFileName); | |
| $this->result['res'][$file['name']]=$file['newName']; | |
| $this->result['originalName'][] = $file['name']; | |
| $this->result['fileBaseName'][] = $file['newName']; | |
| $this->result['webPath'][] = str_replace("\\", "/", $webDir.'/'.$file['newName']); | |
| $this->result['uploaded']++; | |
| } | |
| protected function alternativeName($fileName, $path) { | |
| foreach([1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f','g','h','i','h','k','l','m','n','o','p',] as $letter) { | |
| $test = str_replace('.', "$letter.", $fileName); | |
| if(!$this->path_exists($path . '/' . $test)) { | |
| return $test; | |
| } | |
| } | |
| return false; | |
| } | |
| protected function fileError($file, $acceptFilesRegExp) { | |
| if(empty($file['name']) && empty($file['error']) || $file['error'] == 4 ) { | |
| return true; | |
| } | |
| $error = $file['error']; | |
| if(!empty($error)) { | |
| $this->putError($file['name'], $error); | |
| return true; | |
| } | |
| if(!preg_match($acceptFilesRegExp, $file['name'])) { | |
| $this->putError($file['name'], 'accept_file_types'); | |
| return true; | |
| } | |
| if(empty($file['size'])) { | |
| $this->putError($file['name'], 'Error de transmisión: No llego el tamaño del archivo'); | |
| return true; | |
| } | |
| $file_size = iaLib::units2bytes($file['size']); | |
| if(!empty($_POST['MAX_FILE_SIZE']) && is_numeric($_POST['MAX_FILE_SIZE']) ) { | |
| $max_file_size = iaLib::units2bytes($_POST['MAX_FILE_SIZE']); | |
| if($max_file_size > 0 && $file_size > $max_file_size) { | |
| $this->putError($file['name'], 'max_file_size'); | |
| return true; | |
| } | |
| } | |
| $post_max_size = iaLib::units2bytes( ini_get('post_max_size') ); | |
| if(!empty($post_max_size) && is_numeric($post_max_size) ) { | |
| $max_file_size = iaLib::units2bytes($post_max_size); | |
| if($post_max_size > 0 && $file_size > $post_max_size) { | |
| $this->putError($file['name'], 'post_max_size'); | |
| return true; | |
| } | |
| } | |
| if(empty($file['name'])) { | |
| $this->putError($file['name'], 'Error de transmisión: No llego el file name'); | |
| return true; | |
| } | |
| if(empty($file['newName']) || strlen($file['newName'] > 250)) { | |
| $this->putError($file['name'], 'invalid name, muy largo '); | |
| return true; | |
| } | |
| //@TODO newName no sea dir | |
| if(!is_uploaded_file($file['tmp_name'])) { | |
| $this->putError($file['name'], 'invalid upload temporary directory'); | |
| return true; | |
| } | |
| return false; | |
| } | |
| protected function putError($prefix, $error) { | |
| $this->result['ok'] = false; | |
| $this->result['errormsg'][] = $prefix.": ".(isset($this->error_messages[$error]) ? $this->error_messages[$error] : $error); | |
| } | |
| protected function files_normalize() { | |
| $files=[]; | |
| foreach($_FILES as $key=>$f) { | |
| if(!array_key_exists('error',$f)) { | |
| continue; | |
| } | |
| if(!is_array($f['error'])) { | |
| $files[$key][0] = $f; | |
| continue; | |
| } | |
| $len = count($f['error']); | |
| for($i=0; $i < $len; $i++) { | |
| foreach(['name', 'type', 'tmp_name', 'error', 'size'] as $subKey) { | |
| $files[$key][$i][$subKey] = $f[$subKey][$i]; | |
| } | |
| } | |
| } | |
| return $files; | |
| } | |
| public function filename_sanitize($fileName) { | |
| if(empty($fileName)) | |
| return ''; | |
| $fileName = Str::strim($fileName); | |
| $fileName = basename(strtolower( URLify::downcode($fileName, 'latin') )); | |
| $fileName = str_replace([' ', '-', '/', "\\", PATH_SEPARATOR],"_", $fileName); | |
| if($fileName[0] == '.') { | |
| $fileName[0] = '_'; | |
| } | |
| $fileName = preg_replace('/_{2,}/m','_',$fileName); | |
| return $fileName; | |
| } | |
| protected function path_exists($path) { | |
| clearstatcache(); // (true, $path); | |
| return file_exists($path); | |
| } | |
| public function dirnameNoTrailingSlash($dir) { | |
| $lastChar = substr($dir, -1); | |
| if($lastChar == '/' || $lastChar == DIRECTORY_SEPARATOR || $lastChar == "\\") { | |
| return substr($dir, 0, -1); | |
| } | |
| return $dir; | |
| } | |
| } |