openrat-cms

# OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs

File.class.php (13867B)


      1 <?php
      2 namespace cms\model;
      3 // OpenRat Content Management System
      4 // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de
      5 //
      6 // This program is free software; you can redistribute it and/or
      7 // modify it under the terms of the GNU General Public License
      8 // as published by the Free Software Foundation; either version 2
      9 // of the License, or (at your option) any later version.
     10 //
     11 // This program is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 //
     16 // You should have received a copy of the GNU General Public License
     17 // along with this program; if not, write to the Free Software
     18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     19 
     20 
     21 // Standard Mime-Type 
     22 use cms\publish\filter\AbstractFilter;
     23 use cms\publish\PublishEdit;
     24 use cms\publish\PublishPreview;
     25 use cms\publish\PublishPublic;
     26 use cms\publish\PublishShow;
     27 use JSqueeze;
     28 use Less_Parser;
     29 use Logger;
     30 use util\FileCache;
     31 
     32 define('OR_FILE_DEFAULT_MIMETYPE','application/octet-stream');
     33 
     34 
     35 /**
     36  * Datei.
     37  *
     38  * @author Jan Dankert
     39  * @package openrat.objects
     40  */
     41 class File extends BaseObject
     42 {
     43 	var $fileid;
     44 
     45 	var $size          = 0;
     46 	var $value         = '';
     47 	var $extension     = '';
     48 	var $log_filenames = array();
     49 	var $fullFilename  = '';
     50 
     51     /**
     52      * @var \Publish
     53      */
     54 	var $publish       = null;
     55 
     56 	var $mime_type     = '';
     57 
     58 	var $tmpfile;
     59 
     60 	var $content_negotiation = false;
     61 
     62 
     63 
     64 	/**
     65 	 * Um Probleme mit BLOB-Feldern und Datenbank-Besonderheiten zu vermeiden,
     66 	 * kann der Binaerinhalt BASE64-kodiert gespeichert werden.
     67 	 * @type Boolean
     68 	 */
     69 	var $storeValueAsBase64 = false;
     70 
     71     public $filterid;
     72 
     73     public $public = false ;
     74 
     75     /**
     76 	 * Konstruktor
     77 	 *
     78 	 * @param Objekt-Id
     79 	 */
     80 	function __construct( $objectid='' )
     81 	{
     82 		$this->storeValueAsBase64 = db()->conf['base64'];
     83 
     84 		parent::__construct( $objectid );
     85 		$this->isFile = true;
     86 		$this->typeid = BaseObject::TYPEID_FILE;
     87     }
     88 
     89 
     90     /**
     91      * @return FileCache
     92      */
     93     public function getCache() {
     94         $cacheKey = array('db'=>db()->id,'file'=>$this->objectid,'publish'=>\ClassUtils::getSimpleClassName($this->publisher));
     95 
     96         return new FileCache( $cacheKey,function() {
     97             return $this->loadValueFromDatabase();
     98         }, $this->lastchangeDate );
     99     }
    100 
    101 	/**
    102 	  * Ermitteln des Dateinamens dieser Datei
    103 	  *
    104 	  * @return String Kompletter Dateiname, z.B. '/pfad/datei.jpeg'
    105 	  */
    106 	function full_filename()
    107 	{
    108 		if	( !empty($this->fullFilename) )
    109 			return $this->fullFilename;
    110 
    111 		$filename = parent::full_filename();
    112 
    113 		if	( $this->content_negotiation && config('publish','negotiation','file_negotiate_type' ) )
    114 		{
    115 			// Link auf Datei: Extension bleibt aufgrund Content-Negotiation leer
    116 		}
    117 		else
    118 		{
    119 		    // Nein, wurde bereits in filename() ergänzt.
    120 			//if	( !empty($this->extension) )
    121 			//	$filename .= '.'.$this->extension;
    122 		}
    123 
    124 		$this->fullFilename = $filename;
    125 		return $filename;
    126 	}
    127 
    128 
    129 
    130     /**
    131      * Ermitteln des Dateinamens dieser Datei (ohne Pfadangabe)
    132      *
    133      * @return String Kompletter Dateiname, z.B. '/pfad/datei.jpeg'
    134      */
    135 	public function filename()
    136     {
    137         if	( $this->extension )
    138             return parent::filename().'.'.$this->extension;
    139         else
    140             return parent::filename();
    141 
    142     }
    143 
    144 
    145 
    146 	/**
    147 	  * Ermitteln aller Eigenschaften.
    148 	  *
    149 	  * @return array
    150 	  */
    151 	function getProperties()
    152 	{
    153 		return array_merge( parent::getProperties(),
    154 		                    array('full_filename'=>$this->fullFilename,
    155 		                          'extension'    =>$this->extension,
    156 		                          'size'         =>$this->size,
    157 		                          'filterid'     =>$this->filterid,
    158 		                          'mimetype'     =>$this->mimetype()   ) );
    159 	}
    160 
    161 
    162 
    163 	/**
    164 	 * @deprecated
    165 	 */
    166 	function getFileObjectIdsByExtension( $extension )
    167 	{
    168 		global $SESS;
    169 		$db = db_connection();
    170 
    171 		$sqlquery = 'SELECT * FROM {{object}} ';
    172 
    173 		if   ( $extension != '' )
    174 		{
    175 			$sqlquery .= " WHERE extension='";
    176 
    177 			$ext = explode(',',$extension);
    178 			$sqlquery .= implode( "' OR extension='",$ext );
    179 			$sqlquery .= "' AND typeid=".BaseObject::TYPEID_FILE." AND projectid={projectid}";
    180 		}
    181 		else
    182 		{
    183 			$sqlquery .= " WHERE typeid=".BaseObject::TYPEID_FILE." AND projectid={projectid}";
    184 		}
    185 
    186 		$sql = $db->sql( $sqlquery );
    187 		$sql->setInt( 'projectid',$SESS['projectid'] );
    188 
    189 		return $sql->getCol();
    190 	}
    191 
    192 
    193 
    194 	/**
    195 	  * Es werden Objekte zu einer Dateierweiterung ermittelt
    196 	  *
    197 	  * @param String Dateierweiterung ohne fuehrenden Punkt (z.B. 'jpeg')
    198 	  * @return array Liste der gefundenen Objekt-IDs
    199 	  */
    200 	public static function getObjectIdsByExtension( $extension )
    201 	{
    202 		$db = db_connection();
    203 
    204 		$sql = $db->sql( 'SELECT {{file}}.objectid FROM {{file}} '.
    205 		                ' LEFT JOIN {{object}} '.
    206 		                '   ON {{object}}.id={{file}}.objectid'.
    207 		                ' WHERE {{file}}.extension={extension}' );
    208 		$sql->setString( 'extension',$extension       );
    209 
    210 		return $sql->getCol();
    211 	}
    212 
    213 
    214 
    215 	/**
    216 	 * Ermittelt den Mime-Type zu dieser Datei
    217 	 *
    218 	 * @return String Mime-Type
    219 	 */
    220 	public function mimeType()
    221 	{
    222 		if	( !empty( $this->mime_type ) )
    223 			return $this->mime_type;
    224 
    225 		global $conf;
    226 		$mime_types = $conf['mime-types'];
    227 
    228 
    229 
    230 		$ext = strtolower( $this->getRealExtension() );
    231 
    232 		if	( !empty($mime_types[$ext]) )
    233 			$this->mime_type = $mime_types[$ext];
    234 		else
    235 			// Wenn kein Mime-Type gefunden, dann Standartwert setzen
    236 			$this->mime_type = OR_FILE_DEFAULT_MIMETYPE;
    237 
    238 		return( $this->mime_type );
    239 	}
    240 
    241 
    242 	/**
    243 	 * Lesen der Datei aus der Datenbank.
    244 	 *
    245 	 * Es werden nur die Meta-Daten (Erweiterung, Gr��e) gelesen. Zum Lesen des
    246 	 * Datei-Inhaltes muss #loadValue() aufgerufen werden.
    247 	 */
    248 	public function load()
    249 	{
    250 		$db = db_connection();
    251 
    252 		$sql = $db->sql( 'SELECT id,extension,size,filterid'.
    253 		                ' FROM {{file}}'.
    254 		                ' WHERE objectid={objectid}' );
    255 		$sql->setInt( 'objectid',$this->objectid );
    256 		$row = $sql->getRow();
    257 
    258 		if	( count($row)!=0 )
    259 		{
    260 			$this->fileid    = $row['id'       ];
    261 			$this->extension = $row['extension'];
    262 			$this->size      = $row['size'     ];
    263 			$this->filterid  = $row['filterid' ];
    264 		}
    265 
    266 		$this->objectLoad();
    267 
    268 		return $this;
    269 	}
    270 
    271 
    272 
    273 	/**
    274 	 * Unwiderrufliches L�schen der Datei aus der Datenbank.
    275 	 */
    276 	function delete()
    277 	{
    278 		$db = db_connection();
    279 
    280 		// Datei l?schen
    281 		$sql = $db->sql( 'DELETE FROM {{file}} '.
    282 		                '  WHERE objectid={objectid}' );
    283 		$sql->setInt( 'objectid',$this->objectid );
    284 		$sql->query();
    285 
    286 		$this->objectDelete();
    287 	}
    288 
    289 
    290 
    291 	/**
    292 	 * Stellt anhand der Dateiendung fest, ob es sich bei dieser Datei um ein Bild handelt
    293 	 */
    294 	function isImage()
    295 	{
    296 		return substr($this->mimeType(),0,6)=='image/';
    297 	}
    298 
    299 
    300 
    301 	/**
    302 	 * Ermittelt die Datei-Endung.
    303 	 *
    304 	 * @return String Datei-Endung
    305 	 */
    306 	function extension()
    307 	{
    308 		if ($this->extension != '')
    309 			return $this->extension;
    310 
    311 		$this->load();
    312 		return $this->extension;
    313 	}
    314 
    315 
    316 	/**
    317 	 * Einen Dateinamen in Dateiname und Extension aufteilen.
    318 	 * @param filename Dateiname
    319 	 */
    320 	function parse_filename($filename)
    321 	{
    322 		$filename = basename($filename);
    323 
    324 		$p = strrpos($filename, '.');
    325 		if ($p !== false)
    326 		{
    327 			$this->extension = substr($filename, $p +1);
    328 			$this->filename = substr($filename, 0, $p);
    329 		}
    330 		else
    331 		{
    332 			$this->extension = '';
    333 			$this->filename = $filename;
    334 		}
    335 	}
    336 
    337 
    338 	/**
    339 	 * Speichert die Datei-Informationen in der Datenbank.
    340 	 */
    341 	public function save()
    342 	{
    343 		$db = db_connection();
    344 
    345 		$sql = $db->sql( <<<EOF
    346 UPDATE {{file}} SET
    347   size      = {size},
    348   filterid  = {filterid},
    349   extension = {extension}
    350   WHERE objectid={objectid}
    351 EOF
    352 );
    353 		$sql->setString('size'     ,$this->size      );
    354 		$sql->setString('extension',$this->extension );
    355 		$sql->setString('objectid' ,$this->objectid  );
    356 		$sql->setInt   ('filterid' ,$this->filterid  );
    357 		$sql->query();
    358 
    359 		$this->objectSave();
    360 	}
    361 
    362 
    363 	/**
    364 	 * Kopieren des Inhaltes von einer anderen Datei
    365 	 * @param ID der Datei, von der der Inhalt kopiert werden soll
    366 	 */
    367 	function copyValueFromFile( $otherfileid )
    368 	{
    369 		$of = new File( $otherfileid );
    370 		$this->value = $of->loadValue();
    371 		$this->saveValue();
    372 	}
    373 
    374 
    375     public function loadValue()
    376     {
    377         if	( is_file( $this->getCache()->getFilename() ) && filemtime($this->getCache()->getFilename() < $this->lastchangeDate))
    378             $this->getCache()->invalidate();
    379 
    380         return $this->getCache()->get();
    381     }
    382 
    383 
    384         /**
    385 	 * Lesen des Inhaltes der Datei aus der Datenbank.
    386 	 *
    387 	 * @return String Inhalt der Datei
    388 	 */
    389 	private function loadValueFromDatabase()
    390 	{
    391 	    // Read from cache, if cache exist and is not too old.
    392 
    393 		$settings    = $this->getSettings();
    394 		$proxyFileId = @$settings['proxy-file-id'];
    395 
    396 		if   ( $proxyFileId )
    397 			$objectid = $proxyFileId; // This is a proxy for another file.
    398 		else
    399 			$objectid = $this->objectid;
    400 
    401 		$sql = db()->sql( 'SELECT size,value'.
    402 		                ' FROM {{file}}'.
    403 		                ' WHERE objectid={objectid}' );
    404 		$sql->setInt( 'objectid', $objectid);
    405 		$row = $sql->getRow();
    406 
    407 		if	( count($row) != 0 )
    408 		{
    409 			$this->value = $row['value'];
    410 			$this->size  = $row['size' ];
    411 		}
    412 
    413 		if	( $this->storeValueAsBase64 )
    414 			$this->value = base64_decode( $this->value );
    415 
    416         $this->filterValue();
    417 
    418 		return $this->value;
    419 	}
    420 
    421 
    422 	/**
    423 	 * Speichert den Inhalt in der Datenbank.
    424 	 */
    425 	function saveValue( $value = '' )
    426 	{
    427 		$this->getCache()->invalidate();
    428 
    429 		$db = db_connection();
    430 
    431 		$sql = $db->sql( 'UPDATE {{file}}'.
    432 		                ' SET value={value}, '.
    433 		                '      size={size}   '.
    434 		                ' WHERE objectid={objectid}' );
    435 		$sql->setString( 'objectid' ,$this->objectid      );
    436 		$sql->setInt   ( 'size'     ,strlen($this->value) );
    437 
    438 		if	( $this->storeValueAsBase64 )
    439 			$sql->setString( 'value',base64_encode($this->value) );
    440 		else
    441 			$sql->setString( 'value',$this->value );
    442 
    443 		$sql->query();
    444 	}
    445 
    446 
    447 	/**
    448 	 * Lesen der Datei aus der Datenbank und schreiben in temporaere Datei
    449 	 */
    450 	function write()
    451 	{
    452 	    $this->getCache()->load();
    453 	}
    454 
    455 
    456 	/**
    457 	 * F�gt die Datei der Datenbank hinzu.
    458 	 */
    459 	function add()
    460 	{
    461 		parent::add();
    462 
    463 		$sql = db()->sql('SELECT MAX(id) FROM {{file}}');
    464 		$this->fileid = intval($sql->getOne())+1;
    465 
    466 		$sql = db()->sql('INSERT INTO {{file}}'.
    467 		               ' (id,objectid,extension,size,value)'.
    468 		               " VALUES( {fileid},{objectid},{extension},0,'' )" );
    469 		$sql->setInt   ('fileid'   ,$this->fileid        );
    470 		$sql->setInt   ('objectid' ,$this->objectid      );
    471 		$sql->setString('extension',$this->extension     );
    472 
    473 		$sql->query();
    474 
    475 		$this->saveValue();
    476 	}
    477 
    478 
    479 	public function publish()
    480 	{
    481 		$this->write();
    482 		$this->publisher->copy( $this->getCache()->getFilename(),$this->full_filename(),$this->lastchangeDate );
    483 
    484 		$this->publisher->publishedObjects[] = $this->getProperties();
    485 	}
    486 
    487 
    488 	/**
    489 	 * Setzt den Zeitstempel der Datei auf die aktuelle Zeit.
    490 	 *
    491 	 * @see objectClasses/Object#setTimestamp()
    492 	 */
    493 
    494 	function setTimestamp()
    495 	{
    496         $this->getCache()->invalidate();
    497 
    498 		parent::setTimestamp();
    499 	}
    500 
    501 
    502 
    503 
    504 	/**
    505 	 * Change type.
    506 	 *
    507 	 * This is only allowed for files, because it is only allowed to switch between the following types: file,image,text.
    508 	 */
    509 	public function updateType()
    510 	{
    511 
    512 		$stmt = db()->sql(<<<SQL
    513 UPDATE {{object}} SET 
    514       typeid = {typeid}
    515 WHERE id={objectid}
    516 SQL
    517 		);
    518 
    519 		$stmt->setInt('typeid'  , $this->typeid  );
    520 		$stmt->setInt('objectid', $this->objectid);
    521 		$stmt->query();
    522 	}
    523 
    524 
    525 
    526 
    527 	/**
    528 	 * Ermittelt die wirksame Datei-Endung. Diese kann sich
    529 	 * in der Extra-Dateiendung, aber auch direkt im Dateiname
    530 	 * befinden.
    531 	 *
    532 	 * @return Dateiendung
    533 	 */
    534 	function getRealExtension()
    535 	{
    536 		if	( $this->extension )
    537 		{
    538 			return $this->extension;
    539 		}
    540 		else
    541 		{
    542 			$pos = strrpos($this->filename,'.');
    543 			if	( $pos === false )
    544 				return '';
    545 			else
    546 				return substr($this->filename,$pos+1);
    547 		}
    548 	}
    549 
    550     private function filterValue()
    551     {
    552         $publishType = strtolower(substr(\ClassUtils::getSimpleClassName($this->publisher),7));
    553 
    554         foreach(\ArrayUtils::getSubArray($this->getTotalSettings(), array( 'filter')) as $filterEntry )
    555         {
    556         	$filterName = @$filterEntry['name'];
    557         	$extension  = @$filterEntry['extension'];
    558 
    559 			if   ( $extension && strtolower($extension) != strtolower($this->getRealExtension()) )
    560         		continue; // File extension does not match
    561 
    562         	$onPublish = (array) @$filterEntry['on'];
    563         	if ( ! $onPublish || in_array('all',$onPublish ) )
    564         		$onPublish = ['edit','public','preview','show'];
    565 
    566         	if   ( $onPublish && ! in_array($publishType,$onPublish))
    567         		continue; // Publish type does not match
    568 
    569         	$parameter = (array) @$filterEntry['parameter'];
    570 
    571 			$filterClassNameWithNS = 'cms\\publish\\filter\\' . $filterName.'Filter';
    572 
    573 			if   ( !class_exists( $filterClassNameWithNS ) ) {
    574 				Logger::warn("Filter '$filterName' does not exist.");
    575 				continue;
    576 			}
    577 
    578 			/** @var AbstractFilter $filter */
    579 			$filter = new $filterClassNameWithNS();
    580 
    581 			// Copy filter configuration to filter instance.
    582 			foreach( $parameter as $name=>$value) {
    583 				if   ( property_exists($filter,$name))
    584 					$filter->$name = $value;
    585 			}
    586 
    587 
    588 			// Execute the filter.
    589 			Logger::debug("Filtering '$this->filename' with filter '$filterName'.");
    590 
    591 			try {
    592 
    593 				$this->value = $filter->filter( $this->value );
    594 			} catch( \Exception $e ) {
    595 				// Filter has some undefined error.
    596 				Logger::warn( $e->getTraceAsString() );
    597 				if   ( $this->publisher instanceof PublishPublic )
    598 					return ''; // Do not show errors on public publishing.
    599 				else
    600 					return $e->getMessage()."\n".$e->getTraceAsString();
    601 			}
    602         }
    603 
    604         // Store in cache.
    605         $this->getCache()->invalidate();
    606     }
    607 
    608 
    609 
    610     public function getSize()
    611 	{
    612 		return $this->size;
    613 	}
    614 }
    615 
    616 ?>