kenken999/php
0
1<?php2/**3 * There are two main classes handling file uploads4 * RunnerFileHandler - Image resizing, verifying file type, preparing file metadata to be saved in the database5 * RunnerFileSystem and children - saving and retrieving files from the filesystem, be it local disk, cloud or maybe database?6 */7 8class RunnerFileHandler {9 public $pSet;10 public $field;11 protected $_datasource;12 protected $_fs;13 protected $options = array();14 /**15 * form identifer for multi-upload control16 */17 public $formStamp;18 19 public function __construct( $field, $pSet, $formStamp = "" ) {20 $this->pSet = $pSet;21 $this->field = $field;22 $this->formStamp = $formStamp;23 }24 25 /**26 * @param Array $uploadedFile - standardized uploaded file descriptor27 * @return Array some other file descriptor28 */29 protected function acceptUploadedFile( $uploadedFile ) {30 // create and fill internal file descriptor31 $file = array();32 33 $errorMessage = "";34 if( $uploadedFile["error"] ) {35 $file["error"] = $this->codeToMessage( $uploadedFile["error"] ); 36 return $file;37 }38 if( !$this->validateFile( $uploadedFile["name"], $uploadedFile["size"], $errorMessage ) ) {39 $file["error"] = $errorMessage;40 return $file;41 }42 $file["type"] = RunnerFileHandler::fileType( $uploadedFile );43 $file["size"] = $uploadedFile["size"];44 45 $file["usrName"] = $this->trimFilename( $uploadedFile["name"] );46 47 if( isImageType( $file["type"] ) ) {48 // resize & thumbnail49 $img_size = $this->getImageDimensions( $uploadedFile );50 $img_width = $img_size[0];51 $img_height = $img_size[1];52 global $resizeImagesOnClient;53 54 if( !$resizeImagesOnClient && $img_width && $img_height && $this->pSet->getResizeOnUpload( $this->field ) ) {55 $resizedFileName = $this->resizeUploadedImage( $uploadedFile, $img_width, $img_height, $this->pSet->getNewImageSize( $this->field ) );56 if( $resizedFileName )57 $file["size"] = filesize( $resizedFileName );58 }59 if( $img_width && $img_height && $this->pSet->getCreateThumbnail( $this->field ) ) {60 $thumbnailFileName = $this->resizeUploadedImage( $uploadedFile, $img_width, $img_height, $this->pSet->getThumbnailSize( $this->field ) );61 if( $thumbnailFileName ) {62 $file["thumbnail_size"] = filesize( $thumbnailFileName );63 $file["thumbnail_type"] = $file["type"];64 }65 }66 }67 68 // save the file69 $fs = $this->getFilesystem();70 if( !$resizedFileName ) {71 // save the original file72 $fileId = $fs->saveUploadedFile( $uploadedFile, $file["usrName"] );73 } else {74 $fileId = $fs->moveFile( $resizedFileName, $file["usrName"] );75 unlink( $resizedFileName );76 }77 if( !$fileId ) {78 $file["error"] = $fs->lastError();79 } else {80 $file["name"] = $fileId;81 }82 83 // save thumbnail84 if( $thumbnailFileName ) {85 $fileId = $fs->moveFile( $thumbnailFileName, "th" . $file["usrName"] );86 unlink( $thumbnailFileName );87 if( $fileId ) {88 $file["thumbnail"] = $fileId;89 }90 }91 92 return $file;93 }94 95 /**96 * @return Boolean97 */98 public function delete( $filename ) {99 $fileData = $this->getFormData( $filename );100 if( !$fileData ) {101 return false;102 }103 if( !$fileData[ "fromDB" ] ) {104 // newly uploaded file, delete immediately105 $sessionFile = $fileData["file"];106 $storageProvider = $this->getFilesystem();107 $storageProvider->delete( $sessionFile["name"] );108 if ( $sessionFile["thumbnail"] ) {109 $storageProvider->delete( $sessionFile["thumbnail"] );110 }111 $this->deleteFormData( $filename );112 } else {113 // previously saved fie. Mark for deletion only.114 // will be acrually deleted on form save115 $fileData["deleted"] = true;116 $this->setFormData( $filename, $fileData );117 }118 return true;119 }120 121 /**122 * @param Array $uploadedFiles - array of standardized uploaded file descriptors123 * @return nothing Sends result to output124 */125 public function acceptUpload( $uploadedFiles ) {126 $result = array();127 foreach ($uploadedFiles as $index => $uploadedFile) {128 $file = $this->acceptUploadedFile( $uploadedFile );129 if( !isset( $file["error"] ) ) {130 $fileData = array();131 $fileData["file"] = $file;132 $fileData["deleted"] = false;133 $fileData["fromDB"] = false;134 $this->setFormData( $file['usrName'], $fileData );135 } 136 $result[] = $this->returnFileDescriptor( $file );137 138 }139 header('Vary: Accept');140 header('Content-type: application/json');141 echo my_json_encode( $result );142 }143 144 /**145 * Build return file descriptor, to be returned right after uploading146 */147 protected function returnFileDescriptor( $file ) {148 $returnFile = array();149 if( isset( $file["error"] )) {150 $returnFile["error"] = $file["error"];151 return $returnFile;152 }153 $returnFile["isImg"] = true;154 $returnFile["name"] = $file["usrName"];155 $returnFile["type"] = $file["type"];156 $returnFile["size"] = $file["size"];157 158 $urlParams = array();159 $urlParams["file"] = $file["usrName"];160 $urlParams["table"] = $this->table();161 $urlParams["field"] = $this->field;162 $urlParams["fkey"] = $this->formStamp;163 $fs = $this->getFilesystem();164 $lastModified = time();165 if( $fs->fast() ) {166 $fsInfo = $fs->getFileInfo( $file["name"] );167 if( $fsInfo && $fsInfo["lastModified"] ) {168 $lastModified = $fsInfo["lastModified"];169 }170 }171 $urlParams["hash"] = fileAttrHash( $this->formStamp, $file["size"], $lastModified );172 $returnFile["url"] = GetTableLink( "file", "", prepareUrlQuery( $urlParams ) );173 174 // prepare icon/thumbnail175 if( !CheckImageExtension( $file["usrName"] ) ) {176 $urlParams["icon"] = 1;177 } else {178 $urlParams["thumbnail"] = 1;179 }180 $returnFile["thumbnail_url"] = GetTableLink("file", "", prepareUrlQuery( $urlParams ) );181 182 return $returnFile;183 184 }185 186 protected function validateFile( $filename, $fileSize, &$errorMessage ) {187 if ( !$filename ) {188 $errorMessage = "File name was not provided";189 return false;190 }191 192 $acceptedTypes = $this->pSet->getAcceptFileTypes( $this->field );193 if( $acceptedTypes ) {194 $ext = strtoupper( getFileExtension( $filename ) );195 if( array_search( $ext, $acceptedTypes ) === false && array_search( ".".$ext, $acceptedTypes ) === false ) {196 $errorMessage = "File type is not acceptable";197 return false;198 }199 }200 201 $maxFileSize = $this->pSet->getMaxFileSize( $this->field );202 if ( $maxFileSize && $fileSize > $maxFileSize * 1024 ) {203 $errorMessage = mysprintf("File size exceeds limit of %s kbytes", array( $maxFileSize ) );204 return false;205 }206 207 $maxTotalFileSize = $this->pSet->getMaxTotalFilesSize( $this->field );208 if ( $maxTotalFileSize ) {209 if( $this->getUploadFilesSize() + $fileSize > $maxTotalFileSize * 1024 ) {210 $errorMessage = mysprintf( "Total files size exceeds limit of %s kbytes", array( $maxTotalFileSize ) );211 return false;212 }213 }214 215 $maxNumberOfFiles = $this->pSet->getMaxNumberOfFiles( $this->field );216 if ( $maxNumberOfFiles && $this->getUploadFilesCount() >= $maxNumberOfFiles ) {217 $errorMessage = mysprintf( "You can upload no more than %s files", array( $maxNumberOfFiles ) );218 return false;219 }220 return true;221 }222 223 /**224 * Return total size of all uploaded files225 */226 protected function getUploadFilesSize() {227 $sessKey = "mupload_".$this->formStamp;228 if( !$_SESSION[ $sessKey ] ) {229 return 0;230 }231 $result = 0;232 foreach($_SESSION[ $sessKey ] as $fileArray ) {233 if( !$fileArray["deleted"] )234 $result += $fileArray["file"]["size"];235 }236 return $result;237 }238 239 protected function getUploadFilesCount() {240 $sessKey = "mupload_".$this->formStamp;241 if( !$_SESSION[ $sessKey ] ) {242 return 0;243 }244 $result = 0;245 foreach($_SESSION[ $sessKey ] as $fileArray ) {246 if( !$fileArray["deleted"] )247 ++$result;248 }249 return $result;250 }251 252 253 protected function getFormData( $filename ) {254 $formInfo = $this->getFormInfo();255 return $formInfo[ $filename ];256 }257 258 protected function setFormData( $filename, $data ) {259 $sessKey = "mupload_".$this->formStamp;260 if( !$_SESSION[ $sessKey ] ) {261 $_SESSION[ $sessKey ] = array();262 }263 $formInfo =& $_SESSION[ $sessKey ];264 if( !$data ) {265 unset( $formInfo[ $filename ] );266 } else {267 $formInfo[ $filename ] = $data;268 }269 }270 271 protected function deleteFormData( $filename ) {272 $this->setFormData( $filename, null );273 }274 275 /**276 * Fetch record from the database277 * @return Array278 */279 protected function getTableRecord( $keys ) {280 $dc = new DsCommand();281 if( Security::fieldIsUserpic( $this->table(), $this->field ) && !$this->tableRightsAvailable() ) {282 // if no view rights on the users table, show the userpic anyway283 $dc->filter = Security::currentUserCondition();284 } else {285 // show file/image if the user has access to either list/view or edit, or print page286 $dc->filter = $this->securityCondition();287 $dc->keys = $keys;288 }289 290 $dataSource = $this->getDataSource();291 $qResult = $dataSource->getSingle( $dc );292 if( !$qResult ) {293 return null;294 }295 $cipherer = new RunnerCipherer( $this->table(), $this->pSet );296 return $cipherer->DecryptFetchedArray( $qResult->fetchAssoc() );297 }298 299 /**300 * return file info in unified format301 * @return Array [302 * "usrName" => user-provided filename303 * "name" => file path if saved in filesystem304 * "value" => file contents if saved in DB. If thumbnail is requested, thumbnail305 * "type" => file type in HTTP-ready format.306 * "size" => size in bytes307 * "thumbnail" => thumbnail file path308 * "thumbnail_size" => thumbnail size309 * "thumbnail_type" => thumbnail file type in HTTP-ready format310 * ]311 */312 protected function getFileInfo( $filename, $thumbnail, $keys ) {313 if( $this->formStamp ) {314 // newly uploaded file315 $data = $this->getFormData( $filename );316 if( $data ) {317 return $data["file"];318 } else {319 // when formstamp used, ignore all other parameters pointing to the file like $keys320 return null;321 }322 }323 if( !$keys ) {324 return null;325 }326 $data =& $this->getTableRecord( $keys );327 328 // file in the database329 if( $this->databaseFile() ) {330 $fileData = array();331 $ds = $this->getDataSource();332 $connection = $ds->getConnection();333 if( $thumbnail ) {334 $thumbField = $this->pSet->getStrThumbnail( $this->field );335 if( $thumbField && $data[ $thumbField ] ) {336 $fileData["value"] = $connection->stripSlashesBinary( $data[ $thumbField ] );337 }338 }339 if( !$fileData["value"] )340 $fileData["value"] = $connection->stripSlashesBinary( $data[ $this->field ] );341 if( !$fileData["value"] ) {342 return null;343 }344 $filenameField = $this->pSet->getFilenameField( $this->field );345 if( $filenameField && $data[ $filenameField ] ) {346 $fileData["usrName"] = $data[ $filenameField ];347 } else {348 $fileData["usrName"] = "file.bin";349 }350 351 $fileData["size"] = strlen_bin( $fileData["value"] );352 $fileData["type"] = SupposeImageType( $fileData["value"] );353 return $fileData;354 }355 356 // file in filesystem357 $fs = $this->getFilesystem();358 $filesArray = my_json_decode( $data[ $this->field ] );359 if( !is_array( $filesArray ) || count( $filesArray ) == 0 )360 {361 $filesArray = array();362 $dbFilename = $data[ $this->field ];363 $filePath = $this->pSet->getUploadFolder( $this->field ) . $dbFilename;364 365 $fsFile = $fs->getFileInfo( $filePath );366 if( !$fsFile ) {367 return null;368 }369 $fileDesc = array();370 $fileDesc["usrName"] = runner_basename( $dbFilename );371 $fileDesc["name"] = $fsFile["fullPath"];372 $fileDesc["type"] = mimeTypeByExt( getFileExtension( $dbFilename ) );373 $fileDesc["size"] = $fsFile["size"];374 if( $this->pSet->showThumbnail( $this->field ) ) {375 $thumbPath = $this->pSet->getUploadFolder( $this->field ) . $this->pSet->getStrThumbnail( $this->field ) . $dbFilename;376 $fsThumb = $fs->getFileInfo( $thumbPath );377 if( $fsThumb ) {378 $fileDesc["thumbnail"] = $fsThumb["fullPath"];379 $fileDesc["thumbnail_size"] = $fsThumb["size"];380 $fileDesc["thumbnail_type"] = $fileDesc["type"];381 }382 }383 $filesArray[] = $fileDesc;384 }385 foreach( $filesArray as $uploadedFile ) {386 if( $uploadedFile["usrName"] == $filename ) {387 return $uploadedFile;388 }389 }390 return null;391 }392 393 394 /**395 * Sends the file to the output396 * returns nothing397 * @param String $filename398 * @param Boolean $thumb - when thumbnail is requested399 * @param Boolean $icon - show icon instead of a file.400 * @param Array $keys - key field values to find the record in the database.401 */402 public function showFile( $filename, $thumbnail, $icon, $outputAsAttachment, $useHttpRange, $keys ) {403 if($filename == "")404 return;405 $fileData = $this->getFileInfo( $filename, $thumbnail, $keys );406 407 if( $fileData && !$this->databaseFile() ) {408 // read file info from the filesystem409 $fs = $this->getFilesystem();410 $fsFile = $fs->getFileInfo( $fileData["name"] );411 if( !$fsFile && $fs->lastError() ) {412 showError( $fs->lastError() );413 return;414 }415 }416 417 // non-existing image is requested418 if( !$fileData || !$this->databaseFile() && !$fsFile ) {419 if( $this->imageField() ) {420 $fileData = array();421 $fileData["usrName"] = $filename;422 $fileData["value"] = myfile_get_contents( getabspath( 'images/no_image.gif' ) );423 $fileData["type"] = "image/gif";424 $fileData["size"] = strlen_bin( $fileData["value"] );425 } else {426 return;427 }428 }429 430 if( $thumbnail && $fileData["thumbnail"] ) {431 $fileData["name"] = $fileData["thumbnail"];432 $fileData["size"] = $fileData["thumbnail_size"];433 $fileData["type"] = $fileData["thumbnail_type"];434 }435 436 if( $icon ) {437 $fileData["value"] = myfile_get_contents( getabspath( "images/icons/".getIconByFileType( $fileData["type"], $fileData["usrName"] ) ) );438 $fileData["size"] = strlen_bin( $fileData["value"] );439 $fileData["type"] = "image/png";440 }441 442 if( !$fileData["type"] ) {443 $fileData["type"] = "application/octet-stream";444 }445 446 if( !$fileData["size"] ) {447 if( $fileData["value"] ) {448 $fileData["size"] = strlen_bin( $fileData["value"] );449 } else {450 // ??? 451 $fileData["size"] = $fsFile["size"];452 }453 }454 455 if( !$fileData["value"] && $fsFile && !$fsFile["returnContent"] ) {456 add_nocache_headers();457 $result = $fs->redirectToFile( $fileData["name"], $thumbnail );458 if( $result === false ) {459 showError( $fs->lastError() );460 }461 exit();462 }463 464 $eTag = RunnerFileHandler::calculateETag( $fileData, $fsFile );465 if( $eTag ) {466 header('ETag:' . $eTag );467 if( $_SERVER['HTTP_IF_NONE_MATCH'] === $eTag ) {468 http_response_code( 304 );469 exit();470 }471 }472 if( $useHttpRange && $_SERVER['HTTP_RANGE'] ) {473 $this->showPartialFile( $fileData, $outputAsAttachment );474 } else {475 header('Accept-Ranges: none');476 header("Cache-Control: private, max-age=604800, must-revalidate");477 header("Content-Type: ". $fileData["type"] );478 header('Access-Control-Allow-Methods: HEAD, GET, POST');479 if( $outputAsAttachment )480 header("Content-Disposition: attachment;Filename=\"". $fileData["usrName"] . "\"");481 sendContentLength( $fileData["size"] );482 if($_SERVER['REQUEST_METHOD'] == 'HEAD')483 exit();484 if( $fileData["value"] )485 echoBinary( $fileData["value"] );486 else {487 $fs->printPartial( $fileData["name"] );488 }489 }490 }491 492 protected function showPartialFile( $fileData, $outputAsAttachment ) {493 $httpRange = $_SERVER['HTTP_RANGE'];494 $size_unit = "";495 $range_orig = "";496 if(preg_match('/^bytes=((\d*-\d*,? ?)+)$/', $httpRange) )497 {498 $rangeParts = explode('=', $httpRange);499 $size_unit = $rangeParts[0];500 $range_orig = $rangeParts[1];501 }502 if ($size_unit == 'bytes')503 {504 //multiple ranges could be specified at the same time, but we accept only the first range505 if(strpos($range_orig, ',') !== false)506 {507 $rangeParts = explode(',', $range_orig);508 $range = $rangeParts[0];509 $extra_ranges = $rangeParts[1];510 }else511 $range = $range_orig;512 }513 else {514 $range = '-';515 }516 //figure out download piece from range (if set)517 $rangeParts = explode('-', $range);518 $seek_start = $rangeParts[0];519 $seek_end = $rangeParts[1];520 521 //set start and end based on range (if set), else set defaults522 //also check for invalid ranges.523 $seek_end = (strlen($seek_end) == 0) ? ($fileData["size"] - 1) : min(abs(intval($seek_end)),($fileData["size"] - 1));524 $seek_start = (strlen($seek_start) == 0 || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);525 526 // print headers527 header('HTTP/1.1 206 Partial Content');528 header('Accept-Ranges: bytes');529 header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$fileData["size"]);530 531 if( $outputAsAttachment ) {532 header("Content-Disposition: attachment;Filename=\"".$fileData["usrName"]."\"");533 }534 header( "Content-Length: ". ($seek_end - $seek_start + 1) );535 536 header("Cache-Control: cache, must-revalidate");537 header("Pragma: public");538 header("Content-Type: ".$fileData["type"] );539 if($_SERVER['REQUEST_METHOD'] == 'HEAD') {540 exit();541 }542 if( $fileData["value"] ) {543 echoBinaryPartial( $fileData["value"], $seek_start, $seek_end );544 } else {545 $fs = $this->getFilesystem();546 $fs->printPartial( $fileData["name"], $seek_start, $seek_end );547 }548 }549 550 protected function table() {551 return $this->pSet->table();552 }553 554 protected function pageType() {555 return $this->pSet->pageType();556 }557 558 /**559 * Tells whether the file is saved in the database, not in filesystem560 * @return Boolean561 */562 protected function databaseFile() {563 $viewFormat = $this->pSet->getViewFormat( $this->field );564 return $viewFormat == FORMAT_DATABASE_IMAGE 565 || $viewFormat == FORMAT_DATABASE_FILE566 || $viewFormat == FORMAT_DATABASE_AUDIO567 || $viewFormat == FORMAT_DATABASE_VIDEO;568 }569 570 /**571 * @return Boolean - when View as type is Image572 */573 protected function imageField() {574 $viewFormat = $this->pSet->getViewFormat( $this->field );575 return $viewFormat == FORMAT_DATABASE_IMAGE || $viewFormat == FORMAT_FILE_IMAGE;576 }577 578 protected function getDataSource() {579 if( !$this->_datasource ) {580 $this->_datasource = getDataSource( $this->table(), $this->pSet );581 }582 return $this->_datasource;583 }584 protected function getFilesystem() {585 if( !$this->_fs ) {586 $this->_fs = getStorageProvider( $this->pSet, $this->field );587 }588 return $this->_fs;589 }590 591 public static function fileType( $uploadedFile ) {592 if( $uploadedFile ["type"] ) {593 return $uploadedFile ["type"];594 }595 return mimeTypeByExt( getFileExtension( $uploadedFile["name"] ) );596 }597 598 /**599 * Return unique user-friendly file name600 */601 protected function trimFilename( $name ) {602 while( $this->getFormData( $name ) ) {603 $name = upcount_name( $name );604 }605 return $name;606 }607 608 /**609 * save the image and return the full path to the new image610 * null when there is no new file611 */612 protected function resizeUploadedImage( $uploadedFile, $img_width, $img_height, $size ) {613 614 $scale = min(615 $size / $img_width,616 $size / $img_height617 );618 if ($scale >= 1) {619 return null;620 }621 $new_width = $img_width * $scale;622 $new_height = $img_height * $scale;623 $tempDir = $this->tempFileDir();624 $options = array();625 $newFilename = DiskFileSystem::uniqueFilename( "resize", $tempDir );626 627 $newPath = $tempDir.$newFilename;628 $success = imageCreateThumb(629 $new_width,630 $new_height,631 $img_width,632 $img_height,633 $uploadedFile["tmp_name"],634 $options,635 $newPath,636 $uploadedFile637 );638 639 if( !$success ){640 return null;641 }642 return $tempDir.$newFilename;643 }644 645 /**646 * return String - temporary file directory. Always ends with '/' or '\'647 */648 protected function tempFileDir() {649 $providerType = $this->pSet->fileStorageProvider( $field );650 if( $providerType == stpDISK) {651 return DiskFileSystem::normalizePath( $this->pSet->getUploadFolder( $this->field ) );652 }653 return getabspath( "templates_c" );654 }655 656 657 /**658 * Returns image dimensions if needed659 */660 function getImageDimensions( $uploadedFile ) {661 if( $this->pSet->getCreateThumbnail( $this->field ) || $this->pSet->getResizeOnUpload( $this->field ) ) {662 return runner_getimagesize( $uploadedFile["tmp_name"], $uploadedFile );663 }664 return array();665 }666 667 function codeToMessage($code)668 {669 switch ($code) {670 case 1 /*UPLOAD_ERR_INI_SIZE*/:671 $message = "UPLOAD_ERR_INI_SIZE: The uploaded file exceeds the upload_max_filesize directive in php.ini";672 break;673 case 2 /*UPLOAD_ERR_FORM_SIZE*/:674 $message = "UPLOAD_ERR_FORM_SIZE: The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form";675 break;676 case 3 /*UPLOAD_ERR_PARTIAL*/:677 $message = "UPLOAD_ERR_PARTIAL: The uploaded file was only partially uploaded";678 break;679 case 4 /*UPLOAD_ERR_NO_FILE*/:680 $message = "UPLOAD_ERR_NO_FILE: No file was uploaded";681 break;682 case 6 /*UPLOAD_ERR_NO_TMP_DIR*/:683 $message = "UPLOAD_ERR_NO_TMP_DIR: Missing a temporary folder";684 break;685 case 7 /*UPLOAD_ERR_CANT_WRITE*/:686 $message = "UPLOAD_ERR_CANT_WRITE: Failed to write file to disk";687 break;688 case 8 /*UPLOAD_ERR_EXTENSION*/:689 $message = "UPLOAD_ERR_EXTENSION: File upload stopped by extension";690 break;691 692 default:693 $message = "Unknown upload error";694 break;695 }696 return $message;697 }698 /**699 * @return Boolean - when true, browser uploads files directly to the filesystem skipping the PHP code.700 */701 public function directUpload() {702 $fs = $this->getFilesystem();703 return $fs->directUpload();704 }705 706 /**707 * @param Array $fileData - File interface from JS API708 * https://developer.mozilla.org/en-US/docs/Web/API/File709 * name: string710 * size: number711 * type: string712 * ...713 * 714 * @return Nothing715 * Sends JSON HTML response:716 * {717 * uploadParams: any data to be sent to browser,718 * file: 719 * error?: string - when url is empty720 * }721 * 722 */723 public function prepareDirectUpload( $fileData ) {724 725 $result = array();726 $file = array();727 if( !$this->validateFile( $fileData["name"], $fileData["size"], $errorMessage ) ) {728 $file["error"] = $errorMessage;729 } else {730 $fs = $this->getFilesystem();731 $uploadInfo = $fs->initUpload( $fileData["name"] );732 if( $uploadInfo ) {733 $file["usrName"] = $this->trimFilename( $fileData["name"] );734 $file["size"] = $fileData["size"];735 $file["type"] = $fileData["type"];736 $file["name"] = $uploadInfo['fileId'];737 738 $result["uploadParams"] = $uploadInfo['uploadParams'];739 } else {740 $file["error"] = $fs->lastError();741 }742 743 }744 if( !isset( $file["error"] ) ) {745 $fileData = array();746 $fileData["file"] = $file;747 $fileData["deleted"] = false;748 $fileData["fromDB"] = false;749 $this->setFormData( $file['usrName'], $fileData );750 751 $result["file"] = $this->returnFileDescriptor( $file );752 } else {753 $result["error"] = $file["error"];754 }755 header('Vary: Accept');756 header('Content-type: application/json');757 echo my_json_encode( $result );758 exit();759 }760 761 public static function calculateETag( &$fileData, &$fsFile ) {762 if( !$fileData["value"] && $fsFile ) {763 if( $fsFile["lastModified"] ) {764 return md5( $fileData["name"] . $fsFile["lastModified"] );765 }766 } else if( $fileData["value"] ) {767 $fileSize = strlen_bin( $fileData["value"] );768 $chunkSize = $fileSize > 2000 ? 2000 : $fileSize;769 return md5( $fileSize . substr( $fileData["value"], 0, $chunkSize ) );770 }771 return "";772 }773 774 /**775 * Create session data corresponding to the file field776 * @param - $filesArray - parsed file field contents777 * @return Array to be returned to the JS code778 */779 public function loadFiles( $filesArray ) {780 $userFilesArray = array();781 foreach ( $filesArray as $file ) {782 $sessionArray = array();783 $sessionArray["file"] = $file;784 $sessionArray["fromDB"] = true;785 $sessionArray["deleted"] = false;786 $this->setFormData( $file["usrName"], $sessionArray );787 $userFile = $this->returnFileDescriptor( $file );788 $userFilesArray[] = $userFile;789 }790 return $userFilesArray;791 }792 793 /**794 * Parse and normalize field value from the database795 * @return Array of arrays [796 * "usrName" => user-provided filename797 * "name" => file path if saved in filesystem798 * "type" => (optional) file type in HTTP-ready format.799 * "size" => (optional)size in bytes800 * "thumbnail" => (optional)thumbnail file path801 * "thumbnail_size" => (optional)thumbnail size802 * "thumbnail_type" => (optional)thumbnail file type in HTTP-ready format803 * ]804 */805 public static function getFileArray( $value, $field, $pSet ) {806 if( !$value || $value == "[]") {807 return array();808 }809 $files = runner_json_decode( $value );810 if( $files ) {811 return $files; 812 }813 $path = DiskFileSystem::normalizeRelativePath( $pSet->getUploadFolder( $field ) );814 $fileData = array();815 $fileData["usrName"] = runner_basename( $value );816 $fileData["name"] = $path . $value;817 if( $pSet->showThumbnail( $field ) ) {818 $thumbprefix = $pSet->getStrThumbnail( $field );819 $fileData["thumbnail"] = $path.$thumbprefix.$value;820 }821 return array( $fileData );822 }823 824 /**825 * @return DSCondition or null826 */827 protected function securityCondition() {828 $rights = array( "S", "P", "E" );829 $conditions = array();830 foreach( $rights as $r ) {831 $cond = Security::SelectCondition( $r, $this->pSet );832 // SelectCondition returns NULL when no restrictions!833 if( !$cond ) {834 return null;835 }836 $conditions[] = $cond;837 }838 return DataCondition::_Or( $conditions );839 }840 841 /**842 * return boolean843 */844 protected function tableRightsAvailable() {845 $rights = array( "S", "P", "E" );846 $mask = GetUserPermissions( $this->table() );847 foreach( $rights as $r ) {848 if( strpos( $mask, $r ) !== false ) {849 return true;850 }851 }852 return false;853 }854 855 protected function getFormInfo() {856 $formInfo =& $_SESSION["mupload_".$this->formStamp];857 if( !$formInfo ) {858 return array();859 }860 861 return $formInfo;862 }863 864 public function resetUplodedFiles() {865 $formInfo = $this->getFormInfo();866 foreach ($formInfo as $usrName => $fileData) {867 $info = $fileData["file"];868 if( !$info["fromDB"] ) {869 $this->delete( $usrName );870 }871 }872 return true;873 }874}875 876?>