openrat-cms

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

PublishPublic.class.php (11258B)


      1 <?php
      2 
      3 namespace cms\generator;
      4 
      5 use cms\model\BaseObject;
      6 use cms\model\File;
      7 use cms\model\Folder;
      8 use cms\model\Link;
      9 use cms\model\Page;
     10 use cms\model\Project;
     11 use cms\model\Url;
     12 use cms\generator\target\Dav;
     13 use cms\generator\target\Fax;
     14 use cms\generator\target\Ftp;
     15 use cms\generator\target\Ftps;
     16 use cms\generator\target\Local;
     17 use cms\generator\target\NoTarget;
     18 use cms\generator\target\Scp;
     19 use cms\generator\target\SFtp;
     20 use cms\generator\target\Target;
     21 use util\exception\PublisherException;
     22 use util\FileUtils;
     23 use logger\Logger;
     24 use util\exception\UIException;
     25 use util\Session;
     26 
     27 
     28 
     29 /**
     30  * User: dankert
     31  * Date: 10.08.18
     32  * Time: 23:47
     33  */
     34 
     35 class PublishPublic extends Publish
     36 {
     37     const SCHEMA_ABSOLUTE = 1;
     38     const SCHEMA_RELATIVE = 2;
     39 
     40 	const MAX_RECURSIVE_COUNT = 10;
     41 
     42 
     43 	/**
     44      * The target to which the file will be copied to.
     45 	 *
     46      * @var Target
     47      */
     48     private $target;
     49 
     50     private $localDestinationDirectory = '';
     51 
     52     /**
     53      * Enthaelt die gleichnamige Einstellung aus dem Projekt.
     54      * @var boolean
     55      */
     56     private $contentNegotiation = false;
     57 
     58     /**
     59      * Enthaelt die gleichnamige Einstellung aus dem Projekt.
     60      * @var boolean
     61      */
     62     private $cutIndex           = false;
     63 
     64     /**
     65      * Enthaelt die gleichnamige Einstellung aus dem Projekt.
     66      * @var String
     67      */
     68     private $commandAfterPublish = '';
     69 
     70     /**
     71      * Enthaelt am Ende der Ver�ffentlichung ein Array mit den ver�ffentlichten Objekten.
     72      * @var Array
     73      */
     74     public $publishedObjects    = array();
     75 
     76     /**
     77      * Enthaelt im Fehlerfall (wenn 'ok' auf 'false' steht) eine
     78      * Fehlermeldung.
     79      *
     80      * @var String
     81      */
     82     public $log                 = array();
     83 
     84     /**
     85      * Konstruktor.<br>
     86      * <br>
     87      * Oeffnet ggf. Verbindungen.
     88      *
     89      * @return Publish
     90      */
     91     public function __construct( $projectid )
     92     {
     93         $confPublish = config('publish');
     94 
     95         $project = Project::create( $projectid );
     96         $project->load();
     97 
     98         $this->linkSchema = ($project->linkAbsolute ? self::SCHEMA_ABSOLUTE : self::SCHEMA_RELATIVE);
     99 
    100         $targetScheme = parse_url( $project->target_dir,PHP_URL_SCHEME );
    101 
    102         $availableTargets = [ Local::class,Ftp::class,Ftps::class,Fax::class,SFtp::class,Scp::class,Dav::class ];
    103 
    104 		/** @var Target $target */
    105 		foreach($availableTargets as $target )
    106 		{
    107 			if   ( $target::isAvailable() && $target::accepts( $targetScheme ))
    108 			{
    109 				$this->target = new $target( $project->target_dir );
    110 				break;
    111 			}
    112 		}
    113 
    114 		if   ( empty( $this->target ) )
    115 			throw new PublisherException('Cannot publish to the scheme '.$targetScheme );
    116 
    117         $this->contentNegotiation = ( $project->content_negotiation == '1' );
    118         $this->cutIndex           = ( $project->cut_index           == '1' );
    119 
    120         if	( $confPublish['command']['enable'] )
    121         {
    122             if	( $confPublish['command']['per_project'] && !empty($project->cmd_after_publish) )
    123                 $this->commandAfterPublish   = $project->cmd_after_publish;
    124             else
    125                 $this->commandAfterPublish   = @$confPublish['command']['command'];
    126         }
    127 
    128         // Im Systemkommando Variablen ersetzen
    129         $this->commandAfterPublish = str_replace('{name}'   ,$project->name                ,$this->commandAfterPublish);
    130         $this->commandAfterPublish = str_replace('{dir}'    ,$this->localDestinationDirectory          ,$this->commandAfterPublish);
    131         $this->commandAfterPublish = str_replace('{dirbase}',basename($this->localDestinationDirectory),$this->commandAfterPublish);
    132 
    133         if	( config('security','nopublish') )
    134         {
    135         	$this->target = new NoTarget();
    136             Logger::warn('publishing is disabled.');
    137         }
    138     }
    139 
    140 
    141 
    142     /**
    143      * @var int
    144      */
    145     private $linkSchema;
    146 
    147     /**
    148      * @param $from \cms\model\BaseObject
    149      * @param $to \cms\model\BaseObject
    150      */
    151     public function linkToObject( BaseObject $from, BaseObject $to ) {
    152 
    153         $schema = $this->linkSchema;
    154 
    155 		$counter = 0;
    156         while( $to->typeid == BaseObject::TYPEID_LINK )
    157 		{
    158 			if   ( $counter++ > self::MAX_RECURSIVE_COUNT)
    159 				throw new \LogicException("Too much redirects while following a link. Stopped at #".$to->objectid );
    160 
    161 			$link = new Link( $to->objectid );
    162 			$link->load();
    163 
    164 			$to = new BaseObject( $link->linkedObjectId );
    165 			$to->objectLoad();
    166 		}
    167 
    168         switch( $to->typeid )
    169         {
    170             case BaseObject::TYPEID_FILE:
    171             case BaseObject::TYPEID_IMAGE:
    172             case BaseObject::TYPEID_TEXT:
    173 
    174                 $f = new File( $to->objectid );
    175 
    176                 $p = Project::create( $to->projectid )->load();
    177                 $f->content_negotiation = $p->content_negotiation;
    178 
    179                 $f->load();
    180                 $filename = $f->filename();
    181                 break;
    182 
    183             case BaseObject::TYPEID_PAGE:
    184 
    185                 $p = new Page( $to->objectid );
    186                 $p->languageid          = $from->languageid;
    187                 $p->modelid             = $from->modelid;
    188                 $p->cut_index           = $from->cut_index;
    189                 $p->content_negotiation = $from->content_negotiation;
    190                 $p->withLanguage        = $from->withLanguage;
    191                 $p->withModel           = $from->withModel;
    192                 $p->load();
    193                 $filename = $p->getFilename();
    194                 break;
    195 
    196             case BaseObject::TYPEID_URL:
    197                 $url = new Url( $to->objectid );
    198                 $url->load();
    199                 return $url->url;
    200             default:
    201                 throw new \LogicException("Could not build a link to the unknown Type ".$to->typeid.':'.$to->getType() );
    202         }
    203 
    204 
    205         if	( $from->projectid != $to->projectid )
    206         {
    207             // Target object is in another project.
    208             // we have to use absolute URLs.
    209             $schema = self::SCHEMA_ABSOLUTE;
    210 
    211             // Target is in another Project. So we have to create an absolute URL.
    212             $targetProject = Project::create( $to->projectid )->load();
    213             $host = $targetProject->url;
    214 
    215             if   ( ! strpos($host,'//' ) === FALSE ) {
    216                 // No protocol in hostname. So we have to prepend the URL with '//'.
    217                 $host = '//'.$host;
    218             }
    219         }
    220         else {
    221             $host = '';
    222         }
    223 
    224 
    225 
    226 
    227         if  ( $schema == self::SCHEMA_RELATIVE )
    228         {
    229             $folder = new Folder( $from->getParentFolderId() );
    230             $folder->load();
    231             $fromPathFolders = $folder->parentObjectFileNames(false,true);
    232 
    233             $folder = new Folder($to->getParentFolderId() );
    234 
    235             $toPathFolders = $folder->parentObjectFileNames(false, true);
    236 
    237             // Shorten the relative URL
    238             // if the actual page is /path/folder1/page1
    239             // and the target page is /path/folder2/page2
    240             // we shorten the link from ../../path/folder2/page2
    241             //                     to   ../folder2/page2
    242             foreach( $fromPathFolders as $folderId => $folderFileName ) {
    243                 if   ( count($toPathFolders) >= 1 && array_keys($toPathFolders)[0] == $folderId ) {
    244                     unset( $fromPathFolders[$folderId] );
    245                     unset( $toPathFolders  [$folderId] );
    246                 }else {
    247                     break;
    248                 }
    249 
    250             }
    251 
    252             if   ( $fromPathFolders )
    253                 $path = str_repeat( '../',count($fromPathFolders) );
    254             else
    255                 $path = './'; // Just to clarify- this could be blank too.
    256 
    257             if   ( $toPathFolders )
    258                 $path .= implode('/',$toPathFolders).'/';
    259         }
    260         else {
    261             // Absolute Pfadangaben
    262             $folder = new Folder( $to->getParentFolderId() );
    263             $toPathFolders = $folder->parentObjectFileNames(false, true);
    264 
    265             $path = '/';
    266 
    267             if   ( $toPathFolders )
    268                 $path .= implode('/',$toPathFolders).'/';
    269         }
    270 
    271 
    272         $uri = $host . $path . $filename;
    273 
    274         if( !$uri )
    275             $uri = '.';
    276 
    277         return $uri;
    278     }
    279 
    280 
    281 
    282 
    283 
    284     /**
    285      * Kopieren einer Datei aus dem tempor�ren Verzeichnis in das Zielverzeichnis.<br>
    286      * Falls notwenig, wird ein Hochladen per FTP ausgef�hrt.
    287      *
    288      * @param String $tmp_filename
    289      * @param String $dest_filename
    290      */
    291     public function copy( $tmp_filename,$dest_filename,$lastChangeDate=null )
    292     {
    293 		$this->target->put($tmp_filename,$dest_filename,$lastChangeDate);
    294     }
    295 
    296 
    297 
    298 
    299     /**
    300      * Beenden des Ver�ffentlichungs-Vorganges.<br>
    301      * Eine vorhandene FTP-Verbindung wird geschlossen.<br>
    302      * Falls entsprechend konfiguriert, wird ein Systemkommando ausgef�hrt.
    303      */
    304     public function close()
    305     {
    306         $this->target->close();
    307 
    308         // Ausfuehren des Systemkommandos.
    309         if	( !empty($this->commandAfterPublish) )
    310         {
    311             $ausgabe = array();
    312             $rc      = false;
    313             Logger::debug('Executing system command: '.Logger::sanitizeInput($this->commandAfterPublish) );
    314             $user = Session::getUser();
    315             putenv("CMS_USER_NAME=".$user->name  );
    316             putenv("CMS_USER_ID="  .$user->userid);
    317             putenv("CMS_USER_MAIL=".$user->mail  );
    318 
    319             exec( $this->commandAfterPublish,$ausgabe,$rc );
    320 
    321             if	( $rc != 0 ) // Wenn Returncode ungleich 0, dann Fehler melden.
    322                 throw new PublisherException('System command failed - returncode is ' . $rc . "\n" .
    323 					$ausgabe);
    324             else
    325                 Logger::debug('System command successful' );
    326 
    327         }
    328     }
    329 
    330 
    331 
    332     /**
    333      * Aufraeumen des Zielverzeichnisses.<br><br>
    334      * Es wird der komplette Zielordner samt Unterverzeichnissen durchsucht. Jede
    335      * Datei, die laenger existiert als der aktuelle Request alt ist, wird geloescht.<br>
    336      * Natuerlich darf diese Funktion nur nach einem Gesamt-Veroeffentlichen ausgefuehrt werden.
    337      */
    338     public function clean()
    339     {
    340         if	( !empty($this->localDestinationDirectory) )
    341             $this->cleanFolder($this->localDestinationDirectory);
    342     }
    343 
    344 
    345 
    346     /**
    347      * Aufr�umen eines Verzeichnisses.<br><br>
    348      * Dateien, die l�nger existieren als der aktuelle Request alt ist, werden gel�scht.<br>
    349      *
    350      * @param String Verzeichnis
    351      */
    352     private function cleanFolder( $folderName )
    353     {
    354         $dh = opendir( $folderName );
    355 
    356         while( $file = readdir($dh) )
    357         {
    358             if	( $file != '.' && $file != '..')
    359             {
    360                 $fullpath = $folderName.'/'.$file;
    361 
    362                 // Wenn eine Datei beschreibbar und entsprechend alt
    363                 // ist, dann entfernen
    364                 if	( is_file($fullpath)     &&
    365                     is_writable($fullpath) &&
    366                     filemtime($fullpath) < START_TIME  )
    367                     unlink($fullpath);
    368 
    369                 // Bei Ordnern rekursiv absteigen
    370                 if	( is_dir( $fullpath) )
    371                 {
    372                     $this->cleanFolder($fullpath);
    373                     @rmdir($fullpath);
    374                 }
    375             }
    376         }
    377     }
    378 
    379 
    380     public function isSimplePreview()
    381     {
    382         return false;
    383     }
    384 
    385     public function isPublic()
    386     {
    387         return true;
    388     }
    389 }