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 }