Location: PHPKode > projects > AModules3 > amodules-3.0.1/lib/DatabaseStorage.php
<?php
/*
 * Created on 27.10.2006 by *Camper* (hide@address.com)
 */

class DatabaseStorage extends AbstractStorage{
	private $files;
	private $filespaces;
	private $filetypes;
	private $deleted_files;
	
	private $filespace_id;
		
	function init(){
		parent::init();
		//TODO may be assign tables in setSource
		$this->files=$this->api->db->dsql()->table('file');
		$this->filespaces=$this->api->db->dsql()->table('filespace');
		$this->filetypes=$this->api->db->dsql()->table('filetype');
		$this->deleted_files=$this->api->db->dsql()->table('filedelnum');
	}
	function getFileList(){
		$file_list = array();
		//TODO get file list from DB. array should be applicable for datasource usage
		$file_list=$this->files->table('file file')->field('*')->calc_found_rows()->do_getAllHash();
		return $file_list;
	}
	function getFiles(){
		return $this->files;
	}
	function getFilespaces(){
		return $this->filespaces;
	}
	function getFilespacePath(){
		return $this->getFilespaces()->where('id',$this->getFilespaceId())->field('dirname')->do_getOne();
	}
    function getFilespaceId($filesize=0) {
    	if($filesize==0)return $this->filespace_id;
    	if (($res = $this->api->db->getHash("select id, dirname " .
    			"from ".DTP.'filespace'.
    			" where enabled = '1' and (used_space + $filesize) <= total_space " .
    			" and stored_files_cnt < 4096*256*256 " .
    			" limit 1"))===false) {
    		throw new FileException("Error getting filespace");}
		if (empty($res) or (disk_free_space($res['dirname'])<$filesize)) {
			throw new FileException('Unavailable filespace for file!');
		}
		$this->filespace_id=$res['id'];
		return $this->filespace_id;
    }

