EGOCMS  24.0
EGOTEC Content-Managament-System
Page.php
gehe zur Dokumentation dieser Datei
1 <?php
5 require_once 'base/Page_Iterator.php';
6 require_once 'base/Mediapool.php';
7 
11 class Page_Exception extends Exception {
12  const ROOT_PROTECTION = 1;
13  const FILE_REPLACE = 4;
14  const METHOD_NOT_FOUND = 8;
15 }
16 
28 class Page {
29  const CACHE_BROWSER = 1;
30  const CACHE_PROXY = 2;
31  const CACHE_SERVER = 4;
32  const ACTIVE_FLAG = 0;
33  const INACTIVE_FLAG = 1;
34  const RELEASE_FLAG = 2;
35  const IDENTITY_SEPARATOR = '.';
37  public $field;
38  public $extra;
39  public $message = '';
41  private $_site;
42  private $tableSuffix = '';
43  public $mainOrient = 'center';
45  protected $typeInfo = array();
50  public $archiveOnly = false;
52  public $originalType = '';
53  private $lastChangeDate = '';
54  private $frontendActive = false;
55  private $editFields = array();
57  public $conf = array();
59  private static $nextIds = array();
71  function __construct(Site $site, $field, $archive = false) {
72  $this->_site = $site;
73  $this->field = $field;
74  $this->extra = $this->field['extra']?unserialize($this->field['extra']):array();
75  $this->lastChangeDate = $this->field['m_date'];
76  $this->originalType = $this->field['type'];
77 
78  if ($_REQUEST['c_date'] && $this->field['id']) { // Einen Archiveintrag holen.
79  $c_date = $_REQUEST['c_date'];
80  if (is_numeric($c_date)) {
81  $c_date = date('Y-m-d H:i:s', $_REQUEST['c_date']);
82  }
83  $db = new_db_connection(array(
84  'table' => $this->_site->pageTable.'_v',
85  'where' => "id=".$this->field['id']." AND m_date<=:cdate",
86  'order' => 'm_date DESC',
87  'limit' => 1,
88  'bind' => array('cdate' => $c_date)
89  ));
90  if ($db->nextRecord()) {
91  $this->field = $db->Record;
92  $this->extra = $db->Record['extra']?unserialize($db->Record['extra']):array();
93  }
94 
95  $this->lastChangeDate = $this->field['m_date'];
96  } elseif (
97  $_GET['preview']
98  && $_REQUEST['id'] == $field['id']
99  && $_REQUEST['site'] == $site->name
100  && !$GLOBALS['frontend_admin']
101  && $_SESSION['egotec_page_preview'][$identity = $this->getIdentity()]
102  ) {
103  // Echte Vorschau.
104  $this->field = $_SESSION['egotec_page_preview'][$identity]['field'];
105  $this->extra = Ego_System::cleanTypes($_SESSION['egotec_page_preview'][$identity]['extra']) ?: [];
106  $this->lastChangeDate = $this->field['m_date'];
107  } else {
108  // Im Adminbereich/Frontend Administration ist die aktuelle Page immer der letzte Archiveintrag
109  if (
110  $archive
111  || (
112  $this->isPublicSave()
113  && ($GLOBALS['is_admin'] || $GLOBALS['frontend_admin'] || $_REQUEST['preview'])
114  && !empty($GLOBALS['site'])
115  && empty($GLOBALS['public_save_get_original_page'])
116  && empty($GLOBALS['auto_translate_get_original_page'])
117  && $this->_site->name == $GLOBALS['site']->name
118  && in_array($this->field['id'], array($_REQUEST['list'], $_REQUEST['id'], $_REQUEST['field']['id']))
119  )
120  ) {
121  $db = new_db_connection();
122  $db->select(array(
123  'table' => $this->_site->pageTable.'_v',
124  'where' => 'id = :id',
125  'order' => 'm_date DESC',
126  'limit' => 1,
127  'bind' => array(
128  'id' => $this->field['id']
129  )
130  ));
131  if ($db->nextRecord() && $db->Record['m_date'] > $this->field['m_date']) {
132  // Daten des Archivs verwenden
133  $this->field = $db->Record;
134  $this->extra = $this->field['extra']?unserialize($this->field['extra']):array();
135  $this->archiveOnly = true;
136 
137  // Mediapool Archiv verwenden (nicht für Input Plugins)
138  if (empty($_REQUEST['input'])) {
139  $current_dir = $this->getMediapool()->dir().$this->getMediapool()->currentDir;
140  $this->getMediapool()->currentDir = (string) Ego_System::dateEncode($this->field['m_date']);
141  $archive_dir = $this->getMediapool()->dir().$this->getMediapool()->currentDir;
142  if (
143  !Ego_System::file_exists($archive_dir)
144  && Ego_System::file_exists($current_dir)
145  ) {
146  // Automatische Migration: Existiert kein Mediapool Archiv, dann wird current kopiert
147  Ego_System::copy($current_dir, $archive_dir);
148  }
149  }
150  }
151  }
152 
153  // Standardsprache automatisch korrigieren wenn diese nicht existiert
154  if (
155  $this->extra['language_standard']
156  && !in_array($this->extra['language_standard'], $this->_site->getLanguages())
157  ) {
158  $this->extra['language_standard'] = $this->_site->language;
159  $this->updateExtra($this->extra, true, true);
160  }
161 
162  // Ist diese Page die aktuelle Seite in der Frontend Administration, dann automatisch umwandeln
163  if (
164  !empty($GLOBALS['frontend_admin'])
165  && !empty($GLOBALS['smarty'])
166  && $this->isCurrentPage(true)
167  ) {
168  $this->frontendAdmin();
169  }
170  }
171  if ($this->extra['mime_type'] && !is_string($this->extra['mime_type'])) {
172  $this->extra['mime_type'] = ''; // Falls in Mime-Type kein String steht.
173  }
174  $this->field['cache'] = (int)$this->field['cache']; // Der Cache ist ein Integer
175 
176  // Page Informationen laden
177  $this->_loadConfig();
178 
179  // Individuelles Standard Layout verwenden, wenn keines definiert ist
180  if (empty($this->extra['_layout'])) {
181  $this->extra['_layout'] = $this->conf['default_layout'];
182  }
183 
184  // Standard Blöcke in einer statischen Orientierung müssen immer gesetzt sein
185  if (is_array($this->conf['layouts'][$this->extra['_layout']]['blocks'])) {
186  foreach ($this->conf['layouts'][$this->extra['_layout']]['blocks'] as $orient => $info) {
187  if (!empty($info['default']) && $info['static']) {
188  if (!is_array($this->extra['_blocks'])) {
189  $this->extra['_blocks'] = array();
190  }
191  $this->extra['_blocks'][$orient] = explode(',', $info['default']);
192 
193  // Andere Blöcke sind in dieser statischen Orientierung nicht erlaubt und werden automatisch entfernt
194  $this->conf['layouts'][$this->extra['_layout']]['blocks'][$orient]['allow'] = implode(',', array_unique($this->extra['_blocks'][$orient]));
195  unset($this->conf['layouts'][$this->extra['_layout']]['blocks'][$orient]['disallow']);
196  }
197  }
198  }
199 
200  if (is_array($this->extra['_blocks'])) {
201  // Blöcke die nicht erlaubt sind nicht anzeigen
202  if (isset($this->conf['layouts'])) {
203  // Prüfen, ob dieser Block erlaubt ist.
204  $validate = function ($block, $orient, $type) use (&$validate) {
205  $info = $this->conf['layouts'][$this->extra['_layout']]['blocks'][$orient];
206  if (isset($info[$type])) {
207  $result = $type == 'allow' ? false : true;
208  foreach (explode(',', $info[$type]) as $name) {
209  switch ($type) {
210  case 'allow':
211  if ($name[0] == '@') {
212  if ($validate($block, substr($name, 1), 'allow')) {
213  $result = true;
214  break 2;
215  }
216  } elseif ($block == $name) {
217  $result = true;
218  break 2;
219  }
220  break;
221  case 'disallow':
222  if ($name[0] == '@') {
223  if (!$validate($block, substr($name, 1), 'disallow')) {
224  $result = false;
225  break 2;
226  }
227  } elseif ($block == $name) {
228  $result = false;
229  break 2;
230  }
231  }
232  }
233  return $result;
234  }
235  return true;
236  };
237 
238  foreach ($this->extra['_blocks'] as $orient => $blocks) {
239  if (is_array($blocks)) {
240  foreach ($blocks as $index => $block) {
241  if (
242  !$validate($block, $orient, 'allow')
243  || !$validate($block, $orient, 'disallow')
244  || (
245  $block == 'template' // Das Standard Template entfernen
246  && $this->conf['template_block'] !== true // ...wenn dieses nicht erwünscht ist
247  && $this->conf['blocks']['template']['removable'] === true // ...und explizit entfernt werden darf
248  )
249  ) {
250  if (isset($this->extra['_blocks'][$orient][$index])) {
251  unset($this->extra['_blocks'][$orient][$index]);
252  }
253  if (isset($this->extra['_contents'][$orient][$index])) {
254  unset($this->extra['_contents'][$orient][$index]);
255  }
256  }
257  }
258  }
259  }
260  }
261 
262  // Schlüssel aller Block Inhalte korrigieren und Standardwerte setzen
263  foreach ($this->extra['_blocks'] as $orient => $blocks) {
264  if (is_array($blocks)) {
265  $num = 0;
266  $contents = array();
267  foreach ($blocks as $index => $block) {
268  if (isset($this->extra['_contents'][$orient][$index])) {
269  $new_index = $index;
270  if ($new_index >= $num + 1) {
271  $new_index = $num;
272  $this->extra['_blocks'][$orient][$new_index] = $block;
273  unset($this->extra['_blocks'][$orient][$index]);
274  }
275  $contents[$new_index] = $this->extra['_contents'][$orient][$index];
276  } elseif (isset($this->conf['blocks'][$block]['default'][$orient])) {
277  $contents[$index] = $this->conf['blocks'][$block]['default'][$orient];
278  }
279  $num++;
280  }
281  $this->extra['_contents'][$orient] = $contents;
282  }
283  }
284  }
285 
286  // Mediapool Konfiguration korrigieren
287  if (isset($this->extra['mediapool']) && !is_array($this->extra['mediapool'])) {
288  $this->extra['mediapool'] = array();
289  }
290 
291  // Sicherstellen, dass die aus der Datenbank ermittelten Felder den richtigen Typ verwenden
292  $this->field['id'] = (int) $this->field['id'];
293  $this->field['name'] = (string) $this->field['name'];
294  $this->field['title'] = (string) $this->field['title'];
295  $this->field['url'] = (string) $this->field['url'];
296  $this->field['short'] = (string) $this->field['short'];
297  $this->field['content'] = (string) $this->field['content'];
298  $this->field['extra'] = (string) $this->field['extra'];
299  $this->field['a_date'] = (string) $this->field['a_date'];
300  $this->field['c_date'] = (string) $this->field['c_date'];
301  $this->field['a_user'] = (string) $this->field['a_user'];
302  $this->field['c_user'] = (string) $this->field['c_user'];
303  $this->field['type'] = (string) $this->field['type'];
304  $this->field['children_order'] = (string) $this->field['children_order'];
305  $this->field['order_field'] = (int) $this->field['order_field'];
306  $this->field['nav_hide'] = (int) $this->field['nav_hide'];
307  $this->field['inactive'] = (int) $this->field['inactive'];
308  $this->field['cache'] = (int) $this->field['cache'];
309  $this->field['release_from'] = (string) $this->field['release_from'];
310  $this->field['release_until'] = (string) $this->field['release_until'];
311  $this->field['workflow'] = (string) $this->field['workflow'];
312  $this->field['workflow_state'] = (int) $this->field['workflow_state'];
313  $this->field['deleted'] = (int) $this->field['deleted'];
314  }
315 
321  private function _loadConfig() {
322  // Konfigurationen lesen
323  $cache_key = 'pageConf'.md5(serialize(array($this->field['type'], $_SERVER['REQUEST_SUFFIX'])));
324  $this->conf = $this->_site->getCacheEntry($cache_key);
325  if ($this->conf === null) {
326  // 1. System
327  $confs = array(
328  $GLOBALS['egotec_conf']['lib_dir'] . 'page/conf.json'
329  );
330 
337  $get_type_confs = function($path) use (&$confs) {
338  $parts = explode('/', $this->field['type']);
339  $i = 0;
340  do {
341  $confs[] = str_replace('*', implode('/', array_slice($parts, 0, ++$i)), $path);
342  } while ($i < sizeof($parts));
343  };
344 
345  $get_type_confs($GLOBALS['egotec_conf']['lib_dir'] . 'type/site/*/admin/conf.json');
346 
347  foreach (array('', $_SERVER['REQUEST_SUFFIX']) as $suffix) {
348  if (!empty($suffix) && trim(mb_strtolower(ltrim($suffix, '.'))) != 'html') {
349  $suffix = '.' . mb_strtolower(ltrim($suffix, '.'));
350  }
351  if ($suffix == '.html') {
352  continue;
353  }
354 
355  // 2. Designvorlage
356  if ($this->_site->theme) {
357  $confs[] = $GLOBALS['egotec_conf']['pub_dir'] . 'theme/' . $this->_site->theme . '/site/admin/conf' . $suffix . '.json';
358  }
359 
360  // 3. Global
361  if ($this->_site->globalAllowed()) {
362  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/conf.json';
363 
364  // 4. Global / Designvorlage
365  if ($this->_site->theme) {
366  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/' . $this->_site->theme . $suffix . '.json';
367  }
368 
369  // 5. Global / Standarddesign
370  if ($this->_site->skin) {
371  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/' . $this->_site->skin . $suffix . '.json';
372  }
373  }
374 
375  // 6. Mandant
376  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/admin/conf' . $suffix . '.json';
377 
378  // 7. Designvorlage / Seitentyp
379  if ($this->_site->theme) {
380  $get_type_confs($GLOBALS['egotec_conf']['pub_dir'] . 'theme/' . $this->_site->theme . '/site/*/admin/conf' . $suffix . '.json');
381  }
382 
383  // 8. Global / Seitentyp
384  if ($this->_site->globalAllowed()) {
385  $get_type_confs($GLOBALS['egotec_conf']['site_dir'] . '_global/*/admin/conf' . $suffix . '.json');
386 
387  // 9. Global / Seitentyp / Designvorlage
388  if ($this->_site->theme) {
389  $get_type_confs($GLOBALS['egotec_conf']['site_dir'] . '_global/*/admin/' . $this->_site->theme . $suffix . '.json');
390  }
391 
392  // 10. Global / Seitentyp / Standarddesign
393  if ($this->_site->skin) {
394  $get_type_confs($GLOBALS['egotec_conf']['site_dir'] . '_global/*/admin/' . $this->_site->skin . $suffix . '.json');
395  }
396  }
397 
398  // 11. Mandant / Seitentyp
399  $get_type_confs($GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/*/admin/conf' . $suffix . '.json');
400  }
401 
402  $this->conf = array();
403  $confs = array_unique($confs);
404  foreach ($confs as $file) {
405  if (Ego_System::file_exists($file)) {
406  $this->conf = Ego_System::getJSON($file, $this->conf, true, ['plugins', 'toolbar', 'menubar', 'editor.options']);
407  }
408  }
409  if (empty($this->conf['default_layout'])) {
410  $this->conf['default_layout'] = 'default'; // Standard Layout ist "default", wenn keines definiert ist
411  }
412  unset($this->conf['site'], $this->conf['admin']); // Site Konfigurationen nicht in Page aufnehmen
413  $this->_site->setCacheEntry($cache_key, $this->conf);
414  }
415  if ($this->conf['main_orient']) {
416  // Die Haupt-Orientierung überschreiben
417  $this->mainOrient = $this->conf['main_orient'];
418  }
419  }
420 
428  public function __call($function, $params) {
429  // Mediapool Methoden beginnen mit "pool*"
430  if (strpos($function, 'pool') === 0 && is_callable($call = [$this->getMediapool(), lcfirst(substr($function, 4))])) {
431  egotec_deprecated_log('18.4', 'Please use getMediapool() and the Mediapool object\'s methods.');
432  return call_user_func_array($call, $params);
433  }
434 
435  // Page Magic Methoden
436  $key = 'Page.magic'.md5(serialize(array($function, $this->field['type'])));
437  $magic_file = $this->_site->getCacheEntry($key);
438  if ($magic_file === null) {
439  $files = array(
440  "{$this->field['type']}/Page.{$function}.php"
441  );
442  $types = explode('/', $this->field['type']);
443  while (array_pop($types)) {
444  if (!empty($types)) {
445  $files[] = implode('/', $types) . "/Page.{$function}.php";
446  }
447  }
448  $files[] = "Page.{$function}.php";
449  foreach ($files as $file) {
450  if ($found = $this->_site->getSiteFile($file)) {
451  $magic_file = $found;
452  $this->_site->setCacheEntry($key, $magic_file);
453  break;
454  }
455  }
456 
457  // Auch wenn keine Magic Methode gefunden wurde, das Ergebnis zwischenspeichern
458  if ($magic_file === null) {
459  $this->_site->setCacheEntry($key, '');
460  }
461  }
462  if (empty($magic_file)) {
463  $magic_file = $GLOBALS['egotec_conf']['lib_dir'] . 'base/Page.' . $function . '.php';
464  }
465  if (!file_exists($magic_file)) {
466  throw new Page_Exception("Method 'Page.$function' not found", Page_Exception::METHOD_NOT_FOUND);
467  }
468  require_once($magic_file);
469  return call_user_func($function, $this, $params);
470  }
471 
477  public function getTableSuffix() {
478  return $this->tableSuffix;
479  }
480 
487  public function setTableSuffix($suffix = '') {
488  $this->tableSuffix = $suffix;
489  }
490 
497  function getUser($user_type='c') {
498  require_once('auth/Auth.php');
499  return Auth::getUserRecord($this->field[$user_type.'_user']);
500  }
501 
507  private function _archiveEntry() {
508  if (!$this->getTableSuffix()) {
509  $table = $this->_site->pageTable.'_v';
510  $db = new_db_connection();
511 
513  unset($field['has_children']);
514 
515  $field['title'] = $field['title'] ?: '';
516  $field['a_user'] = $field['a_user'] ?: '';
517  $field['c_user'] = $field['c_user'] ?: '';
518  unset($field['parents']);
519  $db->insert(array(
520  'table' => $table,
521  'set' => $field,
522  'primary' => array('id', 'm_date'),
523  'replace' => true
524  ));
525 
526  // Mediapool archivieren
527  $this->getMediapool()->archive($field['m_date']);
528  }
529  }
530 
540  private function _insertEntry($field, $lang='') {
541  if (!isset($field['id']) || $field['id']<=0) {
542  $field['id'] = $this->_site->nextId();
543  }
544  unset($field['parents']);
545 
546  // Alle Felder von nicht UTF8 Zeichen befreien
547  foreach ($field as $key => $value) {
548  if (is_string($value)) {
549  if ($key == 'extra') {
551  } else {
552  $field[$key] = Ego_System::filterNonUtf8($value);
553  }
554  }
555  }
556 
557  // Name und Titel ohne Leerzeichen am Anfang und Ende
558  foreach (array('name', 'title') as $key) {
559  if (isset($field[$key])) {
560  $field[$key] = trim($field[$key]);
561  }
562  }
563 
564  $db = new_db_connection();
565  $db->insert(array(
566  'table' => $lang?$this->_site->name.'_'.$lang:$this->_site->pageTable.$this->getTableSuffix(),
567  'set' => $field
568  ));
569  if ($lang) {
570  $site = clone $this->_site;
571  $site->setLanguage($lang);
572  } else {
573  $site = $this->_site;
574  }
575  $class = $site->getPageClass($field['type']);
576  $child = new $class($site, $field);
577  $child->_archiveEntry();
578  if (!isset($field['inactive']) || !$field['inactive']) {
579  $this->_clearCache();
580  }
581 
582  // Neue ID, die dieses Page Objekt erzeugt hat, merken
583  self::$nextIds[] = $child->field['id'];
584 
585  return $child;
586  }
587 
597  private function _changeEntry($field = array(), $asis = false, $silent = false) {
598  $db = new_db_connection();
599  if (!$silent) {
600  $field['m_user'] = $GLOBALS['auth']->getId() ? $GLOBALS['auth']->getId() : '';
601  $field['m_date'] = date('Y-m-d H:i:s');
602  if (!$asis) {
603  $field['c_user'] = $field['m_user'];
604  $field['c_date'] = $field['m_date'];
605  }
606  }
607  unset($this->field['idx']);
608  unset($field['idx']);
609  if (!isset($field['id'])) {
610  $field['id'] = $this->field['id'];
611  }
612  if (isset($field['nav_hide']) && !is_numeric($field['nav_hide'])) { // Oracle wirft einen ORA-01722, wenn kein numerischer Wert übergeben wird.
613  $field['nav_hide'] = 0;
614  }
615 
616  // nav_hide für diesen Seitentyp hat immer einen festgelegten Wert
617  if (isset($field['type'])) {
618  $this->field['type'] = $field['type'];
619  $this->typeInfo = [];
620  }
621  if (($info = $this->getTypeInfo()) && isset($info['nav_hide'])) {
622  $field['nav_hide'] = (int) $info['nav_hide'];
623  }
624 
625  // Name und Titel ohne Leerzeichen am Anfang und Ende
626  foreach (array('name', 'title') as $key) {
627  if (isset($field[$key])) {
628  $field[$key] = trim($field[$key]);
629  }
630  }
631 
632  // Der Name der Seite darf nie leer sein
633  if (isset($field['name']) && $field['name'] == '') {
634  $field['name'] = isset($field['title']) && $field['name'] != ''
635  ? $field['name']
636  : 'Neu';
637  }
638 
639  // Freigabe ab und bis Datum für die Datenbank leer setzen
640  if (isset($field['release_from']) && empty($field['release_from'])) {
641  $field['release_from'] = '0000-00-00 00:00:00';
642  }
643  if (isset($field['release_until']) && empty($field['release_until'])) {
644  $field['release_until'] = '0000-00-00 00:00:00';
645  }
646 
647  // Die Startseite kann nicht deaktiviert werden
648  if ($field['id'] == $this->_site->rootId) {
649  $field['inactive'] = self::ACTIVE_FLAG;
650  }
651 
652  // Die komplette Cache leeren, wenn ein Bild gelöscht oder wiederhergestellt wird
653  $cache_complete = isset($field['deleted'])
654  && $this->field['type'] == 'multimedia/image'
655  && $this->field['deleted'] != $field['deleted'];
656 
657  // Alle Felder von nicht UTF8 und bestimmten Unicode Zeichen befreien
658  $filter = function($value) use (&$filter) {
659  if (is_array($value)) {
660  foreach ($value as $k => $v) {
661  $value[$k] = $filter($v);
662  }
663  return $value;
664  }
665 
666  if (is_string($value)) {
667  if (
668  (
669  !empty($GLOBALS['egotec_conf']['editor']['filter_unicode'])
670  || !empty($this->_site->admin['editor']['filter_unicode'])
671  )
672  && $value[0] !== '{' // Nicht für JSON Strings
673  ) {
674  $value = Ego_System::filterUnicode($value);
675  }
676  return Ego_System::filterNonUtf8($value);
677  }
678  return $value;
679  };
680  foreach ($field as $key => $value) {
681  if (is_string($value)) {
682  if ($key == 'extra') {
683  $field[$key] = serialize($filter(unserialize($value)));
684  } else {
685  $field[$key] = $filter($value);
686  }
687  }
688  }
689 
690  if (!$this->archiveOnly) {
691  // Der letzte Archiveintrag ändert nie das Original
692  $db->update(array(
693  'table' => $this->_site->pageTable.$this->getTableSuffix(),
694  'set' => $field,
695  'where' => 'id='.$this->field['id']
696  ));
697 
698  // Beim Veröffentlichen wird das letzte Mediapool Archiv nach current kopiert
699  if (
700  $this->isPublicSave()
701  && $this->getMediapool()->currentDir != 'current'
702  ) {
707  @rename($this->getMediapool()->dir().'current', $this->getMediapool()->dir().'current.backup');
708  $retry = 0;
709  do {
710  Ego_System::copy($this->getMediapool()->dir().$this->getMediapool()->currentDir, $this->getMediapool()->dir().'current', '', true);
711  sleep($retry++);
712  } while (!Ego_System::file_exists($this->getMediapool()->dir().'current') && $retry < 3);
713  if (!Ego_System::file_exists($this->getMediapool()->dir().'current')) {
714  @rename($this->getMediapool()->dir().'current.backup', $this->getMediapool()->dir().'current');
715  } else {
716  Ego_Queue::add(array('Ego_System', 'deldir'), array($this->getMediapool()->dir().'current.backup'));
717  }
718 
719  Ego_Queue::add(array($this, 'reset'), array(false));
720  }
721  }
722  $this->_clearCache($cache_complete);
723  $this->field = array_merge($this->field, $field); // Die geänderten Werte auch direkt in das aktuelle Objekt übernehmen.
724  if (isset($field['extra'])) {
725  $extra = unserialize($field['extra']);
726  $this->extra = $extra?$extra:array();
727  }
728  }
729 
740  public function _getAncestorsIds($page, $query, $param = array()) {
741  $ancestors_ids = array();
742  if ($page) {
743  $cache_key = '_getAncestorsIds.'
744  .$page->field['id']
745  .'.'
746  .($query ? md5(serialize($query)) : '-')
747  .($param ? md5(serialize($param)) : '-');
748  $cache_val = $page->getSite()->getCacheEntry($cache_key);
749  if ($cache_val) {
750  return $cache_val;
751  }
752  foreach ($page->getParents($query, $param) as $parent) /* @var $parent Page */ {
753  $ancestors_ids[] = $parent->field['id'];
754  $ancestors_ids = array_merge($ancestors_ids, $this->_getAncestorsIds($parent, $query, $param));
755  }
756  $page->getSite()->setCacheEntry($cache_key, $ancestors_ids);
757  }
758  return $ancestors_ids;
759  }
760 
773  private function _getDescendantsIds($page, $query=array(), $param=array(), &$descendants=array()) {
774  $query['hash'].= ':'.$page->field['id'];
775  foreach ($page->getChildren($query, $param) as $child) /* @var $child Page */ {
776  if (in_array($child->field['id'], $descendants)) { // Endlosschleifen abfangen
777  ; // egotec_error_log('infinite loop protection on '.$child->field['id']);
778  } else {
779  set_time_limit(30);
780  $descendants[] = $child->field['id'];
781  if ($child->field['has_children']) { // Nur weiter nach unten gehen, wenn eine Seite tatsächlich Kinder besitzt.
782  $this->_getDescendantsIds($child, $query, $param, $descendants);
783  }
784  }
785  }
786  }
787 
795  private function _getRights($perm_type='') {
796  return new_db_connection(array(
797  'fields' => '*',
798  'from' => $this->_site->pageTable.'_rights',
799  'where' => "page_id=".$this->field['id'].($perm_type?" AND perm='".$perm_type."'":"")
800  ));
801  }
802 
810  private function _getUsers($perm_type='') {
811  return new_db_connection(array(
812  'fields' => '*',
813  'from' => $this->_site->pageTable.'_users',
814  'where' => "page_id=".$this->field['id'].($perm_type?" AND perm='".$perm_type."'":'')
815  ));
816  }
817 
826  private function _getEmptyEntry($new=array()) {
827  unset($new['idx']);
828  unset($new['parents']);
829 
830  $user_id = $GLOBALS['auth']->getId() ? $GLOBALS['auth']->getId() : '';
831  $date = date('Y-m-d H:i:s');
832  $empty = array(
833  'id' => '',
834  'title' => 'Neue Seite',
835  'name' => 'Neu',
836  'short' => '',
837  'content' => '',
838  'extra' => '',
839  'type' => 'page',
840  'cache' => self::CACHE_BROWSER|self::CACHE_PROXY|self::CACHE_SERVER,
841  'inactive' => self::INACTIVE_FLAG,
842  'release_from' => '0000-00-00 00:00:00',
843  'release_until' => '0000-00-00 00:00:00',
844  'nav_hide' => 0,
845  'deleted' => 0,
846  'a_date' => $date,
847  'c_date' => $date,
848  'm_date' => $date,
849  'a_user' => $user_id,
850  'c_user' => $user_id,
851  'm_user' => $user_id,
852  'order_field' => 0,
853  'children_order'=> 'children',
854  'workflow_state'=> 0,
855  'workflow' => '',
856  'url' => ''
857  );
858  if ($new) {
859  foreach ($new as $key => $value) {
860  if (!is_null($value)) {
861  $empty[$key] = $value;
862  }
863  }
864  }
865  return $empty;
866  }
867 
876  function hasRights($rights, $user_id = false, $cache = true) {
877  return $this->_site->hasRightsOnId($this->field['id'], $rights, $user_id, $cache);
878  }
879 
888  public function hasUserRight(string $right_type, string $user_id): bool {
889  $user_rights = $this->getUsersArray();
890 
891  if (isset($user_rights[$right_type])) {
892  foreach ($user_rights[$right_type] as $user_right) {
893  if ($user_right['user_id'] === $user_id) {
894  return true;
895  }
896  }
897  }
898 
899  return false;
900  }
901 
908  public function hasRightsOn($perm) {
909  // Gruppen/Rollen prüfen
910  $rights = $this->getRightsArray($perm);
911  if (!empty($rights[$perm])) {
912  foreach ($rights[$perm] as $right) {
913  if ($right['group_id'] != '*' && $right['role_id'] != '*') {
914  return true;
915  }
916  }
917  }
918 
919  // Benutzer prüfen
920  $users = $this->getUsersArray($perm);
921  if (!empty($users[$perm])) {
922  foreach ($users[$perm] as $user) {
923  if ($user['user_id'] != '*') {
924  return true;
925  }
926  }
927  }
928 
929  return false;
930  }
931 
942  function newChild($field = array(), $extra = array(), $inherit=true) {
943  if (!isset($GLOBALS['__egotec_skip_replication'])) {
944  $GLOBALS['__egotec_skip_replication'] = 'newChild';
945  }
946 
947  $original_field = !isset($field) ? ($field = array()) : $field;
948  $original_extra = !isset($extra) ? ($extra = array()) : $extra;
949 
950  if ($field['deleted'] == 1) { // Es wird grundsätzlich keine Seite angelegt, die das deleted flag gesetzt hat.
951  return false;
952  }
953 
954  if (!$extra['release_id'] && $this->_site->admin['multi_lang']['auto_link']) { // Automatische Verknüpfung in alle Sprachen erstellen (außer für Freigabekopien).
955  $extra['language_standard'] = $this->_site->language;
956  foreach ($this->_site->getLanguages() as $lang) {
957  $extra['language_link'][$lang] = $lang != $extra['language_standard']
958  && Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'translate')
959  && $this->extra['language_link'][$lang] == 2
960  ? 2 : 1;
961  }
962  } elseif(!$extra['language_standard']) {
963  if ($this->extra['language_standard'] == $this->_site->language) {
964  // Die Sprachverknüpfungen nur bei der Standardspreche vererben
965  $extra['language_standard'] = $this->extra['language_standard'];
966  $extra['language_link'] = $this->extra['language_link'];
967  if (!$extra['language_standard']) {
968  $extra['language_standard'] = $this->_site->language;
969  }
970  if (!$extra['language_link']) {
971  $extra['language_link'] = array();
972  foreach ($this->_site->getLanguages() as $lang) {
973  if ($lang == $extra['language_standard']) {
974  $extra['language_link'][$lang] = 1;
975  } else {
976  $extra['language_link'][$lang] = 0;
977  }
978  }
979  }
980  } else {
981  // ansonsten wird die aktuelle Sprache zur Standardsprache
982  $extra['language_standard'] = $this->_site->language;
983  }
984  }
985 
986  if ($inherit) { // Eigenschaften vererben.
987  // Den Workflow auf die neue Seite kopieren
988  if ($this->_site->admin['workflow']['enabled'] && $this->field['workflow']) {
989  $field['workflow'] = $this->field['workflow'];
990  if ($this->extra['workflows']) {
991  $extra['workflows'] = $this->extra['workflows'];
992  }
993  }
994 
995  // Intranet- und Navigationsflag vererben.
996  $field['nav_hide'] = $field['nav_hide'] === 0 ? 0 : ((int) $field['nav_hide']) | ((int) $this->field['nav_hide']);
997 
998  // Template und Design Variante vererben (nur bei gleichen Seitentypen).
999  if (
1000  $this->field['type'] == $field['type']
1001  || (!isset($field['type']) && $this->field['type'] == 'page')
1002  ) {
1003  if (!empty($this->extra['_template']) && empty($extra['_template'])) {
1004  $extra['_template'] = $this->extra['_template'];
1005  }
1006  if (!empty($this->extra['_style']) && empty($extra['_style'])) {
1007  $extra['_style'] = $this->extra['_style'];
1008  }
1009  }
1010 
1011  // IP Ansichtsrechte vererben
1012  if (empty($extra['ip_rights']) && !empty($this->extra['ip_rights'])) {
1013  $extra['ip_rights'] = $this->extra['ip_rights'];
1014  }
1015  }
1016  $field = $this->_getEmptyEntry($field);
1017 
1018  // Bereichspasswort vererben
1019  if ($this->extra['area_password'] && !$extra['area_password']) {
1020  $extra['area_password'] = $this->extra['area_password'];
1021  }
1022 
1023  $extra = Ego_System::cleanTypes($extra);
1024  $field['extra'] = serialize($extra);
1025 
1026  $new_page = $this->_insertEntry($field);
1027  $new_page->addParent($this->field['id']);
1028  $field['id'] = $new_page->field['id'];
1029  if (
1030  !$new_page->isWorkflowCopy()
1031  && !$new_page->isReleaseCopy()
1032  && !$new_page->isClone()
1033  && is_array($new_page->extra['language_link'])
1034  ) { // Automatisch Verknüpfung in alle Sprachen erstellen.
1035  foreach ($this->_site->getLanguages() as $lang) {
1036  if ($lang != $this->_site->language && $new_page->extra['language_link'][$lang]) {
1037  $lang_page = $new_page->getLanguagePage($lang, array('auth_or' => '1=1', 'inactive' => true, 'only_active' => false));
1038  if ($lang_page) {
1039  continue;
1040  }
1041  $lang_parent = $this->getLanguagePage($lang, array('auth_or' => '1=1', 'deleted_or' => '1=1', 'inactive' => true, 'only_active' => false));
1042  if ($lang_parent && $lang_parent->field['deleted']) {
1043  $lang_parent->undelete();
1044  }
1045 
1046  // Automatisch übersetzen
1047  $translated = $new_page->autoTranslate([
1048  'field' => $field,
1049  'extra' => $extra
1050  ], $lang, false);
1051 
1052  $lang_page = $this->_insertEntry($translated['field'], $lang);
1053  $new_page->createPath($lang);
1054  $lang_page->addParent($this->field['id']);
1055  // Die Rechte der aktuellen Seite auf die neue Seite kopieren, das Bearbeitungsrecht aber auf 'Untermenüpunkt anlegen' setzen.
1056  $new_rights = $this->getRightsArray();
1057  $new_rights['edit'] = $new_rights['child'];
1058  $new_users = $this->getUsersArray();
1059  $new_users['edit'] = $new_users['child'];
1060  $lang_page->setRightsArray($new_rights);
1061  $lang_page->setUsersArray($new_users);
1062  }
1063  }
1064  }
1065 
1066  $this->message = $GLOBALS['auth']->translate('Neue Seite wurde erstellt!');
1067  if ($new_page->field['inactive']) {
1068  $this->message.= "\n".$GLOBALS['auth']->translate('Diese Seite ist inaktiv (nicht online verfügbar).');
1069  } else {
1070  $this->message.= "\n".$GLOBALS['auth']->translate('Diese Seite ist freigeschaltet.');
1071  }
1072 
1073  // Die Rechte der aktuellen Seite auf die neue Seite kopieren, das Bearbeitungsrecht aber auf 'Untermenüpunkt anlegen' setzen.
1074  $new_rights = $this->getRightsArray();
1075  $new_rights['edit'] = $new_rights['child'];
1076  $new_users = $this->getUsersArray();
1077  $new_users['edit'] = $new_users['child'];
1078  $new_page->setRightsArray($new_rights);
1079  $new_page->setUsersArray($new_users);
1080 
1081  // Rechte klonen
1082  $new_page->_updateCloneRights();
1083 
1084  $new_page->updateIndex();
1085  $new_page->hookUpdate('newchild');
1086  $new_page->hookUpdate();
1087 
1088  $this->replicate('newChild', $original_field, $original_extra, $inherit);
1089 
1090  if ($new_page->_site->admin['video']['convert'] && preg_match('/video/', $new_page->extra['mime_type']) && $new_page->extra['mime_type'] != 'video/mp4') {
1091  // Video konvertieren
1092  Ego_Queue::add(array($new_page, 'convertVideo'));
1093  } elseif($new_page->_site->admin['video']['compress'] && $new_page->extra['mime_type'] == 'video/mp4') {
1094  // Video komprimieren
1095  Ego_Queue::add([$new_page, 'compressVideo']);
1096  }
1097 
1098  return $new_page;
1099  }
1100 
1108  public function hasFile($name, $suffix = '') {
1109  $children = $this->getChildren(array(
1110  'where' => "name = :name AND type IN ('multimedia/file', 'multimedia/image')",
1111  'bind' => array(
1112  'name' => $name
1113  )
1114  ), array(
1115  'inactive' => 1,
1116  'only_active' => false
1117  ));
1118  if ($page = $children->nextPage()) {
1119  if (!$suffix || $page->extra['image_type'] == $suffix) {
1120  return $page;
1121  }
1122  }
1123  return null;
1124  }
1125 
1140  public function newFile($source, $name, $options = array(), $suffix = '') {
1141  if ($this->_site->site['type'] == 'media' && $this->validateFile($source, $name)) {
1142  @set_time_limit(0);
1143 
1144  // WebDAV benötigt immer ein globales Site Objekt
1145  if (!isset($GLOBALS['site'])) {
1146  $GLOBALS['site'] = $this->getSite();
1147  }
1148 
1149  require_once 'media/functions.php';
1150  require_once 'base/Ego_MimeType.php';
1151 
1152  if ($name) {
1153  $path_info = Ego_System::pathinfo($name);
1154 
1155  if (!$path_info['extension'] && $suffix) {
1156  $path_info['extension'] = $suffix;
1157  }
1158 
1159  $GLOBALS['mediaType'] = $path_info['extension'];
1160  }
1161 
1162  $mime = new Ego_MimeType();
1163  $mime_type = $mime->autoDetect($source);
1164 
1165  $is_image = !(strpos($mime_type, 'image') === false);
1166  $field = $options;
1167  $extra = [];
1168 
1169  if ($field['extra']) {
1170  $extra = $field['extra'];
1171  unset($field['extra']);
1172  }
1173 
1174  $field['name'] = trim(Ego_System::filterNonUtf8(Ego_System::stringEncode($options['name'] ?: $name)));
1175  $field['title'] = trim(Ego_System::filterNonUtf8(Ego_System::stringEncode($options['title'] ?: $field['name'])));
1176 
1177  if (!Ego_System::file_exists($GLOBALS['egotec_conf']['tmp_dir'])) {
1178  Ego_System::mkdir($GLOBALS['egotec_conf']['tmp_dir']);
1179  }
1180 
1181  if (!empty($options['extra']['mime_type'])) {
1182  $extra['mime_type'] = $options['extra']['mime_type'];
1183  } else {
1184  $extra['mime_type'] = $mime_type;
1185  }
1186 
1187  if ($suffix) {
1188  $extra['image_type'] = $suffix;
1189  } else {
1190  // Falls keine Endung angegeben ist, wird diese aus dem Namen gewonnen.
1191  if ($path_info['extension']) {
1192  $extra['image_type'] = $path_info['extension'];
1193  } else {
1194  // Als allerletztes die Endung aus dem Mime/Type bestimmen.
1195  if (!$GLOBALS['mime2ext']) {
1196  $GLOBALS['mime2ext'] = array_flip(Ego_System::getMimeTypes());
1197  }
1198 
1199  if ($extra['mime_type'] == 'image/svg') {
1200  $extra['mime_type'] = 'image/svg+xml';
1201  }
1202 
1203  $extra['image_type'] = $GLOBALS['mime2ext'][$extra['mime_type']];
1204  }
1205  }
1206 
1207  $extra['origFileSize'] = Ego_System::filesize($source);
1208 
1209  if ($is_image && $extra['origFileSize'] > 0) {
1210  require_once 'base/Ego_Image.php';
1211 
1212  $imageTransform = new Ego_Image();
1213  $imageTransform->load($source);
1214 
1215  if (!minimumImageDimensions($imageTransform, $this->_site)) {
1216  return null;
1217  }
1218 
1219  scaleImageOnUpload($imageTransform, $this->_site);
1220 
1221  $extra['origImgWidth'] = $imageTransform->getImageWidth();
1222  $extra['origImgHeight'] = $imageTransform->getImageHeight();
1223 
1224  $keywords = [];
1225  setExifData($field, $extra, $keywords, $imageTransform, $this);
1226  } else {
1227  getFileInfo($source, $extra);
1228  }
1229 
1230  $field['type'] = 'multimedia/' . ($is_image ? 'image' : 'file');
1231  $field['inactive'] = self::ACTIVE_FLAG;
1232  $field['parents'] = ','.trim($this->field['id'],',').',';
1233 
1234  // Wenn Search+ aktiviert ist, wird der Dateiinhalt in die DB aufgenommen
1235  if (!$is_image && $GLOBALS['egotec_conf']['openoffice']['active']) {
1236  require_once 'openoffice/converter.php';
1237  $field['content'] = convert_content($source, $extra['image_type'], $extra['mime_type']);
1238  }
1239 
1240  $child = $this->newChild($field, $extra);
1241 
1242  if (isset($keywords) && !empty($keywords)) {
1243  foreach ($keywords as $keyword) {
1244  $child->addParent($keyword);
1245  }
1246  }
1247 
1248  // Datei nach var/media/ kopieren
1249  $media_dir = $GLOBALS['egotec_conf']['var_dir'].'media'.DIRECTORY_SEPARATOR.$this->_site->name;
1250  if (!Ego_System::file_exists($media_dir)) {
1251  Ego_System::mkdir(strtr($media_dir, '/', DIRECTORY_SEPARATOR), 0777);
1252  }
1253 
1254  $dest = $media_dir.DIRECTORY_SEPARATOR.$child->getMediaFilename(true);
1256  $source,
1257  $dest
1258  );
1259 
1260  // Archiveintrag
1262  $dest,
1263  $media_dir.DIRECTORY_SEPARATOR.$child->getMediaFilename(
1264  true,
1265  '_'.strtotime($child->field['m_date'])
1266  ),
1267  '',
1268  true
1269  );
1270 
1271  // Bilder umwandeln
1272  Ego_Queue::add([$child, 'convertImages']);
1273 
1274  return $child;
1275  }
1276 
1277  return null;
1278  }
1279 
1287  public function extractFile($source, &$images = array()) {
1288  $id = $this->field['id'];
1289  $dir = $GLOBALS['egotec_conf']['tmp_dir'].'import/zip/';
1290  $name = time();
1291  $dest = $dir.$name;
1292  if (!Ego_System::file_exists($dest)) {
1293  Ego_System::mkdir(strtr($dest, '/', DIRECTORY_SEPARATOR), 0777, true);
1294  }
1295  $file = tempnam($dir, 'ZIP_').'.zip';
1296  if (@move_uploaded_file($source, $file)) {
1297  require_once('media/functions.php');
1298  require_once('Archive/Zip.php');
1299  $zip = new Archive_Zip($file);
1300  chdir($dest);
1301  @set_time_limit(0);
1302  $zip->extract();
1303  chdir($GLOBALS['egotec_conf']['bin_dir'].'admin');
1304  $num = GetDir($dest, '', $this->field['id'], true, $images);
1305  Ego_System::deldir($dest, true);
1306  @unlink($file);
1307  if (isset($GLOBALS['_GetDir_firstId'])) {
1308  $id = $GLOBALS['_GetDir_firstId'];
1309  unset($GLOBALS['_GetDir_firstId']);
1310  }
1311  }
1312  return $this->_site->getPage($id);
1313  }
1314 
1322  public function updateFile($source, $name = '') {
1323  if (!$this->validateFile($source, $name)) {
1324  return false;
1325  }
1326 
1327  // WebDAV benötigt immer ein globales Site Objekt
1328  if (!isset($GLOBALS['site'])) {
1329  $GLOBALS['site'] = $this->getSite();
1330  }
1331 
1332  require_once('media/functions.php');
1333  require_once('base/Ego_MimeType.php');
1334  if ($name) {
1335  $path_info = Ego_System::pathinfo($name);
1336  $GLOBALS['mediaType'] = $path_info['extension'];
1337  }
1338  $mime = new Ego_MimeType();
1339  $mime_type = $mime->autoDetect($source);
1340  $is_image = !(strpos($mime_type, 'image') === false);
1341 
1342  $field = array();
1343  $extra = $this->extra;
1344 
1345  $extra['mime_type'] = $mime_type;
1346  if ($name) {
1347  if ($path_info['extension']) {
1348  $extra['image_type'] = $path_info['extension'];
1349  }
1350  }
1351  if (!$name || !$extra['image_type']) {
1352  // Als allerletztes die Endung aus dem Mime/Type bestimmen.
1353  if (!$GLOBALS['mime2ext']) {
1354  $GLOBALS['mime2ext'] = array_flip(Ego_System::getMimeTypes());
1355  }
1356  $extra['image_type'] = $GLOBALS['mime2ext'][$extra['mime_type']];
1357  }
1358 
1359  $extra['origFileSize'] = Ego_System::filesize($source);
1360  $field['type'] = 'multimedia/'.($is_image ? 'image' : 'file');
1361 
1362  if ($is_image) {
1363  require_once('base/Ego_Image.php');
1364  $imageTransform = new Ego_Image();
1365  $imageTransform->load($source);
1366 
1367  if (!minimumImageDimensions($imageTransform, $this->_site)) {
1368  return false;
1369  }
1370 
1371  // Umgewandelte Bilder löschen
1372  Ego_Queue::add([$this, 'clearConvertedImages']);
1373 
1374  scaleImageOnUpload($imageTransform);
1375 
1376  $extra['origImgWidth'] = $imageTransform->getImageWidth();
1377  $extra['origImgHeight'] = $imageTransform->getImageHeight();
1378 
1379  $keywords = [];
1380  setExifData($field, $extra, $keywords, $imageTransform, $this);
1381 
1382  $oldKeywords = array_reduce(
1383  iterator_to_array($this->getParents(['where' => "type = '_keywords/entry'"])),
1384  function($carry, $item) {
1385  return array_merge($carry, [$item->field['id']]);
1386  },
1387  []
1388  );
1389 
1390  // Alte Schlagwörter entfernen
1391  foreach ($oldKeywords as $oldKeyword) {
1392  $this->unlinkFrom($oldKeyword);
1393  }
1394 
1395  // Neue Schlagwörter setzen
1396  if (isset($keywords) && !empty($keywords)) {
1397  foreach ($keywords as $keyword) {
1398  $this->addParent($keyword);
1399  }
1400  }
1401  } else {
1402  getFileInfo($source, $extra);
1403  }
1404 
1405  // Wenn Search+ aktiviert ist, wird der Dateiinhalt in die DB aufgenommen
1406  if (!$is_image) {
1407  if ($GLOBALS['egotec_conf']['openoffice']['active']) {
1408  // OpenOffice: Inhalt neu ermitteln
1409  require_once('openoffice/converter.php');
1410  $field['content'] = convert_content($source, $extra['image_type'], $extra['mime_type']);
1411  } elseif (Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'elastic')) {
1412  // Elasticsearch: Inhalt leeren; wird beim Update automatisch indiziert
1413  $field['content'] = '';
1414  unset($extra['_indexed']);
1415  }
1416  }
1417 
1418  $this->update(array(
1419  'field' => $field,
1420  'extra' => $extra
1421  ));
1422 
1423  // Alle Ausschnitte ebenfalls aktualiseren
1424  if ($this->field['type'] == 'multimedia/image') {
1425  foreach ($this->getChildren(array(), array(
1426  'auth_or' => '1=1'
1427  )) as $child) {
1428  if ($child->extra['crop_image']) {
1429  $extra = array(
1430  'edit' => $child->extra['edit'],
1431  'crop_image' => true
1432  );
1433  $child->updateExtra(array_merge($this->extra, $extra));
1434  }
1435  }
1436  }
1437 
1438  // Datei nach var/media/ kopieren
1439  $media_dir = $GLOBALS['egotec_conf']['var_dir'].'media'.DIRECTORY_SEPARATOR.$this->_site->name;
1440  if (!Ego_System::file_exists($media_dir)) {
1441  Ego_System::mkdir(strtr($media_dir, '/', DIRECTORY_SEPARATOR), 0777, true);
1442  }
1443 
1444  // Falls die Datei der Standard Sprache noch nicht im Sprach Verzeichnis liegt, dann verschieben
1445  if (
1446  $this->_site->language == $this->_site->site['default_language']
1447  && !Ego_System::file_exists($media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(true))
1448  && Ego_System::file_exists($media_dir.DIRECTORY_SEPARATOR.$this->field['id'])
1449  ) {
1450  rename(
1451  $media_dir.DIRECTORY_SEPARATOR.$this->field['id'],
1452  $media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(true)
1453  );
1454 
1455  $mediafiles = glob($media_dir.DIRECTORY_SEPARATOR.$this->field['id'].'_*');
1456  if (is_array($mediafiles)) {
1457  foreach ($mediafiles as $mediafile) {
1458  preg_match('/\d+_\d+$/', $mediafile, $name);
1459  rename(
1460  $mediafile,
1461  $media_dir.DIRECTORY_SEPARATOR.$this->_site->language.DIRECTORY_SEPARATOR.$name[0]
1462  );
1463  }
1464  }
1465  }
1466 
1467  // Vor dem Ersetzen das Original löschen, damit sich die Archive nicht ändern, weil diese Hardlinks sind
1468  $dest = $media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(true);
1469  @unlink($dest);
1470  Ego_System::copy($source, $dest);
1471 
1472  // Archiveintrag
1474  $dest,
1475  $media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(
1476  true,
1477  '_'.strtotime($this->field['m_date'])
1478  ),
1479  '',
1480  true
1481  );
1482 
1484  $GLOBALS['egotec_conf']['cachemedia_dir'].$this->_site->name.DIRECTORY_SEPARATOR.
1485  $this->getMediaFilename(true)
1486  );
1487 
1488  if ($this->_site->admin['video']['convert'] && preg_match('/video/', $this->extra['mime_type']) && $this->extra['mime_type'] != 'video/mp4') {
1489  // Video konvertieren
1490  Ego_Queue::add(array($this, 'convertVideo'));
1491  } elseif($this->_site->admin['video']['compress'] && $this->extra['mime_type'] == 'video/mp4') {
1492  // Video komprimieren
1493  Ego_Queue::add([$this, 'compressVideo']);
1494  }
1495 
1496  return true;
1497  }
1498 
1505  public function updateDocumentFiles($remove = false) {
1506  if ($this->_site->site['type'] == 'media') {
1507  // Multimedia
1508  if ($this->field['type'] == 'multimedia/file') {
1509  $file = $GLOBALS['egotec_conf']['var_dir'] . 'media/' . $this->_site->name . '/' . $this->getMediaFilename();
1510  if (Ego_System::file_exists($tmp_file = $GLOBALS['egotec_conf']['tmp_dir'] . 'document-' . md5($file))) {
1511  if (!$remove) {
1512  $this->updateFile($tmp_file, $this->field['name'] . '.' . $this->extra['image_type']);
1513  }
1514  @unlink($tmp_file);
1515  }
1516  }
1517  } elseif (!empty($this->_site->admin['mediapool']['active'])) {
1518  // Mediapool
1519  $mediapool = $this->getMediapool();
1520  foreach ($mediapool->getDirs() as $dir) {
1521  foreach ($mediapool->list($dir, ['only_files' => true]) as $item) {
1522  if (Ego_System::file_exists($tmp_file = $GLOBALS['egotec_conf']['tmp_dir'] . 'document-' . md5($item['file']))) {
1523  if (!$remove) {
1524  $mediapool->put($tmp_file, $item['name'], $dir);
1525  }
1526  @unlink($tmp_file);
1527  }
1528  }
1529  }
1530  }
1531  }
1532 
1544  function copyTo($id, $recursive = false, $params = array(), &$copied_pages = array())
1545  {
1546  $original_copied_pages = $copied_pages;
1547 
1548  if (!isset($GLOBALS['__egotec_skip_replication'])) {
1549  $GLOBALS['__egotec_skip_replication'] = 'copyTo';
1550  }
1551 
1552  if ($this->isClone() || $this->isWorkflowCopy() || $this->isReleaseCopy()) {
1553  return false; // Keine Klone, Workflow- und Freigabekopien kopieren
1554  }
1555 
1556  $param = array(
1557  'auth_or' => '1=1',
1558  'only_active' => false,
1559  'inactive' => true
1560  );
1561 
1562  /* @var $new_parent Page */
1563  if (is_a($id, 'Page')) {
1564  // $id ist bereits das Page Objekt
1565  $new_parent = $id;
1566  } elseif (is_a($params['site'], 'Site')) {
1567  // Übergebenes Site Objekt
1568  $new_parent = $params['site']->getPage($id, $param);
1569  } elseif (
1570  $this->_site->name == $GLOBALS['site']->name
1571  && $this->_site->language == $GLOBALS['site']->language
1572  ) {
1573  // Quell- und Ziel-Mandant sind identisch
1574  $new_parent = $this->_site->getPage($id, $param);
1575  } else {
1576  // Kopieren über Mandanten hinweg
1577  if ($this->_site->site['type'] == 'media') {
1578  $new_parent = $GLOBALS['site']->getMediaSite()->getPage($id, $param);
1579  } else {
1580  $new_parent = $GLOBALS['site']->getPage($id, $param);
1581  }
1582  }
1583  $site_parent = $new_parent->getSite();
1584 
1585  // Kopieren in den selben Mandanten: Endlosschleife vermeiden
1586  if ($this->_site->name == $site_parent->name) {
1587  $ancestors = $this->_getAncestorsIds(
1588  $new_parent,
1589  array('fields' => 'id'),
1590  array('auth_or' => '1=1')
1591  );
1592  if (in_array($this->field['id'], $ancestors)) {
1593  return false;
1594  }
1595  }
1596 
1597  // Kopierte Werte setzen
1598  if (is_array($params['field'])) {
1599  $field = $params['field'];
1600  } else {
1601  $field = $this->field;
1602  }
1603  if (is_array($params['extra'])) {
1604  $extra = $params['extra'];
1605  } else {
1606  $extra = $this->extra;
1607  }
1608 
1609  unset($field['id']);
1610  unset($field['extra']);
1611  $field['a_user'] = $GLOBALS['auth']->user->field['user_id'];
1612  $field['a_date'] = date('Y-m-d H:i:s');
1613  unset($extra['workflow_page']);
1614 
1615  // Eine kopierte Seite hat keine Klone
1616  unset($extra['clones']);
1617  foreach (array_keys($extra) as $key) {
1618  if (
1619  strpos($key, 'clone_children_') === 0
1620  || strpos($key, 'clone_rights_') === 0
1621  || strpos($key, 'clone_release_') === 0
1622  ) {
1623  unset($extra[$key]);
1624  }
1625  }
1626 
1627  // Meta Url löschen wenn die Seite im gleichen Mandanten kopiert wird
1628  if($this->_site->name == $site_parent->name) {
1629  unset($field['url']);
1630  }
1631 
1632  // Kopierte Seite aufräumen
1633  if ($params['cleanup']) {
1634  // Immer inaktiv
1635  $field['inactive'] = 1;
1636 
1637  // Keine Workflowhistorie
1638  unset($extra['history']);
1639  }
1640 
1641  // Vor dem Kopieren einer Seite dessen Felder manipulieren
1642  try {
1643  [$field, $extra] = $this->copyToFields($field, $extra);
1644  } catch (Exception $e) {
1645  // "copyToFields" existiert nicht, ignorieren
1646  }
1647 
1648  $copy = $new_parent->newChild($field, $extra); /* @var $copy Page */
1649 
1650  /* Evtl. vorhandene MM-Datei kopieren */
1651  if (file_exists($GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename())) {
1652  if ($this->_site->name == $site_parent->name && $this->_site->language == $site_parent->language) {// Quell- und Ziel-Mandant sind identisch
1654  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename(),
1655  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$copy->getMediaFilename(true),
1656  '',
1657  true
1658  );
1659  } else { //Kopieren über Mandanten hinweg
1661  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename(),
1662  $GLOBALS['egotec_conf']['var_dir'].'media/'.$site_parent->name.'/'.$copy->getMediaFilename(true),
1663  '',
1664  true
1665  );
1666  }
1667  }
1668 
1669  // Mediapool kopieren
1670  $this->getMediapool()->copy($copy, '', false, false, false);
1671 
1672  // Sprachen beachten
1673  if (
1674  !$copy->isReleaseCopy() // Freigabekopien werden nur in der aktuellen Sprache angelegt
1675  ) {
1676  foreach($this->_site->getLanguages() as $lang) {
1677  if ($lang != $this->_site->language) {
1678  if (in_array($lang, $this->_site->getLanguages()) &&
1679  in_array($lang, $copy->getSite()->getLanguages())
1680  ) {
1681  $lang_page = $this->getLanguagePage($lang); // die sprachversion der zu kopierenden seite
1682 
1683  if ($lang_page) {
1684  $lang_page_field = $lang_page->field;
1685  $lang_page_extra = $lang_page->extra;
1686  $lang_page_field['id'] = $copy->field['id'];
1687 
1688  // Vor dem Kopieren einer Seite dessen Felder manipulieren
1689  try {
1690  [$lang_page_field, $lang_page_extra] = $this->copyToFields($lang_page_field, $lang_page_extra);
1691  } catch (Exception $e) {
1692  // "copyToFields" existiert nicht, ignorieren
1693  }
1694 
1695  $_param = array('auth_or'=>'1=1', 'deleted_or'=>'1=1', 'inactive'=>true);
1696  $lang_copy = $copy->getLanguagePage($lang, $_param);
1697  if (!$lang_copy) {
1698  $copy_parent = $new_parent->getLanguagePage($lang, $_param);
1699  if (!$copy_parent) { // Sprachversion der Elternseite existiert nicht, also direkt unter der Startseite einfügen
1700  $copy_parent = $copy->getSite()->getRoot()->getLanguagePage($lang, $_param);
1701  }
1702  $lang_copy = $copy_parent->newChild($lang_page_field, $lang_page_extra);
1703  } else { // Sprachversion existiert bereits
1704  $lang_copy->update(
1705  array(
1706  'field' => $lang_page_field,
1707  'extra' => $lang_page_extra
1708  )
1709  );
1710  }
1711 
1712  if($lang_copy) {
1713  // Rechte übernehmen
1714  $rights = array(
1715  "rights" => $lang_page->getRightsArray()
1716  ,"users" => $lang_page->getUsersArray()
1717  );
1718  $lang_copy->updateRights($rights, false);
1719  }
1720  }
1721  }
1722  }
1723  }
1724  }
1725 
1726  if ($recursive) {
1727  // Bei einer Rekursion werden Mehrfacheinhängungen beibhalten
1728  if (!isset($copied_pages[$this->field['id']])) {
1729  $copied_pages[$this->field['id']] = $copy;
1730  }
1731 
1732  if ($params['children_param']['sitemap'] !== false) {
1733  $params['children_param']['sitemap'] = true;
1734  }
1735 
1736  $children = $this->getChildren($params['children_query'], $params['children_param']);
1737 
1738  foreach ($children as $child) {
1739  set_time_limit(0); // Ein Timeout verhindern.
1740  if ($new_child = $copied_pages[$child->field['id']]) {
1741  // Mehrfacheinhängung beibehalten
1742  $new_child->addParent($copy->field['id'], true);
1743  } else {
1744  $child->copyTo($copy,$recursive,$params,$copied_pages);
1745  }
1746  }
1747  }
1748 
1749  if ($new_parent->extra['clones']) { // Prüfen ob die neue Elternseite Klone hat und diese dann aktualisieren
1750  $param = array(
1751  'field' => $new_parent->field
1752  );
1753  $new_parent->_updateClones($param);
1754  }
1755 
1756  $this->replicate('copyTo', $id, $recursive, $params, $original_copied_pages);
1757 
1758  return $copy;
1759  }
1760 
1768  function move($from, $to) {
1769  if (!isset($GLOBALS['__egotec_skip_replication'])) {
1770  $GLOBALS['__egotec_skip_replication'] = 'move';
1771  }
1772 
1773  if ($from != $to && $this->addParent($to)) {
1774  $this->delParent($from, true);
1775  }
1776  $this->hookUpdate();
1777 
1778  $this->replicate('move', $from, $to);
1779  }
1780 
1787  function linkTo($id) {
1788  $this->addParent($id);
1789  }
1790 
1803  function delete($parent = false, $nostart = false, $keeplinks = true, $query = array()) {
1804  if (!isset($GLOBALS['__egotec_skip_replication'])) {
1805  $GLOBALS['__egotec_skip_replication'] = 'delete';
1806  }
1807 
1808  if ($this->isRoot()) {
1809  throw new Page_Exception("Can't delete root page.", Page_Exception::ROOT_PROTECTION);
1810  }
1811 
1812  // Wird ein Schlagwort gelöscht, werden auch nur Schlagwörter berücksichtigt
1813  // TODO mit param[sitemap] = false lösen
1814  if ($this->field['type'] == '_keywords/entry') {
1815  if ($query['where']) {
1816  $query['where'] = "({$query['where']}) AND type = '_keywords/entry'";
1817  } else {
1818  $query['where'] = "type = '_keywords/entry'";
1819  }
1820  }
1821 
1822  $this->archiveOnly = false;
1823  $children = $this->getChildren(
1824  $query,
1825  array(
1826  'inactive' => true,
1827  'auth_or' => '1=1'
1828  )
1829  );
1830  foreach ($children as $child) { // Die Seite hat Unterseiten
1831  $child->delete($keeplinks ? $this : false, false, $keeplinks, $query);
1832  if (isset($child->extra['main_category']) && $child->extra['main_category'] == $this->field['id']) {
1833  unset($child->extra['main_category']);
1834  $child->update([], true, true);
1835  }
1836  }
1837 
1838  // Sprachverknüpfungen: wenn die Standardsprache gelöscht wird ...
1839  if (
1840  is_array($this->extra['language_link'])
1841  && $this->extra['language_standard'] == $this->_site->language
1842  ) {
1843  $languages = $this->_site->getLanguages();
1844 
1845  // wird ein neuer Standard gesetzt
1846  $standard = $languages[0] == $this->_site->language
1847  ? $languages[1]
1848  : $languages[0];
1849 
1850  // werden alle anderen sprachen durchgegangen
1851  foreach ($languages as $lang) {
1852  if ($lang == $this->_site->language) {
1853  continue;
1854  }
1855 
1856  // Ursprüngliche Sprachverknüpfung aufheben
1857  $this->extra['language_link'][$lang] = 0;
1858 
1859  if (
1860  ($lang_page = $this->getLanguagePage($lang, ['deleted' => -1]))
1861  && is_array($lang_page->extra['language_link'])
1862  && $lang_page->extra['language_link'][$this->_site->language]
1863  ) {
1864  // und die Sprachverknüpfung gelöscht
1865  $extra = $lang_page->extra;
1866  $extra['language_link'][$this->_site->language] = 0;
1867  $extra['language_link'][$standard] = 1;
1868  $extra['language_standard'] = $standard;
1869 
1870  $lang_page->update(array('extra' => $extra));
1871  }
1872  }
1873 
1874  // Die Sprachmatrix der gelöschten Seite wird zur Sprachmatrix der neuen Standardsprache
1875  $lang_page = $this->getLanguagePage($standard, ['deleted' => -1]);
1876  $this->extra['language_link'] = $lang_page->extra['language_link'];
1877  $this->extra['language_standard'] = $lang_page->extra['language_standard'];
1878  }
1879 
1880  $parents = $this->getParents(
1881  array(
1882  'fields' => 'id',
1883  'where' => "type != '_keywords/entry'"
1884  ),
1885  array(
1886  'sitemap' => true,
1887  'inactive' => true,
1888  'auth_or' => '1=1'
1889  )
1890  );
1891  if ($parent && $parents->numRecords() > 1)
1892  {// Die Seite ist mehrfach eingehängt
1893  $this->unlinkFrom($parent->field['id']);
1894  } else {
1895  if(!$nostart) {
1896  // Alle Workflow-, Freigabekopien zerstören
1897  $destroy_ids = array();
1898  if (!empty($this->extra['workflow_page'])) {
1899  $destroy_ids[] = $this->extra['workflow_page'];
1900  }
1901  if (!empty($this->extra['release_ids'])) {
1902  $destroy_ids = array_merge($destroy_ids, $this->extra['release_ids']);
1903  }
1904  foreach ($destroy_ids as $destroy_id) {
1905  if ($destroy_page = $this->_site->getPage($destroy_id, array(
1906  'only_active' => false,
1907  'inactive' => 1,
1908  'auth_or' => '1=1'
1909  ))) {
1910  $destroy_page->destroy(true);
1911  }
1912  }
1913 
1914  // Sich selbst löschen
1915  $field['deleted'] = 1;
1916  $extra = $this->extra;
1917  unset($extra['workflow_page'], $extra['release_ids']);
1918  $this->update(array('field' => $field, 'extra' => $extra));
1919  }
1920  }
1921 
1922  // Achtung: wenn ich eine Klon Seite bin, dann muss die Verknüpfung aus der Originalseite entfernt werden
1923  if ($this->isClone()) {
1924  $org = $this->getCloneOriginal();
1925  $del_clone = $this->getParents(array(), array(
1926  'inactive' => true,
1927  'auth_or' => '1=1'
1928  ))->nextPage();
1929  $del_id = $del_clone->field['id']; // abwärtskompatibel
1930  if ($org) {
1931  $del_url = $this->getCloneUrl();
1932 
1933  $clones = array_filter(array_unique(explode(',', $org->extra['clones'])));
1934  $new_clones = array();
1935  foreach ($clones as $clone_url) {
1936  if (!in_array($clone_url, array($del_id, $del_url))) {
1937  $new_clones[] = $clone_url;
1938  }
1939  }
1940 
1941  $org->extra['clones'] = implode(',', $new_clones);
1942  $org->updateExtra($org->extra);
1943  }
1944  }
1945 
1946  // Achtung: wenn ich eine Freigabekopie bin, dann muss die Verknüpfung aus der Originalseite entfernt werden
1947  if ($this->isReleaseCopy()) {
1948  if (
1949  ($org = $this->_site->getPage($this->extra['release_id'], array(
1950  'only_active' => false,
1951  'inactive' => 1,
1952  'auth_or' => '1=1'
1953  )))
1954  && is_array($org->extra['release_ids'])
1955  ) {
1956  $org->extra['release_ids'] = array_values(array_diff($org->extra['release_ids'], array($this->field['id'])));
1957  $org->update(array(), true, true);
1958  }
1959  }
1960 
1961  // Schlagwort Parents durchgehen und löschen wenn:
1962  // -> der Mandant die Checkbox "Neues Schlagwortregister verwenden" gesetzt hat
1963  // -> der verwendete Schlagwortregister nicht der Mandant des Klon Originals ist
1964  // -> das Schlagwort ein Klon ist
1965  // -> das Schlagwort ansonsten nicht mehr verwendet wird
1966  // oder das Schlagwort Klone hat und
1967  // -> der verwendete Schlagwortregister des Mandanten in dem sich der Klon befindert nicht der Mandant des Originals ist
1968  // -> das Schlagwort ansonsten nicht mehr verwendet wird
1969  // Schlagwort Parents holen wenn der Mandant die Checkbox "Neues Schlagwortregister verwenden" gesetzt hat
1970  if ($this->getSite()->admin['keyword_register_own_site']) {
1971  $keyword_parents = $this->getParents(['where' => "type = '_keywords/entry'"]);
1972 
1973  if ($keyword_parents->numRecords() > 0) {
1974  foreach ($keyword_parents as $keyword_parent) {
1975  if ($keyword_parent->isClone() && !$keyword_parent->hasChildren()
1976  && $keyword_parent->getCloneOriginal()->getSite()->name != $this->getSite()->admin['keywords']['site']) {
1977  $this->_deleteCloneKeywords($this, $keyword_parent);
1978  } elseif (!$keyword_parent->isClone() && $keyword_parent->extra['clones']) {
1979  $keyword_clones = $keyword_parent->getClones();
1980  foreach ($keyword_clones as $keyword_clone) {
1981  if ($keyword_clone->getSite()->name != $keyword_parent->getSite()->admin['keywords']['site']
1982  && !$keyword_clone->hasChildren()) {
1983  $this->_deleteCloneKeywords($keyword_parent, $keyword_clone);
1984  }
1985  }
1986  }
1987  }
1988  }
1989  }
1990 
1991  $this->replicate('delete', $parent, $nostart, $keeplinks, $query);
1992  }
1993 
2001  protected function _destroyEntry($recursive=true) {
2002  @set_time_limit(0); //Wird zwingend benötigt, für den Fall dass viele Unterseiten existieren
2003  $db = new_db_connection();
2004 
2005  $this->message = 'Diese Seite wurde vernichtet.';
2006 
2007  if($recursive) {
2008  $query = array();
2009 
2010  // Wird ein Schlagwort zerstört, werden auch nur Schlagwörter berücksichtigt
2011  // TODO mit param[sitemap] = false lösen
2012  if ($this->field['type'] == '_keywords/entry') {
2013  $query['where'] = "type = '_keywords/entry'";
2014  }
2015 
2016  $pages = $this->getChildren($query, array('deleted' => 1));
2017  $del_array = array();
2018  foreach($pages as $page) { // Zunächst alle Seiten holen,
2019  $del_array[] = $page;
2020  }
2021  foreach($del_array as $page) { // weil es bei ms sql sonst hier zu einer Blockade kommt.
2022  $page->destroy(false, $recursive);
2023  $this->message = 'Diese Seite wurde inklusive Unterseiten erfolgreich vernichtet.';
2024  }
2025  }
2026 
2027  $parents = $this->getParents(array(), array('deleted' => -1));
2028  foreach ($parents as $parent) {
2029  $this->unlinkFrom($parent->field['id']);
2030  }
2031 
2032  $db->begin();
2033  $db->delete(array( // Aus der Tabelle löschen.
2034  'table' => $this->_site->pageTable,
2035  'where' => "id=".$this->field['id']
2036  ));
2037  $db->delete(array( // Aus dem Archiv löschen.
2038  'table' => $this->_site->pageTable.'_v',
2039  'where' => "id=".$this->field['id']
2040  ));
2041  $db->delete(array( // Aus der Rechte-Tabelle löschen.
2042  'table' => $this->_site->pageTable.'_rights',
2043  'where' => "page_id=".$this->field['id']
2044  ));
2045  $db->delete(array( // Aus der User-Tabelle löschen.
2046  'table' => $this->_site->pageTable.'_users',
2047  'where' => "page_id=".$this->field['id']
2048  ));
2049  $db->delete(array( // Aus der Kinder-Tabelle löschen.
2050  'table' => $this->_site->pageTable.'_children',
2051  'where' => 'page_id='.$this->field['id'].' OR child='.$this->field['id']
2052  ));
2053  // Aus der Extra-Tabelle löschen.
2054  if ($db->tableExists($this->_site->pageTable.'_extra'))
2055  {
2056  $db->delete(array(
2057  'table' => $this->_site->pageTable.'_extra',
2058  'where' => 'page_id='.$this->field['id']
2059  ));
2060  }
2061  $db->commit();
2062 
2063  // Evtl. vorhandene Media Dateien löschen
2064  $this->destroyFile();
2065 
2066  // Evtl. vorhandenen Mediapool löschen
2067  $this->getMediapool()->clear('', [], false);
2068 
2069  // Alle URLs löschen
2070  $this->removeUrls();
2071 
2072  // Suchindex aufräumen
2073  require_once('base/Ego_Search_Factory.php');
2074  $search = Ego_Search_Factory::start($this->_site->pageTable);
2075  try {
2076  $search->delete($this->field['id']);
2077  } catch (Exception $e) {
2078  // ignorieren -> id wurde im Index nicht gefunden
2079  }
2080 
2081  $this->message .= ' Eine Wiederherstellung ist nicht möglich.';
2082  }
2083 
2093  public function destroy($force=false, $recursive=true, $destroy_links=true) {
2094  if (!isset($GLOBALS['__egotec_skip_replication'])) {
2095  $GLOBALS['__egotec_skip_replication'] = 'destroy';
2096  }
2097 
2098  if ($this->isRoot()) {
2099  throw new Page_Exception("Can't destroy root page.", Page_Exception::ROOT_PROTECTION);
2100  }
2101  $this->archiveOnly = false;
2102  if (count(Ego_System::getCluster())>0) {
2103  $time = array();
2104  foreach (Ego_System::getCluster() as $cluster) {
2105  $log_filename = $GLOBALS['egotec_conf']['log_dir'].$GLOBALS['site']->name.'/live.'.$this->_site->name.'_'.$this->_site->language.'.'.$cluster['id'].'.up.date';
2106  if (file_exists($log_filename)) {
2107  $time[] = file_get_contents($log_filename);
2108  }
2109  }
2110 
2111  sort($time);
2112 
2113  if (count($time) > 0) {
2114  $live_date = $time[0];
2115  } else {
2116  $live_date = date('Y-m-d H:i:s', time());
2117  }
2118 
2119  } else {
2120  $live_date_file = $GLOBALS['egotec_conf']['log_dir'].$this->_site->name.'/'.'live.'.$this->_site->name.'_'.$this->_site->language.'.date';
2121 
2122  if(file_exists($live_date_file)) {
2123  $live_date = file_get_contents($live_date_file);
2124  } else {
2125  $live_date = date('Y-m-d H:i:s', time());
2126  }
2127  }
2128  if (
2129  !$force
2130  && (
2131  ($GLOBALS['egotec_conf']['liveserver'] && !$this->getSite()->admin['live']['live_only'])
2132  || $this->field['m_date'] > $live_date
2133  || !$this->field['deleted']
2134  )
2135  ) {
2136  return $this->delete();
2137  }
2138 
2139  if (
2140  $destroy_links
2141  && is_array($this->extra['language_link'])
2142  && $this->extra['language_standard'] == $this->_site->language
2143  ) {
2150  foreach($this->_site->getLanguages() as $lang) {
2151  $flag = !empty($this->extra['language_link'][$lang]);
2152  if ($flag && $lang != $this->_site->language) {
2153  try {
2154  if ($lang_page = $this->getLanguagePage($lang, array('deleted' => -1, 'auth_or' => '1=1'))) {
2155  $lang_page->_destroyEntry($recursive);
2156  }
2157  } catch (Site_Exception $e) {
2158  // Eine nicht mehr vorhandene Sprache ignorieren
2159  }
2160  }
2161  }
2162  }
2163 
2164  // Umgewandelte Bilder löschen
2165  Ego_Queue::add([$this, 'clearConvertedImages']);
2166 
2167  $this->replicate('destroy', $force, $recursive);
2168 
2169  $this->_destroyEntry($recursive);
2170  }
2171 
2179  function undelete($recursive = false, $query = array()) {
2180  if (!isset($GLOBALS['__egotec_skip_replication'])) {
2181  $GLOBALS['__egotec_skip_replication'] = 'undelete';
2182  }
2183 
2184  $this->restore();
2185  $this->message = 'Diese Seite wurde erfolgreich wiederhergestellt.';
2186 
2187  if (
2188  ($this->extra['language_standard']==$this->_site->language
2189  || $this->_site->admin['multi_lang']['auto_link'])
2190  && is_array($this->extra['language_link'])
2191  ) {
2192  foreach($this->_site->getLanguages() as $lang) {
2193  $flag = ($this->extra['language_link'] && !empty($this->extra['language_link'][$lang]))
2194  || $lang == $this->extra['language_standard'];
2195  if ($flag || $this->_site->admin['multi_lang']['auto_link']) {
2196  $lang_page = $this->getLanguagePage($lang, array('deleted' => -1));
2197  if (!is_object($lang_page)) {
2198  continue;
2199  }
2200  $lang_page->restore();
2201  if ($recursive) {
2202  $pages = $lang_page->getDescendants(array(), array(
2203  'deleted' => -1,
2204  'children_query' => $query
2205  ));
2206  foreach ($pages as $page)
2207  {
2208  $page->restore();
2209  }
2210  }
2211  }
2212  }
2213  }
2214 
2215  if ($recursive) {
2216  $pages = $this->getDescendants(array(), array(
2217  'deleted' => -1,
2218  'children_param' => array('deleted' => -1),
2219  'children_query' => $query
2220  ));
2221  if ($pages->numRecords()>0) {
2222  $this->message = 'Diese Seite wurde inklusive Unterseiten erfolgreich wiederhergestellt.';
2223  }
2224  foreach ($pages as $page) {
2225  $page->restore();
2226  }
2227  }
2228 
2229  $this->replicate('undelete', $recursive, $query);
2230  }
2231 
2237  private function restore() {
2238  if (!isset($GLOBALS['__egotec_skip_replication'])) {
2239  $GLOBALS['__egotec_skip_replication'] = 'restore';
2240  }
2241 
2242  $inactive = $this->field['inactive'] == self::RELEASE_FLAG ?
2243  self::RELEASE_FLAG :
2244  self::INACTIVE_FLAG;
2245  if ($this->field['type'] == '_keywords/entry') {
2246  $inactive = self::ACTIVE_FLAG;
2247  }
2248  $field = array('inactive' => $inactive, 'deleted' => 0);
2249  if (!empty($this->field['url']) && !$this->isUniqueUrl($this->field['url'])) {
2250  // Beim Wiederherstellen wird die Meta URL gelöscht, wenn diese bereits verwendet wird
2251  $field['url'] = '';
2252  }
2253 
2254  // Ist die einzige Elternseite im Papierkorb oder existiert nicht, dann ist die Startseite die neue Elternseite
2255  $field['parents'] = $this->_site->rootId;
2256  foreach ($this->getParents(array(), array('deleted' => 0)) as $parent) {
2257  unset($field['parents']);
2258  break;
2259  }
2260 
2261  $this->updateField($field, false);
2262 
2263  $this->replicate('restore');
2264  }
2265 
2271  function unlinkFrom($remove_from) {
2272  if (!isset($GLOBALS['__egotec_skip_replication'])) {
2273  $GLOBALS['__egotec_skip_replication'] = 'unlinkFrom';
2274  }
2275 
2276  $this->_removeParent($remove_from);
2277  if (!$this->field['deleted']) {
2278  // Prüfen ob noch weitere Parents vorhanden sind
2279  $parents = $this->getParents(array('fields' => 'id'), array(
2280  'sitemap' => true,
2281  'inactive' => true,
2282  'auth_or' => '1=1'
2283  ));
2284  if (!$parents->next()) {// Es sind keine Eltern mehr vorhanden.
2285  $this->delete();
2286  }
2287  }
2288 
2289  $this->replicate('unlinkFrom', $remove_from);
2290  }
2291 
2300  protected function _updateField($field, $update=true, $asis=false, $silent=false) {
2301  if (!$asis && $field['url'] && $field['id'] && $this->field['url'] != $field['url']) {
2302  $query = array(
2303  'table' => $this->_site->name.'_'.$this->_site->language,
2304  'fields' => 'id, url',
2305  'where' => 'url=:url'.
2306  ' AND deleted=0'.
2307  ' AND id!=:id',
2308  'bind' => array(
2309  'url' => $field['url'],
2310  'id' => $field['id']
2311  )
2312  );
2313  if ($this->extra['original_id']) {
2314  $query['where'].= ' AND id!=:originalid';
2315  $query['bind']['originalid'] = $this->extra['original_id'];
2316  }
2317  $db = new_db_connection($query);
2318  if ($db->nextRecord()) {
2319  $this->message.= $GLOBALS['auth']->translate('Die URL konnte nicht gespeichert werden, weil sie schon vorhanden ist!') . '\n';
2320  $field['url'] = $this->field['url'];
2321  }
2322  }
2323 
2324  // Multimedia Kategorien, Dateien und Bilder dürfen diese Zeichen nicht beinhalten: \/:*?"<>|
2325  if (isset($field['name'])) {
2326  $field['name'] = strip_tags($field['name']);
2327  if (in_array((isset($field['type']) ? $field['type'] : $this->field['type']), array('multimedia/category', 'multimedia/file', 'multimedia/image'))) {
2328  $field['name'] = strtr($field['name'], '\/:*?"<>|', '_________');
2329  }
2330  }
2331 
2332  // Kein HTML für Titel und Kurzbeschreibung
2333  if ($this->_site->admin['editor']['plaintext']) {
2334  if (isset($field['title'])) {
2335  $field['title'] = strip_tags($field['title']);
2336  }
2337  if (isset($field['short']) && !$this->_site->admin['editor']['short'] && !$GLOBALS['egotec_conf']['editor']['short']) {
2338  $field['short'] = strip_tags($field['short']);
2339  }
2340  }
2341 
2342  // Der Seitentyp darf nicht leer sein
2343  if (isset($field['type']) && empty($field['type'])) {
2344  $field['type'] = !empty($this->field['type']) ? $this->field['type'] : 'page';
2345  }
2346 
2347  $this->_cleanEmptyContent($field);
2348 
2349  $this->field = array_merge($this->field, $field);
2350  if ($update)
2351  {
2352  $this->_changeEntry($field, $asis, $silent);
2353  }
2354  }
2355 
2362  protected function _updateKeywords($asis = false) {
2363  // Nur wenn es ein Schlagwortregister gibt
2364  if ($this->_site->admin['keyword_register_own_site']) {
2365  $keywords = $this->_site->getPages(['where' => "type = '_keywords/list'"])->nextPage();
2366  if ($keywords) {
2367  // Alle Abkürzungen ermitteln (performant, ohne getDescendants)
2368  $abbreviations = $this->_site->getPages([], [
2369  'extra' => "type = '_keywords/entry' AND deleted = 0 AND extra.abbreviation = 1"
2370  ]);
2371 
2372  // Unterschiede bei den zugeordneten Abkürzungen erkennen
2373  $old_abbreviations = [];
2374  $new_abbreviations = [];
2375  $current_abbreviations = $this->getParents([
2376  'where' => "type = '_keywords/entry'"
2377  ]);
2378  foreach ($current_abbreviations as $current_abbreviation) {
2379  if ($current_abbreviation->extra['abbreviation']) {
2380  $old_abbreviations[] = $current_abbreviation->field['id'];
2381  }
2382  }
2383 
2384  foreach ($abbreviations as $abbreviation) {
2385  // Zu suchende Wörter
2386  $words = [$abbreviation->field['name']];
2387 
2388  // Synonyme ebenfalls suchen
2389  if ($abbreviation->extra['synonym']) {
2390  require_once 'base/Ego_Combo.php';
2391  $combo = new Ego_Combo($abbreviation->extra['synonym']);
2392  foreach ($combo->getText() as $text) {
2393  $words[] = (string) $text;
2394  }
2395  }
2396 
2397  // Rekursiv nach den Begriffen suchen
2398  $search = function($value) use (&$search, $words) {
2399  if (is_array($value)) {
2400  foreach ($value as $v) {
2401  if ($search($v)) {
2402  return true;
2403  }
2404  }
2405  }
2406  return is_string($value)
2407  && preg_match('/>?[^<]*?\W*(' . implode('|', array_map(function($v) {
2408  return preg_quote($v, '/');
2409  }, $words)) . ')\W*[^>]*?<?/is', $value);
2410  };
2411 
2412  if (
2413  $search($this->field['name'])
2414  || $search($this->field['title'])
2415  || $search($this->field['short'])
2416  || $search($this->field['content'])
2417  || $search($this->field['extra'])
2418  ) {
2419  // Schlagwort hinzufügen
2420  if (!$this->hasParent($abbreviation->field['id'])) {
2421  $this->addParent($abbreviation->field['id'], $asis);
2422  }
2423  $new_abbreviations[] = $abbreviation->field['id'];
2424  } elseif ($this->hasParent($abbreviation->field['id'])) {
2425  // Schlagwort entfernen
2426  $this->delParent($abbreviation->field['id'], $asis);
2427  }
2428  }
2429 
2430  $diff1 = array_diff($old_abbreviations, $new_abbreviations);
2431  $diff2 = array_diff($new_abbreviations, $old_abbreviations);
2432  return !empty($diff1) || !empty($diff2);
2433  }
2434  }
2435  return false;
2436  }
2437 
2444  protected function _updateChildren($children, $merge = true) {
2445  // Unterseiten beibehalten die nicht übergeben wurden, um verlorene Seiten zu vermeiden
2446  if ($merge) {
2447  $db = new_db_connection([
2448  'table' => $this->_site->pageTable . '_children',
2449  'where' => 'page_id = :page_id',
2450  'bind' => [
2451  'page_id' => $this->field['id']
2452  ],
2453  'order' => 'idx ASC'
2454  ]);
2455  while ($db->nextRecord()) {
2456  if (!in_array($db->Record['child'], $children)) {
2457  array_splice($children, (int)$db->Record['idx'], 0, $db->Record['child']);
2458  }
2459  }
2460  }
2461 
2462  $ancestors_iterator = $this->getAncestors(
2463  array('fields' => 'id'),
2464  array('auth_or' => '1=1', 'children_param' => array('auth_or' => '1=1'))
2465  );
2466  $ancestors = array();
2467  foreach ($ancestors_iterator as $ancestor_page)
2468  {
2469  $ancestors[] = $ancestor_page->field['id'];
2470  }
2471  $ancestors[] = $this->field['id'];
2472 
2473  $db = new_db_connection();
2474  $db->begin();
2475  $table = $this->_site->pageTable;
2476  $db->delete(array( // Alte Einträge löschen.
2477  'table' => $table.'_children',
2478  'where' => 'page_id='.$this->field['id']
2479  ));
2480  $children = array_unique($children); // Keine Seite mehrmals derselben Seite unterordnen.
2481  $idx = 0;
2482  foreach ($children as $child) {
2483  if ($child) { // Keine leeren Einträge.
2484  if (in_array($child, $ancestors)) { // Keine Endlosschleifen.
2485  egotec_error_log('infinite loop prevention at children: '.$this->_site->pageTable.' '.$this->field['id'].','.$child);
2486  } else {
2487  $db->insert(array(
2488  'table' => $table.'_children',
2489  'set' => array('page_id' => $this->field['id'], 'idx' => $idx, 'child' => $child)
2490  ));
2491  $idx++;
2492  }
2493  }
2494  }
2495  $db->commit();
2496 
2497  $this->_updateCloneChildren();
2498 
2499  $this->_clearCache();
2500  }
2501 
2507  protected function _updateParents($parents) {
2508  if (empty($parents)) {
2509  egotec_error_log('empty parents: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id']);
2510  return;
2511  }
2512  $current_parents = array();
2513  $db = new_db_connection(array(
2514  'table' => $this->_site->pageTable . '_children',
2515  'where' => 'child = :child',
2516  'bind' => array(
2517  'child' => $this->field['id']
2518  )
2519  ));
2520  while ($db->nextRecord()) {
2521  $current_parents[] = $db->Record['page_id'];
2522  }
2523  $num_parents = 0;
2524  $remove_parents = array();
2525  foreach ($current_parents as $current_parent) {
2526  $key = array_search($current_parent, $parents);
2527  if ($key!==false) { // Vorhandene Eltern in Ruhe lassen.
2528  unset($parents[$key]);
2529  $num_parents++;
2530  } else { // Nicht mehr vorhandene Eltern löschen.
2531  $remove_parents[] = $current_parent;
2532  }
2533  }
2534  foreach ($parents as $parent_id) { // Neue Eltern hinzufügen.
2535  if ($parent_id) {
2536  if ($parent_id!=$this->field['id']) {// Keine Endlosschleife erzeugen!
2537  if ($this->_addParent($parent_id)) {
2538  $num_parents++;
2539  }
2540  } else {
2541  egotec_error_log('infinite loop prevention at parents: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id'].','.$parent_id);
2542  }
2543  }
2544  }
2545  if ($num_parents == 0) {
2546  egotec_error_log('empty parents 2: '.print_r($parents, true).' / '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id']);
2547  return;
2548  } else {
2549  // Eltern erst löschen, wenn es noch mindestens eine Elternseite gibt
2550  foreach ($remove_parents as $remove_parent) {
2551  $this->_removeParent($remove_parent);
2552  }
2553  }
2554  }
2555 
2561  private function _removeParent($parent_id) {
2562  $db = new_db_connection();
2563  $db->delete([
2564  'table' => $this->_site->pageTable.'_children',
2565  'where' => 'page_id = '.$parent_id.' AND child = '.$this->field['id']
2566  ]);
2567  $this->_site->clearCache();
2568 
2569  $parent = $this->_site->getPage($parent_id);
2570 
2571  if (isset($parent) && isset($this->extra['main_category']) && $this->extra['main_category'] == $parent->field['id']) {
2572  // Elternseite aus main_category dieser Seite entfernen
2573  unset($this->extra['main_category']);
2574  $this->update([], true, true);
2575  }
2576 
2577  // Wenn Parent ein Schlagwort ist, dann löschen wenn:
2578  // -> der Mandant des Klones die Checkbox "Neues Schlagwortregister verwenden" gesetzt hat
2579  // -> der verwendete Schlagwortregister nicht der Mandant des Klon Originals ist
2580  // -> das Schlagwort nicht mehr verwendet wird
2581  if ($parent && $parent->field['type'] == '_keywords/entry' && $parent->isClone()
2582  && $this->_site->admin['keyword_register_own_site'] && $parent->getCloneOriginal()->getSite()->name != $this->_site->admin['keywords']['site']
2583  && !$parent->hasChildren()) {
2584  $this->_deleteCloneKeywords($this, $parent);
2585  } elseif ($parent && $parent->extra['clones'] && !$this->isReleaseCopy() && !$this->isWorkflowCopy()) {
2586  // Elternseite existiert als Klon und hat geklonte Unterseiten
2587  $clones = explode(',', $parent->extra['clones']);
2588  foreach ($clones as $clone_url) {
2589  $parent_clone = Ego_System::urltopage(
2590  $clone_url,
2591  [
2592  'params' => [
2593  'param' => [
2594  'auth_or' => '1=1',
2595  'deleted_or' => '1=1',
2596  'inactive' => true,
2597  'only_active' => false
2598  ]
2599  ]
2600  ]
2601  );
2602 
2603  // Prüfen ob geklonte Unterseiten oder deren Schlagwort Parents gelöscht werden sollen
2604  if ($parent_clone && ($parent->extra['clone_children_' . $clone_url] || $parent_clone->field['type'] == '_keywords/entry')) {
2605  foreach ($parent_clone->getChildren([], [
2606  'auth_or' => '1=1',
2607  'deleted_or' => '1=1',
2608  'inactive' => true,
2609  'only_active' => false
2610  ]) as $clone) {
2611  if (in_array($clone->getCloneUrl(), explode(',', $this->extra['clones']))) {
2612  // Wenn der Klon mehrere Parents hat, dann nur Parent aushängen statt komplett zu löschen
2613  if ($clone->hasMultiParents()) {
2614  $clone->delParent($parent_clone->field['id']);
2615 
2616  // Wenn Parent ein Schlagwort ist, dann löschen wenn:
2617  // -> der Mandant des Klones die Checkbox "Neues Schlagwortregister verwenden" gesetzt hat
2618  // -> der verwendete Schlagwortregister nicht der Mandant des Klon Originals ist
2619  // -> das Schlagwort nicht mehr verwendet wird
2620  if ($parent_clone->field['type'] == '_keywords/entry' && !$parent_clone->hasChildren()
2621  && $clone->getSite()->admin['keyword_register_own_site']
2622  && $parent_clone->getCloneOriginal()->getSite()->name != $clone->getSite()->admin['keywords']['site']) {
2623  $this->_deleteCloneKeywords($clone, $parent_clone);
2624  }
2625  } else {
2626  $clone->destroyClone();
2627  }
2628  }
2629  }
2630  }
2631  }
2632  }
2633  }
2634 
2640  private function _addParent($parent_id) {
2641  if ($this->field['id']==$parent_id) { // Eine Endlosschleife vermeiden.
2642  egotec_error_log('infinite loop prevention: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id'].','.$parent_id);
2643  return false;
2644  }
2645  $parent = $this->_site->getPage($parent_id, [
2646  'inactive' => true,
2647  'only_active' => false
2648  ]);
2649  if (!$parent) {
2650  return false;
2651  }
2652  $ancestors = $this->_getAncestorsIds(
2653  $parent,
2654  array('fields' => 'id'),
2655  array('auth_or' => '1=1')
2656  );
2657  if (in_array($this->field['id'], $ancestors)) { // Eine Endlosschleife vermeiden.
2658  return false;
2659  }
2660  if ($this->hasParent($parent_id)) { // Keine Seite mehrmals derselben Seite unterordnen.
2661  egotec_error_log('infinite loop prevention: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id'].','.$parent_id);
2662  return false;
2663  }
2664  $db = new_db_connection();
2665  $db->select([ // höchsten Index der Kinder abfragen.
2666  'fields' => 'idx',
2667  'table' => $this->_site->pageTable . '_children',
2668  'where' => "page_id=" . $parent_id,
2669  'order' => 'idx DESC',
2670  'limit' => 1
2671  ]);
2672  $idx = $db->nextRecord() ? $db->Record['idx'] + 1 : 0;
2673  $db->replace([
2674  'table' => $this->_site->pageTable . '_children',
2675  'set' => ['page_id' => $parent_id, 'idx' => $idx, 'child' => $this->field['id']],
2676  'primary' => ['page_id', 'idx']
2677  ]);
2678 
2679  // Schlagwörter Parents aktualisieren/hinzufügen wenn das Original bearbeitet wird
2680  if ($parent && $parent->field['type'] == '_keywords/entry' && !$this->isClone()) {
2681  $my_clones = $this->getClones();
2682 
2683  foreach ($my_clones as $my_clone) {
2684  $this->_updateCloneKeywords($this, $my_clone);
2685  }
2686  } elseif ($parent && $parent->extra['clones'] && !$this->isReleaseCopy() && !$this->isWorkflowCopy()) {
2687  // Elternseite existiert als Klon und Unterseiten sollen ebenfalls geklont werden
2688  $clones = explode(',', $parent->extra['clones']);
2689  foreach ($clones as $clone_url) {
2690  $clone = Ego_System::urltopage(
2691  $clone_url,
2692  array(
2693  'params' => array(
2694  'param' => array(
2695  'auth_or' => '1=1',
2696  'deleted_or' => '1=1',
2697  'inactive' => true,
2698  'only_active' => false
2699  )
2700  )
2701  )
2702  );
2703 
2704  // Prüfen ob Unterseiten geklont werden sollen
2705  if ($clone && $clone->isClone() && $parent->extra['clone_children_' . $clone_url]) {
2706  // Wenn die Unterseite bereits geklont ist, dann Parent hinzufügen
2707  $_clones = $this->getClones();
2708  foreach ($_clones as $_clone) {
2709  if (
2710  $_clone->getSite()->name == $clone->getSite()->name
2711  && !$_clone->hasParent($clone->field['id'])
2712  ) {
2713  $_clone->addParent($clone->field['id']);
2714  continue 2;
2715  }
2716  }
2717 
2718  $clone->createClone(
2719  $this,
2720  true,
2721  $parent->extra['clone_rights_' . $clone_url],
2722  $parent->extra['clone_release_' . $clone_url]
2723  );
2724  }
2725  }
2726  }
2727 
2728  return true;
2729  }
2730 
2737  private function _clearCache($complete = false) {
2738  if ($this->archiveOnly) {
2739  // Cache nicht löschen, wenn es sich um eine Zwischenspeicherung handelt
2740  return;
2741  }
2742 
2743  $this->_site->clearCache(!$complete && $this->field['type'] == 'multimedia/image' ? $this->field['id'] : 0);
2744 
2745  // Die Cache aller verweisenden Seiten anderer Mandanten ebenfalls löschen
2746  $cleared = array();
2747  foreach ($this->getLinkedPages() as $link) {
2748  foreach ($link['sources'] as $site_name => $source) {
2749  if ($site_name != $this->_site->name && !in_array($site_name, $cleared)) {
2750  $cleared[] = $site_name;
2751  try {
2752  $site = new Site($site_name);
2753  Ego_Queue::add(array($site, 'clearCache'));
2754  } catch (Site_Exception $e) {
2755  // ignorieren
2756  }
2757  }
2758  }
2759  }
2760  }
2761 
2771  protected function _updateClones(&$param) {
2772  if ($this->isReleaseCopy() || $this->isWorkflowCopy()) {
2773  return;
2774  }
2775  if ($param['extra']['clones'] || $this->extra['clones']) { // wenn ich Klone hab oder hatte
2776  $this_page_url = $this->getCloneUrl();
2777 
2778  if (isset($param['extra'])) {
2779  $folders = explode(',', $param['extra']['clones']);
2780  $param['extra']['clones'] = '';
2781  $old_clones = array_filter(array_unique(explode(',', $this->extra['clones'])));
2782 
2783  // wenn welche aus der liste entfernt wurden, löschen
2784  foreach ($old_clones as $old_c) {
2785  if ($old_c == '') continue;
2786 
2787  if (!in_array($old_c, $folders)) {
2788  $clone = Ego_System::urltopage($old_c, array('params' => array('param' => array(
2789  'auth_or' => '1=1',
2790  'deleted_or' => '1=1',
2791  'inactive' => true,
2792  'only_active' => false
2793  ))));
2794  if ($clone) {
2795  // Klon entfernen
2796  $clone->delete();
2797  }
2798  unset($param['extra']['clone_children_' . $old_c], $param['extra']['clone_rights_' . $old_c], $param['extra']['clone_release_' . $old_c]);
2799  }
2800  }
2801  } elseif (isset($this->extra['clones'])) {
2802  // Wenn extra nicht übergeben wird, dann mit dem aktuellen extra weitermachen
2803  $folders = array_filter(array_unique(explode(',', $this->extra['clones'])));
2804  } else {
2805  return;
2806  }
2807 
2808  // Sicherstellen, dass immer alle Daten vorhanden sind
2809  $param['field'] = $param['field'] ? $param['field'] : $this->field;
2810  $param['extra'] = $param['extra'] ? $param['extra'] : $this->extra;
2811 
2812  // Aktualisieren
2813  foreach ($folders as $f) {
2814  if (!$f) continue; // Leere überspringen
2815  $remove_parent = false;
2816 
2817  // Eltern holen
2818  $f_url = $f;
2819  $clone = Ego_System::urltopage($f, array('params' => array('param' => array(
2820  'auth_or' => '1=1',
2821  'deleted_or' => '1=1',
2822  'inactive' => true,
2823  'only_active' => false
2824  ))));
2825 
2826  if (!$clone) {
2827  // Wenn der Klon nicht existiert, wird er dennoch beibehalten
2828  $clones = array_filter(explode(',', $param['extra']['clones']));
2829  $param['extra']['clones'] = implode(',', array_unique(array_merge($clones, array($f))));
2830  continue;
2831  }
2832 
2833  $p = array(
2834  'field' => $param['field'],
2835  'extra' => $param['extra']
2836  );
2837  $p['extra']['clone_original'] = $this_page_url;
2838  unset($p['field']['id']);
2839  unset($p['field']['parents']);
2840  unset($p['field']['url']);
2841  unset($p['extra']['clones']);
2842 
2843  foreach ($p['extra'] as $key => $value) {
2844  if (
2845  strpos($key, 'clone_children_') === 0
2846  || strpos($key, 'clone_rights_') === 0
2847  || strpos($key, 'clone_release_') === 0
2848  ) {
2849  unset($p['extra'][$key]);
2850  }
2851  }
2852 
2853  if (isset($p['extra']['main_category'])) {
2854  $main_category = $this->_site->getPage($p['extra']['main_category'], [
2855  'auth_or' => '1=1',
2856  'deleted_or' => '1=1',
2857  'inactive' => true,
2858  'only_active' => false
2859  ]);
2860 
2861  unset($p['extra']['main_category']);
2862 
2863  if ($main_category) {
2864  $main_category_clones = $main_category->getClones();
2865  $clone_parents = $clone->getParents([
2866  'auth_or' => '1=1',
2867  'deleted_or' => '1=1',
2868  'inactive' => true,
2869  'only_active' => false
2870  ]);
2871 
2872  foreach ($main_category_clones as $main_category_clone) {
2873  foreach ($clone_parents as $clone_parent) {
2874  if ($clone_parent->getIdentity() == $main_category_clone->getIdentity()) {
2875  $p['extra']['main_category'] = $clone_parent->field['id'];
2876  break 2;
2877  }
2878  }
2879  }
2880  }
2881  }
2882 
2883  if ($clone->isClone()) {
2884  if (isset($clone->conf['edit_clone'])) {
2885  // Nicht die Felder ändern, die bereits existieren und einen anderen Wert als den ursprünglichen haben
2886  $combined_p = array();
2887  foreach ($p as $field => $values) {
2888  $combined_p[$field] = $values;
2889  if (is_array($values) && isset($clone->conf['edit_clone'][$field])) {
2890  $clone_edit = explode(',', $clone->conf['edit_clone'][$field]);
2891  foreach ($clone_edit as $edit_key) {
2892  $value = Ego_System::getAssocValue($this->{$field}, $edit_key);
2893  if (
2894  ($clone_value = Ego_System::getAssocValue($clone->{$field}, $edit_key)) !== null
2895  && $clone_value != $value
2896  ) {
2897  // Wert beibehalten
2898  $value = $clone_value;
2899  }
2900  Ego_System::setAssocValue($combined_p[$field], $edit_key, $value);
2901  }
2902  }
2903  }
2904  } else {
2905  // Alle Felder ändern
2906  $combined_p = $p;
2907  }
2908 
2909  // Bei Freigabeklonen wird Freigabe ab und bis nicht mit denen vom Original überschrieben
2910  $clone_page_url = $clone->getCloneUrl();
2911  if ($param['extra']['clone_release_' . $clone_page_url]) {
2912  unset($combined_p['field']['release_from'], $combined_p['field']['release_until']);
2913  }
2914 
2915  $clone->update($combined_p);
2916  } else { // es muss ein Klon erzeugt werden
2917  $clone = $clone->newChild($p['field'], $p['extra']);
2918 
2919  if (!$clone) {
2920  continue;
2921  }
2922  $remove_parent = true;
2923  }
2924 
2925  // Original des Klones holen um Schlagwörter zu klonen
2926  $original = $clone->getCloneOriginal();
2927 
2928  // Schlagwörter Parents aktualisieren/hinzufügen
2929  if ($original) {
2930  $this->_updateCloneKeywords($original, $clone);
2931  }
2932 
2933  // Mediapool kopieren
2934  $this->getMediapool()->copy($clone);
2935 
2936  // Klon merken
2937  $clone_page_url = $clone->getCloneUrl();
2938  $clones = array_filter(explode(',', $param['extra']['clones']));
2939  $param['extra']['clones'] = implode(',', array_unique(array_merge($clones, array($clone_page_url))));
2940 
2941  /* Übergebene Informationen verweisen auf die Elternseite des neuen Klons,
2942  * diese verwerfen
2943  */
2944  if ($remove_parent)
2945  {
2946  $param['extra']['clone_children_' . $clone_page_url] = $param['extra']['clone_children_' . $f_url];
2947  $param['extra']['clone_rights_' . $clone_page_url] = $param['extra']['clone_rights_' . $f_url];
2948  $param['extra']['clone_release_' . $clone_page_url] = $param['extra']['clone_release_' . $f_url];
2949 
2950  unset($param['extra']['clone_children_' . $f_url], $param['extra']['clone_rights_' . $f_url], $param['extra']['clone_release_' . $f_url]);
2951 
2952  // Eingetragene Freigabe ab/bis Daten ändern
2953  if ($param['extra']['clone_release_' . $clone_page_url]) {
2954  $param['extra']['clone_release_from_' . $clone_page_url] = $param['extra']['clone_release_from_' . $f_url];
2955  $param['extra']['clone_release_until_' . $clone_page_url] = $param['extra']['clone_release_until_' . $f_url];
2956 
2957  unset($param['extra']['clone_release_from_' . $f_url], $param['extra']['clone_release_until_' . $f_url]);
2958  }
2959  }
2960 
2961  // Die eingetragenen Freigabe ab/bis Daten verwenden
2962  if ($param['extra']['clone_release_'.$clone_page_url]) {
2963  $clone_release = array();
2964 
2965  if ($param['extra']['clone_release_from_' . $clone_page_url]) {
2966  $clone_release['release_from'] = $param['extra']['clone_release_from_' . $clone_page_url];
2967  } else {
2968  $clone_release['release_from'] = '0000-00-00 00:00:00';
2969  }
2970 
2971  if ($param['extra']['clone_release_until_' . $clone_page_url]) {
2972  $clone_release['release_until'] = $param['extra']['clone_release_until_' . $clone_page_url];
2973  } else {
2974  $clone_release['release_until'] = '0000-00-00 00:00:00';
2975  }
2976 
2977  if (!empty($clone_release)) {
2978  $clone->updateField($clone_release);
2979  }
2980  }
2981 
2982  // Informationen zu Freigabe ab/bis des Klons nicht merken
2983  unset(
2984  $param['extra']['clone_release_from_' . $clone_page_url],
2985  $param['extra']['clone_release_until_' . $clone_page_url]
2986  );
2987 
2988  // Prüfen ob an Klonen mit Unterseiten etwas geändert worden ist
2989  if (
2990  $param['extra']['clone_children_'.$clone_page_url] != $this->extra['clone_children_'.$clone_page_url]
2991  || $param['extra']['_update_child_clones'] // Klon Unterseiten in jeden Fall aktualisieren
2992  )
2993  {
2994  unset($param['extra']['_update_child_clones']);
2995  if ($param['extra']['clone_children_'.$clone_page_url] == 1)
2996  {
2997  // Klon Kinder für diesen Klon erstellen
2998  $this->_createChildClones($clone);
2999  }
3000  else
3001  {
3002  // Klon Kinder dieses Klons entfernen
3003  $this->_destroyChildClones($clone);
3004  }
3005  }
3006  }
3007  } elseif ($this->isClone()) {
3008  // Ist diese Seite ein Klon und funktioniert als Verknüpfung, dann das Original auch speichern
3009  $type_info = $this->getTypeInfo();
3010  if (
3011  $type_info['clone_link']
3012  && ($page = Ego_System::urltopage($this->extra['clone_original'], array('params' => array('param' => array(
3013  'auth_or' => '1=1',
3014  'deleted_or' => '1=1',
3015  'inactive' => true,
3016  'only_active' => false
3017  )))))
3018  ) {
3019  $p = array(
3020  'field' => $param['field'],
3021  'extra' => $param['extra']
3022  );
3023  $p['extra']['clones'] = $page->extra['clones'];
3024  foreach ($page->extra as $key => $value) {
3025  if (
3026  strpos($key, 'clone_children_') === 0
3027  || strpos($key, 'clone_rights_') === 0
3028  || strpos($key, 'clone_release_') === 0
3029  ) {
3030  $p['extra'][$key] = $value;
3031  }
3032  }
3033  unset($p['field']['id']);
3034  unset($p['field']['parents']);
3035  unset($p['field']['url']);
3036  unset($p['extra']['clone_original']);
3037  $page->update($p);
3038 
3039  // Mediapool kopieren
3040  $this->getMediapool()->copy($page);
3041  }
3042  }
3043  }
3044 
3050  public function getClones($target_site = 'all') {
3051  $clones = [];
3052  $clone_array = array_filter(array_unique(explode(',', $this->extra['clones'])));
3053  foreach ($clone_array as $clone_index) {
3054  if ($clone_index == '') continue;
3055  $clone = Ego_System::urltopage($clone_index, array('params' => array('param' => array(
3056  'auth_or' => '1=1',
3057  'deleted_or' => '1=1',
3058  'inactive' => true,
3059  'only_active' => false
3060  ))));
3061  if (($clone && $target_site == 'all') || ($clone && $target_site != 'all' && $target_site == $clone->getSite()->name)) {
3062  $clones[] = $clone;
3063  }
3064  }
3065  return $clones;
3066  }
3067 
3079  public function createClone($page, $children = false, $rights = false, $release = false, $multiple = true) {
3080  $_REQUEST['var']['reload_dlg'] = true; // Wird die Methode in einem Action Hook aufgerufen, muss das dlg neu geladen werden
3081  return $this->_createClone($page, $children, $rights, $release, $multiple);
3082  }
3083 
3094  protected function _createClone($page, $children = false, $rights = false, $release = false, $multiple = true) {
3095  $clone_url = $page->getCloneUrl();
3096 
3097  if (!$multiple) {
3098  // Prüfen, ob es diesen Klon bereits gibt
3099  $children2 = $this->getChildren(array(), array(
3100  'auth_or' => '1=1',
3101  'inactive' => true,
3102  'only_active' => false
3103  ));
3104  foreach ($children2 as $child) {
3105  if ($child->extra['clone_original'] == $clone_url) {
3106  return $child;
3107  }
3108  }
3109  }
3110 
3111  // Neuen Klon erstellen
3112  $p = array(
3113  'field' => $page->field,
3114  'extra' => $page->extra
3115  );
3116  $p['extra']['clone_original'] = $clone_url;
3117  unset($p['field']['id']);
3118  unset($p['field']['parents']);
3119  unset($p['field']['url']);
3120  unset($p['extra']['clones']);
3121 
3122  $clone = $this->newChild($p['field'], $p['extra']);
3123 
3124  // Neuen Klon auf dieser Seite eintragen
3125  $extra = $page->extra;
3126 
3127  $clones = array_filter(explode(',', $extra['clones']));
3128  $clone_page_url = $clone->getCloneUrl();
3129 
3130  $extra['clones'] = implode(',', array_unique(array_merge($clones, array($clone_page_url))));
3131  if ($children) {
3132  $extra['clone_children_' . $clone_page_url] = 1;
3133  }
3134  if ($rights) {
3135  $extra['clone_rights_' . $clone_page_url] = 1;
3136  }
3137  if ($release) {
3138  $extra['clone_release_' . $clone_page_url] = 1;
3139  }
3140 
3141  /* Die Klon Einstellungen müssen bereits jetzt in der Datenbank bekannt sein, damit Unterseiten,
3142  * die ebenfalls geklont werden, beim Ermitteln der Klone Elternseite die Klone auch finden können.
3143  * Nur so kann z.B. die "main_category" für den Klon angepasst werden.
3144  * Dabei auch keine "asis" Archive anlegen. */
3145  $page->updateExtra($extra, true, true, true);
3146 
3147  // Nicht für Schlagwörter, da dies geklonte Schlagwörter unter der jeweiligen Seite löschen würde
3148  if (strpos($page->field['type'], '_keywords/') !== 0) {
3149  $page->extra['_update_child_clones'] = true; // Klon Unterseiten in jeden Fall aktualisieren
3150  }
3151  $page->update();
3152 
3153  $this->_updateCloneKeywords($page, $clone);
3154 
3155  return $clone;
3156  }
3157 
3163  protected function _updateCloneRights() {
3164  if (isset($this->extra['clones']) && !$this->isClone()) {
3165  foreach (explode(',', $this->extra['clones']) as $clone_url) {
3166  if (!empty($this->extra['clone_rights_'.$clone_url])) {
3167  $clone = Ego_System::urltopage($clone_url, array('params' => array('param' => array(
3168  'auth_or' => '1=1',
3169  'inactive' => true,
3170  'only_active' => false
3171  ))));
3172  if ($clone) {
3173  $clone->setRightsArray($this->getRightsArray());
3174  $clone->setUsersArray($this->getUsersArray());
3175  }
3176  }
3177  }
3178  }
3179  }
3180 
3186  protected function _updateCloneChildren() {
3187  if ($this->field['children_order'] == 'children' && isset($this->extra['clones']) && !$this->isClone()) {
3188  foreach (explode(',', $this->extra['clones']) as $clone_url) {
3189  if ($this->extra['clone_children_'.$clone_url]) {
3190  $clone = Ego_System::urltopage($clone_url, array('params' => array('param' => array(
3191  'auth_or' => '1=1',
3192  'inactive' => true,
3193  'only_active' => false
3194  ))));
3195  if ($clone) {
3196  $clone_children = [];
3197  $children = $this->getChildren([], [
3198  'auth_or' => '1=1',
3199  'inactive' => true,
3200  'only_active' => false
3201  ]);
3202 
3203  foreach ($children as $child) {
3204  if (!empty($child->extra['clones'])) {
3205  foreach (explode(',', $child->extra['clones']) as $clone_child_url) {
3206  $clone_child = Ego_System::urltopage($clone_child_url, ['params' => ['param' => [
3207  'auth_or' => '1=1',
3208  'inactive' => true,
3209  'only_active' => false
3210  ]]]);
3211  if ($clone_child) {
3212  $clone_child_parents = $clone_child->getParents([], [
3213  'auth_or' => '1=1',
3214  'inactive' => true,
3215  'only_active' => false
3216  ]);
3217  foreach ($clone_child_parents as $clone_child_parent) {
3218  if ($clone_child_parent->getIdentity() == $clone->getIdentity()) {
3219  $clone_children[] = $clone_child->field['id'];
3220  break;
3221  }
3222  }
3223  }
3224  }
3225  }
3226  }
3227 
3228  if (!empty($clone_children)) {
3229  $clone->updateChildren($clone_children);
3230  }
3231  }
3232  }
3233  }
3234  }
3235  }
3236 
3242  protected function _createChildClones($parent) {
3243  // Kinder dieser Seite
3244  $children = $this->getChildren(array(), array(
3245  'auth_or' => '1=1',
3246  'inactive' => true,
3247  'only_active' => false
3248  ));
3249 
3250  foreach($children as $child) {
3251  // Klone des Kindes prüfen ob bereits der Zielparent (im gleichen Mandanten) gesetzt ist
3252  // Wenn nicht, dann Parent hinzufügen
3253  $clones = $child->getClones();
3254 
3255  foreach ($clones as $clone) {
3256  if (
3257  $clone->getSite()->name == $parent->getSite()->name
3258  && !$clone->hasParent($parent->field['id'])
3259  ) {
3260  $clone->addParent($parent->field['id']);
3261  continue 2;
3262  }
3263  }
3264 
3265  // Klon nur anlegen falls es noch nicht existiert
3266  $clone_child = $parent->getChildren(
3267  array(
3268  'where' => 'name=:n AND a_date=:a',
3269  'bind' => array(
3270  'n' => $child->field['name'],
3271  'a' => $child->field['a_date']
3272  )
3273  ),
3274  array(
3275  'inactive' => true
3276  )
3277  );
3278 
3279  if (!$clone_child->numRecords()) {
3280  $parent->createClone(
3281  $child,
3282  true,
3283  !!$this->extra['clone_rights_'.$parent->getCloneUrl()],
3284  !!$this->extra['clone_release_'.$parent->getCloneUrl()]
3285  );
3286  }
3287  }
3288  }
3289 
3296  protected function _updateCloneKeywords($original, $clone) {
3297  if ($clone->field['type'] != '_keywords/entry') {
3298  $keywords = $original->getParents(['where' => "type = '_keywords/entry'"]);
3299 
3300  if ($keywords) {
3301  foreach ($keywords as $keyword) {
3302  $clones_keyword = $keyword->getClones($clone->getSite()->name);
3303  // Wenn kein Klon von diesem Schlagwort auf dem Ziel Mandanten existiert und dieser das neue Schlagwortregistermodul verwendet
3304  if ($clone->getSite()->admin['keyword_register_own_site'] && empty($clones_keyword)) {
3305  $keyword_list = $clone->getSite()->getPages(['where' => "type = '_keywords/list'"])->nextPage(); // Schlagwortregister auf dem Ziel Mandanten
3306 
3307  $createCloneKeywords = function($keyword_list, $keyword, $siteName) {
3308  if (empty($keyword->getClones($siteName))) {
3309  $current_keyword = $keyword; // derzeitiges Schlagwort
3310  $parent_keywords = []; // Schlagwort Parents
3311 
3312  // alle Schlagwort Parents durchgehen
3313  while ($current_keyword = $current_keyword->getParents(['where' => "type = '_keywords/entry'"])->nextPage()) {
3314  array_unshift($parent_keywords, $current_keyword);
3315  }
3316 
3317  // wenn Schlagwort Parents existieren
3318  if (!empty($parent_keywords)) {
3319  foreach ($parent_keywords as $key => $parent_keyword) {
3320  // Wenn noch kein Klon auf dem Mandanten existiert, dann lege diesen an
3321  if (!$parent_keyword->getClones($siteName)) {
3322  if ($key == 0) {
3323  // Schlagwort unter Schlagwortregister klonen
3324  $current_keyword = $keyword_list->createClone($parent_keyword);
3325  } else {
3326  // Schlagwort unter Parents klonen
3327  $current_keyword = $current_keyword->createClone($parent_keyword);
3328  }
3329  } else {
3330  // Wenn bereits ein Klon auf dem Mandanten existiert, dann verwende diesen als $current_keyword weiter
3331  $current_keyword = $parent_keyword->getClones($siteName)[0];
3332  }
3333  }
3334 
3335  // Schlagwort unter Parents klonen
3336  $current_keyword->createClone($keyword);
3337  } else {
3338  // Schlagwort unter Schlagwortregister klonen
3339  $keyword_list->createClone($keyword);
3340  }
3341  }
3342  };
3343 
3344  // Führe es einmal für den Zielmandanten aus damit diese Schlagwörter dem Klon hinzugefügt werden können
3345  $createCloneKeywords($keyword_list, $keyword, $keyword_list->getSite()->name);
3346 
3347  // Dann nochmal für das Original und eventuelle weitere Klone
3348  if ($keyword_list->isClone()) {
3349  $original_keyword_list = $keyword_list->getCloneOriginal();
3350 
3351  $createCloneKeywords($original_keyword_list, $keyword, $original_keyword_list->getSite()->name);
3352 
3353  foreach ($original_keyword_list->getClones() as $keyword_list_clone) {
3354  if ($keyword_list->getSite()->name != $keyword_list_clone->getSite()->name) {
3355  $createCloneKeywords($keyword_list_clone, $keyword, $keyword_list_clone->getSite()->name);
3356  }
3357  }
3358  }
3359 
3360  $clones_keyword = $keyword->getClones($clone->getSite()->name);
3361  }
3362 
3363  if ($clones_keyword) {
3364  // Schlagwörter Klone durchgehen und ggf. als Parent hinzufügen
3365  foreach ($clones_keyword as $clone_keyword) {
3366  if (!$clone->hasParent($clone_keyword->field['id'])) {
3367  $clone->addParent($clone_keyword->field['id']);
3368  }
3369  }
3370  }
3371  }
3372  }
3373  }
3374  }
3375 
3381  protected function _deleteCloneKeywords($clone_check, $clone_to_delete) {
3382  $current_keyword = $clone_to_delete;
3383  $parent_keywords = [];
3384 
3385  while ($current_keyword = $current_keyword->getParents(['where' => "type = '_keywords/entry'"])->nextPage()) {
3386  $parent_keywords[] = $current_keyword;
3387  }
3388 
3389  $clone_to_delete->destroyClone();
3390 
3391  if (!empty($parent_keywords)) {
3392  foreach ($parent_keywords as $parent_keyword) {
3393  // Wenn Parent ein Schlagwort ist, dann löschen wenn:
3394  // -> der Mandant des Klones die Checkbox "Neues Schlagwortregister verwenden" gesetzt hat
3395  // -> der verwendete Schlagwortregister nicht der Mandant des Klon Originals ist
3396  // -> das Schlagwort nicht mehr verwendet wird
3397  if ($parent_keyword->field['type'] == '_keywords/entry' && !$parent_keyword->hasChildren()
3398  && $clone_check->getSite()->admin['keyword_register_own_site']
3399  && $parent_keyword->getCloneOriginal()->getSite()->name != $clone_check->getSite()->admin['keywords']['site']) {
3400  $parent_keyword->destroyClone();
3401  }
3402  }
3403  }
3404  }
3405 
3411  protected function _destroyChildClones($parent) {
3412  // Kinder dieser Seite
3413  $children = $this->getChildren(array(), array(
3414  'auth_or' => '1=1',
3415  'inactive' => true,
3416  'only_active' => false
3417  ));
3418 
3419  foreach($children as $child) {
3420  // Klon nur entfernen falls es existiert
3421  $clone_child = $parent->getChildren(
3422  array(
3423  'where' => 'name=:n AND a_date=:a',
3424  'bind' => array(
3425  'n' => $child->field['name'],
3426  'a' => $child->field['a_date']
3427  )
3428  ),
3429  array(
3430  'inactive' => true
3431  )
3432  );
3433 
3434  if ($clone = $clone_child->nextPage()) { // Klon entfernen
3435  $clone->destroyClone();
3436  }
3437  }
3438  }
3439 
3445  public function destroyClone() {
3446  $_REQUEST['var']['reload_dlg'] = true; // Wird die Methode in einem Action Hook aufgerufen, muss das dlg neu geladen werden
3447  return $this->_destroyClone();
3448  }
3449 
3455  protected function _destroyClone() {
3456  $page = $this->getCloneOriginal();
3457  if (!$page) {
3458  return false;
3459  }
3460  $extra = $page->extra;
3461  $clones = explode(',', $extra['clones']);
3462  $clone_page_url = $this->getCloneUrl();
3463  if (!in_array($clone_page_url, $clones)) {
3464  return false;
3465  }
3466 
3467  $new_clones = array();
3468  foreach($clones as $c) {
3469  if ($c != $clone_page_url) {
3470  $new_clones[] = $c;
3471  }
3472  }
3473 
3474  $extra['clones'] = implode(',', array_filter(array_unique($new_clones)));
3475  unset($extra['clone_children_' . $clone_page_url], $extra['clone_release_' . $clone_page_url]);
3476 
3477  $page->updateExtra($extra);
3478  $this->delete();
3479 
3480  return true;
3481  }
3482 
3492  protected function _updateRights($rights, $asis = false) {
3493  $db = new_db_connection();
3494  if ($rights['_delete']) {
3495  $delete_query_where = ' AND perm in (\''.join('\',\'', $rights['_delete']).'\')';
3496  unset($rights['_delete']);
3497  }
3498  $rights['rights'] = array_merge($this->getRightsArray(),$rights['rights']);
3499  if ($rights['rights']) { // Gruppen und Rollen.
3500  $db->delete(array( // Alte Einträge löschen.
3501  'from' => $this->_site->pageTable.'_rights',
3502  'where' => 'page_id='.$this->field['id'].$delete_query_where
3503  ));
3504  foreach ($rights['rights'] as $right => $groups) {
3505  $is_null = true; // Zunächst von keiner Beschränkung ausgehen.
3506  foreach ($groups as $group) {
3507  if (!$group['group_id'] || !$group['role_id']) {
3508  if ($rights['users'] && $rights['users'][$right] && count($rights['users'][$right]) != 0) {
3509  // es sind user vorhanden aber keine Group/Role Kombination
3510  $group['group_id'] = $GLOBALS['egotec_conf']['superuser']['group'];
3511  $group['role_id'] = $GLOBALS['egotec_conf']['superuser']['role'];
3512  }
3513  }
3514 
3515  if ($group['group_id'] && $group['role_id']) { // Keine leeren Einträge setzen.
3516  $db->replace(array(
3517  'table' => $this->_site->pageTable.'_rights',
3518  'set' => array(
3519  'page_id' => $this->field['id'],
3520  'perm' => $right,
3521  'group_id' => $group['group_id'],
3522  'role_id' => $group['role_id']
3523  ),
3524  'primary' => array('page_id', 'perm', 'group_id', 'role_id')
3525  ));
3526  $is_null = false; // Es wurde eine Beschränkung gesetzt.
3527  }
3528  }
3529  if ($is_null && strpos(Auth::NO_NULL_RIGHTS, ','.$right.',')!==false) { // Bei einem Recht, das nicht per IS NULL abgefragt wird
3530  $db->replace(array(
3531  'table' => $this->_site->pageTable.'_rights',
3532  'set' => array(
3533  'page_id' => $this->field['id'],
3534  'perm' => $right,
3535  'group_id' => '*', // *|* setzen.
3536  'role_id' => '*'
3537  ),
3538  'primary' => array('page_id', 'perm', 'group_id', 'role_id')
3539  ));
3540  }
3541  }
3542  }
3543 
3544  if ($rights['users']) {
3545  // Benutzer.
3546  $db->delete(array( // Alte Einträge löschen.
3547  'from' => $this->_site->pageTable.'_users',
3548  'where' => "page_id=".$this->field['id'].$delete_query_where
3549  ));
3550  foreach ($rights['users'] as $right => $users) {
3551  if (is_array($users)) {
3552  foreach ($users as $user) {
3553  if ($user['user_id']) { // Leere Einträge vermeiden
3554  $db->insert(array(
3555  'table' => $this->_site->pageTable.'_users',
3556  'set' => array(
3557  'page_id' => $this->field['id'],
3558  'perm' => $right,
3559  'user_id' => trim($user['user_id'],"'"),
3560  )
3561  ));
3562  }
3563  }
3564  }
3565  }
3566  }
3567 
3568  // Multimedia Bilder vererben das Ansichtsrecht an alle Bildausschnitte
3569  if ($this->field['type'] == 'multimedia/image') {
3570  $children = $this->getChildren(array(
3571  'where' => "type = 'multimedia/image'"
3572  ), array(
3573  'auth_or' => '1=1',
3574  'inactive' => true,
3575  'only_active' => false
3576  ));
3577  foreach ($children as $child) {
3578  if ($child->extra['crop_image']) {
3579  $child->update(array(
3580  'rights' => array(
3581  'rights' => array(
3582  'view' => $rights['rights']['view'] ? $rights['rights']['view'] : array()
3583  ),
3584  'users' => array(
3585  'view' => $rights['users']['view'] ? $rights['users']['view'] : array()
3586  )
3587  )
3588  ));
3589  }
3590  }
3591  }
3592 
3593  // Die eingetragenen Rechte klonen
3594  if (!$asis) {
3595  $this->_updateCloneRights();
3596  }
3597 
3598  if (!isset($this->field['inactive']) || !$this->field['inactive']) {
3599  $this->_clearCache();
3600  }
3601  }
3602 
3615  protected function _update($param, $matrix_flag = true, $asis = false, $silent = false) {
3616  $language_standard = $this->extra['language_standard'];
3617 
3618  // Automatisch übersetzen
3619  $param = $this->autoTranslate($param, $this->_site->language, !($param['translate_no_diff'] === true));
3620 
3621  if (!$asis) { // @TODO Ist das notwendig?
3622  $this->_updateClones($param);
3623  }
3624 
3625  if (isset($param['extra']) && $param['field'] && (int)$param['extra']['original_id']) { // Workflowkopien sind immer inaktiv;
3626  $param['field']['inactive'] = $this->isReleaseCopy() ? self::RELEASE_FLAG : self::INACTIVE_FLAG;
3627  }
3628  if (isset($param['extra'])) {
3629  $new_extra = array();
3630  if (is_array($param['extra'])) {
3631  $new_extra = Ego_System::cleanTypes($param['extra']);
3632 
3633  $area_password_changed = 0;
3634  if($new_extra['area_pw'] != '') {
3635  $salt = sha1($this->field['id']);
3636  $new_extra['area_password'] = crypt($new_extra['area_pw'], '$6$rounds=5000$' . $salt . '$');
3637  $area_password_changed = 1;
3638  }
3639 
3640  if ($new_extra['area_pw_reset'] == true) {
3641  unset($new_extra['area_pw_reset']);
3642  unset($new_extra['area_password']);
3643  $area_password_changed = 2;
3644  }
3645 
3646  unset($new_extra['area_pw']);
3647 
3648  if ($area_password_changed > 0) {
3649  foreach ($this->getChildren() as $child) {
3650  $child_extra = $child->extra;
3651  switch ($area_password_changed) {
3652  case 1:
3653  $child_extra['area_password'] = $new_extra['area_password'];
3654  break;
3655  case 2:
3656  unset($child_extra['area_password']);
3657  }
3658  $child->updateExtra($child_extra, true, $asis, $silent);
3659  }
3660  }
3661  }
3662 
3663  // Vererbte Blöcke nicht speichern
3664  if (!empty($new_extra['_inherited'])) {
3665  $blocks = $new_extra['_blocks'];
3666  $contents = $new_extra['_contents'];
3667  foreach ($new_extra['_inherited'] as $orient => $checksum) {
3668  if ($blocks[$orient] && $contents[$orient]) {
3669  $checksum_blocks = Ego_System::getChecksum($blocks[$orient]);
3670  $checksum_contents = Ego_System::getChecksum($contents[$orient]);
3671  if ($checksum_blocks == $checksum['blocks'] && $checksum_contents == $checksum['contents']) {
3672  unset($new_extra['_blocks'][$orient], $new_extra['_contents'][$orient]);
3673  }
3674  }
3675  }
3676  }
3677 
3678  unset($new_extra['_inherited']);
3679  if (!$asis) {
3680  unset($new_extra['_asis']);
3681  }
3682  $param['extra'] = $new_extra;
3683  }
3684  if ($param['field'] || $param['extra']) {
3685  // Der Seitentyp wird gewechselt
3686  if (
3687  !empty($param['field']['type'])
3688  && $param['field']['type'] != $this->field['type']
3689  && $this->isFrontendAdmin()
3690  ) {
3691  $this->field['type'] = $param['field']['type'];
3692  $this->_loadConfig();
3693  if (!empty($this->conf['default_layout'])) {
3694  // Das Standard Layout des neuen Seitentyps verwenden
3695  $param['extra'] = isset($param['extra'])
3696  ? $param['extra']
3697  : $this->extra;
3698  $param['extra']['_layout'] = $this->conf['default_layout'];
3699  }
3700  }
3701 
3702  if ($param['field']['children']) {
3703  if (!isset($param['children'])) {
3704  $param['children'] = explode(',', trim($param['field']['children'], ','));
3705  }
3706  unset($param['field']['children']);
3707  }
3708  if ($param['field']['parents']) {
3709  if (!isset($param['parents'])) {
3710  $param['parents'] = explode(',', trim($param['field']['parents'], ','));
3711  }
3712  unset($param['field']['parents']);
3713  }
3714 
3715  if (isset($param['extra'])) {
3716  $param['field']['extra'] = serialize($param['extra']);
3717  }
3718 
3719  $this->_updateField($param['field'], true, $asis, $silent);
3720  }
3721 
3722  // Mediapool Aktionen ausführen
3723  if ($param['pool']) {
3724  // Dateien umbenennen
3725  if (is_array($param['pool']['rename'])) {
3726  foreach ($param['pool']['rename'] as $info) {
3727  if ($info['name'] != $info['new_name']) {
3728  $this->getMediapool()->edit($info['name'], array(
3729  'new_name' => $info['new_name']
3730  ), (string) $info['dir']);
3731  }
3732  }
3733  }
3734  }
3735 
3736  if ($param['children']) {
3737  $this->_updateChildren($param['children'], !($param['merge_children'] === false));
3738  }
3739  if ($param['parents'] && $this->field['id'] != $this->_site->rootId) {
3740  $this->_updateParents($param['parents']);
3741  }
3742 
3743  if ($param['rights']) {
3744  $this->_updateRights($param['rights'], $asis);
3745  }
3746 
3747  // Schlagwörter automatisch hinzufügen
3748  $reload = $this->_updateKeywords($asis);
3749 
3750  if (
3751  !$this->isClone()
3752  && !$this->extra['crop_image'] // Ausschnitte legen keine Archive oder Sprachen an
3753  && !$silent
3754  ) {
3755  // Archiv anlegen
3756  $this->_archiveEntry();
3757 
3758  // Die Inhalte der Standardsprache in die verknüpften Bereiche speichern.
3759  if (
3760  !$this->archiveOnly // Nicht für Zwischenspeicherungen
3761  && !$this->isWorkflowCopy()
3762  && $matrix_flag
3763  && $language_standard == $this->_site->language
3764  && is_array($param['extra']['language_link'])
3765  ) {
3772  $clean_clones = function($extra) {
3773  unset($extra['clones'], $extra['area_domain']);
3774  foreach (array_keys($extra) as $key) {
3775  if (strpos($key, 'clone_') === 0) {
3776  unset($extra[$key]);
3777  }
3778  }
3779  return $extra;
3780  };
3781 
3782  $languages = array();
3783  $site_languages = $this->_site->getLanguages();
3784  foreach ($site_languages as $lang) {
3785  // #173630: Nur wenn es die Sprache auch noch gibt
3786  $matrix_page = $this->getLanguagePage($lang, array(
3787  'deleted' => -1,
3788  'inactive' => 1,
3789  'only_active' => false,
3790  'auth_or' => '1=1'
3791  ));
3792  $flag = $param['extra']['language_link'][$lang];
3793  if ($flag && $lang!=$this->_site->language) {
3794  if ($matrix_page) {
3795  $param['extra'] = $clean_clones(array_merge($this->extra, $param['extra']));
3796  if (!isset($param['rights'])) {
3797  $param['rights'] = [
3798  'rights' => $this->getRightsArray(),
3799  'users' => $this->getUsersArray()
3800  ];
3801  }
3802 
3803  $matrix_param = $param;
3804  if (!empty($param['extra']['language_urls'][$lang])) {
3805  $matrix_param['field']['url'] = $param['extra']['language_urls'][$lang];
3806  }
3807 
3808  // Meta URL für Sprachverknüpfung setzen
3809  $matrix_page->update($matrix_param, false, $asis, $silent);
3810 
3811  // Mediapool kopieren
3812  $this->getMediapool()->copy($matrix_page, '', false, false, true, true, false, '', false);
3813 
3814  // Wenn bereits eine Sprachkopie existiert und darauß eine Sprachverknpüfung wird, dann alle Multimedia Dateien löschen
3815  if ($this->_site->site['type'] == 'media') {
3816  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media' . DIRECTORY_SEPARATOR . $this->_site->name;
3817  $source = $media_dir . DIRECTORY_SEPARATOR . $matrix_page->getMediaFilename(true);
3818 
3819  foreach (glob($source . '*') as $media_file) {
3820  @unlink($media_file);
3821  }
3822  }
3823  } elseif (!$this->isReleaseCopy()) { // Wenn die Seite noch nicht in dieser Sprache vorhanden ist, dann wird diese erzeugt (außer für Freigabekopien).
3824  $matrix_parent = $this->getParents(array(), array('auth_or' => '1=1'));
3825  if ($matrix_parent) {
3826  $matrix_parent = $matrix_parent->nextPage(); /* @var $matrix_parent Page */
3827  if ($matrix_parent) {
3828  $matrix_parent = $matrix_parent->getLanguagePage($lang, array(
3829  'auth_or' => '1=1',
3830  'inactive' => 1,
3831  'only_active' => false,
3832  'deleted_or' => '1=1'
3833  ));
3834  if ($matrix_parent)
3835  {
3836  if ($matrix_parent->field['deleted']) {
3837  // Elternseite wiederherstellen
3838  $matrix_parent->undelete();
3839  }
3840  if ($matrix_page = $matrix_parent->newChild($this->field, $clean_clones($this->extra))) {
3841  // Mediapool kopieren
3842  $this->getMediapool()->copy($matrix_page, '', false, false, true, true, false, '', false);
3843  }
3844  }
3845  }
3846  }
3847  }
3848  $languages[] = $lang;
3849  }
3850  elseif (!$this->field['deleted'] && $lang!=$this->_site->language) {
3851  // #204196: Nur wenn diese Sprache keine Sprachverknüpfung (und nicht gelöscht) ist
3852  if ($matrix_page) {
3853  if (
3854  !Ego_System::isEqual($matrix_page->extra['language_link'], $param['extra']['language_link'])
3855  || !Ego_System::isEqual($matrix_page->extra['language_standard'], $param['extra']['language_standard'])
3856  ) {
3857  $matrix_page_link = $matrix_page->extra['language_link'][$lang];
3858 
3859  $matrix_page_extra = $matrix_page->extra;
3860  $matrix_page_extra['language_link'] = $param['extra']['language_link'];
3861  $matrix_page_extra['language_standard'] = $param['extra']['language_standard'];
3862 
3863  $matrix_page->updateExtra($clean_clones($matrix_page_extra), false, $asis, $silent);
3864 
3865  // Aus einer existierenden Sprachverknüpfung wird eine Sprachkopie
3866  if (!$param['extra']['language_link'][$lang] && $matrix_page_link) {
3867  // Multimedia Dateien müssen kopiert werden
3868  if ($this->_site->site['type'] == 'media') {
3869  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media' . DIRECTORY_SEPARATOR . $this->_site->name;
3870  $source = $media_dir . DIRECTORY_SEPARATOR . $this->getMediaFilename();
3871 
3872  if (Ego_System::file_exists($source)) {
3873  $dest = $media_dir . DIRECTORY_SEPARATOR . $matrix_page->getMediaFilename(true);
3874  Ego_System::copy(
3875  $source,
3876  $dest,
3877  '',
3878  true
3879  );
3880 
3881  // Archiveintrag
3882  Ego_System::copy(
3883  $dest,
3884  $media_dir . DIRECTORY_SEPARATOR . $matrix_page->getMediaFilename(
3885  true,
3886  '_'.strtotime($matrix_page->field['m_date'])
3887  ),
3888  '',
3889  true
3890  );
3891  }
3892  }
3893  }
3894  }
3895  }
3896  }
3897  }
3898  if ($languages)
3899  {
3900  $this->message.= "\n".$GLOBALS['auth']->translate('Folgende Sprachen wurden auch geändert:').' '.join(', ', $languages)."\n";
3901  $this->_updatedLinkLanguages = $languages;
3902  }
3903  }
3904  }
3905 
3906  // Wird ein Multimedia Bild gespeichert, muss für alle untergeordneten Ausschnitte
3907  if ($this->field['type'] == 'multimedia/image') {
3908  foreach ($this->getChildren() as $child) {
3909  // ... die Spracheinstellungen vererbt werden
3910  if (isset($param['extra'])) {
3911  $extra = $child->extra;
3912  $extra['language_link'] = $param['extra']['language_link'];
3913  $extra['language_standard'] = $param['extra']['language_standard'];
3914  $child->updateExtra($extra, true, $asis, $silent);
3915  }
3916 
3917  // ... der Cache gelöscht werden
3918  $this->_site->clearCache($child->field['id']);
3919  }
3920  }
3921 
3922  $this->hookUpdate();
3923  $this->updateIndex();
3924 
3925  // Bilder umwandeln
3926  Ego_Queue::add([$this, 'convertImages']);
3927 
3928  return $reload;
3929  }
3930 
3937  function hookUpdate($hook = 'update') {
3938  // Zwischenspeicherungen führen keine Hooks aus
3939  if ($hook == 'update' && $this->archiveOnly) {
3940  return;
3941  }
3942 
3943  $cache_key = $this->_site->name.'/'.$this->field['type'].'/'.$hook;
3944  $hook_cache = array();
3945  if (isset($GLOBALS['hook_cache'][$cache_key])) {
3946  $hook_cache = $GLOBALS['hook_cache'][$cache_key];
3947  } else {
3948  $dirs = array(
3949  $GLOBALS['egotec_conf']['lib_dir'] . 'type/site/' => 0, // System
3950  $GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme.'/site/' => 'theme', // pub theme
3951  $GLOBALS['egotec_conf']['site_dir'] . '_global/' => 'global', // Global
3952  $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/' => 'misc' // Mandant
3953  );
3954  foreach ($dirs as $dir => $flag) {
3955  if ($flag == 'global' && !$this->_site->globalAllowed()) {
3956  continue;
3957  }
3958  $script_path = $dir . 'admin/' . $hook . '.php';
3959  if ($flag && Ego_System::file_exists($script_path)) {
3960  $hook_cache[] = array('path' => $script_path, 'flag' => $flag, 'type' => false);
3961  }
3962  $script_path = $dir . $this->field['type'] . '/admin/' . $hook . '.php';
3963  if (Ego_System::file_exists($script_path)) {
3964  $hook_cache[] = array('path' => $script_path, 'flag' => $flag ? $flag : 'misc', 'type' => true);
3965  }
3966  }
3967  if (!isset($GLOBALS['hook_cache'])) {
3968  $GLOBALS['hook_cache'] = array();
3969  }
3970  $GLOBALS['hook_cache'][$cache_key] = $hook_cache;
3971  }
3972  if ($hook_cache) {
3973  if (!$this->field['type']) {
3974  throw new Exception();
3975  }
3976  foreach ($hook_cache as $script_path) {
3977  $call_func = $script_path['type']
3978  ? 'site_'.$hook.'_'.str_replace('/', '_', $this->field['type']).'_'.$script_path['flag']
3979  : 'site_' . $hook . '_' . $script_path['flag'];
3980  if (!function_exists($call_func)) {
3981  require_once($script_path['path']);
3982  }
3983  if (function_exists($call_func)) {
3984  $call_func($this);
3985  }
3986  }
3987 
3988  if (!isset($GLOBALS['hook_cache'])) {
3989  $GLOBALS['hook_cache'] = array();
3990  }
3991  $GLOBALS['hook_cache'][$cache_key] = $hook_cache;
3992  }
3993 
3994  if (!$GLOBALS['egotec_setup']) {
3995  // Alle Verweise dieser Page sammeln
3996  if ($hook == 'update') {
3997  Ego_Queue::add(array($this, 'updateLinks'));
3998  }
3999 
4000  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'url') {
4001  if (
4002  (
4003  $hook == 'delete'
4004  || $this->field['inactive']
4005  )
4006  && !$this->isWorkflowCopy()
4007  ) {
4008  // URLs dieser Page archivieren
4009  Ego_Queue::add(array($this, 'archiveUrls'));
4010  } else {
4011  // URLs dieser Page aktualisieren
4012  if ($hook == 'newchild') {
4013  // Direkt ausführen, da die URLs direkt benötigt werden könnten
4014  $this->updateUrls();
4015  } else {
4016  Ego_Queue::add(array($this, 'updateUrls'));
4017  }
4018  }
4019  }
4020  }
4021  }
4022 
4030  function updateField($field, $matrix_flag = true, $asis = false, $silent = false) {
4031  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4032  $GLOBALS['__egotec_skip_replication'] = 'updateField';
4033  }
4034 
4035  $this->replicate('updateField', $field, $matrix_flag, $asis, $silent);
4036 
4037  return $this->update(array('field' => $field), $matrix_flag, $asis, $silent);
4038  }
4039 
4047  function updateChildren($children) {
4048  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4049  $GLOBALS['__egotec_skip_replication'] = 'updateChildren';
4050  }
4051 
4052  $this->replicate('updateChildren', $children);
4053 
4054  return $this->update(array('children' => $children), true, true);
4055  }
4056 
4063  function updateParents($parents) {
4064  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4065  $GLOBALS['__egotec_skip_replication'] = 'updateParents';
4066  }
4067 
4068  $this->replicate('updateParents', $parents);
4069 
4070  return $this->update(array('parents' => $parents), true, true);
4071  }
4072 
4081  function updateExtra($extra, $matrix_flag = true, $asis = false, $silent = false) {
4082  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4083  $GLOBALS['__egotec_skip_replication'] = 'updateExtra';
4084  }
4085 
4086  $this->replicate('updateExtra', $extra, $matrix_flag, $asis, $silent);
4087 
4088  return $this->update(array('extra' => $extra), $matrix_flag, $asis, $silent);
4089  }
4090 
4102  function updateRights($rights, $matrix_flag = true, $asis = false) {
4103  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4104  $GLOBALS['__egotec_skip_replication'] = 'updateRights';
4105  }
4106 
4107  $this->replicate('updateRights', $rights, $matrix_flag, $asis);
4108 
4109  return $this->update(array('rights' => $rights), $matrix_flag, $asis);
4110  }
4111 
4124  function update($param = array(), $matrix_flag = true, $asis = false, $silent = false) {
4125  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4126  $GLOBALS['__egotec_skip_replication'] = 'update';
4127  }
4128 
4129  if (empty($param)) {
4130  // Aktuelle Daten speichern
4131  $reload = $this->_update(array(
4132  'field' => $this->field,
4133  'extra' => $this->extra,
4134  'rights' => array(
4135  'rights' => $this->getRightsArray(),
4136  'users' => $this->getUsersArray()
4137  )
4138  ), $matrix_flag, $asis, $silent);
4139  } else {
4140  $reload = $this->_update($param, $matrix_flag, $asis, $silent);
4141  }
4142  if($this->field['deleted'] == "1") {
4143  $this->hookUpdate("delete");
4144  $this->message.= $GLOBALS['auth']->translate('Die Seite wurde gelöscht.');
4145  }
4146 
4147  $this->replicate('update', $param, $matrix_flag, $asis, $silent);
4148 
4149  return $reload;
4150  }
4151 
4159  public function updateIndex($search=null, $queue=true, $recursive=true) {
4160  if (
4161  // Zwischenspeicherungen aktualisieren nicht den Suchindex
4162  $this->archiveOnly
4163  // Erfolgt der Aufruf über den Liveabgleich und ist die "ewige" Cache aktiv, wird kein Suchindex aktualisiert
4164  || ($_SERVER['HTTP_X_SOAP_CALL'] == 'Replication' && $this->getSite()->getCache()->getEternal())
4165  || !empty($GLOBALS['__skip_update_index'])
4166  ) {
4167  return;
4168  }
4169 
4170  // Bei einer rekursiven Suchindex Aktualisierung sicherstellen, dass die selben Seiten nicht mehrfach aktualisiert werden
4171  if (isset($GLOBALS['__page_update_index_stack']) && in_array($this->getIdentity(), $GLOBALS['__page_update_index_stack'])) {
4172  return;
4173  }
4174  if (!isset($GLOBALS['__page_update_index_stack'])) {
4175  $GLOBALS['__page_update_index_stack'] = [];
4176  }
4177  $GLOBALS['__page_update_index_stack'][] = $this->getIdentity();
4178 
4179  if (!$search) {
4180  require_once('base/Ego_Search_Factory.php');
4181  try {
4182  $search = Ego_Search_Factory::start($this->_site->pageTable.$this->getTableSuffix(), ['throw_exception' => true]);
4183  } catch (Exception $e) {
4184  // Ist die Suche nicht erreichbar, darf es hier zu keinem Abbruch kommen
4185  Ego_Action::add(Ego_Action::PAGE_UPDATE_INDEX, [
4186  'identity' => $this->getIdentity(),
4187  'recursive' => $recursive
4188  ], $e);
4189  return;
4190  }
4191  }
4192 
4193  // Relevanz der Felder beachten
4194  if ($queue) {
4195  Ego_Queue::add(array($search, 'update'), array($this->field['id'], $this, $this->_site->getSearchCount($this->extra['search_weight']), $recursive));
4196  } else {
4197  // sofort ausführen
4198  $search->update($this->field['id'], $this, $this->_site->getSearchCount($this->extra['search_weight']), $recursive);
4199  }
4200  }
4201 
4208  public function convertImages($reset = false) {
4209  $convert_type = '';
4210 
4211  // Die relevanten Mandanten für die Einstellungen ermitteln
4212  $sites = [];
4213  if ($this->_site->site['type'] == 'media') {
4214  $convert_type = 'multimedia';
4215 
4216  foreach (Ego_System::getAllSites('', '', false, 'content') as $site) {
4217  if (
4218  $site->site['media'] == $this->_site->name
4219  && !empty($site->admin['image']['convert'])
4220  ) {
4221  $sites[] = $site;
4222  }
4223  }
4224  } elseif (
4225  $this->_site->site['type'] == 'content'
4226  && !empty($this->_site->admin['mediapool']['active'])
4227  && !empty($this->_site->admin['image']['convert'])
4228  ) {
4229  $convert_type = 'mediapool';
4230 
4231  $sites[] = $this->_site;
4232  }
4233 
4234  // Liste aller bereits durchgeführten Umwandlungen
4235  $converted = [];
4236 
4237  foreach ($sites as $site) {
4238  if (
4239  (
4240  $convert_type == 'multimedia'
4241  && $this->field['type'] == 'multimedia/image'
4242  )
4243  || $convert_type == 'mediapool'
4244  ) {
4245  require_once 'base/Ego_Output.php';
4246 
4247  foreach (explode(',', $site->admin['image']['convert']) as $format) {
4248  if (!in_array($format, $converted)) {
4249  switch ($convert_type) {
4250  // Multimedia
4251  case 'multimedia':
4252  if (
4253  !empty($this->field['extra']['convert_ignore'])
4254  && in_array($format, explode(',', $this->field['extra']['convert_ignore']))
4255  ) {
4256  // Umwandlung ignorieren
4257  continue 2;
4258  }
4259 
4260  $output = new Ego_Output($this);
4261  $output->convertImage($format, $reset);
4262  break;
4263 
4264  // Mediapool
4265  case 'mediapool':
4266  $mediapool = $this->getMediapool();
4267  foreach ($mediapool->getDirs() as $dir) {
4268  foreach ($mediapool->list($dir) as $item) {
4269  if (
4270  $item['isImage']
4271  && !empty($item['convertIgnore'])
4272  && in_array($format, $item['convertIgnore'])
4273  ) {
4274  // Umwandlung ignorieren
4275  continue 4;
4276  }
4277  }
4278 
4279  $output = new Ego_Output($this, $item['name'], $dir);
4280  $output->convertImage($format, $reset);
4281  }
4282  }
4283 
4284  $converted[] = $format;
4285  }
4286  }
4287  }
4288  }
4289  }
4290 
4297  public function clearConvertedImages() {
4298  Ego_System::deldir($GLOBALS['egotec_conf']['var_dir']
4299  . 'converted/'
4300  . $this->_site->name . '/'
4301  . $this->_site->language . '/'
4302  . $this->field['id']);
4303  }
4304 
4318  function getChildren($query=array(), $param=array()) {
4319  $page_table = $this->_site->name.'_'.($param['lang']?$param['lang']:$this->_site->language);
4320  $children_table = $page_table.'_children';
4321  $query['table'] = $children_table;
4322 
4323  $query = $this->buildChildrenOrder($query, $param);
4324 
4325  $query['where'] = (isset($query['where'])?'('.$query['where'].') AND ':'').
4326  $children_table.'.page_id='.$this->field['id'].' AND '.$page_table.'.id='.$children_table.'.child';
4327  return $this->_site->getPages($query, $param);
4328  }
4329 
4337  public function buildChildrenOrder($query=array(), $param=array()) {
4338  $page_table = $this->_site->name.'_'.($param['lang']?$param['lang']:$this->_site->language);
4339  $children_table = $page_table.'_children';
4340  $order = trim(isset($query['order'])?$query['order']:$this->field['children_order']);
4341 
4342  if ($order[strlen($order) -1]=='R') {
4343  // r steht für reverse
4344  $param['reverse'] = !$param['reverse'];
4345  $order = substr($order, 0, strlen($order) -1);
4346  }
4347  switch ($order) {
4348  case 'title':
4349  $query['order'] = $page_table.'.title '.($param['reverse']?'desc':'asc');
4350  break;
4351  case 'name':
4352  $query['order'] = $page_table.'.name '.($param['reverse']?'desc':'asc');
4353  break;
4354  case 'a_date':
4355  $query['order'] = $page_table.'.a_date '.($param['reverse']?'desc':'asc');
4356  break;
4357  case 'c_date':
4358  $query['order'] = $page_table.'.c_date '.($param['reverse']?'desc':'asc');
4359  break;
4360  case 'release_from':
4361  $query['order'] = $page_table.'.release_from '.($param['reverse']?'desc':'asc');
4362  break;
4363  case 'release_until':
4364  $query['order'] = $page_table.'.release_until '.($param['reverse']?'desc':'asc');
4365  break;
4366  case 'asc':
4367  $query['order'] = $page_table.'.order_field '.($param['reverse']?'desc':'asc');
4368  break;
4369  case 'desc':
4370  $query['order'] = $page_table.'.order_field '.($param['reverse']?'asc':'desc');
4371  break;
4372  case 'type':
4373  $query['order'] = $page_table.'.type '.($param['reverse']?'desc':'asc').','.$page_table.'.name '.($param['reverse']?'desc':'asc');
4374  break;
4375  case 'none':
4376  unset($query['order']);
4377  break;
4378  case 'children':
4379  $query['order'] = $children_table.'.idx '.($param['reverse']?'desc':'asc');
4380  if (!isset($query['fields2'])) {
4381  $query['fields2'] = [];
4382  } elseif (is_string($query['fields2'])) {
4383  $query['fields2'] = [$query['fields2']];
4384  }
4385  $query['fields2'][] = $children_table.'.idx';
4386  }
4387  if ($query['order'] && $query['order']!='id') { // Um die rückwärts gerichtete Sortierung korrekt zu bekommen, muss immer noch nach der id sortiert werden.
4388  $query['order'].= ','.$page_table.'.id '.($param['reverse']?'desc':'asc');
4389  }
4390 
4391  return $query;
4392  }
4393 
4401  public function hasChildren($query = array(), $param = array()) {
4402  if (isset($this->field['has_children'])) {
4403  return !empty($this->field['has_children']);
4404  }
4405  $children = $this->getChildren($query, $param);
4406  while ($children->nextPage()) {
4407  return true;
4408  }
4409  return false;
4410  }
4411 
4423  function getParents($query=array(), $param=array()) {
4424  $page_table = $this->_site->name.'_'.($param['lang']?$param['lang']:$this->_site->language);
4425  $children_table = $page_table.'_children';
4426  $query['table'] = $children_table;
4427  $query['where'] = (isset($query['where'])?'('.$query['where'].') AND ':'').
4428  $children_table.'.child='.$this->field['id'].' AND '.$page_table.'.id='.$children_table.'.page_id';
4429 
4430  // Die Hauptkategorie ist das erste Elter (nur wenn nicht bereits explizit sortiert wird)
4431  if (!empty($this->extra['main_category']) && !isset($query['order'])) {
4432  $field2 = "CASE WHEN {$page_table}.id = {$this->extra['main_category']} THEN 1 ELSE 0 END AS main_category";
4433  if (!isset($query['fields2'])) {
4434  $query['fields2'] = [];
4435  }
4436  $query['fields2'][] = $field2;
4437  $query['order'] = "main_category DESC, {$page_table}.id ASC";
4438  }
4439 
4440  return $this->_site->getPages($query, $param);
4441  }
4442 
4452  function getAncestors($query=array(), $param=array()) {
4453  if ($this->field['deleted']) {
4454  $param = array_merge($param, array('deleted' => -1));
4455  }
4456  $ancestors_ids = $this->_getAncestorsIds($this, $param['children_query'], $param['children_param']);
4457  if ($param['id_list']) {
4458  return $ancestors_ids;
4459  }
4460  if ($ancestors_ids) {
4461  $ancestors_ids = array_reverse($ancestors_ids);
4462  $query['where'] = (isset($query['where'])?'('.$query['where'].') AND ':'').
4463  'id IN ('.join(',', $ancestors_ids).')';
4464  $query['proposed_order'] = array(
4465  'field' => 'id',
4466  'values' => $ancestors_ids
4467  );
4468  return $this->_site->getPages($query, $param);
4469  } else {
4470  return new Page_Iterator();
4471  }
4472  }
4473 
4481  function getDescendants($query=array(), $param=array()) {
4482  $lang = $param['lang']?$param['lang']:$this->_site->language;
4483  $page_table = $this->_site->name.'_'.$lang;
4484  if (!$param['children_query']) {
4485  $param['children_query']['fields'] = 'id';
4486  }
4487  $param['children_query']['order'] = '';
4488  $param['children_query']['hash'] = $this->field['id'].md5(serialize($param['children_query']));
4489  $param['children_param']['has_children'] = 1;
4490  $param['children_param']['no_cache'] = 1;
4491 
4492  $cache = $this->_site->getCache();
4493  $cache_key = '_desc_'.$this->field['id'].'_'.
4494  ($GLOBALS['auth'] ? $GLOBALS['auth']->getId() : 'guest').'_'.
4495  md5(serialize($param['children_query']).serialize($param['children_param'])).'_'.
4496  md5(serialize($this->_site->getHash()));
4497  $descendants_ids = $cache->get($cache_key);
4498  if ($descendants_ids === null) {
4499  $descendants_ids = array();
4500  $this->_getDescendantsIds($this, $param['children_query'], $param['children_param'], $descendants_ids);
4501  if ($param['with_root']) {
4502  $descendants_ids[] = $this->field['id'];
4503  }
4504  $cache->set($cache_key, $descendants_ids);
4505  }
4506  if ($param['return_ids']) {
4507  return $descendants_ids;
4508  }
4509  if ($descendants_ids) {
4510  $query['where'] = (isset($query['where'])?
4511  '('.$query['where'].') and ':
4512  '');
4513  // Oracle verträgt max. 1000 Elemente pro Liste
4514  $idgroups = array();
4515  foreach (array_chunk($descendants_ids, 999) as $ids)
4516  {
4517  // IDs splitten in 999-Häppchen
4518  $idgroups[] = $page_table.'.id in ('.implode(',', $ids).')';
4519  }
4520  $query['where'] .= '('.implode(' or ', $idgroups).')';
4521 
4522  //$page_table.'.id in ('.join(',', $descendants_ids).')';
4523  return $this->_site->getPages($query, $param);
4524  } else {
4525  return new Page_Iterator();
4526  }
4527  }
4528 
4544  function getSiblings($query=array(), $param=array(), $proposed_path=array()) {
4545  assert(
4546  (!isset($query['limit']) && isset($param['next']))
4547  || (isset($query['limit']) && !isset($param['next']))
4548  || (!isset($query['limit']) && !isset($param['next']))
4549  );
4550 
4551  $parents_query = $param['parents_query']?$param['parents_query']:array();
4552  if ($proposed_path) {
4553  $parents_query2 = $parents_query;
4554  $parents_query2['where'] = ($parents_query2['where']?$parents_query2['where'].' AND ':'').'id IN ('.join(',', $proposed_path).')';
4555  $parents = $this->getParents($parents_query2, array(
4556  'auth_or' => '1=1',
4557  'inactive' => true,
4558  'only_active' => false
4559  ));
4560  $parent = $parents->nextPage();
4561  }
4562  if (!$parent) {
4563  $parent = $this->getParents($parents_query, array(
4564  'auth_or' => '1=1',
4565  'inactive' => true,
4566  'only_active' => false
4567  ))->nextPage(); /* @var $parent Page */
4568  }
4569  if ($parent) {
4570  if ($param['without_self']) {
4571  $query['where'] .= (isset($query['where']) ? ' AND ' : '') . 'id != :self_id';
4572  $query['bind']['self_id'] = $this->field['id'];
4573  }
4574 
4575  $siblings = $parent->getChildren($query, $param);
4576  if ($param['next']) { // Nur die Geschwister ab der aktuellen Seite anzeigen.
4577  $siblings->setHaltId($this->field['id']);
4578  }
4579  }
4580  if ($siblings) {
4581  return $siblings;
4582  } else {
4583  return new Page_Iterator();
4584  }
4585  }
4586 
4593  function getLanguagePage($lang, $param = array()) {
4594  $site = clone $this->_site; /* @var $site Site */
4595  try {
4596  $site->setLanguage($lang);
4597  } catch (Site_Exception $e) {
4598  if ($e->getCode() == Site_Exception::LANG_DOESNT_EXIST) {
4599  return null;
4600  }
4601  }
4602  return $site->getPage($this->field['id'], $param);
4603  }
4604 
4613  function createLanguagePage($lang, $param = array()) {
4614  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4615  $GLOBALS['__egotec_skip_replication'] = 'createLanguagePage';
4616  }
4617 
4618  if (!in_array($lang, $this->_site->getLanguages())) {
4619  throw new Site_Exception('Die Sprache existiert nicht', Site_Exception::LANG_DOESNT_EXIST);
4620  }
4621 
4622  // Parameter um die Seite in jedem Fall zu erhalten
4623  $l_param = array(
4624  'auth_or' => '1=1',
4625  'deleted_or' => '1=1',
4626  'inactive' => true,
4627  'only_active' => false
4628  );
4629 
4630  if ($l_page = $this->getLanguagePage($lang, $l_param)) { // Übersetzte Seite existiert bereits, diese aktualisieren
4631  $field = is_array($param['field'])? $param['field']:$this->field;
4632  $extra = is_array($param['extra'])? $param['extra']:$this->extra;
4633 
4634  // Keine Workflow Historie übernehmen
4635  unset($extra['history']);
4636 
4637  $l_page->update(
4638  array(
4639  'field' => $field,
4640  'extra' => $extra
4641  )
4642  );
4643  return $l_page;
4644  } else {
4645  // Felder und Extra vorbereiten
4646  $field = is_array($param['field'])? $param['field']:$this->field;
4647  $field['id'] = $this->field['id'];
4648 
4649  $extra = is_array($param['extra'])? $param['extra']:$this->extra;
4650 
4651  // Keine Workflow Historie übernehmen
4652  unset($extra['history']);
4653 
4654  // Elternseite ermitteln
4655  $parents = $this->getParents(array(), $l_param);
4656 
4657  $parent = $parents->nextPage();
4658 
4659  // Übersetzte Elternseite ermitteln
4660  $l_parent = $parent->getLanguagePage($lang, $l_param);
4661 
4662  if (!$l_parent) { // Übersetzte Elternseite existiert nicht, alle benötigten Vorfahren anlegen
4663  $path = $this->getPath(false, $GLOBALS['current_path'], false);
4664 
4665  // Ab der übersetzten Startseite alle Vorfahren durchgehen
4666  $_parent = $this->_site->getRoot()->getLanguagePage($lang, $l_param);
4667 
4668  foreach ($path as $pid) {
4669  // Übersetzten Vorfahren ermitteln
4670  $p = $this->_site->getPage($pid, $l_param);
4671  $lp = $p->getLanguagePage($lang, $l_param);
4672 
4673  if (!$lp) { // Übersetzter Vorfahre existiert nicht, eine inaktive Sprachkopie anlegen
4674  $copied_field = $p->field;
4675  $copied_field['inactive'] = self::INACTIVE_FLAG;
4676 
4677  $copied_extra = $p->extra;
4678  $lp = $_parent->newChild($copied_field, $copied_extra);
4679  } elseif ($lp->field['deleted']) {
4680  // Übersetzter Vorfahre wurde gelöscht, Seite wiederherstellen
4681  $restored_field = $p->field;
4682 
4683  unset($restored_field['deleted']);
4684  $restored_field['inactive'] = self::INACTIVE_FLAG; // Sprachkopie deaktivieren
4685 
4686  $lp->updateField($restored_field);
4687  }
4688 
4689  // Nächste Elternseite ist die aktuelle übersetzte Seite
4690  $_parent = $lp;
4691  }
4692 
4693  // Alle Vorfahren wurden angelegt, jetzt die erwünschte übersetzte Seite anlegen
4694  $l_child = $_parent->newChild($field, $extra);
4695  } else { // Übersetzte Elternseite existiert, übersetzte Seite anlegen
4696  if ($l_parent->field['deleted']) {
4697  // Übersetzter Vorfahre wurde gelöscht, Seite wiederherstellen
4698  $restored_field = $l_parent->field;
4699 
4700  unset($restored_field['deleted']);
4701  $restored_field['inactive'] = self::INACTIVE_FLAG; // Sprachkopie deaktivieren
4702 
4703  $l_parent->updateField($restored_field);
4704  }
4705 
4706  $l_child = $l_parent->newChild($field, $extra);
4707  }
4708 
4709  // Mediapool kopieren
4710  $this->getMediapool()->copy($l_child);
4711  $l_child->getMediapool()->import(true);
4712 
4713  $this->replicate('createLanguagePage', $lang, $param);
4714 
4715  return $l_child;
4716  }
4717  }
4718 
4726  public function getKeywords($language = '', $own_keywords = false) {
4727  // Sprache muss gesetzt sein
4728  if ($language == '') {
4729  $language = $this->_site->language;
4730  }
4731 
4732  // Die Keyword-Tabelle ermitteln:
4733  // Das Schlagwortregister eines anderen Mandanten verwenden
4734  // (kann im Adminbereich pro Mandant eingestellt werden)
4735  if ($this->_site->admin['keywords']['site'] &&
4736  $this->_site->admin['keywords']['site'] != $this->_site->name
4737  ) {
4738  $keyword_table = $this->_site->admin['keywords']['site'].'_'.$language.'_keywords';
4739  } else {
4740  $keyword_table = $this->_site->name.'_'.$language.'_keywords';
4741  }
4742 
4743  // In der Relationen-Tabelle befinden sich die Zuweisungen,
4744  // also welches Schlagwort zu welcher Seite gehört
4745  $relation_table = $this->_site->name.'_keywords_rel';
4746 
4747  // Suche durchführen
4748  // Achtung! Diese Suche findet nur die Zuweisungen,
4749  // welche über den Pool verlinkt sind.
4750  // Nicht die eigenen Schlagworte, die in der Seite eingetragen wurden
4751  $db = new_db_connection();
4752 
4753  if (!$db->tableExists($keyword_table)) {
4754  return '';
4755  }
4756 
4757  $db->select(array(
4758  "fields" => "*",
4759  "table" => "$keyword_table INNER JOIN $relation_table ON $keyword_table.id = $relation_table.keyword_id",
4760  "where" => 'page_id = '.$this->field['id']
4761  ));
4762 
4763  // Alle Keywords sammeln
4764  $keywords = array();
4765 
4766  // zunächst die Zuweisungen aus dem Pool
4767  $keywords_list = explode(',', $this->extra['keywords_list']);
4768  while ($result = $db->next()) {
4769  if (in_array($result['id'], $keywords_list)) {
4770  array_push($keywords,$result['word']);
4771  }
4772  }
4773 
4774  // die eigenen Keywords werden zusätzlich ins Extra-Feld kommasepariert gespeichert und hier auch ausgelesen
4775  if ($own_keywords && $this->extra['keywords_list_own']) {
4776  $tmp = explode(',', $this->extra['keywords_list_own']);
4777  $keywords = array_merge($keywords, $tmp);
4778  }
4779 
4780  // Die Keyword-Liste kommasepariert ausgeben
4781  $keywords = implode(',', $keywords);
4782  return trim($keywords, ',');
4783  }
4784 
4791  function addKeyword($word, $add_to_pool = false) {
4792  if (!isset($GLOBALS['__egotec_skip_replication'])) {
4793  $GLOBALS['__egotec_skip_replication'] = 'addKeyword';
4794  }
4795 
4796  // Whitespaces entfernen und Wort prüfen
4797  $word = trim($word);
4798  if ($word == '') {
4799  return false;
4800  }
4801 
4802  /*
4803  * Das Schlagwortregister kann auch aus einem andreen Mandanten verwendet werden
4804  * Achtung! Wenn z.B. in einem deutschen Page-Objekt ein Keywords hinzugefügt wird,
4805  * dieser Mandant aber nicht in dieser Sprache existiert,
4806  * dann wird kein Schlagwort erstellt.
4807  */
4808  if ($this->_site->admin['keywords']['site'] && $this->_site->admin['keywords']['site'] != $this->_site->name) {
4809  // Existenz der Sprache prüfen
4810  $keywordSite = new Site($this->_site->admin['keywords']['site'],$this->_site->language);
4811  } else {
4812  $keywordSite = $this->_site;
4813  }
4814 
4818  $k_db = new_db_connection();
4819  $k_db->select(array(
4820  'table' => $keywordSite->pageTable.'_keywords',
4821  'where' => 'LOWER(word)=:word',
4822  'bind' => array('word' => strtolower($word))
4823  ));
4824 
4829  if($k_db->next()) {
4830  $maxid = $k_db->Record['id'];
4831  } else {
4832  // Die nächst höchste ID herausfinden von allen verfügbaren Sprachen des Mandanten
4833  $max = 0;
4834  foreach($keywordSite->getLanguages() as $sprache) {
4835  $u_db = new_db_connection();
4836  $u_db->select(array(
4837  'fields' => 'id',
4838  'table' => $keywordSite->name.'_'.$sprache.'_keywords',
4839  'order' => 'id DESC',
4840  'limit' => '1'
4841  ));
4842 
4843  $maxentry = $u_db->next();
4844  if((int)$maxentry['id'] > $max) {
4845  $max = (int)$maxentry['id'];
4846  }
4847  }
4848  $maxid = $max+1; // Neue ID ist höchste ID + 1
4849 
4853  $k_db->insert(array(
4854  'table' => $keywordSite->pageTable.'_keywords',
4855  'set' => array(
4856  'id' => $maxid,
4857  'word' => $word,
4858  'c_date' => date('Y-m-d H:i:s'),
4859  'main' => 1, // Neues Wort ist immer der Hauptsprachbegriff
4860  'not_in_list' => ($add_to_pool) ? 0 : 1 // Im gesamten Schlagwortregister aufnehmen oder nicht
4861  ))
4862  );
4863  }
4864 
4876  $db2 = new_db_connection();
4877  $db2->select(array(
4878  'table' => $keywordSite->name.'_keywords_rel',
4879  'where' => "page_id = '".$this->field['id']."' AND keyword_id = '".$maxid."'",
4880  'order' => 'page_id',
4881  'limit' => 1
4882  ));
4883  if ($db2->next()) {
4884  return true; // alles ok, Schlagwort ist bereits zugewiesen
4885  }
4886 
4887  if ($k_db->insert(array(
4888  'table' => $keywordSite->name.'_keywords_rel',
4889  'set' => array(
4890  'page_id' => $this->field['id'],
4891  'keyword_id' => $maxid,
4892  'c_date' => date('Y-m-d H:i:s')
4893  )))) { // Abwärtskompatibilität Schlagworte auch in die Extra-Felder "keywords_list" und "keywords_list_own" schreiben
4894  // Alle zugewiesenden Schlagwort-Ids auslesen
4895  $k_db->select(array(
4896  'table' => $keywordSite->name.'_keywords_rel',
4897  'where' => "page_id = '".$this->field['id']."'"
4898  ));
4899  $entries = array();
4900  while ($entry = $k_db->next()) {
4901  $entries[] = $entry['id'];
4902  }
4903 
4904  // Alle Schlagworte auslesen
4905  $k_db->select(array(
4906  'table' => $keywordSite->pageTable.'_keywords',
4907  'where' => "id IN ('".implode("','", $entries)."')"
4908  ));
4909 
4910  $keywords_list = array();
4911  $keywords_list_own = array();
4912  while ($entry = $k_db->next()) {
4913 
4914  if ($entry['not_in_list'] == "1") {
4915  $keywords_list_own[] = $entry['word'];
4916  } else {
4917  $keywords_list[] = $entry['id'];
4918  }
4919  }
4920 
4921  // Schlagworte bzw. SchlagwortIDs kommasepariert ins extra-Feld
4922  if ($keywords_list || $keywords_list_own) {
4923  $this->extra['keywords_list'] = implode(",",$keywords_list);
4924  $this->extra['keywords_list_own'] = implode(",",$keywords_list_own);
4925  $this->updateExtra($this->extra,true);
4926  }
4927 
4928  $this->replicate('addKeyword', $word);
4929 
4930  return true;
4931  } else {
4932  return false;
4933  }
4934  }
4935 
4942  function getUrl($param = array()) {
4943  if (($this->extra['image_type'] || $param['pool']) && !$param['download'] && !$param['thumbnail']) { // Multimediaendung setzen.
4944  if (!$param['no_suffix'] && $this->extra['image_type']) {
4945  $param['suffix'] = $this->extra['image_type'];
4946  }
4947  unset($param['no_suffix']);
4948 
4949  /* Bild URLs müssen immer width und height Parameter beinhalten.
4950  * Wird nur width oder nur height übergeben, dann muss der Gegenwert
4951  * relativ berechnet werden (Skalierung).
4952  * Wird keiner der Parameter übergeben, dann werden die Originalwerte
4953  * verwendet (origImgWidth und origImgHeight).
4954  * Werden beide Parameter übergeben, dann werden diese verwendet.
4955  * Wird ein ungültiger Wert übergeben, dann wird der Parameter aus der URL entfernt.
4956  * Die URL Auflösung skaliert automatisch,
4957  * wenn nur width oder nur height in der URL vorkommt.*/
4958  $param = $this->addImageParams($param);
4959  }
4960  if (!$param['lang'] || $param['lang'] == $this->_site->language) {
4961  // Wird die URL für die aktuelle Seite angefordert, ist das Page Objekt bereits bekannt
4962  return $this->_site->getPageUrl($this->field['id'], $param, $this);
4963  }
4964  return $this->_site->getPageUrl($this->field['id'], $param);
4965  }
4966 
4973  public function getFrontendUrl($param = array()) {
4974  $now = date('Y-m-d H:i:s');
4975  if (
4976  $this->field['inactive'] > 0
4977  || ($this->field['release_from'] != '0000-00-00 00:00:00' && $this->field['release_from'] > $now)
4978  || ($this->field['release_until'] != '0000-00-00 00:00:00' && $this->field['release_until'] < $now)
4979  || $this->isWorkflowCopy()
4980  || $this->isReleaseCopy()
4981  ) {
4982  return '';
4983  }
4984  $param['get_frontend_url'] = true;
4985  return $this->getUrl($param);
4986  }
4987 
4994  public function getLiveUrl($param = array()) {
4995  if (((int) $this->field['nav_hide']&2) == 2) {
4996  // Es gibt keine Liveserver URLs für Seiten, die nicht auf dem Liveserver existieren dürfen
4997  return '';
4998  }
4999 
5000  // Immer eine absolute URL erzeugen
5001  $param['return_absolute'] = true;
5002 
5003  if (!$GLOBALS['egotec_conf']['liveserver']) {
5004  // URL vom (ersten) Liveserver erzeugen
5005  $clusters = Ego_System::getCluster();
5006  array_walk($clusters, function (&$value) {
5007  $value = $value['url'];
5008  });
5009  $liveservers = array_values(array_filter(array_merge([$this->_site->admin['live']['location']], $clusters)));
5010 
5011  if (!empty($liveservers)) {
5012  // Liveserver URL setzen
5013  $live = $this->_site->admin['live'];
5014  $live['location'] = $liveservers[0];
5015 
5016  require_once('soap/Ego_SOAP.php');
5017  $soap = new Ego_SOAP($live, 1);
5018  try {
5019  return $soap->soapCall('pageGetUrl', [
5020  'site' => $this->_site->name,
5021  'lang' => $this->_site->language,
5022  'id' => $this->field['id'],
5023  'param' => soap_var($param)
5024  ]);
5025  } catch (Exception $e) {
5026  return '';
5027  }
5028  }
5029  }
5030 
5031  // URL von diesem Server erzeugen
5032  return $this->getFrontendUrl($param);
5033  }
5034 
5040  public function getCloneUrl() {
5041  return 'index.php?' . http_build_query(array(
5042  'id' => $this->field['id'],
5043  'site' => $this->_site->name,
5044  'lang' => $this->_site->language
5045  ));
5046  }
5047 
5053  public function getCloneOriginal() {
5054  if ($this->isClone()) {
5055  $param = array(
5056  'auth_or' => '1=1',
5057  'deleted_or' => '1=1',
5058  'inactive' => true,
5059  'only_active' => false
5060  );
5061  if (is_numeric($this->extra['clone_original'])) { // abwärtskompatibel
5062  $page = $this->_site->getPage($this->extra['clone_original'], $param);
5063  } else {
5064  $page = Ego_System::urltopage($this->extra['clone_original'], array(
5065  'params' => array(
5066  'param' => $param
5067  )
5068  ));
5069  }
5070  return $page;
5071  }
5072  return null;
5073  }
5074 
5087  function lock($user_id='') {
5088  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5089  $GLOBALS['__egotec_skip_replication'] = 'lock';
5090  }
5091 
5092  if (!$user_id) {
5093  $user_id = $GLOBALS['auth']->getId();
5094  }
5095  if (!$user_id) {
5096  // bei einem anonymen Benutzer wird eine Kombination aus remote_addr und user_agent gespeichert #93240
5097  $user_id = $GLOBALS['auth']->getAnonymousId();
5098  }
5099 
5100  $db = new_db_connection(array(
5101  'fields' => 'egotec_page_lock.*,egotec_user.*, egotec_page_lock.user_id AS lock_user_id',
5102  'table' => 'egotec_page_lock',
5103  'join' => 'egotec_user on egotec_page_lock.user_id=egotec_user.user_id',
5104  'where' => "(page_table='".$this->_site->pageTable."') AND (page=".$this->field['id'].")"
5105  ));
5106  if ($db->nextRecord()) {
5107  if (
5108  $db->Record['stamp'] >= (time() - $GLOBALS['egotec_conf']['page_timeout'])
5109  && $db->Record['user_id'] != $user_id
5110  ) {
5111  $db->Record['extra'] = unserialize($db->Record['extra']);
5112  return $db->Record;
5113  } else {
5114  $db->update(array(
5115  'table' => 'egotec_page_lock',
5116  'set' => array(
5117  'user_id' => $user_id,
5118  'stamp' => time()
5119  ),
5120  'where' => "page_table = '{$this->_site->pageTable}' AND page = {$this->field['id']}"
5121  ));
5122  return false;
5123  }
5124  }
5125 
5126  try {
5127  @$db->insert(array(
5128  'table' => 'egotec_page_lock',
5129  'set' => array(
5130  'page_table' => $this->_site->pageTable,
5131  'page' => $this->field['id'],
5132  'user_id' => $user_id,
5133  'stamp' => time()
5134  ),
5135  'nobackup' => true
5136  ));
5137  } catch (Exception $e) {
5138  // ignorieren
5139  }
5140 
5141  $this->replicate('lock', $user_id);
5142 
5143  return false;
5144  }
5145 
5151  function unlock($user_id=false) {
5152  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5153  $GLOBALS['__egotec_skip_replication'] = 'unlock';
5154  }
5155 
5156  $db = new_db_connection();
5157  if ($user_id === false) {
5158  $user_id = $GLOBALS['auth']->getId();
5159  }
5160  if (!$user_id) {
5161  // bei einem anonymen Benutzer wird eine Kombination aus remote_addr und user_agent gespeichert #93240
5162  $user_id = $GLOBALS['auth']->getAnonymousId();
5163  }
5164  $db->delete(array(
5165  'table' => 'egotec_page_lock',
5166  'where' => "
5167  (page_table='".$this->_site->pageTable."') AND
5168  (page=".$this->field['id'].") AND
5169  (user_id='$user_id')"
5170  ));
5171 
5172  $this->replicate('unlock', $user_id);
5173  }
5174 
5183  public function isLocked($exclude_self = true) {
5184  $where = 'page_table = :page_table AND page = :page AND stamp >= :stamp';
5185  $bind = array(
5186  'page_table' => $this->_site->pageTable,
5187  'page' => $this->field['id'],
5188  'stamp' => time() - $GLOBALS['egotec_conf']['page_timeout']
5189  );
5190  if ($exclude_self) {
5191  $where .= ' AND user_id != :user_id';
5192  $bind['user_id'] = $GLOBALS['auth']->isNobody()
5193  ? $GLOBALS['auth']->getAnonymousId()
5194  : $GLOBALS['auth']->getId();
5195  }
5196  $db = new_db_connection(array(
5197  'table' => 'egotec_page_lock',
5198  'where' => $where,
5199  'bind' => $bind
5200  ));
5201  if ($db->nextRecord()) {
5202  try {
5203  $user = new User_SQL($db->Record['user_id']);
5204  } catch (User_Exception $e) {
5205  $user = null;
5206  }
5207  return array(
5208  'user' => $user,
5209  'stamp' => $db->Record['stamp']
5210  );
5211  }
5212  return array();
5213  }
5214 
5222  function getRightsArray($perm_type='', $no_null=false) {
5223  $db = $this->_getRights($perm_type);
5224  $a = array();
5225  while ($db->nextRecord()) {
5226  $a[$db->Record['perm']][] = array(
5227  'group_id' => $db->Record['group_id'],
5228  'role_id' => $db->Record['role_id']
5229  );
5230  }
5231  // Für alle Felder in denen kein IS NULL verwendet werden darf muss später ein *|* eingetragen werden
5232  if (!$perm_type) {
5233  $no_null_fields = explode(',', trim(Auth::NO_NULL_RIGHTS, ','));
5234  foreach ($no_null_fields as $f) {
5235  if (!$a[$f]) {
5236  if ($f == 'live') {
5237  // Das Veröffentlichen Recht ist standardmäßig immer root/Administrator
5238  $a[$f][] = array(
5239  'group_id' => $GLOBALS['egotec_conf']['superuser']['group'],
5240  'role_id' => $GLOBALS['egotec_conf']['superuser']['role']
5241  );
5242  } elseif ($no_null) {
5243  $a[$f][] = array(
5244  'group_id' => '*',
5245  'role_id' => '*'
5246  );
5247  } else {
5248  $a[$f][] = array();
5249  }
5250  }
5251  }
5252  }
5253  return $a;
5254  }
5255 
5263  public function getRights($perm_type='') {
5264  return $this->_getRights($perm_type);
5265  }
5266 
5272  function setRightsArray($rights) {
5273  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5274  $GLOBALS['__egotec_skip_replication'] = 'setRightsArray';
5275  }
5276 
5277  $db = new_db_connection();
5278  $db->begin();
5279  $table = $this->_site->pageTable.'_rights';
5280  $db->delete(array(
5281  'table' => $table,
5282  'where' => "page_id=".$this->field['id']
5283  ));
5284  $set = array(); // Doppelte Einträge vermeiden
5285  foreach ($rights as $perm => $perm_rights) {
5286  if ($perm_rights) { // $perm_rights könnte auch null sein.
5287  foreach ($perm_rights as $right) {
5288  if ($right['group_id'] && $right['role_id']) { // Nur einfügen, wenn tatsächlich eine GroupID und RoleID angegeben ist.
5289  $key = $this->field['id'].'.'.$perm.'.'.$right['group_id'].'.'.$right['role_id'];
5290  if (!in_array($key, $set)) {
5291  $db->insert(array(
5292  'table' => $table,
5293  'set' => array(
5294  'page_id' => $this->field['id'],
5295  'perm' => $perm,
5296  'group_id' => $right['group_id'],
5297  'role_id' => $right['role_id']
5298  )
5299  ));
5300  $set[] = $key;
5301  }
5302  }
5303  }
5304  }
5305  }
5306  $db->commit();
5307 
5308  $this->replicate('setRightsArray', $rights);
5309  }
5310 
5317  function getUsersArray($perm_type='') {
5318  $db = $this->_getUsers($perm_type);
5319  $a = array();
5320  while ($db->nextRecord()) {
5321  $a[$db->Record['perm']][] = array(
5322  'user_id' => $db->Record['user_id']
5323  );
5324  }
5325  return $a;
5326  }
5327 
5333  function setUsersArray($users) {
5334  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5335  $GLOBALS['__egotec_skip_replication'] = 'setUsersArray';
5336  }
5337 
5338  $db = new_db_connection();
5339  $table = $this->_site->pageTable.'_users';
5340  $db->delete(array(
5341  'table' => $table,
5342  'where' => "page_id=".$this->field['id']
5343  ));
5344  $set = array(); // Doppelte Einträge vermeiden
5345  foreach ($users as $perm => $perm_users) {
5346  if ($perm_users) { // $perm_users könnte auch null sein.
5347  foreach ($perm_users as $user) {
5348  if ($user['user_id']) { // Nur einfügen, wenn tatsächlich eine UserID angegeben ist.
5349  $key = $this->field['id'].'.'.$perm.'.'.$user['user_id'];
5350  if (!in_array($key, $set)) {
5351  $db->insert(array(
5352  'table' => $table,
5353  'set' => array(
5354  'page_id' => $this->field['id'],
5355  'perm' => $perm,
5356  'user_id' => $user['user_id']
5357  )
5358  ));
5359  $set[] = $key;
5360  }
5361  }
5362  }
5363  }
5364  }
5365 
5366  $this->replicate('setUsersArray', $users);
5367  }
5368 
5374  public function getSite() {
5375  return $this->_site;
5376  }
5377 
5383  public function getMediapool() {
5384  return new Mediapool($this);
5385  }
5386 
5393  public function hasParent($parent_id) {
5394  $db = new_db_connection(array(
5395  'table' => $this->_site->pageTable.'_children',
5396  'where' => 'page_id='.$parent_id.' AND child='.$this->field['id']
5397  ));
5398  return $db->nextRecord() !== null;
5399  }
5400 
5408  public function addParent($parent_id, $asis=false) {
5409  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5410  $GLOBALS['__egotec_skip_replication'] = 'addParent';
5411  }
5412 
5413  $this->archiveOnly = false;
5414  if (!$this->_addParent($parent_id)) {
5415  return false;
5416  }
5417  $this->_updateField(array(), true, $asis, $asis); // Änderungsdatum aktualisieren und Cache löschen.
5418  $this->hookUpdate();
5419 
5420  $this->replicate('addParent', $parent_id, $asis);
5421 
5422  return true;
5423  }
5424 
5433  public function addChild($child_id='', $child_id2='') {
5434  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5435  $GLOBALS['__egotec_skip_replication'] = 'addChild';
5436  }
5437 
5438  if (!$child_id) {
5439  $child_id = $child_id2;
5440  }
5441  $this->_site->getPage($child_id)->addParent($this->field['id']);
5442 
5443  $this->replicate('addChild', $child_id, $child_id2);
5444  }
5445 
5453  public function delParent($parent_id, $asis=false) {
5454  if (!isset($GLOBALS['__egotec_skip_replication'])) {
5455  $GLOBALS['__egotec_skip_replication'] = 'delParent';
5456  }
5457 
5458  $this->archiveOnly = false;
5459  $this->_removeParent($parent_id);
5460  $this->_updateField(array(), true, $asis, $asis); // Änderungsdatum aktualisieren und Cache löschen.
5461  $this->hookUpdate();
5462 
5463  $this->replicate('delParent', $parent_id, $asis);
5464  }
5465 
5471  public function isWriteable(){
5472  if (!$this->hasRights(array('edit'))) {
5473  return false;
5474  } else if (
5475  $this->_site->admin['workflow']['enabled'] // Workflow ist aktiviert
5476  && $this->field['workflow'] // UND und für dieser Seite ist ein Workflow zugewiesen
5477  && !(int)$this->extra['original_id'] // UND bei der Site handelt es sich NICHT um eine Worflow-Kopie
5478  && !$this->hasRights('workflow') // UND der aktuelle User hat NICHT das Recht den Workflow zu ändern
5479  ) {
5480  return false;
5481  }
5482  return true;
5483  }
5484 
5490  public function isRoot() {
5491  return ($this->field['id'] == $this->_site->rootId);
5492  }
5493 
5505  public function getPath($with_root=true, $proposed_path=array(), $return_string=true, $query=array('fields' => 'id,name,url,inactive'), $param = array(), &$assorted = null) {
5506  $return_pages = $return_string == 2 && $return_string != 1;
5507  if ($return_pages) {
5508  /* Werden Page Objekte zurückgeliefert, dann diese immer mit allen Daten.
5509  * Ansonsten können Methoden wie update(), newChild(), usw. auf diesen Page Objekten Probleme machen. */
5510  unset($query['fields']);
5511  }
5512  if (!isset($param['inactive'])) {
5513  // Falls die Einstellung zu inaktiven Seiten nicht explizit übergeben wird, wird die des Site Objekts verwendet.
5514  $param['only_active'] = $this->_site->getOnlyActive();
5515  $param['inactive'] = !$param['only_active'];
5516  }
5517 
5518  $cache_key = 'path'.md5(serialize([$this->getIdentity(), $with_root, $proposed_path, $return_string, $query, $param]));
5519  $cache_entry = $this->_site->getCacheEntry($cache_key);
5520 
5521  if ($cache_entry === null) {
5522  if (
5523  !empty($this->extra['main_category'])
5524  && empty($proposed_path)
5525  && ($category = $this->_site->getPage($this->extra['main_category'], array_merge($param, array(
5526  'auth_or' => '1=1'
5527  ))))
5528  ) {
5529  $proposed_path = $category->getPath(false, [], false);
5530  $proposed_path[] = $category->field['id'];
5531  }
5532 
5533  if ($this->field['id'] == $this->_site->rootId) {
5534  // Die Startseite hat keinen Pfad
5535  if ($with_root) {
5536  // ...und gibt maximal sich selbst aus
5537  if ($return_pages) {
5538  $path = array($this);
5539  } elseif ($return_string) {
5540  if ($GLOBALS['egotec_conf']['meta_in_path']) {
5541  $path = Ego_System::encode_path(empty($this->field['url'])?$this->field['name']:$this->field['url']).'/';
5542  } else {
5543  $path = Ego_System::encode_path($this->field['name']).'/';
5544  }
5545  } else {
5546  $path = array($this->field['id']);
5547  }
5548  } else {
5549  $path = in_array($return_string, array(1, true), true) ? '' : array();
5550  }
5551  } else {
5552  if (
5553  !$proposed_path && is_array($GLOBALS['current_path'])
5554  ) {
5555  $proposed_path = $GLOBALS['current_path'];
5556  }
5557  $proposed_path[] = $this->field['id'];
5558  $ancestor_ids = array();
5559  $ancestor_order = false;
5560  $hidden_ancestor_ids = array();
5561  foreach (
5562  $this->getAncestors(
5563  array('fields' => 'id,nav_hide'),
5564  array_merge(array(
5565  'auth_or' => '1=1',
5566  'inactive' => self::INACTIVE_FLAG,
5567  'children_query' => array('where' => "type != '_keywords/entry'"),
5568  'children_param' => array_merge(array('auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG), $param)
5569  ), $param)
5570  )
5571  as $page) { // Alle möglichen Pfade der aktuellen Seite.
5572  if (!$GLOBALS['admin_area'] && $page->field['nav_hide']&1 == 1) {
5573  $hidden_ancestor_ids[] = $page->field['id'];
5574  } else {
5575  $ancestor_ids[] = $page->field['id'];
5576  }
5577  }
5578  if (!empty($hidden_ancestor_ids)) {
5579  // Pfade im Frontend möglichst nur aus Seiten generieren, die in der Navigation erreichbar sind
5580  $ancestor_ids = array_merge($ancestor_ids, $hidden_ancestor_ids);
5581  if (!empty($ancestor_ids)) {
5582  $ancestor_order = '(CASE id';
5583  foreach ($ancestor_ids as $index => $ancestor_id) {
5584  $ancestor_order .= ' WHEN ' . $ancestor_id . ' THEN ' . ($index + 1);
5585  }
5586  $ancestor_order .= ' ELSE ' . (sizeof($ancestor_ids) + 1) . ' END)';
5587  }
5588  }
5589  $ancestor_ids[] = $this->field['id'];
5590  if ($ancestor_ids) {
5591  $ancestor_where = ' AND id IN ('.join(',', $ancestor_ids).')';
5592  }
5593  $page = $this->_site->getRoot(array_merge(array('auth_or' => '1=1'), $param));
5594  if ($with_root) {
5595  if ($return_pages) {
5596  $path[] = $this->_site->getPage($this->_site->rootId, array_merge(array('auth_or' => '1=1'), $param));
5597  } elseif ($return_string) {
5598  if ($GLOBALS['egotec_conf']['meta_in_path']) {
5599  $path = Ego_System::encode_path(empty($page->field['url'])?$page->field['name']:$page->field['url']).'/';
5600  } else {
5601  $path = Ego_System::encode_path($page->field['name']).'/';
5602  }
5603  } else {
5604  $path[] = $this->_site->rootId;
5605  }
5606  } else {
5607  $path = in_array($return_string, array(1, true), true) ? '' : array();
5608  }
5609  while ($page->field['id']!=$this->field['id'] && $page) {
5610  $proposed_id = array_shift($proposed_path);
5611  if ($proposed_id==$page->field['id']) {
5612  $proposed_id = array_shift($proposed_path);
5613  }
5614  if (in_array($proposed_id, $hidden_ancestor_ids)) {
5615  $proposed_id = null;
5616  }
5617  if ($proposed_id && is_numeric($proposed_id)) {
5618  $children = $page->getChildren(
5619  array(
5620  'fields' => $query['fields'] ?? $this->_site->pageTable . '.*',
5621  'where' => 'id=:id'.$ancestor_where,
5622  'order' => $ancestor_order,
5623  'bind' => array(
5624  'id' => $proposed_id
5625  )
5626  ), array_merge(array(
5627  'auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG
5628  ), $param)
5629  );
5630  $child = $children->nextPage();
5631  } else {
5632  $child = false;
5633  }
5634  if (!$child) {
5635  $children = $page->getChildren(
5636  array(
5637  'fields' => $query['fields'] ?? $this->_site->pageTable . '.*',
5638  'where' => '1=1 '.$ancestor_where,
5639  'order' => $ancestor_order
5640  ), array_merge(array(
5641  'auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG
5642  ), $param)
5643  );
5644  $child = $children->nextPage();
5645  if (!$child) {
5646  break;
5647  }
5648  }
5649  if ($child->field['id']==$this->field['id']) {
5650  break;
5651  }
5652  if (
5653  $child->field['inactive'] == self::ACTIVE_FLAG
5654  || !empty($param['inactive']) // Falls inaktive Seiten im Pfad abgefragt werden
5655  ) {
5656  if ($return_pages) {
5657  $path[] = $child;
5658  } elseif ($return_string) {
5659  if ($_SESSION['export']) {
5660  $path.='-p-'.$child->field['id'].'/';
5661  } else {
5662  if ($GLOBALS['egotec_conf']['meta_in_path']) {
5663  $path.= Ego_System::encode_path(empty($child->field['url'])?$child->field['name']:$child->field['url']).'/';
5664  } else {
5665  $path.= Ego_System::encode_path($child->field['name']).'/';
5666  }
5667  }
5668  } else {
5669  $path[] = $child->field['id'];
5670  }
5671  }
5672  $page = $child;
5673 
5674  // Prüfen, ob der Pfad wirklich eindeutig ist (keine Seite im Pfad hat in selber Ebene eine gleichnamige Seite)
5675  if ($assorted === false) {
5676  $siblings = $page->getSiblings(array(
5677  'fields' => 'id,url,name',
5678  'where' => '(url = :name1 OR name = :name2)',
5679  'bind' => array(
5680  'name1' => $child->field['name'],
5681  'name2' => $child->field['name']
5682  )
5683  ), array_merge(array('auth_or' => '1=1'), $param));
5684  if ($siblings->numRecords() > 1) {
5685  $assorted = true;
5686  }
5687  }
5688  }
5689  }
5690 
5691  $this->_site->setCacheEntry($cache_key, [
5692  'path' => $return_pages ? array_map(function($page) {
5693  // Pages in Identitäten umwandeln
5694  return $page->getIdentity();
5695  }, $path) : $path,
5696  'assorted' => $assorted
5697  ]);
5698  } else {
5699  $path = $return_pages && is_array($cache_entry['path']) ? array_map(function($identity) use ($param) {
5700  // Identitäten in Pages umwandeln
5701  return self::isIdentity($identity) ? Page::byIdentity($identity, $param) : $identity;
5702  }, $cache_entry['path']) : $cache_entry['path'];
5703  $assorted = $cache_entry['assorted'];
5704  }
5705  return $path;
5706  }
5707 
5716  private function getPaths($with_root = false, $in_root = false, $area_domain = false) {
5717  $paths = array();
5718  $get_path = function($page, $path = array()) use (&$get_path, &$paths, $with_root, $in_root, $area_domain) {
5719  if (
5720  !$with_root
5721  && (
5722  $page->field['id'] == $this->_site->rootId
5723  || ($area_domain && $page->extra['area_domain'])
5724  )
5725  ) {
5726  array_pop($path);
5727  return $path;
5728  }
5729  $get_name = function($page) {
5730  $names = $page->getUrlNames();
5731  return array(
5732  'name' => $names[0],
5733  'id' => (int) $page->field['id']
5734  );
5735  };
5736  $index = 0;
5737  $original_path = $path;
5738  foreach ($page->getParents(array(), array(
5739  'auth_or' => '1=1',
5740  'deleted_or' => '1=1',
5741  'inactive' => true,
5742  'only_active' => false
5743  )) as $parent) {
5744  // Alle Pfade dieser Seite aus dem Cache verwenden
5745  $cache_key = 'getPaths' . md5(serialize([$parent->field['id'], $with_root, $in_root, $area_domain]));
5746  $cached_paths = $this->_site->getCacheEntry($cache_key);
5747  if ($cached_paths !== null) {
5748  $cached_path = array_pop($cached_paths);
5749 
5750  if ($index == 0) {
5751  if ($cached_path[sizeof($cached_path) - 1]['name'] === '') {
5752  // Die Startseite im Pfad ist nur für Seiten direkt unterhalb der Startseite relevant
5753  array_pop($cached_path);
5754  }
5755  array_unshift($cached_path, $get_name($parent));
5756  $path = array_merge($path, $cached_path);
5757  } elseif (!empty($cached_paths)) {
5758  $paths = array_merge($paths, $cached_paths);
5759  }
5760 
5761  $index++;
5762  continue;
5763  }
5764 
5765  if ($index++ == 0) {
5766  // Erster Pfad
5767  $path[] = $get_name($parent);
5768  $path = $get_path($parent, $path);
5769  if (empty($path) && $in_root && $parent->field['id'] == $this->_site->rootId) {
5770  // Pfad direkt unter der Startseite aufnehmen
5771  $path[] = array(
5772  'name' => '',
5773  'id' => $with_root ? (int) $parent->field['id'] : ''
5774  );
5775  }
5776  } else {
5777  // Weitere Pfade
5778  $tmp_path = $original_path;
5779  $tmp_path[] = $get_name($parent);
5780  $paths[] = $get_path($parent, $tmp_path);
5781  }
5782  }
5783  return $path;
5784  };
5785  $path = $get_path($this);
5786  if (!empty($path)) {
5787  $paths[] = $path;
5788  }
5789 
5790  // Alle Pfade im Cache speichern, um sie später wiederverwenden zu können
5791  if (sizeof($paths) > 0) {
5792  $cache_key = 'getPaths' . md5(serialize([$this->field['id'], $with_root, $in_root, $area_domain]));
5793  $this->_site->setCacheEntry($cache_key, $paths);
5794  }
5795 
5796  if (!empty($paths)) {
5797  $paths = array_reverse(array_map('array_reverse', $paths));
5798  $grouped_paths = array();
5799  foreach ($paths as $index => $path) {
5800  foreach ($path as $entry) {
5801  foreach ($entry as $key => $value) {
5802  $grouped_paths[$index][$key][] = $value;
5803  }
5804  }
5805  }
5806  foreach ($grouped_paths as $index => $path) {
5807  foreach ($path as $key => $values) {
5808  $grouped_paths[$index][$key] = implode($key == 'name' ? '/' : ',', $values);
5809  }
5810  }
5811  return $grouped_paths;
5812  }
5813  return $paths;
5814  }
5815 
5826  public function createPath($lang) {
5827  $parents = $this->getParents([], ['auth_or' => '1=1', 'deleted_or' => '1=1']);
5828 
5829  $root = $this->_site->getRoot();
5830  foreach ($parents as $parent) {
5831  $lang_parent = $parent->getLanguagePage($lang, ['auth_or' => '1=1', 'deleted_or' => '1=1']);
5832  if (!$lang_parent) { // Wenn die Elternseite nicht existiert, dann alle benötigten Vorfahren anlegen
5833  $_vorfahr = $parent->getPath(false, [], 2, [], ['auth_or' => '1=1', 'deleted_or' => '1=1', 'only_active' => false, 'inactive' => true]);
5834  $_vorfahr[] = $parent;
5835 
5836  $opa = $root->getLanguagePage($lang, ['auth_or' => '1=1', 'deleted_or' => '1=1', 'only_active' => false, 'inactive' => true]);
5837  foreach ($_vorfahr as $vorfahr) {
5838  $vorfahr_field = $vorfahr->field;
5839  unset($vorfahr_field['a_user']);
5840  unset($vorfahr_field['a_date']);
5841  $vorfahr_extra = $vorfahr->extra;
5842  unset($vorfahr_extra['workflow_page']);
5843  $vorfahr_field['inactive'] = 1; // Sprachkopien müssen immer inaktiv sein.
5844 
5845  $vater = $vorfahr->getLanguagePage($lang, ['auth_or' => '1=1', 'deleted_or' => '1=1', 'only_active' => false, 'inactive' => true]);
5846 
5847  if ($vater) {
5848  if ($vater->field['deleted']) { // Falls die Sprachseite gelöscht ist, wird sie wiederhergestellt und bekommt die Inhalte kopiert.
5849  $vater->update(['field' => $vorfahr_field, 'extra' => $vorfahr_extra]);
5850  }
5851  } else { // Seite ist nicht vorhanden und muss angelegt werden
5852  // Keine Workflow Historie übernehmen
5853  unset($vorfahr_extra['history']);
5854 
5855  $vater = $opa->newChild($vorfahr_field, $vorfahr_extra);
5856  // Rechte von der Original Sprachseite übernehmen
5857  $vater->setRightsArray($vorfahr->getRightsArray());
5858  $vater->setUsersArray($vorfahr->getUsersArray());
5859  }
5860 
5861  $opa = $vater;
5862  }
5863  } elseif ($lang_parent->field['deleted']) {
5864  // Elternseite wiederherstellen
5865  $lang_parent->undelete();
5866  }
5867  }
5868  }
5869 
5875  public function hasMultiParents(){
5876  return ((integer)$this->getParents(array(), array('auth_or'=>'1=1'))->numRecords())>1;
5877  }
5878 
5879  static function unserialize ($session_value) {
5880  $obj = @unserialize($session_value);
5881  if (get_class($obj) == '__PHP_Incomplete_Class') {
5887  $session_value = preg_replace('/^O:\d+:"Page.*?":/msi', 'O:4:"Page":', $session_value);
5888  $obj = @unserialize($session_value);
5889  if (get_class($obj) == '__PHP_Incomplete_Class') {
5890  return null;
5891  }
5892  }
5893  return $obj;
5894  }
5895 
5896  public function serialize (){
5897  return serialize($this);
5898  }
5899 
5900  public function __toString(){
5901  return get_class($this).'('.$this->getIdentity().')';
5902  }
5903 
5910  protected function _cleanEmptyContent(&$field) {
5911  if ($this->field['type']=="code") {
5912  return;
5913  }
5914 
5915  if ($field['content']) { // der neue Content
5916  $str = $field['content'];
5917  } else { // der alte Content
5918  $str = $this->field['content'];
5919  }
5920 
5921  if ($str != '') {
5922  if (Ego_System::isEmptyContent($str)) {
5923  $field['content'] = ''; // richtig leeren
5924  }
5925  }
5926  }
5927 
5936  public function cleanEmptyContent($asis=false, $silent=false) {
5937  $field = array();
5938  $field['content'] = $this->field['content'];
5939  $vorher = strlen($field['content']);
5940  $this->_cleanEmptyContent($field);
5941  $nachher = strlen($field['content']);
5942  if ($vorher != $nachher) {
5943  $param = array(
5944  'field' => $field
5945  );
5946  $this->update($param,array(),true, $asis, $silent);
5947  return true;
5948  }
5949  return false;
5950  }
5951 
5962  public function getMediaFilename($force_lang = false, $suffix = "") {
5963  $dir = $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/';
5964  $id = $this->field['id'].$suffix;
5965  $filename = $this->_site->language.'/'.$id;
5966 
5967  // Verzeichnis für die Sprache anlegen
5968  Ego_System::mkdir($dir.$this->_site->language);
5969 
5970  if (
5971  Ego_System::file_exists($dir.$filename) // Datei existiert in dieser Sprache
5972  || $force_lang // ID und Sprache muss ausgegeben werden
5973  ) {
5974  return $filename;
5975  } elseif (
5976  $this->_site->language != $this->_site->site['default_language']
5977  && Ego_System::file_exists($dir.$this->_site->site['default_language'].'/'.$id)
5978  ) {
5979  // Datei existiert aber in der Standard Sprache
5980  return $this->_site->site['default_language'].'/'.$id;
5981  }
5982 
5983  // Nur die ID ausgeben
5984  return $id;
5985  }
5986 
5993  public function addImageParams($param = array()) {
5994  $width = $param['width'];
5995  $height = $param['height'];
5996  $orig_width = $orig_height = null;
5997 
5998  // Die originale Breite/Höhe wird übergeben
5999  foreach (array('width', 'height') as $key) {
6000  if (isset($param['original_' . $key])) {
6001  $var = 'orig_' . $key;
6002  ${$var} = (int) $param['original_' . $key];
6003  unset($param['original_' . $key]);
6004  }
6005  }
6006 
6013  $use_clip = function($clip) use (&$orig_width, &$orig_height) {
6014  [$x1, $y1, $x2, $y2] = explode(',', $clip, 4);
6015  $orig_width = $x2 - $x1;
6016  $orig_height = $y2 - $y1;
6017  };
6018 
6019  if ($this->extra['image_type']) {
6020  // Multimedia
6021  if ($this->extra['mime_type'] == 'image/svg+xml') {
6022  return $param;
6023  }
6024 
6025  $orig_width = $this->extra['origImgWidth'];
6026  $orig_height = $this->extra['origImgHeight'];
6027  if (!empty($this->extra['edit']['clip'])) {
6028  $use_clip($this->extra['edit']['clip']);
6029  }
6030  } elseif (isset($param['pool'])) {
6031  // Mediapool
6032  $pool = $this->getMediapool()->get($param['pool'], $param['dir']);
6033  if (!empty($pool) && $pool['isImage'] && !in_array($pool['mime'], array('image/svg', 'image/svg+xml'))) {
6034  require_once 'base/Ego_Image.php';
6035  [$orig_width, $orig_height] = Ego_Image::getDimensions($pool['file']);
6036  if (!empty($pool['clip'])) {
6037  $use_clip($pool['clip']);
6038  }
6039  } elseif (!$orig_width && !$orig_height) {
6040  return $param;
6041  }
6042  } else {
6043  return $param;
6044  }
6045 
6046  if (is_numeric($param['width'])) {
6047  if (
6048  is_numeric($orig_width)
6049  && is_numeric($orig_height)
6050  && !isset($param['height'])
6051  ) {
6052  $width = $param['width'];
6053  $height = ceil($orig_height * ($param['width'] / $orig_width));
6054  }
6055  } elseif (is_numeric($orig_width) && !isset($param['height'])) {
6056  $width = $orig_width;
6057  }
6058  if (is_numeric($param['height'])) {
6059  if (
6060  is_numeric($orig_height)
6061  && is_numeric($orig_width)
6062  && !isset($param['width'])
6063  ) {
6064  $width = ceil($orig_width * ($param['height'] / $orig_height));
6065  $height = $param['height'];
6066  }
6067  } elseif (is_numeric($orig_height) && !isset($param['width'])) {
6068  $height = $orig_height;
6069  }
6070  if (is_numeric($width)) {
6071  $param['width'] = $width;
6072  } else {
6073  unset($param['width']);
6074  }
6075  if (is_numeric($height)) {
6076  $param['height'] = $height;
6077  } else {
6078  unset($param['height']);
6079  }
6080  return $param;
6081  }
6082 
6089  public function hasLanguageFile($lang) {
6090  $dir = $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/';
6091  $filename = $lang.'/'.$this->field['id'];
6092 
6093  return file_exists($dir.$filename);
6094  }
6095 
6104  public function destroyFile(){
6105  $dir = $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/';
6106  $filename = $this->_site->language.'/'.$this->field['id'];
6107 
6108  if (file_exists($dir.$filename)) {
6109  unlink($dir.$filename);
6110  }
6111 
6112  $mediafiles = glob($dir.$filename.'_*');
6113  if (is_array($mediafiles)) {
6114  foreach ($mediafiles as $mediafile) {
6115  unlink($mediafile);
6116  }
6117  }
6118 
6119  // Die Seite existiert ohne Sprache und die aktuelle Sprache ist die Standard Sprache
6120  if ($this->_site->language == $this->_site->site['default_language']) {
6121  $filename = $this->field['id'];
6122 
6123  if (file_exists($dir.$filename)) {
6124  unlink($dir.$filename);
6125  }
6126 
6127  $mediafiles = glob($dir.$filename.'_*');
6128  if (is_array($mediafiles)) {
6129  foreach ($mediafiles as $mediafile) {
6130  unlink($mediafile);
6131  }
6132  }
6133  }
6134  }
6135 
6142  public function getProtocol($site = null) {
6143  if (!$site) {
6144  $site = $GLOBALS['site'];
6145  }
6146  return 'http'.(
6147  ($_SERVER['HTTPS'] == 'on'
6148  && $site
6149  && $site->name == $this->_site->name
6150  && $site->language == $this->_site->language)
6151  || !empty($this->extra['https']) ? 's' : ''
6152  ).'://';
6153  }
6154 
6160  public function getInformationLocked() {
6161  $params = array();
6162  $params['tpl_name'] = 'information_locked.html';
6163  if ($this->field['type'] == 'multimedia/image') {
6164  $params['tpl_name'] = 'information_locked_image.html';
6165  }
6166  $file_name = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/'.$this->field['type'].'/admin/navigation.ini';
6167  if (!file_exists($file_name)) {
6168  $file_name = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/admin/navigation.ini';
6169  if ($this->_site->globalAllowed() && !file_exists($file_name)) {
6170  $file_name = $GLOBALS['egotec_conf']['site_dir'].'_global/admin/navigation.ini';
6171  }
6172  }
6173  if (file_exists($file_name)) {
6174  $navigation = parse_ini_file($file_name, true);
6175  foreach ($navigation as $key => $value) {
6176  if (stripos($value['url'], 'info.php?') === 0) {
6177  if (preg_match_all('/([^\?&=]+)=([^\?&=#]*)/', $value['url'], $matches)) {
6178  foreach ($matches[0] as $index => $match) {
6179  if ($matches[1][$index] != 'tpl_name') {
6180  $params[$matches[1][$index]] = $matches[2][$index];
6181  }
6182  }
6183  }
6184  break;
6185  }
6186  }
6187  }
6188  $params['url'] = 'extra.php?'.http_build_query($params);
6189  return $params;
6190  }
6191 
6200  public function getContent($main_orient = false, $variant = '', $include_scripts = false) {
6201  $content = '';
6202  if ($variant != '') {
6203  // Block Variante global weiterreichen, damit alle Aufrufe im fetch() darauf zugreifen können
6204  $GLOBALS['_block_variant'] = $variant;
6205  }
6206  if ($this->isFrontendAdmin(false)) {
6207  if ($main_orient) {
6208  // Nur die Blöcke der Haupt-Orientierung
6209  $content = $this->getBlocks($this->mainOrient, $variant, $include_scripts);
6210  } elseif ($layout = $this->getLayout($GLOBALS['is_mobile'])) {
6211  require_once 'smarty/Ego_Smarty.php';
6212  $smarty = Ego_Smarty::createFrontend($this->_site, array(
6213  'page' => $this
6214  ));
6215  $smarty->autoload_filters['output'] = array('frontend_edit');
6216 
6217  // Seiten spezifische Skripte einbinden
6218  if ($include_scripts) {
6219  $include_script = function($file) use ($smarty) {
6220  // Weitere Variablen im Skript verfügbar machen
6221  $page = $this;
6222  $site = $page->getSite();
6223  $auth = $GLOBALS['auth'];
6224 
6225  $length = strlen($needle = "/{$this->field['type']}/index.php");
6226  if (substr($file, -$length) === $needle) {
6227  // Nur das Seitentyp spezifische Skript mehrmals einbinden
6228  require $file;
6229  } else {
6230  require_once $file;
6231  }
6232  };
6233  foreach ($this->getScripts() as $file) {
6234  $include_script($file);
6235  }
6236  }
6237 
6238  $original_smarty = $GLOBALS['smarty'];
6239  $GLOBALS['smarty'] = $smarty;
6240  $content = $smarty->fetch($layout);
6241  $GLOBALS['smarty'] = $original_smarty;
6242  }
6243  }
6244  if ($content == '') {
6245  $content = $this->field['content'];
6246  }
6247  unset($GLOBALS['_block_variant']);
6248  return $content;
6249  }
6250 
6261  public function getLayout($mobile = false, $name = '', $suffix = '', &$script = '', $skip = array('module')) {
6262  // Layout Template ermitteln
6263  if (empty($suffix)) {
6264  $suffix = $_SERVER['REQUEST_SUFFIX'];
6265  }
6266  $suffix = $suffix != '.html' ? $suffix : '';
6267  $name = $name ? $name : $this->extra['_layout'];
6268  $cache_key = 'pageLayout'.md5(serialize(array($this->field['type'], $name, $mobile, $suffix, $skip)));
6269  $layout = $this->_site->getCacheEntry($cache_key);
6270 
6271  if ($layout === null) {
6272  $layout = '';
6273  $set_to_default = false;
6274 
6275  if ($name !== $this->conf['default_layout']) {
6276  // Prüfen, ob das Layout vom Seitentyp aus erlaubt ist
6277  $typeInfo = $this->getTypeInfo();
6278  if (isset($typeInfo['layouts']) && !in_array($name, explode(',', $typeInfo['layouts']))) {
6279  $layout = $this->getLayout($mobile, $this->conf['default_layout'], '.html', $script, $skip);
6280  $set_to_default = true;
6281  }
6282 
6283  // Prüfen, ob das Layout in der conf.json deaktiviert ist
6284  if (
6285  !empty($this->conf['layouts'])
6286  && isset($this->conf['layouts'][$name]['disabled'])
6287  && $this->conf['layouts'][$name]['disabled']
6288  ) {
6289  $layout = $this->getLayout($mobile, $this->conf['default_layout'], '.html', $script, $skip);
6290  $set_to_default = true;
6291  }
6292  }
6293 
6294  if (!$set_to_default) {
6295  foreach (array('.tpl', '.html') as $file_suffix) {
6296  if (!empty($name) && $name != 'default') {
6297  if (
6298  ($file = $this->_site->getSkinFile("{$this->field['type']}/layouts/{$name}{$suffix}{$file_suffix}", $skip))
6299  || ($file = $this->_site->getSkinFile("layouts/{$name}{$suffix}{$file_suffix}", $skip))
6300  ) {
6301  $layout = $file;
6302  break;
6303  }
6304  } else if (
6305  ($file = $this->_site->getSkinFile("{$this->field['type']}/layout{$suffix}{$file_suffix}", $skip))
6306  || ($file = $this->_site->getSkinFile("layout{$suffix}{$file_suffix}", $skip))
6307  ) {
6308  $layout = $file;
6309  break;
6310  }
6311  }
6312 
6313  if (empty($layout)) {
6314  if ($suffix != '') {
6315  $layout = $this->getLayout($mobile, $name, '.html', $script, $skip);
6316  } elseif ($name != $this->conf['default_layout']) {
6317  $layout = $this->getLayout($mobile, $this->conf['default_layout'], '.html', $script, $skip);
6318  }
6319  }
6320  }
6321 
6322  $this->_site->setCacheEntry($cache_key, $layout);
6323  }
6324 
6325  // Layout Skript ermitteln
6326  $cache_key = 'pageLayoutScript'.md5(serialize(array($this->field['type'], $name, $mobile, $suffix, $skip)));
6327  $script = $this->_site->getCacheEntry($cache_key);
6328 
6329  if ($script === null) {
6330  $script = '';
6331 
6332  if (!empty($name) && $name != 'default') {
6333  if ($name == 'default') {
6334  if (
6335  ($file = $this->_site->getSiteFile("{$this->field['type']}/layout{$suffix}.php", $skip))
6336  || ($file = $this->_site->getSiteFile("layout{$suffix}.php", $skip))
6337  ) {
6338  $script = $file;
6339  }
6340  } elseif (
6341  ($file = $this->_site->getSiteFile("{$this->field['type']}/layouts/{$name}{$suffix}.php", $skip))
6342  || ($file = $this->_site->getSiteFile("layouts/{$name}{$suffix}.php", $skip))
6343  ) {
6344  $script = $file;
6345  }
6346  }
6347  if (
6348  empty($script)
6349  && (
6350  ($file = $this->_site->getSiteFile("{$this->field['type']}/layout{$suffix}.php", $skip))
6351  || ($file = $this->_site->getSiteFile("layout{$suffix}.php", $skip))
6352  )
6353  ) {
6354  $script = $file;
6355  }
6356  $this->_site->setCacheEntry($cache_key, $script);
6357  }
6358 
6359  return $layout;
6360  }
6361 
6368  public function getLayouts($skip = array()) {
6369  $layouts = $this->_site->getLayoutFiles($this->field['type'], $skip, $this->conf['layouts']);
6370 
6371  // Nur bestimmte Layouts sind für diese Page erlaubt
6372  $info = $this->getTypeInfo();
6373  if (!empty($info['layouts'])) {
6374  return array_intersect_key($layouts, array_flip(explode(',', $info['layouts'])));
6375  }
6376 
6377  // Bestimmte Layouts deaktivieren
6378  if (!empty($this->conf['layouts'])) {
6379  foreach ($this->conf['layouts'] as $layout => $conf) {
6380  if ($conf['disabled']) {
6381  unset($layouts[$layout]);
6382  }
6383  }
6384  }
6385 
6386  return $layouts;
6387  }
6388 
6394  public function isMovable() {
6395  $info = $this->getTypeInfo();
6396 
6397  // Darf es verschoben werden?
6398  if (array_key_exists('movable', $info)) {
6399  if ($info['movable']) {
6400  return true;
6401  }
6402  return false;
6403  }
6404 
6405  // Bildausschnitte dürfen nicht verschoben werden
6406  if ($this->extra['crop_image']) {
6407  return false;
6408  }
6409 
6410  // Nicht gesetzt -> Automatisch true
6411  return true;
6412  }
6413 
6418  public function getMovableList($type) {
6419  $info = $this->getTypeInfo();
6420  if (isset($info['movable_' . $type . 'list'])) {
6421  return array_map('trim', explode(',', $info['movable_' . $type . 'list']));
6422  }
6423  return null;
6424  }
6425 
6435  public function getTemplate($mobile = false, $name = 'body', $variant = '') {
6436  return $this->_site->getTemplate($mobile, $name, $this->field['type'], $variant ? $variant : (string) $this->extra['_template']);
6437  }
6438 
6445  public function getContents($orient) {
6446  return $this->extra['_contents'][$orient];
6447  }
6448 
6460  public function getScripts() {
6461  $scripts = array(
6462  $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/index.php',
6463  $this->_site->getSiteFile($this->field['type'] . '/index.php')
6464  );
6465  if ($this->_site->globalAllowed()) {
6466  // Für diesen Mandanten ein globales Skript verwenden
6467  array_unshift($scripts, $GLOBALS['egotec_conf']['site_dir'] . '_global/index.php');
6468  }
6469  if (!empty($this->_site->theme)) {
6470  array_splice($scripts, 2, 0, $this->_site->getSiteFile('index.php', array('module', 'custom', 'global', 'parent_custom')));
6471  }
6472  $existing_scripts = [];
6473  foreach ($scripts as $script) {
6474  if ($script && Ego_System::file_exists($script)) {
6475  $existing_scripts[] = $script;
6476  }
6477  }
6478  return $existing_scripts;
6479  }
6480 
6487  public function hasContent($orient = null) {
6488  if ($this->isFrontendAdmin(false)) {
6489  return $this->field['type'] != 'page' // @TODO Muss auch für andere Seitentypen funktionieren
6490  || (
6491  isset($this->extra['_contents'])
6492  && !empty($this->extra['_contents'])
6493  && (
6494  !$orient
6495  || (
6496  isset($this->extra['_contents'][$orient])
6497  && !empty($this->extra['_contents'][$orient])
6498  )
6499  )
6500  );
6501  }
6502  return !Ego_System::isEmptyContent($this->field['content']);
6503  }
6504 
6512  public function hasBlock($block, $orient = '') {
6513  $n = 0;
6514  if (is_array($this->extra['_blocks'])) {
6515  foreach ($this->extra['_blocks'] as $_orient => $blocks) {
6516  if (!$orient || $orient == $_orient) {
6517  $values = array_count_values($blocks);
6518  if (isset($values[$block])) {
6519  $n += $values[$block];
6520  }
6521  }
6522  }
6523  }
6524  return $n;
6525  }
6526 
6536  public function addBlock($orient, $name, $content = [], $index = -1) {
6537  $content = array_merge([
6538  '_uid' => Ego_System::createUID()
6539  ], $content);
6540  $keys = [
6541  '_blocks' => $name,
6542  '_contents' => $content
6543  ];
6544  foreach ($keys as $key => $value) {
6545  if (!isset($this->extra[$key][$orient])) {
6546  $this->extra[$key][$orient] = [$value];
6547  } elseif ($index >= 0) {
6548  array_splice($this->extra[$key][$orient], $index, 0, [$value]);
6549  } else {
6550  $this->extra[$key][$orient][] = $value;
6551  }
6552  }
6553  }
6554 
6562  public function removeBlockByName($orient, $name) {
6563  if (isset($this->extra['_blocks'][$orient])) {
6564  $removed = false;
6565  while (($index = array_search($name, $this->extra['_blocks'][$orient])) !== false) {
6566  $this->removeBlockByIndex($orient, $index);
6567  $removed = true;
6568  }
6569  return $removed;
6570  }
6571  return false;
6572  }
6573 
6581  public function removeBlockByIndex($orient, $index) {
6582  if (isset($this->extra['_blocks'][$orient][$index])) {
6583  unset(
6584  $this->extra['_blocks'][$orient][$index],
6585  $this->extra['_contents'][$orient][$index]
6586  );
6587  $this->extra['_blocks'][$orient] = array_values($this->extra['_blocks'][$orient]);
6588  $this->extra['_contents'][$orient] = array_values($this->extra['_contents'][$orient]);
6589  return true;
6590  }
6591  return false;
6592  }
6593 
6605  public function removeAllBlocks(string $orients = ''): array {
6606  $array_return = [
6607  '_blocks' => [],
6608  '_contents' => []
6609  ];
6610 
6611  if ($orients != '') {
6612  foreach (explode(',', $orients) as $orient) {
6613  $array_return['_blocks'][$orient] = $this->extra['_blocks'][$orient];
6614  $array_return['_contents'][$orient] = $this->extra['_contents'][$orient];
6615 
6616  unset(
6617  $this->extra['_blocks'][$orient],
6618  $this->extra['_contents'][$orient]
6619  );
6620  }
6621  } else {
6622  $array_return['_blocks'] = $this->extra['_blocks'];
6623  $array_return['_contents'] = $this->extra['_contents'];
6624 
6625  unset(
6626  $this->extra['_blocks'],
6627  $this->extra['_contents']
6628  );
6629  }
6630 
6631  return $array_return;
6632  }
6633 
6642  public function getBlocks($orient, $variant = '', $page_frame = false) {
6643  // Wird diese Methode innerhalb eines Attach Element Templates aufgerufen, werden die Namen nicht erweitert
6644  $restore_value_prefix = '';
6645  if (isset($GLOBALS['_smarty_value_prefix'])) {
6646  $restore_value_prefix = $GLOBALS['_smarty_value_prefix'];
6647  unset($GLOBALS['_smarty_value_prefix']);
6648  }
6649 
6650  if ($variant == '') {
6651  if (isset($GLOBALS['_block_variant'])) {
6652  // Die Block Variante wird global weitergereicht
6653  $variant = $GLOBALS['_block_variant'];
6654  } elseif (in_array($_SERVER['REQUEST_SUFFIX'], array('.pdf', '.print'))) {
6655  // Block Varianten für .pdf und .print verwenden
6656  $variant = ltrim($_SERVER['REQUEST_SUFFIX'], '.');
6657  } elseif ($this->extra['_template']) {
6658  // Template Variante als Block Variante verwenden
6659  $variant = $this->extra['_template'];
6660  }
6661  }
6662  $layout = $this->extra['_layout'];
6663  $blocks = $this->extra['_blocks'][$orient];
6664 
6665  if (!is_array($blocks) || empty($blocks)) {
6666  // Standard Blöcke verwenden
6667  $blocks = array();
6668  if (empty($layout)) {
6669  $layout = $this->conf['default_layout']; // Standard Layout verwenden
6670  }
6671 
6672  if (!empty($this->conf['layouts'][$layout]['blocks'][$orient]['default'])) {
6673  // Standard Blöcke
6674  $blocks = explode(',', $this->conf['layouts'][$layout]['blocks'][$orient]['default']);
6675  }
6676  if (empty($blocks) && $orient == $this->mainOrient && $this->conf['template_block'] === true) {
6677  // Keine Blöcke und die Haupt-Orientierung: Immer das Standard Template verwenden
6678  $blocks[] = 'template';
6679  }
6680  }
6681 
6682  // Standard Template immer anzeigen, wenn
6683  if (
6684  $this->field['type'] != 'page' // ...nicht der Standard Seitentyp verwendet wird
6685  ) {
6686  // Der Seitentyp besitzt ein eigenes body Template und das Standard Template wird immer angezeigt
6687  // @TODO Nur wenn das Template aus dem Systemstandard kommt?
6688  $body_template = null;
6689  $default_template = $GLOBALS['egotec_conf']['lib_dir'] . 'type/skin/page/body.html';
6690  $get_body_template = function() use (&$body_template, $variant) {
6691  if (!$body_template) {
6692  $body_template = $this->getTemplate($GLOBALS['is_mobile'], 'body', $variant);
6693  }
6694  return $body_template;
6695  };
6696 
6697  // Das Standard Template darf nicht entfernt werden, wenn
6698  if (
6699  $this->conf['blocks']['template']['removable'] !== true // ...nicht explizit das Entfernen erlaubt ist
6700  && $get_body_template() != $default_template // ...der Seitentyp ein eigenes body Template besitzt
6701  ) {
6702  $this->conf['blocks']['template']['removable'] = false;
6703  }
6704 
6705  // Das Standard Template muss für nicht Standard Seitentypen immer vorhanden sein
6706  if (
6707  $orient == $this->mainOrient // ...nur für die Haupt-Orientierung
6708  && !in_array('template', $blocks) // ...und das Standard Template nicht bereits eingebunden wird
6709  && $this->conf['blocks']['template']['removable'] !== true // ...außer es darf explizit entfernt werden
6710  && $get_body_template() != $default_template // ...der Seitentyp ein eigenes body Template besitzt
6711  ) {
6712  $blocks[] = 'template';
6713  }
6714  }
6715 
6716  // HTML aller Blöcke zusammenfügen
6717  $html = '';
6718  if (!empty($blocks)) {
6719  $system_blocks = $this->getSystemBlocks();
6720 
6721  foreach ($blocks as $index => $block) {
6722  if ($block != 'template' && isset($this->conf['blocks'][$block]['system']) && !isset($system_blocks[$block])) {
6723  // Deaktivierte System Blöcke nicht anzeigen
6724  continue;
6725  }
6726 
6727  if ($page_frame && $this->conf['blocks'][$block]['exclude']) {
6728  // Blöcke, die für die Einbindung als dynamischer Inhalt ignoriert werden sollen, überspringen
6729  continue;
6730  }
6731 
6732  $removable = !isset($this->conf['blocks'][$block]['removable']) || (bool) $this->conf['blocks'][$block]['removable'];
6733  $template = $this->getTemplateBlock($block, $orient, $index, false, false, $variant, $removable, false, $page_frame);
6734  if ($template === null) {
6735  // Block existiert nicht
6736  if ($GLOBALS['frontend_admin'] && $this->conf['orients'][$orient]['disabled'] !== true) {
6737  // Einen unbekannten Block darstellen
6738  $html .= $this->getTemplateBlock('unknown', $orient, $index, false, false, $variant, $removable, false, $page_frame);
6739  $this->extra['_blocks'][$orient][$index] = 'unknown';
6740  unset($this->extra['_contents'][$orient][$index]);
6741  }
6742  continue;
6743  }
6744 
6745  $html .= $template;
6746  }
6747  }
6748 
6749  // Formulare erweitern
6750  if (!empty($this->extra['_forms'][$orient])) {
6751  // Unsichtbare Formular Felder generieren
6752  if (!empty($this->extra['_forms'][$orient]['hidden'])) {
6753  require_once('base/Ego_Combo.php');
6754  $combo = new Ego_Combo($this->extra['_forms'][$orient]['hidden']);
6755  foreach ($combo->getData() as $field) {
6756  $html .= '<input type="hidden" name="' . $field->key . '" value="' . $field->value . '">';
6757  }
6758  }
6759 
6760  // Mehrfachversand verhindern
6761  require_once 'base/Ego_ValidateForm.php';
6762  $html .= Ego_ValidateForm::generateToken($orient);
6763  $html .= Ego_ValidateForm::generateCSRF($orient);
6764 
6765  // Seiten mit Formularen immer ohne Cache ausliefern, da sonst der eindeutige Token/CSRF mehrfach verwendet werden kann
6766  $this->field['cache'] = 0;
6767  }
6768 
6769  // Vorangestellten Namen für Attach Element Templates wiederherstellen
6770  if (!empty($restore_value_prefix)) {
6771  $GLOBALS['_smarty_value_prefix'] = $restore_value_prefix;
6772  }
6773 
6774  return $html;
6775  }
6776 
6786  public function getBlock($orient, $uid, $variant = '', $page_frame = false) {
6787  $html = '';
6788  $blocks = $this->extra['_blocks'][$orient];
6789 
6790  if (is_numeric($uid)) {
6791  // Abwärtskompatibilität: UID ist die Position des Blocks
6792  $index = $uid;
6793  if (!empty($blocks) && isset($blocks[$index])) {
6794  $block = $blocks[$index];
6795 
6796  $removable = !isset($this->conf['blocks'][$block]['removable']) || (bool) $this->conf['blocks'][$block]['removable'];
6797  $template = $this->getTemplateBlock($block, $orient, $index, false, false, $variant, $removable, false, $page_frame);
6798  if ($template !== null) {
6799  $html = $template;
6800  }
6801  }
6802  } elseif (is_array($blocks)) {
6803  foreach ($blocks as $index => $block) {
6804  if ($this->extra['_contents'][$orient][$index]['_uid'] == $uid) {
6805  $removable = !isset($this->conf['blocks'][$block]['removable']) || (bool) $this->conf['blocks'][$block]['removable'];
6806  $template = $this->getTemplateBlock($block, $orient, $index, false, false, $variant, $removable, false, $page_frame);
6807  if ($template !== null) {
6808  $html = $template;
6809  }
6810  break;
6811  }
6812  }
6813  }
6814 
6815  return $html;
6816  }
6817 
6823  private function getSystemBlocks() {
6824  $blocks = [];
6825 
6826  $system_conf = Ego_System::getJSON($GLOBALS['egotec_conf']['lib_dir'] . 'page/conf.json');
6827  foreach ($system_conf['blocks'] as $block => $conf) {
6828  $this->conf['blocks'][$block]['system'] = strpos($block, 'input_') === 0
6829  ? 'form'
6830  : 'system';
6831 
6832  if ($block != 'template' && empty($this->conf['no_' . $block])) {
6833  // Deaktivierte Systemeigene Blöcke ausschließen
6834  if (
6835  isset($this->_site->admin['blocks']['overwrite'])
6836  && !empty($this->_site->admin['blocks']['overwrite'])
6837  ) {
6838  if (
6839  isset($this->_site->admin['blocks']['system_disabled'])
6840  && in_array($block, explode(',', $this->_site->admin['blocks']['system_disabled']))
6841  ) {
6842  continue;
6843  }
6844  } elseif (
6845  isset($GLOBALS['egotec_conf']['blocks']['system_disabled'])
6846  && in_array($block, explode(',', $GLOBALS['egotec_conf']['blocks']['system_disabled']))
6847  ) {
6848  continue;
6849  }
6850 
6851  if (!isset($this->conf['blocks'][$block])) {
6852  $this->conf['blocks'][$block] = $conf;
6853  } else {
6854  $this->conf['blocks'][$block] = array_merge($conf, $this->conf['blocks'][$block]);
6855  }
6856 
6857  $blocks[$block] = $conf['title'];
6858  }
6859  }
6860 
6861  return $blocks;
6862  }
6863 
6872  public function getBlockList($layout = null, $template = false, $for_orient = '') {
6873  $skip = !$this->_site->globalAllowed() ? ['global'] : [];
6874  $cache_key = 'blockList_' . md5(serialize(array(
6875  $layout,
6876  $template,
6877  $for_orient,
6878  $this->field['type'],
6879  $skip,
6880  $this->_site->language,
6881  $GLOBALS['auth']->isNobody() ? '' : $GLOBALS['auth']->user->field['user_id']
6882  )));
6883  $blocks = $this->_site->getCacheEntry($cache_key);
6884 
6885  if ($blocks === null) {
6886  // Sicherstellen, dass Block Informationen immer mit den Backend Übersetzungen ermitteln werden
6887  $original_smarty = $GLOBALS['smarty'];
6888  unset($GLOBALS['translation'][$GLOBALS['t_language']]);
6889  $GLOBALS['smarty'] = Ego_Smarty::createAdmin($this->_site, array(
6890  'page' => $this
6891  ), true);
6892 
6893  $blocks = array();
6894 
6895  // Liste der verfügbaren Blöcke generieren (auch von übergeordneten Seitentypen erben)
6896  $block_files = [];
6897  $current_path = '';
6898  foreach (explode('/', $this->field['type']) as $path) {
6899  $current_path .= '/' . $path;
6900  $block_files = array_merge($block_files, $this->_site->getBlockFiles(ltrim($current_path, '/'), $skip));
6901  }
6902 
6903  // Systemeigene Blöcke hinzufügen
6904  $block_files = array_merge($block_files, $this->getSystemBlocks());
6905 
6906  $sort = array();
6907  foreach ($block_files as $block => $title) {
6908  if ($block == 'unknown') {
6909  continue;
6910  } elseif ($block == '_empty') {
6911  if ($this->conf['template_block'] !== true && !$template) {
6912  continue;
6913  }
6914  // Das Standard Template ist immer verfügbar
6915  $block = 'template';
6916  } elseif ($this->_site->isDisabledBlock($block)) {
6917  // Block ist deaktiviert
6918  continue;
6919  } elseif (empty($this->conf['blocks'][$block])) {
6920  $this->conf['blocks'][$block] = array();
6921  }
6922  if (strpos($block, 'input_') === 0) {
6923  // Formular Blöcke automatisch erweitern
6924  if (!isset($this->conf['blocks'][$block]['system'])) {
6925  $this->conf['blocks'][$block]['system'] = 'form';
6926  }
6927  if (!isset($this->conf['blocks'][$block]['group'])) {
6928  $this->conf['blocks'][$block]['group'] = 'Formular';
6929  }
6930  if (!isset($this->conf['blocks'][$block]['controls'])) {
6931  $this->conf['blocks'][$block]['controls'] = array();
6932  }
6933  array_unshift($this->conf['blocks'][$block]['controls'], array(
6934  'type' => 'input',
6935  'name' => substr(strrchr($block, '_'), 1)
6936  ));
6937  }
6938  $blocks[$block] = array(
6939  'title' => $GLOBALS['auth']->translate($this->conf['blocks'][$block]['title'] ? $this->conf['blocks'][$block]['title'] : $title),
6940  'description' => $GLOBALS['auth']->translate((string)$this->conf['blocks'][$block]['description']),
6941  'image' => $this->conf['blocks'][$block]['image'] ? $GLOBALS['egotec_conf']['url_dir'] . $this->conf['blocks'][$block]['image'] : '',
6942  'max' => (int)$this->conf['blocks'][$block]['max'],
6943  'translate' => $this->conf['blocks'][$block]['translate'] !== false
6944  );
6945  if (isset($this->conf['blocks'][$block]['index'])) {
6946  $blocks[$block]['index'] = (int)$this->conf['blocks'][$block]['index'];
6947  }
6948  if (!empty($this->conf['blocks'][$block]['system'])) {
6949  $blocks[$block]['system'] = $this->conf['blocks'][$block]['system'];
6950  }
6951  if ($controls = $this->getBlockControls($block)) {
6952  $blocks[$block]['controls'] = $controls;
6953  }
6954  if (!empty($this->conf['blocks'][$block]['group'])) {
6955  $groups = array();
6956  foreach (explode(',', $this->conf['blocks'][$block]['group']) as $group) {
6957  $groups[] = $GLOBALS['auth']->translate(trim($group));
6958  }
6959  $blocks[$block]['group'] = implode(',', $groups);
6960  }
6961  if (!empty($this->conf['blocks'][$block]['pattern'])) {
6962  $blocks[$block]['pattern'] = array();
6963  foreach (explode(',', $this->conf['blocks'][$block]['pattern']) as $index => $pattern) {
6964  if (preg_match_all('/\[([^:=]+?)(:([^=]+?))?(=(.+?))?\]/', $pattern, $matches)) {
6965  $blocks[$block]['pattern'][$index] = array();
6966  foreach ($matches[0] as $index2 => $match) {
6967  $width = $matches[1][$index2];
6968  $type = (string) $matches[3][$index2];
6969  $color = (string) $matches[5][$index2];
6970  $data = array(
6971  'width' => $width,
6972  'color' => $color
6973  );
6974  if (strpos($type, 'image:') === 0) {
6975  $data['image'] = $GLOBALS['egotec_conf']['url_dir'] . substr($type, 6);
6976  } else {
6977  $data['type'] = $type;
6978  }
6979  $blocks[$block]['pattern'][$index][] = $data;
6980  }
6981  }
6982  }
6983  }
6984 
6985  $sort[] = mb_strtolower($blocks[$block]['title']);
6986  }
6987 
6988  // Blöcke alphabetisch sortieren
6989  array_multisort($sort, SORT_ASC, SORT_REGULAR, $blocks);
6990 
6991  // Blöcke variabel sortieren
6992  $index = 0;
6993  $sort = array();
6994  foreach ($blocks as $block => $info) {
6995  switch ($block) {
6996  case 'page_frame':
6997  // Dynamischer Inhalt als letzter Block
6998  $i = sizeof($blocks) + 1;
6999  break;
7000  default:
7001  if (strpos($block, 'input_') === 0) {
7002  // Formular Elemente als vorletzte Blöcke
7003  $i = sizeof($blocks);
7004  } else {
7005  // Individuelle Position
7006  if (isset($info['index'])) {
7007  $i = (int)$info['index'];
7008  if ($i < 0) {
7009  // Negative Position ausgehend vom letzten Block
7010  $i = sizeof($blocks) - abs($i);
7011  }
7012  } elseif ($block == 'template') {
7013  // Standard Template als erster Block, wenn nichts anderes angegeben ist
7014  $i = 0;
7015  } else {
7016  $i = ++$index;
7017  }
7018  }
7019  }
7020  $sort[] = $i;
7021  }
7022  array_multisort($sort, SORT_ASC, SORT_NUMERIC, $blocks);
7023 
7024  if ($layout !== null) {
7025  // Alle Blöcke nach Orientierung gruppieren
7026  $block_list = array();
7027  if (!empty($this->conf['layouts'][$layout]['blocks'])) {
7028  foreach ($this->conf['layouts'][$layout]['blocks'] as $orient => $info) {
7029  $get_blocks = function ($block_list, $type) use ($layout, $info, &$get_blocks) {
7030  $blocks = array();
7031  if (!empty($info['extend_' . $type])) {
7032  $block_list .= ",{$info['extend_'.$type]}";
7033  }
7034  foreach (explode(',', $block_list) as $block) {
7035  if ($block[0] == '@') {
7036  // Blöcke einer anderen Orientierung für dieses Layout verwenden
7037  $orient_block_list = $this->conf['layouts'][$layout]['blocks'][substr($block, 1)][$type];
7038  if (!empty($orient_block_list)) {
7039  $blocks = array_merge($blocks, $get_blocks($orient_block_list, $type));
7040  }
7041  } else {
7042  $blocks[] = $block;
7043  }
7044  }
7045  return array_unique($blocks);
7046  };
7047 
7048  if (!empty($info['allow'])) {
7049  // Nur erlaubte Blöcke ausgeben
7050  $block_list[$orient] = array_intersect_key($blocks, array_flip($get_blocks($info['allow'], 'allow')));
7051  } elseif (!empty($info['disallow'])) {
7052  // Nicht erlaubte Blöcke nicht ausgeben
7053  $block_list[$orient] = array_diff_key($blocks, array_flip($get_blocks($info['disallow'], 'disallow')));
7054  }
7055  }
7056  } elseif (!empty($for_orient)) {
7057  $block_list[$for_orient] = $blocks;
7058  }
7059  // Gruppierung nach Haupt-Orientierung muss immer existieren
7060  if (empty($block_list[$this->mainOrient])) {
7061  $block_list[$this->mainOrient] = $blocks;
7062  }
7063 
7064  $blocks = $block_list;
7065  }
7066 
7067  $this->_site->setCacheEntry($cache_key, $blocks);
7068  $GLOBALS['smarty'] = $original_smarty;
7069  }
7070 
7071  // Prüfen, ob dieses Layout Formulare beinhaltet
7072  $has_forms = $this->hasForms($layout);
7073 
7074  // Formular Blöcke für bestimmte Orientierungen nicht zurückliefern
7075  $filter = function($blocks) {
7076  $filtered = array();
7077  foreach ($blocks as $key => $block) {
7078  if (strpos($key, 'input_') !== 0) {
7079  $filtered[$key] = $block;
7080  }
7081  }
7082  return $filtered;
7083  };
7084  if ($layout) {
7085  // Sicherstellen, dass die Orientierungen mit Formularen mindestens die Formular Blöcke anzeigen
7086  foreach ($has_forms as $orient) {
7087  if (empty($blocks[$orient])) {
7088  $blocks[$orient] = $blocks[$this->mainOrient];
7089  }
7090  foreach ($blocks[$this->mainOrient] as $key => $block) {
7091  if (strpos($key, 'input_') === 0 && !isset($blocks[$orient][$key])) {
7092  $blocks[$orient][$key] = $block;
7093  }
7094  }
7095  }
7096 
7097  foreach (array_keys($blocks) as $orient) {
7098  if (!in_array($orient, $has_forms)) {
7099  $blocks[$orient] = $filter($blocks[$orient]);
7100  }
7101  }
7102  } elseif (empty($has_forms)) {
7103  $blocks = $filter($blocks);
7104  }
7105 
7106  if (!empty($for_orient)) {
7107  return $blocks[$for_orient];
7108  }
7109  return $blocks;
7110  }
7111 
7118  public function hasForms($layout = '') {
7119  $cache_key = 'hasForms'.md5(serialize(array($this->getIdentity(), $layout)));
7120  $has_forms = $this->_site->getCacheEntry($cache_key);
7121 
7122  if ($has_forms === null) {
7123  $conf_forms = $this->conf['layouts'][$layout ?: 'default']['form'];
7124  if (!empty($conf_forms)) {
7125  $this->_site->setCacheEntry($cache_key, $conf_forms);
7126  return $conf_forms;
7127  }
7128 
7129  if ($file = $this->getLayout(false, $layout)) {
7130  $has_forms = array();
7131 
7132  if (preg_match_all('/<form([^>]*)>(.*?)<\/form>/ims', Ego_System::file_get_contents($file), $matches)) {
7133  foreach (array_keys($matches[0]) as $index) {
7134  if (
7135  // Das Formular ist bereits die Orientierung
7136  preg_match('/data-edit-template=["\'](.+?)["\']/ims', $matches[1][$index], $match)
7137  // Im Formular gibt es untergordnete Orientierungen
7138  || preg_match('/<[^>]+data-edit-template=["\'](.+?)["\'][^>]*>/ims', $matches[2][$index], $match)
7139  ) {
7140  $has_forms[] = $match[1];
7141  }
7142  }
7143  }
7144  $has_forms = array_unique($has_forms);
7145 
7146  $this->_site->setCacheEntry($cache_key, $has_forms);
7147  }
7148  }
7149 
7150  return $has_forms;
7151  }
7152 
7159  public function getBlockControls($block) {
7160  if (isset($this->conf['blocks'][$block]['controls'])) {
7161  $controls = array();
7162  foreach ($this->conf['blocks'][$block]['controls'] as $control) {
7163  if ($control['name'][0] == '@') {
7164  // Steuerelement wird geerbt
7165  [$inherited_block, $name] = explode('.', substr($control['name'], 1));
7166  if (isset($this->conf['blocks'][$inherited_block]['controls'])) {
7167  foreach ($this->conf['blocks'][$inherited_block]['controls'] as $inherited_control) {
7168  if ($inherited_control['name'] == $name) {
7169  $merged_control = array_merge($inherited_control, $control);
7170  $merged_control['name'] = $inherited_control['name'];
7171  $controls[] = $merged_control;
7172  break;
7173  }
7174  }
7175  }
7176  } else {
7177  $controls[] = $control;
7178  }
7179  }
7180  return $controls;
7181  }
7182  return null;
7183  }
7184 
7201  public function getTemplateBlock($block = 'template', $orient = '', $index = 0, $empty = false, $replace = false, $variant = '', $removable = true, $do_save = false, $page_frame = false, $element_types = [], &$smarty = null) {
7202  if ($orient == '') {
7203  $orient = $this->mainOrient;
7204  }
7205 
7206  // Merken, dass man sich im Block speichern Dialog befindet
7207  $GLOBALS['__egotec_edit_do_save'] = $do_save;
7208 
7209  // UID dieses Blocks
7210  $uid = $this->extra['_contents'][$orient][$index]['_uid'];
7211 
7212  $html = $class = '';
7213  $custom_html = false;
7214  if (!$smarty) {
7215  require_once('smarty/Ego_Smarty.php');
7216  $smarty = Ego_Smarty::createFrontend($this->_site, array(
7217  'page' => $this
7218  ), true);
7219  }
7220 
7221  // Das globale Smarty Objekt für das Block Template mit dem eigenen Smarty Objekt überschreiben, falls innerhalb des Blocks darauf zugegriffen wird
7222  $original_smarty = $GLOBALS['smarty'] ? $GLOBALS['smarty'] : $smarty;
7223  $GLOBALS['smarty'] = $smarty;
7224 
7225  // Falls das Extrafeld hier nicht existiert, wird es initialisiert
7226  if (empty($this->extra)) {
7227  $this->extra = unserialize($this->field['extra']);
7228  }
7229 
7230  // Standardwerte für Block Elemente und Extrafeld setzen
7231  if ($empty && !empty($this->conf['blocks'][$block]['default'][$orient])) {
7232  $this->extra['_contents'][$orient][$index] = $this->conf['blocks'][$block]['default'][$orient];
7233  }
7234 
7235  if (is_array($this->extra['_contents'][$orient][$index]['extra'])) {
7236  // Block Extrafeld als $extra übergeben
7237  $extra = $this->extra['_contents'][$orient][$index]['extra'];
7238 
7239  // Leeres Datum nicht übergeben
7240  foreach ($extra as $key => $value) {
7241  if (in_array($value, array('0000-00-00', '0000-00-00 00:00:00'), true)) {
7242  unset($extra[$key]);
7243  }
7244  }
7245 
7246  if (strpos($block, 'input_') === 0) {
7247  // Formular Blöcke kriegen ihren ...
7248  if (isset($_POST[$extra['name']])) {
7249  // ... aktuellen Wert übergeben
7250  $smarty->assign('value', $_POST[$extra['name']]);
7251  if (isset($_POST[$extra['name'] . '_input'])) {
7252  $smarty->assign('value_input', $_POST[$extra['name'] . '_input']);
7253  }
7254  } elseif ($block == 'input_checkbox') {
7255  // ... aktuellen Wert übergeben (Checkbox Listen)
7256  $values = array();
7257  require_once 'base/Ego_Combo.php';
7258  $combo = new Ego_Combo($extra['values']);
7259  $new_data = array();
7260  foreach ($combo->getData() as $data) {
7261  if (isset($_POST[$data->field_name])) {
7262  $values[] = $data->field_name;
7263  }
7264 
7265  // Darstellung für required/optional Checkboxen in Formular Blöcken
7266  foreach (array('required', 'optional') as $type) {
7267  if ($data->{$type}) {
7268  $data->label = $GLOBALS['smarty']->fetch('string:' . str_replace('<%>', $data->label, $this->conf['form'][$type] ?? $data->label));
7269  }
7270  }
7271  $new_data[] = $data;
7272  }
7273 
7274  // Geänderte Daten übernehmen
7275  if (empty($new_data) && isset($extra['name'])) {
7276  // Abwärtskompatibilität: alte, einzelne Checkbox darstellen
7277  } else {
7278  $combo->setData($new_data);
7279  $extra['values'] = $combo->getString();
7280  }
7281 
7282  $smarty->assign('values', $values);
7283  } elseif (empty($_POST['sendform'][$orient]) && isset($extra['default'])) {
7284  // ... Standardwert übergeben
7285  $smarty->assign('value', $extra['default']);
7286  }
7287 
7288  // Formular Block deaktivieren
7289  if (!empty($extra['disabled'])) {
7290  $smarty->assign('disabled', true);
7291  }
7292 
7293  // Regulärer Ausdruck für die E-Mail Validierung
7294  $smarty->assign(array(
7295  'email_pattern' => Ego_System::REGEX_EMAIL,
7296  'email_pattern_optional' => Ego_System::REGEX_EMAIL_OPTIONAL,
7297  'pattern_optional' => $extra['regex'] ? '$|' . $extra['regex'] : ''
7298  ));
7299  }
7300  }
7301 
7302  // Fehler bei der Validierung anzeigen
7303  if (
7304  strpos($block, 'input_') === 0
7305  && isset($GLOBALS['_sendform_error'])
7306  && $GLOBALS['_sendform_error']['orient'] == $orient
7307  && (
7308  $GLOBALS['_sendform_error']['index'] == $index
7309  || (
7310  $GLOBALS['_sendform_error']['block'] == 'input_captcha'
7311  && $block == $GLOBALS['_sendform_error']['block']
7312  )
7313  )
7314  ) {
7315  $smarty->assign('error', $GLOBALS['_sendform_error']['title']);
7316  }
7317 
7318  $smarty->assign('extra', $extra ?? []);
7319  unset($smarty->_plugins['outputfilter'], $smarty->autoload_filters['output']);
7320 
7321  // Diesen Block in der Frontend Administration anzeigen
7322  $frontend_admin = $GLOBALS['frontend_admin'] && $this->conf['orients'][$orient]['disabled'] !== true;
7323 
7324  if ($block == 'template') {
7325  // Das Template des Seitentyps
7326  if ($page_frame) {
7327  /* Wird das Template als dynamischer Inhalt eingebunden, muss das Skript eingebunden werden.
7328  * Andernfalls wird es bereits beim direkten Aufruf des Seitentyps eingebunden. */
7334  $include_type_script = function() use ($block, $orient, $index, $extra, $smarty, $variant) {
7335  if (
7336  (
7337  $variant
7338  && ($file = $this->_site->getSiteFile("{$this->field['type']}/index.{$variant}.php"))
7339  ) || ($file = $this->_site->getSiteFile("{$this->field['type']}/index.php"))
7340  ) {
7341  // Weitere Variablen im Skript verfügbar machen
7342  $page = $this;
7343  $site = $page->getSite();
7344  $auth = $GLOBALS['auth'];
7345 
7346  require_once $file;
7347  }
7348  };
7349  $include_type_script();
7350  }
7351 
7352  $html .= $this->fetch(array(
7353  '_layout' => $this->extra['_layout'],
7354  '_orient' => $orient,
7355  '_index' => $index,
7356  '_block' => $block,
7357  '_empty' => $empty,
7358  '_replace' => $replace,
7359  '_page' => &$this
7360  ), false, (bool) $GLOBALS['__egotec_edit_request'], false, $variant);
7361  } else {
7362  // Ein bestimmtes Template
7363  $block_found = false;
7364  $suffixes = array('.tpl', '.html');
7365  if ($variant) {
7366  // Block Varianten zuerst suchen
7367  array_unshift($suffixes, ".{$variant}.tpl", ".{$variant}.html");
7368  }
7369  foreach ($suffixes as $file_suffix) {
7370  if (
7371  ($file = $this->_site->getInheritedFile('skin', $this->field['type'], "blocks/{$block}{$file_suffix}"))
7372  || ($file = $this->_site->getSkinFile("blocks/{$block}{$file_suffix}"))
7373  || Ego_System::file_exists($file = $GLOBALS['egotec_conf']['lib_dir'] . "page/t/blocks/{$block}.tpl")
7374  ) {
7375  $this->blockProperties = array(
7376  '_layout' => $this->extra['_layout'],
7377  '_orient' => $orient,
7378  '_index' => $index,
7379  '_block' => $block,
7380  '_empty' => $empty,
7381  '_replace' => $replace,
7382  '_uid' => $uid
7383  );
7384  $smarty->assign(array_merge(
7385  $this->blockProperties,
7386  array('_page' => &$this)
7387  ));
7388 
7394  $include_block_script = function() use ($block, $orient, $index, $extra, $smarty, $uid, $variant) {
7395  // Weitere Variablen im Skript verfügbar machen
7396  $page = $this;
7397  $site = $page->getSite();
7398  $auth = $GLOBALS['auth'];
7399 
7400  // Globales Block Skript einbinden
7401  if (
7402  (
7403  $variant
7404  && ($file = $this->_site->getSiteFile("blocks.{$variant}.php"))
7405  ) || ($file = $this->_site->getSiteFile('blocks.php'))
7406  ) {
7407  require $file;
7408  }
7409 
7410  // Block spezifisches Skript einbinden
7411  if (
7412  (
7413  $variant
7414  && (
7415  ($file = $this->_site->getSiteFile("{$this->field['type']}/blocks/{$block}.{$variant}.php"))
7416  || ($file = $this->_site->getSiteFile("blocks/{$block}.{$variant}.php"))
7417  )
7418  ) || ($file = $this->_site->getSiteFile("{$this->field['type']}/blocks/{$block}.php"))
7419  || ($file = $this->_site->getSiteFile("blocks/{$block}.php"))
7420  || Ego_System::file_exists($file = $GLOBALS['egotec_conf']['lib_dir'] . "page/blocks/{$block}.php")
7421  ) {
7422  require $file;
7423  }
7424  };
7425  $include_block_script();
7426 
7427  if ($controls = $this->getBlockControls($block)) {
7428  $domQuery = null;
7429  $dom = function() use ($smarty, $file) {
7430  require_once('base/Ego_DomQuery.php');
7431  $smarty_clone = clone $smarty;
7432  return new Ego_DomQuery($smarty_clone->fetch($file));
7433  };
7434 
7435  // Alle Attach Elemente vorab durchgehen
7436  $element_vars = $element_vars_default = [];
7437  foreach ($controls as $control) {
7438  if ($control['type'] == 'attach') {
7439  $max = 0;
7440  if (!$empty && !empty($this->extra['_contents'][$orient][$index][$control['name']])) {
7441  $max = sizeof($this->extra['_contents'][$orient][$index][$control['name']]);
7442  }
7443  if ($frontend_admin && !$control['optional'] && $max == 0) {
7444  // Wenn keine Elemente vorhanden sind, dann x Elemente automatisch annehmen
7445  $max = $control['start'] ?? 1;
7446  }
7447  $element_vars[$control['name']] = $element_vars_default[$control['name']] = [
7448  'index' => min($max, $control['start'] ?? 1) - 1,
7449  'count' => $max
7450  ];
7451  }
7452  }
7453 
7454  foreach ($controls as $ci => $control) {
7455  switch ($control['type']) {
7456  // Block kann um Elemente erweitert werden
7457  case 'attach':
7458  // Template generieren
7459  $custom_html = true;
7460 
7461  // Anzahl anzuzeigender Elemente ermitteln
7462  $max = $element_vars[$control['name']]['count'];
7463 
7464  foreach ($control['elements'] as $ei => $element) {
7465  $n = 0;
7466  $items = '';
7467  $multiple_items = is_array($element['items']);
7468  while ($n < $max) {
7469  $i = 0;
7470  if ($multiple_items) {
7471  $j = $element_types[$ci][$ei] ?? 0;
7472  if (isset($this->extra['_contents'][$orient][$index][$control['name']][$n]['_type'])) {
7473  $j = (int) $this->extra['_contents'][$orient][$index][$control['name']][$n]['_type'];
7474  }
7475  $item = $element['items'][$j]['item'];
7476  $script = $element['items'][$j]['script'];
7477  $values = $element['items'][$j]['values'];
7478  } else {
7479  $item = $element['item'];
7480  $script = $element['script'];
7481  $values = $element['values'];
7482  }
7483 
7484  // Element Informationen an Smarty übergeben
7485  $element_vars[$control['name']] = array_merge(array_filter($this->extra['_contents'][$orient][$index][$control['name']][$n] ?? [], function($key) {
7486  return $key != '_element';
7487  }, ARRAY_FILTER_USE_KEY), $element_vars_default[$control['name']]);
7488  $element_vars[$control['name']]['index'] = $n;
7489  $smarty->assign('_element', $element_vars);
7490 
7491  // Skript ausführen
7492  if (!empty($script) && ($file = $this->_site->getSiteFile($script))) {
7493  $load_script = function($file) use (&$smarty, $extra, $element_vars) {
7494  $element = $element_vars;
7495  require $file;
7496  };
7497  $load_script($file);
7498  }
7499 
7500  // HTML ermitteln aus...
7501  if (strpos($item, '@') === 0) {
7502  // ...einer Datei
7503  $GLOBALS['_smarty_value_prefix'] = "{$control['name']}][$n][";
7504  $items .= $smarty->fetch('string:' . Ego_System::file_get_contents($this->_site->getSkinFile(substr($item, 1))));
7505  unset($GLOBALS['_smarty_value_prefix']);
7506  } else {
7507  // ...einem String
7508  $items .= $smarty->fetch('string:' . preg_replace_callback('/<%>/', function () use ($values, $n, &$i, $control) {
7509  // Smarty {value} erzeugen
7510  $func = '{value';
7511  foreach ($values[$i] as $attr => $value) {
7512  if ($attr == 'var') {
7513  $value = "{$control['name']}][$n][$value";
7514  }
7515  if (is_array($value)) {
7516  foreach ($value as $sub_attr => $sub_value) {
7517  $func .= " {$attr}.{$sub_attr}=\"{$sub_value}\"";
7518  }
7519  } else {
7520  $func .= " {$attr}=\"{$value}\"";
7521  }
7522  }
7523  $func .= '}';
7524  $i++;
7525  return $func;
7526  }, str_replace(['<#>', '<##>'], [$n + 1, $max], $item)
7527  ));
7528  }
7529 
7530  // Erstes Element aktiv setzen
7531  if ($n == 0 && $element['active']) {
7532  $domQuery2 = new Ego_DomQuery($items);
7533  $nodes = $domQuery2->query($element['active']['selector']);
7534  foreach ($nodes as $node) {
7535  if ($element['active']['attribute'] == 'class') {
7536  if ($className = $node->getAttribute('class')) {
7537  $classes = explode(' ', $className);
7538  } else {
7539  $classes = array();
7540  }
7541  $classes[] = $element['active']['value'];
7542  $node->setAttribute('class', implode(' ', $classes));
7543  } else {
7544  $node->setAttribute($element['active']['attribute'], $element['active']['value']);
7545  }
7546  $items = $domQuery2->getHTML();
7547  break;
7548  }
7549  }
7550 
7551  $n++;
7552  }
7553 
7554  // Platzhalter mit Smarty und HTML ersetzen
7555  if ($domQuery === null) {
7556  $domQuery = $dom();
7557  }
7558  $domQuery->setInnerHTML($domQuery->query($element['selector']), function($node) use ($items) {
7559  return $items;
7560  });
7561  }
7562  break;
7563 
7564  // Eine Seite auswählen und die Daten im Block verwenden
7565  case 'page':
7566  $identity = $this->extra['_contents'][$orient][$index][$control['name']];
7567  if (
7568  !empty($identity)
7569  && ($data = Page::byIdentity($identity))
7570  && $data->getIdentity() !== $this->getIdentity() // Die aktuelle Seite nicht einbinden
7571  ) {
7572  // Sprachversion verwenden, falls vorhanden
7573  if (
7574  $data->getSite()->language != $this->getSite()->language
7575  && ($lang_data = $data->getLanguagePage($this->getSite()->language))
7576  ) {
7577  $data = $lang_data;
7578  }
7579 
7580  $smarty->assign([
7581  $control['name'] => $data,
7582  "{$control['name']}_block" => $this->extra['_contents'][$orient][$index][$control['name'] . '_block']
7583  ]);
7584  }
7585  break;
7586 
7587  // Block kann den Wert eines Nodes ändern
7588  case 'option':
7589  $value = $this->extra['_contents'][$orient][$index][$control['name']];
7590  if (
7591  (
7592  $control['attribute'] == '#text'
7593  || $control['preset'] == 'materialize'
7594  )
7595  && !empty($value)
7596  ) {
7597  $domQuery = $dom();
7598  $domQuery->setInnerHTML($domQuery->query($control['selector']), function($node) use ($value, &$custom_html) {
7599  $custom_html = true;
7600  return $value;
7601  });
7602  }
7603  }
7604  }
7605 
7606  if ($domQuery && $custom_html) {
7607  $html .= $domQuery->getHTML();
7608  }
7609  }
7610 
7611  if (!$custom_html) {
7612  // Template ausgeben
7613  $html .= $smarty->fetch($file);
7614  }
7615 
7616  unset($this->blockProperties);
7617  $block_found = true;
7618  break;
7619  }
7620  }
7621 
7622  if (!$block_found) {
7623  // Block existiert nicht
7624  $GLOBALS['smarty'] = $original_smarty;
7625  return null;
7626  }
7627  }
7628 
7629  // Bei einem Formular Block das Template erweitern
7630  if ($this->conf['form']['wrapper']) {
7631  $replace_form = false; // Erweitertes HTML muss am Ende mit dem FORM Element im Original HTML ersetzt werden
7632  if (strpos($block, 'input_') === 0) {
7633  $form_html = $html;
7634  } elseif (
7635  $block == 'medialist'
7636  && !empty($this->extra['_contents'][$orient][$index]['extra'])
7637  && preg_match('/<form[^>]*>.*?<\/form>/ims', $html, $matches)
7638  ) {
7639  // Upload Formular für den Block "Medienliste" erweitern
7640  $form_html = $matches[0];
7641  $replace_form = true;
7642  } else {
7643  $form_html = '';
7644  }
7645 
7646  if ($form_html != '') {
7647  if (is_array($this->conf['form']['values'])) {
7648  // Der Wrapper führt weitere {value} Elemente ein
7649  $element = $this->conf['form'];
7650  $i = 0;
7651  $form_html = $smarty->fetch('string:' . preg_replace_callback('/<%>/', function() use ($element, &$i, $form_html, $block) {
7652  if (empty($element['values'][$i])) {
7653  // Ein leeres Element markiert wo der eigentliche Formular Block eingefügt wird
7654  return $form_html;
7655  } else {
7656  // Smarty {value} erzeugen
7657  $func = '{value';
7658  foreach ($element['values'][$i] as $attr => $value) {
7659  if (is_array($value)) {
7660  foreach ($value as $sub_attr => $sub_value) {
7661  $func .= " {$attr}.{$sub_attr}=\"{$sub_value}\"";
7662  }
7663  } else {
7664  $func .= " {$attr}=\"{$value}\"";
7665  }
7666  }
7667  $func .= '}';
7668  }
7669  $i++;
7670  return $func;
7671  }, $this->conf['form']['wrapper']));
7672  } else {
7673  $form_html = str_replace('<%>', $form_html, $this->conf['form']['wrapper']);
7674  }
7675 
7676  // Formular Block wird unterteilt
7677  $columns = $this->extra['_contents'][$orient][$index]['extra']['_columns'];
7678  if (!$columns) {
7679  $columns = (string) $this->conf['form']['columns']['default'];
7680  }
7681  if (isset($this->conf['form']['columns']['value'])) {
7682  $columns = str_replace('<%>', $columns, $this->conf['form']['columns']['value']);
7683  }
7684  $columns = trim($columns);
7685 
7686  $form_html = str_replace(
7687  '<|>',
7688  $frontend_admin
7689  ? '' // Im Backend wird die Unterteilung auf das Block Element angewendet
7690  : $columns,
7691  $form_html
7692  );
7693 
7694  if ($replace_form) {
7695  $html = preg_replace('/<form[^>]*>.*?<\/form>/ims', $form_html, $html);
7696  } else {
7697  $html = $form_html;
7698  }
7699  }
7700  }
7701 
7702  // Standard Block HTML modifizieren
7703  $modify_list = array_filter([
7704  $this->conf['blocks'][$block]['modify'], // Modifikationen nur für diesen Block
7705  $this->conf['modify'] // Modifikationen für alle Blöcke
7706  ]);
7707  if (!empty($modify_list)) {
7708  require_once('base/Ego_DomQuery.php');
7709  $domQuery = new Ego_DomQuery($html);
7710  $domQuery->setSmarty($smarty);
7711  $domQuery->setSite($this->getSite());
7712  $changed = false;
7713 
7714  foreach ($modify_list as $modify_entry) {
7715  foreach ($modify_entry as $modify) {
7716  if (isset($modify['scope']) && $modify['scope'] == 'document') {
7717  continue;
7718  }
7719 
7720  // Platzhalter setzen
7721  if (isset($modify['value'])) {
7722  $placeholders = [
7723  'orient' => $orient,
7724  'index' => $index,
7725  'block' => $block,
7726  'id' => $this->field['id'],
7727  'uid' => $uid
7728  ];
7729  foreach ($placeholders as $placeholder => $value) {
7730  $modify['value'] = str_replace("<%{$placeholder}>", $value, $modify['value']);
7731  }
7732  }
7733 
7734  $domQuery->modify($modify, true);
7735  $changed = true;
7736  }
7737  }
7738 
7739  if ($changed) {
7740  $html = $domQuery->getHTML();
7741  }
7742  }
7743 
7744  // Sprungmarke platzieren
7745  if (!empty($this->extra['_contents'][$orient][$index]['_anchor'])) {
7746  $anchor = "<a id=\"{$this->extra['_contents'][$orient][$index]['_anchor']}\"></a>\n";
7747 
7748  if (!empty($this->conf['anchor'])) {
7749  // An eine bestimmte Position im Block HTML
7750  require_once('base/Ego_DomQuery.php');
7751  $domQuery = new Ego_DomQuery($html);
7752  $domQuery->setSmarty($smarty);
7753  $domQuery->setSite($this->getSite());
7754 
7755  $domQuery->insertNode($anchor, $this->conf['anchor']);
7756 
7757  $html = $domQuery->getHTML();
7758  } else {
7759  // An den Anfang des Block HTML
7760  $html = $anchor . $html;
7761  }
7762  }
7763 
7764  // Berechnete Block Styles ermitteln
7765  $hash = md5(implode('-', [$this->getIdentity(), $block, $orient, $index]));
7766  $cache_key = 'blockStyles' . $hash;
7767  $cached_tpl = $this->_site->getCacheEntry($cache_key);
7768  if ($cached_tpl === null) {
7769  $cached_tpl = [];
7770  }
7771  if (
7772  (
7773  ($tpl = $cached_tpl[$block]) !== null
7774  || ($tpl = $this->_site->getSkinFile("{$this->field['type']}/blocks/$block.style.tpl"))
7775  || ($tpl = $this->_site->getSkinFile("{$this->field['type']}/blocks/$block.style.html"))
7776  || ($tpl = $this->_site->getSkinFile("blocks/$block.style.tpl"))
7777  || ($tpl = $this->_site->getSkinFile("blocks/$block.style.html"))
7778  )
7779  && $tpl !== ''
7780  ) {
7781  $css_file = $GLOBALS['egotec_conf']['bin_dir'] . 'tmp/' . $hash . '.css';
7782  Ego_System::file_put_contents($css_file, $smarty->fetch($tpl));
7783  $css_file = $GLOBALS['egotec_conf']['url_dir'] . 'bin/tmp/' . basename($css_file);
7784  $html .= "\n" . '<link rel="stylesheet" property="stylesheet" href="' . $css_file . '">';
7785  } else {
7786  $tpl = '';
7787  }
7788  $cached_tpl[$block] = $tpl;
7789  $GLOBALS['site']->setCacheEntry($cache_key, $cached_tpl);
7790 
7791  $GLOBALS['smarty'] = $original_smarty;
7792 
7793  // CSS Klasse für diesen Block automatisch setzen
7794  if (!empty($this->conf['blocks'][$block]['class'])) {
7795  $class = $this->conf['blocks'][$block]['class'];
7796  }
7797 
7798  // Block spezifische Dateien einbinden (CSS, JS)
7799  if (empty($this->conf['blocks'][$block]['no_files'])) {
7800  $patterns = array(
7801  "blocks/{$block}",
7802  "{$this->field['type']}/blocks/{$block}"
7803  );
7804  foreach (array('css', 'js') as $extension) {
7805  foreach ($patterns as $pattern) {
7806  $path = "$pattern.$extension";
7807  if ($file = $this->_site->getSkinFile($path, array(), true)) {
7808  $html .= Ego_System::includeHtml($file);
7809  }
7810  }
7811  }
7812  }
7813 
7814  // Block als eingeschwärzt markieren
7815  if ($this->extra['_contents'][$orient][$index]['_classified']) {
7816  $classes = explode(' ', $class);
7817  $classes[] = 'egotec-classified';
7818  $class = implode(' ', array_filter($classes));
7819  }
7820 
7821  if (empty($_REQUEST['page_block_preview']) && (!$frontend_admin || !$this->isCurrentPage())) {
7822  return trim($class ? '<div class="' . $class . '">' . $html . '</div>' : $html);
7823  }
7824 
7825  // CSS Klasse für die Unterteilung wird im Backend auf das Block Element angewendet
7826  if (!empty($columns)) {
7827  $class = trim($class . $columns);
7828  }
7829 
7830  if (trim($html) == '' && $this->isCurrentPage()) {
7831  // Damit leere Elemente bedient werden können, erhalten diese einen Platzhalter
7832  $title = $block;
7833  if ($this->conf['blocks'][$block]['title']) {
7834  $title = $GLOBALS['auth']->translate($this->conf['blocks'][$block]['title']);
7835  }
7836  $html = '<div data-edit-empty-block="' . $title . '"></div>';
7837  }
7838 
7839  // Zugehörige Gruppe bestimmen
7840  if (strpos($block, 'input_') === 0 && !isset($this->conf['blocks'][$block]['group'])) {
7841  // Formular Blöcke automatisch erweitern
7842  $this->conf['blocks'][$block]['group'] = 'Formular';
7843  }
7844  $group = (string) $this->conf['blocks'][$block]['group'];
7845  if ($group) {
7846  $group = $GLOBALS['auth']->translate($group);
7847  }
7848 
7849  // Bestimmte Optionen als Attribute im Adminbereich setzen
7850  $backend_options = '';
7851  if (!empty($this->conf['panel']['options'])) {
7852  foreach ($this->conf['panel']['options'] as $option => $name) {
7853  $value = Ego_System::getAssocValue($this->extra, implode('.', ['_contents', $orient, $index, $name]));
7854  if ($value !== null) {
7855  $backend_options .= ' data-edit-option-' . $option . '="' . $value . '"';
7856  }
7857  }
7858  }
7859 
7860  return trim('<div data-edit-block="' . $block . '" data-edit-block-index="' . $index . '" data-edit-block-uid="' . $uid . '"'
7861  . (
7862  ($group ? ' data-edit-group="' . $group . '"' : '')
7863  . (!$removable ? ' data-edit-static="true"' : '')
7864  . (!empty($columns) ? ' data-edit-columns="true"' : '')
7865  )
7866  . $backend_options
7867  . ($class ? ' class="' . $class . '"' : '')
7868  . '>' . $html . '</div>');
7869  }
7870 
7882  public function inheritBlocks() {
7883  if (!empty($this->conf['layouts'][$this->extra['_layout']]['inherit'])) {
7884  if (isset($this->extra['_inherit_disabled']) && !empty($this->extra['_inherit_disabled'])) {
7885  return 2;
7886  }
7887  foreach (explode(',', $this->conf['layouts'][$this->extra['_layout']]['inherit']) as $orient) {
7888  $blocks_key = implode('.', array('_blocks', $orient));
7889  $contents_key = implode('.', array('_contents', $orient));
7890  $extra = $this->inheritExtra(array($blocks_key, $contents_key));
7891  if ($extra[$blocks_key] !== null) {
7892  $checksum_blocks = Ego_System::getChecksum($extra[$blocks_key]);
7893  $checksum_original = Ego_System::getChecksum($this->extra['_blocks'][$orient]);
7894 
7895  if ($checksum_blocks != $checksum_original) {
7896  $checksum_contents = Ego_System::getChecksum($extra[$contents_key]);
7897  $this->extra['_inherited'][$orient] = array(
7898  'blocks' => $checksum_blocks,
7899  'contents' => $checksum_contents
7900  );
7901  }
7902  }
7903  foreach ($extra as $key => $value) {
7904  $this->extra[strstr($key, '.', true)][$orient] = $value;
7905  }
7906  }
7907  return 1;
7908  }
7909  return 0;
7910  }
7911 
7918  public function getFormats($type = '') {
7919  // Standard Formate
7920  $formats = [
7921  'headers' => [
7922  'title' => 'Headers',
7923  'items' => [
7924  ['title' => 'Header 1', 'format' => 'h1'],
7925  ['title' => 'Header 2', 'format' => 'h2'],
7926  ['title' => 'Header 3', 'format' => 'h3'],
7927  ['title' => 'Header 4', 'format' => 'h4'],
7928  ['title' => 'Header 5', 'format' => 'h5'],
7929  ['title' => 'Header 6', 'format' => 'h6']
7930  ]
7931  ],
7932  'inline' => [
7933  'title' => 'Inline',
7934  'items' => [
7935  ['title' => 'Bold', 'icon' => 'bold', 'format' => 'bold'],
7936  ['title' => 'Italic', 'icon' => 'italic', 'format' => 'italic'],
7937  ['title' => 'Underline', 'icon' => 'underline', 'format' => 'underline'],
7938  ['title' => 'Strikethrough', 'icon' => 'strike-through', 'format' => 'strikethrough'],
7939  ['title' => 'Superscript', 'icon' => 'superscript', 'format' => 'superscript'],
7940  ['title' => 'Subscript', 'icon' => 'subscript', 'format' => 'subscript'],
7941  ['title' => 'Code', 'icon' => 'sourcecode', 'format' => 'code']
7942  ]
7943  ],
7944  'blocks' => [
7945  'title' => 'Blocks',
7946  'items' => [
7947  ['title' => 'Paragraph', 'format' => 'p'],
7948  ['title' => 'Blockquote', 'format' => 'blockquote'],
7949  ['title' => 'Div', 'format' => 'div'],
7950  ['title' => 'Pre', 'format' => 'pre']
7951  ]
7952  ],
7953  'alignment' => [
7954  'title' => 'Alignment',
7955  'items' => [
7956  ['title' => 'Left', 'icon' => 'align-left', 'format' => 'alignleft'],
7957  ['title' => 'Center', 'icon' => 'align-center', 'format' => 'aligncenter'],
7958  ['title' => 'Right', 'icon' => 'align-right', 'format' => 'alignright'],
7959  ['title' => 'Justify', 'icon' => 'align-justify', 'format' => 'alignjustify']
7960  ]
7961  ]
7962  ];
7963 
7964  // Bei aktiver Checkbox "Einschwärzen aktivieren" unter Mandant -> Editor die Option PDF einschwärzen unter Formate -> Inline in TinyMCE anzeigen
7965  if ($this->getSite()->admin['editor']['allow_classified']) {
7966  $formats['inline']['items'][] = ['title' => 'Im Druck einschwärzen', 'icon' => 'invert', 'inline' => 'span', 'classes' => 'egotec-classified'];
7967  }
7968 
7969  // Individuelle Formate
7970  if (isset($this->conf['formats'])) {
7971  $custom_formats = $type && isset($this->conf['formats'][$type])
7972  ? $this->conf['formats'][$type] // Formate für einen bestimmten Editor anpassen
7973  : $this->conf['formats']['default']; // Formate für alle Editoren anpassen
7974 
7975  if (is_array($custom_formats)) {
7976  foreach ($custom_formats as $name => $values) {
7977  // Wenn es die Format Liste gibt, wird sie erweitert/überschrieben
7978  if (isset($formats[$name])) {
7979  // Standard Formate überschreiben
7980  if (is_array($values) && $values['options']) {
7981  $new_items = [];
7982 
7983  foreach (explode(',', $values['options']) as $option) {
7984  foreach ($formats[$name]['items'] as $item) {
7985  if ($item['format'] == $option) {
7986  // Die Sortierung der Standard Formate entspricht der angegebenen Reihenfolge
7987  $new_items[] = $item;
7988  break;
7989  }
7990  }
7991  }
7992  $formats[$name]['items'] = $new_items;
7993  }
7994 
7995  if (isset($values) && empty($values)) {
7996  // Wenn es keine Formate gibt, wird auch keine Liste angezeigt
7997  unset($formats[$name]);
7998  } elseif (is_array($values) && isset($values['items'])) {
7999  // Formate nur bearbeiten, wenn es eigene gibt
8000 
8001  if ($values['merge']) {
8002  // Existierende Formate erweitern
8003  $items = $formats[$name]['items'];
8004 
8005  if (is_array($values['items'])) {
8006  foreach ($values['items'] as $custom_item) {
8007  if (($index = array_search($custom_item['title'], array_column($items, 'title'))) !== false) {
8008  $items[$index] = $custom_item;
8009  } else {
8010  $items[] = $custom_item;
8011  }
8012  }
8013  }
8014  } else if (is_array($values['items'])) {
8015  // Existierende Formate überschreiben
8016  $items = $values['items'];
8017  }
8018 
8019  if (!empty($items)) {
8020  $formats[$name] = [
8021  'title' => $formats[$name]['title'],
8022  'items' => $items
8023  ];
8024  } else {
8025  // Wenn es keine Formate gibt, wird auch keine Liste angezeigt
8026  unset($formats[$name]);
8027  }
8028  }
8029  } else {
8030  // Neue Format Liste hinzufügen
8031  $formats[$name] = $values;
8032  }
8033  }
8034  }
8035  }
8036 
8037  return array_values($formats);
8038  }
8039 
8046  public function getToolbar($type = '') {
8047  $result = array(
8048  'plugins' => '',
8049  'menubar' => '',
8050  'toolbar' => '',
8051  'contextmenu' => '',
8052  'menu' => [
8053  'edit' => [
8054  'title' => 'Edit',
8055  'items' => 'undo redo | pastetext selectall | searchreplace'
8056  ],
8057  'insert' => [
8058  'title' => 'Insert',
8059  'items' => 'link | charmap egotecIcons | anchor | egotecAccessibility'
8060  ],
8061  'view' => [
8062  'title' => 'View',
8063  'items' => 'visualaid visualchars visualblocks'
8064  ],
8065  'table' => [
8066  'title' => 'Table',
8067  'items' => 'inserttable | cell row column | tableprops deletetable'
8068  ],
8069  'tools' => [
8070  'title' => 'Tools',
8071  'items' => 'egotecCode | help'
8072  ]
8073  ]
8074  );
8075 
8076  // Standard Toolbar
8077  switch ($type) {
8078  case 'editor':
8079  $result['plugins'] = 'advlist autolink lists egotecLink image charmap anchor searchreplace visualblocks visualchars media table importcss help '
8080  . 'egotecSpellchecker egotecPageFrame egotecImageScale egotecList egotecMaxLength egotecIcons egotecAccessibility';
8081  $result['menubar'] = 'edit insert view table tools';
8082  $result['toolbar'] = 'styles removeformat | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist egotecBullist egotecNumlist | outdent indent | media image link unlink | egotecSpellchecker';
8083  $result['menu']['insert']['items'] .= ' | image media | table';
8084  $result['contextmenu'] = 'table | ';
8085  break;
8086 
8087  case 'content':
8088  $result['plugins'] = 'advlist autolink lists egotecLink charmap anchor searchreplace visualblocks visualchars importcss help '
8089  . 'egotecSpellchecker egotecSplit egotecList egotecMaxLength egotecIcons egotecAccessibility';
8090  $result['menubar'] = 'edit insert view tools';
8091  $result['toolbar'] = 'styles removeformat | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist egotecBullist egotecNumlist | outdent indent | link unlink | egotecSpellchecker | egotecSplit';
8092  break;
8093 
8094  case 'minimal':
8095  $result['plugins'] = 'autolink egotecLink anchor '
8096  . 'egotecSpellchecker egotecSplit egotecAccessibility';
8097  $result['toolbar'] = 'bold italic | link unlink | egotecSpellchecker | egotecSplit';
8098  break;
8099 
8100  case 'table':
8101  $result['plugins'] = 'advlist autolink lists egotecLink charmap anchor searchreplace visualblocks visualchars table importcss help '
8102  . 'egotecSpellchecker egotecList egotecMaxLength egotecAccessibility egotecTable';
8103  $result['menubar'] = 'edit insert view tools';
8104  $result['toolbar'] = 'styles removeformat | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist egotecBullist egotecNumlist | outdent indent | link unlink | egotecSpellchecker | egotecSplit';
8105  $result['contextmenu'] = 'cell row column | ';
8106  break;
8107 
8108  case 'text':
8109  $result['plugins'] = 'egotecSpellchecker egotecSplit egotecPlainText egotecMaxLength egotecAccessibility';
8110  $result['toolbar'] = 'egotecSpellchecker | egotecSplit';
8111  }
8112 
8113  // Alle Editoren verwenden das selbe Kontextmenü
8114  $result['contextmenu'] .= 'link | egotecAccessibility egotecSpellchecker-suggestions';
8115 
8116  if ($this->_site->hasRight("admin")) {
8117  // Quelltext Plugin hinzufügen
8118  $result['plugins'] .= ' egotecCode';
8119  }
8120 
8121  // Das "egotecFix" Plugin immer laden
8122  $result['plugins'] .= ' egotecFix';
8123 
8124  // Individuelle Toolbar
8125  if (!empty($this->conf['toolbar'])) {
8126  $custom_toolbar = $this->conf['toolbar'][$type];
8127  foreach (array_keys($result) as $name) {
8128  if (isset($custom_toolbar[$name])) {
8129  if (in_array($custom_toolbar[$name], ['', false], true)) {
8130  $result[$name] = false;
8131  } elseif (preg_match_all('/[+-]?[^+-]+/', $custom_toolbar[$name], $matches) !== false) {
8132  foreach ($matches[0] as $toolbar) {
8133  $toolbar = trim(str_replace(',', ' ', rtrim($toolbar, ',')), ' |');
8134  if (strpos($toolbar, '+') === 0) {
8135  // Eigenschaften hinzufügen
8136  $result[$name] .= ' ' . substr($toolbar, 1);
8137  } elseif (strpos($toolbar, '-') === 0) {
8138  // Eigenschaften entfernen
8139  $pattern = '/(^| )(' . str_replace(' ', '|', preg_quote(substr($toolbar, 1))) . ')(|$)/';
8140  $result[$name] = preg_replace($pattern, '', $result[$name]);
8141  } else {
8142  // Eigenschaften überschreiben
8143  $result[$name] = $toolbar;
8144  }
8145  }
8146  }
8147  }
8148  }
8149  }
8150 
8151  return $result;
8152  }
8153 
8160  public function getHtml($root = false) {
8161  $html = '';
8162  $type_path = explode('/', $this->field['type']);
8163  $type_info = $this->getTypeInfo();
8164  $inherit = isset($type_info['inherit']) ? explode(',', (string) $type_info['inherit']) : [
8165  'style', 'script' // Alles erben
8166  ];
8167  $variant = '';
8168  if ($this->extra['_style']) {
8169  $variant = '.'.$this->extra['_style'];
8170  }
8171  $suffix = $_SERVER['REQUEST_SUFFIX'] != '.html' ? $_SERVER['REQUEST_SUFFIX'] : '';
8172  $current_path = '';
8173  foreach ($type_path as $path) {
8174  $current_path .= $path.'/';
8175  if (
8176  (
8177  in_array('style', $inherit)
8178  || rtrim($current_path, '/') == $this->field['type']
8179  )
8180  && (
8181  ($suffix != '' && ($src = $this->_site->getSkinFile($current_path.'style'.$suffix.'.css', array('system'), true)))
8182  || ($variant != '' && ($src = $this->_site->getSkinFile($current_path.'style'.$variant.'.css', array('system'), true)))
8183  || ($src = $this->_site->getSkinFile($current_path.'style.css', array('system'), true))
8184  )
8185  ) {
8186  $html .= Ego_System::includeHtml($src);
8187  }
8188  if (
8189  (
8190  in_array('script', $inherit)
8191  || rtrim($current_path, '/') == $this->field['type']
8192  )
8193  && ($src = $this->_site->getSkinFile($current_path.'script.js', array(), true))
8194  ) {
8195  $html .= Ego_System::includeHtml($src);
8196  }
8197  }
8198 
8199  // style.css und script.js aus dem root Verzeichnis einbinden
8200  if ($root) {
8201  if (
8202  ($suffix != '' && ($src = $this->_site->getSkinFile('style'.$suffix.'.css', array('system'), true)))
8203  || ($variant != '' && ($src = $this->_site->getSkinFile('style'.$variant.'.css', array('system'), true)))
8204  || ($src = $this->_site->getSkinFile('style.css', array('system'), true))
8205  ) {
8206  $html .= Ego_System::includeHtml($src);
8207  }
8208  if ($src = $this->_site->getSkinFile('script.js', array('system'), true)) {
8209  $html .= Ego_System::includeHtml($src);
8210  }
8211  }
8212 
8213  return $html;
8214  }
8215 
8222  protected function getOrient($orient = null) {
8223  if ($orient === null) {
8224  $orient = $this->mainOrient; // Standardwert
8225  if (isset($this->blockProperties['_orient'])) {
8226  $orient = $this->blockProperties['_orient'];
8227  }
8228  }
8229  return $orient;
8230  }
8231 
8238  protected function getIndex($index = null) {
8239  if ($index === null) {
8240  $index = 0; // Standardwert
8241  if (isset($this->blockProperties['_index'])) {
8242  $index = $this->blockProperties['_index'];
8243  }
8244  }
8245  return $index;
8246  }
8247 
8257  public function getValue($name, $orient = null, $index = null, $verbose = false) {
8258  // Orientierung und Index automatisch setzen
8259  $orient = $this->getOrient($orient);
8260  $index = $this->getIndex($index);
8261 
8262  // Mehrere Werte prüfen
8263  if (strpos($name, ',') !== false) {
8264  foreach (explode(',', $name) as $sub_name) {
8265  $value = $this->getValue($sub_name, $orient, $index, $verbose);
8266  if ($value !== null) {
8267  return $value;
8268  }
8269  }
8270  }
8271 
8272  // Einen Wert in einem Array finden
8273  if (($pos = strpos($name, '.?.')) !== false) {
8274  $array = $this->getValue(substr($name, 0, $pos), $orient, $index, $verbose);
8275  if (is_array($array)) {
8276  foreach ($array as $i => $value) {
8277  $value = $this->getValue(substr($name, 0, $pos) . ".$i." . substr($name, $pos + 3), $orient, $index, $verbose);
8278  if ($value !== null) {
8279  return $value;
8280  }
8281  }
8282  }
8283  return null;
8284  }
8285 
8286  // Zu durchsuchende Werte
8287  $extra = unserialize($this->field['extra']);
8288 
8289  $value = Ego_System::getAssocValue($extra, implode('.', array('_contents', $orient, $index, $name)));
8290  if ($value !== null) {
8291  if ($verbose) {
8292  // Alle zugehörigen Werte ebenfalls zurückliefern
8293  $array = array(
8294  'value' => $value
8295  );
8296  if (($pos = strrpos($name, '.')) !== false) {
8297  $key = implode('.', array('_contents', $orient, $index, substr($name, 0, $pos)));
8298  $name = substr($name, $pos + 1);
8299  } else {
8300  $key = implode('.', array('_contents', $orient, $index));
8301  }
8302  $values = Ego_System::getAssocValue($extra, $key);
8303  if (is_array($values)) {
8304  foreach ($values as $key => $value) {
8305  if (strpos($key, "{$name}_") === 0) {
8306  $array[substr($key, strlen("{$name}_"))] = $value;
8307  } elseif ($key == 'extra') {
8308  $array[$key] = $value;
8309  }
8310  }
8311  }
8312  return $array;
8313  } else {
8314  return $value;
8315  }
8316  }
8317  return null;
8318  }
8319 
8328  public function getValues($name, $orient = null, $verbose = false) {
8329  // Orientierung automatisch setzen
8330  $orient = $this->getOrient($orient);
8331 
8332  $values = array();
8333  if (is_array($this->extra['_contents'][$orient])) {
8334  $list = $this->extra['_contents'][$orient];
8335  if (is_array($list)) {
8336  foreach (array_keys($list) as $index) {
8337  $value = $this->getValue($name, $orient, $index, $verbose);
8338  if ($value !== null) {
8339  $values[] = $value;
8340  }
8341  }
8342  }
8343  }
8344  return $values;
8345  }
8346 
8355  public function getFirstValue($name, $orient = null, $verbose = false) {
8356  // Orientierung automatisch setzen
8357  $orient = $this->getOrient($orient);
8358 
8359  if (is_array($this->extra['_contents'][$orient])) {
8360  $list = $this->extra['_contents'][$orient];
8361  if (is_array($list)) {
8362  foreach (array_keys($list) as $index) {
8363  $value = $this->getValue($name, $orient, $index, $verbose);
8364  if ($value !== null) {
8365  return $value;
8366  }
8367  }
8368  }
8369  }
8370  return null;
8371  }
8372 
8384  public function getFirstMediaValue(string $name, string $type = 'image', string $orient = null, bool $verbose = false) {
8385  $orient = $this->getOrient($orient);
8386  $list = $this->extra['_contents'][$orient];
8387 
8388  if (is_array($list)) {
8389  foreach (array_keys($list) as $index) {
8390  $value = $this->getValue($name, $orient, $index, $verbose);
8391  if ($value !== null && $this->extra['_contents'][$orient][$index][$name . '_type'] == $type) {
8392  return $value;
8393  }
8394  }
8395  }
8396  return null;
8397  }
8398 
8399 
8410  public function getBlockValue($block, $name, $orient = null, $index = null, $verbose = false) {
8411  // Orientierung und Index automatisch setzen
8412  $orient = $this->getOrient($orient);
8413  $index = $this->getIndex($index);
8414 
8415  if ($this->extra['_blocks'][$orient][$index] == $block) {
8416  $value = $this->getValue($name, $orient, $index, $verbose);
8417  if ($value !== null) {
8418  return $value;
8419  }
8420  }
8421  return null;
8422  }
8423 
8433  public function getBlockValues($block, $name, $orient = null, $verbose = false) {
8434  // Orientierung automatisch setzen
8435  $orient = $this->getOrient($orient);
8436 
8437  $values = array();
8438  if (is_array($this->extra['_blocks'][$orient])) {
8439  foreach ($this->extra['_blocks'][$orient] as $index => $block_name) {
8440  if ($block_name == $block) {
8441  $value = $this->getValue($name, $orient, $index, $verbose);
8442  if ($value !== null) {
8443  $values[] = $value;
8444  }
8445  }
8446  }
8447  }
8448  return $values;
8449  }
8450 
8460  public function getFirstBlockValue($block, $name, $orient = null, $verbose = false) {
8461  // Orientierung automatisch setzen
8462  $orient = $this->getOrient($orient);
8463 
8464  if (is_array($this->extra['_blocks'][$orient])) {
8465  foreach ($this->extra['_blocks'][$orient] as $index => $block_name) {
8466  if ($block_name == $block) {
8467  $value = $this->getValue($name, $orient, $index, $verbose);
8468  if ($value !== null) {
8469  return $value;
8470  }
8471  }
8472  }
8473  }
8474  return null;
8475  }
8476 
8485  public function merge($id, $replicate = true) {
8486  if (!isset($GLOBALS['__egotec_skip_replication'])) {
8487  $GLOBALS['__egotec_skip_replication'] = 'merge';
8488  }
8489 
8490  $original_page = $this->_site->getPage($id, array(
8491  'auth_or' => '1=1',
8492  'deleted_or' => '1=1',
8493  'inactive' => true,
8494  'only_active' => false
8495  ));
8496  if (!$original_page) {
8497  return null;
8498  }
8499  $field = $this->field;
8500  $extra = $this->extra;
8501 
8502  unset($field['children']);
8503  if ($field['children_order'] == 'children') {
8504  // Die Reihenfolge der Kinder neu festlegen
8505  $children_list = array();
8506  $original_children = explode(',', trim($extra['original_children'], ','));
8507  $current_children = $original_page->getChildren(array(), array('auth_or' => '1=1'));
8508  $current_children_list = array();
8509  foreach ($current_children as $child) {
8510  $current_children_list[] = $child->field['id'];
8511  }
8512  foreach ($original_children as $child_id) {
8513  $key = array_search($child_id, $current_children_list);
8514  if ($key !== false) {
8515  $children_list[] = $child_id;
8516  unset($current_children_list[$key]);
8517  }
8518  }
8519  $children_list = array_merge($children_list, $current_children_list);
8520  }
8521 
8522  $field['inactive'] = $extra['original_inactive'];
8523 
8525  unset(
8526  $extra['original_id'],
8527  $extra['original_children'], // @TODO Die original_children werden nicht gelöscht.
8528  $extra['original_inactive'],
8529  $extra['workflow_page']
8530  );
8531  if ($extra['original_parents']) {
8532  $original_parents = $extra['original_parents'];
8533  unset($extra['original_parents']);
8534  }
8535 
8536  // Alle neu erstellten Kinder auf das Original übertragen.
8537  $children = $this->getChildren();
8538  foreach ($children as $child) {
8539  $child->move($this->field['id'], $original_page->field['id']);
8540  $child->updateField(array('inactive' => self::ACTIVE_FLAG));
8541  }
8542 
8543  unset($field['id']);
8544  unset($field['parents']);
8545  unset($field['workflow_state']);
8546  if (isset($original_page->field['workflow'])) {
8547  $field['workflow'] = $original_page->field['workflow'];
8548  } else {
8549  unset($field['workflow']);
8550  }
8551  if (isset($original_page->extra['workflows'])) {
8552  $extra['workflows'] = $original_page->extra['workflows'];
8553  } else {
8554  unset($extra['workflows']);
8555  }
8556 
8557  // Ist die Zielseite eine Freigabekopie, dann wird dieser Status beibehalten
8558  if (!$original_page->isReleaseCopy()) {
8559  unset($extra['release_id']);
8560  if ($field['inactive'] == self::RELEASE_FLAG) {
8561  $field['inactive'] = 0;
8562  }
8563  }
8564 
8565  if (!is_numeric($field['inactive'])) {
8566  $field['inactive'] = 0; // Im Zweifel immer aktivieren
8567  }
8568  // Liegt das Freigabe ab Datum in der Zukunft, wird es entfernt (nur für Freigabekopien)
8569  if ($this->isReleaseCopy() && $field['release_from'] > date('Y-m-d H:i:s')) {
8570  $field['release_from'] = '0000-00-00 00:00:00';
8571  }
8572 
8573  $update = array(
8574  'field' => $field,
8575  'extra' => $extra
8576  );
8577 
8578  if ($children_list) {
8579  $update['children'] = $children_list;
8580  }
8581 
8582  if ($original_parents) {
8583  $current_parents = array();
8584  foreach ($this->getParents(array('fields' => 'id')) as $parent) {
8585  $current_parents[] = $parent->field['id'];
8586  }
8587  $update['parents'] = $current_parents;
8588  }
8589 
8590  $original_page->field = array_merge($original_page->field, $update['field']);
8591  if ($original_page->extra['release_ids']) {
8592  // Freigabekopie Liste aktualisieren
8593  $update['extra']['release_ids'] = array_values(array_diff($original_page->extra['release_ids'], array($this->field['id'])));
8594  }
8595  $original_page->extra = $update['extra']; // Nicht zusammenführen. Das neue Extra überschreibt das alte komplett.
8596 
8597  /* Evtl. vorhandene MM-Datei kopieren */
8598  if (Ego_System::file_exists($GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename())) {
8600  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename(),
8601  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$original_page->getMediaFilename(true)
8602  );
8603  }
8604 
8605  // Mediapool kopieren
8606  $this->getMediapool()->copy($original_page, $this->getMediapool()->currentDir);
8607  $this->getMediapool()->copy($original_page, 'workflow', false, true);
8608 
8609  // Jetzt Bearbeitungsdatum ändern und Archiveintrag anlegen
8610  $original_page->update([
8611  'field' => $original_page->field,
8612  'extra' => $original_page->extra,
8613  'parents' => $update['parents'],
8614  'children' => $update['children']
8615  ]);
8616 
8617  $this->delete();
8618 
8619  if ($replicate) {
8620  $this->replicate('merge', $id);
8621  }
8622 
8623  return $original_page;
8624  }
8625 
8632  public function newRelease($date = '') {
8633  if (!isset($GLOBALS['__egotec_skip_replication'])) {
8634  $GLOBALS['__egotec_skip_replication'] = 'newRelease';
8635  }
8636 
8637  if ($this->field['inactive'] != self::RELEASE_FLAG) {
8638  $this->archiveOnly = false;
8639  $field = $this->field;
8640  $extra = $this->extra;
8641  unset($field['id']);
8642  $field['inactive'] = self::RELEASE_FLAG;
8643  if ($date != '') {
8644  $field['release_from'] = $date;
8645  }
8646 
8647  if ($this->isWorkflowCopy()) {
8648  // Wenn es sich um eine Workflowkopie handelt wird diese zur Freigabekopie
8649  $extra['release_id'] = $extra['original_id'];
8650  unset($extra['original_id']);
8651  $new_page = $this;
8652  } else {
8653  // Eine neue Freigabekopie erstellen
8654  $extra['release_id'] = $this->field['id'];
8655  unset($extra['release_ids']);
8656  $parents = $this->getParents(array(), array('auth_or' => '1=1'));
8657  if ($parent = $parents->nextPage()) {
8658  $new_page = $parent->newChild($field, $extra);
8659  }
8660  if (empty($new_page)) {
8661  // Existiert keine Elternseite, dann unter sich selbst erstellen (Startseite)
8662  $new_page = $this->newChild($field, $extra);
8663  }
8664  }
8665  if ($new_page) {
8666  // Freigabekopie Liste aktualisieren
8667  $original_page = $this->_site->getPage($extra['release_id'], array(
8668  'only_active' => false,
8669  'inactive' => true
8670  ));
8671  $extra = $original_page->extra;
8672  if (!is_array($extra['release_ids'])) {
8673  $extra['release_ids'] = array();
8674  }
8675  $extra['release_ids'][] = $new_page->field['id'];
8676  $extra['release_ids'] = array_unique($extra['release_ids']);
8677  $original_page->updateExtra($extra, true, true);
8678 
8679  $this->replicate('newRelease', $date);
8680 
8681  return $new_page;
8682  }
8683  }
8684 
8685  return null;
8686  }
8687 
8693  public function release() {
8694  if (!isset($GLOBALS['__egotec_skip_replication'])) {
8695  $GLOBALS['__egotec_skip_replication'] = 'release';
8696  }
8697 
8698  if ($this->isReleaseCopy()) {
8699  // Gibt es ein Freigabe bis Datum, wird vom Original eine neue Freigabekopie mit Freigabe ab Datum angelegt
8700  if (
8701  $this->field['release_until'] != '0000-00-00 00:00:00'
8702  && ($original_page = $this->_site->getPage($this->extra['release_id'], array(
8703  'inactive' => true,
8704  'only_active' => false
8705  )))
8706  && $original_page->field['release_until'] == '0000-00-00 00:00:00' // Nur wenn das Original kein Freigabe bis Datum hat
8707  ) {
8708  $release_ids = $original_page->extra['release_ids'] ?? array();
8709  $original_page->extra['release_ids'] = array_values(array_diff($release_ids, array($this->field['id'])));
8710  $GLOBALS['new_release'] = $original_page->newRelease($this->field['release_until']);
8711 
8712  // Das Freigabe bis Datum muss bei der aktuellen Veröffentlichung entfernt werden
8713  $this->field['release_until'] = '0000-00-00 00:00:00';
8714  }
8715 
8716  $this->replicate('release');
8717 
8718  return $this->merge($this->extra['release_id'], false);
8719  }
8720  return null;
8721  }
8722 
8728  public function getWorkflowHistory() {
8729  require_once 'workflow/Ego_Workflow.php';
8730  require_once 'base/template/Ego_Template_Mail.php';
8731  require_once 'base/Ego_Combo.php';
8732  require_once 'rights/User_SQL.php';
8733 
8734  $history = array();
8735 
8736  $tmp_history = $this->extra['history'];
8737  if (is_array($this->extra['history'])) {
8738  $deleted = 0;
8739  foreach ($this->extra['history'] as $workflow_id => $list) {
8740  if (!is_array($list)) {
8741  continue;
8742  }
8743 
8744  $workflow = new Ego_Workflow($workflow_id);
8745  $group = array();
8746  $grouped_list = array();
8747 
8748  ksort($list, SORT_NUMERIC);
8749  foreach ($list as $time => $entry) {
8750  $cleared = false;
8751  $clear = false;
8752  if ($entry['old_phase'] == '-' && !$group['start']) {
8753  // Start
8754  $group['start'] = $time;
8755  } elseif ($entry['old_phase'] == '-' && $group['start']) {
8756  // Abgebrochen ohne Ende
8757  $grouped_list[] = $group;
8758  $group = array();
8759  $group['start'] = $time;
8760  } elseif (
8761  (
8762  $entry['new_phase'] == '1'
8763  && (
8764  !$entry['comment']
8765  || !preg_match(
8766  '/^\{APPROVAL:.*?\}$/msi',
8767  $entry['comment']
8768  ) // Genehmigung für den letzten Status
8769  )
8770  )
8771  || $entry['new_phase'] == 'c'
8772  ) {
8773  // Ende
8774  $group['end'] = $time;
8775  $clear = true;
8776  }
8777 
8778  // Benutzername
8779  if ($entry['user'] != 'SYSTEM') {
8780  $user = new_db_connection(array(
8781  'table' => 'egotec_user',
8782  'where' => 'user_id = :user_id',
8783  'bind' => array(
8784  'user_id' => $entry['user']
8785  )
8786  ));
8787  if ($user->nextRecord()) {
8788  $user_sql = new User_SQL($user->Record['user_id'], $user->Record);
8789  $entry['username'] = $user_sql->getFullname();
8790  }
8791  }
8792 
8793  // Status
8794  $entry['old_phase_name'] = $workflow->extra['phases'][$entry['old_phase']]['name'];
8795  $entry['new_phase_name'] = $workflow->extra['phases'][$entry['new_phase']]['name'];
8796  if (preg_match('/^\{SWITCH:([^:]+):([^:]+)\}$/ims', $entry['comment'], $matches)) {
8797  $from = new Ego_Workflow($matches[1]);
8798  $to = new Ego_Workflow($matches[2]);
8799  $msg = $GLOBALS['auth']->translate('Wechsel von <b>%from</b> nach <b>%to</b>');
8800  $msg = str_replace('%from', $from->field['name'], $msg);
8801  $msg = str_replace('%to', $to->field['name'], $msg);
8802  $entry['comment'] = '';
8803  $entry['system'] = $msg;
8804  }
8805 
8806  // Freigeber
8807  if (preg_match('/^\{APPROVAL:([^:]+)\}$/ims', $entry['comment'], $matches)) {
8808  $msg = $GLOBALS['auth']->translate('Genehmigung von <b>%user</b>');
8809  try {
8810  $user = new User_SQL($matches[1]);
8811  $msg = str_replace('%user', $user->getFullname(), $msg);
8812  } catch (User_Exception $e) {
8813  $msg = str_replace('%user', $GLOBALS['auth']->translate('unbekannt'), $msg);
8814  }
8815  $entry['comment'] = '';
8816  $entry['system'] = $msg;
8817  }
8818 
8819  // Informationen zu den Aktionen
8820  if (is_array($entry['actions'])) {
8821  foreach ($entry['actions'] as $key => $action) {
8822  $info = '';
8823  switch ($action['type']) {
8824  case 'move':
8825  if ($action['parent']) {
8826  $parent = Ego_System::urltopage($action['parent']);
8827  if ($parent) {
8828  $info = $GLOBALS['auth']->translate('Die Seite wurde verschoben nach %parent.');
8829  $parent_site = $parent->getSite();
8830  $url = $GLOBALS['egotec_conf']['url_dir'].'admin.php?site='.$parent_site->name.'&lang='.$parent_site->language.'&list='.$parent->field['id'];
8831  $info = str_replace('%parent', '<a href="'.$url.'">'.$parent->field['name'].'</a>', $info);
8832  }
8833  }
8834  break;
8835  case 'cancel':
8836  // Keine Informationen
8837  break;
8838  case 'switch':
8839  if ($action['workflow']) {
8840  $new_workflow = new Ego_Workflow($action['workflow']);
8841  $info = $GLOBALS['auth']->translate('Der Workflow wurde gewechselt zu %workflow.');
8842  $info = str_replace('%workflow', $new_workflow->field['name'], $info);
8843  }
8844  break;
8845  case 'email':
8846  if ($action['template']) {
8847  $list = array();
8848  try {
8849  if (is_string($action['recipients'])) {
8850  $recipients = (array) json_decode($action['recipients']);
8851  if (!empty($recipients)) {
8852  foreach ($recipients as $type => $combo) {
8853  $combo = new Ego_Combo($combo);
8854  switch ($type) {
8855  case 'cc':
8856  $suffix = ' (<span style=\'color:#2dabff !important;\'>CC</span>)';
8857  break;
8858  case 'bcc':
8859  $suffix = ' (<span style=\'color:#e63f2d !important;\'>BCC</span>)';
8860  break;
8861  default:
8862  $suffix = '';
8863  }
8864  foreach ($combo->getRights() as $r) {
8865  $list[] = '<b>'.$r['group']->field['group_name'].'/'.$r['role']->field['role_name'].'</b>'.$suffix;
8866  }
8867  foreach ($combo->getUsers() as $u) {
8868  $list[] = '<u>'.$u->getFullname().'</u>'.$suffix;
8869  }
8870  foreach ($combo->getText() as $text) {
8871  $list[] = '<i>'.$text.'</i>'.$suffix;
8872  }
8873  }
8874  }
8875  }
8876  if (!empty($list)) {
8877  $info = $GLOBALS['auth']->translate('Die E-Mail wurde versendet an:').'<br/>';
8878  $info .= implode(', ', $list);
8879  } else {
8880  try {
8881  $template = new Ego_Template_Mail($action['template']);
8882  $info = $GLOBALS['auth']->translate('Die E-Mail wurde versendet an die Empfänger des Templates:').'<br/>'.$template->field['name'];
8883  } catch (Ego_Template_Exception $e) {
8884  $info = $GLOBALS['auth']->translate('Die E-Mail wurde nicht versendet, da ein ungültiges Template ausgewählt ist.');
8885  }
8886  }
8887  } catch (Exception $e) {
8888  // Ignorieren
8889  }
8890  }
8891  break;
8892  case 'editor':
8893  $list = array();
8894  if (is_string($action['combo'])) {
8895  $combo = new Ego_Combo($action['combo']);
8896 
8897  foreach ($combo->getRights() as $r) {
8898  $list[] = '<b>'.$r['group']->field['group_name'].'/'.$r['role']->field['role_name'].'</b>';
8899  }
8900  foreach ($combo->getUsers() as $u) {
8901  $list[] = '<u>'.$u->getFullname().'</u>';
8902  }
8903  }
8904  if (!empty($list)) {
8905  $info = $GLOBALS['auth']->translate('Folgende Bearbeiter wurden ausgewählt:').'<br/>';
8906  $info .= implode(', ', $list);
8907  }
8908  break;
8909  case 'approval':
8910  $list = array();
8911  if (is_string($action['approval_users'])) {
8912  $combo = new Ego_Combo($action['approval_users']);
8913 
8914  foreach ($combo->getUsers() as $u) {
8915  $list[] = '<u>'.$u->getFullname().'</u>';
8916  }
8917  }
8918  if (!empty($list)) {
8919  $info = $GLOBALS['auth']->translate('Folgende Freigeber wurden ausgewählt:').'<br/>';
8920  $info .= implode(', ', $list);
8921  }
8922  break;
8923  case 'script':
8924  if ($action['file']) {
8925  $info = $GLOBALS['auth']->translate('Folgendes Skript wurde ausgeführt:').'<br/>';
8926  $info .= $action['file'];
8927  }
8928  }
8929  if (empty($info)) {
8930  $info = $GLOBALS['auth']->translate('Es sind keine Informationen verfügbar.');
8931  }
8932  $entry['actions'][$key]['_info'] = $info;
8933  }
8934  }
8935 
8936  if (!is_array($group['list'])) {
8937  $group['list'] = array();
8938  }
8939  $entry['time'] = $time;
8940  $group['list'][$time] = $entry;
8941  if ($clear) {
8942  $grouped_list[] = $group;
8943  $group = array();
8944  $cleared = true;
8945  }
8946  }
8947  if (empty($cleared) && !empty($group)) {
8948  // Die laufende Historie auch anzeigen wenn diese nicht abgeschlossen ist
8949  $grouped_list[] = $group;
8950  }
8951 
8952  $history[] = array(
8953  'id' => $workflow_id,
8954  'name' => $workflow->field['name'],
8955  'list' => $grouped_list
8956  );
8957  }
8958  }
8959 
8960  return $history;
8961  }
8962 
8968  public function isWorkflowCopy() {
8969  return ($this->field['workflow'] && $this->extra['original_id']);
8970  }
8971 
8977  public function isReleaseCopy() {
8978  return ($this->extra['release_id'] && $this->field['inactive'] == self::RELEASE_FLAG);
8979  }
8980 
8986  public function isClone() {
8987  return !empty($this->extra['clone_original']);
8988  }
8989 
8995  public function isLanguageLink()
8996  {
8997  return ($this->extra['language_link'][$this->getSite()->language] && $this->extra['language_standard'] != $this->getSite()->language);
8998  }
8999 
9005  public function isArchive() {
9006  return $this->archiveOnly || $this->getTableSuffix() == '_v';
9007  }
9008 
9014  public function isActive() {
9015  return !$this->field['inactive']
9016  && !$this->field['deleted']
9017  && ($this->field['release_from'] == '0000-00-00 00:00:00' || date('Y-m-d H:i:s') > $this->field['release_from'])
9018  && ($this->field['release_until'] == '0000-00-00 00:00:00' || date('Y-m-d H:i:s') < $this->field['release_until'])
9019  && !$this->isWorkflowCopy()
9020  && !$this->isReleaseCopy();
9021  }
9022 
9028  public function isClassified() {
9029  return $this->getSite()->admin['editor']['allow_classified'] && !empty($this->extra['_classified']);
9030  }
9031 
9037  public function getNonPublic() {
9038  if ($this->isPublicSave()) {
9039  $db = new_db_connection();
9040  $db->select(array(
9041  'table' => $this->_site->pageTable . '_v',
9042  'where' => 'id = :id AND m_date > :c_date',
9043  'order' => 'm_date DESC',
9044  'limit' => 1,
9045  'bind' => array(
9046  'id' => $this->field['id'],
9047  'c_date' => $this->lastChangeDate
9048  )
9049  ));
9050  if ($db->nextRecord()) {
9051  $class = $this->_site->getPageClass($db->Record['type']);
9052  return new $class($this->_site, $db->Record);
9053  }
9054  }
9055  return null;
9056  }
9057 
9063  public function isPublicSave() {
9064  return $this->_site->isPublicSave()
9065  && !$this->isWorkflowCopy()
9066  && !$this->isReleaseCopy()
9067  && ($info = $this->getTypeInfo(false))
9068  && !$info['no_public_save'];
9069  }
9070 
9076  public function isPublic() {
9077  if ($this->isPublicSave()) {
9078  return $this->lastChangeDate == $this->field['m_date'];
9079  }
9080  return true;
9081  }
9082 
9089  public function getLastChangeDate() {
9090  return $this->lastChangeDate;
9091  }
9092 
9099  public function getArchivePage($c_date = '') {
9100  $db = new_db_connection();
9101  $params = array(
9102  'table' => $this->_site->pageTable.'_v',
9103  'where' => 'id = :id',
9104  'order' => 'm_date DESC',
9105  'limit' => 1,
9106  'bind' => array(
9107  'id' => $this->field['id']
9108  )
9109  );
9110  if ($c_date) {
9111  // Archiveintrag zu einem bestimmten Zeitpunkt
9112  $params['where'] .= ' AND m_date = :c_date';
9113  $params['bind']['c_date'] = $c_date;
9114  }
9115  $db->select($params);
9116  if ($db->nextRecord()) {
9117  $page = clone $this;
9118  $page->setTableSuffix('_v');
9119  $page->field = $db->Record;
9120  $page->extra = $db->Record['extra']
9121  ? unserialize($db->Record['extra'])
9122  : array();
9123  return $page;
9124  }
9125  return null;
9126  }
9127 
9134  public function getArchivePages($query=array())
9135  {
9136  $query['table'] = $this->getSite()->pageTable . '_v';
9137  if ($query['where']) {
9138  $query['where'].= ' AND ';
9139  }
9140  $query['where'].= 'id=:id';
9141  $query['bind']['id'] = $this->field['id'];
9142  if (!isset($query['order'])) {
9143  $query['order'] = 'm_date DESC';
9144  }
9145  return new Page_Iterator($this->_site, new_db_connection($query));
9146  }
9147 
9154  public function restoreArchivPage($c_date)
9155  {
9156  $db = new_db_connection();
9157  $db->select(array(
9158  'table' => $this->getSite()->pageTable.'_v',
9159  'where' => "id=".$this->field['id']." AND m_date='".$c_date."'"
9160  ));
9161 
9162  if (!$db->nextRecord()) {
9163  return false;
9164  }
9165 
9166  /* Einige Daten werden nicht wieder aus dem Archiv überschrieben */
9167  $field = $db->Record;
9168  unset($field['id']);
9169  unset($field['children']);
9170  unset($field['parents']);
9171  $extra = unserialize($field['extra']);
9172 
9173  // Dazugehöriges Mediapool Archiv wiederherstellen
9174  $this->getMediapool()->restore(Ego_System::dateEncode($c_date));
9175 
9176  if (empty($extra['piwik']) && !empty($this->extra['piwik'])) {
9177  // Die Piwik Einstellungen beim Wiederherstellen beibehalten
9178  $extra['piwik'] = $this->extra['piwik'];
9179  }
9180  $this->update(array(
9181  'field' => $field,
9182  'extra' => $extra
9183  ));
9184 
9196  if ($file = $this->getSite()->getSiteFile($this->field['type'].'/admin/archive_restore.php')) {
9197  // Diese Variablen müssen zur Abwärtskompatibilität gesetzt sein
9198  $site = $this->getSite();
9199  $current_page = $this;
9200  $smarty = $GLOBALS['smarty'];
9201  require($file);
9202  }
9203 
9204  return true;
9205  }
9206 
9215  public function download($recursive = true, $target_dir = '', $write_log = true) {
9216  $log = $GLOBALS['egotec_conf']['log_dir'].'page_download-'.date('Y-m-d');
9217  if ($write_log) {
9218  file_put_contents($log, "\r\n===> ".date('Y-m-d H:i:s')
9219  ." Page Download für "
9220  ."{$this->_site->name}.{$this->_site->language}.{$this->field['id']}"
9221  ." beginnt:\r\n", FILE_APPEND);
9222  }
9223  if ($target_dir) {
9224  $dir = $target_dir;
9225  } else {
9226  $dir = $GLOBALS['egotec_conf']['tmp_dir'].'download'.md5(microtime()).'/';
9227  }
9228  $media_dir = $dir.'media/'.$this->_site->name.'/';
9229  if ($write_log) {
9230  file_put_contents($log, "Verzeichnisse anlegen\r\n", FILE_APPEND);
9231  }
9232  Ego_System::mkdir($dir);
9233  Ego_System::mkdir($media_dir);
9234  $params = array(
9235  'inactive' => true,
9236  'only_active' => false,
9237  'no_cache' => true,
9238  'auth_or' => '1=1'
9239  );
9240 
9241  $pages = array($this);
9242  if ($recursive) {
9243  if ($write_log) {
9244  file_put_contents($log, "Alle Nachfahren ermitteln\r\n", FILE_APPEND);
9245  }
9246  foreach ($this->getDescendants(
9247  array(),
9248  $params
9249  ) as $descendant) {
9250  $pages[] = $descendant;
9251  }
9252  }
9253 
9254  $data = array();
9255  $db = new_db_connection();
9256  Ego_System::mkdir($dir.'db/');
9257  foreach ($pages as $page) {
9258  if ($write_log) {
9259  file_put_contents($log, "Seite {$page->field['name']} ({$page->field['id']}) sichern\r\n", FILE_APPEND);
9260  }
9261  foreach ($this->_site->getLanguages() as $lang) {
9262  $lang_page = $page->getLanguagePage($lang);
9263  if ($write_log) {
9264  file_put_contents($log, "> Sprache {$lang} sichern\r\n", FILE_APPEND);
9265  }
9266 
9267  // Haupttabelle sichern
9268  $table = $this->_site->name.'_'.$lang;
9269  $db->select(array(
9270  'table' => $table,
9271  'fields' => '*',
9272  'where' => 'id = :id',
9273  'bind' => array(
9274  'id' => $page->field['id']
9275  )
9276  ));
9277  while ($db->nextRecord()) {
9278  $s = serialize($db->Record);
9279  $file = $dir.'db/'.$table;
9280  file_put_contents($file, strlen($s)."\n".$s, FILE_APPEND);
9281 
9282  $path = $GLOBALS['egotec_conf']['var_dir']
9283  .'media/'.$this->_site->name.'/';
9284 
9285  // Mediapool
9286  if (Ego_System::file_exists($path.$lang.'/pool/'.$page->field['id'].'/')) {
9287  if ($write_log) {
9288  file_put_contents($log, "> Mediapool sichern\r\n", FILE_APPEND);
9289  }
9290  Ego_System::mkdir($media_dir.$lang.'/pool/'.$page->field['id'].'/');
9292  $path.$lang.'/pool/'.$page->field['id'].'/',
9293  $media_dir.$lang.'/pool/'.$page->field['id'].'/'
9294  );
9295  }
9296 
9297  // Multimedia
9298  if (
9299  in_array($page->field['type'], array('multimedia/file', 'multimedia/image'))
9300  && $lang_page
9301  ) {
9302  if ($write_log) {
9303  file_put_contents($log, "> Datei sichern\r\n", FILE_APPEND);
9304  }
9305  $file = $lang_page->getMediaFilename();
9306  Ego_System::mkdir($dir.'media/'.$this->_site->name.'/'.$lang);
9307  @copy(
9308  $path.$file,
9309  $dir.'media/'.$this->_site->name.'/'.$lang.'/'.$page->field['id']
9310  );
9311  }
9312  }
9313 
9314  // Alle verknüpften Tabellen sichern
9315  $tables = array(
9316  'buchungen' => $table.'_buchungen',
9317  'children' => $table.'_children',
9318  'extra' => $table.'_extra',
9319  'infodienst' => $table.'_infodienst',
9320  'newsletter_light' => $table.'_newsletter_light',
9321  'rights' => $table.'_rights',
9322  'users' => $table.'_users',
9323  'keywords' => $this->_site->name.'_keywords_rel',
9324  'v' => $table.'_v'
9325  );
9326  if ($write_log) {
9327  file_put_contents($log, "> Verknüpfte Tabellen sichern\r\n", FILE_APPEND);
9328  }
9329  foreach ($tables as $key => $table) {
9330  if (!$db->tableExists($table)) {
9331  continue;
9332  }
9333  if ($write_log) {
9334  file_put_contents($log, ">> $table\r\n", FILE_APPEND);
9335  }
9336  switch ($key) {
9337  case 'newsletter_light':
9338  $where = 'abonnent_id = :id';
9339  break;
9340  case 'v':
9341  $where = 'id = :id';
9342  break;
9343  default:
9344  $where = 'page_id = :id';
9345  }
9346  $db->select(array(
9347  'table' => $table,
9348  'fields' => '*',
9349  'where' => $where,
9350  'bind' => array(
9351  'id' => $page->field['id']
9352  )
9353  ));
9354  while ($db->nextRecord()) {
9355  $s = serialize($db->Record);
9356  $file = $dir.'db/'.$table;
9357  file_put_contents($file, strlen($s)."\n".$s, FILE_APPEND);
9358  }
9359  }
9360 
9361  // Alle Verweise sichern
9362  if (!$target_dir && $lang_page) {
9363  if ($write_log) {
9364  file_put_contents($log, "> Verweise sichern\r\n", FILE_APPEND);
9365  }
9366  foreach ($lang_page->getLinks() as $link) {
9367  try {
9368  $link_site = new Site($link['dest_site'], $link['dest_lang']);
9369  $link_page = $link_site->getPage($link['dest_id'], $params);
9370  if ($link_page) {
9371  $link_page->download(false, $dir, false);
9372 
9373  // Die Elternseiten müssen auch gesichert werden
9374  foreach ($link_page->getParents(array(), $params) as $parent) {
9375  $parent->download(false, $dir, false);
9376  }
9377  }
9378  } catch (Exception $e) {
9379  // Ignorieren
9380  }
9381  }
9382 
9383  $db->select(array(
9384  'table' => 'egotec_links',
9385  'fields' => '*',
9386  'where' => "src_site = :site AND src_lang = :lang AND src_id = :id",
9387  'bind' => array(
9388  'site' => $this->_site->name,
9389  'lang' => $lang,
9390  'id' => $page->field['id']
9391  )
9392  ));
9393  while ($db->nextRecord()) {
9394  $s = serialize($db->Record);
9395  $file = $dir.'db/egotec_links';
9396  file_put_contents($file, strlen($s)."\n".$s, FILE_APPEND);
9397  }
9398  }
9399  }
9400  }
9401 
9402  if (!$target_dir) {
9403  if ($write_log) {
9404  file_put_contents($log, "Archiv erstellen\r\n", FILE_APPEND);
9405  }
9406  // Archiv erstellen
9407  require_once('Archive/Tar.php');
9408  $cwd = getcwd();
9409  chdir($dir);
9410  $tmp = tempnam($GLOBALS['egotec_conf']['tmp_dir'], 'download');
9411  $zip = new Archive_Tar($tmp, 'gz');
9412  $zip->add('./');
9413  chdir($cwd);
9414  Ego_System::deldir($dir);
9415 
9416  if ($write_log) {
9417  file_put_contents($log, "Archiv ausgeben\r\n", FILE_APPEND);
9418  }
9419  require_once('base/Ego_Output.php');
9420  $output = new Ego_Output($tmp);
9421  $date = date('Ymd-His');
9422  $output->setName('page_'.$this->_site->name.'.'.str_replace(' ', '_', $this->field['name']).'.'.$date.'.tar.gz');
9423  $output->setTemporary(true);
9424  $output->download();
9425  }
9426  }
9427 
9433  public function export() {
9434  if ($this->field['type'] == 'multimedia/category') {
9435  $dir = $GLOBALS['egotec_conf']['tmp_dir'];
9436  $name = 'export'.md5(microtime());
9437  $folder = $name.DIRECTORY_SEPARATOR
9438  .urldecode(Ego_System::encode_path(trim($this->field['name']))).DIRECTORY_SEPARATOR;
9439  $file = $name.'.tar.gz';
9440  $this->exportArchive($this, $dir.$folder);
9441 
9442  // Archiv erstellen
9443  require_once('Archive/Tar.php');
9444  $cwd = getcwd();
9445  chdir($dir);
9446  $zip = new Archive_Tar($file, 'gz');
9447  $zip->_separator = ',';
9448  $zip->createModify(rtrim($folder, DIRECTORY_SEPARATOR), '', $name);
9449  chdir($cwd);
9450  Ego_System::deldir($dir.$name);
9451  return $dir.$file;
9452  }
9453  return null;
9454  }
9455 
9462  private function exportArchive($page, $path) {
9463  Ego_System::mkdir($path);
9464  foreach ($page->getChildren() as $child) {
9465  $name = urldecode(Ego_System::encode_path(trim($child->field['name'])));
9466  if ($child->field['type'] == 'multimedia/category') {
9467  $this->exportArchive($child, $path.$name.DIRECTORY_SEPARATOR);
9468  } elseif (in_array($child->field['type'], array('multimedia/file', 'multimedia/image'))) {
9469  $dir = $GLOBALS['egotec_conf']['var_dir'].
9470  'media'.DIRECTORY_SEPARATOR.$this->_site->name.DIRECTORY_SEPARATOR;
9471  $file = $child->getMediaFilename();
9472  if ($child->extra['image_type']) {
9473  $name .= '.'.$child->extra['image_type'];
9474  }
9475  Ego_System::copy($dir.$file, $path.$name);
9476  }
9477  }
9478  }
9479 
9485  public function frontendAdmin() {
9486  if (!$this->frontendActive) {
9487  $this->frontendActive = true; // Nur einmal umwandeln
9488  $GLOBALS['frontend_admin'] = true;
9489  unset($GLOBALS['admin_area']);
9490  if (!$_SESSION['login']['live_preview']) {
9491  $_REQUEST['preview'] = $_REQUEST['nonactive'] = 1; // showdeleted wird nicht benötigt
9492  } else {
9493  unset($_REQUEST['preview'], $_REQUEST['nonactive']);
9494  }
9495 
9496  // In der Frontend Administration werden auch inaktive Seiten angezeigt
9497  $this->_site->setOnlyActive(!$_REQUEST['preview']);
9498 
9499  $lock = $this->lock();
9500  if (!$lock) {
9501  $settings = $this->getEditFieldSettings();
9502 
9503  if (!empty($this->conf['noneditable'])) {
9504  // Diese Elemente dürfen in der Frontend Administration nicht bearbeitet werden
9505  $settings = array_diff_key($settings, array_flip(explode(',', $this->conf['noneditable'])));
9506  }
9507 
9508  // Der Inhalt (field.content) wird automatisch in einen Editor umgewandelt
9509  $this->createEditField('content', $settings['content']);
9510  } elseif ($GLOBALS['smarty']) {
9511  // Die Seite ist gesperrt und kann nicht bearbeitet werden
9512  $GLOBALS['smarty']->assign('inlineedit_lock', true);
9513  }
9514  }
9515  }
9516 
9523  public function getEditFieldSettings($name = '') {
9524  // Typ der Kurzbeschreibung bestimmen
9525  $short_type = !$this->_site->admin['editor']['short'] && !$GLOBALS['egotec_conf']['editor']['short']
9526  ? 'text' : 'content';
9527 
9528  // Für Titel und Kurzbeschreibung kein HTML zulassen
9529  $plaintext = (bool) $this->_site->admin['editor']['plaintext'];
9530 
9531  // Konfigurationen zusammenführen
9532  $settings = array(
9533  'name' => array(
9534  'field' => true,
9535  'title' => $GLOBALS['auth']->translate('Name'),
9536  'dir' => 'right',
9537  'type' => 'text',
9538  'perm' => 'extra_information',
9539  'mandatory' => true,
9540  'readonly' => true,
9541  'plaintext' => true
9542  ),
9543  'title' => array(
9544  'field' => true,
9545  'title' => $GLOBALS['auth']->translate('Titel'),
9546  'dir' => 'right',
9547  'type' => 'text',
9548  'perm' => 'extra_information',
9549  'readonly' => true,
9550  'plaintext' => $plaintext
9551  ),
9552  'short' => array(
9553  'field' => true,
9554  'title' => $GLOBALS['auth']->translate('Kurzbeschreibung'),
9555  'dir' => 'right',
9556  'type' => $short_type,
9557  'perm' => 'extra_information',
9558  'plaintext' => $plaintext && $short_type == 'text'
9559  ),
9560  'content' => array(
9561  'field' => true,
9562  'title' => $GLOBALS['auth']->translate('Inhalt'),
9563  'dir' => 'right',
9564  'type' => 'editor'
9565  )
9566  );
9567  if (!empty($this->conf['fields'])) {
9568  $settings = array_replace_recursive($settings, $this->conf['fields']);
9569  }
9570 
9571  if ($name) {
9572  // Nur ein bestimmtes Feld zurückliefern
9573  if (isset($settings[$name])) {
9574  return $settings[$name];
9575  }
9576  return null;
9577  }
9578  return $settings;
9579  }
9580 
9593  public function createEditField($name, $setting = array(), $empty = false, $orient = '', $index = 0, $block = '', $replace = false) {
9594  $field = $setting['field'] ? 'field' : 'extra';
9595 
9596  // Sicherstellen, dass ein editierbares Feld nur einmal umgewandelt wird
9597  if (isset($this->editFields[$field][$name])) {
9598  return $this->editFields[$field][$name];
9599  }
9600 
9601  // Standardwert aus einer Variablen beziehen
9602  if (isset($setting['default']) && strpos($setting['default'], '@') === 0) {
9603  $parts = explode('.', substr($setting['default'], 1), 2);
9604  $parts[1] = str_replace(array('@orient', '@index', '@block'), array($orient, $index, $block), $parts[1]);
9605  $setting['default'] = strip_tags((string) Ego_System::getAssocValue($this->{$parts[0]}, $parts[1]));
9606  }
9607 
9608  // Standard Parameter aus der Konfiguration übernehmen, wenn diese nicht direkt übergeben werden
9609  if (is_array($this->conf['values'][$orient][$setting['type']])) {
9610  foreach ($this->conf['values'][$orient][$setting['type']] as $param => $value) {
9611  if (!isset($setting[$param])) {
9612  $setting[$param] = $value;
9613  }
9614  }
9615  }
9616 
9617  // Titel muss immer gesetzt sein
9618  if (!isset($setting['title'])) {
9619  $setting['title'] = $setting['var'];
9620  }
9621 
9622  // Platzhalter immer setzen
9623  if (!isset($setting['placeholder'])) {
9624  $setting['placeholder'] = $setting['title'];
9625  }
9626 
9632  $edit_field = function() use ($field, $name, $setting, $empty, $orient, $index, $block, $replace) {
9633  $this_value = $setting['no_auto'] && !empty($setting['value'])
9634  ? $setting['value']
9635  : Ego_System::getAssocValue($this->{$field}, $name);
9636  if ($field == 'extra' || $this_value !== null) {
9637  $frontend_admin = $GLOBALS['frontend_admin'] && $this->conf['orients'][$orient]['disabled'] !== true && $this->isCurrentPage();
9638  $title = $setting['title'] ? $GLOBALS['auth']->translate($setting['title']) : $setting['var'];
9639  $dir = $setting['dir'] ? $setting['dir'] : 'right';
9640 
9641  $type = $setting['type'];
9642  if ($setting['type'] == 'media') {
9643  // "media" Element automatisch auf "image" oder "video" stellen
9644  $type = Ego_System::getAssocValue($this->{$field}, "{$name}_type");
9645  if (!$type) {
9646  // Standardmäßig wird "image" verwendet
9647  $type = 'image';
9648  }
9649  }
9650 
9651  // Wert ist gekoppelt
9652  if (strpos($setting['var'], '=') === 0) {
9653  [$field, $name] = explode('.', substr($setting['var'], 1), 2);
9654  }
9655 
9656  // Gesetzten Wert ermitteln
9657  if (($empty || $replace) && isset($setting['initial'])) {
9658  // Startwert verwenden
9659  $edit_value = $setting['initial'];
9660  } elseif ($empty) {
9661  $edit_value = '';
9662 
9663  // Standardwert verwenden
9664  if (!empty($this->conf['blocks'][$block]['default'][$orient])) {
9665  $sub_name = implode('.', array_slice(explode('.', $name), 3));
9666  if (($default_value = Ego_System::getAssocValue($this->conf['blocks'][$block]['default'][$orient], $sub_name)) !== null) {
9667  $edit_value = $default_value;
9668  }
9669  }
9670  } else {
9671  $edit_value = $this_value;
9672  }
9673 
9674  // Verwendetes Layout ermitteln
9675  $layout = $this->extra['_layout'];
9676  if (empty($layout)) {
9677  $layout = $this->conf['default_layout']; // Standard Layout verwenden
9678  }
9679 
9680  // Standardblöcke haben immer einen Standardwert
9681  if (
9682  !$setting['default']
9683  && !$setting['optional']
9684  && !empty($this->conf['layouts'][$layout]['blocks'][$orient]['default'])
9685  && in_array($block, explode(',', $this->conf['layouts'][$layout]['blocks'][$orient]['default']))
9686  && !in_array($type, array('image', 'media', 'video', 'audio', 'table'))
9687  ) {
9688  $setting['default'] = $title;
9689  }
9690 
9691  if (($empty || ($replace && !$GLOBALS['__egotec_edit_do_save'])) && $frontend_admin && $edit_value == '' && in_array($type, array('text', 'minimal', 'content', 'editor', 'link'))) {
9692  // Leere Text Felder vorbelegen
9693  if ($type == 'link') {
9694  // Bei einem "link" Element muss auch der Linktext vorbelegt werden
9695  $edit_value = $setting['default'] ?? '';
9696  Ego_System::setAssocValue($this->{$field}, "{$name}_text", $title);
9697  } else {
9698  $edit_value = $setting['default'];
9699  }
9700  }
9701 
9702  if ($frontend_admin && in_array($type, array('image', 'video', 'audio'))) {
9703  $type_class = "egotec_type_{$type}";
9704  if (!empty($setting['attr']['class'])) {
9705  $setting['attr']['_class'] = $setting['attr']['class'];
9706  }
9707  $setting['attr']['class'] = "egotec_media {$type_class}";
9708  }
9709 
9710  switch ($type) {
9711  case 'editor':
9712  case 'content':
9713  case 'text':
9714  case 'minimal':
9715  if (!$frontend_admin) {
9716  // Text Elemente unterstützen auch den "attr" Parameter
9717  if (isset($setting['attr'])) {
9718  $tag_name = $type == 'text' ? 'span' : 'div';
9719  $wrapper = '<' . $tag_name;
9720  foreach ($setting['attr'] as $attr => $value) {
9721  $wrapper .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
9722  }
9723  $wrapper .= '>' . $edit_value . '</' . $tag_name . '>';
9724  $edit_value = $wrapper;
9725  }
9726  }
9727  break;
9728 
9729  case 'video':
9730  case 'audio':
9731  // "video" Elemente erzeugen ein VIDEO Element
9732  // "audio" Elemente erzeugen ein AUDIO Element
9733 
9734  // Für die Erzeugung die Smarty video Funktion verwenden
9735  require_once 'smarty/plugins/function.video.php';
9736  $edit_value = smarty_function_video(array_replace_recursive(array(
9737  'src' => $edit_value,
9738  'poster' => Ego_System::getAssocValue($this->{$field}, "{$name}_poster"),
9739  'alt' => Ego_System::getAssocValue($this->{$field}, "{$name}_alt"),
9740  'controls' => $setting['attr']['controls'] ?? Ego_System::getAssocValue($this->{$field}, "{$name}_controls"),
9741  'autoplay' => $setting['attr']['autoplay'] ?? Ego_System::getAssocValue($this->{$field}, "{$name}_autoplay"),
9742  'loop' => $setting['attr']['loop'] ?? Ego_System::getAssocValue($this->{$field}, "{$name}_loop"),
9743  'muted' => $setting['attr']['muted'] ?? Ego_System::getAssocValue($this->{$field}, "{$name}_muted"),
9744  'preload' => Ego_System::getAssocValue($this->{$field}, "{$name}_preload"),
9745  'fallback' => $frontend_admin,
9746  'audio' => $type == 'audio'
9747  ), $setting), $GLOBALS['smarty']);
9748 
9749  if (empty($edit_value)) {
9750  $setting['empty'] = true;
9751  }
9752 
9753  break;
9754 
9755  case 'image':
9756  // "image" Elemente erzeugen ein PICTURE Element
9757  if (!$frontend_admin && empty($edit_value) && !$setting['default']) {
9758  // Im Frontend keine leeren Bilder anzeigen
9759  return '';
9760  }
9761 
9762  // Attribute festlegen
9763  foreach (array('alt', 'title') as $attr) {
9764  if (!isset($setting['attr'][$attr])) {
9765  if (($attr_value = Ego_System::getAssocValue($this->{$field}, "{$name}_{$attr}")) !== null) {
9766  $setting['attr'][$attr] = $attr_value;
9767  }
9768  }
9769  }
9770  if (isset($setting['attr']['class'])) {
9771  $setting['attr']['class'] .= ' ' . Ego_System::getAssocValue($this->{$field}, "{$name}_class");
9772  $setting['attr']['class'] = trim($setting['attr']['class']);
9773  } elseif (($attr_value = Ego_System::getAssocValue($this->{$field}, "{$name}_class")) !== null) {
9774  $setting['attr']['class'] = $attr_value;
9775  }
9776 
9777  // Verlinkung erkennen
9778  if ($image_href = Ego_System::getAssocValue($this->{$field}, "{$name}_href")) {
9779  $setting['attr']['data-href'] = $image_href;
9780  $setting['attr']['data-target'] = Ego_System::getAssocValue($this->{$field}, "{$name}_target");
9781  }
9782 
9783  // URLs für die unterschiedlichen Viewports
9784  $viewports = Ego_System::getAssocValue($this->{$field}, "{$name}_viewports");
9785 
9786  // Für die Erzeugung die Smarty picture Funktion verwenden
9787  require_once('smarty/plugins/function.picture.php');
9788  $edit_value = smarty_function_picture(array_replace_recursive(array(
9789  'src' => $edit_value,
9790  'href' => !$setting['url'] ? $image_href : '',
9791  'target' => !$setting['url'] ? Ego_System::getAssocValue($this->{$field}, "{$name}_target") : '',
9792  'fallback' => $frontend_admin
9793  ), $setting, [
9794  'viewports' => $viewports
9795  ]), $GLOBALS['smarty']);
9796  if (empty($edit_value)) {
9797  $setting['empty'] = true;
9798  }
9799  break;
9800 
9801  case 'file':
9802  // "file" Elemente erzeugen ein IFRAME Element
9803  if (!$frontend_admin && empty($edit_value) && !$setting['default']) {
9804  // Im Frontend keine leeren Dateien anzeigen
9805  return '';
9806  }
9807 
9808  // Platzhalter URL
9809  $default = $GLOBALS['egotec_conf']['url_dir'] . 'bin/page/blocks/file.html';
9810 
9811  // Proportionen (Standard: 16:9)
9812  $ratio = str_replace(':', '/', $setting['ratio'] ?? '16:9');
9813 
9814  $setting['misc'] = array_merge([
9815  'src' => $default,
9816  'style' => 'width: 100%; height: auto; aspect-ratio: ' . $ratio,
9817  'allowfullscreen' => '',
9818  'loading' => 'lazy'
9819  ], $setting['attr'] ?? []);
9820 
9821  // Attribute werden nur für das IFRAME Element gesetzt
9822  if (isset($setting['attr'])) {
9823  unset($setting['attr']);
9824  }
9825 
9826  $iframe = '<iframe';
9827  foreach ($setting['misc'] as $attr => $value) {
9828  if ($attr == 'src') {
9829  // Anzeige im Dokumentenbetrachter (nur für interne URLs)
9830  if (
9831  Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'document')
9832  && !empty($GLOBALS['egotec_conf']['document']['blocks_enabled'])
9833  && !empty($edit_value)
9834  && strpos(ltrim($edit_value, '/'), 'index.php') === 0
9835  ) {
9836  $info = array_filter(Ego_System::getUrlParams($edit_value), function($key) {
9837  return in_array($key, ['site', 'lang', 'id', 'pool', 'dir']);
9838  }, ARRAY_FILTER_USE_KEY);
9839  $edit_value = $GLOBALS['egotec_conf']['url_dir'] . 'bin/document/editor.php?' . http_build_query($info);
9840  }
9841 
9842  $value = $edit_value ?: $value;
9843  }
9844  $iframe .= ' ' . $attr . ($value === '' ? '' : '="' . $value . '"');
9845  }
9846  $iframe .= '></iframe>';
9847 
9848  $edit_value = $iframe;
9849  if ($frontend_admin) {
9850  $edit_value = '<div>' . $edit_value . '</div>';
9851  }
9852 
9853  // NULL Werte nicht übernehmen
9854  $setting['misc'] = array_filter($setting['misc'], function($value) {
9855  return $value !== null;
9856  });
9857  break;
9858 
9859  case 'link':
9860  // "link" Elemente erzeugen ein A Element
9861  if (!$frontend_admin && empty($edit_value)) {
9862  // Im Frontend keine leeren Links anzeigen
9863  return '';
9864  }
9865 
9866  // Attribute festlegen
9867  $default = '<a href=""';
9868  $a = '<a href="' . $edit_value . '"';
9869  if (!is_array($setting['attr'])) {
9870  $setting['attr'] = array();
9871  }
9872  foreach (array('class', 'title', 'target') as $attr) {
9873  if (!isset($setting['attr'][$attr])) {
9874  $setting['attr'][$attr] = Ego_System::getAssocValue($this->{$field}, "{$name}_{$attr}");
9875  } elseif ($attr == 'class') {
9876  $setting['attr']['class'] .= ' ' . Ego_System::getAssocValue($this->{$field}, "{$name}_class");
9877  $setting['attr']['class'] = trim($setting['attr']['class']);
9878  }
9879  }
9880  foreach ($setting['attr'] as $attr => $value) {
9881  if ($attr != 'href' && $value != '') {
9882  if ($attr != 'target') {
9883  $default .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
9884  }
9885  $a .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
9886  }
9887  }
9888  $default .= '>' . ($setting['default'] ? $setting['default'] : $title) . '</a>';
9889  $a .= '>' . Ego_System::getAssocValue($this->{$field}, "{$name}_text") . '</a>';
9890  $setting['default'] = $default;
9891  $edit_value = empty($edit_value) ? $default : $a;
9892  break;
9893 
9894  case 'table':
9895  // "table" Elemente erzeugen ein TABLE Element
9896  if (!$frontend_admin && empty($edit_value)) {
9897  // Im Frontend keine leeren Tabellen anzeigen
9898  return '';
9899  }
9900 
9901  if (strpos($this->field['type'], 'e2e/') !== 0) { // "e2e" Seitentypen ignorieren
9902  // Zeilen und Spalten können standardmäßig bearbeitet werden
9903  foreach (['rows_edit', 'cols_edit', 'cols_size'] as $key) {
9904  if (!isset($setting[$key]) || !empty($setting[$key])) {
9905  $setting[$key] = true;
9906  }
9907  }
9908 
9920  $create = function ($name1, $name2, $rows, $cols, $contents = '') {
9921  $contents = explode('|', is_string($contents) ? $contents : '');
9922  $html = "<{$name1}>";
9923  for ($r = 0; $r < $rows; $r++) {
9924  $html .= '<tr>';
9925  for ($c = 0; $c < $cols; $c++) {
9926  $content = isset($contents[$c]) && trim($contents[$c]) != ''
9927  ? $GLOBALS['auth']->translate(trim($contents[$c]))
9928  : '<br>'; // muss gesetzt werden, damit man die Spalte beschreiben kann
9929  $html .= "<{$name2}>{$content}</{$name2}>";
9930  }
9931  $html .= '</tr>';
9932  }
9933  $html .= "</{$name1}>";
9934  return $html;
9935  };
9936 
9937  if (!empty($setting['default'])) {
9938  // Übergebene Standard Tabelle verwenden
9939  $table = trim($setting['default']);
9940  } else {
9941  // Standard Tabelle erzuegen
9942  $rows = $setting['rows'] ? (int)$setting['rows'] : 2;
9943  $cols = $setting['cols'] ? (int)$setting['cols'] : 2;
9944 
9945  $table = '<table';
9946  if (is_array($setting['attr'])) {
9947  // Attribute setzen
9948  foreach ($setting['attr'] as $attr => $value) {
9949  $table .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
9950  }
9951  }
9952  $table .= '>';
9953 
9954  $table .= ($setting['thead'] ? $create('thead', 'th', 1, $cols, $setting['thead']) : '')
9955  . $create('tbody', 'td', $rows, $cols)
9956  . ($setting['tfoot'] ? $create('tfoot', 'td', 1, $cols, $setting['tfoot']) : '')
9957  . '</table>';
9958 
9959  // Standard Tabelle verwenden
9960  $setting['default'] = $table;
9961  }
9962 
9963  if (empty($edit_value)) {
9964  $edit_value = $table;
9965  } else {
9966  // Falls sich die Attribute geändert haben, muss die Tabelle aktualisiert werden
9967  require_once('base/Ego_DomQuery.php');
9968  $dom = new Ego_DomQuery($edit_value);
9969  $table = $dom->doc->firstChild;
9970  $changed = false;
9971  if ($table->hasAttributes()) {
9972  foreach ($table->attributes as $attribute) {
9973  if (
9974  !is_array($setting['attr'])
9975  || empty($setting['attr'])
9976  || !in_array($table->nodeName, array_keys($setting['attr']))
9977  ) {
9978  // Attribut entfernen
9979  $table->removeAttribute($attribute->nodeName);
9980  $changed = true;
9981  }
9982  }
9983  }
9984  if (is_array($setting['attr'])) {
9985  foreach ($setting['attr'] as $attr => $value) {
9986  if (!$table->hasAttribute($attr) || $table->getAttribute($attr) != $value) {
9987  // Neues oder geändertes Attribut hinzufügen
9988  $table->setAttribute($attr, $value);
9989  $changed = true;
9990  }
9991  }
9992  }
9993  if ($changed) {
9994  $edit_value = $dom->getHTML();
9995  }
9996  }
9997  }
9998  break;
9999 
10000  case 'value':
10001  case 'date':
10002  // "value", "date" Elemente geben nur den Wert zurück
10003  $value = Ego_System::getAssocValue($this->{$field}, $name);
10004 
10012  $get_value = function($value, $select) use ($type, $setting) {
10013  if (empty($value)) {
10014  $value = !empty($select['default'])
10015  ? $select['default']
10016  : (!empty($setting['default'])
10017  ? $setting['default']
10018  : '');
10019 
10020  // Der Standardwert für "date" kann ein relatives Datum sein
10021  if ($type == 'date' && preg_match('/^<%(.*?)>$/', $value, $match)) {
10022  $value = $match[1];
10023  }
10024  }
10025  if (!empty($select['format']) && !empty($value)) {
10026  $value = date($select['format'], strtotime($value));
10027  }
10028  if (!empty($select['value'])) {
10029  $value = str_replace('<%>', $value, $select['value']);
10030  }
10031  return $value;
10032  };
10033 
10034  // Zunächst die Einstellungen des Bedienelements anwenden
10035  if (
10036  !empty($orient)
10037  && (($block_name = $block) || ($block_name = $this->extra['_blocks'][$orient][$index]))
10038  && ($controls = $this->getBlockControls($block_name))
10039  ) {
10040  $value_name = ltrim(strrchr($name, '.'), '.');
10041  foreach ($controls as $select) {
10042  if ($select['name'] == $value_name) {
10043  $value = $get_value($value, $select);
10044  }
10045  }
10046  }
10047 
10048  // Dann die direkten Einstellungen anwenden
10049  $value = $get_value($value, $setting);
10050 
10051  return $value;
10052 
10053  case 'code':
10054  if (empty($edit_value)) {
10055  if (!$frontend_admin) {
10056  // Im Frontend keinen leeren Code anzeigen
10057  return '';
10058  } else {
10059  $edit_value = $setting['default'] ?? $title;
10060  }
10061  }
10062 
10063  $languages = $setting['languages'] ?? $this->conf['code']['languages'] ?? array();
10064  if (!is_array($languages)) {
10065  $languages_array = explode(',', $languages);
10066  $languages = array();
10067  foreach ($languages_array as $language) {
10068  $languages[$language] = $language;
10069  }
10070  }
10071  asort($languages, SORT_NATURAL);
10072  $first_language = null;
10073  foreach ($languages as $value => $text) {
10074  $first_language = $value;
10075  break;
10076  }
10077 
10078  // Ausgewählte Sprache bestimmen
10079  $mode = Ego_System::getAssocValue($this->extra, $name . '_mode')
10080  ?? $setting['mode']
10081  ?? $this->conf['code']['mode']
10082  ?? $first_language
10083  ?? 'HTML';
10084 
10085  $smarty = Ego_Smarty::createFrontend($this->getSite(), array(
10086  'id' => 'code-' . md5($name),
10087  'name' => $name,
10088  'value' => $edit_value,
10089  'theme' => $setting['theme'] ?? $this->conf['code']['theme'] ?? 'monokai',
10090  'mode' => mb_strtolower($mode),
10091  'selected_mode' => $mode,
10092  'label' => $setting['label'] ?? $languages[$mode] ?? $mode,
10093  'min' => $setting['min'] ?? $this->conf['code']['min'] ?? 3,
10094  'max' => $setting['max'] ?? $this->conf['code']['max'] ?? 20,
10095  'languages' => $languages
10096  ));
10097  $edit_value = $smarty->fetch($GLOBALS['egotec_conf']['lib_dir'] . 'page/t/input/code.tpl');
10098  }
10099 
10106  $label_callback = function($callback) use ($setting, $orient, $index, $block) {
10107  if ($setting['var'] == 'label') {
10108  foreach (array('required', 'optional') as $display_type) {
10109  if (
10110  $this->conf['form'][$display_type]
10111  && strpos($block, 'input_') === 0
10112  && $this->extra['_contents'][$orient][$index]['extra'][$display_type]
10113  ) {
10114  $callback($display_type);
10115  }
10116  }
10117  }
10118  };
10119 
10120  // Standardwert für required/optional Eingabefelder für Labels in Formular Blöcken
10121  $label_callback(function($display_type) use (&$edit_value, &$setting, $title) {
10122  if (trim($edit_value) == '') {
10123  $edit_value = $setting['default'] = $setting['default'] ?? $title;
10124  }
10125  });
10126 
10127  // Automatisches Befüllen
10128  $autofill = $this->conf['autofill'];
10129  if (isset($this->conf['blocks'][$block]['autofill'])) {
10130  $autofill = $this->conf['blocks'][$block]['autofill'];
10131  }
10132  if (isset($setting['autofill'])) {
10133  $autofill = $setting['autofill'];
10134  }
10135 
10136  // Nur in der Frontend Administration und nur für diese Seite ein editierbares Element verwenden
10137  if ($frontend_admin) {
10144  $escape = function($s) {
10145  return htmlspecialchars(
10146  preg_replace('/\s+/', ' ', $s),
10147  ENT_QUOTES,
10148  'UTF-8'
10149  );
10150  };
10151 
10152  // Booleansche Werte müssen als String übergeben werden
10153  foreach (array('toolbar', 'menubar') as $key) {
10154  if (isset($setting[$key]) && is_bool($setting[$key])) {
10155  $setting[$key] = $setting[$key] === true ? 'true' : 'false';
10156  }
10157  }
10158 
10159  // Zusätzliche Attribute setzen
10160  $additional_attributes = array();
10161  if (!empty($setting['attr'])) {
10162  foreach ($setting['attr'] as $attr => $value) {
10163  if (
10164  $attr == '_class'
10165  // Bestimmte Elemente setzen die Attribute für das implizite HTML
10166  || in_array($setting['type'], array('link', 'table'))
10167  ) {
10168  continue;
10169  }
10170 
10171  if ($attr == 'class' && isset($setting['attr']['_class'])) {
10172  $setting['attr']['class'] = implode(' ', array_unique(array_merge(explode(' ', $value), explode(' ', $setting['attr']['_class']))));
10173  unset($setting['attr']['_class']);
10174  }
10175 
10176  // Klassen, die nur auf dem Bild gesetzt sein sollen nicht auf den Container setzen
10177  if ($attr === 'class' && in_array($setting['type'], ['image', 'media'])) {
10178  $classes = explode(' ', $value);
10179  $image_classes = explode(' ', Ego_System::getAssocValue($this->{$field}, "{$name}_class"));
10180  $div_classes = [];
10181 
10182  foreach ($classes as $class) {
10183  if (!in_array($class, $image_classes)) {
10184  $div_classes[] = $class;
10185  }
10186  }
10187 
10188  $value = implode(' ', $div_classes);
10189  }
10190 
10191  $additional_attributes[] = $attr . '="' . $escape($value) . '"';
10192  }
10193  }
10194 
10195  $tag_name = $setting['tag_name'] ?? 'div';
10196  $edit_value = '<' . $tag_name
10197  . ($setting['field'] ? ' data-edit-field="' . $name . '"' : ' data-edit-extra="' . $name . '"')
10198  . ' data-edit-type="' . $setting['type'] . '"'
10199  . ($setting['default'] ? ' data-edit-default="' . $escape($GLOBALS['auth']->translate($setting['default'])) . '"' : '')
10200  . ($setting['perm'] && !$this->hasRights(explode(',', $setting['perm'])) ? ' data-edit-locked="true"' : '')
10201  . ($setting['style'] ? ' style="' . $setting['style'] . '"' : '') // @deprecated
10202  . ($setting['mandatory'] ? ' data-edit-mandatory="true"' : '')
10203  . ($setting['readonly'] ? ' data-edit-readonly="true"' : '')
10204  . ($setting['no_auto'] ? ' data-edit-no-auto="true"' : '')
10205  . ($setting['rows_edit'] ? ' data-edit-rows="true"' : '')
10206  . ($setting['cols_edit'] ? ' data-edit-cols="true"' : '')
10207  . ($setting['cols_size'] ? ' data-edit-cols-size="true"' : '')
10208  . ($setting['maxlength'] ? ' data-edit-maxlength="' . $setting['maxlength'] . '"' : '')
10209  . ($setting['srcset'] ? ' data-edit-srcset="' . $setting['srcset'] . '"' : '')
10210  . ($setting['empty'] ? ' data-edit-empty="true"' : '')
10211  . ($setting['href'] === false ? ' data-edit-href="false"' : '')
10212  . ($setting['optional'] ? ' data-edit-optional="true"' : '')
10213  . ($setting['plaintext'] ? ' data-edit-plaintext="true"' : '')
10214  . ($setting['root'] ? ' data-edit-root="true"' : '')
10215  . ($setting['unsafe'] ? ' data-edit-unsafe="true"' : '')
10216  . ($setting['hooks'] ? ' data-edit-hooks="' . $setting['hooks'] . '"' : '')
10217  . ($setting['plugins'] ? ' data-edit-plugins="' . $setting['plugins'] . '"' : '')
10218  . ($setting['toolbar'] ? ' data-edit-toolbar="' . $setting['toolbar'] . '"' : '')
10219  . ($setting['menubar'] ? ' data-edit-menubar="' . $setting['menubar'] . '"' : '')
10220  . ($setting['paste_tags'] ? ' data-edit-paste-tags="' . $setting['paste_tags'] . '"' : '')
10221  . ($setting['paste_attrs'] ? ' data-edit-paste-attrs="' . $setting['paste_attrs'] . '"' : '')
10222  . ($setting['placeholder'] ? ' data-edit-placeholder="' . $escape($GLOBALS['auth']->translate($setting['placeholder'])) . '"' : '')
10223  . ($setting['edit'] !== false ? ' data-edit-media="' . $escape(json_encode($setting['edit'] ?? true, JSON_FORCE_OBJECT)) . '"' : '')
10224  . (!empty($setting['attr']) ? ' data-edit-attr="' . $escape(json_encode($setting['attr'], JSON_FORCE_OBJECT)) . '"' : '')
10225  . (!empty($setting['misc']) ? ' data-edit-misc="' . $escape(json_encode($setting['misc'], JSON_FORCE_OBJECT)) . '"' : '')
10226  . (!empty($autofill) ? ' data-edit-autofill="' . $escape(json_encode($autofill, JSON_FORCE_OBJECT)) . '"' : '')
10227  . ((!empty($setting['caption']) && !empty($setting['url'])) || !empty($setting['no_link']) ? ' data-edit-hide-link="1"' : '')
10228  . implode(' ', $additional_attributes)
10229  . '>' . $edit_value . '</' . $tag_name . '>';
10230  Ego_System::setAssocValue($this->{$field}, $name, $edit_value);
10231  }
10232 
10233  // Darstellung für required/optional Eingabefelder für Labels in Formular Blöcken
10234  $label_callback(function($display_type) use (&$edit_value) {
10235  $edit_value = $GLOBALS['smarty']->fetch('string:' . str_replace('<%>', $edit_value, $this->conf['form'][$display_type]));
10236  });
10237 
10238  if (in_array($type, array('video', 'audio', 'image', 'media'))) {
10239  // Bildbeschreibung hinzufügen (im Frontend nur, wenn der Wert nicht leer ist)
10240  $caption = $this->conf['caption'];
10241  if (isset($this->conf['blocks'][$block]['caption'])) {
10242  $caption = $this->conf['blocks'][$block]['caption'];
10243  }
10244  if (isset($setting['caption'])) {
10245  $caption = $setting['caption'];
10246  }
10247 
10248  if ($caption) {
10249  $caption_autofill = !empty($autofill['caption']['readonly']);
10250  $caption_value = '';
10251 
10252  // Bildbeschreibung automatisch ermitteln
10253  if ($caption_autofill && !empty($this_value) && ($media_page = Ego_System::urltopage($this_value, ['inactive' => true, 'only_active' => false]))) {
10254  $result = $media_page->getAutoFill($autofill, Ego_System::getUrlParams($this_value));
10255  $caption_value = (string) $result['caption']['value'];
10256  }
10257 
10258  if ($frontend_admin) {
10259  // Für die Erzeugung die Smarty value Funktion verwenden
10260  require_once('smarty/plugins/function.value.php');
10261  $var = substr(strrchr($name, '.'), 1);
10262  $caption_value = smarty_function_value(array(
10263  'var' => "{$var}_caption",
10264  'type' => 'minimal',
10265  'title' => $setting['type'] == 'image'
10266  ? $GLOBALS['auth']->translate('Bildbeschreibung')
10267  : $GLOBALS['auth']->translate('Beschreibung'),
10268  'orient' => $orient,
10269  'index' => $index,
10270  'readonly' => $caption_autofill,
10271  'no_auto' => $caption_autofill,
10272  'value' => $caption_value
10273  ), $GLOBALS['smarty']);
10274  } elseif (!$caption_autofill) {
10275  $caption_value = Ego_System::getAssocValue($this->{$field}, "{$name}_caption");
10276  }
10277  if ($caption_value != '') {
10278  $edit_value = str_replace(array('<%>', '<#>'), array($edit_value, $caption_value), $caption);
10279  }
10280  }
10281  }
10282 
10283  if ($setting['tag_name'] && !$frontend_admin && $edit_value != '') {
10284  // Wrapper für das Element hinzufügen (im Frontend nur, wenn der Wert nicht leer ist)
10285  $edit_value = "<{$setting['tag_name']}>$edit_value</{$setting['tag_name']}>";
10286  }
10287 
10288  if ($setting['wrapper'] && ($frontend_admin || $edit_value != '')) {
10289  // Wrapper für das Element hinzufügen (im Frontend nur, wenn der Wert nicht leer ist)
10290  $edit_value = str_replace('<%>', $edit_value, $setting['wrapper']);
10291  }
10292 
10293  if ($setting['url']) {
10294  // URL platzieren
10295  $href = Ego_System::getAssocValue($this->{$field}, "{$name}_href");
10296  $target = Ego_System::getAssocValue($this->{$field}, "{$name}_target");
10297  if ($frontend_admin || !$href) {
10298  // Keine Aktion ausführen
10299  $href = 'javascript:void(0)';
10300  }
10301 
10302  require_once('base/Ego_DomQuery.php');
10303  $dom = new Ego_DomQuery($edit_value);
10304  $links = $dom->query($setting['url']);
10305  foreach ($links as $link) {
10306  $link->setAttribute('href', $href);
10307  if ($target) {
10308  $link->setAttribute('target', $target);
10309  }
10310  }
10311  $edit_value = $dom->getHTML();
10312  }
10313 
10314  return $edit_value;
10315  }
10316  return null;
10317  };
10318 
10319  return $this->editFields[$field][$name] = $edit_field();
10320  }
10321 
10337  public function updateUrls($verbose = false, $domain = null, $force_recursive = false, $called_recursive = false) {
10338  if (
10339  $GLOBALS['egotec_conf']['rewrite_engine'] != 'url' // Nur wenn die richtige RewriteEngine eingestellt ist
10340  || (
10341  $_SERVER['HTTP_X_SOAP_CALL'] == 'Replication' // Erfolgt der Aufruf über den Liveabgleich
10342  && $this->getSite()->getCache()->getEternal() // und ist die "ewige" Cache aktiv, werden keine URLs aktualisiert
10343  )
10344  || $this->field['deleted'] // Gelöschte Seiten haben keine URLs
10345  || $this->isReleaseCopy() // Freigabekopien haben keine URLs
10346  || strpos($this->field['type'], '/occupancy/') // Buchungen der Resourcenverwaltung haben keine URLs
10347  ) {
10348  return;
10349  }
10350 
10351  // Bei einer rekursiven URL Generierung sicherstellen, dass die selben Seiten nicht mehrfach berechnet werden
10352  if (isset($GLOBALS['__page_update_urls_stack']) && in_array($this->getIdentity(), $GLOBALS['__page_update_urls_stack'])) {
10353  return;
10354  }
10355  if (!isset($GLOBALS['__page_update_urls_stack'])) {
10356  $GLOBALS['__page_update_urls_stack'] = [];
10357  }
10358  $GLOBALS['__page_update_urls_stack'][] = $this->getIdentity();
10359 
10360  $db = new_db_connection();
10361 
10367  $get_current_urls = function() use ($db) {
10368  $db->select(array(
10369  'table' => 'egotec_url',
10370  'fields' => 'site, lang, id, domain, dir, path, canonical',
10371  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical = 1',
10372  'bind' => array(
10373  'site' => $this->_site->name,
10374  'lang' => $this->_site->language,
10375  'id' => $this->field['id']
10376  )
10377  ));
10378  $urls = array();
10379  while ($db->nextRecord()) {
10380  $urls[] = $db->Record;
10381  }
10382  return $urls;
10383  };
10384 
10385  $old_urls = $get_current_urls();
10386 
10387  // Alle primären und sekundären virtuellen Hosts ermitteln
10388  $virtual_hosts = $this->_site->getVirtualHosts();
10389 
10390  // Bereichs-Domain ermitteln (nur auf einem Liveserver oder Redaktionsserver, wenn es keine Liveserver gibt)
10391  $area_domain = [];
10392  $use_area_domain = $GLOBALS['egotec_conf']['liveserver'] || !$this->_site->hasLiveserver();
10393  if ($use_area_domain) {
10394  if ($domain) {
10395  $area_domain = $domain;
10396  }
10397  if ($this->extra['area_domain']) {
10398  // Die eigene Bereichs-Domain wird immer zur primären URL
10399  array_unshift($area_domain, mb_strtolower($this->extra['area_domain']));
10400  }
10401 
10402  // Keine Vererbung, wenn der Aufruf rekursiv erfolgt oder die Domain(s) bereits übergeben wurde(n)
10403  if (!$called_recursive && empty($domain)) {
10404  $ancestors = $this->getAncestors();
10405  $inherited_domains = [];
10406  foreach ($ancestors as $ancestor) {
10407  if ($ancestor->extra['area_domain']) {
10408  $inherited_domains[] = mb_strtolower($ancestor->extra['area_domain']);
10409  }
10410  }
10411  if (!empty($inherited_domains)) {
10412  $inherited_domains = array_reverse($inherited_domains);
10413  foreach ($inherited_domains as $inherited_domain) {
10414  $area_domain[] = $inherited_domain;
10415  }
10416  }
10417  }
10418  if (!empty($area_domain)) {
10419  for ($i = 0; $i < sizeof($area_domain); $i++) {
10420  $area_domain[$i] = rtrim(preg_replace('/^https?:\/\//', '', $area_domain[$i]), '/');
10421  }
10422  $virtual_hosts = $area_domain; // Nur die Bereichs-Domains, bzw. übergebenen Domains verwenden
10423  }
10424  }
10425 
10426  if (!$this->field['inactive'] || $this->isWorkflowCopy()) {
10427  $now = date('Y-m-d H:i:s');
10428 
10429  // Zu verwendende Konfiguration ermitteln
10430  $conf = $this->_site->getRewriteConf();
10431 
10432  // Merken, ob die erste URL (canonical = 1) bereits eingefügt wurde
10433  $first_url_inserted = 0;
10434 
10443  $insert_urls = function($names, $paths, $exists = false) use ($db, $domain, $virtual_hosts, $now, &$first_url_inserted) {
10444  foreach ($names as $ni => $name) {
10445  foreach ($paths as $pi => $path) {
10446  $dir = trim($GLOBALS['egotec_conf']['url_dir'] . implode('/', array_filter(array($path['name'], $name))), '/');
10447 
10448  foreach ($virtual_hosts as $vi => $virtual_host) {
10449  $this_dir = $dir;
10450  // Domains mit /abc übergeben die Erweiterung dem Pfad
10451  $virtual_host = rtrim($virtual_host, '/');
10452  if ($part = strstr($virtual_host, '/')) {
10453  $virtual_host = strstr($virtual_host, '/', true);
10454  $this_dir = trim($part . "/{$dir}", '/');
10455  }
10456 
10457  $params = array(
10458  'site' => $this->_site->name,
10459  'lang' => $this->_site->language,
10460  'id' => $this->field['id'],
10461  'domain' => $virtual_host,
10462  'dir' => $this_dir,
10463  'path' => (string)$path['id']
10464  );
10465 
10466  // Sicherstellen, dass der Pfad einmalig ist (archivierte URLs werden bei der Prüfung ignoriert)
10467  $unique_dir = $this_dir;
10468  $duplicate_params = $params;
10469  unset(
10470  $duplicate_params['site'],
10471  $duplicate_params['lang'],
10472  $duplicate_params['id'],
10473  $duplicate_params['path']
10474  );
10475  $n = 1;
10476  while ($this_dir != '') {
10477  $duplicate_params['dir'] = $unique_dir;
10478  $db->select(array(
10479  'table' => 'egotec_url',
10480  'where' => 'domain = :domain AND dir = :dir',
10481  'bind' => $duplicate_params
10482  ));
10483  if ($db->nextRecord()) {
10484  if (
10485  $db->Record['site'] == $this->_site->name
10486  && $db->Record['lang'] == $this->_site->language
10487  && $db->Record['id'] == $this->field['id']
10488  && !$db->nextRecord()
10489  ) {
10490  break;
10491  }
10492  if ($db->Record['canonical'] == 0) {
10493  $db->delete(array(
10494  'table' => 'egotec_url',
10495  'where' => 'site = :site AND lang = :lang AND id = :id AND domain = :domain AND dir = :dir AND path = :path AND canonical = 0',
10496  'bind' => array(
10497  'site' => $db->Record['site'],
10498  'lang' => $db->Record['lang'],
10499  'id' => $db->Record['id'],
10500  'domain' => $db->Record['domain'],
10501  'dir' => $db->Record['dir'],
10502  'path' => $db->Record['path']
10503  )
10504  ));
10505  } else {
10506  $unique_dir = $this_dir . '-' . $n++;
10507  }
10508  } else {
10509  break;
10510  }
10511  }
10512  $params['dir'] = $unique_dir;
10513 
10514  // Prüfen, ob die URL bereits eingetragen ist
10515  if ($exists) {
10516  $db->select(array(
10517  'table' => 'egotec_url',
10518  'where' => 'domain = :domain AND dir = :dir AND canonical > 0',
10519  'bind' => array(
10520  'domain' => $params['domain'],
10521  'dir' => $params['dir']
10522  )
10523  ));
10524  if ($db->nextRecord()) {
10525  // Änderungsdatum aktualisieren, damit diese URL nicht archiviert wird
10526  $db->update(array(
10527  'table' => 'egotec_url',
10528  'where' => 'domain = :domain AND dir = :dir AND canonical > 0',
10529  'bind' => array(
10530  'domain' => $params['domain'],
10531  'dir' => $params['dir']
10532  ),
10533  'set' => array(
10534  'c_date' => $now
10535  )
10536  ));
10537 
10538  continue;
10539  }
10540  }
10541 
10542  // Doppelte Einträge vermeiden
10543  $db->begin();
10544  $db->delete(array(
10545  'table' => 'egotec_url',
10546  'where' => 'domain = :domain AND dir = :dir',
10547  'bind' => array(
10548  'domain' => $params['domain'],
10549  'dir' => $params['dir']
10550  )
10551  ));
10552 
10553  // Neue kanonische URL einfügen
10554  $db->insert(array(
10555  'table' => 'egotec_url',
10556  'set' => array_merge($params, array(
10557  'canonical' => $first_url_inserted == 0 && $ni == 0 && $vi == 0 ? ($first_url_inserted = 1) : 2,
10558  'c_date' => $now
10559  ))
10560  ));
10561  $db->commit();
10562  }
10563  }
10564  }
10565  };
10566 
10567  // Namen und Pfade generieren
10568  $names = array();
10569  $paths = array();
10570 
10571  // Alle möglichen Namen dieser Seite für die URLs
10572  if (empty($this->field['url']) || $conf['meta']) {
10573  if (!$conf['flat']) {
10574  // URLs aus allen Pfaden
10575  $paths = $this->getPaths(false, true, $use_area_domain);
10576  }
10577 
10578  $names = $this->getUrlNames();
10579  }
10580 
10581  // Die Startseite kennt auch URLs ohne Namen (wird immer zu canonical = 1)
10582  if ($this->field['id'] == $this->_site->rootId || ($use_area_domain && $this->extra['area_domain'])) {
10583  array_unshift($names, '');
10584  }
10585 
10586  if (!empty($names)) {
10587  if (empty($paths)) {
10588  // URLs ohne Pfad
10589  $paths[] = array(
10590  'name' => ''
10591  );
10592  }
10593 
10594  $insert_urls($names, $paths);
10595  }
10596 
10597  // Eindeutige Meta URL
10598  if (!empty($this->field['url'])) {
10599  $paths = array(array(
10600  'name' => ''
10601  ));
10602  $space = $conf['space'];
10603  if (empty($space)) {
10604  $space = '+';
10605  }
10606  $name = str_replace(' ', $space, $this->field['url']);
10607  $names = array($name);
10608 
10609  $insert_urls($names, $paths, true);
10610  }
10611 
10612  // Permalinks hinzufügen
10613  $db->delete(array(
10614  'table' => 'egotec_url',
10615  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical = 3',
10616  'bind' => array(
10617  'site' => $this->_site->name,
10618  'lang' => $this->_site->language,
10619  'id' => $this->field['id']
10620  )
10621  ));
10622 
10623  $db->begin();
10624  foreach ($virtual_hosts as $vi => $virtual_host) {
10625  $dir = '';
10626 
10627  // Domains mit /abc übergeben die Erweiterung dem Pfad
10628  $virtual_host = rtrim($virtual_host, '/');
10629  if ($part = strstr($virtual_host, '/')) {
10630  $virtual_host = strstr($virtual_host, '/', true);
10631  $dir = ltrim($part . '/', '/');
10632  }
10633 
10634  $db->replace(array(
10635  'table' => 'egotec_url',
10636  'set' => array(
10637  'site' => $this->_site->name,
10638  'lang' => $this->_site->language,
10639  'id' => $this->field['id'],
10640  'domain' => $virtual_host,
10641  'dir' => "{$dir}-{$this->field['id']}",
10642  'path' => '',
10643  'canonical' => 3,
10644  'c_date' => $now
10645  ),
10646  'primary' => [ 'domain', 'dir' ]
10647  ));
10648  }
10649  $db->commit();
10650 
10651  // Alle alten URLs archivieren
10652  $db->update(array(
10653  'table' => 'egotec_url',
10654  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical > 0 AND c_date < :c_date',
10655  'bind' => array(
10656  'site' => $this->_site->name,
10657  'lang' => $this->_site->language,
10658  'id' => $this->field['id'],
10659  'c_date' => $now
10660  ),
10661  'set' => array(
10662  'canonical' => 0
10663  )
10664  ));
10665  }
10666 
10667  if ($verbose) {
10668  Ego_System::flush('.');
10669  }
10670 
10671  // Rekursiv alle Unterseiten aktualisieren
10672  if (
10673  $force_recursive
10674  || (
10675  $this->field['id'] != $this->_site->rootId // nicht für die Startseite
10676  && serialize($old_urls) != serialize($get_current_urls()) // und nur, wenn sich die URLs dieser Seite geändert haben
10677  )
10678  ) {
10679  $children = $this->getChildren(array(), array(
10680  'auth_or' => '1=1',
10681  'inactive' => true,
10682  'only_active' => false
10683  ));
10684  foreach ($children as $child) {
10685  $child->updateUrls($verbose, $area_domain, $force_recursive, true); // @TODO Performancegewinn wenn man die bereits berechneten URLs weitergibt?
10686  }
10687  }
10688  }
10689 
10695  public function archiveUrls() {
10696  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'url') {
10697  $db = new_db_connection();
10698  $db->begin();
10699 
10700  $db->update(array(
10701  'table' => 'egotec_url',
10702  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical > 0',
10703  'bind' => array(
10704  'site' => $this->_site->name,
10705  'lang' => $this->_site->language,
10706  'id' => $this->field['id']
10707  ),
10708  'set' => array(
10709  'canonical' => 0
10710  )
10711  ));
10712 
10713  $db->commit();
10714  }
10715  }
10716 
10722  public function removeUrls() {
10723  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'url') {
10724  $db = new_db_connection();
10725  $db->begin();
10726 
10727  $db->delete(array(
10728  'table' => 'egotec_url',
10729  'where' => 'site = :site AND lang = :lang AND id = :id',
10730  'bind' => array(
10731  'site' => $this->_site->name,
10732  'lang' => $this->_site->language,
10733  'id' => $this->field['id']
10734  )
10735  ));
10736 
10737  $db->commit();
10738  }
10739  }
10740 
10746  protected function getUrlNames() {
10747  // Der Name der Seite wird für die URL vorgesehen
10748  $name = $this->field['name'];
10749 
10750  // Zu verwendende Konfiguration ermitteln
10751  $conf = $this->_site->getRewriteConf();
10752 
10753  // Umlaute ersetzen
10754  if ($conf['umlauts']) {
10755  $name = str_replace(array('Ä', 'Ö', 'Ü', 'ä', 'ö', 'ü', 'ß'), array('Ae', 'Oe', 'Ue', 'ae', 'oe', 'ue', 'ss'), $name);
10756  }
10757 
10758  // Groß- und Kleinschreibung
10759  switch ($conf['case']) {
10760  // Alles groß
10761  case 'upper':
10762  $name = mb_strtoupper($name);
10763  break;
10764 
10765  // Alles klein
10766  case 'lower':
10767  $name = mb_strtolower($name);
10768  }
10769 
10770  // Leerzeichen ersetzen
10771  $space = $conf['space'];
10772  if (empty($space)) {
10773  $space = '+';
10774  }
10775  $name = str_replace(' ', $space, $name);
10776 
10777  // Und-Zeichen ausschreiben (über System-Übersetzungen, "var/lib/locale/", übersetzbar)
10778  if (!empty($conf['ampersand'])) {
10779  $language = $this->extra['language_link'][$this->_site->language] == 1
10780  ? $this->extra['language_standard']
10781  : $this->_site->language;
10782  $replace = $GLOBALS['auth']->translate('und', array(), $language);
10783  $name = str_replace('&', $replace, $name);
10784  }
10785 
10786  // Ungültige Zeichen entfernen
10787  $invalid_characters = "%\n\r\t,;#!?:&/'\".\\";
10788  $default_special = '_';
10789  $special = $conf['special'];
10790  if (empty($special)) {
10791  $special = $default_special;
10792  }
10793  $name = strtr($name, $invalid_characters, str_repeat($special, mb_strlen($invalid_characters)));
10794  if ($special != $default_special) {
10795  // Sicherstellen, dass das neue Zeichen für ungültige Zeichen nicht selbst ungültige Zeichen enthält
10796  $name = strtr($name, $invalid_characters, str_repeat($default_special, mb_strlen($invalid_characters)));
10797  }
10798 
10799  if ($name[0] == '-') {
10800  // Der Name darf nicht mit - beginnen (reserviert für Permalink)
10801  $name[0] = $special != '-' ? $special : $default_special;
10802  }
10803 
10804  // Ersetzte ungültige Zeichen zusammenfassen (beinhaltet auch ersetzte Leerzeichen)
10805  $name = preg_replace('/' . preg_quote($special, '/') . '{2,}/', $special, $name);
10806 
10807  // Fallback auf kundenspezifische Datei
10808  $url_file = $GLOBALS['egotec_conf']['var_dir'] . 'lib/url.php';
10809  if (Ego_System::file_exists($url_file)) {
10810  require_once $url_file;
10811  $result = get_url_names($this, $conf, $name/* Vom System generierter Name */);
10812  if (sizeof($result) > 0) {
10813  foreach ($result as $key => $value) {
10814  if ($value[0] == '-') {
10815  // Der Name darf nicht mit - beginnen (reserviert für Permalink)
10816  $result[$key][0] = '_';
10817  }
10818  }
10819  return $result;
10820  }
10821  }
10822 
10823  return array($name);
10824  }
10825 
10826 
10832  public function getPermUrl() {
10833  return $this->getUrl([
10834  'return_absolute' => true,
10835  'return_permalink' => true
10836  ]);
10837  }
10838 
10839 
10845  public function getPermissionName($perm) {
10846  $title = $perm;
10847 
10848  switch ($perm) {
10849  // Standardrechte
10850  case 'view':
10851  $title = $GLOBALS['auth']->translate('Ansicht');
10852  break;
10853  case 'edit':
10854  $title = $GLOBALS['auth']->translate('Bearbeiten');
10855  break;
10856  case 'release':
10857  $title = $GLOBALS['auth']->translate('Freigabe ändern');
10858  break;
10859  case 'remove':
10860  $title = $GLOBALS['auth']->translate('Löschen');
10861  break;
10862  case 'child':
10863  $title = $GLOBALS['auth']->translate('Ausschnitte/Seite anlegen');
10864  break;
10865  case 'workflow':
10866  $title = $GLOBALS['auth']->translate('Workflow ändern');
10867  break;
10868  case 'linkto':
10869  $title = $GLOBALS['auth']->translate('Verlinkung erlauben');
10870  break;
10871  case 'live':
10872  $title = $GLOBALS['auth']->translate('Übertragen');
10873  break;
10874 
10875  // Standardreiter
10876  case 'view_newsletter':
10877  $title = $GLOBALS['auth']->translate('Newsletter');
10878  break;
10879  case 'view_meta':
10880  $title = $GLOBALS['auth']->translate('Meta');
10881  break;
10882  case 'view_keywords':
10883  $title = $GLOBALS['auth']->translate('Schlagwortregister');
10884  break;
10885  case 'view_release':
10886  $title = $GLOBALS['auth']->translate('Freigabe');
10887  break;
10888  case 'view_navi':
10889  $title = $GLOBALS['auth']->translate('Navigation');
10890  break;
10891  case 'view_stats':
10892  $title = $GLOBALS['auth']->translate('Statistik');
10893  break;
10894  case 'view_workflow':
10895  $title = $GLOBALS['auth']->translate('Workflow');
10896  break;
10897  case 'view_rights':
10898  $title = $GLOBALS['auth']->translate('Rechte');
10899  break;
10900  case 'view_clone':
10901  $title = $GLOBALS['auth']->translate('Klone');
10902  break;
10903  case 'view_archive':
10904  $title = $GLOBALS['auth']->translate('Archiv');
10905  break;
10906  case 'view_media':
10907  $title = $GLOBALS['auth']->translate('Media');
10908  }
10909 
10910  // Kundenspezifischer Reiter
10911  $tabs = $this->getTabs();
10912  $real_perm = preg_replace('/^extra_/', '', $perm);
10913  if (isset($tabs[$real_perm])) {
10914  $title = $GLOBALS['auth']->translate($tabs[$real_perm]['title']);
10915  }
10916 
10917  return $title;
10918  }
10919 
10925  public function getTabs() {
10926  $nav_file = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/'.$this->field['type'].'/admin/navigation.ini';
10927 
10928  if ($this->_site->theme && !Ego_System::file_exists($nav_file))
10929  {
10930  $nav_file = $GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme.'/site/'.$this->field['type'].'/admin/navigation.ini';
10931  }
10932 
10933  if ($this->_site->globalAllowed() && !Ego_System::file_exists($nav_file))
10934  {
10935  $nav_file = $GLOBALS['egotec_conf']['site_dir'].'_global/'.$this->field['type'].'/admin/navigation.ini';
10936  }
10937 
10938  if (!Ego_System::file_exists($nav_file)) {
10939  $nav_file = $GLOBALS['egotec_conf']['lib_dir'].'type/site/'.$this->field['type'].'/admin/navigation.ini';
10940  }
10941 
10942  if (!Ego_System::file_exists($nav_file))
10943  {
10944  $nav_file = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/page/admin/navigation.ini';
10945  }
10946 
10947  if (!Ego_System::file_exists($nav_file))
10948  {
10949  $nav_file = $GLOBALS['egotec_conf']['lib_dir'].'type/site/page/admin/navigation.ini';
10950  }
10951 
10952  $reiter = parse_ini_file($nav_file, true);
10953  $nav_file = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/admin/navigation.ini';
10954 
10955  if (Ego_System::file_exists($nav_file))
10956  { // Zusätzliche Reiter für jeden Seitentyp (aus site/mandant).
10957  $reiter = array_merge($reiter, parse_ini_file($nav_file, true));
10958  }
10959 
10960  if ($this->_site->theme) {
10961  $nav_file = $GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme.'/site/admin/navigation.ini';
10962 
10963  if (Ego_System::file_exists($nav_file)) { // Zusätzliche Reiter für jeden Seitentyp (aus pub/theme).
10964  $reiter = array_merge($reiter, parse_ini_file($nav_file, true));
10965  }
10966  }
10967 
10968  if ($this->_site->globalAllowed()) {
10969  $nav_file = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/navigation.ini';
10970 
10971  if (file_exists($nav_file)) { // Zusätzliche Reiter für jeden Seitentyp (aus site/_global).
10972  $reiter = array_merge($reiter, parse_ini_file($nav_file, true));
10973  }
10974  }
10975 
10976  return $reiter;
10977  }
10978 
10987  public function updateLinks($inherited = true, $cleared = false) {
10988  $links = array();
10989 
10990  // Alle alten Verweise löschen
10991  if (!$cleared) {
10992  $this->removeLinks();
10993  }
10994 
10995  if (!$this->field['deleted']) {
10996  // Alle Verweise sammeln und speichern (nicht für Multimedia Dateien)
10997  if (!in_array($this->field['type'], array('multimedia/file', 'multimedia/image'))) {
10998  $this->updateLinksRecursive($links, $this->field['content'], true);
10999  }
11000  $this->updateLinksRecursive($links, $this->field['short'], true);
11001  $this->updateLinksRecursive($links, $this->extra);
11002 
11003  // Erweiterte Verweise aus Standard Blöcken sammeln
11004  if (is_array($this->extra['_blocks'])) {
11005  foreach ($this->extra['_blocks'] as $orient => $blocks) {
11006  foreach ($blocks as $index => $block) {
11007  $data = [];
11008  if (is_array($this->extra['_contents'][$orient][$index])) {
11009  $data = $this->extra['_contents'][$orient][$index];
11010  }
11011 
11012  switch ($block) {
11013  // Medienliste
11014  case 'medialist':
11015  // Alle untergeordneten Dateien der Multimedia Kategorie sammeln
11016  if (
11017  $data['extra']['source'] == 'multimedia'
11018  && !empty($data['extra']['category'])
11019  && ($category = Ego_System::urltopage($data['extra']['category'], ['auth_or' => '1=1']))
11020  ) {
11021  $children = $category->getChildren(['where' => "type IN ('multimedia/file', 'multimedia/image')"]);
11022  foreach ($children as $child) {
11023  $links['pages'][] = array(
11024  'src_site' => $this->_site->name,
11025  'src_lang' => $this->_site->language,
11026  'src_id' => $this->field['id'],
11027  'dest_site' => $child->getSite()->name,
11028  'dest_lang' => $child->getSite()->language,
11029  'dest_id' => $child->field['id'],
11030  'tag' => '',
11031  'text' => '',
11032  'num' => 1,
11033  'extra_key' => implode(',', ['_contents', $orient, $index, 'extra', 'category'])
11034  );
11035  }
11036  }
11037  }
11038  }
11039  }
11040  }
11041 
11042  // Die eingetragenen Benutzer einfügen
11043  foreach ($this->getUsersArray() as $perm => $users) {
11044  foreach ($users as $user) {
11045  $links['users'][] = array(
11046  'src_site' => $this->_site->name,
11047  'src_lang' => $this->_site->language,
11048  'src_id' => $this->field['id'],
11049  'src_perm' => $perm,
11050  'src_user' => '',
11051  'dest_site' => '',
11052  'dest_lang' => '',
11053  'dest_id' => 0,
11054  'dest_user' => $user['user_id'],
11055  'extra_key' => ''
11056  );
11057  }
11058  }
11059 
11060  $db = new_db_connection();
11061  $db->begin();
11062  foreach ($links as $type => $link_list) {
11063  $table = $type == 'pages' ? 'egotec_links' : 'egotec_user_links';
11064  if ($db->tableExists($table)) {
11065  foreach ($link_list as $link) {
11066  $db->insert(array(
11067  'table' => $table,
11068  'set' => $link
11069  ));
11070  }
11071  }
11072  }
11073  $db->commit();
11074 
11075  /* Bei einer Multimedia Datei müssen alle Verweise
11076  * auf eine Multimedia Kategorie aktualisiert werden */
11077  if ($inherited && $this->_site->site['type'] == 'media') {
11078  $params = array(
11079  'inactive' => true,
11080  'only_active' => false,
11081  'no_cache' => true,
11082  'auth_or' => '1=1',
11083  'deleted' => -1
11084  );
11085  foreach ($this->getAncestors(array(
11086  'where' => "type = 'multimedia/category'"
11087  ), $params) as $ancestor) {
11088  $db->select(array(
11089  'table' => 'egotec_links',
11090  'where' => 'dest_site = :site AND dest_lang = :lang AND dest_id = :id',
11091  'bind' => array(
11092  'site' => $this->_site->name,
11093  'lang' => $this->_site->language,
11094  'id' => $ancestor->field['id']
11095  )
11096  ));
11097  while ($db->nextRecord()) {
11098  try {
11099  $site = new Site($db->Record['src_site'], $db->Record['src_lang']);
11100  if ($page = $site->getPage($db->Record['src_id'], $params)) {
11101  $page->updateLinks(false, $cleared);
11102  }
11103  } catch (Site_Exception $e) {
11104  // Mandant existiert nicht
11105  }
11106  }
11107  }
11108  }
11109  }
11110  }
11111 
11122  private function updateLinksRecursive(&$links, $data, $only_nodes = false, $extra = array(), $num = 0) {
11123  set_time_limit(0);
11124  $params = array(
11125  'inactive' => true,
11126  'only_active' => false,
11127  'no_cache' => true,
11128  'auth_or' => '1=1',
11129  'deleted' => -1
11130  );
11131  if (is_array($data)) {
11132  foreach ($data as $key => $value) {
11133  $tmp = $extra;
11134  $tmp[] = $key;
11135  $this->updateLinksRecursive($links, $value, $only_nodes, $tmp, $num);
11136  }
11137  } elseif (!empty($extra)) {
11138  try {
11139  if ($media = $this->_site->getMediaSite()) {
11140  $more_links = array();
11141  switch ($this->field['type']) {
11142  case 'gallery':
11143  if (
11144  end($extra) == 'gallery_path'
11145  && ($page = $media->getPage($data, array('internal' => true)))
11146  ) {
11147  $more_links[] = $page;
11148  foreach ($page->getChildren(array(), $params) as $child) {
11149  $more_links[] = $child;
11150  }
11151  }
11152  break;
11153  case 'gallery2':
11154  if (end($extra) == 'media_verz') {
11155  $page = Ego_System::urltopage($data);
11156  if ($page) {
11157  $more_links[] = $page;
11158  foreach ($page->getChildren(array(), $params) as $child) {
11159  $more_links[] = $child;
11160  }
11161  }
11162  }
11163  break;
11164  case 'medialist':
11165  case 'buergerservice/leistung/entry':
11166  if (end($extra) == 'multimedia_id') {
11167  if (is_numeric($data)) {
11168  $page = $media->getPage($data, array('internal' => true));
11169  } else {
11170  $page = Ego_System::urltopage($data);
11171  }
11172  if ($page) {
11173  $more_links[] = $page;
11174  foreach ($page->getDescendants(array(), $params) as $descendant) {
11175  $more_links[] = $descendant;
11176  }
11177  }
11178  }
11179  break;
11180  case 'buergerservice/leistung/list':
11181  if (
11182  end($extra) == 'mm_mainDir'
11183  && ($page = $media->getPage($data, array('internal' => true)))
11184  ) {
11185  $more_links[] = $page;
11186  foreach ($page->getDescendants(array(), $params) as $descendant) {
11187  $more_links[] = $descendant;
11188  }
11189  }
11190  break;
11191  case 'wiki/diskussion':
11192  case 'wiki/kommentar':
11193  case 'wiki/portal':
11194  case 'wiki/portal_list':
11195  case 'wiki/page':
11196  if (end($extra) == 'documents') {
11197  foreach (explode(',', $data) as $id) {
11198  if ($page = $media->getPage($id)) {
11199  $more_links[] = $page;
11200  }
11201  }
11202  }
11203  }
11204 
11209  $more_links = array_merge($more_links, $this->getMoreLinks());
11210 
11211  reset($extra);
11212  foreach ($more_links as $link) {
11213  if (!$link) {
11214  continue;
11215  }
11216  $links['pages'][] = array(
11217  'src_site' => $this->_site->name,
11218  'src_lang' => $this->_site->language,
11219  'src_id' => $this->field['id'],
11220  'dest_site' => $link->getSite()->name,
11221  'dest_lang' => $link->getSite()->language,
11222  'dest_id' => $link->field['id'],
11223  'tag' => '',
11224  'text' => '',
11225  'num' => 1,
11226  'extra_key' => implode(',', $extra)
11227  );
11228  }
11229  }
11230  } catch (Site_Exception $e) {
11231  // ignorieren
11232  }
11233  }
11234  if (is_string($data)) {
11235  // index.php URLs
11236  if ($only_nodes) {
11237  $pattern = '/(<([^> ]+) [^>]*)(href="|src="|data="|value="|archive="|class="|url\‍(\')([^,"\']*(index\.php\?|-site-)([^,"\']+))(["\'][^>]*>((.*?)<\/\\2>)?)/ims';
11238  } else {
11239  $pattern = '/(<([^> ]+) [^>]*)?(href="|src="|data="|value="|archive="|class="|url\‍(\')?([^,"\']*(index\.php\?|-site-)([^,"\']+))(["\'][^>]*>((.*?)<\/\\2>)?)?/ims';
11240  }
11241  if (preg_match_all($pattern, $data, $matches)) {
11242  foreach ($matches[0] as $index => $value) {
11243  $url = rtrim($matches[4][$index], '\\');
11244  $info = Ego_System::getUrlInfo(str_replace(
11245  '&amp;amp;',
11246  '&',
11247  $url
11248  ));
11249  if(strlen($info['params']['lang']) != 2) {
11250  continue;
11251  }
11252  if ($info['params']['p']) {
11253  $info['params']['id'] = $info['params']['p'];
11254  }
11255  if ($info['params']['site'] && $info['params']['id']) {
11256  $lang = $info['params']['lang'];
11257  if (empty($lang)) {
11258  try {
11259  $site = new Site($info['params']['site']);
11260  $site->addParam($params);
11261  } catch (Exception $e) {
11262  continue;
11263  }
11264  $lang = $site->language;
11265  }
11266  try {
11267  $page = Ego_System::urltopage($url, array('params' => array('param' => $params)));
11268  } catch (Exception $e) {
11269  continue;
11270  }
11271  if (!$page) {
11272  continue;
11273  }
11274  $text = (string)$matches[9][$index];
11275  $links['pages'][] = array(
11276  'src_site' => $this->_site->name,
11277  'src_lang' => $this->_site->language,
11278  'src_id' => $this->field['id'],
11279  'dest_site' => (string)$info['params']['site'],
11280  'dest_lang' => (string)$lang,
11281  'dest_id' => (int)$info['params']['id'],
11282  'tag' => (string)$matches[2][$index],
11283  'text' => $text,
11284  'num' => ++$num,
11285  'extra_key' => implode(',', $extra)
11286  );
11287  if (trim($text) != '') {
11288  $this->updateLinksRecursive($links, $text, $only_nodes, $extra, $num);
11289  }
11290  if (stripos($matches[0][$index], 'target="_lightbox"') !== false) {
11291  // Bei einer Lightbox werden alle Geschwister ebenfalls verwendet
11292  foreach ($page->getSiblings() as $sibling) {
11293  if (
11294  $sibling->field['type'] == 'multimedia/image'
11295  && !$sibling->field['deleted']
11296  && !$sibling->field['inactive']
11297  ) {
11298  $links['pages'][] = array(
11299  'src_site' => $this->_site->name,
11300  'src_lang' => $this->_site->language,
11301  'src_id' => $this->field['id'],
11302  'dest_site' => (string)$info['params']['site'],
11303  'dest_lang' => (string)$lang,
11304  'dest_id' => $sibling->field['id'],
11305  'tag' => (string)$matches[2][$index],
11306  'text' => $text,
11307  'num' => $num,
11308  'extra_key' => implode(',', $extra)
11309  );
11310  }
11311  }
11312  }
11313  }
11314  }
11315  }
11316 
11317  // Combo Plugin
11318  $pattern = '/^\{.*?"pages":\[\{.*?"(site|lang|id)":.*?\}\].*\}$/ims';
11319  if (preg_match_all($pattern, $data, $matches)) {
11320  require_once('base/Ego_Combo.php');
11321  foreach ($matches[0] as $value) {
11322  try {
11323  $combo = new Ego_Combo($value);
11324  foreach ($combo->getPages(true) as $page) {
11325  $links['pages'][] = array(
11326  'src_site' => $this->_site->name,
11327  'src_lang' => $this->_site->language,
11328  'src_id' => $this->field['id'],
11329  'dest_site' => $page->getSite()->name,
11330  'dest_lang' => $page->getSite()->language,
11331  'dest_id' => $page->field['id'],
11332  'tag' => '',
11333  'text' => '',
11334  'num' => 1,
11335  'extra_key' => implode(',', $extra)
11336  );
11337  }
11338  } catch (Ego_Combo_Exception $e) {
11339  // ignorieren
11340  }
11341  }
11342  }
11343 
11344  // Identitäten
11345  $pattern = '/[a-z0-9_]+'
11346  .preg_quote(self::IDENTITY_SEPARATOR, '/')
11347  .'[a-z]{2}'
11348  .preg_quote(self::IDENTITY_SEPARATOR, '/')
11349  .'\d+/ims';
11350  if (preg_match_all($pattern, $data, $matches)) {
11351  foreach ($matches[0] as $value) {
11352  try {
11353  $page = self::byIdentity($value, $params);
11354  if ($page) {
11355  $links['pages'][] = array(
11356  'src_site' => $this->_site->name,
11357  'src_lang' => $this->_site->language,
11358  'src_id' => $this->field['id'],
11359  'dest_site' => $page->getSite()->name,
11360  'dest_lang' => $page->getSite()->language,
11361  'dest_id' => $page->field['id'],
11362  'tag' => '',
11363  'text' => '',
11364  'num' => 1,
11365  'extra_key' => implode(',', $extra)
11366  );
11367  }
11368  } catch (Site_Exception $e) {
11369  // ignorieren
11370  }
11371  }
11372  }
11373 
11374  // Suche nach 32-Zeichen langen alphanumerischen Hashes und prüfe, ob diese User-IDs sind
11375  if ($extra[0] != 'history') {
11376  $pattern = '/(?<![a-z0-9])([a-z0-9]{32})(?![a-z0-9])/i';
11377  if (preg_match_all($pattern, $data, $matches)) {
11378  foreach ($matches[0] as $index => $values) {
11379  $db = new_db_connection([
11380  'table' => 'egotec_user',
11381  'where' => 'user_id = :user_id',
11382  'bind' => [
11383  'user_id' => $matches[1][$index]
11384  ]
11385  ]);
11386  if ($db->nextRecord()) {
11387  $links['users'][] = array(
11388  'src_site' => $this->_site->name,
11389  'src_lang' => $this->_site->language,
11390  'src_id' => $this->field['id'],
11391  'src_perm' => '',
11392  'src_user' => '',
11393  'dest_site' => '',
11394  'dest_lang' => '',
11395  'dest_id' => 0,
11396  'dest_user' => $db->Record['user_id'],
11397  'extra_key' => implode(',', $extra)
11398  );
11399  }
11400  }
11401  }
11402  }
11403  }
11404  }
11405 
11411  public function removeLinks() {
11412  $db = new_db_connection();
11413 
11414  // Seiten Verweise löschen
11415  $db->delete(array(
11416  'table' => 'egotec_links',
11417  'where' => "src_site = '{$this->_site->name}'"
11418  ." AND src_lang = '{$this->_site->language}'"
11419  ." AND src_id = '{$this->field['id']}'"
11420  ));
11421 
11422  // Benutzer Verweise löschen
11423  if ($db->tableExists('egotec_user_links')) {
11424  $db->delete(array(
11425  'table' => 'egotec_user_links',
11426  'where' => "src_site = '{$this->_site->name}'"
11427  ." AND src_lang = '{$this->_site->language}'"
11428  ." AND src_id = '{$this->field['id']}'"
11429  ));
11430  }
11431  }
11432 
11440  public function getLinks($recursive = false, $c_date = false) {
11441  $links = array();
11442  $c_dates = array();
11443 
11444  $db = new_db_connection();
11445  $db->select(array(
11446  'table' => 'egotec_links',
11447  'where' => "src_site = :site AND src_lang = :lang AND src_id = :id",
11448  'bind' => array(
11449  'site' => $this->_site->name,
11450  'lang' => $this->_site->language,
11451  'id' => $this->field['id']
11452  )
11453  ));
11454  while ($db->nextRecord()) {
11455  $record = $db->Record;
11456  $key = md5(serialize(array($db->Record['dest_site'], $db->Record['dest_lang'])));
11457  $page = null;
11458 
11459  if ($recursive || $c_date) {
11460  // Bei Multimedia Kategorien auch alle Nachfahren ermitteln
11461  try {
11462  $query = array();
11463  $param = array(
11464  'auth_or' => '1=1',
11465  'deleted_or' => '1=1',
11466  'inactive' => true,
11467  'only_active' => false
11468  );
11469 
11470  $site = new Site($db->Record['dest_site'], $db->Record['dest_lang']);
11471  $page = $site->getPage($db->Record['dest_id'], $param);
11472 
11473  if ($page) {
11474  if ($c_date) {
11475  // Nur Nachfahren ermitteln, die seit dem letzten Liveabgleich geändert wurden
11476  if (!isset($c_dates[$key])) {
11477  $c_dates[$key] = '';
11478 
11479  $clusters = Ego_System::getCluster($site);
11480  if (!empty($clusters)) {
11481  // Cluster
11482  foreach ($clusters as $cluster) {
11483  $file = $GLOBALS['egotec_conf']['log_dir'] . $db->Record['dest_site'] . '/live.' . $db->Record['dest_site'] . '_' . $db->Record['dest_lang'] . '.' . $cluster['id'] . '.date';
11484  if (Ego_System::file_exists($file)) {
11485  $date = Ego_System::file_get_contents($file);
11486  if (empty($c_dates[$key]) || $date < $c_dates[$key]) {
11487  $c_dates[$key] = $date;
11488  }
11489  }
11490  }
11491  } else {
11492  // Live
11493  $file = $GLOBALS['egotec_conf']['log_dir'] . $db->Record['dest_site'] . '/live.' . $db->Record['dest_site'] . '_' . $db->Record['dest_lang'] . '.date';
11494  if (Ego_System::file_exists($file)) {
11495  $c_dates[$key] = Ego_System::file_get_contents($file);
11496  }
11497  }
11498  }
11499 
11500  if (!empty($c_dates[$key])) {
11501  $query['where'] = 'm_date > :c_date';
11502  $query['bind'] = array(
11503  'c_date' => $c_dates[$key]
11504  );
11505  }
11506  }
11507 
11508  if ($recursive && $page->field['type'] == 'multimedia/category') {
11509  $descendants = $page->getDescendants($query, $param);
11510  $record['descendants'] = 0;
11511  foreach ($descendants as $descendant) {
11512  $record['descendants']++;
11513  $link = $db->Record;
11514  $link['dest_id'] = $descendant->field['id'];
11515  $link['recursive'] = true;
11516  $links[] = $link;
11517  }
11518  }
11519  }
11520  } catch (Site_Exception $e) {
11521  // ignorieren
11522  }
11523  }
11524 
11525  if ($c_date && !empty($c_dates[$key]) && $page && $page->field['m_date'] <= $c_dates[$key] && empty($record['descendants'])) {
11526  // Verweis ignorieren, wenn er seit dem letzten Liveabgleich nicht geändert wurde und keine relevanten Nachfahren besitzt
11527  continue;
11528  }
11529 
11530  $links[] = $record;
11531  }
11532  return $links;
11533  }
11534 
11544  public function getLinkedPages($recursive = false, $self = true) {
11545  $links = array();
11546  $param = array(
11547  'inactive' => true,
11548  'only_active' => false,
11549  'no_cache' => true,
11550  'auth_or' => '1=1',
11551  'deleted' => -1
11552  );
11553 
11554  $db = new_db_connection();
11555  if ($self) {
11556  foreach ($this->_site->getLanguages() as $lang) {
11557  if ($page = $this->getLanguagePage($lang, $param)) {
11558  $db->select(array(
11559  'table' => 'egotec_links',
11560  'where' => "dest_site = :site1 AND dest_lang = :lang AND dest_id = :id1"
11561  ." AND (src_site != :site2 OR src_id != :id2)", // Auf sich selbst ignorieren
11562  'bind' => array(
11563  'site1' => $this->_site->name,
11564  'lang' => $lang,
11565  'id1' => $this->field['id'],
11566  'site2' => $this->_site->name,
11567  'id2' => $this->field['id']
11568  ),
11569  'order' => 'num ASC'
11570  ));
11571  if ($db->nextRecord()) {
11572  $link = array(
11573  'page' => $page,
11574  'sources' => array()
11575  );
11576 
11577  // Klone werden ignoriert
11578  $clones = array();
11579  if ($page->extra['clones']) {
11580  foreach (explode(',', $page->extra['clones']) as $clone) {
11581  $info = Ego_System::getUrlInfo($clone);
11582  $clones[] = self::createIdentity($info['params']);
11583  }
11584  }
11585 
11586  do {
11587  $record = $db->Record;
11588 
11589  // Klone werden ignoriert
11590  if (!empty($clones) && in_array(self::createIdentity(array(
11591  'site' => $record['src_site'],
11592  'lang' => $record['src_lang'],
11593  'id' => $record['src_id']
11594  )), $clones)) {
11595  continue;
11596  }
11597 
11598  try {
11599  // Nur wenn diese Seite existiert
11600  $db2 = new_db_connection(array(
11601  'table' => $record['src_site'] . '_' . $record['src_lang'],
11602  'where' => 'id = :id',
11603  'bind' => array(
11604  'id' => $record['src_id']
11605  )
11606  ));
11607  } catch (Ego_Sql_Exception $e) {
11608  continue 2;
11609  }
11610  while (!$db2->nextRecord()) {
11611  continue 2;
11612  }
11613 
11614  $src_site = $record['src_site'];
11615  $src_lang = $record['src_lang'];
11616  $src_id = $record['src_id'];
11617 
11618  // Prüfen, ob es sich um einen JSON String handelt
11619  $record['json'] = false;
11620  if ($record['extra_key']) {
11621  $src_page = Page::byIdentity(self::createIdentity(array(
11622  'site' => $src_site,
11623  'lang' => $src_lang,
11624  'id' => $src_id
11625  )), array(
11626  'inactive' => true,
11627  'only_active' => false,
11628  'auth_or' => '1=1'
11629  ));
11630 
11631  if ($src_page) {
11632  $src_value = Ego_System::getAssocValue($src_page->extra, str_replace(',', '.', $record['extra_key']));
11633  if (strpos($src_value, '{') === 0 && @json_decode($src_value)) {
11634  $record['json'] = true;
11635  }
11636  }
11637  }
11638 
11639  $link['sources'][$src_site][$src_lang][$src_id][] = $record;
11640  } while ($db->nextRecord());
11641  if (!empty($link['sources'])) {
11642  $links[] = $link;
11643  }
11644  }
11645  }
11646  }
11647  }
11648 
11649  if ($recursive) {
11650  $descendants = $this->getDescendants(array(), $param);
11651  foreach ($descendants as $descendant) {
11652  $links = array_merge($links, $descendant->getLinkedPages());
11653  }
11654  }
11655 
11656  return $links;
11657  }
11658 
11659  public function getLinkedUsers() {
11660  $links = [];
11661 
11662  $db = new_db_connection();
11663  foreach ($this->_site->getLanguages() as $lang) {
11664  $db->select([
11665  'table' => 'egotec_user_links, egotec_user',
11666  'fields' => '`egotec_user_links`.*, `egotec_user`.username',
11667  'where' => "`egotec_user_links`.src_user = `egotec_user`.user_id AND dest_site = :site AND dest_lang = :lang AND dest_id = :id",
11668  'bind' => [
11669  'site' => $this->_site->name,
11670  'lang' => $lang,
11671  'id' => $this->field['id'],
11672  ],
11673  'order' => '`egotec_user`.username ASC'
11674  ]);
11675 
11676  if ($db->nextRecord()) {
11677  do {
11678  $record = $db->Record;
11679  $user = new User_SQL($record['src_user']);
11680 
11681  $links[] = [
11682  'extra' => $record['extra_key'],
11683  'username' => $user->getFullname(),
11684  'edit' => $GLOBALS['auth']->hasPermissionOn($user),
11685  'url' => get_url('admin.php', [
11686  'view' => 'users',
11687  'user_id' => $record['src_user']
11688  ])
11689  ];
11690  } while ($db->nextRecord());
11691  }
11692  }
11693 
11694  return $links;
11695  }
11696 
11703  public function getMoreLinks() {
11704  return [];
11705  }
11706 
11715  public function getIconUrl($test = false, $folder = false, $quarantine = true) {
11716  if ($quarantine && ($this->extra['quarantine'] || stristr($this->field['extra'], '"quarantine"'))) {
11717  // Quarantäne
11718  return $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/attention.png';
11719  }
11720  if ($this->extra['crop_image']) {
11721  // Bildausschnitt
11722  return $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/crop.png';
11723  }
11724  $url = $test
11725  ? '' // Falls diese Page kein spezielles Icon hat, dann nichts zurückgeben
11726  : ($folder && $this->hasChildren(array(), array('auth_or' => '1=1'))
11727  ? $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/folder.png'
11728  : $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/page.png');
11729  $this->getTypeInfo();
11730  if (!empty($this->typeInfo)) {
11731  if (!empty($this->typeInfo['icon'])) {
11732  $icon = $this->typeInfo['icon'];
11733  $get_path = function() use ($icon) {
11734  $real_path = (string) realpath($icon);
11735  $dir_pos = strpos($real_path, $GLOBALS['egotec_conf']['egotec_dir']);
11736  if ($dir_pos === false) {
11737  // Kann der Pfad nicht gefunden werden, dann automatisch ermitteln
11738  $tmp = explode(DIRECTORY_SEPARATOR, trim($GLOBALS['egotec_conf']['egotec_dir'], DIRECTORY_SEPARATOR));
11739 
11740  $dir = DIRECTORY_SEPARATOR
11741  . array_pop($tmp)
11742  . DIRECTORY_SEPARATOR;
11743  if ($dir_pos = strpos($real_path, $dir)) {
11744  return substr($real_path, $dir_pos + strlen($dir));
11745  }
11746  }
11747  return substr($real_path, $dir_pos + strlen($GLOBALS['egotec_conf']['egotec_dir']));
11748  };
11749  $path = $get_path(); // Abwärtskompatibilität: Pfad mit ../
11750  if (!$path) {
11751  // Pfad ausgehend von egotec_dir
11752  $cwd = getcwd();
11753  chdir($GLOBALS['egotec_conf']['egotec_dir']);
11754  $path = $get_path();
11755  chdir($cwd);
11756  }
11757  $url = $GLOBALS['egotec_conf']['url_dir'] . $path;
11758  } elseif (!empty($this->extra['image_type']) && !$folder) {
11759  $mime = strtolower($this->extra['image_type']);
11760  switch ($mime) {
11761  case 'jpeg':
11762  $mime = 'jpg';
11763  break;
11764  case 'mdb':
11765  $mime = 'access';
11766  break;
11767  case 'htm':
11768  $mime = 'html';
11769  }
11770  if (Ego_System::file_exists($GLOBALS['egotec_conf']['bin_dir'].'admin_skin/egotec/img/icons/small/2013/'.$mime.'.png')) {
11771  $url = $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/icons/small/2013/'.$mime.'.png';
11772  }
11773  }
11774  }
11775  return $url;
11776  }
11777 
11784  public function getTypeInfo($cache = true) {
11785  if (!$cache || empty($this->typeInfo)) {
11786  $key = 'type'.md5(serialize(array($this->_site->name, $this->field['type'])));
11787  $cache = $this->_site->getCacheEntry($key);
11788  if ($cache === null) {
11789  if ($file = $this->_site->getSiteFile($this->field['type'] . DIRECTORY_SEPARATOR . 'type.ini')) {
11790  $this->typeInfo = @parse_ini_file($file, true);
11791  $this->_site->setCacheEntry($key, is_array($this->typeInfo) ? $this->typeInfo : array());
11792  }
11793  } else {
11794  $this->typeInfo = $cache;
11795  }
11796  }
11797  return $this->typeInfo;
11798  }
11799 
11805  public function canChangeType() {
11806  $type_info = $this->getTypeInfo();
11807  return $this->_site->hasRight('change_type') && empty($type_info['unchangeable']);
11808  }
11809 
11815  public function getEditorCSS() {
11816  $css = array();
11817  $content_css = '';
11818  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/editor.css")) {
11819  $css['skin']['editor'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/editor.css";
11820  }
11821  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/editor.css")) {
11822  $css['global']['editor'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/editor.css";
11823  }
11824  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/table.css")) {
11825  $css['skin']['table'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/table.css";
11826  }
11827  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/table.css")) {
11828  $css['global']['table'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/table.css";
11829  }
11830  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/span.css")) {
11831  $css['skin']['span'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/span.css";
11832  }
11833  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/span.css")) {
11834  $css['global']['span'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/span.css";
11835  }
11836  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/img.css")) {
11837  $css['skin']['img'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/img.css";
11838  }
11839  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/img.css")) {
11840  $css['global']['img'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/img.css";
11841  }
11842  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/link.css")) {
11843  $css['skin']['link'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/link.css";
11844  }
11845  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/link.css")) {
11846  $css['global']['link'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/link.css";
11847  }
11848  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/".$this->field['type']."/style.css")) {
11849  $css['type']['style'] = $GLOBALS['egotec_conf']['url_dir']."skin/".$this->_site->skin."/".$this->field['type']."/style.css";
11850  $content_css = $css['type']['style'];
11851  }
11852  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/style.css")) {
11853  $css['skin']['style'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/style.css";
11854  $content_css = $css['skin']['style'];
11855  }
11856  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/style.css")) {
11857  $css['global']['style'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/style.css";
11858  $content_css = $css['global']['style'];
11859  }
11860  if (
11861  $this->extra['_style']
11862  && ($file = $this->_site->getSkinFile($this->field['type'].'/style.'.$this->extra['_style'].'.css', array(), true))
11863  ) {
11864  $css['variant']['style'] = $file;
11865  $content_css = $css['variant']['style'];
11866  }
11867 
11868  // CSS Dateien aus der Designvorlage
11869  if ($this->_site->theme) {
11870  if (empty($css['theme']['editor']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/editor.css")) {
11871  $css['theme']['editor'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/editor.css";
11872  }
11873  if (empty($css['theme']['table']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/table.css")) {
11874  $css['theme']['table'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/table.css";
11875  }
11876  if (empty($css['theme']['span']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/span.css")) {
11877  $css['theme']['span'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/span.css";
11878  }
11879  if (empty($css['theme']['img']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/img.css")) {
11880  $css['theme']['img'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/img.css";
11881  }
11882  if (empty($css['theme']['link']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/link.css")) {
11883  $css['theme']['link'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/link.css";
11884  }
11885  if (empty($css['theme']['style']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/".$this->field['type']."/style.css")) {
11886  $css['theme']['type'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/".$this->field['type']."/style.css";
11887  }
11888  if (empty($css['theme']['style']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/style.css")) {
11889  $css['theme']['style'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/style.css";
11890  }
11891  }
11892 
11893  // admin.css einbinden
11894  if ($GLOBALS['admin_area'] && ($file = $this->_site->getSkinFile('admin.css', array(), true))) {
11895  $css['admin']['style'] = $file;
11896  }
11897 
11898  return array(
11899  'css' => $css,
11900  'content_css' => $content_css
11901  );
11902  }
11903 
11909  public function getLinkText() {
11910  return $this->field['name'];
11911  }
11912 
11918  public function getIdentity() {
11919  return self::createIdentity(array(
11920  'site' => $this->_site->name,
11921  'lang' => $this->_site->language,
11922  'id' => $this->field['id']
11923  ));
11924  }
11925 
11932  public static function isIdentity($identity) {
11933  return is_string($identity)
11934  && ($v = explode(self::IDENTITY_SEPARATOR, $identity))
11935  && sizeof($v) == 3
11936  && !is_numeric($v[0])
11937  && strlen($v[1]) == 2
11938  && is_numeric($v[2]);
11939  }
11940 
11947  public static function createIdentity($params) {
11948  return implode(self::IDENTITY_SEPARATOR, array($params['site'], $params['lang'], $params['id']));
11949  }
11950 
11960  public static function byIdentity($identity, $param = array(), $site = null) {
11961  [$name, $lang, $id] = explode(self::IDENTITY_SEPARATOR, $identity);
11962  try {
11963  if (
11964  !$site
11965  || $site->name != $name
11966  || $site->language != $lang
11967  ) {
11968  if (
11969  $GLOBALS['site']
11970  && $GLOBALS['site']->name == $name
11971  && $GLOBALS['site']->language == $lang
11972  ) {
11973  $site = $GLOBALS['site'];
11974  } else {
11975  $site = new Site($name, $lang, '', !$GLOBALS['admin_area'] || $_SESSION['login']['live_preview']);
11976  }
11977  }
11978  if (!is_array($param)) {
11979  $param = array();
11980  }
11981  return $site->getPage($id, $param);
11982  } catch (Site_Exception $e) {
11983  // ignorieren
11984  }
11985  return null;
11986  }
11987 
11997  public function inheritExtra($keys, $mixed = false, $types = array(), $no_rights = true) {
11998  $cache_key = 'inherit'.md5(serialize([$this->getIdentity(), $keys, $mixed, $types, $no_rights]));
11999  $cache_entry = $this->_site->getCacheEntry($cache_key);
12000 
12001  if ($cache_entry === null) {
12002  $values = array();
12003 
12004  if (!empty($keys)) {
12005  $query = array();
12006  if (!empty($types)) {
12007  // Die Vorfahren müssen einen bestimmten Seitentyp haben
12008  $query['where'] = array();
12009  $query['bind'] = array();
12010  $n = 0;
12011  foreach ($types as $type) {
12012  $query['where'][] = 'type = :type'.(++$n);
12013  $query['bind']['type'.$n] = $type;
12014  }
12015  $query['where'] = implode(' OR ', $query['where']);
12016  }
12017  $param = array();
12018  if ($no_rights) {
12019  // Keine Rechteprüfung
12020  $param['auth_or'] = '1=1';
12021  }
12022 
12023  $ancestors = array();
12024  // Vorfahren umdrehen
12025  foreach ($this->getAncestors($query, $param) as $ancestor) {
12026  $ancestors[] = $ancestor;
12027  }
12028  $ancestors = array_reverse($ancestors);
12029  array_unshift($ancestors, $this);
12030  foreach ($ancestors as $ancestor) {
12031  foreach ($keys as $key) {
12032  $value = Ego_System::getAssocValue($ancestor->extra, $key);
12033  if ($value !== null && !isset($values[$key])) {
12034  $values[$key] = $value;
12035  if (!$mixed) {
12036  // Alle Werte dieses Vorfahren übernehmen
12037  foreach ($keys as $k) {
12038  if ($key != $k) {
12039  $v = Ego_System::getAssocValue($ancestor->extra, $k);
12040  if ($v !== null) {
12041  $values[$k] = $v;
12042  }
12043  }
12044  }
12045  break 2;
12046  }
12047  }
12048  }
12049  }
12050  }
12051 
12052  $this->_site->setCacheEntry($cache_key, $values);
12053  } else {
12054  $values = $cache_entry;
12055  }
12056  return $values;
12057  }
12058 
12064  public function addPiwikSite() {
12065  require_once 'stats/Ego_Piwik.php';
12066  $piwik = new Ego_Piwik();
12067  $piwikdata = $piwik->createWebsite($this);
12068  if (!is_array($piwikdata)) {
12069  return null;
12070  }
12071  return $piwikdata;
12072  }
12073 
12080  public function isUniqueUrl($url) {
12081  $ignore_ids = array($this->field['id']);
12082 
12083  // Seite ist eine Workflow-, Freigabekopie: Meta URL der Originalseite ignorieren
12084  if ($this->isWorkflowCopy()) {
12085  $ignore_ids[] = (int) $this->extra['original_id'];
12086 
12087  $original_page = $this->_site->getPage((int) $this->extra['original_id']);
12088  if (!empty($original_page->extra['release_ids'])) {
12089  foreach ($original_page->extra['release_ids'] as $release_id) {
12090  $ignore_ids[] = (int) $release_id;
12091  }
12092  }
12093  }
12094  if ($this->isReleaseCopy()) {
12095  $ignore_ids[] = (int) $this->extra['release_id'];
12096 
12097  $original_page = $this->_site->getPage((int) $this->extra['release_id']);
12098  if (!empty($original_page->extra['workflow_page'])) {
12099  $ignore_ids[] = (int) $original_page->extra['workflow_page'];
12100  }
12101  }
12102 
12103  // Seite hat Workflow-, Freigabekopien: Meta URLs dieser Seiten ignorieren
12104  if (!empty($this->extra['release_ids'])) {
12105  foreach ($this->extra['release_ids'] as $release_id) {
12106  $ignore_ids[] = (int) $release_id;
12107  }
12108  }
12109  if (!empty($this->extra['workflow_page'])) {
12110  $ignore_ids[] = (int) $this->extra['workflow_page'];
12111  }
12112 
12113  $db = new_db_connection(array(
12114  'table' => $this->_site->pageTable,
12115  'where' => 'url = :url AND deleted = 0 AND id NOT IN (' . implode(', ', array_unique($ignore_ids)) . ')',
12116  'bind' => array(
12117  'url' => $url
12118  )
12119  ));
12120  if (!$db->nextRecord()) {
12121  // Bei der flachen URL Generierung darf es keine Seite mit diesem Namen geben
12122  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'flat') {
12123  $db->select(array(
12124  'table' => $this->_site->pageTable,
12125  'where' => 'name = :name AND id != :id AND deleted = 0',
12126  'bind' => array(
12127  'name' => $url,
12128  'id' => $this->field['id']
12129  )
12130  ));
12131  if ($db->nextRecord()) {
12132  return false;
12133  }
12134  }
12135 
12136  // Bei der Standard URL Generierung darf es keine Seite in erster Ebene mit diesem Namen geben
12137  if (empty($GLOBALS['egotec_conf']['rewrite_engine'])) {
12138  $db->select(array(
12139  'table' => $this->_site->pageTable,
12140  'where' => 'page_id = :root_id AND name = :name AND id != :id AND deleted = 0',
12141  'join' => $this->_site->pageTable.'_children ON ('.$this->_site->pageTable.'_children.child = id)',
12142  'bind' => array(
12143  'root_id' => $this->_site->rootId,
12144  'name' => $url,
12145  'id' => $this->field['id']
12146  )
12147  ));
12148  if ($db->nextRecord()) {
12149  return false;
12150  }
12151  }
12152 
12153  // Der Name darf nicht von einem Mandanten verwendet werden
12154  foreach (Ego_System::getAllSites() as $site) {
12155  if ($site->name == $url) {
12156  return false;
12157  }
12158  }
12159  return true;
12160  }
12161  return false;
12162  }
12163 
12173  public function validateFile($source, $name = '', $form = array(), $files_conf = array()) {
12174  $files_list = array();
12175 
12176  // Übergebene Einstellungen verwenden
12177  if (!empty($files_conf)) {
12178  $files_list[] = $files_conf;
12179  }
12180 
12181  // Einstellungen des Dateiupload Feldes verwenden (alter Editor)
12182  if (!empty($form) && !empty($this->extra['mandatory'][$form['form']][$form['field']]['files'])) {
12183  $files_list[] = $this->extra['mandatory'][$form['form']][$form['field']]['files'];
12184  }
12185 
12186  // Einstellungen des Mandanten verwenden
12187  if (!empty($this->_site->admin['files'])) {
12188  $files_list[] = $this->_site->admin['files'];
12189  }
12190 
12191  // Einstellungen der globalen Konfiguration verwenden
12192  if (!empty($GLOBALS['egotec_conf']['files'])) {
12193  $files_list[] = $GLOBALS['egotec_conf']['files'];
12194  }
12195 
12196  if (!empty($files_list)) {
12197  // Die Datei zuerst vom Virenscanner überprüfen lassen
12198  foreach ($files_list as $files) {
12199  if ($files['validate_files']) {
12200  try {
12201  Ego_System::scan($source);
12202  } catch (Exception $e) {
12203  egotec_error_log($e->getMessage());
12204  return false;
12205  }
12206 
12207  // Die Prüfung abbrechen, da sie erfolgreich war
12208  break;
12209  }
12210  }
12211 
12212  // Die Datei erst nach dem Virenscanner verarbeiten
12213  require_once('base/Ego_MimeType.php');
12214  $mime = new Ego_MimeType();
12215  $prepare_type = function($t) {
12216  return trim(ltrim(mb_strtolower($t), "."));
12217  };
12218  $type = $prepare_type(pathinfo($name ? $name : @basename($source), PATHINFO_EXTENSION));
12219  $size = @filesize($source);
12220 
12221  foreach ($files_list as $files) {
12222  if (
12223  !empty($files['whitelist'])
12224  || !empty($files['blacklist'])
12225  || !empty($files['filesize'])
12226  ) {
12227  $whitelist = array_map($prepare_type, explode(',', (string) $files['whitelist']));
12228  $blacklist = array_map($prepare_type, explode(',', (string) $files['blacklist']));
12229  if (
12230  (!empty($files['whitelist']) && (!in_array($type, $whitelist) || !$mime->hasMimeType($source, $whitelist)))
12231  || (!empty($files['blacklist']) && empty($files['whitelist']) && (in_array($type, $blacklist) || $mime->hasMimeType($source, $blacklist)))
12232  || (!empty($files['filesize']) && $size > (int) $files['filesize'])
12233  ) {
12234  return false;
12235  }
12236 
12237  // Die Prüfung abbrechen, da die Anforderungen erfüllt sind
12238  break;
12239  }
12240  }
12241  }
12242 
12243  return true;
12244  }
12245 
12252  public function isFrontendAdmin($check_rights = true) {
12253  $info = $this->getTypeInfo();
12254  return $this->_site->isFrontendAdmin($check_rights)
12255  && !$info['frontend_ignore']
12256  && (
12257  !$check_rights
12258  || $this->hasRights(array('view'))
12259  );
12260  }
12261 
12268  public function isCurrentPage($lang = false) {
12269  return ($_REQUEST['site'] ? $_REQUEST['site'] : $GLOBALS['default_site']) == $this->_site->name
12270  && (!$lang || ($_REQUEST['lang'] ? $_REQUEST['lang'] : $this->_site->site['default_language']) == $this->_site->language)
12271  && ($_REQUEST['id'] ? $_REQUEST['id'] : ($_REQUEST['list'] ? $_REQUEST['list'] : $this->_site->rootId)) == $this->field['id'];
12272  }
12273 
12279  public function setCurrentPage() {
12280  $_REQUEST['site'] = $this->_site->name;
12281  $_REQUEST['lang'] = $this->_site->language;
12282  $_REQUEST['id'] = $this->field['id'];
12283  $GLOBALS['site'] = &$this->_site;
12284  $GLOBALS['page'] = &$this;
12285  }
12286 
12293  public function reset($self = true) {
12294  $db = new_db_connection();
12295 
12296  // Archiv
12297  if ($self) {
12298  // Zurücksetzen
12299  $db->delete(array(
12300  'table' => $this->_site->pageTable.'_v',
12301  'where' => "id = {$this->field['id']} AND m_date > :date",
12302  'bind' => array(
12303  'date' => $this->lastChangeDate
12304  )
12305  ));
12306  } else {
12307  // Veröffentlichen
12308  $db->delete(array(
12309  'table' => $this->_site->pageTable.'_v',
12310  'where' => "id = {$this->field['id']} AND m_date > :date1 AND m_date != :date2",
12311  'bind' => array(
12312  'date1' => $this->lastChangeDate,
12313  'date2' => $this->field['m_date']
12314  )
12315  ));
12316  }
12317 
12318  // Mediapool
12319  $last_c_date = Ego_System::dateEncode($this->lastChangeDate);
12320  $this_c_date = Ego_System::dateEncode($this->field['m_date']);
12321  foreach (glob($this->getMediapool()->dir().'*', GLOB_ONLYDIR) as $dir) {
12322  $dir_c_date = basename($dir);
12323  if (
12324  is_numeric($dir_c_date)
12325  && (int) $dir_c_date != $this_c_date
12326  && (int) $dir_c_date > $last_c_date
12327  ) {
12328  Ego_System::deldir($dir);
12329  }
12330  }
12331  }
12332 
12338  public function getNextReplicationDate() {
12339  return $this->_site->getNextReplicationDate($this);
12340  }
12341 
12347  public function getCacheEntry($key) {
12348  return $this->_site->getCacheEntry("{$key}_{$this->field['id']}");
12349  }
12350 
12358  public function setCacheEntry($key, $value) {
12359  $this->_site->setCacheEntry("{$key}_{$this->field['id']}", $value);
12360  }
12361 
12370  public function getListItems($where = '', $no_limit = false) {
12371  $items = array();
12372 
12373  $limit = (isset($_REQUEST['dt']['start']) && !$no_limit
12374  ? $_REQUEST['dt']['start'] . ',' . $_REQUEST['dt']['length']
12375  : '');
12376  $order = '';
12377 
12378  // Bei der Server seitigen Abfrage wird die Sortierung übergeben
12379  if (
12380  isset($_REQUEST['dt']['order'])
12381  && isset($_REQUEST['dt']['order']['dir'])
12382  && isset($_REQUEST['dt']['order']['field'])
12383  ) {
12384  switch ($_REQUEST['dt']['order']['dir']) {
12385  case 'asc':
12386  $order = $_REQUEST['dt']['order']['field'] . ' ASC';
12387  break;
12388  case 'desc':
12389  $order = $_REQUEST['dt']['order']['field'] . ' DESC';
12390  }
12391  }
12392 
12393  $query = array(
12394  'where' => $where
12395  );
12396 
12397  if ($limit != '') {
12398  $query['limit'] = $limit;
12399  $query['order'] = $order == '' ? 'id ASC' : $order;
12400  }
12401 
12402  foreach ($this->getChildren($query, array(
12403  'inactive' => true,
12404  'only_active' => false
12405  )) as $child) {
12406  $child->field['identity'] = $child->getIdentity();
12407  $items[] = $child;
12408  }
12409 
12410  // Bei der Server seitigen Abfrage ist die maximale Anzahl erforderlich
12411  if (isset($_REQUEST['dt']['start'])) {
12412  $_REQUEST['dt']['total'] = $this->getChildren(array(
12413  'where' => $where,
12414  ), array(
12415  'inactive' => true,
12416  'only_active' => false
12417  ))->numRecords();
12418  }
12419 
12420  return $items;
12421  }
12422 
12429  public function addListItem($params) {
12430  $this->newChild(array(
12431  'name' => (string) $params['data']->name,
12432  'title' => (string) $params['data']->name,
12433  'type' => $params['type'] ? $params['type'] : 'page'
12434  ));
12435  }
12436 
12443  public function removeListItem($params) {
12444  if ($page = self::byIdentity($params['identity'])) {
12445  $page->destroy();
12446  return true;
12447  }
12448  return false;
12449  }
12450 
12457  public function removeSelectedListItem($params) {
12458  foreach ($params['data']->identities as $identity) {
12459  if ($page = self::byIdentity($identity)) {
12460  $page->destroy();
12461  }
12462  }
12463  return true;
12464  }
12465 
12472  public function reorderListItem($params) {
12473  $children = array();
12474  foreach ($params['data'] as $identity) {
12475  [$name, $lang, $id] = explode(self::IDENTITY_SEPARATOR, $identity);
12476  if ($name == $this->_site->name && $lang == $this->_site->language) {
12477  $children[] = (int) $id;
12478  }
12479  }
12480 
12481  $this->archiveOnly = false;
12482  $this->update(array(
12483  'field' => array(
12484  'children_order' => 'children'
12485  ),
12486  'children' => $children
12487  ));
12488  }
12489 
12496  public function getFormListConf($orient) {
12497  $conf = array(
12498  'a_date' => array(
12499  'title' => $GLOBALS['auth']->translate('Empfangen'),
12500  'formatter' => 'date',
12501  'sortable' => true,
12502  'width' => '15%'
12503  )
12504  );
12505  if (is_array($this->extra['_blocks'][$orient])) {
12506  $upload = false;
12507  foreach ($this->extra['_blocks'][$orient] as $index => $block) {
12508  if (strpos($block, 'input_') === 0 && $block != 'input_submit' && isset($this->extra['_contents'][$orient][$index])) {
12509  if ($block == 'input_file' && $this->extra['_forms'][$orient]['export'] == 'page') {
12510  $upload = true;
12511  continue;
12512  }
12513  $content = $this->extra['_contents'][$orient][$index];
12514  $label = $content['label'] ? trim($content['label'], ' :') : $content['extra']['name'];
12515  if ($block == 'input_checkbox') {
12516  require_once 'base/Ego_Combo.php';
12517  $combo = new Ego_Combo($content['extra']['values']);
12518  foreach ($combo->getData() as $data) {
12519  $conf["data.{$data->field_name}"] = array(
12520  'title' => $label . ': ' . ($data->label ? trim($data->label, ' :') : $data->field_name),
12521  'type' => 'extra',
12522  'sortable' => false
12523  );
12524  }
12525  } elseif (isset($content['extra']['name'])) {
12526  $conf["data.{$content['extra']['name']}"] = array(
12527  'title' => $content['label'] ? trim($content['label'], ' :') : $content['extra']['name'],
12528  'type' => 'extra',
12529  'sortable' => false
12530  );
12531  }
12532  }
12533  }
12534  if ($upload) {
12535  // Mediapool der Unterseiten anzeigen
12536  $conf['pool'] = array(
12537  'title' => $GLOBALS['auth']->translate('Dateien'),
12538  'formatter' => 'pool',
12539  'width' => 75,
12540  'align' => 'center',
12541  'sortable' => false
12542  );
12543  }
12544  }
12545  return $conf;
12546  }
12547 
12554  public function getDataConf($type = '') {
12555  $data = [];
12556 
12557  $files = Ego_System::getFiles('site', $this->_site->name, ($type ?: $this->field['type']) . '/admin/data.json', [], $this->_site->theme, true);
12558  foreach (array_keys(array_reverse($files)) as $file) {
12559  if ($file != '_empty') {
12560  $new_data = json_decode(Ego_System::file_get_contents($GLOBALS['egotec_conf']['egotec_dir'] . $file), true);
12561  if ($new_data['extend']) {
12562  // Konfigurationen zusammenführen
12563  $data = array_merge_recursive($data, $new_data);
12564  } else {
12565  // Konfigurationen überschreiben
12566  $data = $new_data;
12567  }
12568  }
12569  }
12570 
12571  return $data;
12572  }
12573 
12584  public function fetch($params = array(), $outputfilter = false, $script = true, $includes = true, $variant = '') {
12585  if ($template = $this->getTemplate($GLOBALS['is_mobile'], 'body', $variant)) {
12586  $original_site = $GLOBALS['site'];
12587  $original_page = $GLOBALS['page'];
12588  $original_smarty = $GLOBALS['smarty'];
12589  $GLOBALS['site'] = $site = $this->getSite();
12590  $GLOBALS['page'] = $page = $this;
12591  $auth = $GLOBALS['auth'];
12592 
12593  // Jedes "fetch" muss ein auf die Site und Page eingestelltes Smarty Objekt für das Frontend verwenden
12594  $GLOBALS['smarty'] = $smarty = Ego_Smarty::createFrontend($site, array(
12595  'page' => $page
12596  ), true);
12597 
12598  // Skript für den Seitentyp einbinden (Sandbox)
12599  $require_script = function($filename) use ($site, $page, $smarty, $auth) {
12600  require($filename);
12601  };
12602  if ($script && ($filename = $site->getSiteFile($page->field['type'].'/index.php'))) {
12603  $require_script($filename);
12604  }
12605  if (!$outputfilter) {
12606  unset($smarty->_plugins['outputfilter'], $smarty->autoload_filters['output']);
12607  }
12608  $smarty->assign(array_merge(array(
12609  'site' => $site,
12610  'page' => $page
12611  ), $params));
12612 
12613  // Styles und Skripte einbinden
12614  $html = $includes ? $page->getHtml(false) : '';
12615  $html .= $smarty->fetch($template);
12616 
12617  $GLOBALS['site'] = $original_site;
12618  $GLOBALS['page'] = $original_page;
12619  $GLOBALS['smarty'] = $original_smarty;
12620  } else {
12621  $html = $this->field['content'];
12622  }
12623  return $html;
12624  }
12625 
12632  public function isValidSuffix($suffix) {
12633  $result = true;
12634  switch ($this->_site->site['type']) {
12635  case 'media':
12636  // Multimedia Dateien müssen immer auf .<image_type> enden.
12637  require_once 'base/Ego_Output.php';
12638  foreach (array_keys(Ego_Output::$convert_types) as $type) {
12639  if ($suffix == ".$type" && $this->field['type'] == 'multimedia/image') {
12640  // Automatische Umwandlung eines Bildes zulassen
12641  return $result;
12642  }
12643  }
12644  if (
12645  in_array($this->field['type'], array('multimedia/file', 'multimedia/image'))
12646  && !empty($this->extra['image_type'])
12647  && '.' . $this->extra['image_type'] != $suffix
12648  ) {
12649  $result = false;
12650  }
12651  break;
12652  case 'content':
12653  $key = 'suffixes';
12654  $suffixes = $this->_site->getCacheEntry($key);
12655  $type = $this->field['type'];
12656  if ($GLOBALS['is_mobile']) {
12657  $type .= '@mobile';
12658  }
12659  $result = $suffixes[$type][$suffix];
12660  if (!is_bool($result)) {
12661  $result = true;
12662  // Nur wenn nicht .html und bestimmte <suffix> Ausnahmen, die in Seitentypen abgefragt werden.
12663  // Existiert index.<suffix>.* nicht, muss body.<suffix>.* existieren.
12664  if (
12665  !in_array($suffix, array('.html', '.rss', '.ical', '.ics'))
12666  && ($template = $this->getTemplate($GLOBALS['is_mobile'], 'index'))
12667  && strpos(basename($template), "index{$suffix}.") !== 0
12668  && ($template = $this->getTemplate($GLOBALS['is_mobile'], 'body'))
12669  && strpos(basename($template), "body{$suffix}.") !== 0
12670  ) {
12671  $result = false;
12672  }
12673  $suffixes[$type][$suffix] = $result;
12674  $this->_site->setCacheEntry($key, $suffixes);
12675  }
12676  }
12677  return $result;
12678  }
12679 
12685  public function getSocialNetworks() {
12686  if (in_array($this->field['type'], explode(',', $this->_site->admin['social']['types']))) {
12687  return $this->_site->getSocialNetworks();
12688  }
12689  return array();
12690  }
12691 
12697  public function compressVideo() {
12698  @set_time_limit(0);
12699 
12700  // Pfad zur Originaldatei (Multimedia)
12701  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media/' . $this->_site->name;
12702  $dest = $media_dir . DIRECTORY_SEPARATOR . $this->getMediaFilename(true);
12703 
12704  // Auflösung der Originaldatei ermitteln
12705  $resolution = Ego_System::exec('ffprobe', array(
12706  '-v',
12707  'error',
12708  '-select_streams',
12709  'v:0',
12710  '-show_entries',
12711  'stream=height',
12712  '-of',
12713  'csv=s=x:p=0',
12714  $dest,
12715  '2>&1'
12716  ));
12717 
12718  // Mediapool Dateien entfernen
12719  $this->getMediapool()->clear();
12720 
12721  foreach (Ego_System::VIDEO_RESOLUTIONS as $height => $scale) {
12722  if ($resolution >= $height) {
12723  $tmp = tempnam($GLOBALS['egotec_conf']['tmp_dir'], 'video');
12724  $scale = preg_replace('/^\d+:/', '-2:', $scale); // Seitenverhältnis beibehalten
12725 
12726  // Verarbeitungsstatus verfolgen
12727  require_once 'base/Ego_Progress.php';
12728  $progress = new Ego_Progress('worker_' . $this->getIdentity() . '_' . $height . 'p');
12729  Ego_System::exec('ffmpeg', array(
12730  '-i',
12731  $dest,
12732  '-vf',
12733  'scale='.$scale,
12734  '-f',
12735  'mp4',
12736  '-strict',
12737  '-2',
12738  '-y',
12739  $tmp,
12740  '-hide_banner',
12741  '2>&1'
12742  ), $output);
12743 
12744  // Komprimierte Datei in den Mediapool der Originaldatei ablegen
12745  if (Ego_System::file_exists($tmp)) {
12746  $this->getMediapool()->put($tmp, "{$height}p.mp4");
12747  @unlink($tmp);
12748  }
12749 
12750  $progress->clear();
12751  }
12752  }
12753  }
12754 
12763  public function addResolution(int $width, int $height): void {
12764  @set_time_limit(0);
12765 
12766  // Pfad zur Originaldatei (Multimedia)
12767  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media/' . $this->_site->name;
12768  $tmp = tempnam($GLOBALS['egotec_conf']['tmp_dir'], 'video');
12769  $scale = "$width:$height";
12770  $name = "{$width}_$height";
12771 
12772  // Verarbeitungsstatus verfolgen
12773  require_once 'base/Ego_Progress.php';
12774  $progress = new Ego_Progress('worker_' . $this->getIdentity() . '_' . $name);
12775  Ego_System::exec('ffmpeg', [
12776  '-i',
12777  $media_dir . DIRECTORY_SEPARATOR . $this->getMediaFilename(true),
12778  '-vf',
12779  'scale=' . $scale,
12780  '-f',
12781  'mp4',
12782  '-strict',
12783  '-2',
12784  '-y',
12785  $tmp,
12786  '-hide_banner',
12787  '2>&1'
12788  ], $output);
12789 
12790  // Komprimierte Datei in den Mediapool der Originaldatei ablegen
12791  if (Ego_System::file_exists($tmp)) {
12792  $this->getMediapool()->put($tmp, "$name.mp4");
12793  @unlink($tmp);
12794  }
12795 
12796  $progress->clear();
12797  }
12798 
12802  public function convertVideo() {
12803  $original_file = $GLOBALS['egotec_conf']['var_dir'] . "media/" . $this->_site->name . "/" . $this->getMediaFilename();
12804  $target_file = tempnam($GLOBALS['egotec_conf']['var_dir'] . 'tmp', 'convert');
12805 
12806  $log_file = $GLOBALS['egotec_conf']['tmp_dir'] . 'ffmpeg_log';
12807 
12809  "ffmpeg",
12810  [
12811  "-y",
12812  "-i",
12813  $original_file,
12814  "-f mp4",
12815  $target_file,
12816  "2>&1 | tee",
12817  $log_file
12818  ]
12819  );
12820 
12821  $this->updateFile($target_file, $this->field['name'] . '_converted.mp4');
12822  if ($this->_site->admin['video']['compress']) {
12823  // Video komprimieren
12824  $this->compressVideo();
12825  }
12826 
12827  return true;
12828  }
12829 
12840  public function getThumbnail($width, $height = 0, $pool = '', $dir = '', $params = []) {
12841  // Pfad, in welchem das generierte Thumbnail zwischengespeichert wird
12842  $thumbnail = $GLOBALS['egotec_conf']['cachemedia_dir']
12843  . $this->_site->name . '/'
12844  . $this->_site->language . '/'
12845  . $this->field['id'] . '/'
12846  . strtotime($this->field['m_date']) . '/'
12847  . 'thumb_' . $width . 'x' . $height . '_' . md5(serialize([$pool, $dir, $params]));
12848 
12849  if (!Ego_System::file_exists($thumbnail)) {
12850  $file = '';
12851  $mime = '';
12852  if ($pool) {
12853  // Mediapool
12854  $info = $this->getMediapool()->get($pool, $dir);
12855  if (!empty($info) && !$info['quarantine']) {
12856  $file = $info['file'];
12857  $mime = $info['mime'];
12858  }
12859  } elseif (
12860  in_array($this->field['type'], ['multimedia/file', 'multimedia/image'])
12861  && !$this->extra['quarantine']
12862  ) {
12863  // Multimedia
12864  $file = $GLOBALS['egotec_conf']['var_dir'] . 'media/' . $this->_site->name . '/' . $this->getMediaFilename();
12865  $mime = $this->extra['mime_type'];
12866  }
12867 
12868  // Pfad erzeugen, falls er nicht existiert
12869  $thumbnail_dir = dirname($thumbnail);
12870  if (!Ego_System::file_exists($thumbnail_dir)) {
12871  Ego_System::mkdir($thumbnail_dir);
12872  }
12873 
12874  // Thumbnail neu generieren
12875  if ($file && Ego_System::file_exists($file)) {
12876  if ($mime == 'application/pdf' || strpos($mime, 'image') === 0) {
12877  // PDF, Animationen und Bilder können über "index" das erste Frame festlegen
12878  require_once 'base/Ego_Image.php';
12879  $image = new Ego_Image($file . '[' . ($params['index'] ?? 0) . ']');
12880  if ($tmp = $image->thumbnail($width, $height, $params)) {
12881  // Temporäres Thumbnail in den Cache verschieben
12882  @rename($tmp, $thumbnail);
12883  } else {
12884  return null;
12885  }
12886  } else {
12887  // TODO Videos mit ffmpeg
12888  return null;
12889  }
12890  }
12891  }
12892 
12893  // Die Thumbnail URL für die Verwendung im Template zurückliefern
12894  if ($params['get_url']) {
12895  return $this->getUrl(array_filter([
12896  'thumbnail' => implode('x', array_filter([$width, $height, (int) $params['index']])),
12897  'pool' => $pool,
12898  'dir' => $dir
12899  ]));
12900  }
12901 
12902  return $thumbnail;
12903  }
12904 
12912  public function replicate($method, ...$params) {
12913  if ($GLOBALS['__egotec_skip_replication'] === $method) {
12914  unset($GLOBALS['__egotec_skip_replication']);
12915  }
12916 
12917  // Nur wenn der Server ein Liveserver ist, die Live-Replikation aktiviert
12918  // und nur wenn die Replikation von einem anderen Server gestartet wurde
12919  if (
12920  $this->getSite()->admin['cluster']['replication']
12921  && $GLOBALS['egotec_conf']['liveserver']
12922  && !$_SERVER['HTTP_X_REPLICATION']
12923  && !$GLOBALS['__egotec_skip_replication']
12924  ) {
12925  require_once 'base/Ego_REST_Client.php';
12926 
12927  // Mediapool Methode erkennen
12928  if ($pool = (($parts = explode('.', $method, 2))[0] == 'pool')) {
12929  $method = $parts[1];
12930  }
12931 
12932  // Aktion über die Methode ermitteln
12933  $rest = parse_ini_file($GLOBALS['egotec_conf']['lib_dir'] . 'base/rest.ini', true);
12934  if (
12935  ($pool && ($conf = $rest['pool'][$method]))
12936  || ($conf = $rest['page'][$method])
12937  ) {
12938  [$action] = explode(':', $conf, 2);
12939  } else {
12940  // Die Methode wird nicht unterstützt
12941  return;
12942  }
12943 
12944  $replication = function() use ($method, $params, $action, $pool) {
12945  // Hole alle Cluster
12946  $clusters = Ego_System::getCluster($this->getSite());
12947 
12948  // Lege den Benutzer fest, in diesem Fall der Benutzer des Liveabgleichs
12949  $user_id = new_db_connection([
12950  'table' => 'egotec_user',
12951  'where' => 'username = :username',
12952  'bind' => [
12953  'username' => $this->getSite()->admin['live']['login']
12954  ]
12955  ])->nextRecord()['user_id'];
12956  $user = new User_SQL($user_id);
12957  $path = implode('/', array_filter([
12958  $this->getSite()->name,
12959  $this->getSite()->language,
12960  $this->field['id'],
12961  $pool ? 'pool' : null,
12962  $method
12963  ]));
12964 
12971  $convert_pages = function ($values) use (&$convert_pages) {
12972  foreach ($values as $key => $value) {
12973  if (is_array($value)) {
12974  $values[$key] = $convert_pages($value);
12975  } elseif (is_a($value, 'Page')) {
12976  $values[$key] = '@identity:' . $value->getIdentity();
12977  }
12978  }
12979  return $values;
12980  };
12981  $params = $convert_pages($params);
12982 
12983  // Daten und Uploads trennen
12984  $data = $files = [];
12985  foreach ($params as $key => $value) {
12986  // Dateiupload erkennen
12987  if (is_string($value) && strpos($value, '@file:') === 0) {
12988  $data[$key] = '@file';
12989  $files[] = new CURLFile($source = substr($value, 6));
12990  } else {
12991  $data[$key] = $value;
12992  }
12993  }
12994 
12995  // Einzigartige IDs filtern und zwischenspeichern
12996  self::$nextIds = array_unique(self::$nextIds);
12997  $replicateIds = self::$nextIds;
12998 
12999  // Gehe alle Cluster durch
13000  foreach ($clusters as $cluster) {
13001  if (!$cluster['oneway']) {
13002 
13003  // Prüfen ob die IP mit einer der IPs im Array von "getDefaultLocalServerIps" übereinstimmt
13004  // "getDefaultLocalServerIps": "127.0.0.1", "localhost", "::1", "0:0:0:0:0:0:0:1", $_SERVER['SERVER_ADDR']
13005  $host = parse_url($cluster['url'], PHP_URL_HOST);
13006  if (in_array(gethostbyname($host), Ego_System::getDefaultLocalServerIps())) {
13007  // TODO Host zu IP auch wenn nur nach IPv6 aufgelöst werden kann
13008  continue;
13009  }
13010 
13011  $url = rtrim($cluster['url'], '/') . '/rest/';
13012  $client = new Ego_REST_Client($url, $user->field['user_id'], $user->extra['api_token']);
13013 
13014  // Repliziere die Methode
13015  $client->{strtolower($action)}(
13016  $path,
13017  array_merge(['@data' => json_encode($data)], $files),
13018  [
13019  "X-REPLICATION: $host",
13020  "X-NEXT-IDS: " . implode(',', self::$nextIds)
13021  ]
13022  );
13023  }
13024  }
13025 
13026  // ID an erster Stelle entfernen wenn mehr als eine ID im array
13027  if ((sizeof(self::$nextIds) > 1)) {
13028  self::$nextIds = array_slice($replicateIds, 1);
13029  } else {
13030  // Wenn nicht, array aus Zwischenspeicher übernehmen
13031  self::$nextIds = $replicateIds;
13032  }
13033  };
13034 
13035  Ego_Queue::add($replication);
13036  }
13037  }
13038 
13044  public function isTemplate() {
13045  return $this->getAncestors(["where" => "type = '_template/list'"])->next() ? true : false;
13046  }
13047 
13053  public function isShortEditor() {
13054  $info = $this->getTypeInfo();
13055  if (isset($info['editor']['short'])) {
13056  return (bool) $info['editor']['short'];
13057  }
13058  return $this->_site->admin['editor']['short'] || $GLOBALS['egotec_conf']['editor']['short'];
13059  }
13060 
13069  public function getExtraValues(array $conf = [], bool $csv = false): array {
13070  if (count($conf) === 0) {
13071  $conf = $this->conf;
13072  }
13073 
13074  $extra_values = [];
13075 
13076  if (isset($conf['extra_fields']) && is_array($conf['extra_fields'])) {
13077  $src = $conf['extra_fields'];
13078 
13079  if ($csv && isset($conf['extra_fields']['csv']) && count($conf['extra_fields']['csv']) !== 0) {
13080  $src = $conf['extra_fields']['csv'];
13081  }
13082 
13083  // fields durchgehen (field, oder extra)
13084  foreach ($src as $field => $items) {
13085  if ($field === 'csv') {
13086  continue;
13087  }
13088 
13089  // Alle Items in diesem field durchgehen
13090  foreach ($items as $item) {
13091  $value = $this->$field[$item['value']];
13092 
13093  // Arrays werden nicht ausgewertet
13094  if (!is_array($value)) {
13095  // Wenn modifier angegeben ist, diesen auswerten
13096  if (isset($item['modifier'])) {
13097  switch ($item['modifier']['type'] ?? null) {
13098  // Datum formatieren
13099  case 'date':
13100  $value = date($item['modifier']['format'], $item['modifier']['timestamp'] ? $value : strtotime($value));
13101  break;
13102 
13103  // Werte prüfen/vergleichen
13104  case 'assert':
13105  // Wenn ein Bild als Ergebnis des Vergleiches ausgegeben werden soll, immer vom Installationsverzeichnis ausgehen
13106  $true = $item['modifier']['true']['type'] === 'image'
13107  ? ($GLOBALS['egotec_conf']['url_dir'] . $item['modifier']['true']['value'])
13108  : $item['modifier']['true']['value'];
13109 
13110  $false = $item['modifier']['false']['type'] === 'image'
13111  ? ($GLOBALS['egotec_conf']['url_dir'] . $item['modifier']['false']['value'])
13112  : $item['modifier']['false']['value'];
13113 
13114  // Entweder prüfen, ob der Wert existiert (mode: exists), oder ob er einen bestimmten Wert hat (mode: compare)
13115  switch ($item['modifier']['mode'] ?? null) {
13116  case 'exists':
13117  if (isset($value) && !empty($value)) {
13118  $value = $true;
13119  } else {
13120  $value = $false;
13121  }
13122  break;
13123 
13124  case 'compare':
13125  $value = $value === $item['modifier']['value'] ? $true : $false;
13126  break;
13127 
13128  default:
13129  // unbekannter mode => ignorieren
13130  }
13131  break;
13132 
13133  case 'function':
13134  if (
13135  isset($item['modifier']['function'])
13136  && isset($item['modifier']['file'])
13137  && Ego_System::file_exists($GLOBALS['egotec_conf']['var_dir'] . $item['modifier']['file'])
13138  ) {
13139  require_once ($GLOBALS['egotec_conf']['var_dir'] . $item['modifier']['file']);
13140 
13141  $value = call_user_func($item['modifier']['function'], $this);
13142  }
13143  break;
13144 
13145  default:
13146  // unbekannter modifier => ignorieren
13147  }
13148  }
13149 
13150  // Standardwert, wenn dieser angegeben ist
13151  if ($item['default'] && empty($value)) {
13152  $value = $item['default'];
13153  }
13154 
13155  // Das Template muss wissen, ob ein Bild angezeigt werden soll
13156  if ($item['type'] === 'image') {
13157  $extra_values[] = [
13158  'value' => $value,
13159  'image' => true,
13160  'lightbox' => $item['lightbox']
13161  ];
13162  } else {
13163  $extra_values[] = ['value' => $value];
13164  }
13165  } else if (isset($item['default'])) {
13166  $extra_values[] = [
13167  'value' => $item['default']
13168  ];
13169  }
13170  }
13171  }
13172  }
13173 
13174  return $extra_values;
13175  }
13176 
13185  public function exportChildrenAsCSV(array $ids, bool $downloadAll = false): void {
13186  require_once 'base/Ego_Output.php';
13187 
13188  $csv_file = tempnam($GLOBALS['egotec_conf']['tmp_dir'], 'csv');
13189 
13190  // Daten für die CSV-Datei
13191  $data = [];
13192  // Selbst einstellbare Felder
13193  $extra_fields = [];
13194  // Kinder, die exportiert werden
13195  $children = [];
13196 
13197  $src = $this->conf['extra_fields'] ?? [];
13198 
13199  if (isset($src['csv'])) {
13200  $src = $src['csv'];
13201  }
13202 
13203  // Extrafelder aus conf.json auslesen
13204  if (is_array($src)) {
13205  foreach ($src as $field) {
13206  foreach ($field as $item) {
13207  $extra_fields[] = $item['name'];
13208  }
13209  }
13210  }
13211 
13212  // Header setzen
13213  $data[0] = array_merge([
13214  $GLOBALS['auth']->translate('Name'),
13215  $GLOBALS['auth']->translate('Seitentyp'),
13216  $GLOBALS['auth']->translate('Ersteller'),
13217  $GLOBALS['auth']->translate('Erstellungsdatum'),
13218  $GLOBALS['auth']->translate('Letzter Bearbeiter'),
13219  $GLOBALS['auth']->translate('Bearbeitungsdatum'),
13220  $GLOBALS['auth']->translate('Freigabe von'),
13221  $GLOBALS['auth']->translate('Freigabe bis'),
13222  $GLOBALS['auth']->translate('Aktiv'),
13223  ], ($this->_site->admin['workflow']['enabled'] ? [$GLOBALS['auth']->translate('Ist im Workflow')] : []), $extra_fields);
13224 
13225  // Die ids der Seiten, die von den eingestellten Filtern getroffen wurden
13226  if (count($ids) > 0 && !$downloadAll) {
13227  foreach ($ids as $id) {
13228  $children[] = $this->_site->getPage((int) $id, ['inactive' => true]);
13229  }
13230  } else if ($downloadAll) {
13231  $children = $this->getDescendants([], ['inactive' => true]);
13232  } else {
13233  $children = $this->getChildren([], ['inactive' => true]);
13234  }
13235 
13236  // Daten aus den Kindern auslesen
13237  foreach ($children as $child) {
13238  // Workflowkopien ignorieren
13239  if ($child->isWorkflowCopy()) continue;
13240 
13241  $extra_values = [];
13242 
13243  // Eigentlichen Namen des Seitentyps auch ausgeben
13244  $typeInfo = $child->getTypeInfo();
13245 
13246  $a_user = $GLOBALS['auth']->translate('unbekannt');
13247  $c_user = $GLOBALS['auth']->translate('unbekannt');
13248 
13249  try {
13250  $a_user = (new User_SQL($child->field['a_user']))->getFullname(false);
13251  } catch (Exception $e) {/* Ignorieren */}
13252 
13253  try {
13254  $c_user = (new User_SQL($child->field['c_user']))->getFullname(false);
13255  } catch (Exception $e) {/* Ignorieren */}
13256 
13257  foreach ($child->getExtraValues($this->conf, true) as $value) {
13258  $extra_values[] = $value['value'];
13259  }
13260 
13261  // Daten in CSV-Array einfügen
13262  $data[] = array_merge([
13263  $child->field['name'],
13264  $typeInfo['title'] . ' (' . $child->field['type'] . ')',
13265  $a_user,
13266  $child->field['a_date'],
13267  $c_user,
13268  $child->field['c_date'],
13269  $child->field['release_from'] !== '0000-00-00 00:00:00' ? $child->field['release_from'] : '-',
13270  $child->field['release_until'] !== '0000-00-00 00:00:00' ? $child->field['release_until'] : '-',
13271  $child->isActive() ? $GLOBALS['auth']->translate('Ja') : $GLOBALS['auth']->translate('Nein'),
13272  ], $this->_site->admin['workflow']['enabled'] ? ([isset($child->extra['workflow_page']) ? $GLOBALS['auth']->translate('Ja') : $GLOBALS['auth']->translate('Nein')]) : [], $extra_values);
13273  }
13274 
13275  // CSV generieren
13276  Ego_System::createCSV($csv_file, $data);
13277 
13278  // CSV zum download anbieten
13279  $ego_output = new Ego_Output($csv_file);
13280  $ego_output->setName($this->field['title'] . '_Unterseiten.csv');
13281  $ego_output->download();
13282  }
13283 
13291  public function getAutoFill($autofill, $info = []) {
13292  $result = [];
13293 
13294  foreach ($autofill as $type => $data) {
13295  $result[$type]['value'] = preg_replace_callback('/%([a-z0-9_]+)/ims', function($match) use ($info) {
13296  $key = $match[1];
13297 
13298  if ($info['pool']) {
13299  // Mediapool
13300  switch ($key) {
13301  case 'short':
13302  $key = 'description';
13303  }
13304 
13305  $file = $this->getMediapool()->get($info['pool'], (string) $info['dir']);
13306  $value = Ego_System::getAssocValue($file, $key);
13307  } else {
13308  // Normale Seite
13309  switch ($key) {
13310  case 'description':
13311  $key = 'short';
13312  }
13313 
13314  switch ($key) {
13315  case 'name':
13316  case 'title':
13317  case 'short':
13318  $value = Ego_System::getAssocValue($this->field, $key);
13319  break;
13320 
13321  default:
13322  $value = Ego_System::getAssocValue($this->extra, $key);
13323  }
13324  }
13325 
13326  // Bestimmte Werte immer modifizieren
13327  switch ($key) {
13328  // Kurzbeschreibung immer als HTML ausgeben
13329  case 'short':
13330  case 'description':
13331  if (!preg_match('/<[^>]+>/ms', $value)) {
13332  $value = '<p>' . nl2br($value) . '</p>';
13333  }
13334  }
13335 
13336  return $value;
13337  }, $data['value']);
13338 
13339  $result[$type]['readonly'] = (bool) $data['readonly'];
13340  }
13341 
13342  return $result;
13343  }
13344 
13358  public function autoTranslate($param = [], $language = '', $diff = true, $force = false, $glossary = '', $source = '', $target = '', $original = true) {
13359  $language = $language ?: $this->_site->language;
13360 
13361  // Übersetzungen in diesem Durchlauf immer ohne Unterschiede prüfen.
13362  if (
13363  !empty($GLOBALS['__auto_translate_no_diff'])
13364  && (
13365  $GLOBALS['__auto_translate_no_diff'] === true
13366  || in_array($language, explode(',', (string) $GLOBALS['__auto_translate_no_diff']))
13367  )
13368  ) {
13369  $diff = false;
13370  }
13371 
13372  // Aktuelle Daten verwenden
13373  if (empty($param)) {
13374  $param = [
13375  'field' => $this->field,
13376  'extra' => $this->extra
13377  ];
13378  }
13379 
13380  // Zu verwendende Standardsprache
13381  $language_standard = !empty($param['extra']['language_standard'])
13382  ? $param['extra']['language_standard']
13383  : $this->extra['language_standard'];
13384  if (empty($language_standard)) {
13385  $language_standard = $this->_site->site['default_language'];
13386  }
13387 
13388  // Quell- und Zielsprache setzen
13389  $source = $source ?: $language_standard;
13390  $target = $target ?: $language;
13391 
13392  // Ist man selbst eine Sprachverknüpfung und wird DeepL verwendet, müssen alle Inhalte jetzt übersetzt werden
13393  if (
13394  Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'translate')
13395  && $_SERVER['HTTP_X_SOAP_CALL'] !== 'Replication' // Nicht beim Liveabgleich
13396  && (!Ego_System::isDevMode() || !empty($GLOBALS['egotec_conf']['dev']['deepl'])) // Nicht in Entwicklungsumgebungen
13397  && !$this->archiveOnly // Nicht für Zwischenspeicherungen
13398  && empty($param['field']['deleted']) // Nicht für gelöschte Seiten
13399  && !$this->isWorkflowCopy() // Nicht für Workflowkopien
13400  && !$this->isReleaseCopy() // Nicht für Freigabekopien
13401  && !$this->isClone() // Nicht für Klone
13402  ) {
13409  $auto_translate = function($check_diff) use (&$param, $language, $language_standard, $glossary, $source, $target, $original) {
13410  // Standardsprache zum Vergleichen ermitteln
13411  $GLOBALS['auto_translate_get_original_page'] = true;
13412  if ($original) {
13413  $language_page = $this->getLanguagePage($language_standard, [
13414  'inactive' => true,
13415  'only_active' => false,
13416  'auth_or' => '1=1',
13417  'deleted_or' => '1=1'
13418  ]);
13419  } else {
13420  $language_page = $this;
13421  }
13422  unset($GLOBALS['auto_translate_get_original_page']);
13423  if (!$language_page) {
13424  return;
13425  }
13426 
13427  // Nur bestimmte Felder übersetzen (Validierung überspringen)
13428  $fields = $this->getTranslationFields(false);
13429 
13430  foreach ($fields as $field => $keys) {
13431  // Zwischenspeicher für zu übersetzende Texte
13432  $result_keys = [];
13433  $result_values = [];
13434 
13435  foreach ($keys as $pattern) {
13436  $results = Ego_System::getAssocValues($language_page->{$field}, $pattern);
13437  if (is_array($results)) {
13438  foreach ($results as $key => $value) {
13439  if ($value !== null && !Ego_System::isEmptyContent($value)) {
13440  // Prüfen, ob sich der Inhalt geändert hat
13441  if (
13442  $check_diff
13443  && !empty($this->extra['auto_translated'])
13444  && $this->extra['auto_translated'][md5($key)] === md5(Ego_System::getAssocValue($language_page->{$field}, $key))
13445  ) {
13446  // Bisherige Übersetzung beibehalten
13447  Ego_System::setAssocValue($param[$field], $key, Ego_System::getAssocValue($this->{$field}, $key));
13448  $param['extra']['auto_translated'][md5($key)] = $this->extra['auto_translated'][md5($key)];
13449  continue;
13450  }
13451 
13452  $result_keys[] = $key;
13453  $result_values[] = $value;
13454  }
13455  }
13456  }
13457  }
13458 
13459  // Alle gesammelten Texte übersetzen
13460  if (sizeof($result_values) > 0) {
13461  // Zwischenspeicher der zu übersetzenden Texte abarbeiten
13462  require_once 'translate/Ego_DeepL.php';
13463  $deepl = new Ego_DeepL($this->getSite());
13464  $translated_values = $deepl->translate($source, $target, $result_values, $glossary);
13465 
13466  if (sizeof($translated_values) != sizeof($result_values)) {
13467  // Falls nicht dieselbe Menge zurückkommt, dann die bisherigen Übersetzungen behalten
13468  foreach ($result_keys as $result_key) {
13469  Ego_System::setAssocValue($param[$field], $result_key, Ego_System::getAssocValue($this->{$field}, $result_key));
13470  }
13471  } else {
13472  // Übersetzte Texte speichern
13473  foreach ($translated_values as $i => $translated_value) {
13474  Ego_System::setAssocValue($param[$field], $result_keys[$i], $translated_value);
13475  $param['extra']['auto_translated'][md5($result_keys[$i])] = md5($result_values[$i]);
13476  }
13477  }
13478  }
13479  }
13480 
13481  // Alle URLs aus der Standardsprache in diesem Mandanten auf die aktuelle Sprache umstellen
13482  $recursive = function(&$value) use (&$recursive) {
13483  if (is_array($value)) {
13484  foreach ($value as &$v) {
13485  $recursive($v);
13486  }
13487  } else {
13488  $value = preg_replace_callback('/\/?index\.php\?[^ "]+/i', function($matches) {
13489  if (
13490  ($page = Ego_System::urltopage($matches[0]))
13491  && $page->getSite()->name == $this->getSite()->name
13492  && $page->getSite()->language == $this->extra['language_standard']
13493  && $page->getLanguagePage($this->getSite()->language)
13494  ) {
13495  return str_replace('lang=' . $page->getSite()->language, 'lang=' . $this->getSite()->language, $matches[0]);
13496  }
13497  return $matches[0];
13498  }, $value);
13499  }
13500  };
13501  foreach (['field', 'extra'] as $field) {
13502  $recursive($param[$field]);
13503  }
13504 
13505  // Übersetztes Extra-Feld serialisiert in das Standard-Feld übernehmen
13506  if (isset($param['field']) && isset($param['extra'])) {
13507  $param['field']['extra'] = serialize($param['extra']);
13508  }
13509  };
13510 
13511  if (isset($param['extra'])) {
13512  if (
13513  $force
13514  || (
13515  !empty($param['extra']['language_link'][$language])
13516  && $param['extra']['language_link'][$language] == 2
13517  )
13518  ) {
13519  $auto_translate(!$force && $param['extra']['language_link'][$language] != $this->extra['language_link'][$language]
13520  ? false // Wurde die Verknüpfung umgestellt, wird immer übersetzt
13521  : $diff
13522  );
13523  }
13524  } elseif (
13525  $force
13526  || (
13527  !empty($this->extra['language_link'][$language])
13528  && $this->extra['language_link'][$language] == 2
13529  )
13530  ) {
13531  $auto_translate($diff);
13532  }
13533  }
13534 
13535  return $param;
13536  }
13537 
13544  public function getTranslationFields($check = true) {
13545  if (
13546  $check
13547  && (
13548  !Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'translate')
13549  || (
13550  empty($this->extra['language_link'][$this->_site->language])
13551  || $this->extra['language_link'][$this->_site->language] == 1
13552  )
13553  )
13554  ) {
13555  return [
13556  'field' => [],
13557  'extra' => [],
13558  'title' => []
13559  ];
13560  }
13561 
13562  $conf = json_decode(Ego_System::file_get_contents($GLOBALS['egotec_conf']['lib_dir'] . 'translate/translate.json'), true);
13563 
13564  // Kundenspezifische Konfigurationen laden
13565  foreach ([
13566  'admin/translate.json',
13567  $this->field['type'] . '/admin/translate.json'
13568  ] as $path) {
13569  if ($json = $this->_site->getSiteFile($path)) {
13570  $custom_conf = json_decode(Ego_System::file_get_contents($json), true);
13571  if (!empty($custom_conf['merge'])) {
13572  foreach ($custom_conf as $key => $value) {
13573  if (is_array($value)) {
13574  $custom_conf[$key] = array_merge($conf[$key] ?? [], $value);
13575  }
13576  }
13577  }
13578  $conf = $custom_conf;
13579  }
13580  }
13581 
13582  return [
13583  'field' => ['name', 'title', 'short', 'content'],
13584  'extra' => $conf['extra'] ?? [],
13585  'title' => $conf['title'] ?? []
13586  ];
13587  }
13588 
13594  public function getMandatoryFields() : array {
13595  $cache_key = 'mandatory'.md5(serialize(array($this->_site->name, $this->field['type'])));
13596  $mandatory = $this->_site->getCacheEntry($cache_key);
13597 
13598  if ($mandatory === null) {
13599  $mandatory = [];
13600 
13601  foreach ([
13602  $this->_site->getSiteFile('admin/mandatory.ini'),
13603  $this->_site->getSiteFile($this->field['type'] . '/admin/mandatory.ini')
13604  ] as $file) {
13605  if ($file) {
13606  $conf = parse_ini_file($file, true);
13607 
13608  // Alle Felder für diesen Seitentyp ignorieren
13609  if (isset($conf['ignore_types']) && in_array($this->field['type'], explode(',', $conf['ignore_types']))) {
13610  continue;
13611  }
13612 
13613  foreach ($conf as $key => $value) {
13614  if (is_array($value)) {
13615  if (isset($value['ignore_types']) && in_array($this->field['type'], explode(',', $value['ignore_types']))) {
13616  // Dieses Feld für diesen Seitentyp ignorieren
13617  continue;
13618  }
13619 
13620  $mandatory[$key] = $value;
13621  }
13622  }
13623  }
13624  }
13625 
13626  $this->_site->setCacheEntry($cache_key, $mandatory);
13627  }
13628 
13629  return $mandatory;
13630  }
13631 
13637  public function getAllEditUsers(): array {
13638  $users = [];
13639  $allUsers = $GLOBALS['auth']->user->getAllUsers(['auth_or' => '1=1']);
13640  $groupRoleRights = $this->getRightsArray()['edit'] ?? [];
13641  $userRights = $this->getUsersArray()['edit'] ?? [];
13642 
13643  foreach ($allUsers as $user) {
13644  if (empty($userRights) && empty($groupRoleRights)) {
13645  $users[] = $user;
13646  continue;
13647  }
13648 
13649  foreach ($userRights as $userRight) {
13650  if ($user->field['user_id'] === $userRight['user_id']) {
13651  $users[] = $user;
13652  continue 2;
13653  }
13654  }
13655 
13656  foreach ($groupRoleRights as $groupRoleRight) {
13657  if ($GLOBALS['auth']->hasPermission($groupRoleRight['group_id'], $groupRoleRight['role_id'], false, $user->field['user_id'])) {
13658  $users[] = $user;
13659  continue 2;
13660  }
13661  }
13662  }
13663 
13664  return $users;
13665  }
13666 
13672  public function getMetaData(): array {
13673  return [
13674  '@context' => 'https://schema.org',
13675  '@type' => 'WebPage',
13676  'name' => $this->field['title'],
13677  'description' => $this->extra['meta_descr'] ?: $this->field['short'],
13678  'mainEntityOfPage' => [
13679  '@type' => 'WebPage',
13680  '@id' => $this->getFrontendUrl(['return_absolute' => true])
13681  ]
13682  ];
13683  }
13684 
13690  public function pageHasContentTab ():bool {
13691  $site = $this->getSite();
13692  $navigation = [];
13693 
13694  $file_name = $site->getSiteFile($this->field['type'] . '/admin/navigation.ini');
13695  if (!$file_name) {
13696  $file_name = $GLOBALS['egotec_conf']['lib_dir'] . 'type/site/page/admin/navigation.ini';
13697  }
13698 
13699  if (!$file_name || !file_exists($file_name)) {
13700  $file_name = $GLOBALS['egotec_conf']['lib_dir'] . '/type/site/multimedia/category/admin/navigation.ini';
13701  }
13702 
13703  // Seitentyp Reiter
13704  if ($file_name = $site->getSiteFile($this->field['type'] . '/admin/navigation.ini')) {
13705  $this->mergeTabs($file_name, $navigation);
13706  } else {
13707  // Standard Reiter
13708  $this->mergeTabs($GLOBALS['egotec_conf']['lib_dir'] . 'type/site/page/admin/navigation.ini', $navigation);
13709  }
13710 
13711  // Mandanten Reiter
13712  if ($file_name = $site->getSiteFile('admin/navigation.ini', ['module', 'system', 'global'])) {
13713  $this->mergeTabs($file_name, $navigation);
13714  }
13715 
13716  // Globale Reiter (nur für Inhaltsmandanten)
13717  if ($site->globalAllowed()) {
13718  $file_name = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/navigation.ini';
13719 
13720  if ($site->site['type'] == 'content' && Ego_System::file_exists($file_name)) {
13721  $this->mergeTabs($file_name, $navigation);
13722  }
13723  }
13724 
13725  return !empty($navigation['content']);
13726  }
13727 
13735  public function mergeTabs(string $file_name, array &$navigation) {
13736  $navigation2 = parse_ini_file($file_name, true);
13737 
13738  foreach ($navigation2 as $key => $value) {
13739  if ($navigation[$key]) {
13740  // Der Reiter wurde bereits definiert und darf nicht überschrieben werden
13741  continue;
13742  }
13743 
13744  // ignore_sites = "site1,site2" beinhaltet alle Mandanten bei denen dieser Reiter nicht angezeigt wird
13745  if ($value['ignore_sites']) {
13746  $sites = explode(',', $value['ignore_sites']);
13747  if (in_array($this->getSite()->name, $sites)) {
13748  continue;
13749  }
13750  }
13751 
13752  // ignore_types = "type1,type2" beinhaltet alle Seitentypen bei denen dieser Reiter nicht angezeigt wird
13753  if ($value['ignore_types']) {
13754  $types = explode(',', $value['ignore_types']);
13755 
13756  if (in_array($this->field['type'], $types)) {
13757  continue;
13758  }
13759  }
13760 
13761  if (
13762  !empty($value['if'])
13763  ) {
13764  $invert = false;
13765  $regex = false;
13766 
13767  if (strpos($value['if'], '!') === 0) {
13768  $invert = true;
13769  $value['if'] = substr($value['if'], 1);
13770  }
13771 
13772  if (strpos($value['if'], '?') === 0) {
13773  $regex = true;
13774  $value['if'] = substr($value['if'], 1);
13775  }
13776 
13777  [$field_key, $value_to_test] = explode('=', $value['if'], 2);
13778  [$field, $key2] = explode('.', $field_key, 2);
13779 
13780  if (strpos($key2, '.') !== false) {
13781  $test_value = Ego_System::getAssocValue($this->{$field}, $key2);
13782  } else {
13783  $test_value = $this->{$field}[$key2];
13784  }
13785 
13786  if (
13787  $regex
13788  && (
13789  (preg_match($value_to_test, $test_value) && !$invert) // Regex und nicht invertiert (?field.title=#Title#)
13790  || (!preg_match($value_to_test, $test_value) && $invert) // Regex und invertiert (!?field.title=#Title#)
13791  )
13792  ) {
13793  $navigation[$key] = $value;
13794  } else if (
13795  !$regex
13796  && !empty($value_to_test)
13797  && (
13798  ($test_value == $value_to_test && !$invert) // Kein Regex und Prüfung, ob Feld einen bestimmten Wert hat (field.title=Title)
13799  || ($test_value != $value_to_test && $invert) // Kein Regex und Prüfung, ob Feld einen bestimmten Wert nicht hat (!field.title=Title)
13800  )
13801  ) {
13802  $navigation[$key] = $value;
13803  } else if (
13804  !$regex
13805  && empty($value_to_test)
13806  && (
13807  (isset($test_value) && !$invert) // Kein Regex und Prüfung, ob Feld existiert (field.title)
13808  || (empty($test_value) && $invert) // Kein Regex und Prüfung, ob Feld nicht existiert (!field.title)
13809  )
13810  ) {
13811  $navigation[$key] = $value;
13812  }
13813  } else {
13814  $navigation[$key] = $value;
13815  }
13816  }
13817  }
13818 
13825  public function getMessages($params = []) {
13826  $messages = [];
13827 
13828  // Die Seite ist gelöscht
13829  if ($this->field['deleted']) {
13830  $messages[] = [
13831  'type' => 'error',
13832  'text' => $GLOBALS['auth']->translate('Die Seite ist gelöscht.')
13833  ];
13834  }
13835 
13836  // Die Seite ist inaktiv
13837  if (!$this->field['deleted'] && !$this->isActive()) {
13838  $messages[] = [
13839  'type' => 'error',
13840  'text' => $GLOBALS['auth']->translate('Die Seite ist inaktiv.')
13841  ];
13842  }
13843 
13844  // Die Seite wird nicht auf den Liveserver übertragen
13845  if (!$GLOBALS['egotec_conf']['liveserver'] && $this->_site->hasLiveserver() && ($this->field['nav_hide']&2) == 2) {
13846  $messages[] = [
13847  'type' => 'warning',
13848  'text' => $GLOBALS['auth']->translate('Die Seite wird nicht auf den Liveserver übertragen.')
13849  ];
13850  }
13851 
13852  // Der ausgewählte Seitentyp stimmt nicht
13853  if (!empty($params['type']) && !in_array($this->field['type'], explode(',', $params['type']))) {
13854  $messages[] = [
13855  'type' => 'warning',
13856  'text' => $GLOBALS['auth']->translate('Der ausgewählte Seitentyp stimmt nicht.')
13857  ];
13858  }
13859 
13860  // Die Seite hat Ansichtsrechte
13861  if (!empty($params['view']) && $this->hasRightsOn('view')) {
13862  $messages[] = [
13863  'type' => 'warning',
13864  'text' => $GLOBALS['auth']->translate('Die Seite hat Ansichtsrechte.')
13865  ];
13866  }
13867 
13868  return $messages;
13869  }
13870 }
static getUserRecord($user_id)
Definition: Auth.php:1135
static $convert_types
Definition: Ego_Output.php:146
static add(callable $call, $params=array(), $first=false)
Definition: Ego_Queue.php:72
static start($table='', $param=[], $checkHealthy=false)
static filterNonUtf8($s, $substitute="", $strict=false)
Definition: Ego_System.php:481
static urltopage($url, $params=array(), $only_site=false, $error_page=false, $commit_params=false)
static getUrlParams($url='')
static exec(String $command, Array $params=array(), &$output=null, &$return_var=null, $log=true)
static getMimeTypes($ext='')
static file_put_contents($filename, $data, $flags=0, $context=null)
static encode_path($url, $id=0)
static pathinfo($string)
Definition: Ego_System.php:415
static getAssocValue($a, $k)
static getAssocValues($a, $k, $o='')
static cleanTypes($value)
static getChecksum($value)
static filterUnicode($s)
Definition: Ego_System.php:460
static getDefaultLocalServerIps()
static deldir($location, $del=true, $without='', $rename=true)
Definition: Ego_System.php:803
static createCSV($path, $data, $delimiter=',', $enclosure='"', $escape_char = '\'')
const REGEX_EMAIL
Definition: Ego_System.php:21
static filterData($data)
Definition: Ego_System.php:558
const REGEX_EMAIL_OPTIONAL
Definition: Ego_System.php:23
static checkLicence($ini_path)
static dateEncode($string)
Definition: Ego_System.php:651
static getCluster($site=null)
static includeHtml($src, $once=true)
static isDevMode($ignore=true)
static getFiles($type, $name, $path, $skip=array(), $parent='', $return_path=false, $get_variants=true)
static getUrlInfo($url, $encode=false)
static getAllSites($username='', $perm='', $table=false, $type='')
static file_exists($file)
static setAssocValue(&$a, $k, $v)
static mkdir($dir, $mode=0755, $recursive=true)
Definition: Ego_System.php:669
static isEmptyContent($str)
static file_get_contents($filename, $utf8=true, $context=null)
const VIDEO_RESOLUTIONS
Definition: Ego_System.php:33
static getJSON($path, $values=[], $combine=false, $ignore=[], $replace=true, $no_cache=false)
static scan(string $path, bool $remove=false, bool $recursive=true, ?array &$summary=[])
static flush($string='')
Definition: Ego_System.php:934
static stringEncode($string, $from='UTF-8', $to='UTF-8')
Definition: Ego_System.php:615
static copy($src, $dest, $except='', $useLinks=false, $noArchive=false, $preserveDate=false)
static filesize($file)
const FILE_REPLACE
Definition: Page.php:13
const METHOD_NOT_FOUND
Definition: Page.php:14
const ROOT_PROTECTION
Definition: Page.php:12
Definition: Page.php:28
addResolution(int $width, int $height)
Definition: Page.php:12763
getMessages($params=[])
Definition: Page.php:13825
const RELEASE_FLAG
Definition: Page.php:34
export()
Definition: Page.php:9433
_updateCloneChildren()
Definition: Page.php:3186
addPiwikSite()
Definition: Page.php:12064
static unserialize($session_value)
Definition: Page.php:5879
__call($function, $params)
Definition: Page.php:428
getArchivePages($query=array())
Definition: Page.php:9134
createEditField($name, $setting=array(), $empty=false, $orient='', $index=0, $block='', $replace=false)
Definition: Page.php:9593
createClone($page, $children=false, $rights=false, $release=false, $multiple=true)
Definition: Page.php:3079
__construct(Site $site, $field, $archive=false)
Definition: Page.php:71
getEditorCSS()
Definition: Page.php:11815
getNonPublic()
Definition: Page.php:9037
newChild($field=array(), $extra=array(), $inherit=true)
Definition: Page.php:942
download($recursive=true, $target_dir='', $write_log=true)
Definition: Page.php:9215
mergeTabs(string $file_name, array &$navigation)
Definition: Page.php:13735
removeLinks()
Definition: Page.php:11411
const CACHE_PROXY
Definition: Page.php:30
getNextReplicationDate()
Definition: Page.php:12338
getBlockControls($block)
Definition: Page.php:7159
getAutoFill($autofill, $info=[])
Definition: Page.php:13291
move($from, $to)
Definition: Page.php:1768
exportChildrenAsCSV(array $ids, bool $downloadAll=false)
Definition: Page.php:13185
getToolbar($type='')
Definition: Page.php:8046
getMoreLinks()
Definition: Page.php:11703
getTabs()
Definition: Page.php:10925
hasRightsOn($perm)
Definition: Page.php:908
getTableSuffix()
Definition: Page.php:477
isShortEditor()
Definition: Page.php:13053
removeUrls()
Definition: Page.php:10722
getWorkflowHistory()
Definition: Page.php:8728
getFormats($type='')
Definition: Page.php:7918
updateUrls($verbose=false, $domain=null, $force_recursive=false, $called_recursive=false)
Definition: Page.php:10337
const CACHE_BROWSER
Definition: Page.php:29
destroy($force=false, $recursive=true, $destroy_links=true)
Definition: Page.php:2093
_getAncestorsIds($page, $query, $param=array())
Definition: Page.php:740
isFrontendAdmin($check_rights=true)
Definition: Page.php:12252
$mainOrient
Definition: Page.php:43
getPermissionName($perm)
Definition: Page.php:10845
removeListItem($params)
Definition: Page.php:12443
static createIdentity($params)
Definition: Page.php:11947
hasUserRight(string $right_type, string $user_id)
Definition: Page.php:888
getClones($target_site='all')
Definition: Page.php:3050
getIndex($index=null)
Definition: Page.php:8238
getCacheEntry($key)
Definition: Page.php:12347
addListItem($params)
Definition: Page.php:12429
getSocialNetworks()
Definition: Page.php:12685
_destroyClone()
Definition: Page.php:3455
_updateRights($rights, $asis=false)
Definition: Page.php:3492
getFirstMediaValue(string $name, string $type='image', string $orient=null, bool $verbose=false)
Definition: Page.php:8384
serialize()
Definition: Page.php:5896
updateFile($source, $name='')
Definition: Page.php:1322
const IDENTITY_SEPARATOR
Definition: Page.php:35
pageHasContentTab()
Definition: Page.php:13690
$typeInfo
Definition: Page.php:45
getFormListConf($orient)
Definition: Page.php:12496
const INACTIVE_FLAG
Definition: Page.php:33
getDataConf($type='')
Definition: Page.php:12554
canChangeType()
Definition: Page.php:11805
destroyClone()
Definition: Page.php:3445
isWorkflowCopy()
Definition: Page.php:8968
archiveUrls()
Definition: Page.php:10695
setCurrentPage()
Definition: Page.php:12279
removeSelectedListItem($params)
Definition: Page.php:12457
getLinkedPages($recursive=false, $self=true)
Definition: Page.php:11544
getTranslationFields($check=true)
Definition: Page.php:13544
autoTranslate($param=[], $language='', $diff=true, $force=false, $glossary='', $source='', $target='', $original=true)
Definition: Page.php:13358
updateDocumentFiles($remove=false)
Definition: Page.php:1505
getIconUrl($test=false, $folder=false, $quarantine=true)
Definition: Page.php:11715
frontendAdmin()
Definition: Page.php:9485
static byIdentity($identity, $param=array(), $site=null)
Definition: Page.php:11960
isValidSuffix($suffix)
Definition: Page.php:12632
getFirstValue($name, $orient=null, $verbose=false)
Definition: Page.php:8355
isArchive()
Definition: Page.php:9005
$extra
Definition: Page.php:38
getLinks($recursive=false, $c_date=false)
Definition: Page.php:11440
extractFile($source, &$images=array())
Definition: Page.php:1287
merge($id, $replicate=true)
Definition: Page.php:8485
convertVideo()
Definition: Page.php:12802
getLinkedUsers()
Definition: Page.php:11659
getListItems($where='', $no_limit=false)
Definition: Page.php:12370
getFirstBlockValue($block, $name, $orient=null, $verbose=false)
Definition: Page.php:8460
getMediapool()
Definition: Page.php:5383
isClassified()
Definition: Page.php:9028
_updateKeywords($asis=false)
Definition: Page.php:2362
getLastChangeDate()
Definition: Page.php:9089
validateFile($source, $name='', $form=array(), $files_conf=array())
Definition: Page.php:12173
$originalType
Definition: Page.php:52
_updateChildren($children, $merge=true)
Definition: Page.php:2444
setCacheEntry($key, $value)
Definition: Page.php:12358
$field
Definition: Page.php:37
getUrlNames()
Definition: Page.php:10746
isReleaseCopy()
Definition: Page.php:8977
getThumbnail($width, $height=0, $pool='', $dir='', $params=[])
Definition: Page.php:12840
newFile($source, $name, $options=array(), $suffix='')
Definition: Page.php:1140
getIdentity()
Definition: Page.php:11918
getMetaData()
Definition: Page.php:13672
getOrient($orient=null)
Definition: Page.php:8222
unlinkFrom($remove_from)
Definition: Page.php:2271
isTemplate()
Definition: Page.php:13044
$archiveOnly
Definition: Page.php:50
_updateCloneRights()
Definition: Page.php:3163
_updateClones(&$param)
Definition: Page.php:2771
hasFile($name, $suffix='')
Definition: Page.php:1108
setTableSuffix($suffix='')
Definition: Page.php:487
_updateField($field, $update=true, $asis=false, $silent=false)
Definition: Page.php:2300
isActive()
Definition: Page.php:9014
_createChildClones($parent)
Definition: Page.php:3242
getBlockValue($block, $name, $orient=null, $index=null, $verbose=false)
Definition: Page.php:8410
isClone()
Definition: Page.php:8986
_createClone($page, $children=false, $rights=false, $release=false, $multiple=true)
Definition: Page.php:3094
getArchivePage($c_date='')
Definition: Page.php:9099
getLinkText()
Definition: Page.php:11909
getExtraValues(array $conf=[], bool $csv=false)
Definition: Page.php:13069
isCurrentPage($lang=false)
Definition: Page.php:12268
$message
Definition: Page.php:39
getPermUrl()
Definition: Page.php:10832
isPublic()
Definition: Page.php:9076
hasRights($rights, $user_id=false, $cache=true)
Definition: Page.php:876
compressVideo()
Definition: Page.php:12697
replicate($method,... $params)
Definition: Page.php:12912
fetch($params=array(), $outputfilter=false, $script=true, $includes=true, $variant='')
Definition: Page.php:12584
isPublicSave()
Definition: Page.php:9063
undelete($recursive=false, $query=array())
Definition: Page.php:2179
getUser($user_type='c')
Definition: Page.php:497
updateLinks($inherited=true, $cleared=false)
Definition: Page.php:10987
_updateParents($parents)
Definition: Page.php:2507
inheritExtra($keys, $mixed=false, $types=array(), $no_rights=true)
Definition: Page.php:11997
copyTo($id, $recursive=false, $params=array(), &$copied_pages=array())
Definition: Page.php:1544
getEditFieldSettings($name='')
Definition: Page.php:9523
getBlockValues($block, $name, $orient=null, $verbose=false)
Definition: Page.php:8433
release()
Definition: Page.php:8693
getMandatoryFields()
Definition: Page.php:13594
reorderListItem($params)
Definition: Page.php:12472
const CACHE_SERVER
Definition: Page.php:31
_destroyEntry($recursive=true)
Definition: Page.php:2001
getHtml($root=false)
Definition: Page.php:8160
getValues($name, $orient=null, $verbose=false)
Definition: Page.php:8328
newRelease($date='')
Definition: Page.php:8632
getValue($name, $orient=null, $index=null, $verbose=false)
Definition: Page.php:8257
linkTo($id)
Definition: Page.php:1787
isUniqueUrl($url)
Definition: Page.php:12080
const ACTIVE_FLAG
Definition: Page.php:32
$conf
Definition: Page.php:57
$_updatedLinkLanguages
Definition: Page.php:47
getTemplateBlock($block='template', $orient='', $index=0, $empty=false, $replace=false, $variant='', $removable=true, $do_save=false, $page_frame=false, $element_types=[], &$smarty=null)
Definition: Page.php:7201
reset($self=true)
Definition: Page.php:12293
static isIdentity($identity)
Definition: Page.php:11932
updateExtra($extra, $matrix_flag=true, $asis=false, $silent=false)
Definition: Page.php:4081
_deleteCloneKeywords($clone_check, $clone_to_delete)
Definition: Page.php:3381
getAllEditUsers()
Definition: Page.php:13637
getUsersArray($perm_type='')
Definition: Page.php:5317
inheritBlocks()
Definition: Page.php:7882
getTypeInfo($cache=true)
Definition: Page.php:11784
_updateCloneKeywords($original, $clone)
Definition: Page.php:3296
_destroyChildClones($parent)
Definition: Page.php:3411
isLanguageLink()
Definition: Page.php:8995
Definition: Site.php:30