CoolFace
Apppublic

kenken999/php

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
filehandler.php876 linesDownload Raw Back to classes
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?>