	function getFileSize($file_id){
		return $this->files->clear_args('where')->where('id',$file_id)->field('filesize')->do_getOne();
	}
	function getFilenum($file_id){
		return $this->files->clear_args('where')->clear_args('fields')->where('id',$file_id)->field('filenum')->do_getOne();
	}
	function deleteFile($file_id){
		$filenum=$this->getFilenum($file_id);
		$this->filespace_id=$this->files->clear_args('fields')->where('id',$file_id)->field('filespace_id')->do_getOne();
    	if ($res = @unlink($this->_real_filename($file_id,$filenum))) {
	    	// update filespace record (decrease used space)
	    	$this->filespaces
	    		->set('used_space = used_space - '.$this->getFilesize($file_id))
	    		->set('stored_files_cnt = stored_files_cnt - 1')
	    		->where('id',$this->getFilespaceId())
	    		->do_update();
/*	
			// enabled filespace if used space less than total space
	    	if ($db->query('update '.tbn('filespace').
	    	               '   set enabled = \'1\' '.
	                       ' where enabled = \'0\' and used_space < total_space and id = :id',
	                       array('int id'=>$this->_filespace_id))===false) db_error(__FILE__,__LINE__);
*/	
			// delete record desctibe currect file
	    	$this->files->clear_args('where')
	    		->where('id',$file_id)
	    		->do_delete();

	    	$this->deleted_files
	    		->set('filespace_id',$this->getFilespaceId())
	    		->set('filenum',$filenum)
	    		->do_insert();
    	}
    	    	
    	return $res; 
	}
	function downloadFile($file_id){
		/**
		 * Returns file data by filespace id and file id
		 */
		$this->filespace_id=$this->files->clear_args('fields')->where('id',$file_id)->field('filespace_id')->do_getOne();
		$file=$this->files->table('file file')->clear_args('where')
			->join('filetype filetype','filetype.id=file.filetype_id')
			->where('file.id',$file_id)
			->field('file.id,file.filename,filetype.mime_type,file.filenum')
			->do_getHash();
        header("Content-type: ".$file['mime_type']);
        header('Content-Disposition: attachment; filename="'.$file['filename'].'"');
        echo file_get_contents($this->_real_filename($file['id'],$file['filenum']));
	}
	function uploadFile($files_array, $saveas_name=''){
		//assigning vars
		$this->upload_orig_name=$files_array['name'];
		$this->upload_temp_name=$files_array['tmp_name'];
		$this->upload_save_name=$saveas_name==''?$this->upload_orig_name:$saveas_name;
		$this->upload_filetype=$files_array['type'];
		$this->upload_temp_name = $this->do_upload($this->upload_temp_name);
		if($this->upload_temp_name === false)
			throw new FileException("Error uploading file: ".$_FILES[$files_array]['error']);
		if($this->upload_filesize==0)throw new BaseException("Error uploading file.");
		if(!$this->getFilespaceId($this->upload_filesize))throw new FileException("Error getting filespace");
		//TODO hooks before saving
		$this->beforeSave();
		try{
			//locking
			if (($res_op = $this->api->db->getOne("/* hack */select get_lock('fs_fnum_lock',5)"))===false) 
				throw new FileException("Error getting record (wonder why?!)");
			if (empty($res_op)) throw new FileException('Error getting lock for filenumber calculation.');
			//trying to get number from the deleted list
			$filenum = $this->deleted_files->field('filenum')->where('filespace_id',$this->getFilespaceId())
				->do_getOne();
			//if successful - use deleted number...
			if (!empty($filenum)) {
				$this->deleted_files->where('filenum',$filenum)->where('filespace_id',$this->getFilespaceId())
					->do_delete();
			}else{
				//...else creating new one
				$filenum = $this->files->field('max(filenum)+1')->where('filespace_id',$this->getFilespaceId())
					->do_getOne();
				$filenum = (empty($filenum))?1:$filenum;
			}
			//inserting a record to files
	    	$this->files
	    		->set('filespace_id',$this->getFilespaceId())
	    		->set('filetype_id',$this->getFileType($this->upload_filetype))
	    		->set('filenum',$filenum)
	    		->set('filename',$this->upload_save_name)
	    		->set('filesize',$this->upload_filesize)
	    		->do_insert(); 
	
	    	$this->_filenum = $filenum;
			$_id = $this->api->db->lastId();  
			// release lock
			if (($res_op = $this->api->db->getOne("/* hack */select release_lock('fs_fnum_lock')"))===false) 
			           throw new FileException("Error releasing lock");
			
			// moving file to its actual destination
			if(!@rename($this->upload_temp_name,$this->_real_filename($_id,$filenum))) {
				$this->files->where('id',$_id)->do_delete();
				$_id = null;
				throw new FileException ('Error moving file '.$this->upload_orig_name.' into filespace ('.
					$this->_real_filename($_id,$filenum).')!'); 
			}else{
				// increase used space
		    	if ($this->filespaces->where('id',$this->getFilespaceId())
		    		->set('used_space = used_space + '.$this->upload_filesize)
		    		->set('stored_files_cnt = stored_files_cnt + 1')
		    		->do_update()===false) throw new FileException("Error updating filespace");
			}
		}catch (FileException $e){
			//releasing locks
			if (!($this->api->db->getOne("/* hack */select IS_FREE_LOCK('fs_fnum_lock')")))
				$this->api->db->getOne("/* hack */select release_lock('fs_fnum_lock')");
			throw $e;
		}
		//TODO hooks after upload
		return $_id;
	}
	function getFileType($filetype){
		$id=$this->filetypes->field('id')->where('mime_type',$filetype)->do_getOne();
		if (empty($id)) {
			$this->filetypes->set('mime_type',$filetype)->do_insert(); 
			$id = $this->api->db->lastId();
		}
		return $id;
	}
	//********** FileHandler routines ***********
    /**
     *  return filename in filespace, create directories if necessary
     */
    private function _real_filename($file_id,$filenum='') {
    	if($filenum=='')$filenum=$this->getFilenum($file_id);
    	$path = str_pad(substr(strtoupper(dechex($filenum)),-7,7), 7, '0', STR_PAD_LEFT);
    	$res = $this->getFilespacePath().DIRECTORY_SEPARATOR.substr($path,0,3);
    	
    	if (!file_exists($res)) 
    		if (!@mkdir($res)) 
    			throw new FileException('Error create directory '.$res);
    		
		$res .= DIRECTORY_SEPARATOR.substr($path,3,2);
    	if (!file_exists($res)) 
    		if (!@mkdir($res)) 
    			throw new FileException('Error create directory '.$res);
		
		$res .= DIRECTORY_SEPARATOR.substr($path,5,2);
    	
    	return $res; 
    }
}
Return current item: AModules3