EGOCMS  18.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 }
15 
27 class Page {
28  const CACHE_BROWSER = 1;
29  const CACHE_PROXY = 2;
30  const CACHE_SERVER = 4;
31  const ACTIVE_FLAG = 0;
32  const INACTIVE_FLAG = 1;
33  const RELEASE_FLAG = 2;
34  const IDENTITY_SEPARATOR = '.';
35  const VIDEO_RESOLUTIONS = array(
36  1080 => '1920:1080',
37  720 => '1280:720',
38  360 => '640:360'
39  );
40 
41  public $field;
42  public $extra;
43  public $message = '';
45  private $_site;
46  private $_pool;
47  private $tableSuffix = '';
48  public $mainOrient = 'center';
50  protected $typeInfo = array();
55  public $archiveOnly = false;
57  private $lastChangeDate = '';
58  private $frontendActive = false;
59  private $editFields = array();
61  public $conf = array();
72  function __construct(Site $site, $field) {
73  $this->_site = $site;
74  $this->_pool = new Mediapool($this);
75  $this->field = $field;
76  $this->extra = $this->field['extra']?unserialize($this->field['extra']):array();
77  $this->lastChangeDate = $this->field['c_date'];
78 
79  if ($_REQUEST['c_date'] && $this->field['id']) { // Einen Archiveintrag holen.
80  $c_date = $_REQUEST['c_date'];
81  if (is_numeric($c_date)) {
82  $c_date = date('Y-m-d H:i:s', $_REQUEST['c_date']);
83  }
84  $db = new_db_connection(array(
85  'table' => $this->_site->pageTable.'_v',
86  'where' => "id=".$this->field['id']." AND c_date<=:cdate",
87  'order' => 'c_date DESC',
88  'limit' => 1,
89  'bind' => array('cdate' => $c_date)
90  ));
91  if ($db->nextRecord()) {
92  $this->field = $db->Record;
93  $this->extra = $db->Record['extra']?unserialize($db->Record['extra']):array();
94  }
95 
96  $this->lastChangeDate = $this->field['c_date'];
97  } elseif (
98  $_GET['preview']
99  && $_REQUEST['id'] == $field['id']
100  && $_REQUEST['site'] == $site->name
101  && !$GLOBALS['frontend_admin']
102  && $_SESSION['egotec_page_preview'][$identity = $this->getIdentity()]
103  ) {
104  // Echte Vorschau.
105  $this->field = $_SESSION['egotec_page_preview'][$identity]['field'];
106  $this->extra = $_SESSION['egotec_page_preview'][$identity]['extra']?$_SESSION['egotec_page_preview'][$identity]['extra']:array();
107  $this->lastChangeDate = $this->field['c_date'];
108  } else {
109  // Im Adminbereich/Frontend Administration ist die aktuelle Page immer der letzte Archiveintrag
110  if (
111  $this->isPublicSave()
112  && ($GLOBALS['is_admin'] || $GLOBALS['frontend_admin'] || $_REQUEST['preview'])
113  && !empty($GLOBALS['site'])
114  && $this->_site->name == $GLOBALS['site']->name
115  && in_array($this->field['id'], array($_REQUEST['list'], $_REQUEST['id'], $_REQUEST['field']['id']))
116  ) {
117  $db = new_db_connection();
118  $db->select(array(
119  'table' => $this->_site->pageTable.'_v',
120  'where' => 'id = :id',
121  'order' => 'c_date DESC',
122  'limit' => 1,
123  'bind' => array(
124  'id' => $this->field['id']
125  )
126  ));
127  if ($db->nextRecord() && $db->Record['c_date'] > $this->field['c_date']) {
128  // Daten des Archivs verwenden
129  $this->field = $db->Record;
130  $this->extra = $this->field['extra']?unserialize($this->field['extra']):array();
131  $this->archiveOnly = true;
132 
133  // Mediapool Archiv verwenden
134  $current_dir = $this->getMediapool()->dir().$this->getMediapool()->currentDir;
135  $this->getMediapool()->currentDir = (string) Ego_System::dateEncode($this->field['c_date']);
136  $archive_dir = $this->getMediapool()->dir().$this->getMediapool()->currentDir;
137  if (
138  !Ego_System::file_exists($archive_dir)
139  && Ego_System::file_exists($current_dir)
140  ) {
141  // Automatische Migration: Existiert kein Mediapool Archiv, dann wird current kopiert
142  Ego_System::copy($current_dir, $archive_dir);
143  }
144  }
145  }
146 
147  // Standardsprache automatisch korrigieren wenn diese nicht existiert
148  if (
149  $this->extra['language_standard']
150  && !in_array($this->extra['language_standard'], $this->_site->getLanguages())
151  ) {
152  $this->extra['language_standard'] = $this->_site->language;
153  $this->updateExtra($this->extra, true, true);
154  }
155 
156  // Ist diese Page die aktuelle Seite in der Frontend Administration, dann automatisch umwandeln
157  if (
158  !empty($GLOBALS['frontend_admin'])
159  && !empty($GLOBALS['smarty'])
160  && $this->isCurrentPage(true)
161  ) {
162  $this->frontendAdmin();
163  }
164  }
165  if ($this->extra['mime_type'] && !is_string($this->extra['mime_type'])) {
166  $this->extra['mime_type'] = ''; // Falls in Mime-Type kein String steht.
167  }
168  $this->field['cache'] = (int)$this->field['cache']; // Der Cache ist ein Integer
169 
170  // Page Informationen laden
171  $this->_loadConfig();
172 
173  // Individuelles Standard Layout verwenden, wenn keines definiert ist
174  if (empty($this->extra['_layout'])) {
175  $this->extra['_layout'] = $this->conf['default_layout'];
176  }
177 
178  // Standard Blöcke in einer statischen Orientierung müssen immer gesetzt sein
179  if (is_array($this->conf['layouts'][$this->extra['_layout']]['blocks'])) {
180  foreach ($this->conf['layouts'][$this->extra['_layout']]['blocks'] as $orient => $info) {
181  if (!empty($info['default']) && $info['static']) {
182  if (!is_array($this->extra['_blocks'])) {
183  $this->extra['_blocks'] = array();
184  }
185  $this->extra['_blocks'][$orient] = explode(',', $info['default']);
186 
187  // Andere Blöcke sind in dieser statischen Orientierung nicht erlaubt und werden automatisch entfernt
188  $this->conf['layouts'][$this->extra['_layout']]['blocks'][$orient]['allow'] = implode(',', array_unique($this->extra['_blocks'][$orient]));
189  unset($this->conf['layouts'][$this->extra['_layout']]['blocks'][$orient]['disallow']);
190  }
191  }
192  }
193 
194  if (is_array($this->extra['_blocks'])) {
195  // Blöcke die nicht erlaubt sind nicht anzeigen
196  if (isset($this->conf['layouts'])) {
197  // Prüfen, ob dieser Block erlaubt ist.
198  $validate = function ($block, $orient, $type) use (&$validate) {
199  $info = $this->conf['layouts'][$this->extra['_layout']]['blocks'][$orient];
200  if (isset($info[$type])) {
201  $result = $type == 'allow' ? false : true;
202  foreach (explode(',', $info[$type]) as $name) {
203  switch ($type) {
204  case 'allow':
205  if ($name[0] == '@') {
206  if ($validate($block, substr($name, 1), 'allow')) {
207  $result = true;
208  break 2;
209  }
210  } elseif ($block == $name) {
211  $result = true;
212  break 2;
213  }
214  break;
215  case 'disallow':
216  if ($name[0] == '@') {
217  if (!$validate($block, substr($name, 1), 'disallow')) {
218  $result = false;
219  break 2;
220  }
221  } elseif ($block == $name) {
222  $result = false;
223  break 2;
224  }
225  }
226  }
227  return $result;
228  }
229  return true;
230  };
231 
232  foreach ($this->extra['_blocks'] as $orient => $blocks) {
233  if (is_array($blocks)) {
234  foreach ($blocks as $index => $block) {
235  if (
236  !$validate($block, $orient, 'allow')
237  || !$validate($block, $orient, 'disallow')
238  || (
239  $block == 'template' // Das Standard Template entfernen
240  && $this->conf['no_template'] // ...wenn dieses nicht erwünscht ist
241  && $this->conf['blocks']['template']['removable'] === true // ...und explizit entfernt werden darf
242  )
243  ) {
244  if (isset($this->extra['_blocks'][$orient][$index])) {
245  unset($this->extra['_blocks'][$orient][$index]);
246  }
247  if (isset($this->extra['_contents'][$orient][$index])) {
248  unset($this->extra['_contents'][$orient][$index]);
249  }
250  }
251  }
252  }
253  }
254  }
255 
256  // Schlüssel aller Block Inhalte korrigieren und Standardwerte setzen
257  foreach ($this->extra['_blocks'] as $orient => $blocks) {
258  if (is_array($blocks)) {
259  $num = 0;
260  $contents = array();
261  foreach ($blocks as $index => $block) {
262  if (isset($this->extra['_contents'][$orient][$index])) {
263  $new_index = $index;
264  if ($new_index >= $num + 1) {
265  $new_index = $num;
266  $this->extra['_blocks'][$orient][$new_index] = $block;
267  unset($this->extra['_blocks'][$orient][$index]);
268  }
269  $contents[$new_index] = $this->extra['_contents'][$orient][$index];
270  } elseif (isset($this->conf['blocks'][$block]['default'][$orient])) {
271  $contents[$index] = $this->conf['blocks'][$block]['default'][$orient];
272  }
273  $num++;
274  }
275  $this->extra['_contents'][$orient] = $contents;
276  }
277  }
278  }
279 
280  // Mediapool Konfiguration korrigieren
281  if (isset($this->extra['mediapool']) && !is_array($this->extra['mediapool'])) {
282  $this->extra['mediapool'] = array();
283  }
284  }
285 
291  private function _loadConfig() {
292  // Konfigurationen lesen
293  $cache_key = 'pageConf'.md5(serialize(array($this->field['type'], $_SERVER['REQUEST_SUFFIX'])));
294  $this->conf = $this->_site->getCacheEntry($cache_key);
295  if ($this->conf === null) {
296  // 1. System
297  $confs = array(
298  $GLOBALS['egotec_conf']['lib_dir'] . 'page/conf.json',
299  $GLOBALS['egotec_conf']['lib_dir'] . 'type/site/' . $this->field['type'] . '/admin/conf.json'
300  );
301 
302  foreach (array('', $_SERVER['REQUEST_SUFFIX']) as $suffix) {
303  if (!empty($suffix) && trim(mb_strtolower(ltrim($suffix, '.'))) != 'html') {
304  $suffix = '.' . mb_strtolower(ltrim($suffix, '.'));
305  }
306  if ($suffix == '.html') {
307  continue;
308  }
309 
310  // 2. Designvorlage
311  if ($this->_site->theme) {
312  $confs[] = $GLOBALS['egotec_conf']['pub_dir'] . 'theme/' . $this->_site->theme . '/site/admin/conf' . $suffix . '.json';
313  }
314 
315  // 3. Global
316  if ($this->_site->globalAllowed()) {
317  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/conf.json';
318 
319  // 4. Global / Designvorlage
320  if ($this->_site->theme) {
321  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/' . $this->_site->theme . $suffix . '.json';
322  }
323 
324  // 5. Global / Standarddesign
325  if ($this->_site->skin) {
326  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/admin/' . $this->_site->skin . $suffix . '.json';
327  }
328  }
329 
330  // 6. Mandant
331  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/admin/conf' . $suffix . '.json';
332 
333  // 7. Designvorlage / Seitentyp
334  if ($this->_site->theme) {
335  $confs[] = $GLOBALS['egotec_conf']['pub_dir'] . 'theme/' . $this->_site->theme . '/site/' . $this->field['type'] . '/admin/conf' . $suffix . '.json';
336  }
337 
338  // 8. Global / Seitentyp
339  if ($this->_site->globalAllowed()) {
340  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/' . $this->field['type'] . '/admin/conf' . $suffix . '.json';
341 
342  // 9. Global / Seitentyp / Designvorlage
343  if ($this->_site->theme) {
344  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/' . $this->field['type'] . '/admin/' . $this->_site->theme . $suffix . '.json';
345  }
346 
347  // 10. Global / Seitentyp / Standarddesign
348  if ($this->_site->skin) {
349  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . '_global/' . $this->field['type'] . '/admin/' . $this->_site->skin . $suffix . '.json';
350  }
351  }
352 
353  // 11. Mandant / Seitentyp
354  $confs[] = $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/' . $this->field['type'] . '/admin/conf' . $suffix . '.json';
355  }
356 
357  $this->conf = array();
358  $confs = array_unique($confs);
359  foreach ($confs as $file) {
360  if (Ego_System::file_exists($file)) {
361  $this->conf = Ego_System::getJSON($file, $this->conf, true, ['plugins', 'toolbar', 'menubar', 'editor.options']);
362  }
363  }
364  if (empty($this->conf['default_layout'])) {
365  $this->conf['default_layout'] = 'default'; // Standard Layout ist "default", wenn keines definiert ist
366  }
367  unset($this->conf['site'], $this->conf['admin']); // Site Konfigurationen nicht in Page aufnehmen
368  $this->_site->setCacheEntry($cache_key, $this->conf);
369  }
370  if ($this->conf['main_orient']) {
371  // Die Haupt-Orientierung überschreiben
372  $this->mainOrient = $this->conf['main_orient'];
373  }
374  }
375 
383  public function __call($function, $params) {
384  // Mediapool Methoden beginnen mit "pool*"
385  if (strpos($function, 'pool') === 0 && is_callable($call = [$this->_pool, lcfirst(substr($function, 4))])) {
386  egotec_deprecated_log('18.4', 'Please use getMediapool() and the Mediapool object\'s methods.');
387  return call_user_func_array($call, $params);
388  }
389 
390  // Page Magic Methoden
391  $key = 'Page.magic'.md5(serialize(array($function, $this->field['type'])));
392  $magic_file = $this->_site->getCacheEntry($key);
393  if ($magic_file === null) {
394  $files = array(
395  "{$this->field['type']}/Page.{$function}.php"
396  );
397  $types = explode('/', $this->field['type']);
398  while (array_pop($types)) {
399  if (!empty($types)) {
400  $files[] = implode('/', $types) . "/Page.{$function}.php";
401  }
402  }
403  $files[] = "Page.{$function}.php";
404  foreach ($files as $file) {
405  if ($found = $this->_site->getSiteFile($file)) {
406  $magic_file = $found;
407  $this->_site->setCacheEntry($key, $magic_file);
408  break;
409  }
410  }
411  }
412  if (empty($magic_file)) {
413  $magic_file = $GLOBALS['egotec_conf']['lib_dir'] . 'base/Page.' . $function . '.php';
414  }
415  if (!file_exists($magic_file)) {
416  throw new Exception("Method 'Page.$function' not found");
417  }
418  require_once($magic_file);
419  return call_user_func($function, $this, $params);
420  }
421 
427  public function getTableSuffix() {
428  return $this->tableSuffix;
429  }
430 
437  public function setTableSuffix($suffix = '') {
438  $this->tableSuffix = $suffix;
439  }
440 
447  function getUser($user_type='c') {
448  require_once('auth/Auth.php');
449  return Auth::getUserRecord($this->field[$user_type.'_user']);
450  }
451 
458  private function _archiveEntry($asis = false) {
459  if (!$this->getTableSuffix()) {
460  $table = $this->_site->pageTable.'_v';
461  $db = new_db_connection();
462 
463  $field = $this->field;
464 
465  // Systemänderung markieren und ein neues Archiv anlegen
466  if ($asis) {
467  $field['c_date'] = date('Y-m-d H:i:s');
468  $extra = unserialize($field['extra']);
469  $extra['_asis'] = $this->field['c_date']; // @TODO Mit e_date lösen
470  $field['extra'] = serialize($extra);
471  }
472 
473  $field['title'] = $field['title'] ? $field['title'] : '';
474  $field['a_user'] = $field['a_user'] ? $field['a_user'] : '';
475  $field['c_user'] = $field['c_user'] ? $field['c_user'] : '';
476  unset($field['parents']);
477  $db->insert(array(
478  'table' => $table,
479  'set' => $field,
480  'primary' => array('id', 'c_date'),
481  'replace' => true
482  ));
483 
484  // Mediapool archivieren
485  $this->getMediapool()->archive($field['c_date']);
486  }
487  }
488 
498  private function _insertEntry($field, $lang='') {
499  if (!isset($field['id']) || $field['id']<=0) {
500  $field['id'] = $this->_site->nextId();
501  }
502  unset($field['parents']);
503 
504  // Alle Felder von nicht UTF8 Zeichen befreien
505  foreach ($field as $key => $value) {
506  if (is_string($value)) {
507  if ($key == 'extra') {
508  $field[$key] = serialize(Ego_System::filterData(unserialize($value)));
509  } else {
510  $field[$key] = Ego_System::filterNonUtf8($value);
511  }
512  }
513  }
514 
515  // Name und Titel ohne Leerzeichen am Anfang und Ende
516  foreach (array('name', 'title') as $key) {
517  if (isset($field[$key])) {
518  $field[$key] = trim($field[$key]);
519  }
520  }
521 
522  $db = new_db_connection();
523  $db->insert(array(
524  'table' => $lang?$this->_site->name.'_'.$lang:$this->_site->pageTable.$this->getTableSuffix(),
525  'set' => $field
526  ));
527  if ($lang) {
528  $site = clone $this->_site;
529  $site->setLanguage($lang);
530  } else {
531  $site = $this->_site;
532  }
533  $class = $site->getPageClass($field['type']);
534  $child = new $class($site, $field);
535  $child->_archiveEntry();
536  if (!isset($field['inactive']) || !$field['inactive']) {
537  $this->_clearCache();
538  }
539  return $child;
540  }
541 
550  private function _changeEntry($field = array(), $asis = false) {
551  $db = new_db_connection();
552  if (!$asis) {
553  $field['c_user'] = $GLOBALS['auth']->getId() ? $GLOBALS['auth']->getId() : '';
554  $field['c_date'] = date('Y-m-d H:i:s');
555  }
556  unset($this->field['idx']);
557  unset($field['idx']);
558  if (!isset($field['id'])) {
559  $field['id'] = $this->field['id'];
560  }
561  if (isset($field['nav_hide']) && !is_numeric($field['nav_hide'])) { // Oracle wirft einen ORA-01722, wenn kein numerischer Wert übergeben wird.
562  $field['nav_hide'] = 0;
563  }
564 
565  // nav_hide für diesen Seitentyp hat immer einen festgelegten Wert
566  if (isset($field['type'])) {
567  $this->field['type'] = $field['type'];
568  }
569  if (($info = $this->getTypeInfo()) && isset($info['nav_hide'])) {
570  $field['nav_hide'] = (int) $info['nav_hide'];
571  }
572 
573  // Name und Titel ohne Leerzeichen am Anfang und Ende
574  foreach (array('name', 'title') as $key) {
575  if (isset($field[$key])) {
576  $field[$key] = trim($field[$key]);
577  }
578  }
579 
580  // Der Name der Seite darf nie leer sein
581  if (isset($field['name']) && $field['name'] == '') {
582  $field['name'] = isset($field['title']) && $field['name'] != ''
583  ? $field['name']
584  : 'Neu';
585  }
586 
587  // Freigabe ab und bis Datum für die Datenbank leer setzen
588  if (isset($field['release_from']) && empty($field['release_from'])) {
589  $field['release_from'] = '0000-00-00 00:00:00';
590  }
591  if (isset($field['release_until']) && empty($field['release_until'])) {
592  $field['release_until'] = '0000-00-00 00:00:00';
593  }
594 
595  // Die Startseite kann nicht deaktiviert werden
596  if ($field['id'] == $this->_site->rootId) {
597  $field['inactive'] = self::ACTIVE_FLAG;
598  }
599 
600  // Die komplette Cache leeren, wenn ein Bild gelöscht oder wiederhergestellt wird
601  $cache_complete = isset($field['deleted'])
602  && $this->field['type'] == 'multimedia/image'
603  && $this->field['deleted'] != $field['deleted'];
604 
605  // Alle Felder von nicht UTF8 Zeichen befreien
606  foreach ($field as $key => $value) {
607  if (is_string($value)) {
608  if ($key == 'extra') {
609  $field[$key] = serialize(Ego_System::filterData(unserialize($value)));
610  } else {
611  $field[$key] = Ego_System::filterNonUtf8($value);
612  }
613  }
614  }
615 
616  if (!$this->archiveOnly) {
617  // Der letzte Archiveintrag ändert nie das Original
618  $db->update(array(
619  'table' => $this->_site->pageTable.$this->getTableSuffix(),
620  'set' => $field,
621  'where' => 'id='.$this->field['id']
622  ));
623 
624  // Beim Veröffentlichen wird das letzte Mediapool Archiv nach current kopiert
625  if (
626  $this->isPublicSave()
627  && $this->getMediapool()->currentDir != 'current'
628  ) {
633  @rename($this->getMediapool()->dir().'current', $this->getMediapool()->dir().'current.backup');
634  $retry = 0;
635  do {
636  Ego_System::copy($this->getMediapool()->dir().$this->getMediapool()->currentDir, $this->getMediapool()->dir().'current', '', true);
637  sleep($retry++);
638  } while (!Ego_System::file_exists($this->getMediapool()->dir().'current') && $retry < 3);
639  if (!Ego_System::file_exists($this->getMediapool()->dir().'current')) {
640  @rename($this->getMediapool()->dir().'current.backup', $this->getMediapool()->dir().'current');
641  } else {
642  Ego_Queue::add(array('Ego_System', 'deldir'), array($this->getMediapool()->dir().'current.backup'));
643  }
644 
645  Ego_Queue::add(array($this, 'reset'), array(false));
646  }
647  }
648  $this->_clearCache($cache_complete);
649  $this->field = array_merge($this->field, $field); // Die geänderten Werte auch direkt in das aktuelle Objekt übernehmen.
650  if (isset($field['extra'])) {
651  $extra = unserialize($field['extra']);
652  $this->extra = $extra?$extra:array();
653  }
654  }
655 
666  public function _getAncestorsIds($page, $query, $param = array()) {
667  $ancestors_ids = array();
668  if ($page) {
669  $cache_key = '_getAncestorsIds.'
670  .$page->field['id']
671  .'.'
672  .($query ? md5(serialize($query)) : '-')
673  .($param ? md5(serialize($param)) : '-');
674  $cache_val = $page->getSite()->getCacheEntry($cache_key);
675  if ($cache_val) {
676  return $cache_val;
677  }
678  foreach ($page->getParents($query, $param) as $parent) /* @var $parent Page */ {
679  $ancestors_ids[] = $parent->field['id'];
680  $ancestors_ids = array_merge($ancestors_ids, $this->_getAncestorsIds($parent, $query, $param));
681  }
682  $page->getSite()->setCacheEntry($cache_key, $ancestors_ids);
683  }
684  return $ancestors_ids;
685  }
686 
699  private function _getDescendantsIds($page, $query=array(), $param=array(), &$descendants=array()) {
700  $query['hash'].= ':'.$page->field['id'];
701  foreach ($page->getChildren($query, $param) as $child) /* @var $child Page */ {
702  if (in_array($child->field['id'], $descendants)) { // Endlosschleifen abfangen
703  ; // egotec_error_log('infinite loop protection on '.$child->field['id']);
704  } else {
705  set_time_limit(30);
706  $descendants[] = $child->field['id'];
707  if ($child->field['has_children']) { // Nur weiter nach unten gehen, wenn eine Seite tatsächlich Kinder besitzt.
708  $this->_getDescendantsIds($child, $query, $param, $descendants);
709  }
710  }
711  }
712  }
713 
721  private function _getRights($perm_type='') {
722  return new_db_connection(array(
723  'fields' => '*',
724  'from' => $this->_site->pageTable.'_rights',
725  'where' => "page_id=".$this->field['id'].($perm_type?" AND perm='".$perm_type."'":"")
726  ));
727  }
728 
736  private function _getUsers($perm_type='') {
737  return new_db_connection(array(
738  'fields' => '*',
739  'from' => $this->_site->pageTable.'_users',
740  'where' => "page_id=".$this->field['id'].($perm_type?" AND perm='".$perm_type."'":'')
741  ));
742  }
743 
752  private function _getEmptyEntry($new=array()) {
753  unset($new['idx']);
754  unset($new['parents']);
755 
756  $user_id = $GLOBALS['auth']->getId() ? $GLOBALS['auth']->getId() : '';
757  $date = date('Y-m-d H:i:s');
758  $empty = array(
759  'id' => '',
760  'title' => 'Neue Seite',
761  'name' => 'Neu',
762  'short' => '',
763  'content' => '',
764  'extra' => '',
765  'type' => 'page',
766  'cache' => self::CACHE_BROWSER|self::CACHE_PROXY|self::CACHE_SERVER,
767  'inactive' => self::INACTIVE_FLAG,
768  'release_from' => '0000-00-00 00:00:00',
769  'release_until' => '0000-00-00 00:00:00',
770  'nav_hide' => 0,
771  'deleted' => 0,
772  'a_date' => $date,
773  'c_date' => $date,
774  'a_user' => $user_id,
775  'c_user' => $user_id,
776  'order_field' => 0,
777  'children_order'=> 'children',
778  'workflow_state'=> 0,
779  'workflow' => '',
780  'url' => ''
781  );
782  if ($new) {
783  foreach ($new as $key => $value) {
784  if (!is_null($value)) {
785  $empty[$key] = $value;
786  }
787  }
788  }
789  return $empty;
790  }
791 
798  function hasRights($rights, $user_id = false) {
799  return $this->_site->hasRightsOnId($this->field['id'], $rights, $user_id);
800  }
801 
808  public function hasRightsOn($perm) {
809  // Gruppen/Rollen prüfen
810  $rights = $this->getRightsArray($perm);
811  if (!empty($rights[$perm])) {
812  foreach ($rights[$perm] as $right) {
813  if ($right['group_id'] != '*' && $right['role_id'] != '*') {
814  return true;
815  }
816  }
817  }
818 
819  // Benutzer prüfen
820  $users = $this->getUsersArray($perm);
821  if (!empty($users[$perm])) {
822  foreach ($users[$perm] as $user) {
823  if ($user['user_id'] != '*') {
824  return true;
825  }
826  }
827  }
828 
829  return false;
830  }
831 
842  function newChild($field = array(), $extra = array(), $inherit=true) {
843  if ($field['deleted'] == 1) { // Es wird grundsätzlich keine Seite angelegt, die das deleted flag gesetzt hat.
844  return false;
845  }
846 
847  if (!$extra['release_id'] && $this->_site->admin['multi_lang']['auto_link']) { // Automatische Verknüpfung in alle Sprachen erstellen (außer für Freigabekopien).
848  $extra['language_standard'] = $this->_site->language;
849  foreach ($this->_site->getLanguages() as $lang) {
850  $extra['language_link'][$lang] = 1;
851  }
852  } elseif(!$extra['language_standard']) {
853  if ($this->extra['language_standard'] == $this->_site->language) {
854  // Die Sprachverknüpfungen nur bei der Standardspreche vererben
855  $extra['language_standard'] = $this->extra['language_standard'];
856  $extra['language_link'] = $this->extra['language_link'];
857  if (!$extra['language_standard']) {
858  $extra['language_standard'] = $this->_site->language;
859  }
860  if (!$extra['language_link']) {
861  $extra['language_link'] = array();
862  foreach ($this->_site->getLanguages() as $lang) {
863  if ($lang == $extra['language_standard']) {
864  $extra['language_link'][$lang] = 1;
865  } else {
866  $extra['language_link'][$lang] = 0;
867  }
868  }
869  }
870  } else {
871  // ansonsten wird die aktuelle Sprache zur Standardsprache
872  $extra['language_standard'] = $this->_site->language;
873  }
874  }
875 
876  if ($inherit) { // Eigenschaften vererben.
877  // Den Workflow auf die neue Seite kopieren
878  if ($this->_site->admin['workflow']['enabled'] && $this->field['workflow'] && !isset($field['workflow'])) {
879  $field['workflow'] = $this->field['workflow'];
880  if ($this->extra['workflows']) {
881  $extra['workflows'] = $this->extra['workflows'];
882  }
883  }
884 
885  // Intranet- und Navigationsflag vererben.
886  $field['nav_hide'] = ((int) $field['nav_hide']) | ((int) $this->field['nav_hide']);
887 
888  // Template und Design Variante vererben (nur bei gleichen Seitentypen).
889  if (
890  $this->field['type'] == $field['type']
891  || (!isset($field['type']) && $this->field['type'] == 'page')
892  ) {
893  if (!empty($this->extra['_template']) && empty($extra['_template'])) {
894  $extra['_template'] = $this->extra['_template'];
895  }
896  if (!empty($this->extra['_style']) && empty($extra['_style'])) {
897  $extra['_style'] = $this->extra['_style'];
898  }
899  }
900 
901  // IP Ansichtsrechte vererben
902  if (empty($extra['ip_rights']) && !empty($this->extra['ip_rights'])) {
903  $extra['ip_rights'] = $this->extra['ip_rights'];
904  }
905  }
906  $field = $this->_getEmptyEntry($field);
907 
908  $field['extra'] = serialize($extra);
909  $new_page = $this->_insertEntry($field);
910  $field['id'] = $new_page->field['id'];
911  if (
912  !$new_page->isWorkflowCopy()
913  && !$new_page->isReleaseCopy()
914  && !$new_page->isClone()
915  && is_array($new_page->extra['language_link'])
916  ) { // Automatisch Verknüpfung in alle Sprachen erstellen.
917  foreach ($this->_site->getLanguages() as $lang) {
918  if ($lang != $this->_site->language && $new_page->extra['language_link'][$lang]) {
919  $lang_page = $new_page->getLanguagePage($lang, array('auth_or' => '1=1'));
920  if ($lang_page) {
921  continue;
922  }
923  $lang_parent = $this->getLanguagePage($lang, array('auth_or' => '1=1', 'deleted_or' => '1=1'));
924  if ($lang_parent && $lang_parent->field['deleted']) {
925  $lang_parent->undelete();
926  }
927  $lang_page = $this->_insertEntry($field, $lang);
928  $lang_page->addParent($this->field['id']);
929  // Die Rechte der aktuellen Seite auf die neue Seite kopieren, das Bearbeitungsrecht aber auf 'Untermenüpunkt anlegen' setzen.
930  $new_rights = $this->getRightsArray();
931  $new_rights['edit'] = $new_rights['child'];
932  $new_users = $this->getUsersArray();
933  $new_users['edit'] = $new_users['child'];
934  $lang_page->setRightsArray($new_rights);
935  $lang_page->setUsersArray($new_users);
936  }
937  }
938  }
939  $new_page->addParent($this->field['id']);
940  $this->message = $GLOBALS['auth']->translate('Neuer Untermenüpunkt wurde erstellt!');
941  if ($new_page->field['inactive']) {
942  $this->message.= "\n".$GLOBALS['auth']->translate('Diese Seite ist inaktiv (nicht online verfügbar).');
943  } else {
944  $this->message.= "\n".$GLOBALS['auth']->translate('Diese Seite ist freigeschaltet.');
945  }
946 
947  // Die Rechte der aktuellen Seite auf die neue Seite kopieren, das Bearbeitungsrecht aber auf 'Untermenüpunkt anlegen' setzen.
948  $new_rights = $this->getRightsArray();
949  $new_rights['edit'] = $new_rights['child'];
950  $new_users = $this->getUsersArray();
951  $new_users['edit'] = $new_users['child'];
952  $new_page->setRightsArray($new_rights);
953  $new_page->setUsersArray($new_users);
954  $new_page->updateIndex();
955  $new_page->hookUpdate('newchild');
956  $new_page->hookUpdate();
957 
958  return $new_page;
959  }
960 
968  public function hasFile($name, $suffix = '') {
969  $children = $this->getChildren(array(
970  'where' => "name = :name AND type IN ('multimedia/file', 'multimedia/image')",
971  'bind' => array(
972  'name' => $name
973  )
974  ), array(
975  'inactive' => 1,
976  'only_active' => false
977  ));
978  if ($page = $children->nextPage()) {
979  if (!$suffix || $page->extra['image_type'] == $suffix) {
980  return $page;
981  }
982  }
983  return null;
984  }
985 
995  public function newFile($source, $name, $options = array(), $suffix = '') {
996  if ($this->_site->site['type'] == 'media' && $this->validateFile($source, $name)) {
997  @set_time_limit(0);
998 
999  require_once('media/functions.php');
1000  require_once('base/Ego_MimeType.php');
1001  if ($name) {
1002  $path_info = Ego_System::pathinfo($name);
1003  $GLOBALS['mediaType'] = $path_info['extension'];
1004  }
1005  $mime = new Ego_MimeType();
1006  $mime_type = $mime->autoDetect($source);
1007 
1008  $is_image = !(strpos($mime_type, 'image') === false);
1009  $field = $options;
1010  $extra = array();
1011  if ($field['extra']) {
1012  $extra = $field['extra'];
1013  }
1014 
1016  $options['name'] ? $options['name'] : $name)));
1017  $field['title'] = trim(Ego_System::filterNonUtf8(Ego_System::stringEncode(
1018  $options['title'] ? $options['title'] : $field['name'])));
1019 
1020  if (!Ego_System::file_exists($GLOBALS['egotec_conf']['tmp_dir'])) {
1021  Ego_System::mkdir($GLOBALS['egotec_conf']['tmp_dir']);
1022  }
1023  if(!empty($options['extra']['mime_type'])) {
1024  $extra['mime_type'] = $options['extra']['mime_type'];
1025  } else {
1026  $extra['mime_type'] = $mime_type;
1027  }
1028  if ($suffix) {
1029  $extra['image_type'] = $suffix;
1030  } else {
1031  // Falls keine Endung angegeben ist, wird diese aus dem Namen gewonnen.
1032  if ($path_info['extension']) {
1033  $extra['image_type'] = $path_info['extension'];
1034  } else {
1035  // Als allerletztes die Endung aus dem Mime/Type bestimmen.
1036  if (!$GLOBALS['mime2ext']) {
1037  $GLOBALS['mime2ext'] = array_flip(Ego_System::getMimeTypes());
1038  }
1039  $extra['image_type'] = $GLOBALS['mime2ext'][$extra['mime_type']];
1040  }
1041  }
1042  if ($is_image) {
1043  require_once('base/Ego_Image.php');
1044  $imageTransform = new Ego_Image();
1045  $imageTransform->load($source);
1046 
1047  if (!minimumImageDimensions($imageTransform, $this->_site)) {
1048  return null;
1049  }
1050  scaleImageOnUpload($imageTransform, $this->_site);
1051 
1052  $extra['origImgWidth'] = $imageTransform->getImageWidth();
1053  $extra['origImgHeight'] = $imageTransform->getImageHeight();
1054  $extra['copyright'] = $imageTransform->getExif(Ego_Image::EXIF_COPYRIGHT);
1055  } else {
1056  getFileInfo($source, $extra);
1057  }
1058  $extra['origFileSize'] = Ego_System::filesize($source);
1059  $field['type'] = 'multimedia/'.($is_image ? 'image' : 'file');
1060  $field['inactive'] = self::ACTIVE_FLAG;
1061  $field['parents'] = ','.trim($this->field['id'],',').',';
1062 
1063  // Wenn Search+ aktiviert ist, wird der Dateiinhalt in die DB aufgenommen
1064  if (!$is_image && $GLOBALS['egotec_conf']['openoffice']['active']) {
1065  require_once('openoffice/converter.php');
1066  $field['content'] = convert_content($source, $extra['image_type'], $extra['mime_type']);
1067  }
1068  $child = $this->newChild($field, $extra);
1069 
1070  // Datei nach var/media/ kopieren
1071  $media_dir = $GLOBALS['egotec_conf']['var_dir'].'media'.DIRECTORY_SEPARATOR.$this->_site->name;
1072  if (!Ego_System::file_exists($media_dir)) {
1073  Ego_System::mkdir(strtr($media_dir, '/', DIRECTORY_SEPARATOR), 0777, true);
1074  }
1075 
1076  $dest = $media_dir.DIRECTORY_SEPARATOR.$child->getMediaFilename(true);
1078  $source,
1079  $dest
1080  );
1081 
1082  // Archiveintrag
1084  $dest,
1085  $media_dir.DIRECTORY_SEPARATOR.$child->getMediaFilename(
1086  true,
1087  '_'.strtotime($child->field['c_date'])
1088  ),
1089  '',
1090  true
1091  );
1092 
1093  return $child;
1094  }
1095  return null;
1096  }
1097 
1104  public function extractFile($source) {
1105  $id = $this->field['id'];
1106  $dir = $GLOBALS['egotec_conf']['tmp_dir'].'import/zip/';
1107  $name = time();
1108  $dest = $dir.$name;
1109  $file = tempnam($dir, 'ZIP_').'.zip';
1110  if (!Ego_System::file_exists($dest)) {
1111  Ego_System::mkdir(strtr($dest, '/', DIRECTORY_SEPARATOR), 0777, true);
1112  }
1113  if (@move_uploaded_file($source, $file)) {
1114  require_once('media/functions.php');
1115  require_once('Archive/Zip.php');
1116  $zip = new Archive_Zip($file);
1117  chdir($dest);
1118  @set_time_limit(0);
1119  $zip->extract();
1120  chdir($GLOBALS['egotec_conf']['bin_dir'].'admin');
1121  $num = GetDir($dest, '', $this->field['id'], true);
1122  Ego_System::deldir($dest, true);
1123  @unlink($file);
1124  if (isset($GLOBALS['_GetDir_firstId'])) {
1125  $id = $GLOBALS['_GetDir_firstId'];
1126  unset($GLOBALS['_GetDir_firstId']);
1127  }
1128  }
1129  return $this->_site->getPage($id);
1130  }
1131 
1139  public function updateFile($source, $name = '') {
1140  if (!$this->validateFile($source, $name)) {
1141  return false;
1142  }
1143 
1144  require_once('media/functions.php');
1145  require_once('base/Ego_MimeType.php');
1146  if ($name) {
1147  $path_info = Ego_System::pathinfo($name);
1148  $GLOBALS['mediaType'] = $path_info['extension'];
1149  }
1150  $mime = new Ego_MimeType();
1151  $mime_type = $mime->autoDetect($source);
1152  $is_image = !(strpos($mime_type, 'image') === false);
1153 
1154  $field = array();
1155  $extra = $this->extra;
1156 
1157  $extra['mime_type'] = $mime_type;
1158  if ($name) {
1159  if ($path_info['extension']) {
1160  $extra['image_type'] = $path_info['extension'];
1161  }
1162  }
1163  if (!$name || !$extra['image_type']) {
1164  // Als allerletztes die Endung aus dem Mime/Type bestimmen.
1165  if (!$GLOBALS['mime2ext']) {
1166  $GLOBALS['mime2ext'] = array_flip(Ego_System::getMimeTypes());
1167  }
1168  $extra['image_type'] = $GLOBALS['mime2ext'][$extra['mime_type']];
1169  }
1170 
1171  $extra['origFileSize'] = Ego_System::filesize($source);
1172  $field['type'] = 'multimedia/'.($is_image ? 'image' : 'file');
1173 
1174  if ($is_image) {
1175  require_once('base/Ego_Image.php');
1176  $imageTransform = new Ego_Image();
1177  $imageTransform->load($source);
1178 
1179  if (!minimumImageDimensions($imageTransform, $this->_site)) {
1180  return false;
1181  }
1182  scaleImageOnUpload($imageTransform);
1183 
1184  $extra['origImgWidth'] = $imageTransform->getImageWidth();
1185  $extra['origImgHeight'] = $imageTransform->getImageHeight();
1186  $extra['copyright'] = $imageTransform->getExif(Ego_Image::EXIF_COPYRIGHT);
1187  } else {
1188  getFileInfo($source, $extra);
1189  }
1190 
1191  // Wenn Search+ aktiviert ist, wird der Dateiinhalt in die DB aufgenommen
1192  if (!$is_image) {
1193  if ($GLOBALS['egotec_conf']['openoffice']['active']) {
1194  // OpenOffice: Inhalt neu ermitteln
1195  require_once('openoffice/converter.php');
1196  $field['content'] = convert_content($source, $extra['image_type'], $extra['mime_type']);
1197  } elseif (Ego_System::checkLicence($GLOBALS['egotec_conf']['lib_dir'] . 'elastic')) {
1198  // Elasticsearch: Inhalt leeren; wird beim Update automatisch indiziert
1199  $field['content'] = '';
1200  unset($extra['_indexed']);
1201  }
1202  }
1203 
1204  $this->update(array(
1205  'field' => $field,
1206  'extra' => $extra
1207  ));
1208 
1209  // Alle Ausschnitte ebenfalls aktualiseren
1210  if ($this->field['type'] == 'multimedia/image') {
1211  foreach ($this->getChildren(array(), array(
1212  'auth_or' => '1=1'
1213  )) as $child) {
1214  if ($child->extra['crop_image']) {
1215  $extra = array(
1216  'edit' => $child->extra['edit'],
1217  'crop_image' => true
1218  );
1219  $child->updateExtra(array_merge($this->extra, $extra));
1220  }
1221  }
1222  }
1223 
1224  // Datei nach var/media/ kopieren
1225  $media_dir = $GLOBALS['egotec_conf']['var_dir'].'media'.DIRECTORY_SEPARATOR.$this->_site->name;
1226  if (!Ego_System::file_exists($media_dir)) {
1227  Ego_System::mkdir(strtr($media_dir, '/', DIRECTORY_SEPARATOR), 0777, true);
1228  }
1229 
1230  // Falls die Datei der Standard Sprache noch nicht im Sprach Verzeichnis liegt, dann verschieben
1231  if (
1232  $this->_site->language == $this->_site->site['default_language']
1233  && !Ego_System::file_exists($media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(true))
1234  && Ego_System::file_exists($media_dir.DIRECTORY_SEPARATOR.$this->field['id'])
1235  ) {
1236  rename(
1237  $media_dir.DIRECTORY_SEPARATOR.$this->field['id'],
1238  $media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(true)
1239  );
1240 
1241  $mediafiles = glob($media_dir.DIRECTORY_SEPARATOR.$this->field['id'].'_*');
1242  if (is_array($mediafiles)) {
1243  foreach ($mediafiles as $mediafile) {
1244  preg_match('/\d+_\d+$/', $mediafile, $name);
1245  rename(
1246  $mediafile,
1247  $media_dir.DIRECTORY_SEPARATOR.$this->_site->language.DIRECTORY_SEPARATOR.$name[0]
1248  );
1249  }
1250  }
1251  }
1252 
1253  // Vor dem Ersetzen das Original löschen, damit sich die Archive nicht ändern, weil diese Hardlinks sind
1254  $dest = $media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(true);
1255  @unlink($dest);
1256  Ego_System::copy($source, $dest);
1257 
1258  // Archiveintrag
1260  $dest,
1261  $media_dir.DIRECTORY_SEPARATOR.$this->getMediaFilename(
1262  true,
1263  '_'.strtotime($this->field['c_date'])
1264  ),
1265  '',
1266  true
1267  );
1268 
1270  $GLOBALS['egotec_conf']['cachemedia_dir'].$this->_site->name.DIRECTORY_SEPARATOR.
1271  $this->getMediaFilename(true)
1272  );
1273 
1274  // Video komprimieren
1275  if ($this->_site->admin['video']['compress'] && $this->extra['mime_type'] == 'video/mp4') {
1276  Ego_Queue::add(array($this, 'compressVideo'));
1277  }
1278 
1279  return true;
1280  }
1281 
1293  function copyTo($id, $recursive = false, $params = array(), &$copied_pages = array())
1294  {
1295  if ($this->isClone() || $this->isWorkflowCopy() || $this->isReleaseCopy()) {
1296  return false; // Keine Klone, Workflow- und Freigabekopien kopieren
1297  }
1298 
1299  $param = array(
1300  'auth_or' => '1=1',
1301  'only_active' => false,
1302  'inactive' => true
1303  );
1304 
1305  /* @var $new_parent Page */
1306  if (is_a($id, 'Page')) {
1307  // $id ist bereits das Page Objekt
1308  $new_parent = $id;
1309  } elseif (is_a($params['site'], 'Site')) {
1310  // Übergebenes Site Objekt
1311  $new_parent = $params['site']->getPage($id, $param);
1312  } elseif (
1313  $this->_site->name == $GLOBALS['site']->name
1314  && $this->_site->language == $GLOBALS['site']->language
1315  ) {
1316  // Quell- und Ziel-Mandant sind identisch
1317  $new_parent = $this->_site->getPage($id, $param);
1318  } else {
1319  // Kopieren über Mandanten hinweg
1320  if ($this->_site->site['type'] == 'media') {
1321  $new_parent = $GLOBALS['site']->getMediaSite()->getPage($id, $param);
1322  } else {
1323  $new_parent = $GLOBALS['site']->getPage($id, $param);
1324  }
1325  }
1326  $site_parent = $new_parent->getSite();
1327 
1328  // Kopieren in den selben Mandanten: Endlosschleife vermeiden
1329  if ($this->_site->name == $site_parent->name) {
1330  $ancestors = $this->_getAncestorsIds(
1331  $new_parent,
1332  array('fields' => 'id'),
1333  array('auth_or' => '1=1')
1334  );
1335  if (in_array($this->field['id'], $ancestors)) {
1336  return false;
1337  }
1338  }
1339 
1340  // Kopierte Werte setzen
1341  if (is_array($params['field'])) {
1342  $field = $params['field'];
1343  } else {
1344  $field = $this->field;
1345  }
1346  if (is_array($params['extra'])) {
1347  $extra = $params['extra'];
1348  } else {
1349  $extra = $this->extra;
1350  }
1351 
1352  unset($field['id']);
1353  unset($field['extra']);
1354  $field['a_user'] = $GLOBALS['auth']->user->field['user_id'];
1355  $field['a_date'] = date('Y-m-d H:i:s');
1356  unset($extra['workflow_page']);
1357 
1358  // Eine kopierte Seite hat keine Klone
1359  unset($extra['clones']);
1360  foreach (array_keys($extra) as $key) {
1361  if (
1362  strpos($key, 'clone_children_') === 0
1363  || strpos($key, 'clone_release_') === 0
1364  ) {
1365  unset($extra[$key]);
1366  }
1367  }
1368 
1369  // Meta Url löschen wenn die Seite im gleichen Mandanten kopiert wird
1370  if($this->_site->name == $site_parent->name) {
1371  unset($field['url']);
1372  }
1373 
1374  // Vor dem Kopieren einer Seite dessen Felder manipulieren
1375  try {
1376  list($field, $extra) = $this->copyToFields($field, $extra);
1377  } catch (Exception $e) {
1378  // "copyToFields" existiert nicht, ignorieren
1379  }
1380 
1381  $copy = $new_parent->newChild($field, $extra); /* @var $copy Page */
1382  $rights = array(
1383  'rights' => $this->getRightsArray(),
1384  'users' => $this->getUsersArray()
1385  );
1386  $copy->updateRights($rights, false);
1387 
1388  /* Evtl. vorhandene MM-Datei kopieren */
1389  if (file_exists($GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename())) {
1390  if ($this->_site->name == $site_parent->name && $this->_site->language == $site_parent->language) {// Quell- und Ziel-Mandant sind identisch
1392  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename(),
1393  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$copy->getMediaFilename(true),
1394  '',
1395  true
1396  );
1397  } else { //Kopieren über Mandanten hinweg
1399  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename(),
1400  $GLOBALS['egotec_conf']['var_dir'].'media/'.$site_parent->name.'/'.$copy->getMediaFilename(true),
1401  '',
1402  true
1403  );
1404  }
1405  }
1406 
1407  // Mediapool kopieren
1408  $this->getMediapool()->copy($copy, '', false, false, false);
1409 
1410  // Sprachen beachten
1411  if (
1412  !$copy->isReleaseCopy() // Freigabekopien werden nur in der aktuellen Sprache angelegt
1413  && $this->extra['language_link']
1414  ) {
1415  foreach($this->extra['language_link'] as $lang => $flag) {
1416  if ($lang != $this->_site->language) {
1417  if (in_array($lang, $this->_site->getLanguages()) &&
1418  in_array($lang, $copy->getSite()->getLanguages())
1419  ) {
1420  $lang_page = $this->getLanguagePage($lang); // die sprachversion der zu kopierenden seite
1421 
1422  if ($lang_page) {
1423  $lang_page_field = $lang_page->field;
1424  $lang_page_extra = $lang_page->extra;
1425  $lang_page_field['id'] = $copy->field['id'];
1426 
1427  // Vor dem Kopieren einer Seite dessen Felder manipulieren
1428  try {
1429  list($lang_page_field, $lang_page_extra) = $this->copyToFields($lang_page_field, $lang_page_extra);
1430  } catch (Exception $e) {
1431  // "copyToFields" existiert nicht, ignorieren
1432  }
1433 
1434  $_param = array('auth_or'=>'1=1', 'deleted_or'=>'1=1', 'inactive'=>true);
1435  $lang_copy = $copy->getLanguagePage($lang, $_param);
1436  if (!$lang_copy) {
1437  $copy_parent = $new_parent->getLanguagePage($lang, $_param);
1438  if (!$copy_parent) { // Sprachversion der Elternseite existiert nicht, also direkt unter der Startseite einfügen
1439  $copy_parent = $copy->getSite()->getRoot()->getLanguagePage($lang, $_param);
1440  }
1441  $lang_copy = $copy_parent->newChild($lang_page_field, $lang_page_extra);
1442  } else { // Sprachversion existiert bereits
1443  $lang_copy->update(
1444  array(
1445  'field' => $lang_page_field,
1446  'extra' => $lang_page_extra
1447  )
1448  );
1449  }
1450 
1451  if($lang_copy) {
1452  // Rechte übernehmen
1453  $rights = array(
1454  "rights" => $lang_page->getRightsArray()
1455  ,"users" => $lang_page->getUsersArray()
1456  );
1457  $lang_copy->updateRights($rights, false);
1458  }
1459  }
1460  }
1461  }
1462  }
1463  }
1464  if ($recursive) {
1465  // Bei einer Rekursion werden Mehrfacheinhängungen beibhalten
1466  if (!isset($copied_pages[$this->field['id']])) {
1467  $copied_pages[$this->field['id']] = $copy;
1468  }
1469 
1470  $children = $this->getChildren($params['children_query'], $params['children_param']);
1471  foreach ($children as $child) {
1472  set_time_limit(0); // Ein Timeout verhindern.
1473  if ($new_child = $copied_pages[$child->field['id']]) {
1474  // Mehrfacheinhängung beibehalten
1475  $new_child->addParent($copy->field['id'], true);
1476  } else {
1477  $child->copyTo($copy,$recursive,$params,$copied_pages);
1478  }
1479  }
1480  }
1481 
1482  if ($new_parent->extra['clones']) { // Prüfen ob die neue Elternseite Klone hat und diese dann aktualisieren
1483  $param = array(
1484  'field' => $new_parent->field
1485  );
1486  $new_parent->_updateClones($param);
1487  }
1488  return $copy;
1489  }
1490 
1498  function move($from, $to) {
1499  if ($from != $to && $this->addParent($to)) {
1500  $this->delParent($from, true);
1501  }
1502  $this->hookUpdate();
1503  }
1504 
1511  function linkTo($id) {
1512  $this->addParent($id);
1513  }
1514 
1527  function delete($parent = false, $nostart = false, $keeplinks = true, $query = array()) {
1528  if ($this->isRoot()) {
1529  throw new Page_Exception("Can't delete root page.", Page_Exception::ROOT_PROTECTION);
1530  }
1531 
1532  // Wird ein Schlagwort gelöscht, werden auch nur Schlagwörter berücksichtigt
1533  // TODO mit param[sitemap] = false lösen
1534  if ($this->field['type'] == '_keywords/entry') {
1535  if ($query['where']) {
1536  $query['where'] = "({$query['where']}) AND type = '_keywords/entry'";
1537  } else {
1538  $query['where'] = "type = '_keywords/entry'";
1539  }
1540  }
1541 
1542  $this->archiveOnly = false;
1543  $children = $this->getChildren(
1544  $query,
1545  array(
1546  'inactive' => true,
1547  'auth_or' => '1=1'
1548  )
1549  );
1550  foreach ($children as $child) { // Die Seite hat Unterseiten
1551  $child->delete($keeplinks ? $this : false, false, $keeplinks, $query);
1552  }
1553 
1554  // sprachverknuepfungen ...
1555  // wenn die standardsprache geloescht wird ...
1556  if (is_array($this->extra['language_link'])
1557  && $this->extra['language_standard']==$this->_site->language
1558  ) {
1559  $languages = $this->_site->getLanguages();
1560 
1561  // es wird ein neues Standard gesetzt
1562  $std = $languages[0]==$this->_site->language?$languages[1]:$languages[0];
1563  $link_a = array();
1564 
1565  // werden alle sprachen durchgegangen ...
1566  foreach($languages as $lang) {
1567  $lang_page = $this->getLanguagePage($lang, array('deleted' => -1));
1568  if(!is_object($lang_page)) continue;
1569 
1570  // und die sprachverknuepfungen geloescht
1571  $extra = $lang_page->extra;
1572  unset($extra['language_link']);
1573  $extra['language_link'] = $link_a;
1574  if($std) $extra['language_standard'] = $std;
1575  $lang_page->_update(array('extra' => $extra),true,false);
1576  }
1577  }
1578 
1579  $parents = $this->getParents(
1580  array(
1581  'fields' => 'id'
1582  ),
1583  array(
1584  'sitemap' => true,
1585  'inactive' => true,
1586  'auth_or' => '1=1'
1587  )
1588  );
1589  if ($parent && $parents->numRecords() > 1)
1590  {// Die Seite ist mehrfach eingehängt
1591  $this->unlinkFrom($parent->field['id']);
1592  } else {
1593  if(!$nostart) {
1594  // Alle Workflow-, Freigabekopien zerstören
1595  $destroy_ids = array();
1596  if (!empty($this->extra['workflow_page'])) {
1597  $destroy_ids[] = $this->extra['workflow_page'];
1598  }
1599  if (!empty($this->extra['release_ids'])) {
1600  $destroy_ids = array_merge($destroy_ids, $this->extra['release_ids']);
1601  }
1602  foreach ($destroy_ids as $destroy_id) {
1603  if ($destroy_page = $this->_site->getPage($destroy_id, array(
1604  'only_active' => false,
1605  'inactive' => 1,
1606  'auth_or' => '1=1'
1607  ))) {
1608  $destroy_page->destroy(true);
1609  }
1610  }
1611 
1612  $field['deleted'] = 1;
1613  $extra = $this->extra;
1614  unset($extra['workflow_page'], $extra['release_ids']);
1615  $this->update(array('field' => $field, 'extra' => $extra));
1616  }
1617  }
1618 
1619  // Achtung: wenn ich eine Klon Seite bin, dann muss die Verknüpfung aus der Originalseite entfernt werden
1620  if ($this->isClone()) {
1621  $org = $this->getCloneOriginal();
1622  $del_clone = $this->getParents(array(), array(
1623  'inactive' => true,
1624  'auth_or' => '1=1'
1625  ))->nextPage();
1626  $del_id = $del_clone->field['id']; // abwärtskompatibel
1627  if ($org) {
1628  $del_url = $this->getCloneUrl();
1629 
1630  $clones = array_filter(array_unique(explode(',', $org->extra['clones'])));
1631  $new_clones = array();
1632  foreach ($clones as $clone_url) {
1633  if (!in_array($clone_url, array($del_id, $del_url))) {
1634  $new_clones[] = $clone_url;
1635  }
1636  }
1637 
1638  $org->extra['clones'] = implode(',', $new_clones);
1639  $org->updateExtra($org->extra);
1640  }
1641  }
1642 
1643  // Achtung: wenn ich eine Freigabekopie bin, dann muss die Verknüpfung aus der Originalseite entfernt werden
1644  if ($this->isReleaseCopy()) {
1645  if (
1646  ($org = $this->_site->getPage($this->extra['release_id'], array(
1647  'only_active' => false,
1648  'inactive' => 1,
1649  'auth_or' => '1=1'
1650  )))
1651  && is_array($org->extra['release_ids'])
1652  ) {
1653  $org->extra['release_ids'] = array_values(array_diff($org->extra['release_ids'], array($this->field['id'])));
1654  $org->update(array(), true, true);
1655  }
1656  }
1657  }
1658 
1666  protected function _destroyEntry($recursive=true) {
1667  @set_time_limit(0); //Wird zwingend benötigt, für den Fall dass viele Unterseiten existieren
1668  $db = new_db_connection();
1669 
1670  $this->message = 'Diese Seite wurde vernichtet.';
1671 
1672  if($recursive) {
1673  $query = array();
1674 
1675  // Wird ein Schlagwort zerstört, werden auch nur Schlagwörter berücksichtigt
1676  // TODO mit param[sitemap] = false lösen
1677  if ($this->field['type'] == '_keywords/entry') {
1678  $query['where'] = "type = '_keywords/entry'";
1679  }
1680 
1681  $pages = $this->getChildren($query, array('deleted' => 1));
1682  $del_array = array();
1683  foreach($pages as $page) { // Zunächst alle Seiten holen,
1684  $del_array[] = $page;
1685  }
1686  foreach($del_array as $page) { // weil es bei ms sql sonst hier zu einer Blockade kommt.
1687  $page->destroy(false, $recursive);
1688  $this->message = 'Diese Seite wurde inklusive Unterseiten erfolgreich vernichtet.';
1689  }
1690  }
1691 
1692  $parents = $this->getParents(array(), array('deleted' => -1));
1693  foreach ($parents as $parent) {
1694  $this->unlinkFrom($parent->field['id']);
1695  }
1696 
1697  $db->begin();
1698  $db->delete(array( // Aus der Tabelle löschen.
1699  'table' => $this->_site->pageTable,
1700  'where' => "id=".$this->field['id']
1701  ));
1702  $db->delete(array( // Aus dem Archiv löschen.
1703  'table' => $this->_site->pageTable.'_v',
1704  'where' => "id=".$this->field['id']
1705  ));
1706  $db->delete(array( // Aus der Rechte-Tabelle löschen.
1707  'table' => $this->_site->pageTable.'_rights',
1708  'where' => "page_id=".$this->field['id']
1709  ));
1710  $db->delete(array( // Aus der User-Tabelle löschen.
1711  'table' => $this->_site->pageTable.'_users',
1712  'where' => "page_id=".$this->field['id']
1713  ));
1714  $db->delete(array( // Aus der Kinder-Tabelle löschen.
1715  'table' => $this->_site->pageTable.'_children',
1716  'where' => 'page_id='.$this->field['id'].' OR child='.$this->field['id']
1717  ));
1718  // Aus der Extra-Tabelle löschen.
1719  if ($db->tableExists($this->_site->pageTable.'_extra'))
1720  {
1721  $db->delete(array(
1722  'table' => $this->_site->pageTable.'_extra',
1723  'where' => 'page_id='.$this->field['id']
1724  ));
1725  }
1726  $db->commit();
1727 
1728  // Evtl. vorhandene Media Dateien löschen
1729  $this->destroyFile();
1730 
1731  // Evtl. vorhandenen Mediapool löschen
1732  $this->getMediapool()->clear('', [], false);
1733 
1734  // Alle URLs löschen
1735  $this->removeUrls();
1736 
1737  $this->message .= ' Eine Wiederherstellung ist nicht möglich.';
1738  }
1739 
1748  public function destroy($force=false, $recursive=true) {
1749  if ($this->isRoot()) {
1750  throw new Page_Exception("Can't destroy root page.", Page_Exception::ROOT_PROTECTION);
1751  }
1752  $this->archiveOnly = false;
1753  if (count(Ego_System::getCluster())>0) {
1754  $time = array();
1755  foreach (Ego_System::getCluster() as $cluster) {
1756  $log_filename = $GLOBALS['egotec_conf']['log_dir'].$GLOBALS['site']->name.'/live.'.$this->_site->name.'_'.$this->_site->language.'.'.$cluster['id'].'.up.date';
1757  if (file_exists($log_filename)) {
1758  $time[] = file_get_contents($log_filename);
1759  }
1760  }
1761 
1762  sort($time);
1763 
1764  if (count($time) > 0) {
1765  $live_date = $time[0];
1766  } else {
1767  $live_date = time();
1768  }
1769 
1770  } else {
1771  $live_date_file = $GLOBALS['egotec_conf']['log_dir'].$this->_site->name.'/'.'live.'.$this->_site->name.'_'.$this->_site->language.'.date';
1772 
1773  if(file_exists($live_date_file)) {
1774  $live_date = file_get_contents($live_date_file);
1775  } else {
1776  $live_date = time();
1777  }
1778  }
1779  if (
1780  !$force
1781  && (
1782  $GLOBALS['egotec_conf']['liveserver']
1783  || $this->field['c_date'] > $live_date
1784  || !$this->field['deleted']
1785  )
1786  ) {
1787  return $this->delete();
1788  }
1789 
1790  if (
1791  is_array($this->extra['language_link'])
1792  && $this->extra['language_standard'] == $this->_site->language
1793  ) {
1800  foreach($this->extra['language_link'] as $lang => $flag) {
1801  if ($flag && $lang != $this->_site->language) {
1802  try {
1803  $lang_page = $this->getLanguagePage($lang, array('deleted' => -1, 'auth_or' => '1=1'));
1804  if (is_object($lang_page)) {
1805  $lang_page->_destroyEntry($recursive);
1806  }
1807  } catch (Site_Exception $e) {
1808  // Eine nicht mehr vorhandene Sprache ignorieren
1809  }
1810  }
1811  }
1812  }
1813  $this->_destroyEntry($recursive);
1814  }
1815 
1823  function undelete($recursive = false, $query = array()) {
1824  $this->restore();
1825  $this->message = 'Diese Seite wurde erfolgreich wiederhergestellt.';
1826 
1827  if (
1828  ($this->extra['language_standard']==$this->_site->language
1829  || $this->_site->admin['multi_lang']['auto_link'])
1830  && is_array($this->extra['language_link'])
1831  ) {
1832  foreach($this->extra['language_link'] as $lang=>$flag) {
1833  if ($flag || $this->_site->admin['multi_lang']['auto_link']) {
1834  $lang_page = $this->getLanguagePage($lang, array('deleted' => -1));
1835  if (!is_object($lang_page)) {
1836  continue;
1837  }
1838  $lang_page->restore();
1839  if ($recursive) {
1840  $pages = $lang_page->getDescendants(array(), array(
1841  'deleted' => -1,
1842  'children_query' => $query
1843  ));
1844  foreach ($pages as $page)
1845  {
1846  $page->restore();
1847  }
1848  }
1849  }
1850  }
1851  }
1852 
1853  if ($recursive) {
1854  $pages = $this->getDescendants(array(), array(
1855  'deleted' => -1,
1856  'children_param' => array('deleted' => -1),
1857  'children_query' => $query
1858  ));
1859  if ($pages->numRecords()>0) {
1860  $this->message = 'Diese Seite wurde inklusive Unterseiten erfolgreich wiederhergestellt.';
1861  }
1862  foreach ($pages as $page) {
1863  $page->restore();
1864  }
1865  }
1866  }
1867 
1873  private function restore() {
1874  $inactive = $this->field['inactive'] == self::RELEASE_FLAG ?
1875  self::RELEASE_FLAG :
1876  self::INACTIVE_FLAG;
1877  if ($this->field['type'] == '_keywords/entry') {
1878  $inactive = self::ACTIVE_FLAG;
1879  }
1880  $field = array('inactive' => $inactive, 'deleted' => 0);
1881  if (!empty($this->field['url']) && !$this->isUniqueUrl($this->field['url'])) {
1882  // Beim Wiederherstellen wird die Meta URL gelöscht, wenn diese bereits verwendet wird
1883  $field['url'] = '';
1884  }
1885 
1886  // Ist die einzige Elternseite im Papierkorb oder existiert nicht, dann ist die Startseite die neue Elternseite
1887  $field['parents'] = $this->_site->rootId;
1888  foreach ($this->getParents(array(), array('deleted' => 0)) as $parent) {
1889  unset($field['parents']);
1890  break;
1891  }
1892 
1893  $this->updateField($field, false);
1894  }
1895 
1901  function unlinkFrom($remove_from) {
1902  $this->_removeParent($remove_from);
1903  if (!$this->field['deleted']) {
1904  // Prüfen ob noch weitere Parents vorhanden sind
1905  $parents = $this->getParents(array(), array('auth_or' => '1=1', 'sitemap' => true));
1906  if (!$parents->next()) {// Es sind keine Eltern mehr vorhanden.
1907  $this->delete();
1908  }
1909  }
1910  }
1911 
1919  protected function _updateField($field, $update=true, $asis=false) {
1920  if (!$asis && $field['url'] && $field['id'] && $this->field['url'] != $field['url']) {
1921  $query = array(
1922  'table' => $this->_site->name.'_'.$this->_site->language,
1923  'fields' => 'id, url',
1924  'where' => 'url=:url'.
1925  ' AND deleted=0'.
1926  ' AND id!=:id',
1927  'bind' => array(
1928  'url' => $field['url'],
1929  'id' => $field['id']
1930  )
1931  );
1932  if ($this->extra['original_id']) {
1933  $query['where'].= ' AND id!=:originalid';
1934  $query['bind']['originalid'] = $this->extra['original_id'];
1935  }
1936  $db = new_db_connection($query);
1937  if ($db->nextRecord()) {
1938  $this->message.= $GLOBALS['auth']->translate('Die URL konnte nicht gespeichert werden, weil sie schon vorhanden ist!') . '\n';
1939  $field['url'] = $this->field['url'];
1940  }
1941  }
1942 
1943  // Multimedia Kategorien, Dateien und Bilder dürfen diese Zeichen nicht beinhalten: \/:*?"<>|
1944  if (isset($field['name'])) {
1945  $field['name'] = strip_tags($field['name']);
1946  if (in_array((isset($field['type']) ? $field['type'] : $this->field['type']), array('multimedia/category', 'multimedia/file', 'multimedia/image'))) {
1947  $field['name'] = strtr($field['name'], '\/:*?"<>|', '_________');
1948  }
1949  }
1950 
1951  // Kein HTML für Titel und Kurzbeschreibung
1952  if ($this->_site->admin['editor']['plaintext']) {
1953  if (isset($field['title'])) {
1954  $field['title'] = strip_tags($field['title']);
1955  }
1956  if (isset($field['short']) && !$this->_site->admin['editor']['short'] && !$GLOBALS['egotec_conf']['editor']['short']) {
1957  $field['short'] = strip_tags($field['short']);
1958  }
1959  }
1960 
1961  // Der Seitentyp darf nicht leer sein
1962  if (isset($field['type']) && empty($field['type'])) {
1963  $field['type'] = !empty($this->field['type']) ? $this->field['type'] : 'page';
1964  }
1965 
1966  $this->_cleanEmptyContent($field);
1967 
1968  $this->field = array_merge($this->field, $field);
1969  if ($update)
1970  {
1971  $this->_changeEntry($field, $asis);
1972  }
1973  }
1974 
1981  protected function _updateKeywords($asis = false) {
1982  // Nur wenn es ein Schlagwortregister gibt
1983  if ($this->_site->admin['keyword_register_own_site']) {
1984  $keywords = $this->_site->getPages(['where' => "type = '_keywords/list'"])->nextPage();
1985  if ($keywords) {
1986  $abbreviations = $keywords->getDescendants([
1987  'where' => "type = '_keywords/entry'"
1988  ], [
1989  'extra' => 'extra.abbreviation = 1'
1990  ]);
1991 
1992  // Unterschiede bei den zugeordneten Abkürzungen erkennen
1993  $old_abbreviations = [];
1994  $new_abbreviations = [];
1995  $current_abbreviations = $this->getParents([
1996  'where' => "type = '_keywords/entry'"
1997  ], [
1998  'extra' => 'extra.abbreviation = 1'
1999  ]);
2000  foreach ($current_abbreviations as $current_abbreviation) {
2001  if ($current_abbreviation->extra['abbreviation']) {
2002  $old_abbreviations[] = $current_abbreviation->field['id'];
2003  }
2004  }
2005 
2006  foreach ($abbreviations as $abbreviation) {
2007  if (!$abbreviation->extra['abbreviation']) {
2008  continue;
2009  }
2010 
2011  // Zu suchende Wörter
2012  $words = [$abbreviation->field['name']];
2013 
2014  // Synonyme ebenfalls suchen
2015  if ($abbreviation->extra['synonym']) {
2016  require_once 'base/Ego_Combo.php';
2017  $combo = new Ego_Combo($abbreviation->extra['synonym']);
2018  foreach ($combo->getText() as $text) {
2019  $words[] = (string) $text;
2020  }
2021  }
2022 
2023  // Rekursiv nach den Begriffen suchen
2024  $search = function($value) use (&$search, $words) {
2025  if (is_array($value)) {
2026  foreach ($value as $v) {
2027  if ($search($v)) {
2028  return true;
2029  }
2030  }
2031  }
2032  return is_string($value)
2033  && preg_match('/>?[^<]*?\W*(' . implode('|', array_map(function($v) {
2034  return preg_quote($v, '/');
2035  }, $words)) . ')\W*[^>]*?<?/is', $value);
2036  };
2037 
2038  if (
2039  $search($this->field['name'])
2040  || $search($this->field['title'])
2041  || $search($this->field['short'])
2042  || $search($this->field['content'])
2043  || $search($this->field['extra'])
2044  ) {
2045  // Schlagwort hinzufügen
2046  if (!$this->hasParent($abbreviation->field['id'])) {
2047  $this->addParent($abbreviation->field['id'], $asis);
2048  }
2049  $new_abbreviations[] = $abbreviation->field['id'];
2050  } elseif ($this->hasParent($abbreviation->field['id'])) {
2051  // Schlagwort entfernen
2052  $this->delParent($abbreviation->field['id'], $asis);
2053  }
2054  }
2055 
2056  $diff1 = array_diff($old_abbreviations, $new_abbreviations);
2057  $diff2 = array_diff($new_abbreviations, $old_abbreviations);
2058  return !empty($diff1) || !empty($diff2);
2059  }
2060  }
2061  return false;
2062  }
2063 
2069  protected function _updateChildren($children) {
2070  // Unterseiten beibehalten die nicht übergeben wurden, um verlorene Seiten zu vermeiden
2071  $db = new_db_connection(array(
2072  'table' => $this->_site->pageTable . '_children',
2073  'where' => 'page_id = :page_id',
2074  'bind' => array(
2075  'page_id' => $this->field['id']
2076  ),
2077  'order' => 'idx ASC'
2078  ));
2079  while ($db->nextRecord()) {
2080  if (!in_array($db->Record['child'], $children)) {
2081  array_splice($children, (int) $db->Record['idx'], 0, $db->Record['child']);
2082  }
2083  }
2084 
2085  $ancestors_iterator = $this->getAncestors(
2086  array('fields' => 'id'),
2087  array('auth_or' => '1=1', 'children_param' => array('auth_or' => '1=1'))
2088  );
2089  $ancestors = array();
2090  foreach ($ancestors_iterator as $ancestor_page)
2091  {
2092  $ancestors[] = $ancestor_page->field['id'];
2093  }
2094  $ancestors[] = $this->field['id'];
2095 
2096  $db = new_db_connection();
2097  $db->begin();
2098  $table = $this->_site->pageTable;
2099  $db->delete(array( // Alte Einträge löschen.
2100  'table' => $table.'_children',
2101  'where' => 'page_id='.$this->field['id']
2102  ));
2103  $children = array_unique($children); // Keine Seite mehrmals derselben Seite unterordnen.
2104  $idx = 0;
2105  foreach ($children as $child) {
2106  if ($child) { // Keine leeren Einträge.
2107  if (in_array($child, $ancestors)) { // Keine Endlosschleifen.
2108  egotec_error_log('infinite loop prevention at children: '.$this->_site->pageTable.' '.$this->field['id'].','.$child);
2109  } else {
2110  $db->insert(array(
2111  'table' => $table.'_children',
2112  'set' => array('page_id' => $this->field['id'], 'idx' => $idx, 'child' => $child)
2113  ));
2114  $idx++;
2115  }
2116  }
2117  }
2118  $db->commit();
2119  $this->_clearCache();
2120  }
2121 
2127  protected function _updateParents($parents) {
2128  if (empty($parents)) {
2129  egotec_error_log('empty parents: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id']);
2130  return;
2131  }
2132  $current_parents = array();
2133  $db = new_db_connection(array(
2134  'table' => $this->_site->pageTable . '_children',
2135  'where' => 'child = :child',
2136  'bind' => array(
2137  'child' => $this->field['id']
2138  )
2139  ));
2140  while ($db->nextRecord()) {
2141  $current_parents[] = $db->Record['page_id'];
2142  }
2143  $num_parents = 0;
2144  $remove_parents = array();
2145  foreach ($current_parents as $current_parent) {
2146  $key = array_search($current_parent, $parents);
2147  if ($key!==false) { // Vorhandene Eltern in Ruhe lassen.
2148  unset($parents[$key]);
2149  $num_parents++;
2150  } else { // Nicht mehr vorhandene Eltern löschen.
2151  $remove_parents[] = $current_parent;
2152  }
2153  }
2154  foreach ($parents as $parent_id) { // Neue Eltern hinzufügen.
2155  if ($parent_id) {
2156  if ($parent_id!=$this->field['id']) {// Keine Endlosschleife erzeugen!
2157  $this->_addParent($parent_id);
2158  $num_parents++;
2159  } else {
2160  egotec_error_log('infinite loop prevention at parents: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id'].','.$parent_id);
2161  }
2162  }
2163  }
2164  if ($num_parents == 0) {
2165  egotec_error_log('empty parents 2: '.print_r($parents, true).' / '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id']);
2166  return;
2167  } else {
2168  // Eltern erst löschen, wenn es noch mindestens eine Elternseite gibt
2169  foreach ($remove_parents as $remove_parent) {
2170  $this->_removeParent($remove_parent);
2171  }
2172  }
2173  }
2174 
2180  private function _removeParent($parent_id) {
2181  $db = new_db_connection();
2182  $db->delete(array(
2183  'table' => $this->_site->pageTable.'_children',
2184  'where' => 'page_id = '.$parent_id.' AND child = '.$this->field['id']
2185  ));
2186  $this->_site->clearCache();
2187 
2188  // Elternseite existiert als Klon und Unterseiten sollen ebenfalls geklont werden
2189  $parent = $this->_site->getPage($parent_id);
2190  if ($parent && $parent->extra['clones'] && !$this->isReleaseCopy() && !$this->isWorkflowCopy()) {
2191  $clones = explode(',', $parent->extra['clones']);
2192  foreach ($clones as $clone_url) {
2193  $parent_clone = Ego_System::urltopage(
2194  $clone_url,
2195  array(
2196  'params' => array(
2197  'param' => array(
2198  'auth_or' => '1=1',
2199  'deleted_or' => '1=1',
2200  'inactive' => true,
2201  'only_active' => false
2202  )
2203  )
2204  )
2205  );
2206 
2207  // Prüfen ob Unterseiten geklont werden sollen
2208  if ($parent_clone && $parent->extra['clone_children_' . $clone_url]) {
2209  foreach ($parent_clone->getChildren(array(), array(
2210  'auth_or' => '1=1',
2211  'deleted_or' => '1=1',
2212  'inactive' => true,
2213  'only_active' => false
2214  )) as $clone) {
2215  if (in_array($clone->getCloneUrl(), explode(',', $this->extra['clones']))) {
2216  $clone->destroyClone();
2217  }
2218  }
2219  }
2220  }
2221  }
2222  }
2223 
2229  private function _addParent($parent_id) {
2230  if ($this->field['id']==$parent_id) { // Eine Endlosschleife vermeiden.
2231  egotec_error_log('infinite loop prevention: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id'].','.$parent_id);
2232  return false;
2233  }
2234  $parent = $this->_site->getPage($parent_id, array(
2235  'inactive' => true,
2236  'only_active' => false
2237  ));
2238  if (!$parent) {
2239  return false;
2240  }
2241  $ancestors = $this->_getAncestorsIds(
2242  $parent,
2243  array('fields' => 'id'),
2244  array('auth_or' => '1=1')
2245  );
2246  if (in_array($this->field['id'], $ancestors)) { // Eine Endlosschleife vermeiden.
2247  return false;
2248  }
2249  if ($this->hasParent($parent_id)) { // Keine Seite mehrmals derselben Seite unterordnen.
2250  egotec_error_log('infinite loop prevention: '.$this->_site->pageTable.$this->getTableSuffix().' '.$this->field['id'].','.$parent_id);
2251  return false;
2252  }
2253  $db = new_db_connection();
2254  $db->select(array( // höchsten Index der Kinder abfragen.
2255  'fields'=> 'idx',
2256  'table' => $this->_site->pageTable.'_children',
2257  'where' => "page_id=".$parent_id,
2258  'order' => 'idx DESC',
2259  'limit' => 1
2260  ));
2261  $idx = $db->nextRecord()?$db->Record['idx']+1:0;
2262  $db->replace(array(
2263  'table' => $this->_site->pageTable.'_children',
2264  'set' => array('page_id' => $parent_id, 'idx' => $idx, 'child' => $this->field['id']),
2265  'primary' => array('page_id', 'idx')
2266  ));
2267 
2268  // Elternseite existiert als Klon und Unterseiten sollen ebenfalls geklont werden
2269  if ($parent && $parent->extra['clones'] && !$this->isReleaseCopy() && !$this->isWorkflowCopy()) {
2270  $clones = explode(',', $parent->extra['clones']);
2271  foreach ($clones as $clone_url) {
2272  $clone = Ego_System::urltopage(
2273  $clone_url,
2274  array(
2275  'params' => array(
2276  'param' => array(
2277  'auth_or' => '1=1',
2278  'deleted_or' => '1=1',
2279  'inactive' => true,
2280  'only_active' => false
2281  )
2282  )
2283  )
2284  );
2285 
2286  // Prüfen ob Unterseiten geklont werden sollen
2287  if ($clone && $parent->extra['clone_children_' . $clone_url]) {
2288  $clone->createClone($this);
2289  }
2290  }
2291  }
2292  return true;
2293  }
2294 
2301  private function _clearCache($complete = false) {
2302  $this->_site->clearCache(!$complete && $this->field['type'] == 'multimedia/image' ? $this->field['id'] : 0);
2303 
2304  // Die Cache aller verweisenden Seiten anderer Mandanten ebenfalls löschen
2305  $cleared = array();
2306  foreach ($this->getLinkedPages() as $link) {
2307  foreach ($link['sources'] as $site_name => $source) {
2308  if ($site_name != $this->_site->name && !in_array($site_name, $cleared)) {
2309  $cleared[] = $site_name;
2310  try {
2311  $site = new Site($site_name);
2312  Ego_Queue::add(array($site, 'clearCache'));
2313  } catch (Site_Exception $e) {
2314  // ignorieren
2315  }
2316  }
2317  }
2318  }
2319  }
2320 
2330  protected function _updateClones(&$param) {
2331  if ($this->isReleaseCopy() || $this->isWorkflowCopy()) {
2332  return;
2333  }
2334  if ($param['extra']['clones'] || $this->extra['clones']) { // wenn ich Klone hab oder hatte
2335  $this_page_url = $this->getCloneUrl();
2336 
2337  if (isset($param['extra'])) {
2338  $folders = explode(',', $param['extra']['clones']);
2339  $param['extra']['clones'] = '';
2340  $old_clones = array_filter(array_unique(explode(',', $this->extra['clones'])));
2341 
2342  // wenn welche aus der liste entfernt wurden, löschen
2343  foreach ($old_clones as $old_c) {
2344  if ($old_c == '') continue;
2345 
2346  if (!in_array($old_c, $folders)) {
2347  $clone = Ego_System::urltopage($old_c, array('params' => array('param' => array(
2348  'auth_or' => '1=1',
2349  'deleted_or' => '1=1',
2350  'inactive' => true,
2351  'only_active' => false
2352  ))));
2353  if ($clone) {
2354  // Klon entfernen
2355  $clone->delete();
2356  }
2357  unset($param['extra']['clone_children_' . $old_c], $param['extra']['clone_release_' . $old_c]);
2358  }
2359  }
2360  } elseif (isset($this->extra['clones'])) {
2361  // Wenn extra nicht übergeben wird, dann mit dem aktuellen extra weitermachen
2362  $folders = array_filter(array_unique(explode(',', $this->extra['clones'])));
2363  } else {
2364  return;
2365  }
2366 
2367  // Sicherstellen, dass immer alle Daten vorhanden sind
2368  $param['field'] = $param['field'] ? $param['field'] : $this->field;
2369  $param['extra'] = $param['extra'] ? $param['extra'] : $this->extra;
2370 
2371  // Aktualisieren
2372  foreach ($folders as $f) {
2373  if (!$f) continue; // Leere überspringen
2374  $remove_parent = false;
2375 
2376  // Eltern holen
2377  $f_url = $f;
2378  $clone = Ego_System::urltopage($f, array('params' => array('param' => array(
2379  'auth_or' => '1=1',
2380  'deleted_or' => '1=1',
2381  'inactive' => true,
2382  'only_active' => false
2383  ))));
2384 
2385  if (!$clone) {
2386  // Wenn der Klon nicht existiert, wird er dennoch beibehalten
2387  $clones = array_filter(explode(',', $param['extra']['clones']));
2388  $param['extra']['clones'] = implode(',', array_unique(array_merge($clones, array($f))));
2389  continue;
2390  }
2391 
2392  $p = array(
2393  'field' => $param['field'],
2394  'extra' => $param['extra']
2395  );
2396  $p['extra']['clone_original'] = $this_page_url;
2397  unset($p['field']['id']);
2398  unset($p['field']['parents']);
2399  unset($p['field']['url']);
2400  unset($p['extra']['clones']);
2401 
2402  foreach ($p['extra'] as $key => $value) {
2403  if (
2404  strpos($key, 'clone_children_') === 0
2405  || strpos($key, 'clone_release_') === 0
2406  ) {
2407  unset($p['extra'][$key]);
2408  }
2409  }
2410 
2411  if ($clone->isClone()) {
2412  if (isset($clone->conf['edit_clone'])) {
2413  // Nicht die Felder ändern, die bereits existieren und einen anderen Wert als den ursprünglichen haben
2414  $combined_p = array();
2415  foreach ($p as $field => $values) {
2416  $combined_p[$field] = $values;
2417  if (is_array($values) && isset($clone->conf['edit_clone'][$field])) {
2418  $clone_edit = explode(',', $clone->conf['edit_clone'][$field]);
2419  foreach ($clone_edit as $edit_key) {
2420  $value = Ego_System::getAssocValue($this->{$field}, $edit_key);
2421  if (
2422  ($clone_value = Ego_System::getAssocValue($clone->{$field}, $edit_key)) !== null
2423  && $clone_value != $value
2424  ) {
2425  // Wert beibehalten
2426  $value = $clone_value;
2427  }
2428  Ego_System::setAssocValue($combined_p[$field], $edit_key, $value);
2429  }
2430  }
2431  }
2432  } else {
2433  // Alle Felder ändern
2434  $combined_p = $p;
2435  }
2436 
2437  // Bei Freigabeklonen wird Freigabe ab und bis nicht mit denen vom Original überschrieben
2438  $clone_page_url = $clone->getCloneUrl();
2439  if ($param['extra']['clone_release_' . $clone_page_url]) {
2440  unset($combined_p['field']['release_from'], $combined_p['field']['release_until']);
2441  }
2442 
2443  $clone->update($combined_p);
2444  } else { // es muss ein Klon erzeugt werden
2445  unset($p['field']['release_from'], $p['field']['release_until']);
2446 
2447  $clone = $clone->newChild($p['field'], $p['extra']);
2448  if (!$clone) {
2449  continue;
2450  }
2451  $remove_parent = true;
2452  }
2453 
2454  // Mediapool kopieren
2455  $this->getMediapool()->copy($clone);
2456 
2457  // Klon merken
2458  $clone_page_url = $clone->getCloneUrl();
2459  $clones = array_filter(explode(',', $param['extra']['clones']));
2460  $param['extra']['clones'] = implode(',', array_unique(array_merge($clones, array($clone_page_url))));
2461 
2462  /* Übergebene Informationen verweisen auf die Elternseite des neuen Klons,
2463  * diese verwerfen
2464  */
2465  if ($remove_parent)
2466  {
2467  $param['extra']['clone_children_' . $clone_page_url] = $param['extra']['clone_children_' . $f_url];
2468  $param['extra']['clone_release_' . $clone_page_url] = $param['extra']['clone_release_' . $f_url];
2469 
2470  unset($param['extra']['clone_children_' . $f_url], $param['extra']['clone_release_' . $f_url]);
2471 
2472  // Eingetragene Freigabe ab/bis Daten ändern
2473  if ($param['extra']['clone_release_' . $clone_page_url]) {
2474  $param['extra']['clone_release_from_' . $clone_page_url] = $param['extra']['clone_release_from_' . $f_url];
2475  $param['extra']['clone_release_until_' . $clone_page_url] = $param['extra']['clone_release_until_' . $f_url];
2476 
2477  unset($param['extra']['clone_release_from_' . $f_url], $param['extra']['clone_release_until_' . $f_url]);
2478  }
2479  }
2480 
2481  // Die eingetragenen Freigabe ab/bis Daten verwenden
2482  if ($param['extra']['clone_release_'.$clone_page_url]) {
2483  $clone_release = array();
2484 
2485  if ($param['extra']['clone_release_from_' . $clone_page_url]) {
2486  $clone_release['release_from'] = $param['extra']['clone_release_from_' . $clone_page_url];
2487  } else {
2488  $clone_release['release_from'] = '0000-00-00 00:00:00';
2489  }
2490 
2491  if ($param['extra']['clone_release_until_' . $clone_page_url]) {
2492  $clone_release['release_until'] = $param['extra']['clone_release_until_' . $clone_page_url];
2493  } else {
2494  $clone_release['release_until'] = '0000-00-00 00:00:00';
2495  }
2496 
2497  if (!empty($clone_release)) {
2498  $clone->updateField($clone_release);
2499  }
2500  }
2501 
2502  // Informationen zu Freigabe ab/bis des Klons nicht merken
2503  unset(
2504  $param['extra']['clone_release_from_' . $clone_page_url],
2505  $param['extra']['clone_release_until_' . $clone_page_url]
2506  );
2507 
2508  // Prüfen ob an Klonen mit Unterseiten etwas geändert worden ist
2509  if ($param['extra']['clone_children_'.$clone_page_url] != $this->extra['clone_children_'.$clone_page_url])
2510  {
2511  if ($param['extra']['clone_children_'.$clone_page_url] == 1)
2512  {
2513  // Klon Kinder für diesen Klon erstellen
2514  $this->_createChildClones($clone);
2515  }
2516  else
2517  {
2518  // Klon Kinder dieses Klons entfernen
2519  $this->_destroyChildClones($clone);
2520  }
2521  }
2522  }
2523  } elseif ($this->isClone()) {
2524  // Ist diese Seite ein Klon und funktioniert als Verknüpfung, dann das Original auch speichern
2525  $type_info = $this->getTypeInfo();
2526  if (
2527  $type_info['clone_link']
2528  && ($page = Ego_System::urltopage($this->extra['clone_original'], array('params' => array('param' => array(
2529  'auth_or' => '1=1',
2530  'deleted_or' => '1=1',
2531  'inactive' => true,
2532  'only_active' => false
2533  )))))
2534  ) {
2535  $p = array(
2536  'field' => $param['field'],
2537  'extra' => $param['extra']
2538  );
2539  $p['extra']['clones'] = $page->extra['clones'];
2540  foreach ($page->extra as $key => $value) {
2541  if (
2542  strpos($key, 'clone_children_') === 0
2543  || strpos($key, 'clone_release_') === 0
2544  ) {
2545  $p['extra'][$key] = $value;
2546  }
2547  }
2548  unset($p['field']['id']);
2549  unset($p['field']['parents']);
2550  unset($p['field']['url']);
2551  unset($p['extra']['clone_original']);
2552  $page->update($p);
2553 
2554  // Mediapool kopieren
2555  $this->getMediapool()->copy($page);
2556  }
2557  }
2558  }
2559 
2565  public function getClones() {
2566  $clones = [];
2567  $clone_array = array_filter(array_unique(explode(',', $this->extra['clones'])));
2568  foreach ($clone_array as $clone_index) {
2569  if ($clone_index == '') continue;
2570  $clone = Ego_System::urltopage($clone_index, array('params' => array('param' => array(
2571  'auth_or' => '1=1',
2572  'deleted_or' => '1=1',
2573  'inactive' => true,
2574  'only_active' => false
2575  ))));
2576  if ($clone) {
2577  $clones[] = $clone;
2578  }
2579  }
2580  return $clones;
2581  }
2582 
2593  public function createClone($page, $children = false, $release = false, $multiple = true) {
2594  $_REQUEST['var']['reload_dlg'] = true; // Wird die Methode in einem Action Hook aufgerufen, muss das dlg neu geladen werden
2595  return $this->_createClone($page, $children, $release, $multiple);
2596  }
2597 
2607  protected function _createClone($page, $children = false, $release = false, $multiple = true) {
2608  $clone_url = $page->getCloneUrl();
2609 
2610  if (!$multiple) {
2611  // Prüfen, ob es diesen Klon bereits gibt
2612  $children2 = $this->getChildren(array(), array(
2613  'auth_or' => '1=1',
2614  'inactive' => true,
2615  'only_active' => false
2616  ));
2617  foreach ($children2 as $child) {
2618  if ($child->extra['clone_original'] == $clone_url) {
2619  return $child;
2620  }
2621  }
2622  }
2623 
2624  // Neuen Klon erstellen
2625  $p = array(
2626  'field' => $page->field,
2627  'extra' => $page->extra
2628  );
2629  $p['extra']['clone_original'] = $clone_url;
2630  unset($p['field']['id']);
2631  unset($p['field']['parents']);
2632  unset($p['field']['url']);
2633  unset($p['extra']['clones']);
2634 
2635  $clone = $this->newChild($p['field'], $p['extra']);
2636 
2637  // Neuen Klon auf dieser Seite eintragen
2638  $extra = $page->extra;
2639 
2640  $clones = array_filter(explode(',', $extra['clones']));
2641  $clone_page_url = $clone->getCloneUrl();
2642 
2643  $extra['clones'] = implode(',', array_unique(array_merge($clones, array($clone_page_url))));
2644  if ($children) {
2645  $extra['clone_children_' . $clone_page_url] = 1;
2646  }
2647  if ($release) {
2648  $extra['clone_release_' . $clone_page_url] = 1;
2649  }
2650  $page->updateExtra($extra);
2651 
2652  return $clone;
2653  }
2654 
2660  protected function _createChildClones($parent) {
2661  // Kinder dieser Seite
2662  $children = $this->getChildren(
2663  array(),
2664  array(
2665  'inactive' => true
2666  )
2667  );
2668 
2669  foreach($children as $child) {
2670  // Klon nur anlegen falls es noch nicht existiert
2671  $clone_child = $parent->getChildren(
2672  array(
2673  'where' => 'name=:n AND a_date=:a',
2674  'bind' => array(
2675  'n' => $child->field['name'],
2676  'a' => $child->field['a_date']
2677  )
2678  ),
2679  array(
2680  'inactive' => true
2681  )
2682  );
2683 
2684  if (!$clone_child->numRecords()) {
2685  $parent->createClone($child, true);
2686  }
2687  }
2688  }
2689 
2695  protected function _destroyChildClones($parent) {
2696  // Kinder dieser Seite
2697  $children = $this->getChildren(
2698  array(),
2699  array(
2700  'inactive' => true
2701  )
2702  );
2703 
2704  foreach($children as $child) {
2705  // Klon nur entfernen falls es existiert
2706  $clone_child = $parent->getChildren(
2707  array(
2708  'where' => 'name=:n AND a_date=:a',
2709  'bind' => array(
2710  'n' => $child->field['name'],
2711  'a' => $child->field['a_date']
2712  )
2713  ),
2714  array(
2715  'inactive' => true
2716  )
2717  );
2718 
2719  if ($clone = $clone_child->nextPage()) { // Klon entfernen
2720  $clone->destroyClone();
2721  }
2722  }
2723  }
2724 
2730  public function destroyClone() {
2731  $_REQUEST['var']['reload_dlg'] = true; // Wird die Methode in einem Action Hook aufgerufen, muss das dlg neu geladen werden
2732  return $this->_destroyClone();
2733  }
2734 
2740  protected function _destroyClone() {
2741  $page = $this->getCloneOriginal();
2742  if (!$page) {
2743  return false;
2744  }
2745  $extra = $page->extra;
2746  $clones = explode(',', $extra['clones']);
2747  $clone_page_url = $this->getCloneUrl();
2748  if (!in_array($clone_page_url, $clones)) {
2749  return false;
2750  }
2751 
2752  $new_clones = array();
2753  foreach($clones as $c) {
2754  if ($c != $clone_page_url) {
2755  $new_clones[] = $c;
2756  }
2757  }
2758 
2759  $extra['clones'] = implode(',', array_filter(array_unique($new_clones)));
2760  unset($extra['clone_children_' . $clone_page_url], $extra['clone_release_' . $clone_page_url]);
2761 
2762  $page->updateExtra($extra);
2763  $this->delete();
2764 
2765  return true;
2766  }
2767 
2776  protected function _updateRights($rights) {
2777  $db = new_db_connection();
2778  if ($rights['_delete']) {
2779  $delete_query_where = ' AND perm in (\''.join('\',\'', $rights['_delete']).'\')';
2780  unset($rights['_delete']);
2781  }
2782  $rights['rights'] = array_merge($this->getRightsArray(),$rights['rights']);
2783  if ($rights['rights']) { // Gruppen und Rollen.
2784  $db->delete(array( // Alte Einträge löschen.
2785  'from' => $this->_site->pageTable.'_rights',
2786  'where' => 'page_id='.$this->field['id'].$delete_query_where
2787  ));
2788  foreach ($rights['rights'] as $right => $groups) {
2789  $is_null = true; // Zunächst von keiner Beschränkung ausgehen.
2790  foreach ($groups as $group) {
2791  if (!$group['group_id'] || !$group['role_id']) {
2792  if ($rights['users'] && $rights['users'][$right] && count($rights['users'][$right]) != 0) {
2793  // es sind user vorhanden aber keine Group/Role Kombination
2794  $group['group_id'] = $GLOBALS['egotec_conf']['superuser']['group'];
2795  $group['role_id'] = $GLOBALS['egotec_conf']['superuser']['role'];
2796  }
2797  }
2798 
2799  if ($group['group_id'] && $group['role_id']) { // Keine leeren Einträge setzen.
2800  $db->replace(array(
2801  'table' => $this->_site->pageTable.'_rights',
2802  'set' => array(
2803  'page_id' => $this->field['id'],
2804  'perm' => $right,
2805  'group_id' => $group['group_id'],
2806  'role_id' => $group['role_id']
2807  ),
2808  'primary' => array('page_id', 'perm', 'group_id', 'role_id')
2809  ));
2810  $is_null = false; // Es wurde eine Beschränkung gesetzt.
2811  }
2812  }
2813  if ($is_null && strpos(Auth::NO_NULL_RIGHTS, ','.$right.',')!==false) { // Bei einem Recht, das nicht per IS NULL abgefragt wird
2814  $db->replace(array(
2815  'table' => $this->_site->pageTable.'_rights',
2816  'set' => array(
2817  'page_id' => $this->field['id'],
2818  'perm' => $right,
2819  'group_id' => '*', // *|* setzen.
2820  'role_id' => '*'
2821  ),
2822  'primary' => array('page_id', 'perm', 'group_id', 'role_id')
2823  ));
2824  }
2825  }
2826  }
2827 
2828  if ($rights['users']) {
2829  // Benutzer.
2830  $db->delete(array( // Alte Einträge löschen.
2831  'from' => $this->_site->pageTable.'_users',
2832  'where' => "page_id=".$this->field['id'].$delete_query_where
2833  ));
2834  foreach ($rights['users'] as $right => $users) {
2835  if (is_array($users)) {
2836  foreach ($users as $user) {
2837  if ($user['user_id']) { // Leere Einträge vermeiden
2838  $db->insert(array(
2839  'table' => $this->_site->pageTable.'_users',
2840  'set' => array(
2841  'page_id' => $this->field['id'],
2842  'perm' => $right,
2843  'user_id' => trim($user['user_id'],"'"),
2844  )
2845  ));
2846  }
2847  }
2848  }
2849  }
2850  }
2851 
2852  // Multimedia Bilder vererben das Ansichtsrecht an alle Bildausschnitte
2853  if ($this->field['type'] == 'multimedia/image') {
2854  $children = $this->getChildren(array(
2855  'where' => "type = 'multimedia/image'"
2856  ), array(
2857  'auth_or' => '1=1',
2858  'inactive' => true,
2859  'only_active' => false
2860  ));
2861  foreach ($children as $child) {
2862  if ($child->extra['crop_image']) {
2863  $child->update(array(
2864  'rights' => array(
2865  'rights' => array(
2866  'view' => $rights['rights']['view'] ? $rights['rights']['view'] : array()
2867  ),
2868  'users' => array(
2869  'view' => $rights['users']['view'] ? $rights['users']['view'] : array()
2870  )
2871  )
2872  ));
2873  }
2874  }
2875  }
2876 
2877  if (!isset($this->field['inactive']) || !$this->field['inactive']) {
2878  $this->_clearCache();
2879  }
2880  }
2881 
2893  protected function _update($param, $matrix_flag = true, $asis = false) {
2894  if (!$asis) { // @TODO Ist das notwendig?
2895  $this->_updateClones($param);
2896  }
2897  $language_standard = $this->extra['language_standard'];
2898 
2899  if (isset($param['extra']) && $param['field'] && (int)$param['extra']['original_id']) { // Workflowkopien sind immer inaktiv;
2900  $param['field']['inactive'] = $this->isReleaseCopy() ? self::RELEASE_FLAG : self::INACTIVE_FLAG;
2901  }
2902  if (isset($param['extra'])) {
2903  $new_extra = array();
2904  if (is_array($param['extra'])) {
2925  $cleanup = function($value) use (&$cleanup) {
2926  if (is_array($value)) {
2927  $new_value = [];
2928  $numeric_keys = true;
2929  foreach ($value as $k => $v) {
2930  $v = $cleanup($v);
2931  if (in_array($k, ['', 'undefined'], true) || empty($v)) {
2932  continue;
2933  }
2934  $new_value[$k] = $v;
2935  if (!is_numeric($k)) {
2936  $numeric_keys = false;
2937  }
2938  }
2939  if ($numeric_keys) {
2940  // Sicherstellen, dass bei numerischen Schlüsseln immer aufsteigend sortiert ist
2941  ksort($new_value);
2942  }
2943  $value = $new_value;
2944  } elseif (is_string($value)) {
2945  if (preg_match('/^[1-9]+[0-9]*$/', $value)) {
2946  // Nur Ganzzahlen umwandeln; ansonsten können Werte wie 6.350 in 6,35 umgewandelt werden
2947  // Auch nicht für Ganzzahlen, die mit einer 0 beginnen
2948  $value = $value + 0;
2949  } elseif (in_array($value, ['true', 'false'], true)) {
2950  $value = $value == 'true';
2951  } elseif (in_array($value, ['null', 'undefined'], true)) {
2952  $value = null;
2953  }
2954  }
2955  return $value;
2956  };
2957 
2958  $new_extra = $cleanup($param['extra']);
2959  }
2960 
2961  // Vererbte Blöcke nicht speichern
2962  if (!empty($new_extra['_inherited'])) {
2963  $blocks = $new_extra['_blocks'];
2964  $contents = $new_extra['_contents'];
2965  foreach ($new_extra['_inherited'] as $orient => $checksum) {
2966  if ($blocks[$orient] && $contents[$orient]) {
2967  $checksum_blocks = Ego_System::getChecksum($blocks[$orient]);
2968  $checksum_contents = Ego_System::getChecksum($contents[$orient]);
2969  if ($checksum_blocks == $checksum['blocks'] && $checksum_contents == $checksum['contents']) {
2970  unset($new_extra['_blocks'][$orient], $new_extra['_contents'][$orient]);
2971  }
2972  }
2973  }
2974  }
2975 
2976  unset($new_extra['_asis'], $new_extra['_inherited']);
2977  $param['extra'] = $new_extra;
2978  }
2979  if ($param['field'] || $param['extra']) {
2980  // Der Seitentyp wird gewechselt
2981  if (
2982  !empty($param['field']['type'])
2983  && $param['field']['type'] != $this->field['type']
2984  && $this->isFrontendAdmin()
2985  ) {
2986  $this->field['type'] = $param['field']['type'];
2987  $this->_loadConfig();
2988  if (!empty($this->conf['default_layout'])) {
2989  // Das Standard Layout des neuen Seitentyps verwenden
2990  $param['extra'] = isset($param['extra'])
2991  ? $param['extra']
2992  : $this->extra;
2993  $param['extra']['_layout'] = $this->conf['default_layout'];
2994  }
2995  }
2996 
2997  if ($param['field']['children']) {
2998  if (!isset($param['children'])) {
2999  $param['children'] = explode(',', trim($param['field']['children'], ','));
3000  }
3001  unset($param['field']['children']);
3002  }
3003  if ($param['field']['parents']) {
3004  if (!isset($param['parents'])) {
3005  $param['parents'] = explode(',', trim($param['field']['parents'], ','));
3006  }
3007  unset($param['field']['parents']);
3008  }
3009 
3010  if (isset($param['extra'])) {
3011  $param['field']['extra'] = serialize($param['extra']);
3012  }
3013 
3014  $this->_updateField($param['field'], true, $asis);
3015  }
3016  if ($param['children']) {
3017  $this->_updateChildren($param['children']);
3018  }
3019  if ($param['parents'] && $this->field['id'] != $this->_site->rootId) {
3020  $this->_updateParents($param['parents']);
3021  }
3022 
3023  if ($param['rights']) {
3024  $this->_updateRights($param['rights']);
3025  }
3026 
3027  // Schlagwörter automatisch hinzufügen
3028  $reload = $this->_updateKeywords($asis);
3029 
3030  // Mediapool Aktionen ausführen
3031  if ($param['pool']) {
3032  // Dateien umbenennen
3033  if (is_array($param['pool']['rename'])) {
3034  foreach ($param['pool']['rename'] as $info) {
3035  if ($info['name'] != $info['new_name']) {
3036  $this->getMediapool()->edit($info['name'], array(
3037  'new_name' => $info['new_name']
3038  ), (string) $info['dir']);
3039  }
3040  }
3041  }
3042  }
3043 
3044  if (
3045  !$this->isClone()
3046  && !$this->extra['crop_image'] // Ausschnitte legen keine Archive oder Sprachen an
3047  && (!$asis || $this->isPublicSave())
3048  ) {
3049  // Archiv anlegen
3050  $this->_archiveEntry($asis);
3051 
3052  // Die Inhalte der Standardsprache in die verknüpften Bereiche speichern.
3053  if (
3054  !$this->archiveOnly // Nicht für Zwischenspeicherungen
3055  && !$this->isWorkflowCopy()
3056  && $matrix_flag
3057  && $language_standard == $this->_site->language
3058  && is_array($param['extra']['language_link'])
3059  ) {
3066  $clean_clones = function($extra) {
3067  unset($extra['clones']);
3068  foreach (array_keys($extra) as $key) {
3069  if (strpos($key, 'clone_') === 0) {
3070  unset($extra[$key]);
3071  }
3072  }
3073  return $extra;
3074  };
3075 
3076  $languages = array();
3077  $site_languages = $this->_site->getLanguages();
3078  foreach ($param['extra']['language_link'] as $lang=>$flag) {
3079  // #173630: Nur wenn es die Sprache auch noch gibt
3080  if (in_array($lang, $site_languages)) {
3081  $matrix_page = $this->getLanguagePage($lang, array(
3082  'deleted' => -1,
3083  'inactive' => 1,
3084  'only_active' => false,
3085  'auth_or' => '1=1'
3086  ));
3087 
3088  if ($flag && $lang!=$this->_site->language) {
3089  if ($matrix_page) {
3090  $param['extra'] = $clean_clones(array_merge($this->extra, $param['extra']));
3091  if (!isset($param['rights'])) {
3092  $param['rights'] = [
3093  'rights' => $this->getRightsArray(),
3094  'users' => $this->getUsersArray()
3095  ];
3096  }
3097  $matrix_page->update($param, false, $asis);
3098  $this->getMediapool()->copy($matrix_page); // Mediapool kopieren
3099 
3100  // Wenn bereits eine Sprachkopie existiert und darauß eine Sprachverknpüfung wird, dann alle Multimedia Dateien löschen
3101  if ($this->_site->site['type'] == 'media') {
3102  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media' . DIRECTORY_SEPARATOR . $this->_site->name;
3103  $source = $media_dir . DIRECTORY_SEPARATOR . $matrix_page->getMediaFilename();
3104 
3105  foreach (glob($source . '*') as $media_file) {
3106  @unlink($media_file);
3107  }
3108  }
3109  } elseif (!$this->isReleaseCopy()) { // Wenn die Seite noch nicht in dieser Sprache vorhanden ist, dann wird diese erzeugt (außer für Freigabekopien).
3110  $matrix_parent = $this->getParents(array(), array('auth_or' => '1=1'));
3111  if ($matrix_parent) {
3112  $matrix_parent = $matrix_parent->nextPage(); /* @var $matrix_parent Page */
3113  if ($matrix_parent) {
3114  $matrix_parent = $matrix_parent->getLanguagePage($lang, array(
3115  'inactive' => 1,
3116  'only_active' => false,
3117  'deleted_or' => '1=1'
3118  ));
3119  if ($matrix_parent)
3120  {
3121  if ($matrix_parent->field['deleted']) {
3122  // Elternseite wiederherstellen
3123  $matrix_parent->undelete();
3124  }
3125  if ($matrix_page = $matrix_parent->newChild($this->field, $clean_clones($this->extra))) {
3126  $this->getMediapool()->copy($matrix_page); // Mediapool kopieren
3127  }
3128  }
3129  }
3130  }
3131  }
3132  $languages[] = $lang;
3133  }
3134  elseif ($lang!=$this->_site->language) {
3135  // #204196: Nur wenn diese Sprache keine Sprachverknüpfung ist
3136  if ($matrix_page) {
3137  if (
3138  !Ego_System::isEqual($matrix_page->extra['language_link'], $param['extra']['language_link'])
3139  || !Ego_System::isEqual($matrix_page->extra['language_standard'], $param['extra']['language_standard'])
3140  ) {
3141  $matrix_page_link = $matrix_page->extra['language_link'][$lang];
3142 
3143  $matrix_page_extra = $matrix_page->extra;
3144  $matrix_page_extra['language_link'] = $param['extra']['language_link'];
3145  $matrix_page_extra['language_standard'] = $param['extra']['language_standard'];
3146 
3147  $matrix_page->updateExtra($clean_clones($matrix_page_extra), false, $asis);
3148 
3149  // Aus einer existierenden Sprachverknüpfung wird eine Sprachkopie
3150  if (!$param['extra']['language_link'][$lang] && $matrix_page_link) {
3151  // Multimedia Dateien müssen kopiert werden
3152  if ($this->_site->site['type'] == 'media') {
3153  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media' . DIRECTORY_SEPARATOR . $this->_site->name;
3154  $source = $media_dir . DIRECTORY_SEPARATOR . $this->getMediaFilename();
3155 
3156  if (Ego_System::file_exists($source)) {
3157  $dest = $media_dir . DIRECTORY_SEPARATOR . $matrix_page->getMediaFilename(true);
3158  Ego_System::copy(
3159  $source,
3160  $dest,
3161  '',
3162  true
3163  );
3164 
3165  // Archiveintrag
3166  Ego_System::copy(
3167  $dest,
3168  $media_dir . DIRECTORY_SEPARATOR . $matrix_page->getMediaFilename(
3169  true,
3170  '_'.strtotime($matrix_page->field['c_date'])
3171  ),
3172  '',
3173  true
3174  );
3175  }
3176  }
3177  }
3178  }
3179  }
3180  }
3181  }
3182  }
3183  if ($languages)
3184  {
3185  $this->message.= "\n".$GLOBALS['auth']->translate('Folgende Sprachen wurden auch geändert:').' '.join(', ', $languages)."\n";
3186  $this->_updatedLinkLanguages = $languages;
3187  }
3188  }
3189  }
3190 
3191  // Wird ein Multimedia Bild gespeichert, muss für alle untergeordneten Ausschnitte
3192  if ($this->field['type'] == 'multimedia/image') {
3193  foreach ($this->getChildren() as $child) {
3194  // ... die Spracheinstellungen vererbt werden
3195  if (isset($param['extra'])) {
3196  $extra = $child->extra;
3197  $extra['language_link'] = $param['extra']['language_link'];
3198  $extra['language_standard'] = $param['extra']['language_standard'];
3199  $child->updateExtra($extra, true, $asis);
3200  }
3201 
3202  // ... der Cache gelöscht werden
3203  $this->_site->clearCache($child->field['id']);
3204  }
3205  }
3206 
3207  $this->hookUpdate();
3208 
3209  if (!$this->extra['_indexed']) {
3210  $this->updateIndex();
3211  }
3212 
3213  return $reload;
3214  }
3215 
3222  function hookUpdate($hook = 'update') {
3223  // Zwischenspeicherungen führen keine Hooks aus
3224  if ($hook == 'update' && $this->archiveOnly) {
3225  return;
3226  }
3227 
3228  $cache_key = $this->_site->name.'/'.$this->field['type'].'/'.$hook;
3229  $hook_cache = array();
3230  if (isset($GLOBALS['hook_cache'][$cache_key])) {
3231  $hook_cache = $GLOBALS['hook_cache'][$cache_key];
3232  } else {
3233  $dirs = array(
3234  $GLOBALS['egotec_conf']['lib_dir'] . 'type/site/' => 0, // System
3235  $GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme.'/site/' => 'theme', // pub theme
3236  $GLOBALS['egotec_conf']['site_dir'] . '_global/' => 'global', // Global
3237  $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/' => 'misc' // Mandant
3238  );
3239  foreach ($dirs as $dir => $flag) {
3240  if ($flag == 'global' && !$this->_site->globalAllowed()) {
3241  continue;
3242  }
3243  $script_path = $dir . 'admin/' . $hook . '.php';
3244  if ($flag && Ego_System::file_exists($script_path)) {
3245  $hook_cache[] = array('path' => $script_path, 'flag' => $flag, 'type' => false);
3246  }
3247  $script_path = $dir . $this->field['type'] . '/admin/' . $hook . '.php';
3248  if (Ego_System::file_exists($script_path)) {
3249  $hook_cache[] = array('path' => $script_path, 'flag' => $flag ? $flag : 'misc', 'type' => true);
3250  }
3251  }
3252  if (!isset($GLOBALS['hook_cache'])) {
3253  $GLOBALS['hook_cache'] = array();
3254  }
3255  $GLOBALS['hook_cache'][$cache_key] = $hook_cache;
3256  }
3257  if ($hook_cache) {
3258  if (!$this->field['type']) {
3259  throw new Exception();
3260  }
3261  foreach ($hook_cache as $script_path) {
3262  $call_func = $script_path['type']
3263  ? 'site_'.$hook.'_'.str_replace('/', '_', $this->field['type']).'_'.$script_path['flag']
3264  : 'site_' . $hook . '_' . $script_path['flag'];
3265  if (!function_exists($call_func)) {
3266  require_once($script_path['path']);
3267  }
3268  if (function_exists($call_func)) {
3269  $call_func($this);
3270  }
3271  }
3272 
3273  if (!isset($GLOBALS['hook_cache'])) {
3274  $GLOBALS['hook_cache'] = array();
3275  }
3276  $GLOBALS['hook_cache'][$cache_key] = $hook_cache;
3277  }
3278 
3279  if (!$GLOBALS['egotec_setup']) {
3280  // Alle Verweise dieser Page sammeln
3281  if ($hook == 'update') {
3282  Ego_Queue::add(array($this, 'updateLinks'));
3283  }
3284 
3285  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'url') {
3286  if ($hook == 'delete' || $this->field['inactive']) {
3287  // URLs dieser Page archivieren
3288  Ego_Queue::add(array($this, 'archiveUrls'));
3289  } else {
3290  // URLs dieser Page aktualisieren
3291  if ($hook == 'newchild') {
3292  // Direkt ausführen, da die URLs direkt benötigt werden könnten
3293  $this->updateUrls();
3294  } else {
3295  Ego_Queue::add(array($this, 'updateUrls'));
3296  }
3297  }
3298  }
3299  }
3300  }
3301 
3309  function updateField($field, $matrix_flag = true, $asis = false) {
3310  return $this->update(array('field' => $field), $matrix_flag, $asis);
3311  }
3312 
3320  function updateChildren($children) {
3321  return $this->update(array('children' => $children), true, true);
3322  }
3323 
3330  function updateParents($parents) {
3331  return $this->update(array('parents' => $parents), true, true);
3332  }
3333 
3341  function updateExtra($extra, $matrix_flag = true, $asis = false) {
3342  return $this->update(array('extra' => $extra), $matrix_flag, $asis);
3343  }
3344 
3355  function updateRights($rights, $matrix_flag = true) {
3356  return $this->update(array('rights' => $rights), $matrix_flag);
3357  }
3358 
3370  function update($param = array(), $matrix_flag = true, $asis = false) {
3371  if (empty($param)) {
3372  // Aktuelle Daten speichern
3373  $reload = $this->_update(array(
3374  'field' => $this->field,
3375  'extra' => $this->extra,
3376  'rights' => array(
3377  'rights' => $this->getRightsArray(),
3378  'users' => $this->getUsersArray()
3379  )
3380  ), $matrix_flag, $asis);
3381  } else {
3382  $reload = $this->_update($param, $matrix_flag, $asis);
3383  }
3384  if($this->field['deleted'] == "1") {
3385  $this->hookUpdate("delete");
3386  $this->message.= $GLOBALS['auth']->translate('Die Seite wurde gelöscht.');
3387  }
3388  return $reload;
3389  }
3390 
3397  function updateIndex($search=null, $queue=true) {
3398  // Erfolgt der Aufruf über den Liveabgleich und ist die "ewige" Cache aktiv, wird kein Suchindex aktualisiert
3399  if (
3400  // Zwischenspeicherungen aktualisieren nicht den Suchindex
3401  $this->archiveOnly
3402  // Erfolgt der Aufruf über den Liveabgleich und ist die "ewige" Cache aktiv, wird kein Suchindex aktualisiert
3403  || ($_SERVER['HTTP_X_SOAP_CALL'] == 'Replication' && $this->getSite()->getCache()->getEternal())
3404  || !empty($GLOBALS['__skip_update_index'])
3405  ) {
3406  return;
3407  }
3408 
3409  if (!$search) {
3410  require_once('base/Ego_Search_Factory.php');
3411  $search = Ego_Search_Factory::start($this->_site->pageTable.$this->getTableSuffix());
3412  }
3413 
3414  // Relevanz der Felder beachten
3415  if ($queue) {
3416  Ego_Queue::add(array($search, 'update'), array($this->field['id'], $this, $this->_site->getSearchCount($this->extra['search_weight'])));
3417  } else {
3418  // sofort ausführen
3419  $search->update($this->field['id'], $this, $this->_site->getSearchCount($this->extra['search_weight']));
3420  }
3421  }
3422 
3436  function getChildren($query=array(), $param=array()) {
3437  $page_table = $this->_site->name.'_'.($param['lang']?$param['lang']:$this->_site->language);
3438  $children_table = $page_table.'_children';
3439  $query['table'] = $children_table;
3440 
3441  $query = $this->buildChildrenOrder($query, $param);
3442 
3443  $query['where'] = (isset($query['where'])?'('.$query['where'].') AND ':'').
3444  $children_table.'.page_id='.$this->field['id'].' AND '.$page_table.'.id='.$children_table.'.child';
3445  return $this->_site->getPages($query, $param);
3446  }
3447 
3455  public function buildChildrenOrder($query=array(), $param=array()) {
3456  $page_table = $this->_site->name.'_'.($param['lang']?$param['lang']:$this->_site->language);
3457  $children_table = $page_table.'_children';
3458  $order = trim(isset($query['order'])?$query['order']:$this->field['children_order']);
3459 
3460  if ($order[strlen($order) -1]=='R') {
3461  // r steht für reverse
3462  $param['reverse'] = !$param['reverse'];
3463  $order = substr($order, 0, strlen($order) -1);
3464  }
3465  switch ($order) {
3466  case 'title':
3467  $query['order'] = $page_table.'.title '.($param['reverse']?'desc':'asc');
3468  break;
3469  case 'name':
3470  $query['order'] = $page_table.'.name '.($param['reverse']?'desc':'asc');
3471  break;
3472  case 'a_date':
3473  $query['order'] = $page_table.'.a_date '.($param['reverse']?'desc':'asc');
3474  break;
3475  case 'c_date':
3476  $query['order'] = $page_table.'.c_date '.($param['reverse']?'desc':'asc');
3477  break;
3478  case 'release_from':
3479  $query['order'] = $page_table.'.release_from '.($param['reverse']?'desc':'asc');
3480  break;
3481  case 'release_until':
3482  $query['order'] = $page_table.'.release_until '.($param['reverse']?'desc':'asc');
3483  break;
3484  case 'asc':
3485  $query['order'] = $page_table.'.order_field '.($param['reverse']?'desc':'asc');
3486  break;
3487  case 'desc':
3488  $query['order'] = $page_table.'.order_field '.($param['reverse']?'asc':'desc');
3489  break;
3490  case 'type':
3491  $query['order'] = $page_table.'.type '.($param['reverse']?'desc':'asc').','.$page_table.'.name '.($param['reverse']?'desc':'asc');
3492  break;
3493  case 'none':
3494  unset($query['order']);
3495  break;
3496  case 'children':
3497  $query['order'] = $children_table.'.idx '.($param['reverse']?'desc':'asc');
3498  $query['fields2'] = ($query['fields2']?$query['fields2'].',':'').$children_table.'.idx';
3499  }
3500  if ($query['order'] && $query['order']!='id') { // Um die rückwärts gerichtete Sortierung korrekt zu bekommen, muss immer noch nach der id sortiert werden.
3501  $query['order'].= ','.$page_table.'.id '.($param['reverse']?'desc':'asc');
3502  }
3503 
3504  return $query;
3505  }
3506 
3514  public function hasChildren($query = array(), $param = array()) {
3515  if (isset($this->field['has_children'])) {
3516  return !empty($this->field['has_children']);
3517  }
3518  $children = $this->getChildren($query, $param);
3519  while ($children->nextPage()) {
3520  return true;
3521  }
3522  return false;
3523  }
3524 
3536  function getParents($query=array(), $param=array()) {
3537  $page_table = $this->_site->name.'_'.($param['lang']?$param['lang']:$this->_site->language);
3538  $children_table = $page_table.'_children';
3539  $query['table'] = $children_table;
3540  $query['where'] = (isset($query['where'])?'('.$query['where'].') AND ':'').
3541  $children_table.'.child='.$this->field['id'].' AND '.$page_table.'.id='.$children_table.'.page_id';
3542  return $this->_site->getPages($query, $param);
3543  }
3544 
3554  function getAncestors($query=array(), $param=array()) {
3555  if ($this->field['deleted']) {
3556  $param = array_merge($param, array('deleted' => -1));
3557  }
3558  $ancestors_ids = $this->_getAncestorsIds($this, $param['children_query'], $param['children_param']);
3559  if ($param['id_list']) {
3560  return $ancestors_ids;
3561  }
3562  if ($ancestors_ids) {
3563  $ancestors_ids = array_reverse($ancestors_ids);
3564  $query['where'] = (isset($query['where'])?'('.$query['where'].') AND ':'').
3565  'id IN ('.join(',', $ancestors_ids).')';
3566  $query['proposed_order'] = array(
3567  'field' => 'id',
3568  'values' => $ancestors_ids
3569  );
3570  return $this->_site->getPages($query, $param);
3571  } else {
3572  return new Page_Iterator();
3573  }
3574  }
3575 
3583  function getDescendants($query=array(), $param=array()) {
3584  $lang = $param['lang']?$param['lang']:$this->_site->language;
3585  $page_table = $this->_site->name.'_'.$lang;
3586  if (!$param['children_query']) {
3587  $param['children_query']['fields'] = 'id';
3588  }
3589  $param['children_query']['order'] = '';
3590  $param['children_query']['hash'] = $this->field['id'].md5(serialize($param['children_query']));
3591  $param['children_param']['has_children'] = 1;
3592  $param['children_param']['no_cache'] = 1;
3593 
3594  $cache = $this->_site->getCache();
3595  $cache_key = '_desc_'.$this->field['id'].'_'.
3596  ($GLOBALS['auth'] ? $GLOBALS['auth']->getId() : 'guest').'_'.
3597  md5(serialize($param['children_query']).serialize($param['children_param'])).'_'.
3598  md5(serialize($this->_site->getHash()));
3599  $descendants_ids = $cache->get($cache_key);
3600  if ($descendants_ids === null) {
3601  $descendants_ids = array();
3602  $this->_getDescendantsIds($this, $param['children_query'], $param['children_param'], $descendants_ids);
3603  if ($param['with_root']) {
3604  $descendants_ids[] = $this->field['id'];
3605  }
3606  $cache->set($cache_key, $descendants_ids);
3607  }
3608  if ($param['return_ids']) {
3609  return $descendants_ids;
3610  }
3611  if ($descendants_ids) {
3612  $query['where'] = (isset($query['where'])?
3613  '('.$query['where'].') and ':
3614  '');
3615  // Oracle verträgt max. 1000 Elemente pro Liste
3616  $idgroups = array();
3617  foreach (array_chunk($descendants_ids, 999) as $ids)
3618  {
3619  // IDs splitten in 999-Häppchen
3620  $idgroups[] = $page_table.'.id in ('.implode(',', $ids).')';
3621  }
3622  $query['where'] .= '('.implode(' or ', $idgroups).')';
3623 
3624  //$page_table.'.id in ('.join(',', $descendants_ids).')';
3625  return $this->_site->getPages($query, $param);
3626  } else {
3627  return new Page_Iterator();
3628  }
3629  }
3630 
3646  function getSiblings($query=array(), $param=array(), $proposed_path=array()) {
3647  assert(
3648  (!isset($query['limit']) && isset($param['next']))
3649  || (isset($query['limit']) && !isset($param['next']))
3650  || (!isset($query['limit']) && !isset($param['next']))
3651  );
3652 
3653  $parents_query = $param['parents_query']?$param['parents_query']:array();
3654  if ($proposed_path) {
3655  $parents_query2 = $parents_query;
3656  $parents_query2['where'] = ($parents_query2['where']?$parents_query2['where'].' AND ':'').'id IN ('.join(',', $proposed_path).')';
3657  $parents = $this->getParents($parents_query2, array(
3658  'auth_or' => '1=1',
3659  'inactive' => true,
3660  'only_active' => false
3661  ));
3662  $parent = $parents->nextPage();
3663  }
3664  if (!$parent) {
3665  $parent = $this->getParents($parents_query, array(
3666  'auth_or' => '1=1',
3667  'inactive' => true,
3668  'only_active' => false
3669  ))->nextPage(); /* @var $parent Page */
3670  }
3671  if ($parent) {
3672  if ($param['without_self']) {
3673  $query['where'] .= (isset($query['where']) ? ' AND ' : '') . 'id != :self_id';
3674  $query['bind']['self_id'] = $this->field['id'];
3675  }
3676 
3677  $siblings = $parent->getChildren($query, $param);
3678  if ($param['next']) { // Nur die Geschwister ab der aktuellen Seite anzeigen.
3679  $siblings->setHaltId($this->field['id']);
3680  }
3681  }
3682  if ($siblings) {
3683  return $siblings;
3684  } else {
3685  return new Page_Iterator();
3686  }
3687  }
3688 
3695  function getLanguagePage($lang, $param = array()) {
3696  $site = clone $this->_site; /* @var $site Site */
3697  try {
3698  $site->setLanguage($lang);
3699  } catch (Site_Exception $e) {
3700  if ($e->getCode() == Site_Exception::LANG_DOESNT_EXIST) {
3701  return null;
3702  }
3703  }
3704  return $site->getPage($this->field['id'], $param);
3705  }
3706 
3715  function createLanguagePage($lang, $param = array()) {
3716  if (!in_array($lang, $this->_site->getLanguages())) {
3717  throw new Site_Exception('Die Sprache existiert nicht', Site_Exception::LANG_DOESNT_EXIST);
3718  }
3719 
3720  // Parameter um die Seite in jedem Fall zu erhalten
3721  $l_param = array(
3722  'auth_or' => '1=1',
3723  'deleted_or' => '1=1',
3724  'inactive' => true,
3725  'only_active' => false
3726  );
3727 
3728  if ($l_page = $this->getLanguagePage($lang, $l_param)) { // Übersetzte Seite existiert bereits, diese aktualisieren
3729  $field = is_array($param['field'])? $param['field']:array();
3730  $extra = is_array($param['extra'])? $param['extra']:array();
3731 
3732  $l_page->update(
3733  array(
3734  'field' => $field,
3735  'extra' => $extra
3736  )
3737  );
3738  return $l_page;
3739  } else {
3740  // Felder und Extra vorbereiten
3741  $field = is_array($param['field'])? $param['field']:array();
3742  $field['id'] = $this->field['id'];
3743 
3744  $extra = is_array($param['extra'])? $param['extra']:array();
3745 
3746  // Elternseite ermitteln
3747  $parents = $this->getParents(
3748  array(),
3749  array(
3750  'auth_or' => '1=1',
3751  'inactive' => true,
3752  'only_active' => false
3753  )
3754  );
3755 
3756  $parent = $parents->nextPage();
3757 
3758  // Übersetzte Elternseite ermitteln
3759  $l_parent = $parent->getLanguagePage($lang, $l_param);
3760 
3761  if (!$l_parent) { // Übersetzte Elternseite existiert nicht, alle benötigten Vorfahren anlegen
3762  $path = $this->getPath(false, $GLOBALS['current_path'], false);
3763 
3764  // Ab der übersetzten Startseite alle Vorfahren durchgehen
3765  $_parent = $this->_site->getRoot()->getLanguagePage($lang, $l_param);
3766 
3767  foreach ($path as $pid) {
3768  // Übersetzten Vorfahren ermitteln
3769  $p = $this->_site->getPage($pid);
3770  $lp = $p->getLanguagePage(
3771  $lang,
3772  array(
3773  'auth_or' => '1=1',
3774  'inactive' => true,
3775  'only_active' => false
3776  )
3777  );
3778 
3779  if (!$lp) { // Übersetzter Vorfahre existiert nicht, eine inaktive Sprachkopie anlegen
3780  $copied_field = $p->field;
3781  $copied_field['inactive'] = self::INACTIVE_FLAG;
3782 
3783  $copied_extra = $p->extra;
3784  $lp = $_parent->newChild($copied_field, $copied_extra);
3785  } elseif ($lp->field['deleted']) {
3786  // Übersetzter Vorfahre wurde gelöscht, Seite wiederherstellen
3787  $restored_field = $p->field;
3788 
3789  unset($restored_field['deleted']);
3790  $restored_field['inactive'] = self::INACTIVE_FLAG; // Sprachkopie deaktivieren
3791 
3792  $lp->update($restored_field);
3793  }
3794 
3795  // Nächste Elternseite ist die aktuelle übersetzte Seite
3796  $_parent = $lp;
3797  }
3798 
3799  // Alle Vorfahren wurden angelegt, jetzt die erwünschte übersetzte Seite anlegen
3800  $l_child = $_parent->newChild($field, $extra);
3801  } else { // Übersetzte Elternseite existiert, übersetzte Seite anlegen
3802  $l_child = $l_parent->newChild($field, $extra);
3803  }
3804 
3805  // Mediapool kopieren
3806  $this->getMediapool()->copy($l_child);
3807  $l_child->getMediapool()->import(true);
3808 
3809  return $l_child;
3810  }
3811  }
3812 
3820  public function getKeywords($language = '', $own_keywords = false) {
3821  // Sprache muss gesetzt sein
3822  if ($language == '') {
3823  $language = $this->_site->language;
3824  }
3825 
3826  // Die Keyword-Tabelle ermitteln:
3827  // Das Schlagwortregister eines anderen Mandanten verwenden
3828  // (kann im Adminbereich pro Mandant eingestellt werden)
3829  if ($this->_site->admin['keywords']['site'] &&
3830  $this->_site->admin['keywords']['site'] != $this->_site->name
3831  ) {
3832  $keyword_table = $this->_site->admin['keywords']['site'].'_'.$language.'_keywords';
3833  } else {
3834  $keyword_table = $this->_site->name.'_'.$language.'_keywords';
3835  }
3836 
3837  // In der Relationen-Tabelle befinden sich die Zuweisungen,
3838  // also welches Schlagwort zu welcher Seite gehört
3839  $relation_table = $this->_site->name.'_keywords_rel';
3840 
3841  // Suche durchführen
3842  // Achtung! Diese Suche findet nur die Zuweisungen,
3843  // welche über den Pool verlinkt sind.
3844  // Nicht die eigenen Schlagworte, die in der Seite eingetragen wurden
3845  $db = new_db_connection();
3846 
3847  if (!$db->tableExists($keyword_table)) {
3848  return '';
3849  }
3850 
3851  $db->select(array(
3852  "fields" => "*",
3853  "table" => "$keyword_table INNER JOIN $relation_table ON $keyword_table.id = $relation_table.keyword_id",
3854  "where" => 'page_id = '.$this->field['id']
3855  ));
3856 
3857  // Alle Keywords sammeln
3858  $keywords = array();
3859 
3860  // zunächst die Zuweisungen aus dem Pool
3861  $keywords_list = explode(',', $this->extra['keywords_list']);
3862  while ($result = $db->next()) {
3863  if (in_array($result['id'], $keywords_list)) {
3864  array_push($keywords,$result['word']);
3865  }
3866  }
3867 
3868  // die eigenen Keywords werden zusätzlich ins Extra-Feld kommasepariert gespeichert und hier auch ausgelesen
3869  if ($own_keywords && $this->extra['keywords_list_own']) {
3870  $tmp = explode(',', $this->extra['keywords_list_own']);
3871  $keywords = array_merge($keywords, $tmp);
3872  }
3873 
3874  // Die Keyword-Liste kommasepariert ausgeben
3875  $keywords = implode(',', $keywords);
3876  return trim($keywords, ',');
3877  }
3878 
3885  function addKeyword($word, $add_to_pool = false) {
3886  // Whitespaces entfernen und Wort prüfen
3887  $word = trim($word);
3888  if ($word == '') {
3889  return false;
3890  }
3891 
3892  /*
3893  * Das Schlagwortregister kann auch aus einem andreen Mandanten verwendet werden
3894  * Achtung! Wenn z.B. in einem deutschen Page-Objekt ein Keywords hinzugefügt wird,
3895  * dieser Mandant aber nicht in dieser Sprache existiert,
3896  * dann wird kein Schlagwort erstellt.
3897  */
3898  if ($this->_site->admin['keywords']['site'] && $this->_site->admin['keywords']['site'] != $this->_site->name) {
3899  // Existenz der Sprache prüfen
3900  $keywordSite = new Site($this->_site->admin['keywords']['site'],$this->_site->language);
3901  } else {
3902  $keywordSite = $this->_site;
3903  }
3904 
3908  $k_db = new_db_connection();
3909  $k_db->select(array(
3910  'table' => $keywordSite->pageTable.'_keywords',
3911  'where' => 'LOWER(word)=:word',
3912  'bind' => array('word' => strtolower($word))
3913  ));
3914 
3919  if($k_db->next()) {
3920  $maxid = $k_db->Record['id'];
3921  } else {
3922  // Die nächst höchste ID herausfinden von allen verfügbaren Sprachen des Mandanten
3923  $max = 0;
3924  foreach($keywordSite->getLanguages() as $sprache) {
3925  $u_db = new_db_connection();
3926  $u_db->select(array(
3927  'fields' => 'id',
3928  'table' => $keywordSite->name.'_'.$sprache.'_keywords',
3929  'order' => 'id DESC',
3930  'limit' => '1'
3931  ));
3932 
3933  $maxentry = $u_db->next();
3934  if((int)$maxentry['id'] > $max) {
3935  $max = (int)$maxentry['id'];
3936  }
3937  }
3938  $maxid = $max+1; // Neue ID ist höchste ID + 1
3939 
3943  $k_db->insert(array(
3944  'table' => $keywordSite->pageTable.'_keywords',
3945  'set' => array(
3946  'id' => $maxid,
3947  'word' => $word,
3948  'c_date' => date('Y-m-d H:i:s'),
3949  'main' => 1, // Neues Wort ist immer der Hauptsprachbegriff
3950  'not_in_list' => ($add_to_pool) ? 0 : 1 // Im gesamten Schlagwortregister aufnehmen oder nicht
3951  ))
3952  );
3953  }
3954 
3966  $db2 = new_db_connection();
3967  $db2->select(array(
3968  'table' => $keywordSite->name.'_keywords_rel',
3969  'where' => "page_id = '".$this->field['id']."' AND keyword_id = '".$maxid."'",
3970  'order' => 'page_id',
3971  'limit' => 1
3972  ));
3973  if ($db2->next()) {
3974  return true; // alles ok, Schlagwort ist bereits zugewiesen
3975  }
3976 
3977  if ($k_db->insert(array(
3978  'table' => $keywordSite->name.'_keywords_rel',
3979  'set' => array(
3980  'page_id' => $this->field['id'],
3981  'keyword_id' => $maxid,
3982  'c_date' => date('Y-m-d H:i:s')
3983  )))) { // Abwärtskompatibilität Schlagworte auch in die Extra-Felder "keywords_list" und "keywords_list_own" schreiben
3984  // Alle zugewiesenden Schlagwort-Ids auslesen
3985  $k_db->select(array(
3986  'table' => $keywordSite->name.'_keywords_rel',
3987  'where' => "page_id = '".$this->field['id']."'"
3988  ));
3989  $entries = array();
3990  while ($entry = $k_db->next()) {
3991  $entries[] = $entry['id'];
3992  }
3993 
3994  // Alle Schlagworte auslesen
3995  $k_db->select(array(
3996  'table' => $keywordSite->pageTable.'_keywords',
3997  'where' => "id IN ('".implode("','", $entries)."')"
3998  ));
3999 
4000  $keywords_list = array();
4001  $keywords_list_own = array();
4002  while ($entry = $k_db->next()) {
4003 
4004  if ($entry['not_in_list'] == "1") {
4005  $keywords_list_own[] = $entry['word'];
4006  } else {
4007  $keywords_list[] = $entry['id'];
4008  }
4009  }
4010 
4011  // Schlagworte bzw. SchlagwortIDs kommasepariert ins extra-Feld
4012  if ($keywords_list || $keywords_list_own) {
4013  $this->extra['keywords_list'] = implode(",",$keywords_list);
4014  $this->extra['keywords_list_own'] = implode(",",$keywords_list_own);
4015  $this->updateExtra($this->extra,true);
4016  }
4017 
4018  return true;
4019  } else {
4020  return false;
4021  }
4022  }
4023 
4030  function getUrl($param = array()) {
4031  if (($this->extra['image_type'] || $param['pool']) && !$param['download'] && !$param['thumbnail']) { // Multimediaendung setzen.
4032  if (!$param['no_suffix'] && $this->extra['image_type']) {
4033  $param['suffix'] = $this->extra['image_type'];
4034  }
4035  unset($param['no_suffix']);
4036 
4037  /* Bild URLs müssen immer width und height Parameter beinhalten.
4038  * Wird nur width oder nur height übergeben, dann muss der Gegenwert
4039  * relativ berechnet werden (Skalierung).
4040  * Wird keiner der Parameter übergeben, dann werden die Originalwerte
4041  * verwendet (origImgWidth und origImgHeight).
4042  * Werden beide Parameter übergeben, dann werden diese verwendet.
4043  * Wird ein ungültiger Wert übergeben, dann wird der Parameter aus der URL entfernt.
4044  * Die URL Auflösung skaliert automatisch,
4045  * wenn nur width oder nur height in der URL vorkommt.*/
4046  $param = $this->addImageParams($param);
4047  }
4048  if (!$param['lang'] || $param['lang'] == $this->_site->language) {
4049  // Wird die URL für die aktuelle Seite angefordert, ist das Page Objekt bereits bekannt
4050  return $this->_site->getPageUrl($this->field['id'], $param, $this);
4051  }
4052  return $this->_site->getPageUrl($this->field['id'], $param);
4053  }
4054 
4061  public function getFrontendUrl($param = array()) {
4062  $now = date('Y-m-d H:i:s');
4063  if (
4064  $this->field['inactive'] > 0
4065  || ($this->field['release_from'] != '0000-00-00 00:00:00' && $this->field['release_from'] > $now)
4066  || ($this->field['release_until'] != '0000-00-00 00:00:00' && $this->field['release_until'] < $now)
4067  || $this->isWorkflowCopy()
4068  || $this->isReleaseCopy()
4069  ) {
4070  return '';
4071  }
4072  $param['get_frontend_url'] = true;
4073  return $this->getUrl($param);
4074  }
4075 
4082  public function getLiveUrl($param = array()) {
4083  if (((int) $this->field['nav_hide']&2) == 2) {
4084  // Es gibt keine Liveserver URLs für Seiten, die nicht auf dem Liveserver existieren dürfen
4085  return '';
4086  }
4087 
4088  // Immer eine absolute URL erzeugen
4089  $param['return_absolute'] = true;
4090 
4091  if (!$GLOBALS['egotec_conf']['liveserver']) {
4092  // URL vom (ersten) Liveserver erzeugen
4093  $clusters = Ego_System::getCluster();
4094  array_walk($clusters, function (&$value) {
4095  $value = $value['url'];
4096  });
4097  $liveservers = array_values(array_filter(array_merge([$this->_site->admin['live']['location']], $clusters)));
4098 
4099  if (!empty($liveservers)) {
4100  // Liveserver URL setzen
4101  $live = $this->_site->admin['live'];
4102  $live['location'] = $liveservers[0];
4103 
4104  require_once('soap/Ego_SOAP.php');
4105  $soap = new Ego_SOAP($live, 1);
4106  try {
4107  return $soap->soapCall('pageGetUrl', [
4108  'site' => $this->_site->name,
4109  'lang' => $this->_site->language,
4110  'id' => $this->field['id'],
4111  'param' => soap_var($param)
4112  ]);
4113  } catch (Exception $e) {
4114  return '';
4115  }
4116  }
4117  }
4118 
4119  // URL von diesem Server erzeugen
4120  return $this->getFrontendUrl($param);
4121  }
4122 
4128  public function getCloneUrl() {
4129  return 'index.php?' . http_build_query(array(
4130  'id' => $this->field['id'],
4131  'site' => $this->_site->name,
4132  'lang' => $this->_site->language
4133  ));
4134  }
4135 
4141  public function getCloneOriginal() {
4142  if ($this->isClone()) {
4143  $param = array(
4144  'auth_or' => '1=1',
4145  'deleted_or' => '1=1',
4146  'inactive' => true,
4147  'only_active' => false
4148  );
4149  if (is_numeric($this->extra['clone_original'])) { // abwärtskompatibel
4150  $page = $this->_site->getPage($this->extra['clone_original'], $param);
4151  } else {
4152  $page = Ego_System::urltopage($this->extra['clone_original'], array(
4153  'params' => array(
4154  'param' => $param
4155  )
4156  ));
4157  }
4158  return $page;
4159  }
4160  return null;
4161  }
4162 
4175  function lock($user_id='') {
4176  if (!$user_id) {
4177  $user_id = $GLOBALS['auth']->getId();
4178  }
4179  if (!$user_id) {
4180  // bei einem anonymen Benutzer wird eine Kombination aus remote_addr und user_agent gespeichert #93240
4181  $user_id = $GLOBALS['auth']->getAnonymousId();
4182  }
4183 
4184  $db = new_db_connection(array(
4185  'fields' => 'egotec_page_lock.*,egotec_user.*, egotec_page_lock.user_id AS lock_user_id',
4186  'table' => 'egotec_page_lock',
4187  'join' => 'egotec_user on egotec_page_lock.user_id=egotec_user.user_id',
4188  'where' => "(page_table='".$this->_site->pageTable."') AND (page=".$this->field['id'].")"
4189  ));
4190  if ($db->nextRecord()) {
4191  if (
4192  $db->Record['stamp'] >= (time() - $GLOBALS['egotec_conf']['page_timeout'])
4193  && $db->Record['user_id'] != $user_id
4194  ) {
4195  $db->Record['extra'] = unserialize($db->Record['extra']);
4196  return $db->Record;
4197  } else {
4198  $db->update(array(
4199  'table' => 'egotec_page_lock',
4200  'set' => array(
4201  'user_id' => $user_id,
4202  'stamp' => time()
4203  ),
4204  'where' => "page_table = '{$this->_site->pageTable}' AND page = {$this->field['id']}"
4205  ));
4206  return false;
4207  }
4208  }
4209 
4210  try {
4211  @$db->insert(array(
4212  'table' => 'egotec_page_lock',
4213  'set' => array(
4214  'page_table' => $this->_site->pageTable,
4215  'page' => $this->field['id'],
4216  'user_id' => $user_id,
4217  'stamp' => time()
4218  ),
4219  'nobackup' => true
4220  ));
4221  } catch (Exception $e) {
4222  // ignorieren
4223  }
4224  return false;
4225  }
4226 
4232  function unlock($user_id=false) {
4233  $db = new_db_connection();
4234  if ($user_id === false) {
4235  $user_id = $GLOBALS['auth']->getId();
4236  }
4237  if (!$user_id) {
4238  // bei einem anonymen Benutzer wird eine Kombination aus remote_addr und user_agent gespeichert #93240
4239  $user_id = $GLOBALS['auth']->getAnonymousId();
4240  }
4241  $db->delete(array(
4242  'table' => 'egotec_page_lock',
4243  'where' => "
4244  (page_table='".$this->_site->pageTable."') AND
4245  (page=".$this->field['id'].") AND
4246  (user_id='$user_id')"
4247  ));
4248  }
4249 
4258  public function isLocked($exclude_self = true) {
4259  $where = 'page_table = :page_table AND page = :page AND stamp >= :stamp';
4260  $bind = array(
4261  'page_table' => $this->_site->pageTable,
4262  'page' => $this->field['id'],
4263  'stamp' => time() - $GLOBALS['egotec_conf']['page_timeout']
4264  );
4265  if ($exclude_self) {
4266  $where .= ' AND user_id != :user_id';
4267  $bind['user_id'] = $GLOBALS['auth']->isNobody()
4268  ? $GLOBALS['auth']->getAnonymousId()
4269  : $GLOBALS['auth']->getId();
4270  }
4271  $db = new_db_connection(array(
4272  'table' => 'egotec_page_lock',
4273  'where' => $where,
4274  'bind' => $bind
4275  ));
4276  if ($db->nextRecord()) {
4277  return array(
4278  'user' => new User_SQL($db->Record['user_id']),
4279  'stamp' => $db->Record['stamp']
4280  );
4281  }
4282  return array();
4283  }
4284 
4291  function getRightsArray($perm_type='') {
4292  $db = $this->_getRights($perm_type);
4293  $a = array();
4294  while ($db->nextRecord()) {
4295  $a[$db->Record['perm']][] = array(
4296  'group_id' => $db->Record['group_id'],
4297  'role_id' => $db->Record['role_id']
4298  );
4299  }
4300  // Für alle Felder in denen kein IS NULL verwendet werden darf muss später ein *|* eingetragen werden
4301  if (!$perm_type) {
4302  $no_null_fields = explode(',', trim(Auth::NO_NULL_RIGHTS, ','));
4303  foreach ($no_null_fields as $f) {
4304  if (!$a[$f]) {
4305  if ($f == 'live') {
4306  // Das Veröffentlichen Recht ist standardmäßig immer root/Administrator
4307  $a[$f][] = array(
4308  'group_id' => $GLOBALS['egotec_conf']['superuser']['group'],
4309  'role_id' => $GLOBALS['egotec_conf']['superuser']['role']
4310  );
4311  } else {
4312  $a[$f][] = array();
4313  }
4314  }
4315  }
4316  }
4317  return $a;
4318  }
4319 
4327  public function getRights($perm_type='') {
4328  return $this->_getRights($perm_type);
4329  }
4330 
4336  function setRightsArray($rights) {
4337  $db = new_db_connection();
4338  $db->begin();
4339  $table = $this->_site->pageTable.'_rights';
4340  $db->delete(array(
4341  'table' => $table,
4342  'where' => "page_id=".$this->field['id']
4343  ));
4344  $set = array(); // Doppelte Einträge vermeiden
4345  foreach ($rights as $perm => $perm_rights) {
4346  if ($perm_rights) { // $perm_rights könnte auch null sein.
4347  foreach ($perm_rights as $right) {
4348  if ($right['group_id'] && $right['role_id']) { // Nur einfügen, wenn tatsächlich eine GroupID und RoleID angegeben ist.
4349  $key = $this->field['id'].'.'.$perm.'.'.$right['group_id'].'.'.$right['role_id'];
4350  if (!in_array($key, $set)) {
4351  $db->insert(array(
4352  'table' => $table,
4353  'set' => array(
4354  'page_id' => $this->field['id'],
4355  'perm' => $perm,
4356  'group_id' => $right['group_id'],
4357  'role_id' => $right['role_id']
4358  )
4359  ));
4360  $set[] = $key;
4361  }
4362  }
4363  }
4364  }
4365  }
4366  $db->commit();
4367  }
4368 
4375  function getUsersArray($perm_type='') {
4376  $db = $this->_getUsers($perm_type);
4377  $a = array();
4378  while ($db->nextRecord()) {
4379  $a[$db->Record['perm']][] = array(
4380  'user_id' => $db->Record['user_id']
4381  );
4382  }
4383  return $a;
4384  }
4385 
4391  function setUsersArray($users) {
4392  $db = new_db_connection();
4393  $table = $this->_site->pageTable.'_users';
4394  $db->delete(array(
4395  'table' => $table,
4396  'where' => "page_id=".$this->field['id']
4397  ));
4398  $set = array(); // Doppelte Einträge vermeiden
4399  foreach ($users as $perm => $perm_users) {
4400  if ($perm_users) { // $perm_users könnte auch null sein.
4401  foreach ($perm_users as $user) {
4402  if ($user['user_id']) { // Nur einfügen, wenn tatsächlich eine UserID angegeben ist.
4403  $key = $this->field['id'].'.'.$perm.'.'.$user['user_id'];
4404  if (!in_array($key, $set)) {
4405  $db->insert(array(
4406  'table' => $table,
4407  'set' => array(
4408  'page_id' => $this->field['id'],
4409  'perm' => $perm,
4410  'user_id' => $user['user_id']
4411  )
4412  ));
4413  $set[] = $key;
4414  }
4415  }
4416  }
4417  }
4418  }
4419  }
4420 
4426  public function getSite() {
4427  return $this->_site;
4428  }
4429 
4435  public function getMediapool() {
4436  return $this->_pool;
4437  }
4438 
4445  public function hasParent($parent_id) {
4446  $db = new_db_connection(array(
4447  'table' => $this->_site->pageTable.'_children',
4448  'where' => 'page_id='.$parent_id.' AND child='.$this->field['id']
4449  ));
4450  return $db->nextRecord() !== null;
4451  }
4452 
4460  public function addParent($parent_id, $asis=false) {
4461  $this->archiveOnly = false;
4462  if (!$this->_addParent($parent_id)) {
4463  return false;
4464  }
4465  $this->_updateField(array(), true, $asis); // Änderungsdatum aktualisieren und Cache löschen.
4466  $this->hookUpdate();
4467  return true;
4468  }
4469 
4478  public function addChild($child_id='', $child_id2='') {
4479  if (!$child_id) {
4480  $child_id = $child_id2;
4481  }
4482  $this->_site->getPage($child_id)->addParent($this->field['id']);
4483  }
4484 
4492  public function delParent($parent_id, $asis=false) {
4493  $this->archiveOnly = false;
4494  $this->_removeParent($parent_id);
4495  $this->_updateField(array(), true, $asis); // Änderungsdatum aktualisieren und Cache löschen.
4496  $this->hookUpdate();
4497  }
4498 
4504  public function isWriteable(){
4505  if (!$this->hasRights(array('edit'))) {
4506  return false;
4507  } else if (
4508  $this->_site->admin['workflow']['enabled'] // Workflow ist aktiviert
4509  && $this->field['workflow'] // UND und für dieser Seite ist ein Workflow zugewiesen
4510  && !(int)$this->extra['original_id'] // UND bei der Site handelt es sich NICHT um eine Worflow-Kopie
4511  && !$this->hasRights('workflow') // UND der aktuelle User hat NICHT das Recht den Workflow zu ändern
4512  ) {
4513  return false;
4514  }
4515  return true;
4516  }
4517 
4523  public function isRoot() {
4524  return ($this->field['id'] == $this->_site->rootId);
4525  }
4526 
4538  public function getPath($with_root=true, $proposed_path=array(), $return_string=true, $query=array('fields' => 'id,name,url'), $param = array(), &$assorted = null) {
4539  if ($this->field['id'] == $this->_site->rootId) {
4540  // Die Startseite hat keinen Pfad
4541  if ($with_root) {
4542  // ...und gibt maximal sich selbst aus
4543  if ($return_string == 2 && $return_string != 1) {
4544  return array($this);
4545  } elseif ($return_string) {
4546  if ($GLOBALS['egotec_conf']['meta_in_path']) {
4547  return Ego_System::encode_path(empty($this->field['url'])?$this->field['name']:$this->field['url']).'/';
4548  } else {
4549  return Ego_System::encode_path($this->field['name']).'/';
4550  }
4551  } else {
4552  return array($this->field['id']);
4553  }
4554  }
4555  return in_array($return_string, array(1, true), true) ? '' : array();
4556  }
4557  if (
4558  !$proposed_path && is_array($GLOBALS['current_path'])
4559  ) {
4560  $proposed_path = $GLOBALS['current_path'];
4561  }
4562  $proposed_path[] = $this->field['id'];
4563  $ancestor_ids = array();
4564  foreach (
4565  $this->getAncestors(
4566  array('fields' => 'id'),
4567  array_merge($param, array(
4568  'auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG,
4569  'children_query' => array('where' => "type != '_keywords/entry'"),
4570  'children_param' => array('auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG)
4571  ))
4572  )
4573  as $page) { // Alle möglichen Pfade der aktuellen Seite.
4574  $ancestor_ids[] = $page->field['id'];
4575  }
4576  $ancestor_ids[] = $this->field['id'];
4577  if ($ancestor_ids) {
4578  $ancestor_where = ' AND id IN ('.join(',', $ancestor_ids).')';
4579  }
4580  $page = $this->_site->getRoot(array('auth_or' => '1=1'));
4581  if ($with_root) {
4582  if ($return_string == 2 && $return_string != 1) {
4583  $path[] = $this->_site->getPage($this->_site->rootId, array('auth_or' => '1=1'));
4584  } elseif ($return_string) {
4585  if ($GLOBALS['egotec_conf']['meta_in_path']) {
4586  $path = Ego_System::encode_path(empty($page->field['url'])?$page->field['name']:$page->field['url']).'/';
4587  } else {
4588  $path = Ego_System::encode_path($page->field['name']).'/';
4589  }
4590  } else {
4591  $path[] = $this->_site->rootId;
4592  }
4593  } else {
4594  $path = in_array($return_string, array(1, true), true) ? '' : array();
4595  }
4596  while ($page->field['id']!=$this->field['id'] && $page) {
4597  $proposed_id = array_shift($proposed_path);
4598  if ($proposed_id==$page->field['id']) {
4599  $proposed_id = array_shift($proposed_path);
4600  }
4601  if ($proposed_id && is_numeric($proposed_id)) {
4602  $children = $page->getChildren(
4603  array(
4604  'fields' => $query['fields'],
4605  'where' => 'id=:id'.$ancestor_where,
4606  'order' => false,
4607  'bind' => array(
4608  'id' => $proposed_id
4609  )
4610  ), array(
4611  'auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG
4612  )
4613  );
4614  $child = $children->nextPage();
4615  } else {
4616  $child = false;
4617  }
4618  if (!$child) {
4619  $children = $page->getChildren(
4620  array(
4621  'fields' => $query['fields'],
4622  'where' => '1=1 '.$ancestor_where,
4623  'order' => false
4624  ), array(
4625  'auth_or' => '1=1', 'inactive' => self::INACTIVE_FLAG
4626  )
4627  );
4628  $child = $children->nextPage();
4629  if (!$child) {
4630  break;
4631  }
4632  }
4633  if ($child->field['id']==$this->field['id']) {
4634  break;
4635  }
4636  if ($child->field['inactive'] == self::ACTIVE_FLAG) {
4637  if ($return_string == 2 && $return_string != 1) {
4638  $path[] = $child;
4639  } elseif ($return_string) {
4640  if ($_SESSION['export']) {
4641  $path.='-p-'.$child->field['id'].'/';
4642  } else {
4643  if ($GLOBALS['egotec_conf']['meta_in_path']) {
4644  $path.= Ego_System::encode_path(empty($child->field['url'])?$child->field['name']:$child->field['url']).'/';
4645  } else {
4646  $path.= Ego_System::encode_path($child->field['name']).'/';
4647  }
4648  }
4649  } else {
4650  $path[] = $child->field['id'];
4651  }
4652  }
4653  $page = $child;
4654 
4655  // Prüfen, ob der Pfad wirklich eindeutig ist (keine Seite im Pfad hat in selber Ebene eine gleichnamige Seite)
4656  if ($assorted === false) {
4657  $siblings = $page->getSiblings(array(
4658  'fields' => 'id,url,name',
4659  'where' => '(url = :name1 OR name = :name2)',
4660  'bind' => array(
4661  'name1' => $child->field['name'],
4662  'name2' => $child->field['name']
4663  )
4664  ), array('auth_or' => '1=1'));
4665  if ($siblings->numRecords() > 1) {
4666  $assorted = true;
4667  }
4668  }
4669  }
4670  return $path;
4671  }
4672 
4680  public function getPaths($with_root = false, $in_root = false) {
4681  $paths = array();
4682  $get_path = function($page, $path = array()) use (&$get_path, &$paths, $with_root, $in_root) {
4683  if (!$with_root && $page->field['id'] == $this->_site->rootId) {
4684  array_pop($path);
4685  return $path;
4686  }
4687  $get_name = function($page) {
4688  $names = $page->getUrlNames();
4689  return array(
4690  'name' => $names[0],
4691  'id' => (int) $page->field['id']
4692  );
4693  };
4694  $index = 0;
4695  $original_path = $path;
4696  foreach ($page->getParents(array(), array(
4697  'auth_or' => '1=1',
4698  'deleted_or' => '1=1',
4699  'inactive' => true,
4700  'only_active' => false
4701  )) as $parent) {
4702  if ($index++ == 0) {
4703  // Erster Pfad
4704  $path[] = $get_name($parent);
4705  $path = $get_path($parent, $path);
4706  if (empty($path) && $in_root && $parent->field['id'] == $page->getSite()->rootId) {
4707  // Pfad direkt unter der Startseite aufnehmen
4708  $path[] = array(
4709  'name' => '',
4710  'id' => $with_root ? (int) $parent->field['id'] : ''
4711  );
4712  }
4713  } else {
4714  // Weitere Pfade
4715  $tmp_path = $original_path;
4716  $tmp_path[] = $get_name($parent);
4717  $paths[] = $get_path($parent, $tmp_path);
4718  }
4719  }
4720  return $path;
4721  };
4722  $path = $get_path($this);
4723  if (!empty($path)) {
4724  $paths[] = $path;
4725  }
4726  if (!empty($paths)) {
4727  $paths = array_reverse(array_map('array_reverse', $paths));
4728  $grouped_paths = array();
4729  foreach ($paths as $index => $path) {
4730  foreach ($path as $entry) {
4731  foreach ($entry as $key => $value) {
4732  $grouped_paths[$index][$key][] = $value;
4733  }
4734  }
4735  }
4736  foreach ($grouped_paths as $index => $path) {
4737  foreach ($path as $key => $values) {
4738  $grouped_paths[$index][$key] = implode($key == 'name' ? '/' : ',', $values);
4739  }
4740  }
4741  return $grouped_paths;
4742  }
4743  return $paths;
4744  }
4745 
4751  public function hasMultiParents(){
4752  return ((integer)$this->getParents(array(), array('auth_or'=>'1=1'))->numRecords())>1;
4753  }
4754 
4755  static function unserialize ($session_value) {
4756  $obj = @unserialize($session_value);
4757  if (get_class($obj) == '__PHP_Incomplete_Class') {
4763  $session_value = preg_replace('/^O:\d+:"Page.*?":/msi', 'O:4:"Page":', $session_value);
4764  $obj = @unserialize($session_value);
4765  if (get_class($obj) == '__PHP_Incomplete_Class') {
4766  return null;
4767  }
4768  }
4769  return $obj;
4770  }
4771 
4772  public function serialize (){
4773  return serialize($this);
4774  }
4775 
4776  public function __toString(){
4777  return get_class($this).'('.$this->getIdentity().')';
4778  }
4779 
4786  protected function _cleanEmptyContent(&$field) {
4787  if ($this->field['type']=="code") {
4788  return;
4789  }
4790 
4791  if ($field['content']) { // der neue Content
4792  $str = $field['content'];
4793  } else { // der alte Content
4794  $str = $this->field['content'];
4795  }
4796 
4797  if ($str != '') {
4798  if (Ego_System::isEmptyContent($str)) {
4799  $field['content'] = ''; // richtig leeren
4800  }
4801  }
4802  }
4803 
4810  public function cleanEmptyContent($asis=false) {
4811  $field = array();
4812  $field['content'] = $this->field['content'];
4813  $vorher = strlen($field['content']);
4814  $this->_cleanEmptyContent($field);
4815  $nachher = strlen($field['content']);
4816  if ($vorher != $nachher) {
4817  $param = array(
4818  'field' => $field
4819  );
4820  $this->update($param,array(),true, $asis);
4821  return true;
4822  }
4823  return false;
4824  }
4825 
4836  public function getMediaFilename($force_lang = false, $suffix = "") {
4837  $dir = $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/';
4838  $id = $this->field['id'].$suffix;
4839  $filename = $this->_site->language.'/'.$id;
4840 
4841  // Verzeichnis für die Sprache anlegen
4842  Ego_System::mkdir($dir.$this->_site->language);
4843 
4844  if (
4845  Ego_System::file_exists($dir.$filename) // Datei existiert in dieser Sprache
4846  || $force_lang // ID und Sprache muss ausgegeben werden
4847  ) {
4848  return $filename;
4849  } elseif (
4850  $this->_site->language != $this->_site->site['default_language']
4851  && Ego_System::file_exists($dir.$this->_site->site['default_language'].'/'.$id)
4852  ) {
4853  // Datei existiert aber in der Standard Sprache
4854  return $this->_site->site['default_language'].'/'.$id;
4855  }
4856 
4857  // Nur die ID ausgeben
4858  return $id;
4859  }
4860 
4867  public function addImageParams($param = array()) {
4868  $width = $param['width'];
4869  $height = $param['height'];
4870  $orig_width = $orig_height = null;
4871 
4872  // Die originale Breite/Höhe wird übergeben
4873  foreach (array('width', 'height') as $key) {
4874  if (isset($param['original_' . $key])) {
4875  $var = 'orig_' . $key;
4876  ${$var} = (int) $param['original_' . $key];
4877  unset($param['original_' . $key]);
4878  }
4879  }
4880 
4887  $use_clip = function($clip) use (&$orig_width, &$orig_height) {
4888  list($x1, $y1, $x2, $y2) = explode(',', $clip, 4);
4889  $orig_width = $x2 - $x1;
4890  $orig_height = $y2 - $y1;
4891  };
4892 
4893  if ($this->extra['image_type']) {
4894  // Multimedia
4895  $orig_width = $this->extra['origImgWidth'];
4896  $orig_height = $this->extra['origImgHeight'];
4897  if (!empty($this->extra['edit']['clip'])) {
4898  $use_clip($this->extra['edit']['clip']);
4899  }
4900  } elseif (isset($param['pool'])) {
4901  // Mediapool
4902  $pool = $this->getMediapool()->get($param['pool'], $param['dir']);
4903  if (!empty($pool) && $pool['isImage']) {
4904  $size = getimagesize($pool['file']);
4905  $orig_width = $size[0];
4906  $orig_height = $size[1];
4907  if (!empty($pool['clip'])) {
4908  $use_clip($pool['clip']);
4909  }
4910  } elseif (!$orig_width && !$orig_height) {
4911  return $param;
4912  }
4913  } else {
4914  return $param;
4915  }
4916 
4917  if (is_numeric($param['width'])) {
4918  if (
4919  is_numeric($orig_width)
4920  && is_numeric($orig_height)
4921  && !isset($param['height'])
4922  ) {
4923  $width = $param['width'];
4924  $height = ceil($orig_height * ($param['width'] / $orig_width));
4925  }
4926  } elseif (is_numeric($orig_width) && !isset($param['height'])) {
4927  $width = $orig_width;
4928  }
4929  if (is_numeric($param['height'])) {
4930  if (
4931  is_numeric($orig_height)
4932  && is_numeric($orig_width)
4933  && !isset($param['width'])
4934  ) {
4935  $width = ceil($orig_width * ($param['height'] / $orig_height));
4936  $height = $param['height'];
4937  }
4938  } elseif (is_numeric($orig_height) && !isset($param['width'])) {
4939  $height = $orig_height;
4940  }
4941  if (is_numeric($width)) {
4942  $param['width'] = $width;
4943  } else {
4944  unset($param['width']);
4945  }
4946  if (is_numeric($height)) {
4947  $param['height'] = $height;
4948  } else {
4949  unset($param['height']);
4950  }
4951  return $param;
4952  }
4953 
4960  public function hasLanguageFile($lang) {
4961  $dir = $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/';
4962  $filename = $lang.'/'.$this->field['id'];
4963 
4964  return file_exists($dir.$filename);
4965  }
4966 
4975  public function destroyFile(){
4976  $dir = $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/';
4977  $filename = $this->_site->language.'/'.$this->field['id'];
4978 
4979  if (file_exists($dir.$filename)) {
4980  unlink($dir.$filename);
4981  }
4982 
4983  $mediafiles = glob($dir.$filename.'_*');
4984  if (is_array($mediafiles)) {
4985  foreach ($mediafiles as $mediafile) {
4986  unlink($mediafile);
4987  }
4988  }
4989 
4990  // Die Seite existiert ohne Sprache und die aktuelle Sprache ist die Standard Sprache
4991  if ($this->_site->language == $this->_site->site['default_language']) {
4992  $filename = $this->field['id'];
4993 
4994  if (file_exists($dir.$filename)) {
4995  unlink($dir.$filename);
4996  }
4997 
4998  $mediafiles = glob($dir.$filename.'_*');
4999  if (is_array($mediafiles)) {
5000  foreach ($mediafiles as $mediafile) {
5001  unlink($mediafile);
5002  }
5003  }
5004  }
5005  }
5006 
5013  public function getProtocol($site = null) {
5014  if (!$site) {
5015  $site = $GLOBALS['site'];
5016  }
5017  return 'http'.(
5018  ($_SERVER['HTTPS'] == 'on'
5019  && $site
5020  && $site->name == $this->_site->name
5021  && $site->language == $this->_site->language)
5022  || !empty($this->extra['https']) ? 's' : ''
5023  ).'://';
5024  }
5025 
5031  public function getInformationLocked() {
5032  $params = array();
5033  $params['tpl_name'] = 'information_locked.html';
5034  if ($this->field['type'] == 'multimedia/image') {
5035  $params['tpl_name'] = 'information_locked_image.html';
5036  }
5037  $file_name = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/'.$this->field['type'].'/admin/navigation.ini';
5038  if (!file_exists($file_name)) {
5039  $file_name = $GLOBALS['egotec_conf']['site_dir'].$this->_site->name.'/admin/navigation.ini';
5040  if ($this->_site->globalAllowed() && !file_exists($file_name)) {
5041  $file_name = $GLOBALS['egotec_conf']['site_dir'].'_global/admin/navigation.ini';
5042  }
5043  }
5044  if (file_exists($file_name)) {
5045  $navigation = parse_ini_file($file_name, true);
5046  foreach ($navigation as $key => $value) {
5047  if (stripos($value['url'], 'info.php?') === 0) {
5048  if (preg_match_all('/([^\?&=]+)=([^\?&=#]*)/', $value['url'], $matches)) {
5049  foreach ($matches[0] as $index => $match) {
5050  if ($matches[1][$index] != 'tpl_name') {
5051  $params[$matches[1][$index]] = $matches[2][$index];
5052  }
5053  }
5054  }
5055  break;
5056  }
5057  }
5058  }
5059  $params['url'] = 'extra.php?'.http_build_query($params);
5060  return $params;
5061  }
5062 
5070  public function getContent($main_orient = false, $variant = '') {
5071  $content = '';
5072  if ($variant != '') {
5073  // Block Variante global weiterreichen, damit alle Aufrufe im fetch() darauf zugreifen können
5074  $GLOBALS['_block_variant'] = $variant;
5075  }
5076  if ($this->isFrontendAdmin(false)) {
5077  if ($main_orient) {
5078  // Nur die Blöcke der Haupt-Orientierung
5079  $content = $this->getBlocks($this->mainOrient, $variant);
5080  } else {
5081  require_once('smarty/Ego_Smarty.php');
5082  $smarty = Ego_Smarty::createFrontend($this->_site, array(
5083  'page' => $this
5084  ));
5085  $smarty->autoload_filters['output'] = array('frontend_edit');
5086  if ($layout = $this->getLayout($GLOBALS['is_mobile'])) {
5087  $content = $smarty->fetch($layout);
5088  }
5089  }
5090  }
5091  if ($content == '') {
5092  $content = $this->field['content'];
5093  }
5094  unset($GLOBALS['_block_variant']);
5095  return $content;
5096  }
5097 
5107  public function getLayout($mobile = false, $name = '', $suffix = '', &$script = '') {
5108  // Layout Template ermitteln
5109  if (empty($suffix)) {
5110  $suffix = $_SERVER['REQUEST_SUFFIX'];
5111  }
5112  $suffix = $suffix != '.html' ? $suffix : '';
5113  $name = $name ? $name : $this->extra['_layout'];
5114  $cache_key = 'pageLayout'.md5(serialize(array($this->field['type'], $name, $mobile, $suffix)));
5115  $layout = $this->_site->getCacheEntry($cache_key);
5116 
5117  if ($layout === null) {
5118  $layout = '';
5119 
5120  foreach (array('.tpl', '.html') as $file_suffix) {
5121  if (!empty($name) && $name != 'default') {
5122  if (
5123  ($file = $this->_site->getSkinFile("{$this->field['type']}/layouts/{$name}{$suffix}{$file_suffix}"))
5124  || ($file = $this->_site->getSkinFile("layouts/{$name}{$suffix}{$file_suffix}"))
5125  ) {
5126  $layout = $file;
5127  break;
5128  }
5129  } elseif (
5130  ($file = $this->_site->getSkinFile("{$this->field['type']}/layout{$suffix}{$file_suffix}"))
5131  || ($file = $this->_site->getSkinFile("layout{$suffix}{$file_suffix}"))
5132  ) {
5133  $layout = $file;
5134  break;
5135  }
5136  }
5137  if (empty($layout)) {
5138  if ($suffix != '') {
5139  $layout = $this->getLayout($mobile, $name, '.html');
5140  } elseif ($name != $this->conf['default_layout']) {
5141  $layout = $this->getLayout($mobile, $this->conf['default_layout'], '.html');
5142  }
5143  }
5144  $this->_site->setCacheEntry($cache_key, $layout);
5145  }
5146 
5147  // Layout Skript ermitteln
5148  $cache_key = 'pageLayoutScript'.md5(serialize(array($this->field['type'], $name, $mobile, $suffix)));
5149  $script = $this->_site->getCacheEntry($cache_key);
5150 
5151  if ($script === null) {
5152  $script = '';
5153 
5154  if (!empty($name) && $name != 'default') {
5155  if ($name == 'default') {
5156  if (
5157  ($file = $this->_site->getSiteFile("{$this->field['type']}/layout{$suffix}.php"))
5158  || ($file = $this->_site->getSiteFile("layout{$suffix}.php"))
5159  ) {
5160  $script = $file;
5161  }
5162  } elseif (
5163  ($file = $this->_site->getSiteFile("{$this->field['type']}/layouts/{$name}{$suffix}.php"))
5164  || ($file = $this->_site->getSiteFile("layouts/{$name}{$suffix}.php"))
5165  ) {
5166  $script = $file;
5167  }
5168  }
5169  if (
5170  empty($script)
5171  && (
5172  ($file = $this->_site->getSiteFile("{$this->field['type']}/layout{$suffix}.php"))
5173  || ($file = $this->_site->getSiteFile("layout{$suffix}.php"))
5174  )
5175  ) {
5176  $script = $file;
5177  }
5178  $this->_site->setCacheEntry($cache_key, $script);
5179  }
5180 
5181  return $layout;
5182  }
5183 
5190  public function getLayouts($skip = array()) {
5191  $layouts = $this->_site->getLayoutFiles($this->field['type'], $skip, $this->conf['layouts']);
5192 
5193  // Nur bestimmte Layouts sind für diese Page erlaubt
5194  $info = $this->getTypeInfo();
5195  if (!empty($info['layouts'])) {
5196  return array_intersect_key($layouts, array_flip(explode(',', $info['layouts'])));
5197  }
5198 
5199  // Bestimmte Layouts deaktivieren
5200  if (!empty($this->conf['layouts'])) {
5201  foreach ($this->conf['layouts'] as $layout => $conf) {
5202  if ($conf['disabled']) {
5203  unset($layouts[$layout]);
5204  }
5205  }
5206  }
5207 
5208  return $layouts;
5209  }
5210 
5220  public function getTemplate($mobile = false, $name = 'body', $variant = '') {
5221  return $this->_site->getTemplate($mobile, $name, $this->field['type'], $variant ? $variant : (string) $this->extra['_template']);
5222  }
5223 
5230  public function getContents($orient) {
5231  return $this->extra['_contents'][$orient];
5232  }
5233 
5245  public function getScripts() {
5246  $scripts = array(
5247  $GLOBALS['egotec_conf']['site_dir'] . $this->_site->name . '/index.php',
5248  $this->_site->getSiteFile($this->field['type'] . '/index.php')
5249  );
5250  if ($this->_site->globalAllowed()) {
5251  // Für diesen Mandanten ein globales Skript verwenden
5252  array_unshift($scripts, $GLOBALS['egotec_conf']['site_dir'] . '_global/index.php');
5253  }
5254  if (!empty($this->_site->theme)) {
5255  array_splice($scripts, 2, 0, $this->_site->getSiteFile('index.php', array('module', 'custom', 'global', 'parent_custom')));
5256  }
5257  $existing_scripts = [];
5258  foreach ($scripts as $script) {
5259  if ($script && Ego_System::file_exists($script)) {
5260  $existing_scripts[] = $script;
5261  }
5262  }
5263  return $existing_scripts;
5264  }
5265 
5273  public function hasBlock($block, $orient = '') {
5274  $n = 0;
5275  if (is_array($this->extra['_blocks'])) {
5276  foreach ($this->extra['_blocks'] as $_orient => $blocks) {
5277  if (!$orient || $orient == $_orient) {
5278  $values = array_count_values($blocks);
5279  if (isset($values[$block])) {
5280  $n += $values[$block];
5281  }
5282  }
5283  }
5284  }
5285  return $n;
5286  }
5287 
5296  public function getBlocks($orient, $variant = '', $page_frame = false) {
5297  // Keine Blöcke ausgeben
5298  if ($GLOBALS['__no_blocks']) {
5299  return '';
5300  }
5301 
5302  if ($variant == '') {
5303  if (isset($GLOBALS['_block_variant'])) {
5304  // Die Block Variante wird global weitergereicht
5305  $variant = $GLOBALS['_block_variant'];
5306  } elseif (in_array($_SERVER['REQUEST_SUFFIX'], array('.pdf', '.print'))) {
5307  // Block Varianten für .pdf und .print verwenden
5308  $variant = ltrim($_SERVER['REQUEST_SUFFIX'], '.');
5309  }
5310  }
5311  $layout = $this->extra['_layout'];
5312  $blocks = $this->extra['_blocks'][$orient];
5313 
5314  if (!is_array($blocks) || empty($blocks)) {
5315  // Standard Blöcke verwenden
5316  $blocks = array();
5317  if (empty($layout)) {
5318  $layout = $this->conf['default_layout']; // Standard Layout verwenden
5319  }
5320 
5321  if (!empty($this->conf['layouts'][$layout]['blocks'][$orient]['default'])) {
5322  // Standard Blöcke
5323  $blocks = explode(',', $this->conf['layouts'][$layout]['blocks'][$orient]['default']);
5324  }
5325  if (empty($blocks) && $orient == $this->mainOrient && empty($this->conf['no_template'])) {
5326  // Keine Blöcke und die Haupt-Orientierung: Immer das Standard Template verwenden
5327  $blocks[] = 'template';
5328  }
5329  }
5330 
5331  // Standard Template immer anzeigen, wenn
5332  if (
5333  $this->field['type'] != 'page' // ...nicht der Standard Seitentyp verwendet wird
5334  ) {
5335  // Der Seitentyp besitzt ein eigenes body Template und das Standard Template wird immer angezeigt
5336  // @TODO Nur wenn das Template aus dem Systemstandard kommt?
5337  $body_template = null;
5338  $default_template = $GLOBALS['egotec_conf']['lib_dir'] . 'type/skin/page/body.html';
5339  $get_body_template = function() use (&$body_template, $variant) {
5340  if (!$body_template) {
5341  $body_template = $this->getTemplate($GLOBALS['is_mobile'], 'body', $variant);
5342  }
5343  return $body_template;
5344  };
5345 
5346  // Das Standard Template darf nicht entfernt werden, wenn
5347  if (
5348  $this->conf['blocks']['template']['removable'] !== true // ...nicht explizit das Entfernen erlaubt ist
5349  && $get_body_template() != $default_template // ...der Seitentyp ein eigenes body Template besitzt
5350  ) {
5351  $this->conf['blocks']['template']['removable'] = false;
5352  }
5353 
5354  // Das Standard Template muss für nicht Standard Seitentypen immer vorhanden sein
5355  if (
5356  $orient == $this->mainOrient // ...nur für die Haupt-Orientierung
5357  && !in_array('template', $blocks) // ...und das Standard Template nicht bereits eingebunden wird
5358  && $this->conf['blocks']['template']['removable'] !== true // ...außer es darf explizit entfernt werden
5359  && $get_body_template() != $default_template // ...der Seitentyp ein eigenes body Template besitzt
5360  ) {
5361  $blocks[] = 'template';
5362  }
5363  }
5364 
5365  // HTML aller Blöcke zusammenfügen
5366  $html = '';
5367  if (!empty($blocks)) {
5368  foreach ($blocks as $index => $block) {
5369  if ($page_frame && $this->conf['blocks'][$block]['exclude']) {
5370  // Blöcke, die für die Einbindung als dynamischer Inhalt ignoriert werden sollen, überspringen
5371  continue;
5372  }
5373 
5374  $removable = !isset($this->conf['blocks'][$block]['removable']) || (bool) $this->conf['blocks'][$block]['removable'];
5375  $template = $this->getTemplateBlock($block, $orient, $index, false, false, $variant, $removable);
5376  if ($template === null) {
5377  // Block existiert nicht
5378  if ($GLOBALS['frontend_admin'] && $this->conf['orients'][$orient]['disabled'] !== true) {
5379  // Einen unbekannten Block darstellen
5380  $html .= $this->getTemplateBlock('unknown', $orient, $index, false, false, $variant, $removable);
5381  $this->extra['_blocks'][$orient][$index] = 'unknown';
5382  unset($this->extra['_contents'][$orient][$index]);
5383  }
5384  continue;
5385  }
5386  $html .= $template;
5387  }
5388  }
5389 
5390  // Formulare erweitern
5391  if (!empty($this->extra['_forms'][$orient])) {
5392  // Unsichtbare Formular Felder generieren
5393  if (!empty($this->extra['_forms'][$orient]['hidden'])) {
5394  require_once('base/Ego_Combo.php');
5395  $combo = new Ego_Combo($this->extra['_forms'][$orient]['hidden']);
5396  foreach ($combo->getData() as $field) {
5397  $html .= '<input type="hidden" name="' . $field->key . '" value="' . $field->value . '">';
5398  }
5399  }
5400 
5401  // Mehrfachversand verhindern
5402  require_once 'base/Ego_ValidateForm.php';
5403  $html .= Ego_ValidateForm::generateToken($orient);
5404  $html .= Ego_ValidateForm::generateCSRF($orient);
5405 
5406  // Seiten mit Formularen immer ohne Cache ausliefern, da sonst der eindeutige Token/CSRF mehrfach verwendet werden kann
5407  $this->field['cache'] = 0;
5408  }
5409 
5410  return $html;
5411  }
5412 
5420  public function getBlockList($layout = null, $template = false) {
5421  $skip = !$this->_site->globalAllowed() ? ['global'] : [];
5422  $cache_key = 'blockList_' . md5(serialize(array(
5423  $layout,
5424  $template,
5425  $this->field['type'],
5426  $skip,
5427  $this->_site->language,
5428  $GLOBALS['auth']->isNobody() ? '' : $GLOBALS['auth']->user->field['user_id']
5429  )));
5430  $blocks = $this->_site->getCacheEntry($cache_key);
5431 
5432  if ($blocks === null) {
5433  // Sicherstellen, dass Block Informationen immer mit den Backend Übersetzungen ermitteln werden
5434  $original_smarty = $GLOBALS['smarty'];
5435  unset($GLOBALS['translation'][$GLOBALS['t_language']]);
5436  $GLOBALS['smarty'] = Ego_Smarty::createAdmin($this->_site, array(
5437  'page' => $this
5438  ), true);
5439 
5440  $blocks = array();
5441 
5442  // Liste der verfügbaren Blöcke generieren
5443  $block_files = $this->_site->getBlockFiles($this->field['type'], $skip);
5444 
5445  // Systemeigene Blöcke hinzufügen
5446  $system_conf = Ego_System::getJSON($GLOBALS['egotec_conf']['lib_dir'] . 'page/conf.json');
5447  foreach ($system_conf['blocks'] as $block => $conf) {
5448  if ($block != 'template' && empty($this->conf['no_' . $block])) {
5449  if (!isset($this->conf['blocks'][$block])) {
5450  $this->conf['blocks'][$block] = $conf;
5451  } else {
5452  $this->conf['blocks'][$block] = array_merge($conf, $this->conf['blocks'][$block]);
5453  }
5454  $this->conf['blocks'][$block]['system'] = strpos($block, 'input_') === 0
5455  ? 'form'
5456  : 'system';
5457  $block_files[$block] = $conf['title'];
5458  }
5459  }
5460 
5461  $sort = array();
5462  foreach ($block_files as $block => $title) {
5463  if ($block == 'unknown') {
5464  continue;
5465  } elseif ($block == '_empty') {
5466  if (!empty($this->conf['no_template']) && !$template) {
5467  continue;
5468  }
5469  // Das Standard Template ist immer verfügbar
5470  $block = 'template';
5471  } elseif (empty($this->conf['blocks'][$block])) {
5472  $this->conf['blocks'][$block] = array();
5473  }
5474  if (strpos($block, 'input_') === 0) {
5475  // Formular Blöcke automatisch erweitern
5476  if (!isset($this->conf['blocks'][$block]['system'])) {
5477  $this->conf['blocks'][$block]['system'] = 'form';
5478  }
5479  if (!isset($this->conf['blocks'][$block]['group'])) {
5480  $this->conf['blocks'][$block]['group'] = 'Formular';
5481  }
5482  if (!isset($this->conf['blocks'][$block]['controls'])) {
5483  $this->conf['blocks'][$block]['controls'] = array();
5484  }
5485  array_unshift($this->conf['blocks'][$block]['controls'], array(
5486  'type' => 'input',
5487  'name' => substr(strrchr($block, '_'), 1)
5488  ));
5489  }
5490  $blocks[$block] = array(
5491  'title' => $GLOBALS['auth']->translate($this->conf['blocks'][$block]['title'] ? $this->conf['blocks'][$block]['title'] : $title),
5492  'description' => $GLOBALS['auth']->translate((string)$this->conf['blocks'][$block]['description']),
5493  'image' => $this->conf['blocks'][$block]['image'] ? $GLOBALS['egotec_conf']['url_dir'] . $this->conf['blocks'][$block]['image'] : '',
5494  'max' => (int)$this->conf['blocks'][$block]['max']
5495  );
5496  if (isset($this->conf['blocks'][$block]['index'])) {
5497  $blocks[$block]['index'] = (int)$this->conf['blocks'][$block]['index'];
5498  }
5499  if (!empty($this->conf['blocks'][$block]['uid'])) {
5500  $blocks[$block]['uid'] = $this->conf['blocks'][$block]['uid'];
5501  }
5502  if (!empty($this->conf['blocks'][$block]['system'])) {
5503  $blocks[$block]['system'] = $this->conf['blocks'][$block]['system'];
5504  }
5505  if ($controls = $this->getBlockControls($block)) {
5506  $blocks[$block]['controls'] = $controls;
5507  }
5508  if (!empty($this->conf['blocks'][$block]['group'])) {
5509  $groups = array();
5510  foreach (explode(',', $this->conf['blocks'][$block]['group']) as $group) {
5511  $groups[] = $GLOBALS['auth']->translate(trim($group));
5512  }
5513  $blocks[$block]['group'] = implode(',', $groups);
5514  }
5515  if (!empty($this->conf['blocks'][$block]['pattern'])) {
5516  $blocks[$block]['pattern'] = array();
5517  foreach (explode(',', $this->conf['blocks'][$block]['pattern']) as $index => $pattern) {
5518  if (preg_match_all('/\[([^:=]+?)(:([^=]+?))?(=(.+?))?\]/', $pattern, $matches)) {
5519  $blocks[$block]['pattern'][$index] = array();
5520  foreach ($matches[0] as $index2 => $match) {
5521  $width = $matches[1][$index2];
5522  $type = (string) $matches[3][$index2];
5523  $color = (string) $matches[5][$index2];
5524  $data = array(
5525  'width' => $width,
5526  'color' => $color
5527  );
5528  if (strpos($type, 'image:') === 0) {
5529  $data['image'] = $GLOBALS['egotec_conf']['url_dir'] . substr($type, 6);
5530  } else {
5531  $data['type'] = $type;
5532  }
5533  $blocks[$block]['pattern'][$index][] = $data;
5534  }
5535  }
5536  }
5537  }
5538 
5539  $sort[] = mb_strtolower($blocks[$block]['title']);
5540  }
5541 
5542  // Blöcke alphabetisch sortieren
5543  array_multisort($sort, SORT_ASC, SORT_REGULAR, $blocks);
5544 
5545  // Blöcke variabel sortieren
5546  $index = 0;
5547  $sort = array();
5548  foreach ($blocks as $block => $info) {
5549  switch ($block) {
5550  case 'page_frame':
5551  // Dynamischer Inhalt als letzter Block
5552  $i = sizeof($blocks) + 1;
5553  break;
5554  default:
5555  if (strpos($block, 'input_') === 0) {
5556  // Formular Elemente als vorletzte Blöcke
5557  $i = sizeof($blocks);
5558  } else {
5559  // Individuelle Position
5560  if (isset($info['index'])) {
5561  $i = (int)$info['index'];
5562  if ($i < 0) {
5563  // Negative Position ausgehend vom letzten Block
5564  $i = sizeof($blocks) - abs($i);
5565  }
5566  } elseif ($block == 'template') {
5567  // Standard Template als erster Block, wenn nichts anderes angegeben ist
5568  $i = 0;
5569  } else {
5570  $i = ++$index;
5571  }
5572  }
5573  }
5574  $sort[] = $i;
5575  }
5576  array_multisort($sort, SORT_ASC, SORT_NUMERIC, $blocks);
5577 
5578  if ($layout !== null) {
5579  // Alle Blöcke nach Orientierung gruppieren
5580  $block_list = array();
5581  if (!empty($this->conf['layouts'][$layout]['blocks'])) {
5582  foreach ($this->conf['layouts'][$layout]['blocks'] as $orient => $info) {
5583  $get_blocks = function ($block_list, $type) use ($layout, $info, &$get_blocks) {
5584  $blocks = array();
5585  if (!empty($info['extend_' . $type])) {
5586  $block_list .= ",{$info['extend_'.$type]}";
5587  }
5588  foreach (explode(',', $block_list) as $block) {
5589  if ($block[0] == '@') {
5590  // Blöcke einer anderen Orientierung für dieses Layout verwenden
5591  $orient_block_list = $this->conf['layouts'][$layout]['blocks'][substr($block, 1)][$type];
5592  if (!empty($orient_block_list)) {
5593  $blocks = array_merge($blocks, $get_blocks($orient_block_list, $type));
5594  }
5595  } else {
5596  $blocks[] = $block;
5597  }
5598  }
5599  return array_unique($blocks);
5600  };
5601 
5602  if (!empty($info['allow'])) {
5603  // Nur erlaubte Blöcke ausgeben
5604  $block_list[$orient] = array_intersect_key($blocks, array_flip($get_blocks($info['allow'], 'allow')));
5605  } elseif (!empty($info['disallow'])) {
5606  // Nicht erlaubte Blöcke nicht ausgeben
5607  $block_list[$orient] = array_diff_key($blocks, array_flip($get_blocks($info['disallow'], 'disallow')));
5608  }
5609  }
5610  }
5611  // Gruppierung nach Haupt-Orientierung muss immer existieren
5612  if (empty($block_list[$this->mainOrient])) {
5613  $block_list[$this->mainOrient] = $blocks;
5614  }
5615 
5616  $blocks = $block_list;
5617  }
5618 
5619  $this->_site->setCacheEntry($cache_key, $blocks);
5620  $GLOBALS['smarty'] = $original_smarty;
5621  }
5622 
5623  // Prüfen, ob dieses Layout Formulare beinhaltet
5624  $has_forms = array();
5625  if ($file = $this->getLayout(false, $layout)) {
5626  require_once('smarty/Ego_Smarty.php');
5627  $smarty = Ego_Smarty::createFrontend($this->_site, array(
5628  'page' => $this
5629  ), true);
5630  require_once('base/Ego_DomQuery.php');
5631  $smarty_clone = clone $smarty;
5632  $GLOBALS['__no_blocks'] = true; // Keine Blöcke ausgeben
5633  $domQuery = new Ego_DomQuery($smarty_clone->fetch($file));
5634  unset($GLOBALS['__no_blocks']);
5635 
5636  $forms = $domQuery->query('form');
5637  foreach ($forms as $form) {
5638  if ($orient = $form->getAttribute('data-edit-template')) {
5639  $has_forms[] = $orient;
5640  } else {
5641  // Verschachtelte Bereiche im Formular finden
5642  $descendants = $domQuery->xpath('*[@data-edit-template]', $form);
5643  foreach ($descendants as $descendant) {
5644  if ($orient = $descendant->getAttribute('data-edit-template')) {
5645  $has_forms[] = $orient;
5646  }
5647  }
5648  }
5649  }
5650  $has_forms = array_unique($has_forms);
5651  }
5652 
5653  // Formular Blöcke für bestimmte Orientierungen nicht zurückliefern
5654  $filter = function($blocks) {
5655  $filtered = array();
5656  foreach ($blocks as $key => $block) {
5657  if (strpos($key, 'input_') !== 0) {
5658  $filtered[$key] = $block;
5659  }
5660  }
5661  return $filtered;
5662  };
5663  if ($layout) {
5664  // Sicherstellen, dass die Orientierungen mit Formularen mindestens die Formular Blöcke anzeigen
5665  foreach ($has_forms as $orient) {
5666  if (empty($blocks[$orient])) {
5667  $blocks[$orient] = $blocks[$this->mainOrient];
5668  }
5669  foreach ($blocks[$this->mainOrient] as $key => $block) {
5670  if (strpos($key, 'input_') === 0 && !isset($blocks[$orient][$key])) {
5671  $blocks[$orient][$key] = $block;
5672  }
5673  }
5674  }
5675 
5676  foreach (array_keys($blocks) as $orient) {
5677  if (!in_array($orient, $has_forms)) {
5678  $blocks[$orient] = $filter($blocks[$orient]);
5679  }
5680  }
5681  } elseif (empty($has_forms)) {
5682  $blocks = $filter($blocks);
5683  }
5684 
5685  return $blocks;
5686  }
5687 
5694  private function getBlockControls($block) {
5695  if (isset($this->conf['blocks'][$block]['controls'])) {
5696  $controls = array();
5697  foreach ($this->conf['blocks'][$block]['controls'] as $control) {
5698  if ($control['name'][0] == '@') {
5699  // Steuerelement wird geerbt
5700  list($inherited_block, $name) = explode('.', substr($control['name'], 1));
5701  if (isset($this->conf['blocks'][$inherited_block]['controls'])) {
5702  foreach ($this->conf['blocks'][$inherited_block]['controls'] as $inherited_control) {
5703  if ($inherited_control['name'] == $name) {
5704  $merged_control = array_merge($inherited_control, $control);
5705  $merged_control['name'] = $inherited_control['name'];
5706  $controls[] = $merged_control;
5707  break;
5708  }
5709  }
5710  }
5711  } else {
5712  $controls[] = $control;
5713  }
5714  }
5715  return $controls;
5716  }
5717  return null;
5718  }
5719 
5733  public function getTemplateBlock($block = 'template', $orient = '', $index = 0, $empty = false, $replace = false, $variant = '', $removable = true, &$smarty = null) {
5734  if ($orient == '') {
5735  $orient = $this->mainOrient;
5736  }
5737  $html = $class = '';
5738  $custom_html = false;
5739  if (!$smarty) {
5740  require_once('smarty/Ego_Smarty.php');
5741  $smarty = Ego_Smarty::createFrontend($this->_site, array(
5742  'page' => $this
5743  ), true);
5744  }
5745 
5746  // Das globale Smarty Objekt für das Block Template mit dem eigenen Smarty Objekt überschreiben, falls innerhalb des Blocks darauf zugegriffen wird
5747  $original_smarty = $GLOBALS['smarty'] ? $GLOBALS['smarty'] : $smarty;
5748  $GLOBALS['smarty'] = $smarty;
5749 
5750  // Falls das Extrafeld hier nicht existiert, wird es initialisiert
5751  if (empty($this->extra)) {
5752  $this->extra = unserialize($this->field['extra']);
5753  }
5754 
5755  // Standardwerte für Block Elemente und Extrafeld setzen
5756  if ($empty && !empty($this->conf['blocks'][$block]['default'][$orient])) {
5757  $this->extra['_contents'][$orient][$index] = $this->conf['blocks'][$block]['default'][$orient];
5758  }
5759 
5760  if (is_array($this->extra['_contents'][$orient][$index]['extra'])) {
5761  // Block Extrafeld als $extra übergeben
5762  $extra = $this->extra['_contents'][$orient][$index]['extra'];
5763 
5764  // Leeres Datum nicht übergeben
5765  foreach ($extra as $key => $value) {
5766  if (in_array($value, array('0000-00-00', '0000-00-00 00:00:00'))) {
5767  unset($extra[$key]);
5768  }
5769  }
5770 
5771  if (strpos($block, 'input_') === 0) {
5772  // Formular Blöcke kriegen ihren ...
5773  if (isset($_POST[$extra['name']])) {
5774  // ... aktuellen Wert übergeben
5775  $smarty->assign('value', $_POST[$extra['name']]);
5776  if (isset($_POST[$extra['name'] . '_input'])) {
5777  $smarty->assign('value_input', $_POST[$extra['name'] . '_input']);
5778  }
5779  } elseif ($block == 'input_checkbox') {
5780  // ... aktuellen Wert übergeben (Checkbox Listen)
5781  $values = array();
5782  require_once 'base/Ego_Combo.php';
5783  $combo = new Ego_Combo($extra['values']);
5784  $new_data = array();
5785  foreach ($combo->getData() as $data) {
5786  if (isset($_POST[$data->field_name])) {
5787  $values[] = $data->field_name;
5788  }
5789 
5790  // Darstellung für required/optional Checkboxen in Formular Blöcken
5791  foreach (array('required', 'optional') as $type) {
5792  if ($data->{$type}) {
5793  $data->label = $GLOBALS['smarty']->fetch('string:' . str_replace('<%>', $data->label, $this->conf['form'][$type] ?? $data->label));
5794  }
5795  }
5796  $new_data[] = $data;
5797  }
5798 
5799  // Geänderte Daten übernehmen
5800  $combo->setData($new_data);
5801  $extra['values'] = $combo->getString();
5802 
5803  $smarty->assign('values', $values);
5804  } elseif (empty($_POST['sendform'][$orient]) && isset($extra['default'])) {
5805  // ... Standardwert übergeben
5806  $smarty->assign('value', $extra['default']);
5807  }
5808 
5809  // Regulärer Ausdruck für die E-Mail Validierung
5810  $smarty->assign(array(
5811  'email_pattern' => Ego_System::REGEX_EMAIL,
5812  'email_pattern_optional' => Ego_System::REGEX_EMAIL_OPTIONAL,
5813  'pattern_optional' => $extra['regex'] ? '$|' . $extra['regex'] : ''
5814  ));
5815  }
5816 
5817  $smarty->assign('extra', $extra);
5818  }
5819  unset($smarty->_plugins['outputfilter'], $smarty->autoload_filters['output']);
5820 
5821  // Diesen Block in der Frontend Administration anzeigen
5822  $frontend_admin = $GLOBALS['frontend_admin'] && $this->conf['orients'][$orient]['disabled'] !== true;
5823 
5824  if ($block == 'template') {
5825  // Das Template des Seitentyps
5826  $html .= $this->fetch(array(
5827  '_layout' => $this->extra['_layout'],
5828  '_orient' => $orient,
5829  '_index' => $index,
5830  '_block' => $block,
5831  '_empty' => $empty,
5832  '_replace' => $replace,
5833  '_page' => &$this
5834  ), false, (bool) $GLOBALS['__egotec_edit_request'], false, $variant);
5835  } else {
5836  // Ein bestimmtes Template
5837  $block_found = false;
5838  $suffixes = array('.tpl', '.html');
5839  if ($variant) {
5840  // Block Varianten zuerst suchen
5841  array_unshift($suffixes, ".{$variant}.tpl", ".{$variant}.html");
5842  }
5843  foreach ($suffixes as $file_suffix) {
5844  if (
5845  ($file = $this->_site->getSkinFile("{$this->field['type']}/blocks/{$block}{$file_suffix}"))
5846  || ($file = $this->_site->getSkinFile("blocks/{$block}{$file_suffix}"))
5847  || (
5848  $file_suffix == '.tpl' // Systemeigenes Template
5849  && ($system_file = $GLOBALS['egotec_conf']['lib_dir'] . "page/t/blocks/{$block}{$file_suffix}")
5850  && Ego_System::file_exists($system_file)
5851  && ($file = $system_file)
5852  )
5853  ) {
5854  $this->blockProperties = array(
5855  '_layout' => $this->extra['_layout'],
5856  '_orient' => $orient,
5857  '_index' => $index,
5858  '_block' => $block,
5859  '_empty' => $empty,
5860  '_replace' => $replace,
5861  '_uid' => ($uid = $this->extra['_contents'][$orient][$index]['_uid'])
5862  );
5863  $smarty->assign(array_merge(
5864  $this->blockProperties,
5865  array('_page' => &$this)
5866  ));
5867 
5873  $include_script = function() use ($block, $orient, $index, $extra, $smarty, $uid) {
5874  if (
5875  ($file = $this->_site->getSiteFile("{$this->field['type']}/blocks/{$block}.php"))
5876  || ($file = $this->_site->getSiteFile("blocks/{$block}.php"))
5877  ) {
5878  // Weitere Variablen im Skript verfügbar machen
5879  $page = $this;
5880  $site = $page->getSite();
5881  $auth = $GLOBALS['auth'];
5882 
5883  require $file;
5884  }
5885  };
5886  $include_script();
5887 
5888  if ($controls = $this->getBlockControls($block)) {
5889  $domQuery = null;
5890  $dom = function() use ($smarty, $file) {
5891  require_once('base/Ego_DomQuery.php');
5892  $smarty_clone = clone $smarty;
5893  return new Ego_DomQuery($smarty_clone->fetch($file));
5894  };
5895 
5896  foreach ($controls as $control) {
5897  switch ($control['type']) {
5898  // Block kann um Elemente erweitert werden
5899  case 'attach':
5900  // Template generieren
5901  $custom_html = true;
5902 
5903  // Anzahl anzuzeigender Elemente ermitteln
5904  $max = 0;
5905  if (!$empty && !empty($this->extra['_contents'][$orient][$index][$control['name']])) {
5906  $max = sizeof($this->extra['_contents'][$orient][$index][$control['name']]);
5907  }
5908  if ($frontend_admin && !$control['optional'] && $max == 0) {
5909  // Wenn keine Elemente vorhanden sind, dann x Elemente automatisch erzeugen
5910  $max = $control['start'] ?? 1;
5911  }
5912 
5913  foreach ($control['elements'] as $element) {
5914  $n = 0;
5915  $items = '';
5916  $multiple_items = is_array($element['items']);
5917  while ($n < $max) {
5918  $i = 0;
5919  if ($multiple_items) {
5920  $j = 0;
5921  if (isset($this->extra['_contents'][$orient][$index][$control['name']][$n]['_type'])) {
5922  $j = (int) $this->extra['_contents'][$orient][$index][$control['name']][$n]['_type'];
5923  }
5924  $item = $element['items'][$j]['item'];
5925  $values = $element['items'][$j]['values'];
5926  } else {
5927  $item = $element['item'];
5928  $values = $element['values'];
5929  }
5930  $items .= $smarty->fetch('string:' . preg_replace_callback('/<%>/', function () use ($values, $n, &$i, $control) {
5931  // Smarty {value} erzeugen
5932  $func = '{value';
5933  foreach ($values[$i] as $attr => $value) {
5934  if ($attr == 'var') {
5935  $value = "{$control['name']}][$n][$value";
5936  }
5937  if (is_array($value)) {
5938  foreach ($value as $sub_attr => $sub_value) {
5939  $func .= " {$attr}.{$sub_attr}=\"{$sub_value}\"";
5940  }
5941  } else {
5942  $func .= " {$attr}=\"{$value}\"";
5943  }
5944  }
5945  $func .= '}';
5946  $i++;
5947  return $func;
5948  }, str_replace('<#>', $n, $item)
5949  )
5950  );
5951 
5952  // Erstes Element aktiv setzen
5953  if ($n == 0 && $element['active']) {
5954  $domQuery2 = new Ego_DomQuery($items);
5955  $nodes = $domQuery2->query($element['active']['selector']);
5956  foreach ($nodes as $node) {
5957  if ($element['active']['attribute'] == 'class') {
5958  if ($className = $node->getAttribute('class')) {
5959  $classes = explode(' ', $className);
5960  } else {
5961  $classes = array();
5962  }
5963  $classes[] = $element['active']['value'];
5964  $node->setAttribute('class', implode(' ', $classes));
5965  } else {
5966  $node->setAttribute($element['active']['attribute'], $element['active']['value']);
5967  }
5968  $items = $domQuery2->getHTML();
5969  break;
5970  }
5971  }
5972 
5973  $n++;
5974  }
5975 
5976  // Platzhalter mit Smarty und HTML ersetzen
5977  if ($domQuery === null) {
5978  $domQuery = $dom();
5979  }
5980  $domQuery->setInnerHTML($domQuery->query($element['selector']), function($node) use ($items) {
5981  return $items;
5982  });
5983  }
5984  break;
5985 
5986  // Eine Seite auswählen und die Daten im Block verwenden
5987  case 'page':
5988  $identity = $this->extra['_contents'][$orient][$index][$control['name']];
5989  if (!empty($identity) && ($data = Page::byIdentity($identity))) {
5990  $smarty->assign($control['name'], $data);
5991  }
5992  break;
5993 
5994  // Block kann den Wert eines Nodes ändern
5995  case 'option':
5996  $value = $this->extra['_contents'][$orient][$index][$control['name']];
5997  if (
5998  (
5999  $control['attribute'] == '#text'
6000  || $control['preset'] == 'materialize'
6001  )
6002  && !empty($value)
6003  ) {
6004  $domQuery = $dom();
6005  $domQuery->setInnerHTML($domQuery->query($control['selector']), function($node) use ($value, &$custom_html) {
6006  $custom_html = true;
6007  return $value;
6008  });
6009  }
6010  }
6011  }
6012 
6013  if ($domQuery && $custom_html) {
6014  $html .= $domQuery->getHTML();
6015  }
6016  }
6017 
6018  if (!$custom_html) {
6019  // Template ausgeben
6020  $html .= $smarty->fetch($file);
6021  }
6022 
6023  unset($this->blockProperties);
6024  $block_found = true;
6025  break;
6026  }
6027  }
6028 
6029  if (!$block_found) {
6030  // Block existiert nicht
6031  $GLOBALS['smarty'] = $original_smarty;
6032  return null;
6033  }
6034  }
6035 
6036  // Sprungmarke platzieren
6037  if (!empty($this->extra['_contents'][$orient][$index]['_anchor'])) {
6038  $html = "<a id=\"{$this->extra['_contents'][$orient][$index]['_anchor']}\"></a>\n" . $html;
6039  }
6040 
6041  // Bei einem Formular Block das Template erweitern
6042  if ($this->conf['form']['wrapper'] && strpos($block, 'input_') === 0) {
6043  if (is_array($this->conf['form']['values'])) {
6044  // Der Wrapper führt weitere {value} Elemente ein
6045  $element = $this->conf['form'];
6046  $i = 0;
6047  $html = $smarty->fetch('string:' . preg_replace_callback('/<%>/', function() use ($element, &$i, $html, $block) {
6048  if (empty($element['values'][$i])) {
6049  // Ein leeres Element markiert wo der eigentliche Formular Block eingefügt wird
6050  return $html;
6051  } else {
6052  // Smarty {value} erzeugen
6053  $func = '{value';
6054  foreach ($element['values'][$i] as $attr => $value) {
6055  if (is_array($value)) {
6056  foreach ($value as $sub_attr => $sub_value) {
6057  $func .= " {$attr}.{$sub_attr}=\"{$sub_value}\"";
6058  }
6059  } else {
6060  $func .= " {$attr}=\"{$value}\"";
6061  }
6062  }
6063  $func .= '}';
6064  }
6065  $i++;
6066  return $func;
6067  }, $this->conf['form']['wrapper']));
6068  } else {
6069  $html = str_replace('<%>', $html, $this->conf['form']['wrapper']);
6070  }
6071 
6072  // Formular Block wird unterteilt
6073  $columns = $this->extra['_contents'][$orient][$index]['extra']['_columns'];
6074  if (!$columns) {
6075  $columns = (string) $this->conf['form']['columns']['default'];
6076  }
6077  $columns = rtrim(' ' . $columns);
6078 
6079  $html = str_replace(
6080  '<|>',
6081  $frontend_admin
6082  ? '' // Im Backend wird die Unterteilung auf das Block Element angewendet
6083  : $columns,
6084  $html
6085  );
6086  }
6087 
6088  // Standard Block HTML modifizieren
6089  if (!empty($this->conf['blocks'][$block]['modify'])) {
6090  require_once('base/Ego_DomQuery.php');
6091  $domQuery = new Ego_DomQuery($html);
6092  $domQuery->setSmarty($smarty);
6093 
6094  foreach ($this->conf['blocks'][$block]['modify'] as $modify) {
6095  $domQuery->modify($modify);
6096  }
6097 
6098  $html = $domQuery->getHTML();
6099  }
6100 
6101  $GLOBALS['smarty'] = $original_smarty;
6102 
6103  // CSS Klasse für diesen Block automatisch setzen
6104  if (!empty($this->conf['blocks'][$block]['class'])) {
6105  $class = $this->conf['blocks'][$block]['class'];
6106  }
6107 
6108  if (!$frontend_admin || !$this->isCurrentPage()) {
6109  return trim($class ? '<div class="' . $class . '">' . $html . '</div>' : $html);
6110  }
6111 
6112  // CSS Klasse für die Unterteilung wird im Backend auf das Block Element angewendet
6113  if ($frontend_admin && !empty($columns)) {
6114  $class = trim($class . $columns);
6115  }
6116 
6117  if ($frontend_admin && trim($html) == '' && $this->isCurrentPage()) {
6118  // Damit leere Elemente bedient werden können, erhalten diese einen Platzhalter
6119  $title = $block;
6120  if ($this->conf['blocks'][$block]['title']) {
6121  $title = $GLOBALS['auth']->translate($this->conf['blocks'][$block]['title']);
6122  }
6123  $html = '<div data-edit-placeholder="' . $title . '"></div>';
6124  }
6125 
6126  // Zugehörige Gruppe bestimmen
6127  if (strpos($block, 'input_') === 0 && !isset($this->conf['blocks'][$block]['group'])) {
6128  // Formular Blöcke automatisch erweitern
6129  $this->conf['blocks'][$block]['group'] = 'Formular';
6130  }
6131  $group = (string) $this->conf['blocks'][$block]['group'];
6132  if ($group) {
6133  $group = $GLOBALS['auth']->translate($group);
6134  }
6135 
6136  return trim(($frontend_admin ? '<div data-edit-block="' . $block . '" data-edit-block-index="' . $index . '"'
6137  . (
6138  ($group ? ' data-edit-group="' . $group . '"' : '')
6139  . (!$removable ? ' data-edit-static="true"' : '')
6140  . (!empty($columns) ? ' data-edit-columns="true"' : '')
6141  ) : '<div')
6142  . ($class ? ' class="' . $class . '"' : '')
6143  . '>' . $html . '</div>');
6144  }
6145 
6151  public function inheritBlocks() {
6152  if (!empty($this->conf['layouts'][$this->extra['_layout']]['inherit'])) {
6153  foreach (explode(',', $this->conf['layouts'][$this->extra['_layout']]['inherit']) as $orient) {
6154  $blocks_key = implode(array('_blocks', $orient), '.');
6155  $contents_key = implode(array('_contents', $orient), '.');
6156  $extra = $this->inheritExtra(array($blocks_key, $contents_key));
6157  if ($extra[$blocks_key] !== null) {
6158  $checksum_blocks = Ego_System::getChecksum($extra[$blocks_key]);
6159  $checksum_original = Ego_System::getChecksum($this->extra['_blocks'][$orient]);
6160 
6161  if ($checksum_blocks != $checksum_original) {
6162  $checksum_contents = Ego_System::getChecksum($extra[$contents_key]);
6163  $this->extra['_inherited'][$orient] = array(
6164  'blocks' => $checksum_blocks,
6165  'contents' => $checksum_contents
6166  );
6167  }
6168  }
6169  foreach ($extra as $key => $value) {
6170  $this->extra[strstr($key, '.', true)][$orient] = $value;
6171  }
6172  }
6173  }
6174  }
6175 
6182  public function getFormats($type = '') {
6183  // Standard Formate
6184  $formats = [
6185  'headers' => [
6186  'title' => 'Headers',
6187  'items' => [
6188  ['title' => 'Header 1', 'format' => 'h1'],
6189  ['title' => 'Header 2', 'format' => 'h2'],
6190  ['title' => 'Header 3', 'format' => 'h3'],
6191  ['title' => 'Header 4', 'format' => 'h4'],
6192  ['title' => 'Header 5', 'format' => 'h5'],
6193  ['title' => 'Header 6', 'format' => 'h6']
6194  ]
6195  ],
6196  'inline' => [
6197  'title' => 'Inline',
6198  'items' => [
6199  ['title' => 'Bold', 'icon' => 'bold', 'format' => 'bold'],
6200  ['title' => 'Italic', 'icon' => 'italic', 'format' => 'italic'],
6201  ['title' => 'Underline', 'icon' => 'underline', 'format' => 'underline'],
6202  ['title' => 'Strikethrough', 'icon' => 'strikethrough', 'format' => 'strikethrough'],
6203  ['title' => 'Superscript', 'icon' => 'superscript', 'format' => 'superscript'],
6204  ['title' => 'Subscript', 'icon' => 'subscript', 'format' => 'subscript'],
6205  ['title' => 'Code', 'icon' => 'code', 'format' => 'code']
6206  ]
6207  ],
6208  'blocks' => [
6209  'title' => 'Blocks',
6210  'items' => [
6211  ['title' => 'Paragraph', 'format' => 'p'],
6212  ['title' => 'Blockquote', 'format' => 'blockquote'],
6213  ['title' => 'Div', 'format' => 'div'],
6214  ['title' => 'Pre', 'format' => 'pre']
6215  ]
6216  ],
6217  'alignment' => [
6218  'title' => 'Alignment',
6219  'items' => [
6220  ['title' => 'Left', 'icon' => 'alignleft', 'format' => 'alignleft'],
6221  ['title' => 'Center', 'icon' => 'aligncenter', 'format' => 'aligncenter'],
6222  ['title' => 'Right', 'icon' => 'alignright', 'format' => 'alignright'],
6223  ['title' => 'Justify', 'icon' => 'alignjustify', 'format' => 'alignjustify']
6224  ]
6225  ]
6226  ];
6227 
6228  // Individuelle Formate
6229  if (isset($this->conf['formats'])) {
6230  $custom_formats = $type && isset($this->conf['formats'][$type])
6231  ? $this->conf['formats'][$type] // Formate für einen bestimmten Editor anpassen
6232  : $this->conf['formats']['default']; // Formate für alle Editoren anpassen
6233  if (is_array($custom_formats)) {
6234  foreach ($custom_formats as $name => $values) {
6235  // Wenn es die Format Liste gibt, wird sie erweitert/überschrieben
6236  if (isset($formats[$name])) {
6237  // Standard Formate überschreiben
6238  if ($custom_formats[$name]['options']) {
6239  $new_items = array();
6240  foreach (explode(',', $custom_formats[$name]['options']) as $option) {
6241  foreach ($formats[$name]['items'] as $item) {
6242  if ($item['format'] == $option) {
6243  // Die Sortierung der Standard Formate entspricht der angegebenen Reihenfolge
6244  $new_items[] = $item;
6245  break;
6246  }
6247  }
6248  }
6249  $formats[$name]['items'] = $new_items;
6250  }
6251 
6252  if (isset($custom_formats[$name]) && empty($custom_formats[$name])) {
6253  // Wenn es keine Formate gibt, wird auch keine Liste angezeigt
6254  unset($formats[$name]);
6255  } elseif (isset($custom_formats[$name]['items'])) {
6256  // Formate nur bearbeiten, wenn es eigene gibt
6257  $items = array();
6258 
6259  if (!empty($custom_formats[$name]['merge'])) {
6260  // Formate erweitern vorhandene Formate
6261  foreach ($formats[$name]['items'] as $item) {
6262  if (is_array($custom_formats[$name]['items'])) {
6263  foreach ($custom_formats[$name]['items'] as $new_item) {
6264  if ($item['title'] == $new_item['title']) {
6265  $items[] = $new_item;
6266  continue 2;
6267  }
6268  }
6269  }
6270  $items[] = $item;
6271  }
6272  }
6273  // Neue Formate hinzufügen
6274  if (is_array($custom_formats[$name]['items'])) {
6275  foreach ($custom_formats[$name]['items'] as $new_item) {
6276  foreach ($formats[$name]['items'] as $item) {
6277  if ($new_item['title'] == $item['title']) {
6278  continue 2;
6279  }
6280  }
6281  $items[] = $new_item;
6282  }
6283  }
6284  if (!empty($items)) {
6285  $formats[$name] = array(
6286  'title' => $formats[$name]['title'],
6287  'items' => $items
6288  );
6289  } else {
6290  // Wenn es keine Formate gibt, wird auch keine Liste angezeigt
6291  unset($formats[$name]);
6292  }
6293  }
6294  } else {
6295  // Neue Format Liste hinzufügen
6296  $formats[$name] = $values;
6297  }
6298  }
6299  }
6300  }
6301 
6302  return array_values($formats);
6303  }
6304 
6311  public function getToolbar($type = '') {
6312  $result = array(
6313  'plugins' => '',
6314  'menubar' => '',
6315  'toolbar' => '',
6316  'contextmenu' => ''
6317  );
6318 
6319  // Standard Toolbar
6320  switch ($type) {
6321  case 'editor':
6322  $result['plugins'] = 'noneditable advlist autolink lists link image charmap anchor searchreplace visualblocks visualchars code media table contextmenu paste importcss '
6323  . 'egotecSpellchecker egotecPageFrame egotecImageScale egotecList egotecMaxLength egotecIcons';
6324  $result['menubar'] = 'edit insert view table tools';
6325  $result['toolbar'] = 'styleselect removeformat | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | media image link unlink | egotecSpellchecker';
6326  break;
6327 
6328  case 'content':
6329  $result['plugins'] = 'noneditable advlist autolink lists link charmap anchor searchreplace visualblocks visualchars contextmenu paste importcss '
6330  . 'egotecSpellchecker egotecList egotecMaxLength egotecIcons';
6331  $result['menubar'] = 'edit insert view tools';
6332  $result['toolbar'] = 'styleselect removeformat | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link unlink | egotecSpellchecker';
6333  break;
6334 
6335  case 'minimal':
6336  $result['plugins'] = 'noneditable autolink link anchor contextmenu paste '
6337  . 'egotecSpellchecker';
6338  $result['toolbar'] = 'bold italic | link unlink | egotecSpellchecker';
6339  break;
6340 
6341  case 'table':
6342  $result['plugins'] = 'noneditable advlist autolink lists link charmap anchor searchreplace visualblocks visualchars table contextmenu paste importcss '
6343  . 'egotecSpellchecker egotecList egotecMaxLength';
6344  $result['menubar'] = 'edit insert view tools';
6345  $result['toolbar'] = 'styleselect removeformat | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link unlink | egotecSpellchecker';
6346  break;
6347 
6348  case 'text':
6349  $result['plugins'] = 'paste '
6350  . 'egotecSpellchecker egotecPlainText egotecMaxLength';
6351  $result['toolbar'] = 'egotecSpellchecker';
6352  }
6353 
6354  // Alle Editor verwenden das selbe Kontextmenü
6355  $result['contextmenu'] = 'link openlink image inserttable | cell row column deletetable';
6356 
6357  if ($this->_site->hasRight("admin")) {
6358  // Quelltext Plugin hinzufügen
6359  $result['plugins'] .= ' code';
6360  }
6361 
6362  // Individuelle Toolbar
6363  if (!empty($this->conf['toolbar'])) {
6364  $custom_toolbar = $this->conf['toolbar'][$type];
6365  foreach (array_keys($result) as $name) {
6366  if (isset($custom_toolbar[$name])) {
6367  if (in_array($custom_toolbar[$name], ['', false], true)) {
6368  $result[$name] = false;
6369  } elseif (preg_match_all('/[+-]?[^+-]+/', $custom_toolbar[$name], $matches) !== false) {
6370  foreach ($matches[0] as $toolbar) {
6371  $toolbar = trim(str_replace(',', ' ', rtrim($toolbar, ',')), ' |');
6372  if (strpos($toolbar, '+') === 0) {
6373  // Eigenschaften hinzufügen
6374  $result[$name] .= ' ' . substr($toolbar, 1);
6375  } elseif (strpos($toolbar, '-') === 0) {
6376  // Eigenschaften entfernen
6377  $pattern = '/(^| )(' . str_replace(' ', '|', preg_quote(substr($toolbar, 1))) . ')(|$)/';
6378  $result[$name] = preg_replace($pattern, '', $result[$name]);
6379  } else {
6380  // Eigenschaften überschreiben
6381  $result[$name] = $toolbar;
6382  }
6383  }
6384  }
6385  }
6386  }
6387  }
6388 
6389  return $result;
6390  }
6391 
6398  public function getHtml($root = false) {
6399  $html = '';
6400  $type_path = explode('/', $this->field['type']);
6401  $variant = '';
6402  if ($this->extra['_style']) {
6403  $variant = '.'.$this->extra['_style'];
6404  }
6405  $suffix = $_SERVER['REQUEST_SUFFIX'] != '.html' ? $_SERVER['REQUEST_SUFFIX'] : '';
6406  $current_path = '';
6407  foreach($type_path as $path) {
6408  $current_path .= $path.'/';
6409  if (
6410  ($suffix != '' && ($src = $this->_site->getSkinFile($current_path.'style'.$suffix.'.css', array('system'), true)))
6411  || ($variant != '' && ($src = $this->_site->getSkinFile($current_path.'style'.$variant.'.css', array('system'), true)))
6412  || ($src = $this->_site->getSkinFile($current_path.'style.css', array('system'), true))
6413  ) {
6414  $html .= Ego_System::includeHtml($src);
6415  }
6416  if ($src = $this->_site->getSkinFile($current_path.'script.js', array(), true)) {
6417  $html .= Ego_System::includeHtml($src);
6418  }
6419  }
6420 
6421  // style.css und script.js aus dem root Verzeichnis einbinden
6422  if ($root) {
6423  if (
6424  ($suffix != '' && ($src = $this->_site->getSkinFile('style'.$suffix.'.css', array('system'), true)))
6425  || ($variant != '' && ($src = $this->_site->getSkinFile('style'.$variant.'.css', array('system'), true)))
6426  || ($src = $this->_site->getSkinFile('style.css', array('system'), true))
6427  ) {
6428  $html .= Ego_System::includeHtml($src);
6429  }
6430  if ($src = $this->_site->getSkinFile('script.js', array('system'), true)) {
6431  $html .= Ego_System::includeHtml($src);
6432  }
6433  }
6434 
6435  return $html;
6436  }
6437 
6444  protected function getOrient($orient = null) {
6445  if ($orient === null) {
6446  $orient = $this->mainOrient; // Standardwert
6447  if (isset($this->blockProperties['_orient'])) {
6448  $orient = $this->blockProperties['_orient'];
6449  }
6450  }
6451  return $orient;
6452  }
6453 
6460  protected function getIndex($index = null) {
6461  if ($index === null) {
6462  $index = 0; // Standardwert
6463  if (isset($this->blockProperties['_index'])) {
6464  $index = $this->blockProperties['_index'];
6465  }
6466  }
6467  return $index;
6468  }
6469 
6479  public function getValue($name, $orient = null, $index = null, $verbose = false) {
6480  // Orientierung und Index automatisch setzen
6481  $orient = $this->getOrient($orient);
6482  $index = $this->getIndex($index);
6483  $extra = unserialize($this->field['extra']);
6484 
6485  $value = Ego_System::getAssocValue($extra, implode('.', array('_contents', $orient, $index, $name)));
6486  if ($value !== null) {
6487  if ($verbose) {
6488  // Alle zugehörigen Werte ebenfalls zurückliefern
6489  $array = array(
6490  'value' => $value
6491  );
6492  if (($pos = strrpos($name, '.')) !== false) {
6493  $key = implode('.', array('_contents', $orient, $index, substr($name, 0, $pos)));
6494  $name = substr($name, $pos + 1);
6495  } else {
6496  $key = implode('.', array('_contents', $orient, $index));
6497  }
6498  $values = Ego_System::getAssocValue($extra, $key);
6499  if (is_array($values)) {
6500  foreach ($values as $key => $value) {
6501  if (strpos($key, "{$name}_") === 0) {
6502  $array[substr($key, strlen("{$name}_"))] = $value;
6503  }
6504  }
6505  }
6506  return $array;
6507  } else {
6508  return $value;
6509  }
6510  }
6511  return null;
6512  }
6513 
6522  public function getValues($name, $orient = null, $verbose = false) {
6523  // Orientierung automatisch setzen
6524  $orient = $this->getOrient($orient);
6525 
6526  $values = array();
6527  if (is_array($this->extra['_contents'][$orient])) {
6528  $list = $this->extra['_contents'][$orient];
6529  if (is_array($list)) {
6530  foreach (array_keys($list) as $index) {
6531  $value = $this->getValue($name, $orient, $index, $verbose);
6532  if ($value !== null) {
6533  $values[] = $value;
6534  }
6535  }
6536  }
6537  }
6538  return $values;
6539  }
6540 
6549  public function getFirstValue($name, $orient = null, $verbose = false) {
6550  // Orientierung automatisch setzen
6551  $orient = $this->getOrient($orient);
6552 
6553  if (is_array($this->extra['_contents'][$orient])) {
6554  $list = $this->extra['_contents'][$orient];
6555  if (is_array($list)) {
6556  foreach (array_keys($list) as $index) {
6557  $value = $this->getValue($name, $orient, $index, $verbose);
6558  if ($value !== null) {
6559  return $value;
6560  }
6561  }
6562  }
6563  }
6564  return null;
6565  }
6566 
6577  public function getBlockValue($block, $name, $orient = null, $index = null, $verbose = false) {
6578  // Orientierung und Index automatisch setzen
6579  $orient = $this->getOrient($orient);
6580  $index = $this->getIndex($index);
6581 
6582  if ($this->extra['_blocks'][$orient][$index] == $block) {
6583  $value = $this->getValue($name, $orient, $index, $verbose);
6584  if ($value !== null) {
6585  return $value;
6586  }
6587  }
6588  return null;
6589  }
6590 
6600  public function getBlockValues($block, $name, $orient = null, $verbose = false) {
6601  // Orientierung automatisch setzen
6602  $orient = $this->getOrient($orient);
6603 
6604  $values = array();
6605  if (is_array($this->extra['_blocks'][$orient])) {
6606  foreach ($this->extra['_blocks'][$orient] as $index => $block_name) {
6607  if ($block_name == $block) {
6608  $value = $this->getValue($name, $orient, $index, $verbose);
6609  if ($value !== null) {
6610  $values[] = $value;
6611  }
6612  }
6613  }
6614  }
6615  return $values;
6616  }
6617 
6627  public function getFirstBlockValue($block, $name, $orient = null, $verbose = false) {
6628  // Orientierung automatisch setzen
6629  $orient = $this->getOrient($orient);
6630 
6631  if (is_array($this->extra['_blocks'][$orient])) {
6632  foreach ($this->extra['_blocks'][$orient] as $index => $block_name) {
6633  if ($block_name == $block) {
6634  $value = $this->getValue($name, $orient, $index, $verbose);
6635  if ($value !== null) {
6636  return $value;
6637  }
6638  }
6639  }
6640  }
6641  return null;
6642  }
6643 
6651  public function merge($id) {
6652  $original_page = $this->_site->getPage($id, array(
6653  'auth_or' => '1=1',
6654  'deleted_or' => '1=1',
6655  'inactive' => true,
6656  'only_active' => false
6657  ));
6658  if (!$original_page) {
6659  return null;
6660  }
6661  $field = $this->field;
6662  $extra = $this->extra;
6663 
6664  unset($field['children']);
6665  if ($field['children_order'] == 'children') {
6666  // Die Reihenfolge der Kinder neu festlegen
6667  $children_list = array();
6668  $original_children = explode(',', trim($extra['original_children'], ','));
6669  $current_children = $original_page->getChildren(array(), array('auth_or' => '1=1'));
6670  $current_children_list = array();
6671  foreach ($current_children as $child) {
6672  $current_children_list[] = $child->field['id'];
6673  }
6674  foreach ($original_children as $child_id) {
6675  $key = array_search($child_id, $current_children_list);
6676  if ($key !== false) {
6677  $children_list[] = $child_id;
6678  unset($current_children_list[$key]);
6679  }
6680  }
6681  $children_list = array_merge($children_list, $current_children_list);
6682  }
6683 
6684  $field['inactive'] = $extra['original_inactive'];
6685 
6687  unset(
6688  $extra['original_id'],
6689  $extra['original_children'], // @TODO Die original_children werden nicht gelöscht
6690  $extra['original_inactive'],
6691  $extra['workflow_page']
6692  );
6693  if ($extra['original_parents']) {
6694  $original_parents = $extra['original_parents'];
6695  unset($extra['original_parents']);
6696  }
6697 
6698  // Alle neu erstellten Kinder auf das Original übertragen.
6699  $children = $this->getChildren();
6700  foreach ($children as $child) {
6701  $child->move($this->field['id'], $original_page->field['id']);
6702  $child->updateField(array('inactive' => self::ACTIVE_FLAG));
6703  }
6704 
6705  unset($field['id']);
6706  unset($field['parents']);
6707  unset($field['workflow_state']);
6708  if (isset($original_page->field['workflow'])) {
6709  $field['workflow'] = $original_page->field['workflow'];
6710  } else {
6711  unset($field['workflow']);
6712  }
6713  if (isset($original_page->extra['workflows'])) {
6714  $extra['workflows'] = $original_page->extra['workflows'];
6715  } else {
6716  unset($extra['workflows']);
6717  }
6718 
6719  // Ist die Zielseite eine Freigabekopie, dann wird dieser Status beibehalten
6720  if (!$original_page->isReleaseCopy()) {
6721  unset($extra['release_id']);
6722  if ($field['inactive'] == self::RELEASE_FLAG) {
6723  $field['inactive'] = 0;
6724  }
6725  }
6726 
6727  if (!is_numeric($field['inactive'])) {
6728  $field['inactive'] = 0; // Im Zweifel immer aktivieren
6729  }
6730  // Liegt das Freigabe ab Datum in der Zukunft, wird es entfernt (nur für Freigabekopien)
6731  if ($this->isReleaseCopy() && $field['release_from'] > date('Y-m-d H:i:s')) {
6732  $field['release_from'] = '0000-00-00 00:00:00';
6733  }
6734 
6735  $update = array(
6736  'field' => $field,
6737  'extra' => $extra
6738  );
6739 
6740  if ($children_list) {
6741  $update['children'] = $children_list;
6742  }
6743 
6744  if ($original_parents) {
6745  $current_parents = array();
6746  foreach ($this->getParents(array('fields' => 'id')) as $parent) {
6747  $current_parents[] = $parent->field['id'];
6748  }
6749  $update['parents'] = $current_parents;
6750  }
6751 
6752  $original_page->field = array_merge($original_page->field, $update['field']);
6753  if ($original_page->extra['release_ids']) {
6754  // Freigabekopie Liste aktualisieren
6755  $update['extra']['release_ids'] = array_values(array_diff($original_page->extra['release_ids'], array($this->field['id'])));
6756  }
6757  $original_page->extra = $update['extra']; // Nicht zusammenführen. Das neue Extra überschreibt das alte komplett.
6758 
6759  /* Evtl. vorhandene MM-Datei kopieren */
6760  if (Ego_System::file_exists($GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename())) {
6762  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$this->getMediaFilename(),
6763  $GLOBALS['egotec_conf']['var_dir'].'media/'.$this->_site->name.'/'.$original_page->getMediaFilename(true)
6764  );
6765  }
6766 
6767  // Mediapool kopieren
6768  $this->getMediapool()->copy($original_page, $this->getMediapool()->currentDir);
6769  $this->getMediapool()->copy($original_page, 'workflow', false, true);
6770 
6771  // Jetzt Bearbeitungsdatum ändern und Archiveintrag anlegen
6772  $update['field'] = $original_page->field;
6773  $update['extra'] = $original_page->extra;
6774  $original_page->update($update);
6775 
6776  $this->delete();
6777  return $original_page;
6778  }
6779 
6786  public function newRelease($date = '') {
6787  if ($this->field['inactive'] != self::RELEASE_FLAG) {
6788  $this->archiveOnly = false;
6789  $field = $this->field;
6790  $extra = $this->extra;
6791  unset($field['id']);
6792  $field['inactive'] = self::RELEASE_FLAG;
6793  if ($date != '') {
6794  $field['release_from'] = $date;
6795  }
6796 
6797  if ($this->isWorkflowCopy()) {
6798  // Wenn es sich um eine Workflowkopie handelt wird diese zur Freigabekopie
6799  $extra['release_id'] = $extra['original_id'];
6800  unset($extra['original_id']);
6801  $new_page = $this;
6802  } else {
6803  // Eine neue Freigabekopie erstellen
6804  $extra['release_id'] = $this->field['id'];
6805  unset($extra['release_ids']);
6806  $params = array(
6807  'site' => $this->getSite(),
6808  'field' => $field,
6809  'extra' => $extra
6810  );
6811  $parents = $this->getParents(array(), array('auth_or' => '1=1'));
6812  if ($parent = $parents->nextPage()) {
6813  $new_page = $this->copyTo(
6814  $parent->field['id'],
6815  false,
6816  $params
6817  );
6818  }
6819  if (empty($new_page)) {
6820  // Existiert keine Elternseite, dann unter sich selbst erstellen (Startseite)
6821  $new_page = $this->copyTo(
6822  $this->field['id'],
6823  false,
6824  $params
6825  );
6826  }
6827  }
6828  if ($new_page) {
6829  // Freigabekopie Liste aktualisieren
6830  $original_page = $this->_site->getPage($extra['release_id'], array(
6831  'only_active' => false,
6832  'inactive' => true
6833  ));
6834  $extra = $original_page->extra;
6835  if (!is_array($extra['release_ids'])) {
6836  $extra['release_ids'] = array();
6837  }
6838  $extra['release_ids'][] = $new_page->field['id'];
6839  $extra['release_ids'] = array_unique($extra['release_ids']);
6840  $original_page->updateExtra($extra, true, true);
6841  return $new_page;
6842  }
6843  }
6844  return null;
6845  }
6846 
6852  public function release() {
6853  if ($this->isReleaseCopy()) {
6854  // Gibt es ein Freigabe bis Datum, wird vom Original eine neue Freigabekopie mit Freigabe ab Datum angelegt
6855  if (
6856  $this->field['release_until'] != '0000-00-00 00:00:00'
6857  && ($original_page = $this->_site->getPage($this->extra['release_id'], array(
6858  'inactive' => true,
6859  'only_active' => false
6860  )))
6861  && $original_page->field['release_until'] == '0000-00-00 00:00:00' // Nur wenn das Original kein Freigabe bis Datum hat
6862  ) {
6863  $original_page->extra['release_ids'] = array_values(array_diff($original_page->extra['release_ids'], array($this->field['id'])));
6864  $GLOBALS['new_release'] = $original_page->newRelease($this->field['release_until']);
6865 
6866  // Das Freigabe bis Datum muss bei der aktuellen Veröffentlichung entfernt werden
6867  $this->field['release_until'] = '0000-00-00 00:00:00';
6868  }
6869 
6870  return $this->merge($this->extra['release_id']);
6871  }
6872  return null;
6873  }
6874 
6880  public function isWorkflowCopy() {
6881  return ($this->field['workflow'] && $this->extra['original_id']);
6882  }
6883 
6889  public function isReleaseCopy() {
6890  return ($this->extra['release_id'] && $this->field['inactive'] == self::RELEASE_FLAG);
6891  }
6892 
6898  public function isClone() {
6899  return !empty($this->extra['clone_original']);
6900  }
6901 
6907  public function isLanguageLink()
6908  {
6909  return ($this->extra['language_link'][$this->getSite()->language] && $this->extra['language_standard'] != $this->getSite()->language);
6910  }
6911 
6917  public function isArchive() {
6918  return $this->archiveOnly || $this->getTableSuffix() == '_v';
6919  }
6920 
6926  public function isActive() {
6927  return !$this->field['inactive']
6928  && !$this->field['deleted']
6929  && ($this->field['release_from'] == '0000-00-00 00:00:00' || date('Y-m-d H:i:s') > $this->field['release_from'])
6930  && ($this->field['release_until'] == '0000-00-00 00:00:00' || date('Y-m-d H:i:s') < $this->field['release_until'])
6931  && !$this->isWorkflowCopy()
6932  && !$this->isReleaseCopy();
6933  }
6934 
6940  public function getNonPublic() {
6941  if ($this->isPublicSave()) {
6942  $db = new_db_connection();
6943  $db->select(array(
6944  'table' => $this->_site->pageTable . '_v',
6945  'where' => 'id = :id AND c_date > :c_date',
6946  'order' => 'c_date DESC',
6947  'limit' => 1,
6948  'bind' => array(
6949  'id' => $this->field['id'],
6950  'c_date' => $this->lastChangeDate
6951  )
6952  ));
6953  if ($db->nextRecord()) {
6954  $class = $this->_site->getPageClass($db->Record['type']);
6955  return new $class($this->_site, $db->Record);
6956  }
6957  }
6958  return null;
6959  }
6960 
6967  public function getNonPublics($c_user = null) {
6968  $result = array();
6969  $descendants = $this->getDescendants();
6970  foreach ($descendants as $descendant) {
6971  if (
6972  ($page = $descendant->getNonPublic())
6973  && (!$c_user || $page->field['c_user'] == $c_user)
6974  ) {
6975  $result[] = $page;
6976  }
6977  }
6978  return $result;
6979  }
6980 
6986  public function isPublicSave() {
6987  return $this->_site->isPublicSave()
6988  && ($info = $this->getTypeInfo())
6989  && !$info['no_public_save'];
6990  }
6991 
6997  public function isPublic() {
6998  if ($this->isPublicSave()) {
6999  return $this->lastChangeDate == $this->field['c_date'];
7000  }
7001  return true;
7002  }
7003 
7010  public function getLastChangeDate() {
7011  return $this->lastChangeDate;
7012  }
7013 
7020  public function getArchivePage($c_date = '') {
7021  $db = new_db_connection();
7022  $params = array(
7023  'table' => $this->_site->pageTable.'_v',
7024  'where' => 'id = :id',
7025  'order' => 'c_date DESC',
7026  'limit' => 1,
7027  'bind' => array(
7028  'id' => $this->field['id']
7029  )
7030  );
7031  if ($c_date) {
7032  // Archiveintrag zu einem bestimmten Zeitpunkt
7033  $params['where'] .= ' AND c_date = :c_date';
7034  $params['bind']['c_date'] = $c_date;
7035  }
7036  $db->select($params);
7037  if ($db->nextRecord()) {
7038  $page = clone $this;
7039  $page->setTableSuffix('_v');
7040  $page->field = $db->Record;
7041  $page->extra = $db->Record['extra']
7042  ? unserialize($db->Record['extra'])
7043  : array();
7044  return $page;
7045  }
7046  return null;
7047  }
7048 
7055  public function getArchivePages($query=array())
7056  {
7057  $query['table'] = $this->getSite()->pageTable . '_v';
7058  if ($query['where']) {
7059  $query['where'].= ' AND ';
7060  }
7061  $query['where'].= 'id=:id';
7062  $query['bind']['id'] = $this->field['id'];
7063  if (!isset($query['order'])) {
7064  $query['order'] = 'c_date DESC';
7065  }
7066  return new Page_Iterator($this->_site, new_db_connection($query));
7067  }
7068 
7075  public function restoreArchivPage($c_date)
7076  {
7077  $db = new_db_connection();
7078  $db->select(array(
7079  'table' => $this->getSite()->pageTable.'_v',
7080  'where' => "id=".$this->field['id']." AND c_date='".$c_date."'"
7081  ));
7082 
7083  if (!$db->nextRecord()) {
7084  return false;
7085  }
7086 
7087  /* Einige Daten werden nicht wieder aus dem Archiv überschrieben */
7088  $field = $db->Record;
7089  unset($field['id']);
7090  unset($field['children']);
7091  unset($field['parents']);
7092  $extra = unserialize($field['extra']);
7093 
7094  // Dazugehöriges Mediapool Archiv wiederherstellen
7095  $this->getMediapool()->restore(Ego_System::dateEncode($c_date));
7096 
7097  if (empty($extra['piwik']) && !empty($this->extra['piwik'])) {
7098  // Die Piwik Einstellungen beim Wiederherstellen beibehalten
7099  $extra['piwik'] = $this->extra['piwik'];
7100  }
7101  $this->update(array(
7102  'field' => $field,
7103  'extra' => $extra
7104  ));
7105 
7117  if ($file = $this->getSite()->getSiteFile($this->field['type'].'/admin/archive_restore.php')) {
7118  // Diese Variablen müssen zur Abwärtskompatibilität gesetzt sein
7119  $site = $this->getSite();
7120  $current_page = $this;
7121  $smarty = $GLOBALS['smarty'];
7122  require($file);
7123  }
7124 
7125  return true;
7126  }
7127 
7136  public function download($recursive = true, $target_dir = '', $write_log = true) {
7137  $log = $GLOBALS['egotec_conf']['log_dir'].'page_download-'.date('Y-m-d');
7138  if ($write_log) {
7139  file_put_contents($log, "\r\n===> ".date('Y-m-d H:i:s')
7140  ." Page Download für "
7141  ."{$this->_site->name}.{$this->_site->language}.{$this->field['id']}"
7142  ." beginnt:\r\n", FILE_APPEND);
7143  }
7144  if ($target_dir) {
7145  $dir = $target_dir;
7146  } else {
7147  $dir = $GLOBALS['egotec_conf']['tmp_dir'].'download'.md5(microtime()).'/';
7148  }
7149  $media_dir = $dir.'media/'.$this->_site->name.'/';
7150  if ($write_log) {
7151  file_put_contents($log, "Verzeichnisse anlegen\r\n", FILE_APPEND);
7152  }
7153  Ego_System::mkdir($dir);
7154  Ego_System::mkdir($media_dir);
7155  $params = array(
7156  'inactive' => true,
7157  'only_active' => false,
7158  'no_cache' => true,
7159  'auth_or' => '1=1'
7160  );
7161 
7162  $pages = array($this);
7163  if ($recursive) {
7164  if ($write_log) {
7165  file_put_contents($log, "Alle Nachfahren ermitteln\r\n", FILE_APPEND);
7166  }
7167  foreach ($this->getDescendants(
7168  array(),
7169  $params
7170  ) as $descendant) {
7171  $pages[] = $descendant;
7172  }
7173  }
7174 
7175  $data = array();
7176  $db = new_db_connection();
7177  Ego_System::mkdir($dir.'db/');
7178  foreach ($pages as $page) {
7179  if ($write_log) {
7180  file_put_contents($log, "Seite {$page->field['name']} ({$page->field['id']}) sichern\r\n", FILE_APPEND);
7181  }
7182  foreach ($this->_site->getLanguages() as $lang) {
7183  $lang_page = $page->getLanguagePage($lang);
7184  if ($write_log) {
7185  file_put_contents($log, "> Sprache {$lang} sichern\r\n", FILE_APPEND);
7186  }
7187 
7188  // Haupttabelle sichern
7189  $table = $this->_site->name.'_'.$lang;
7190  $db->select(array(
7191  'table' => $table,
7192  'fields' => '*',
7193  'where' => 'id = :id',
7194  'bind' => array(
7195  'id' => $page->field['id']
7196  )
7197  ));
7198  while ($db->nextRecord()) {
7199  $s = serialize($db->Record);
7200  $file = $dir.'db/'.$table;
7201  file_put_contents($file, strlen($s)."\n".$s, FILE_APPEND);
7202 
7203  $path = $GLOBALS['egotec_conf']['var_dir']
7204  .'media/'.$this->_site->name.'/';
7205 
7206  // Mediapool
7207  if (Ego_System::file_exists($path.$lang.'/pool/'.$page->field['id'].'/')) {
7208  if ($write_log) {
7209  file_put_contents($log, "> Mediapool sichern\r\n", FILE_APPEND);
7210  }
7211  Ego_System::mkdir($media_dir.$lang.'/pool/'.$page->field['id'].'/');
7213  $path.$lang.'/pool/'.$page->field['id'].'/',
7214  $media_dir.$lang.'/pool/'.$page->field['id'].'/'
7215  );
7216  }
7217 
7218  // Multimedia
7219  if (
7220  in_array($page->field['type'], array('multimedia/file', 'multimedia/image'))
7221  && $lang_page
7222  ) {
7223  if ($write_log) {
7224  file_put_contents($log, "> Datei sichern\r\n", FILE_APPEND);
7225  }
7226  $file = $lang_page->getMediaFilename();
7227  Ego_System::mkdir($dir.'media/'.$this->_site->name.'/'.$lang);
7228  @copy(
7229  $path.$file,
7230  $dir.'media/'.$this->_site->name.'/'.$lang.'/'.$page->field['id']
7231  );
7232  }
7233  }
7234 
7235  // Alle verknüpften Tabellen sichern
7236  $tables = array(
7237  'buchungen' => $table.'_buchungen',
7238  'children' => $table.'_children',
7239  'extra' => $table.'_extra',
7240  'infodienst' => $table.'_infodienst',
7241  'newsletter_light' => $table.'_newsletter_light',
7242  'rights' => $table.'_rights',
7243  'users' => $table.'_users',
7244  'keywords' => $this->_site->name.'_keywords_rel',
7245  'v' => $table.'_v'
7246  );
7247  if ($write_log) {
7248  file_put_contents($log, "> Verknüpfte Tabellen sichern\r\n", FILE_APPEND);
7249  }
7250  foreach ($tables as $key => $table) {
7251  if (!$db->tableExists($table)) {
7252  continue;
7253  }
7254  if ($write_log) {
7255  file_put_contents($log, ">> $table\r\n", FILE_APPEND);
7256  }
7257  switch ($key) {
7258  case 'newsletter_light':
7259  $where = 'abonnent_id = :id';
7260  break;
7261  case 'v':
7262  $where = 'id = :id';
7263  break;
7264  default:
7265  $where = 'page_id = :id';
7266  }
7267  $db->select(array(
7268  'table' => $table,
7269  'fields' => '*',
7270  'where' => $where,
7271  'bind' => array(
7272  'id' => $page->field['id']
7273  )
7274  ));
7275  while ($db->nextRecord()) {
7276  $s = serialize($db->Record);
7277  $file = $dir.'db/'.$table;
7278  file_put_contents($file, strlen($s)."\n".$s, FILE_APPEND);
7279  }
7280  }
7281 
7282  // Alle Verweise sichern
7283  if (!$target_dir && $lang_page) {
7284  if ($write_log) {
7285  file_put_contents($log, "> Verweise sichern\r\n", FILE_APPEND);
7286  }
7287  foreach ($lang_page->getLinks() as $link) {
7288  try {
7289  $link_site = new Site($link['dest_site'], $link['dest_lang']);
7290  $link_page = $link_site->getPage($link['dest_id'], $params);
7291  if ($link_page) {
7292  $link_page->download(false, $dir, false);
7293 
7294  // Die Elternseiten müssen auch gesichert werden
7295  foreach ($link_page->getParents(array(), $params) as $parent) {
7296  $parent->download(false, $dir, false);
7297  }
7298  }
7299  } catch (Exception $e) {
7300  // Ignorieren
7301  }
7302  }
7303 
7304  $db->select(array(
7305  'table' => 'egotec_links',
7306  'fields' => '*',
7307  'where' => "src_site = :site AND src_lang = :lang AND src_id = :id",
7308  'bind' => array(
7309  'site' => $this->_site->name,
7310  'lang' => $lang,
7311  'id' => $page->field['id']
7312  )
7313  ));
7314  while ($db->nextRecord()) {
7315  $s = serialize($db->Record);
7316  $file = $dir.'db/egotec_links';
7317  file_put_contents($file, strlen($s)."\n".$s, FILE_APPEND);
7318  }
7319  }
7320  }
7321  }
7322 
7323  if (!$target_dir) {
7324  if ($write_log) {
7325  file_put_contents($log, "Archiv erstellen\r\n", FILE_APPEND);
7326  }
7327  // Archiv erstellen
7328  require_once('Archive/Tar.php');
7329  $cwd = getcwd();
7330  chdir($dir);
7331  $tmp = tempnam($GLOBALS['egotec_conf']['tmp_dir'], 'download');
7332  $zip = new Archive_Tar($tmp, 'gz');
7333  $zip->add('./');
7334  chdir($cwd);
7335  Ego_System::deldir($dir);
7336 
7337  if ($write_log) {
7338  file_put_contents($log, "Archiv ausgeben\r\n", FILE_APPEND);
7339  }
7340  require_once('base/Ego_Output.php');
7341  $output = new Ego_Output($tmp);
7342  $date = date('Ymd-His');
7343  $output->setName('page_'.$this->_site->name.'.'.str_replace(' ', '_', $this->field['name']).'.'.$date.'.tar.gz');
7344  $output->setTemporary(true);
7345  $output->download();
7346  }
7347  }
7348 
7354  public function export() {
7355  if ($this->field['type'] == 'multimedia/category') {
7356  $dir = $GLOBALS['egotec_conf']['tmp_dir'];
7357  $name = 'export'.md5(microtime());
7358  $folder = $name.DIRECTORY_SEPARATOR
7359  .urldecode(Ego_System::encode_path(trim($this->field['name']))).DIRECTORY_SEPARATOR;
7360  $file = $name.'.tar.gz';
7361  $this->exportArchive($this, $dir.$folder);
7362 
7363  // Archiv erstellen
7364  require_once('Archive/Tar.php');
7365  $cwd = getcwd();
7366  chdir($dir);
7367  $zip = new Archive_Tar($file, 'gz');
7368  $zip->_separator = ',';
7369  $zip->createModify(rtrim($folder, DIRECTORY_SEPARATOR), '', $name);
7370  chdir($cwd);
7371  Ego_System::deldir($dir.$name);
7372  return $dir.$file;
7373  }
7374  return null;
7375  }
7376 
7383  private function exportArchive($page, $path) {
7384  Ego_System::mkdir($path);
7385  foreach ($page->getChildren() as $child) {
7386  $name = urldecode(Ego_System::encode_path(trim($child->field['name'])));
7387  if ($child->field['type'] == 'multimedia/category') {
7388  $this->exportArchive($child, $path.$name.DIRECTORY_SEPARATOR);
7389  } elseif (in_array($child->field['type'], array('multimedia/file', 'multimedia/image'))) {
7390  $dir = $GLOBALS['egotec_conf']['var_dir'].
7391  'media'.DIRECTORY_SEPARATOR.$this->_site->name.DIRECTORY_SEPARATOR;
7392  $file = $child->getMediaFilename();
7393  if ($child->extra['image_type']) {
7394  $name .= '.'.$child->extra['image_type'];
7395  }
7396  Ego_System::copy($dir.$file, $path.$name);
7397  }
7398  }
7399  }
7400 
7406  public function frontendAdmin() {
7407  if (!$this->frontendActive) {
7408  $this->frontendActive = true; // Nur einmal umwandeln
7409  $GLOBALS['frontend_admin'] = true;
7410  if (!$_SESSION['login']['live_preview']) {
7411  $_REQUEST['preview'] = $_REQUEST['nonactive'] = 1; // showdeleted wird nicht benötigt
7412  } else {
7413  unset($_REQUEST['preview'], $_REQUEST['nonactive']);
7414  }
7415 
7416  // In der Frontend Administration werden auch inaktive Seiten angezeigt
7417  $this->_site->setOnlyActive(!$_REQUEST['preview']);
7418 
7419  $lock = $this->lock();
7420  if (!$lock) {
7421  $settings = $this->getEditFieldSettings();
7422 
7423  if (!empty($this->conf['noneditable'])) {
7424  // Diese Elemente dürfen in der Frontend Administration nicht bearbeitet werden
7425  $settings = array_diff_key($settings, array_flip(explode(',', $this->conf['noneditable'])));
7426  }
7427 
7428  // Der Inhalt (field.content) wird automatisch in einen Editor umgewandelt
7429  $this->createEditField('content', $settings['content']);
7430  } elseif ($GLOBALS['smarty']) {
7431  // Die Seite ist gesperrt und kann nicht bearbeitet werden
7432  $GLOBALS['smarty']->assign('inlineedit_lock', true);
7433  }
7434  }
7435  }
7436 
7443  private function getEditFieldSettings($name = '') {
7444  // Typ der Kurzbeschreibung bestimmen
7445  $short_type = !$this->_site->admin['editor']['short'] && !$GLOBALS['egotec_conf']['editor']['short']
7446  ? 'text' : 'content';
7447 
7448  // Für Titel und Kurzbeschreibung kein HTML zulassen
7449  $plaintext = (bool) $this->_site->admin['editor']['plaintext'];
7450 
7451  // Konfigurationen zusammenführen
7452  $settings = array(
7453  'name' => array(
7454  'field' => true,
7455  'title' => $GLOBALS['auth']->translate('Name'),
7456  'dir' => 'right',
7457  'type' => 'text',
7458  'perm' => 'extra_information',
7459  'mandatory' => true,
7460  'readonly' => true,
7461  'plaintext' => true
7462  ),
7463  'title' => array(
7464  'field' => true,
7465  'title' => $GLOBALS['auth']->translate('Titel'),
7466  'dir' => 'right',
7467  'type' => 'text',
7468  'perm' => 'extra_information',
7469  'readonly' => true,
7470  'plaintext' => $plaintext
7471  ),
7472  'short' => array(
7473  'field' => true,
7474  'title' => $GLOBALS['auth']->translate('Kurzbeschreibung'),
7475  'dir' => 'right',
7476  'type' => $short_type,
7477  'perm' => 'extra_information',
7478  'plaintext' => $plaintext && $short_type == 'text'
7479  ),
7480  'content' => array(
7481  'field' => true,
7482  'title' => $GLOBALS['auth']->translate('Inhalt'),
7483  'dir' => 'right',
7484  'type' => 'editor'
7485  )
7486  );
7487  if (!empty($this->conf['fields'])) {
7488  $settings = array_replace_recursive($settings, $this->conf['fields']);
7489  }
7490 
7491  if ($name) {
7492  // Nur ein bestimmtes Feld zurückliefern
7493  if (isset($settings[$name])) {
7494  return $settings[$name];
7495  }
7496  return null;
7497  }
7498  return $settings;
7499  }
7500 
7513  public function createEditField($name, $setting = array(), $empty = false, $orient = '', $index = 0, $block = '', $replace = false) {
7514  if (empty($setting) && !($setting = $this->getEditFieldSettings($name))) {
7515  return null;
7516  }
7517 
7518  $field = $setting['field'] ? 'field' : 'extra';
7519 
7520  // Sicherstellen, dass ein editierbares Feld nur einmal umgewandelt wird
7521  if (isset($this->editFields[$field][$name])) {
7522  return $this->editFields[$field][$name];
7523  }
7524 
7525  // Standardwert aus einer Variablen beziehen
7526  if (isset($setting['default']) && strpos($setting['default'], '@') === 0) {
7527  $parts = explode('.', substr($setting['default'], 1), 2);
7528  $parts[1] = str_replace(array('@orient', '@index', '@block'), array($orient, $index, $block), $parts[1]);
7529  $setting['default'] = strip_tags((string) Ego_System::getAssocValue($this->{$parts[0]}, $parts[1]));
7530  }
7531 
7532  // Standard Parameter aus der Konfiguration übernehmen, wenn diese nicht direkt übergeben werden
7533  if (is_array($this->conf['values'][$orient][$setting['type']])) {
7534  foreach ($this->conf['values'][$orient][$setting['type']] as $param => $value) {
7535  if (!isset($setting[$param])) {
7536  $setting[$param] = $value;
7537  }
7538  }
7539  }
7540 
7546  $edit_field = function() use ($field, $name, $setting, $empty, $orient, $index, $block, $replace) {
7547  $this_value = Ego_System::getAssocValue($this->{$field}, $name);
7548  if ($field == 'extra' || $this_value !== null) {
7549  $frontend_admin = $GLOBALS['frontend_admin'] && $this->conf['orients'][$orient]['disabled'] !== true && $this->isCurrentPage();
7550  $title = $setting['title'] ? $GLOBALS['auth']->translate($setting['title']) : $setting['var'];
7551  $dir = $setting['dir'] ? $setting['dir'] : 'right';
7552 
7553  $type = $setting['type'];
7554  if ($setting['type'] == 'media') {
7555  // "media" Element automatisch auf "image" oder "video" stellen
7556  $type = Ego_System::getAssocValue($this->{$field}, "{$name}_type");
7557  if (!$type) {
7558  // Standardmäßig wird "image" verwendet
7559  $type = 'image';
7560  }
7561  }
7562 
7563  // Wert ist gekoppelt
7564  if (strpos($setting['var'], '=') === 0) {
7565  list($field, $name) = explode('.', substr($setting['var'], 1), 2);
7566  }
7567 
7568  // Gesetzten Wert ermitteln
7569  if ($empty) {
7570  $edit_value = '';
7571 
7572  // Standardwert verwenden
7573  if (!empty($this->conf['blocks'][$block]['default'][$orient])) {
7574  $sub_name = implode('.', array_slice(explode('.', $name), 3));
7575  if (($default_value = Ego_System::getAssocValue($this->conf['blocks'][$block]['default'][$orient], $sub_name)) !== null) {
7576  $edit_value = $default_value;
7577  }
7578  }
7579  } else {
7580  $edit_value = $this_value;
7581  }
7582 
7583  // Verwendetes Layout ermitteln
7584  $layout = $this->extra['_layout'];
7585  if (empty($layout)) {
7586  $layout = $this->conf['default_layout']; // Standard Layout verwenden
7587  }
7588 
7589  // Standardblöcke haben immer einen Standardwert
7590  if (
7591  !$setting['default']
7592  && !$setting['optional']
7593  && !empty($this->conf['layouts'][$layout]['blocks'][$orient]['default'])
7594  && in_array($block, explode(',', $this->conf['layouts'][$layout]['blocks'][$orient]['default']))
7595  && !in_array($type, array('image', 'media', 'video', 'audio', 'table'))
7596  ) {
7597  $setting['default'] = $title;
7598  }
7599 
7600  if (($empty || $replace) && $frontend_admin && $edit_value == '' && in_array($type, array('text', 'minimal', 'content', 'editor', 'link'))) {
7601  // Leere Text Felder vorbelegen
7602  if ($type == 'link') {
7603  // Bei einem "link" Element muss auch der Linktext vorbelegt werden
7604  $edit_value = $setting['default'] ? $setting['default'] : '';
7605  Ego_System::setAssocValue($this->{$field}, "{$name}_text", $title);
7606  } else {
7607  $edit_value = $setting['default'] ? $setting['default'] : $title;
7608  }
7609  }
7610 
7611  if ($frontend_admin && in_array($type, array('image', 'video', 'audio'))) {
7612  $type_class = "egotec_type_{$type}";
7613  if (empty($setting['attr']['class'])) {
7614  $setting['attr']['class'] = "egotec_media {$type_class}";
7615  } else {
7616  $setting['attr']['class'] .= " egotec_media {$type_class}";
7617  }
7618  }
7619 
7620  switch ($type) {
7621  case 'editor':
7622  case 'content':
7623  case 'text':
7624  case 'minimal':
7625  // Text Elemente unterstützen auch den "attr" Parameter
7626  if (isset($setting['attr'])) {
7627  $tag_name = $type == 'text' ? 'span' : 'div';
7628  $wrapper = '<' . $tag_name;
7629  foreach ($setting['attr'] as $attr => $value) {
7630  $wrapper .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
7631  }
7632  $wrapper .= '>' . $edit_value . '</' . $tag_name . '>';
7633  $edit_value = $wrapper;
7634  }
7635  break;
7636 
7637  case 'video':
7638  case 'audio':
7639  // "video" Elemente erzeugen ein VIDEO Element
7640  // "audio" Elemente erzeugen ein AUDIO Element
7641 
7642  // Für die Erzeugung die Smarty video Funktion verwenden
7643  require_once('smarty/plugins/function.video.php');
7644  $edit_value = smarty_function_video(array_replace_recursive(array(
7645  'src' => $edit_value,
7646  'poster' => Ego_System::getAssocValue($this->{$field}, "{$name}_poster"),
7647  'alt' => Ego_System::getAssocValue($this->{$field}, "{$name}_alt"),
7648  'controls' => Ego_System::getAssocValue($this->{$field}, "{$name}_controls"),
7649  'autoplay' => Ego_System::getAssocValue($this->{$field}, "{$name}_autoplay"),
7650  'loop' => Ego_System::getAssocValue($this->{$field}, "{$name}_loop"),
7651  'muted' => Ego_System::getAssocValue($this->{$field}, "{$name}_muted"),
7652  'fallback' => $frontend_admin,
7653  'audio' => $type == 'audio'
7654  ), $setting), $GLOBALS['smarty']);
7655  if (empty($edit_value)) {
7656  $setting['empty'] = true;
7657  }
7658  break;
7659 
7660  case 'image':
7661  // "image" Elemente erzeugen ein PICTURE Element
7662  if (!$frontend_admin && empty($edit_value) && !$setting['default']) {
7663  // Im Frontend keine leeren Bilder anzeigen
7664  return '';
7665  }
7666 
7667  // Attribute festlegen
7668  foreach (array('alt', 'title') as $attr) {
7669  if (!isset($setting['attr'][$attr])) {
7670  if (($attr_value = Ego_System::getAssocValue($this->{$field}, "{$name}_{$attr}")) !== null) {
7671  $setting['attr'][$attr] = $attr_value;
7672  }
7673  }
7674  }
7675  if (isset($setting['attr']['class'])) {
7676  $setting['attr']['class'] .= ' ' . Ego_System::getAssocValue($this->{$field}, "{$name}_class");
7677  $setting['attr']['class'] = trim($setting['attr']['class']);
7678  } elseif (($attr_value = Ego_System::getAssocValue($this->{$field}, "{$name}_class")) !== null) {
7679  $setting['attr']['class'] = $attr_value;
7680  }
7681 
7682  // Für die Erzeugung die Smarty picture Funktion verwenden
7683  require_once('smarty/plugins/function.picture.php');
7684  $edit_value = smarty_function_picture(array_replace_recursive(array(
7685  'src' => $edit_value,
7686  'href' => !$setting['url'] ? Ego_System::getAssocValue($this->{$field}, "{$name}_href") : '',
7687  'target' => !$setting['url'] ? Ego_System::getAssocValue($this->{$field}, "{$name}_target") : '',
7688  'fallback' => $frontend_admin
7689  ), $setting), $GLOBALS['smarty']);
7690  if (empty($edit_value)) {
7691  $setting['empty'] = true;
7692  }
7693  break;
7694 
7695  case 'link':
7696  // "link" Elemente erzeugen ein A Element
7697  if (!$frontend_admin && empty($edit_value)) {
7698  // Im Frontend keine leeren Links anzeigen
7699  return '';
7700  }
7701 
7702  // Attribute festlegen
7703  $default = '<a href=""';
7704  $a = '<a href="' . $edit_value . '"';
7705  if (!is_array($setting['attr'])) {
7706  $setting['attr'] = array();
7707  }
7708  foreach (array('class', 'title', 'target') as $attr) {
7709  if (!isset($setting['attr'][$attr])) {
7710  $setting['attr'][$attr] = Ego_System::getAssocValue($this->{$field}, "{$name}_{$attr}");
7711  } elseif ($attr == 'class') {
7712  $setting['attr']['class'] .= ' ' . Ego_System::getAssocValue($this->{$field}, "{$name}_class");
7713  $setting['attr']['class'] = trim($setting['attr']['class']);
7714  }
7715  }
7716  foreach ($setting['attr'] as $attr => $value) {
7717  if ($attr != 'href' && $value != '') {
7718  if ($attr != 'target') {
7719  $default .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
7720  }
7721  $a .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
7722  }
7723  }
7724  $default .= '>' . ($setting['default'] ? $setting['default'] : $title) . '</a>';
7725  $a .= '>' . Ego_System::getAssocValue($this->{$field}, "{$name}_text") . '</a>';
7726  $setting['default'] = $default;
7727  $edit_value = empty($edit_value) ? $default : $a;
7728  break;
7729 
7730  case 'table':
7731  // "table" Elemente erzeugen ein TABLE Element
7732  if (!$frontend_admin && empty($edit_value)) {
7733  // Im Frontend keine leeren Tabellen anzeigen
7734  return '';
7735  }
7736 
7737  // Zeilen und Spalten können standardmäßig bearbeitet werden
7738  foreach (['rows_edit', 'cols_edit', 'cols_size'] as $key) {
7739  if (!isset($setting[$key]) || !empty($setting[$key])) {
7740  $setting[$key] = true;
7741  }
7742  }
7743 
7754  $create = function($name1, $name2, $rows, $cols, $contents = '') {
7755  $contents = explode('|', is_string($contents) ? $contents : '');
7756  $html = "<{$name1}>";
7757  for ($r = 0; $r < $rows; $r++) {
7758  $html .= '<tr>';
7759  for ($c = 0; $c < $cols; $c++) {
7760  $content = isset($contents[$c]) && trim($contents[$c]) != ''
7761  ? $GLOBALS['auth']->translate(trim($contents[$c]))
7762  : '<br>'; // muss gesetzt werden, damit man die Spalte beschreiben kann
7763  $html .= "<{$name2}>{$content}</{$name2}>";
7764  }
7765  $html .= '</tr>';
7766  }
7767  $html .= "</{$name1}>";
7768  return $html;
7769  };
7770 
7771  // Standard Tabelle erzuegen
7772  $rows = $setting['rows'] ? (int) $setting['rows'] : 2;
7773  $cols = $setting['cols'] ? (int) $setting['cols'] : 2;
7774 
7775  $table = '<table';
7776  if (is_array($setting['attr'])) {
7777  // Attribute setzen
7778  foreach ($setting['attr'] as $attr => $value) {
7779  $table .= ' ' . $attr . '="' . str_replace('"', '\"', $value) . '"';
7780  }
7781  }
7782  $table .= '>';
7783 
7784  $table .= ($setting['thead'] ? $create('thead', 'th', 1, $cols, $setting['thead']) : '')
7785  . $create('tbody', 'td', $rows, $cols)
7786  . ($setting['tfoot'] ? $create('tfoot', 'td', 1, $cols, $setting['tfoot']) : '')
7787  . '</table>';
7788 
7789  // Standard Tabelle verwenden
7790  $setting['default'] = $table;
7791  if (empty($edit_value)) {
7792  $edit_value = $table;
7793  } else {
7794  // Falls sich die Attribute geändert haben, muss die Tabelle aktualisiert werden
7795  require_once('base/Ego_DomQuery.php');
7796  $dom = new Ego_DomQuery($edit_value);
7797  $table = $dom->doc->firstChild;
7798  $changed = false;
7799  if ($table->hasAttributes()) {
7800  foreach ($table->attributes as $attribute) {
7801  if (
7802  !is_array($setting['attr'])
7803  || empty($setting['attr'])
7804  || !in_array($table->nodeName, array_keys($setting['attr']))
7805  ) {
7806  // Attribut entfernen
7807  $table->removeAttribute($attribute->nodeName);
7808  $changed = true;
7809  }
7810  }
7811  }
7812  if (is_array($setting['attr'])) {
7813  foreach ($setting['attr'] as $attr => $value) {
7814  if (!$table->hasAttribute($attr) || $table->getAttribute($attr) != $value) {
7815  // Neues oder geändertes Attribut hinzufügen
7816  $table->setAttribute($attr, $value);
7817  $changed = true;
7818  }
7819  }
7820  }
7821  if ($changed) {
7822  $edit_value = $dom->getHTML();
7823  }
7824  }
7825  break;
7826 
7827  case 'value':
7828  case 'date':
7829  // "value", "date" Elemente geben nur den Wert zurück
7830  $value = Ego_System::getAssocValue($this->{$field}, $name);
7831 
7839  $get_value = function($value, $setting) use ($type) {
7840  if (empty($value)) {
7841  $value = !empty($setting['default']) ? $setting['default'] : '';
7842 
7843  // Der Standardwert für "date" kann ein relatives Datum sein
7844  if ($type == 'date' && preg_match('/^<%(.*?)>$/', $value, $match)) {
7845  $value = $match[1];
7846  }
7847  }
7848  if (!empty($setting['format']) && !empty($value)) {
7849  $value = date($setting['format'], strtotime($value));
7850  }
7851  if (!empty($setting['value'])) {
7852  $value = str_replace('<%>', $value, $setting['value']);
7853  }
7854  return $value;
7855  };
7856 
7857  // Zunächst die Einstellungen des Bedienelements anwenden
7858  if (
7859  !empty($orient)
7860  && (($block_name = $block) || ($block_name = $this->extra['_blocks'][$orient][$index]))
7861  && ($controls = $this->getBlockControls($block_name))
7862  ) {
7863  $value_name = ltrim(strrchr($name, '.'), '.');
7864  foreach ($controls as $select) {
7865  if ($select['name'] == $value_name) {
7866  $value = $get_value($value, $select);
7867  }
7868  }
7869  }
7870 
7871  // Dann die direkten Einstellungen anwenden
7872  $value = $get_value($value, $setting);
7873 
7874  return $value;
7875 
7876  case 'code':
7877  if (empty($edit_value)) {
7878  if (!$frontend_admin) {
7879  // Im Frontend keinen leeren Code anzeigen
7880  return '';
7881  } else {
7882  $edit_value = $setting['default'] ? $setting['default'] : $title;
7883  }
7884  }
7885 
7886  $languages = $setting['languages'] ?? $this->conf['code']['languages'] ?? array();
7887  if (!is_array($languages)) {
7888  $languages_array = explode(',', $languages);
7889  $languages = array();
7890  foreach ($languages_array as $language) {
7891  $languages[$language] = $language;
7892  }
7893  }
7894  $first_language = null;
7895  foreach ($languages as $value => $text) {
7896  $first_language = $value;
7897  break;
7898  }
7899 
7900  // Ausgewählte Sprache bestimmen
7901  $mode = Ego_System::getAssocValue($this->extra, $name . '_mode')
7902  ?? $setting['mode']
7903  ?? $this->conf['code']['mode']
7904  ?? $first_language
7905  ?? 'HTML';
7906 
7907  $smarty = Ego_Smarty::createFrontend($this->getSite(), array(
7908  'id' => 'code-' . md5($name),
7909  'name' => $name,
7910  'value' => $edit_value,
7911  'theme' => $setting['theme'] ?? $this->conf['code']['theme'] ?? 'monokai',
7912  'mode' => mb_strtolower($mode),
7913  'label' => $setting['label'] ?? $languages[$mode] ?? $mode,
7914  'min' => $setting['min'] ?? $this->conf['code']['min'] ?? 3,
7915  'max' => $setting['max'] ?? $this->conf['code']['max'] ?? 20,
7916  'languages' => $languages
7917  ));
7918  $edit_value = $smarty->fetch($GLOBALS['egotec_conf']['lib_dir'] . 'page/t/input/code.tpl');
7919  }
7920 
7921  $original_value = $edit_value;
7922 
7923  // Nur in der Frontend Administration und nur für diese Seite ein editierbares Element verwenden
7924  if ($frontend_admin) {
7931  $escape = function($s) {
7932  return htmlspecialchars(
7933  preg_replace('/\s+/', ' ', $s),
7934  ENT_QUOTES,
7935  'UTF-8'
7936  );
7937  };
7938 
7939  // Booleansche Werte müssen als String übergeben werden
7940  foreach (array('toolbar', 'menubar') as $key) {
7941  if (isset($setting[$key]) && is_bool($setting[$key])) {
7942  $setting[$key] = $setting[$key] === true ? 'true' : 'false';
7943  }
7944  }
7945 
7946  // Zusätzliche Attribute setzen
7947  $additional_attributes = array();
7948  if (!empty($setting['attr'])) {
7949  foreach ($setting['attr'] as $attr => $value) {
7950  if (in_array($setting['type'], array('link', 'table'))) {
7951  // Bestimmte Elemente setzen die Attribute für das implizite HTML
7952  continue;
7953  }
7954  $additional_attributes[] = $attr . '="' . $escape($value) . '"';
7955  }
7956  }
7957 
7958  $edit_value = '<div'
7959  . ($setting['field'] ? ' data-edit-field="' . $name . '"' : ' data-edit-extra="' . $name . '"')
7960  . ' data-edit-tooltip="' . $escape($title) . '"'
7961  . ' data-edit-tooltip-dir="' . $dir . '"'
7962  . ' data-edit-type="' . $setting['type'] . '"'
7963  . ($setting['default'] ? ' data-edit-default="' . $escape($setting['default']) . '"' : '')
7964  . ($setting['perm'] && !$this->hasRights(explode(',', $setting['perm'])) ? ' data-edit-locked="true"' : '')
7965  . ($setting['style'] ? ' style="' . $setting['style'] . '"' : '') // @deprecated
7966  . ($setting['mandatory'] ? ' data-edit-mandatory="true"' : '')
7967  . ($setting['readonly'] ? ' data-edit-readonly="true"' : '')
7968  . ($setting['rows_edit'] ? ' data-edit-rows="true"' : '')
7969  . ($setting['cols_edit'] ? ' data-edit-cols="true"' : '')
7970  . ($setting['cols_size'] ? ' data-edit-cols-size="true"' : '')
7971  . ($setting['maxlength'] ? ' data-edit-maxlength="' . $setting['maxlength'] . '"' : '')
7972  . ($setting['empty'] ? ' data-edit-empty="true"' : '')
7973  . ($setting['href'] === false ? ' data-edit-href="false"' : '')
7974  . ($setting['optional'] ? ' data-edit-optional="true"' : '')
7975  . ($setting['plaintext'] ? ' data-edit-plaintext="true"' : '')
7976  . ($setting['root'] ? ' data-edit-root="true"' : '')
7977  . ($setting['unsafe'] ? ' data-edit-unsafe="true"' : '')
7978  . ($setting['hooks'] ? ' data-edit-hooks="' . $setting['hooks'] . '"' : '')
7979  . ($setting['plugins'] ? ' data-edit-plugins="' . $setting['plugins'] . '"' : '')
7980  . ($setting['toolbar'] ? ' data-edit-toolbar="' . $setting['toolbar'] . '"' : '')
7981  . ($setting['menubar'] ? ' data-edit-menubar="' . $setting['menubar'] . '"' : '')
7982  . ($setting['paste_tags'] ? ' data-edit-paste-tags="' . $setting['paste_tags'] . '"' : '')
7983  . ($setting['paste_attrs'] ? ' data-edit-paste-attrs="' . $setting['paste_attrs'] . '"' : '')
7984  . ($setting['edit'] ? ' data-edit-media="' . $escape(json_encode($setting['edit'], JSON_FORCE_OBJECT)) . '"' : '')
7985  . (!empty($setting['attr']) ? ' data-edit-attr="' . $escape(json_encode($setting['attr'], JSON_FORCE_OBJECT)) . '"' : '')
7986  . implode(' ', $additional_attributes)
7987  . '>' . $edit_value . '</div>';
7988  Ego_System::setAssocValue($this->{$field}, $name, $edit_value);
7989  }
7990 
7991  // Darstellung für required/optional Eingabefelder für Labels in Formular Blöcken
7992  foreach (array('required', 'optional') as $display_type) {
7993  if (
7994  $this->conf['form'][$display_type]
7995  && $setting['var'] == 'label'
7996  && trim($original_value) != ''
7997  && strpos($block, 'input_') === 0
7998  && $this->extra['_contents'][$orient][$index]['extra'][$display_type]
7999  ) {
8000  $edit_value = $GLOBALS['smarty']->fetch('string:' . str_replace('<%>', $edit_value, $this->conf['form'][$display_type]));
8001  }
8002  }
8003 
8004  if (in_array($type, array('video', 'audio', 'image', 'media'))) {
8005  // Bildbeschreibung hinzufügen (im Frontend nur, wenn der Wert nicht leer ist)
8006  $caption = $this->conf['caption'];
8007  if (isset($this->conf['blocks'][$block]['caption'])) {
8008  $caption = $this->conf['blocks'][$block]['caption'];
8009  }
8010  if (isset($setting['caption'])) {
8011  $caption = $setting['caption'];
8012  }
8013 
8014  if ($caption) {
8015  if ($frontend_admin) {
8016  // Für die Erzeugung die Smarty value Funktion verwenden
8017  require_once('smarty/plugins/function.value.php');
8018  $var = substr(strrchr($name, '.'), 1);
8019  $caption_value = smarty_function_value(array(
8020  'var' => "{$var}_caption",
8021  'type' => 'minimal',
8022  'title' => $setting['type'] == 'image'
8023  ? $GLOBALS['auth']->translate('Bildbeschreibung')
8024  : $GLOBALS['auth']->translate('Beschreibung'),
8025  'orient' => $orient,
8026  'index' => $index
8027  ), $GLOBALS['smarty']);
8028  } else {
8029  $caption_value = Ego_System::getAssocValue($this->{$field}, "{$name}_caption");
8030  }
8031  if ($caption_value != '') {
8032  $edit_value = str_replace(array('<%>', '<#>'), array($edit_value, $caption_value), $caption);
8033  }
8034  }
8035  }
8036 
8037  if ($setting['wrapper'] && ($frontend_admin || $edit_value != '')) {
8038  // Wrapper für das Element hinzufügen (im Frontend nur, wenn der Wert nicht leer ist)
8039  $edit_value = str_replace('<%>', $edit_value, $setting['wrapper']);
8040  }
8041 
8042  if ($setting['url']) {
8043  // URL platzieren
8044  $href = Ego_System::getAssocValue($this->{$field}, "{$name}_href");
8045  $target = Ego_System::getAssocValue($this->{$field}, "{$name}_target");
8046  if ($frontend_admin || !$href) {
8047  // Keine Aktion ausführen
8048  $href = 'javascript:void(0)';
8049  }
8050 
8051  require_once('base/Ego_DomQuery.php');
8052  $dom = new Ego_DomQuery($edit_value);
8053  $links = $dom->query($setting['url']);
8054  foreach ($links as $link) {
8055  $link->setAttribute('href', $href);
8056  if ($target) {
8057  $link->setAttribute('target', $target);
8058  }
8059  }
8060  $edit_value = $dom->getHTML();
8061  }
8062 
8063  return $edit_value;
8064  }
8065  return null;
8066  };
8067 
8068  return $this->editFields[$field][$name] = $edit_field();
8069  }
8070 
8084  public function updateUrls($verbose = false, $force_recursive = false) {
8085  if (
8086  $GLOBALS['egotec_conf']['rewrite_engine'] != 'url' // Nur wenn die richtige RewriteEngine eingestellt ist
8087  || (
8088  $_SERVER['HTTP_X_SOAP_CALL'] == 'Replication' // Erfolgt der Aufruf über den Liveabgleich
8089  && $this->getSite()->getCache()->getEternal() // und ist die "ewige" Cache aktiv, werden keine URLs aktualisiert
8090  )
8091  || $this->field['deleted'] // Gelöschte Seiten haben keine URLs
8092  || ($this->field['nav_hide']&8) == 8 // Unsichtbare Seiten haben keine URLs (werden nicht in der Sitemap angezeigt)
8093  || $this->isWorkflowCopy() // Workflowkopien haben keine URLs
8094  || $this->isReleaseCopy() // Freigabekopien haben keine URLs
8095  || strpos($this->field['type'], '/occupancy/') // Buchungen der Resourcenverwaltung haben keine URLs
8096  ) {
8097  return;
8098  }
8099 
8100  $db = new_db_connection();
8101 
8107  $get_current_urls = function() use ($db) {
8108  $db->select(array(
8109  'table' => 'egotec_url',
8110  'fields' => 'site, lang, id, domain, dir, path, canonical',
8111  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical = 1',
8112  'bind' => array(
8113  'site' => $this->_site->name,
8114  'lang' => $this->_site->language,
8115  'id' => $this->field['id']
8116  )
8117  ));
8118  $urls = array();
8119  while ($db->nextRecord()) {
8120  $urls[] = $db->Record;
8121  }
8122  return $urls;
8123  };
8124 
8125  $old_urls = $get_current_urls();
8126 
8127  if (!$this->field['inactive']) {
8128  $now = date('Y-m-d H:i:s');
8129 
8130  // Alle primären und sekundären virtuellen Hosts ermitteln
8131  $virtual_hosts = $this->_site->getVirtualHosts();
8132 
8133  // Zu verwendende Konfiguration ermitteln
8134  $conf = $this->_site->getRewriteConf();
8135 
8136  // Pfade generieren
8137  $paths = array();
8138 
8139  if (!empty($this->field['url'])) {
8140  // Eindeutige Meta URL
8141  $paths[] = array(
8142  'name' => ''
8143  );
8144  $space = $conf['space'];
8145  if (empty($space)) {
8146  $space = '+';
8147  }
8148  $name = str_replace(' ', $space, $this->field['url']);
8149  $names = array($name);
8150  } else {
8151  if (!$conf['flat']) {
8152  // URLs aus allen Pfaden
8153  $paths = $this->getPaths(false, true);
8154  }
8155  if (empty($paths)) {
8156  // URLs ohne Pfad
8157  $paths[] = array(
8158  'name' => ''
8159  );
8160  }
8161 
8162  // Alle möglichen Namen dieser Seite für die URLs
8163  $names = $this->getUrlNames();
8164  }
8165  if ($this->field['id'] == $this->_site->rootId) {
8166  // Die Startseite kennt auch URLs ohne Namen
8167  array_unshift($names, '');
8168  }
8169 
8170  foreach ($names as $ni => $name) {
8171  foreach ($paths as $pi => $path) {
8172  $dir = trim($GLOBALS['egotec_conf']['url_dir'] . implode('/', array_filter(array($path['name'], $name))), '/');
8173  foreach ($virtual_hosts as $vi => $virtual_host) {
8174  $this_dir = $dir;
8175  // Domains mit /abc übergeben die Erweiterung dem Pfad
8176  $virtual_host = rtrim($virtual_host, '/');
8177  if ($part = strstr($virtual_host, '/')) {
8178  $virtual_host = strstr($virtual_host, '/', true);
8179  $this_dir = trim($part . "/{$dir}", '/');
8180  }
8181 
8182  $params = array(
8183  'site' => $this->_site->name,
8184  'lang' => $this->_site->language,
8185  'id' => $this->field['id'],
8186  'domain' => $virtual_host,
8187  'dir' => $this_dir,
8188  'path' => (string)$path['id']
8189  );
8190 
8191  // Sicherstellen, dass der Pfad einmalig ist (archivierte URLs werden bei der Prüfung ignoriert)
8192  $unique_dir = $this_dir;
8193  $duplicate_params = $params;
8194  unset($duplicate_params['site'], $duplicate_params['lang'], $duplicate_params['id']);
8195  $n = 1;
8196  while (true) {
8197  $duplicate_params['dir'] = $unique_dir;
8198  $db->select(array(
8199  'table' => 'egotec_url',
8200  'where' => 'domain = :domain AND dir = :dir AND path = :path',
8201  'bind' => $duplicate_params
8202  ));
8203  if ($db->nextRecord()) {
8204  if (
8205  $db->Record['site'] == $this->_site->name
8206  && $db->Record['lang'] == $this->_site->language
8207  && $db->Record['id'] == $this->field['id']
8208  && !$db->nextRecord()
8209  ) {
8210  break;
8211  }
8212  if ($db->Record['canonical'] == 0) {
8213  $db->delete(array(
8214  'table' => 'egotec_url',
8215  'where' => 'site = :site AND lang = :lang AND id = :id AND domain = :domain AND dir = :dir AND path = :path AND canonical = 0',
8216  'bind' => array(
8217  'site' => $db->Record['site'],
8218  'lang' => $db->Record['lang'],
8219  'id' => $db->Record['id'],
8220  'domain' => $db->Record['domain'],
8221  'dir' => $db->Record['dir'],
8222  'path' => $db->Record['path']
8223  )
8224  ));
8225  } else {
8226  $unique_dir = $this_dir . '-' . $n++;
8227  }
8228  } else {
8229  break;
8230  }
8231  }
8232  $params['dir'] = $unique_dir;
8233 
8234  // Doppelte Einträge vermeiden
8235  $db->begin();
8236  $db->delete(array(
8237  'table' => 'egotec_url',
8238  'where' => 'domain = :domain AND dir = :dir',
8239  'bind' => array(
8240  'domain' => $params['domain'],
8241  'dir' => $params['dir']
8242  )
8243  ));
8244 
8245  // Neue kanonische URL einfügen
8246  $db->insert(array(
8247  'table' => 'egotec_url',
8248  'set' => array_merge($params, array(
8249  'canonical' => $ni == 0 && $vi == 0 ? 1 : 2,
8250  'c_date' => $now
8251  ))
8252  ));
8253  $db->commit();
8254  }
8255  }
8256  }
8257 
8258  // Permalinks hinzufügen
8259  $db->delete(array(
8260  'table' => 'egotec_url',
8261  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical = 3',
8262  'bind' => array(
8263  'site' => $this->_site->name,
8264  'lang' => $this->_site->language,
8265  'id' => $this->field['id']
8266  )
8267  ));
8268 
8269  $db->begin();
8270  foreach ($virtual_hosts as $vi => $virtual_host) {
8271  $dir = '';
8272 
8273  // Domains mit /abc übergeben die Erweiterung dem Pfad
8274  $virtual_host = rtrim($virtual_host, '/');
8275  if ($part = strstr($virtual_host, '/')) {
8276  $virtual_host = strstr($virtual_host, '/', true);
8277  $dir = ltrim($part . '/', '/');
8278  }
8279 
8280  $db->replace(array(
8281  'table' => 'egotec_url',
8282  'set' => array(
8283  'site' => $this->_site->name,
8284  'lang' => $this->_site->language,
8285  'id' => $this->field['id'],
8286  'domain' => $virtual_host,
8287  'dir' => "{$dir}-{$this->field['id']}",
8288  'path' => '',
8289  'canonical' => 3,
8290  'c_date' => $now
8291  ),
8292  'primary' => [ 'domain', 'dir' ]
8293  ));
8294  }
8295  $db->commit();
8296 
8297  // Alle alten URLs archivieren
8298  $db->update(array(
8299  'table' => 'egotec_url',
8300  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical > 0 AND c_date < :c_date',
8301  'bind' => array(
8302  'site' => $this->_site->name,
8303  'lang' => $this->_site->language,
8304  'id' => $this->field['id'],
8305  'c_date' => $now
8306  ),
8307  'set' => array(
8308  'canonical' => 0
8309  )
8310  ));
8311  }
8312 
8313  if ($verbose) {
8314  Ego_System::flush('.');
8315  }
8316 
8317  // Rekursiv alle Unterseiten aktualisieren
8318  if (
8319  $force_recursive
8320  || (
8321  $this->field['id'] != $this->_site->rootId // nicht für die Startseite
8322  && serialize($old_urls) != serialize($get_current_urls()) // und nur, wenn sich die URLs dieser Seite geändert haben
8323  )
8324  ) {
8325  $children = $this->getChildren(array(), array(
8326  'auth_or' => '1=1',
8327  'inactive' => true,
8328  'only_active' => false,
8329  'sitemap' => true // Seiten, die nicht in der Sitemap angezeigt werden, haben keine URLs
8330  ));
8331  foreach ($children as $child) {
8332  $child->updateUrls($verbose, $force_recursive); // @TODO Performancegewinn wenn man die bereits berechneten URLs weitergibt?
8333  }
8334  }
8335  }
8336 
8342  public function archiveUrls() {
8343  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'url') {
8344  $db = new_db_connection();
8345  $db->begin();
8346 
8347  $db->update(array(
8348  'table' => 'egotec_url',
8349  'where' => 'site = :site AND lang = :lang AND id = :id AND canonical > 0',
8350  'bind' => array(
8351  'site' => $this->_site->name,
8352  'lang' => $this->_site->language,
8353  'id' => $this->field['id']
8354  ),
8355  'set' => array(
8356  'canonical' => 0
8357  )
8358  ));
8359 
8360  $db->commit();
8361  }
8362  }
8363 
8369  public function removeUrls() {
8370  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'url') {
8371  $db = new_db_connection();
8372  $db->begin();
8373 
8374  $db->delete(array(
8375  'table' => 'egotec_url',
8376  'where' => 'site = :site AND lang = :lang AND id = :id',
8377  'bind' => array(
8378  'site' => $this->_site->name,
8379  'lang' => $this->_site->language,
8380  'id' => $this->field['id']
8381  )
8382  ));
8383 
8384  $db->commit();
8385  }
8386  }
8387 
8393  protected function getUrlNames() {
8394  // Der Name der Seite wird für die URL vorgesehen
8395  $name = $this->field['name'];
8396 
8397  // Zu verwendende Konfiguration ermitteln
8398  $conf = $this->_site->getRewriteConf();
8399 
8400  // Umlaute ersetzen
8401  if ($conf['umlauts']) {
8402  $name = str_replace(array('Ä', 'Ö', 'Ü', 'ä', 'ö', 'ü', 'ß'), array('Ae', 'Oe', 'Ue', 'ae', 'oe', 'ue', 'ss'), $name);
8403  }
8404 
8405  // Groß- und Kleinschreibung
8406  switch ($conf['case']) {
8407  // Alles groß
8408  case 'upper':
8409  $name = mb_strtoupper($name);
8410  break;
8411 
8412  // Alles klein
8413  case 'lower':
8414  $name = mb_strtolower($name);
8415  }
8416 
8417  // Leerzeichen ersetzen
8418  $space = $conf['space'];
8419  if (empty($space)) {
8420  $space = '+';
8421  }
8422  $name = str_replace(' ', $space, $name);
8423 
8424  // Ungültige Zeichen entfernen
8425  $name = strtr($name, "%\n\r\t,;#?:&/'\".\\", '_______________'); // @TODO Notwendig?
8426 
8427  if ($name[0] == '-') {
8428  // Der Name darf nicht mit - beginnen (reserviert für Permalink)
8429  $name[0] = '_';
8430  }
8431 
8432  // Fallback auf kundenspezifische Datei
8433  $url_file = $GLOBALS['egotec_conf']['var_dir'] . 'lib/url.php';
8434  if (Ego_System::file_exists($url_file)) {
8435  require_once $url_file;
8436  $result = get_url_names($this, $conf, $name/* Vom System generierter Name */);
8437  if (sizeof($result) > 0) {
8438  foreach ($result as $key => $value) {
8439  if ($value[0] == '-') {
8440  // Der Name darf nicht mit - beginnen (reserviert für Permalink)
8441  $result[$key][0] = '_';
8442  }
8443  }
8444  return $result;
8445  }
8446  }
8447 
8448  return array($name);
8449  }
8450 
8458  public function updateLinks($inherited = true) {
8459  $links = array();
8460 
8461  // Alle alten Verweise löschen
8462  $this->removeLinks();
8463 
8464  if (!$this->field['deleted']) {
8465  // Alle Verweise sammeln und speichern (nicht für Multimedia Dateien)
8466  if (!in_array($this->field['type'], array('multimedia/file', 'multimedia/image'))) {
8467  $this->updateLinksRecursive($links, $this->field['content'], true);
8468  }
8469  $this->updateLinksRecursive($links, $this->extra);
8470 
8471  $db = new_db_connection();
8472  $db->begin();
8473  foreach ($links as $link) {
8474  $db->insert(array(
8475  'table' => 'egotec_links',
8476  'set' => $link
8477  ));
8478  }
8479  $db->commit();
8480 
8481  /* Bei einer Multimedia Datei müssen alle Verweise
8482  * auf eine Multimedia Kategorie aktualisiert werden */
8483  if ($inherited && $this->_site->site['type'] == 'media') {
8484  $params = array(
8485  'inactive' => true,
8486  'only_active' => false,
8487  'no_cache' => true,
8488  'auth_or' => '1=1',
8489  'deleted' => -1
8490  );
8491  foreach ($this->getAncestors(array(
8492  'where' => "type = 'multimedia/category'"
8493  ), $params) as $ancestor) {
8494  $db->select(array(
8495  'table' => 'egotec_links',
8496  'where' => 'dest_site = :site AND dest_lang = :lang AND dest_id = :id',
8497  'bind' => array(
8498  'site' => $this->_site->name,
8499  'lang' => $this->_site->language,
8500  'id' => $ancestor->field['id']
8501  )
8502  ));
8503  while ($db->nextRecord()) {
8504  try {
8505  $site = new Site($db->Record['src_site'], $db->Record['src_lang']);
8506  if ($page = $site->getPage($db->Record['src_id'], $params)) {
8507  $page->updateLinks(false);
8508  }
8509  } catch (Site_Exception $e) {
8510  // Mandant existiert nicht
8511  }
8512  }
8513  }
8514  }
8515  }
8516  }
8517 
8528  private function updateLinksRecursive(&$links, $data, $only_nodes = false, $extra = array(), $num = 0) {
8529  set_time_limit(0);
8530  $params = array(
8531  'inactive' => true,
8532  'only_active' => false,
8533  'no_cache' => true,
8534  'auth_or' => '1=1',
8535  'deleted' => -1
8536  );
8537  if (is_array($data)) {
8538  foreach ($data as $key => $value) {
8539  $tmp = $extra;
8540  $tmp[] = $key;
8541  $this->updateLinksRecursive($links, $value, $only_nodes, $tmp, $num);
8542  }
8543  } elseif (!empty($extra)) {
8544  try {
8545  if ($media = $this->_site->getMediaSite()) {
8546  $more_links = array();
8547  switch ($this->field['type']) {
8548  case 'gallery':
8549  if (
8550  end($extra) == 'gallery_path'
8551  && ($page = $media->getPage($data, array('internal' => true)))
8552  ) {
8553  $more_links[] = $page;
8554  foreach ($page->getChildren(array(), $params) as $child) {
8555  $more_links[] = $child;
8556  }
8557  }
8558  break;
8559  case 'gallery2':
8560  if (end($extra) == 'media_verz') {
8561  $page = Ego_System::urltopage($data);
8562  if ($page) {
8563  $more_links[] = $page;
8564  foreach ($page->getChildren(array(), $params) as $child) {
8565  $more_links[] = $child;
8566  }
8567  }
8568  }
8569  break;
8570  case 'medialist':
8571  case 'buergerservice/leistung/entry':
8572  if (end($extra) == 'multimedia_id') {
8573  if (is_numeric($data)) {
8574  $page = $media->getPage($data, array('internal' => true));
8575  } else {
8576  $page = Ego_System::urltopage($data);
8577  }
8578  if ($page) {
8579  $more_links[] = $page;
8580  foreach ($page->getDescendants(array(), $params) as $descendant) {
8581  $more_links[] = $descendant;
8582  }
8583  }
8584  }
8585  break;
8586  case 'buergerservice/leistung/list':
8587  if (
8588  end($extra) == 'mm_mainDir'
8589  && ($page = $media->getPage($data, array('internal' => true)))
8590  ) {
8591  $more_links[] = $page;
8592  foreach ($page->getDescendants(array(), $params) as $descendant) {
8593  $more_links[] = $descendant;
8594  }
8595  }
8596  break;
8597  case 'wiki/diskussion':
8598  case 'wiki/kommentar':
8599  case 'wiki/portal':
8600  case 'wiki/portal_list':
8601  case 'wiki/page':
8602  if (end($extra) == 'documents') {
8603  foreach (explode(',', $data) as $id) {
8604  if ($page = $media->getPage($id)) {
8605  $more_links[] = $page;
8606  }
8607  }
8608  }
8609  }
8610 
8615  try {
8616  $more_links = array_merge($more_links, $this->getMoreLinks());
8617  } catch (Exception $e) {
8618  // ignorieren
8619  }
8620 
8621  reset($extra);
8622  foreach ($more_links as $link) {
8623  if (!$link) {
8624  continue;
8625  }
8626  $links[] = array(
8627  'src_site' => $this->_site->name,
8628  'src_lang' => $this->_site->language,
8629  'src_id' => $this->field['id'],
8630  'dest_site' => $link->getSite()->name,
8631  'dest_lang' => $link->getSite()->language,
8632  'dest_id' => $link->field['id'],
8633  'tag' => '',
8634  'text' => '',
8635  'num' => 1,
8636  'extra_key' => implode(',', $extra)
8637  );
8638  }
8639  }
8640  } catch (Site_Exception $e) {
8641  // ignorieren
8642  }
8643  }
8644  if (is_string($data)) {
8645  // index.php URLs
8646  if ($only_nodes) {
8647  $pattern = '/(<([^> ]+) [^>]*)(href="|src="|data="|value="|archive="|class="|url\(\')([^,"\']*(index\.php\?|-site-)([^,"\']+))(["\'][^>]*>((.*?)<\/\\2>)?)/ims';
8648  } else {
8649  $pattern = '/(<([^> ]+) [^>]*)?(href="|src="|data="|value="|archive="|class="|url\(\')?([^,"\']*(index\.php\?|-site-)([^,"\']+))(["\'][^>]*>((.*?)<\/\\2>)?)?/ims';
8650  }
8651  if (preg_match_all($pattern, $data, $matches)) {
8652  foreach ($matches[0] as $index => $value) {
8653  $url = rtrim($matches[4][$index], '\\');
8654  $info = Ego_System::getUrlInfo(str_replace(
8655  '&amp;',
8656  '&',
8657  $url
8658  ));
8659  if ($info['params']['p']) {
8660  $info['params']['id'] = $info['params']['p'];
8661  }
8662  if ($info['params']['site'] && $info['params']['id']) {
8663  $lang = $info['params']['lang'];
8664  if (empty($lang)) {
8665  try {
8666  $site = new Site($info['params']['site']);
8667  $site->addParam($params);
8668  } catch (Exception $e) {
8669  continue;
8670  }
8671  $lang = $site->language;
8672  }
8673  try {
8674  $page = Ego_System::urltopage($url, array('params' => array('param' => $params)));
8675  } catch (Exception $e) {
8676  continue;
8677  }
8678  if (!$page) {
8679  continue;
8680  }
8681  $text = (string)$matches[9][$index];
8682  $links[] = array(
8683  'src_site' => $this->_site->name,
8684  'src_lang' => $this->_site->language,
8685  'src_id' => $this->field['id'],
8686  'dest_site' => (string)$info['params']['site'],
8687  'dest_lang' => (string)$lang,
8688  'dest_id' => (int)$info['params']['id'],
8689  'tag' => (string)$matches[2][$index],
8690  'text' => $text,
8691  'num' => ++$num,
8692  'extra_key' => implode(',', $extra)
8693  );
8694  if (trim($text) != '') {
8695  $this->updateLinksRecursive($links, $text, $only_nodes, $extra, $num);
8696  }
8697  if (stripos($matches[0][$index], 'target="_lightbox"') !== false) {
8698  // Bei einer Lightbox werden alle Geschwister ebenfalls verwendet
8699  foreach ($page->getSiblings() as $sibling) {
8700  if (
8701  $sibling->field['type'] == 'multimedia/image'
8702  && !$sibling->field['deleted']
8703  && !$sibling->field['inactive']
8704  ) {
8705  $links[] = array(
8706  'src_site' => $this->_site->name,
8707  'src_lang' => $this->_site->language,
8708  'src_id' => $this->field['id'],
8709  'dest_site' => (string)$info['params']['site'],
8710  'dest_lang' => (string)$lang,
8711  'dest_id' => $sibling->field['id'],
8712  'tag' => (string)$matches[2][$index],
8713  'text' => $text,
8714  'num' => $num,
8715  'extra_key' => implode(',', $extra)
8716  );
8717  }
8718  }
8719  }
8720  }
8721  }
8722  }
8723 
8724  // Combo Plugin
8725  $pattern = '/^\{.*?"pages":\[\{.*?"(site|lang|id)":.*?\}\].*\}$/ims';
8726  if (preg_match_all($pattern, $data, $matches)) {
8727  require_once('base/Ego_Combo.php');
8728  foreach ($matches[0] as $value) {
8729  try {
8730  $combo = new Ego_Combo($value);
8731  foreach ($combo->getPages(true) as $page) {
8732  $links[] = array(
8733  'src_site' => $this->_site->name,
8734  'src_lang' => $this->_site->language,
8735  'src_id' => $this->field['id'],
8736  'dest_site' => $page->getSite()->name,
8737  'dest_lang' => $page->getSite()->language,
8738  'dest_id' => $page->field['id'],
8739  'tag' => '',
8740  'text' => '',
8741  'num' => 1,
8742  'extra_key' => implode(',', $extra)
8743  );
8744  }
8745  } catch (Ego_Combo_Exception $e) {
8746  // ignorieren
8747  }
8748  }
8749  }
8750 
8751  // Identitäten
8752  $pattern = '/[a-z0-9_]+'
8753  .preg_quote(self::IDENTITY_SEPARATOR, '/')
8754  .'[a-z]{2}'
8755  .preg_quote(self::IDENTITY_SEPARATOR, '/')
8756  .'\d+/ims';
8757  if (preg_match_all($pattern, $data, $matches)) {
8758  foreach ($matches[0] as $value) {
8759  try {
8760  $page = self::byIdentity($value, $params);
8761  if ($page) {
8762  $links[] = array(
8763  'src_site' => $this->_site->name,
8764  'src_lang' => $this->_site->language,
8765  'src_id' => $this->field['id'],
8766  'dest_site' => $page->getSite()->name,
8767  'dest_lang' => $page->getSite()->language,
8768  'dest_id' => $page->field['id'],
8769  'tag' => '',
8770  'text' => '',
8771  'num' => 1,
8772  'extra_key' => implode(',', $extra)
8773  );
8774  }
8775  } catch (Site_Exception $e) {
8776  // ignorieren
8777  }
8778  }
8779  }
8780  }
8781  }
8782 
8788  public function removeLinks() {
8789  $db = new_db_connection();
8790  $db->delete(array(
8791  'table' => 'egotec_links',
8792  'where' => "src_site = '{$this->_site->name}'"
8793  ." AND src_lang = '{$this->_site->language}'"
8794  ." AND src_id = '{$this->field['id']}'"
8795  ));
8796  }
8797 
8804  public function getLinks($recursive = false) {
8805  $links = array();
8806 
8807  $db = new_db_connection();
8808  $db->select(array(
8809  'table' => 'egotec_links',
8810  'where' => "src_site = :site AND src_lang = :lang AND src_id = :id",
8811  'bind' => array(
8812  'site' => $this->_site->name,
8813  'lang' => $this->_site->language,
8814  'id' => $this->field['id']
8815  )
8816  ));
8817  while ($db->nextRecord()) {
8818  $record = $db->Record;
8819 
8820  if ($recursive) {
8821  // Bei Multimedia Kategorien auch alle Nachfahren ermitteln
8822  try {
8823  $param = array(
8824  'auth_or' => '1=1',
8825  'deleted_or' => '1=1',
8826  'inactive' => true,
8827  'only_active' => false
8828  );
8829 
8830  $site = new Site($db->Record['dest_site'], $db->Record['dest_lang']);
8831  $page = $site->getPage($db->Record['dest_id'], $param);
8832 
8833  if ($page->field['type'] == 'multimedia/category') {
8834  $descendants = $page->getDescendants(array(), $param);
8835  $record['descendants'] = 0;
8836  foreach ($descendants as $descendant) {
8837  $record['descendants']++;
8838  $link = $db->Record;
8839  $link['dest_id'] = $descendant->field['id'];
8840  $link['recursive'] = true;
8841  $links[] = $link;
8842  }
8843  }
8844  } catch (Site_Exception $e) {
8845  // ignorieren
8846  }
8847  }
8848 
8849  $links[] = $record;
8850  }
8851  return $links;
8852  }
8853 
8863  public function getLinkedPages($recursive = false, $self = true) {
8864  $links = array();
8865  $param = array(
8866  'inactive' => true,
8867  'only_active' => false,
8868  'no_cache' => true,
8869  'auth_or' => '1=1',
8870  'deleted' => -1
8871  );
8872 
8873  $db = new_db_connection();
8874  if ($self) {
8875  foreach ($this->_site->getLanguages() as $lang) {
8876  if ($page = $this->getLanguagePage($lang, $param)) {
8877  $db->select(array(
8878  'table' => 'egotec_links',
8879  'where' => "dest_site = :site1 AND dest_lang = :lang AND dest_id = :id1"
8880  ." AND (src_site != :site2 OR src_id != :id2)", // Auf sich selbst ignorieren
8881  'bind' => array(
8882  'site1' => $this->_site->name,
8883  'lang' => $lang,
8884  'id1' => $this->field['id'],
8885  'site2' => $this->_site->name,
8886  'id2' => $this->field['id']
8887  )
8888  ));
8889  if ($db->nextRecord()) {
8890  $link = array(
8891  'page' => $page,
8892  'sources' => array()
8893  );
8894 
8895  // Klone werden ignoriert
8896  $clones = array();
8897  if ($page->extra['clones']) {
8898  foreach (explode(',', $page->extra['clones']) as $clone) {
8899  $info = Ego_System::getUrlInfo($clone);
8900  $clones[] = self::createIdentity($info['params']);
8901  }
8902  }
8903 
8904  do {
8905  $record = $db->Record;
8906 
8907  // Klone werden ignoriert
8908  if (!empty($clones) && in_array(self::createIdentity(array(
8909  'site' => $record['src_site'],
8910  'lang' => $record['src_lang'],
8911  'id' => $record['src_id']
8912  )), $clones)) {
8913  continue;
8914  }
8915 
8916  try {
8917  // Nur wenn diese Seite existiert
8918  $db2 = new_db_connection(array(
8919  'table' => $record['src_site'] . '_' . $record['src_lang'],
8920  'where' => 'id = :id',
8921  'bind' => array(
8922  'id' => $record['src_id']
8923  )
8924  ));
8925  } catch (Ego_Sql_Exception $e) {
8926  continue 2;
8927  }
8928  while (!$db2->nextRecord()) {
8929  continue 2;
8930  }
8931 
8932  $src_site = $record['src_site'];
8933  $src_lang = $record['src_lang'];
8934  $src_id = $record['src_id'];
8935  $num = $record['num'];
8936  $link['sources'][$src_site][$src_lang][$src_id][$num] = $record;
8937  } while ($db->nextRecord());
8938  if (!empty($link['sources'])) {
8939  $links[] = $link;
8940  }
8941  }
8942  }
8943  }
8944  }
8945 
8946  if ($recursive) {
8947  $descendants = $this->getDescendants(array(), $param);
8948  foreach ($descendants as $descendant) {
8949  $links = array_merge($links, $descendant->getLinkedPages());
8950  }
8951  }
8952 
8953  return $links;
8954  }
8955 
8963  public function getIconUrl($test = false, $folder = false) {
8964  if ($this->extra['crop_image']) {
8965  return $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/crop.png';
8966  }
8967  $url = $test
8968  ? '' // Falls diese Page kein spezielles Icon hat, dann nichts zurückgeben
8969  : ($folder && $this->hasChildren(array(), array('auth_or' => '1=1'))
8970  ? $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/folder.png'
8971  : $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/16x16/page.png');
8972  $this->getTypeInfo();
8973  if (!empty($this->typeInfo)) {
8974  if (!empty($this->typeInfo['icon'])) {
8975  $icon = $this->typeInfo['icon'];
8976  $get_path = function() use ($icon) {
8977  $real_path = (string) realpath($icon);
8978  $dir_pos = strpos($real_path, $GLOBALS['egotec_conf']['egotec_dir']);
8979  if ($dir_pos === false) {
8980  // Kann der Pfad nicht gefunden werden, dann automatisch ermitteln
8981  $dir = DIRECTORY_SEPARATOR
8982  . array_pop(explode(DIRECTORY_SEPARATOR, trim($GLOBALS['egotec_conf']['egotec_dir'], DIRECTORY_SEPARATOR)))
8983  . DIRECTORY_SEPARATOR;
8984  if ($dir_pos = strpos($real_path, $dir)) {
8985  return substr($real_path, $dir_pos + strlen($dir));
8986  }
8987  }
8988  return substr($real_path, $dir_pos + strlen($GLOBALS['egotec_conf']['egotec_dir']));
8989  };
8990  $path = $get_path(); // Abwärtskompatibilität: Pfad mit ../
8991  if (!$path) {
8992  // Pfad ausgehend von egotec_dir
8993  $cwd = getcwd();
8994  chdir($GLOBALS['egotec_conf']['egotec_dir']);
8995  $path = $get_path();
8996  chdir($cwd);
8997  }
8998  $url = $GLOBALS['egotec_conf']['url_dir'] . $path;
8999  } elseif (!empty($this->extra['image_type']) && !$folder) {
9000  $mime = strtolower($this->extra['image_type']);
9001  switch ($mime) {
9002  case 'jpeg':
9003  $mime = 'jpg';
9004  break;
9005  case 'mdb':
9006  $mime = 'access';
9007  break;
9008  case 'htm':
9009  $mime = 'html';
9010  }
9011  if (Ego_System::file_exists($GLOBALS['egotec_conf']['bin_dir'].'admin_skin/egotec/img/icons/small/2013/'.$mime.'.png')) {
9012  $url = $GLOBALS['egotec_conf']['url_dir'].'bin/admin_skin/egotec/img/icons/small/2013/'.$mime.'.png';
9013  }
9014  }
9015  }
9016  return $url;
9017  }
9018 
9024  public function getTypeInfo() {
9025  if (empty($this->typeInfo)) {
9026  $key = 'type'.md5(serialize(array($this->_site->name, $this->field['type'])));
9027  $cache = $this->_site->getCacheEntry($key);
9028  if ($cache === null) {
9029  if ($file = $this->_site->getSiteFile($this->field['type'] . DIRECTORY_SEPARATOR . 'type.ini')) {
9030  $this->typeInfo = @parse_ini_file($file, true);
9031  $this->_site->setCacheEntry($key, is_array($this->typeInfo) ? $this->typeInfo : array());
9032  }
9033  } else {
9034  $this->typeInfo = $cache;
9035  }
9036  }
9037  return $this->typeInfo;
9038  }
9039 
9045  public function canChangeType() {
9046  $type_info = $this->getTypeInfo();
9047  return $this->_site->hasRight('change_type') && empty($type_info['unchangeable']);
9048  }
9049 
9055  public function getEditorCSS() {
9056  $css = array();
9057  $content_css = '';
9058  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/table.css")) {
9059  $css['skin']['table'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/table.css";
9060  }
9061  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/table.css")) {
9062  $css['global']['table'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/table.css";
9063  }
9064  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/span.css")) {
9065  $css['skin']['span'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/span.css";
9066  }
9067  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/span.css")) {
9068  $css['global']['span'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/span.css";
9069  }
9070  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/img.css")) {
9071  $css['skin']['img'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/img.css";
9072  }
9073  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/img.css")) {
9074  $css['global']['img'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/img.css";
9075  }
9076  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/link.css")) {
9077  $css['skin']['link'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/link.css";
9078  }
9079  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/link.css")) {
9080  $css['global']['link'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/link.css";
9081  }
9082  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/".$this->field['type']."/style.css")) {
9083  $css['type']['style'] = $GLOBALS['egotec_conf']['url_dir']."skin/".$this->_site->skin."/".$this->field['type']."/style.css";
9084  $content_css = $css['type']['style'];
9085  }
9086  if (Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir'].$this->_site->skin."/style.css")) {
9087  $css['skin']['style'] = $GLOBALS['egotec_conf']['url_dir'].'skin/'.$this->_site->skin."/style.css";
9088  $content_css = $css['skin']['style'];
9089  }
9090  if ($this->_site->globalAllowed() && Ego_System::file_exists($GLOBALS['egotec_conf']['skin_dir']."_global/style.css")) {
9091  $css['global']['style'] = $GLOBALS['egotec_conf']['url_dir']."skin/_global/style.css";
9092  $content_css = $css['global']['style'];
9093  }
9094  if (
9095  $this->extra['_style']
9096  && ($file = $this->_site->getSkinFile($this->field['type'].'/style.'.$this->extra['_style'].'.css', array(), true))
9097  ) {
9098  $css['variant']['style'] = $file;
9099  $content_css = $css['variant']['style'];
9100  }
9101 
9102  // CSS Dateien aus der Designvorlage
9103  if ($this->_site->theme) {
9104  if (empty($css['theme']['table']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/table.css")) {
9105  $css['theme']['table'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/table.css";
9106  }
9107  if (empty($css['theme']['span']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/span.css")) {
9108  $css['theme']['span'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/span.css";
9109  }
9110  if (empty($css['theme']['img']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/img.css")) {
9111  $css['theme']['img'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/img.css";
9112  }
9113  if (empty($css['theme']['link']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/link.css")) {
9114  $css['theme']['link'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/link.css";
9115  }
9116  if (empty($css['theme']['style']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/".$this->field['type']."/style.css")) {
9117  $css['theme']['type'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/".$this->field['type']."/style.css";
9118  }
9119  if (empty($css['theme']['style']) && Ego_System::file_exists($GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->_site->theme."/skin/style.css")) {
9120  $css['theme']['style'] = $GLOBALS['egotec_conf']['url_dir'].'pub/theme/'.$this->_site->theme."/skin/style.css";
9121  }
9122  }
9123 
9124  // admin.css einbinden
9125  if ($GLOBALS['admin_area'] && ($file = $this->_site->getSkinFile('admin.css', array(), true))) {
9126  $css['admin']['style'] = $file;
9127  }
9128 
9129  return array(
9130  'css' => $css,
9131  'content_css' => $content_css
9132  );
9133  }
9134 
9140  public function getLinkText() {
9141  return $this->field['name'];
9142  }
9143 
9149  public function getIdentity() {
9150  return self::createIdentity(array(
9151  'site' => $this->_site->name,
9152  'lang' => $this->_site->language,
9153  'id' => $this->field['id']
9154  ));
9155  }
9156 
9163  public static function isIdentity($identity) {
9164  return is_string($identity) && preg_match('/^[a-z0-9_]+' . preg_quote(self::IDENTITY_SEPARATOR, '/') . '[a-z]{2}' . preg_quote(self::IDENTITY_SEPARATOR, '/') . '\d+$/i', $identity);
9165  }
9166 
9173  public static function createIdentity($params) {
9174  return implode(self::IDENTITY_SEPARATOR, array($params['site'], $params['lang'], $params['id']));
9175  }
9176 
9185  public static function byIdentity($identity, $param = array()) {
9186  list($name, $lang, $id) = explode(self::IDENTITY_SEPARATOR, $identity);
9187  try {
9188  if (
9189  $GLOBALS['site']
9190  && $GLOBALS['site']->site == $name
9191  && $GLOBALS['site']->language == $lang
9192  ) {
9193  $site = $GLOBALS['site'];
9194  } else {
9195  $site = new Site($name, $lang, '', !$GLOBALS['admin_area'] || $_SESSION['login']['live_preview']);
9196  }
9197  if (!is_array($param)) {
9198  $param = array();
9199  }
9200  return $site->getPage($id, $param);
9201  } catch (Site_Exception $e) {
9202  // ignorieren
9203  }
9204  return null;
9205  }
9206 
9216  public function inheritExtra($keys, $mixed = false, $types = array(), $no_rights = true) {
9217  $values = array();
9218 
9219  if (!empty($keys)) {
9220  $query = array();
9221  if (!empty($types)) {
9222  // Die Vorfahren müssen einen bestimmten Seitentyp haben
9223  $query['where'] = array();
9224  $query['bind'] = array();
9225  $n = 0;
9226  foreach ($types as $type) {
9227  $query['where'][] = 'type = :type'.(++$n);
9228  $query['bind']['type'.$n] = $type;
9229  }
9230  $query['where'] = implode(' OR ', $query['where']);
9231  }
9232  $param = array();
9233  if ($no_rights) {
9234  // Keine Rechteprüfung
9235  $param['auth_or'] = '1=1';
9236  }
9237 
9238  $ancestors = array();
9239  // Vorfahren umdrehen
9240  foreach ($this->getAncestors($query, $param) as $ancestor) {
9241  $ancestors[] = $ancestor;
9242  }
9243  $ancestors = array_reverse($ancestors);
9244  array_unshift($ancestors, $this);
9245  foreach ($ancestors as $ancestor) {
9246  foreach ($keys as $key) {
9247  $value = Ego_System::getAssocValue($ancestor->extra, $key);
9248  if ($value !== null && !isset($values[$key])) {
9249  $values[$key] = $value;
9250  if (!$mixed) {
9251  // Alle Werte dieses Vorfahren übernehmen
9252  foreach ($keys as $k) {
9253  if ($key != $k) {
9254  $v = Ego_System::getAssocValue($ancestor->extra, $k);
9255  if ($v !== null) {
9256  $values[$k] = $v;
9257  }
9258  }
9259  }
9260  return $values;
9261  }
9262  }
9263  }
9264  }
9265  }
9266 
9267  return $values;
9268  }
9269 
9275  public function addPiwikSite() {
9276  require_once 'stats/Ego_Piwik.php';
9277  $piwik = new Ego_Piwik();
9278  $piwikdata = $piwik->createWebsite($this);
9279  if (!is_array($piwikdata)) {
9280  return null;
9281  }
9282  return $piwikdata;
9283  }
9284 
9291  public function isUniqueUrl($url) {
9292  $ignore_ids = array($this->field['id']);
9293 
9294  // Seite ist eine Workflow-, Freigabekopie: Meta URL der Originalseite ignorieren
9295  if ($this->isWorkflowCopy()) {
9296  $ignore_ids[] = (int) $this->extra['original_id'];
9297 
9298  $original_page = $this->_site->getPage((int) $this->extra['original_id']);
9299  if (!empty($original_page->extra['release_ids'])) {
9300  foreach ($original_page->extra['release_ids'] as $release_id) {
9301  $ignore_ids[] = (int) $release_id;
9302  }
9303  }
9304  }
9305  if ($this->isReleaseCopy()) {
9306  $ignore_ids[] = (int) $this->extra['release_id'];
9307 
9308  $original_page = $this->_site->getPage((int) $this->extra['release_id']);
9309  if (!empty($original_page->extra['workflow_page'])) {
9310  $ignore_ids[] = (int) $original_page->extra['workflow_page'];
9311  }
9312  }
9313 
9314  // Seite hat Workflow-, Freigabekopien: Meta URLs dieser Seiten ignorieren
9315  if (!empty($this->extra['release_ids'])) {
9316  foreach ($this->extra['release_ids'] as $release_id) {
9317  $ignore_ids[] = (int) $release_id;
9318  }
9319  }
9320  if (!empty($this->extra['workflow_page'])) {
9321  $ignore_ids[] = (int) $this->extra['workflow_page'];
9322  }
9323 
9324  $db = new_db_connection(array(
9325  'table' => $this->_site->pageTable,
9326  'where' => 'url = :url AND deleted = 0 AND id NOT IN (' . implode(', ', array_unique($ignore_ids)) . ')',
9327  'bind' => array(
9328  'url' => $url
9329  )
9330  ));
9331  if (!$db->nextRecord()) {
9332  // Bei der flachen URL Generierung darf es keine Seite mit diesem Namen geben
9333  if ($GLOBALS['egotec_conf']['rewrite_engine'] == 'flat') {
9334  $db->select(array(
9335  'table' => $this->_site->pageTable,
9336  'where' => 'name = :name AND id != :id AND deleted = 0',
9337  'bind' => array(
9338  'name' => $url,
9339  'id' => $this->field['id']
9340  )
9341  ));
9342  if ($db->nextRecord()) {
9343  return false;
9344  }
9345  }
9346 
9347  // Bei der Standard URL Generierung darf es keine Seite in erster Ebene mit diesem Namen geben
9348  if (empty($GLOBALS['egotec_conf']['rewrite_engine'])) {
9349  $db->select(array(
9350  'table' => $this->_site->pageTable,
9351  'where' => 'page_id = :root_id AND name = :name AND id != :id AND deleted = 0',
9352  'join' => $this->_site->pageTable.'_children ON ('.$this->_site->pageTable.'_children.child = id)',
9353  'bind' => array(
9354  'root_id' => $this->_site->rootId,
9355  'name' => $url,
9356  'id' => $this->field['id']
9357  )
9358  ));
9359  if ($db->nextRecord()) {
9360  return false;
9361  }
9362  }
9363 
9364  // Der Name darf nicht von einem Mandanten verwendet werden
9365  foreach (Ego_System::getAllSites() as $site) {
9366  if ($site->name == $url) {
9367  return false;
9368  }
9369  }
9370  return true;
9371  }
9372  return false;
9373  }
9374 
9384  public function validateFile($source, $name = '', $form = array(), $files_conf = array()) {
9385  $files_list = array();
9386 
9387  // Übergebene Einstellungen verwenden
9388  if (!empty($files_conf)) {
9389  $files_list[] = $files_conf;
9390  }
9391 
9392  // Einstellungen des Dateiupload Feldes verwenden (alter Editor)
9393  if (!empty($form) && !empty($this->extra['mandatory'][$form['form']][$form['field']]['files'])) {
9394  $files_list[] = $this->extra['mandatory'][$form['form']][$form['field']]['files'];
9395  }
9396 
9397  // Einstellungen des Mandanten verwenden
9398  if (!empty($this->_site->admin['files'])) {
9399  $files_list[] = $this->_site->admin['files'];
9400  }
9401 
9402  // Einstellungen der globalen Konfiguration verwenden
9403  if (!empty($GLOBALS['egotec_conf']['files'])) {
9404  $files_list[] = $GLOBALS['egotec_conf']['files'];
9405  }
9406 
9407  if (!empty($files_list)) {
9408  require_once('base/Ego_MimeType.php');
9409  $mime = new Ego_MimeType();
9410  $prepare_type = function($t) {
9411  return trim(ltrim(mb_strtolower($t), "."));
9412  };
9413  $type = $prepare_type(pathinfo($name ? $name : @basename($source), PATHINFO_EXTENSION));
9414  $size = @filesize($source);
9415  foreach ($files_list as $files) {
9416  if (!empty($files['whitelist']) || !empty($files['blacklist']) || !empty($files['filesize'])) {
9417  $whitelist = array_map($prepare_type, explode(',', (string) $files['whitelist']));
9418  $blacklist = array_map($prepare_type, explode(',', (string) $files['blacklist']));
9419  if (
9420  (!empty($files['whitelist']) && (!in_array($type, $whitelist) || !$mime->hasMimeType($source, $whitelist)))
9421  || (!empty($files['blacklist']) && empty($files['whitelist']) && (in_array($type, $blacklist) || $mime->hasMimeType($source, $blacklist)))
9422  || (!empty($files['filesize']) && $size > (int) $files['filesize'])
9423  ) {
9424  return false;
9425  }
9426 
9427  // Die Prüfung abbrechen, da die Anforderungen erfüllt sind
9428  break;
9429  }
9430  }
9431  }
9432 
9433  return true;
9434  }
9435 
9442  public function isFrontendAdmin($check_rights = true) {
9443  $info = $this->getTypeInfo();
9444  return $this->_site->isFrontendAdmin($check_rights)
9445  && !$info['frontend_ignore']
9446  && (
9447  !$check_rights
9448  || $this->hasRights(array('view'))
9449  );
9450  }
9451 
9458  public function isCurrentPage($lang = false) {
9459  return ($_REQUEST['site'] ? $_REQUEST['site'] : $GLOBALS['default_site']) == $this->_site->name
9460  && (!$lang || ($_REQUEST['lang'] ? $_REQUEST['lang'] : $this->_site->site['default_language']) == $this->_site->language)
9461  && ($_REQUEST['id'] ? $_REQUEST['id'] : ($_REQUEST['list'] ? $_REQUEST['list'] : $this->_site->rootId)) == $this->field['id'];
9462  }
9463 
9469  public function setCurrentPage() {
9470  $_REQUEST['site'] = $this->_site->name;
9471  $_REQUEST['lang'] = $this->_site->language;
9472  $_REQUEST['id'] = $this->field['id'];
9473  $GLOBALS['site'] = &$this->_site;
9474  $GLOBALS['page'] = &$this;
9475  }
9476 
9483  public function reset($self = true) {
9484  $db = new_db_connection();
9485 
9486  // Archiv
9487  if ($self) {
9488  // Zurücksetzen
9489  $db->delete(array(
9490  'table' => $this->_site->pageTable.'_v',
9491  'where' => "id = {$this->field['id']} AND c_date > :date",
9492  'bind' => array(
9493  'date' => $this->lastChangeDate
9494  )
9495  ));
9496  } else {
9497  // Veröffentlichen
9498  $db->delete(array(
9499  'table' => $this->_site->pageTable.'_v',
9500  'where' => "id = {$this->field['id']} AND c_date > :date1 AND c_date != :date2",
9501  'bind' => array(
9502  'date1' => $this->lastChangeDate,
9503  'date2' => $this->field['c_date']
9504  )
9505  ));
9506  }
9507 
9508  // Mediapool
9509  $last_c_date = Ego_System::dateEncode($this->lastChangeDate);
9510  $this_c_date = Ego_System::dateEncode($this->field['c_date']);
9511  foreach (glob($this->getMediapool()->dir().'*', GLOB_ONLYDIR) as $dir) {
9512  $dir_c_date = basename($dir);
9513  if (
9514  is_numeric($dir_c_date)
9515  && (int) $dir_c_date != $this_c_date
9516  && (int) $dir_c_date > $last_c_date
9517  ) {
9518  Ego_System::deldir($dir);
9519  }
9520  }
9521  }
9522 
9528  public function getNextReplicationDate() {
9529  return $this->_site->getNextReplicationDate($this);
9530  }
9531 
9537  public function getCacheEntry($key) {
9538  return $this->_site->getCacheEntry("{$key}_{$this->field['id']}");
9539  }
9540 
9548  public function setCacheEntry($key, $value) {
9549  $this->_site->setCacheEntry("{$key}_{$this->field['id']}", $value);
9550  }
9551 
9559  public function getListItems($where = '') {
9560  $items = array();
9561  foreach ($this->getChildren(array(
9562  'where' => $where
9563  ), array(
9564  'inactive' => true,
9565  'only_active' => false
9566  )) as $child) {
9567  $child->field['identity'] = $child->getIdentity();
9568  $items[] = $child;
9569  }
9570  return $items;
9571  }
9572 
9579  public function addListItem($params) {
9580  $this->newChild(array(
9581  'name' => (string) $params['data']->name,
9582  'title' => (string) $params['data']->name,
9583  'type' => $params['type'] ? $params['type'] : 'page'
9584  ));
9585  }
9586 
9593  public function removeListItem($params) {
9594  if ($page = self::byIdentity($params['identity'])) {
9595  $page->destroy();
9596  return true;
9597  }
9598  return false;
9599  }
9600 
9607  public function removeSelectedListItem($params) {
9608  foreach ($params['data']->identities as $identity) {
9609  if ($page = self::byIdentity($identity)) {
9610  $page->destroy();
9611  }
9612  }
9613  return true;
9614  }
9615 
9622  public function reorderListItem($params) {
9623  $children = array();
9624  foreach ($params['data'] as $identity) {
9625  list($name, $lang, $id) = explode(self::IDENTITY_SEPARATOR, $identity);
9626  if ($name == $this->_site->name && $lang == $this->_site->language) {
9627  $children[] = (int) $id;
9628  }
9629  }
9630 
9631  $this->archiveOnly = false;
9632  $this->update(array(
9633  'field' => array(
9634  'children_order' => 'children'
9635  ),
9636  'children' => $children
9637  ));
9638  }
9639 
9646  public function getFormListConf($orient) {
9647  $conf = array(
9648  'a_date' => array(
9649  'title' => $GLOBALS['auth']->translate('Empfangen'),
9650  'formatter' => 'date'
9651  )
9652  );
9653  if (is_array($this->extra['_blocks'][$orient])) {
9654  $upload = false;
9655  foreach ($this->extra['_blocks'][$orient] as $index => $block) {
9656  if (strpos($block, 'input_') === 0 && $block != 'input_submit' && isset($this->extra['_contents'][$orient][$index])) {
9657  if ($block == 'input_file' && $this->extra['_forms'][$orient]['export'] == 'page') {
9658  $upload = true;
9659  continue;
9660  }
9661  $content = $this->extra['_contents'][$orient][$index];
9662  $label = $content['label'] ? trim($content['label'], ' :') : $content['extra']['name'];
9663  if ($block == 'input_checkbox') {
9664  require_once 'base/Ego_Combo.php';
9665  $combo = new Ego_Combo($content['extra']['values']);
9666  foreach ($combo->getData() as $data) {
9667  $conf["data.{$data->field_name}"] = array(
9668  'title' => $label . ': ' . ($data->label ? trim($data->label, ' :') : $data->field_name),
9669  'type' => 'extra'
9670  );
9671  }
9672  } elseif (isset($content['extra']['name'])) {
9673  $conf["data.{$content['extra']['name']}"] = array(
9674  'title' => $content['label'] ? trim($content['label'], ' :') : $content['extra']['name'],
9675  'type' => 'extra'
9676  );
9677  }
9678  }
9679  }
9680  if ($upload) {
9681  // Mediapool der Unterseiten anzeigen
9682  $conf['pool'] = array(
9683  'title' => $GLOBALS['auth']->translate('Dateien'),
9684  'formatter' => 'pool',
9685  'width' => 75,
9686  'align' => 'center'
9687  );
9688  }
9689  }
9690  return $conf;
9691  }
9692 
9703  public function fetch($params = array(), $outputfilter = false, $script = true, $includes = true, $variant = '') {
9704  if ($template = $this->getTemplate($GLOBALS['is_mobile'], 'body', $variant)) {
9705  $original_site = $GLOBALS['site'];
9706  $original_page = $GLOBALS['page'];
9707  $original_smarty = $GLOBALS['smarty'];
9708  $GLOBALS['site'] = $site = $this->getSite();
9709  $GLOBALS['page'] = $page = $this;
9710 
9711  // Jedes "fetch" muss ein auf die Site und Page eingestelltes Smarty Objekt für das Frontend verwenden
9712  $GLOBALS['smarty'] = $smarty = Ego_Smarty::createFrontend($site, array(
9713  'page' => $page
9714  ), true);
9715 
9716  // Skript für den Seitentyp einbinden (Sandbox)
9717  $require_script = function($filename) use ($site, $page, $smarty) {
9718  require($filename);
9719  };
9720  if ($script && ($filename = $site->getSiteFile($page->field['type'].'/index.php'))) {
9721  $require_script($filename);
9722  }
9723  if (!$outputfilter) {
9724  unset($smarty->_plugins['outputfilter'], $smarty->autoload_filters['output']);
9725  }
9726  $smarty->assign(array_merge(array(
9727  'site' => $site,
9728  'page' => $page
9729  ), $params));
9730 
9731  // Styles und Skripte einbinden
9732  $html = $includes ? $page->getHtml(false) : '';
9733  $html .= $smarty->fetch($template);
9734 
9735  $GLOBALS['site'] = $original_site;
9736  $GLOBALS['page'] = $original_page;
9737  $GLOBALS['smarty'] = $original_smarty;
9738  } else {
9739  $html = $this->field['content'];
9740  }
9741  return $html;
9742  }
9743 
9750  public function isValidSuffix($suffix) {
9751  $result = true;
9752  switch ($this->_site->site['type']) {
9753  case 'media':
9754  // Multimedia Dateien müssen immer auf .<image_type> enden.
9755  if (
9756  in_array($this->field['type'], array('multimedia/file', 'multimedia/image'))
9757  && !empty($this->extra['image_type'])
9758  && '.' . $this->extra['image_type'] != $suffix
9759  ) {
9760  $result = false;
9761  }
9762  break;
9763  case 'content':
9764  $key = 'suffixes';
9765  $suffixes = $this->_site->getCacheEntry($key);
9766  $type = $this->field['type'];
9767  if ($GLOBALS['is_mobile']) {
9768  $type .= '@mobile';
9769  }
9770  $result = $suffixes[$type][$suffix];
9771  if (!is_bool($result)) {
9772  $result = true;
9773  // Nur wenn nicht .html und bestimmte <suffix> Ausnahmen, die in Seitentypen abgefragt werden.
9774  // Existiert index.<suffix>.* nicht, muss body.<suffix>.* existieren.
9775  if (
9776  !in_array($suffix, array('.html', '.rss', '.ical', '.ics'))
9777  && ($template = $this->getTemplate($GLOBALS['is_mobile'], 'index'))
9778  && strpos(basename($template), "index{$suffix}.") !== 0
9779  && ($template = $this->getTemplate($GLOBALS['is_mobile'], 'body'))
9780  && strpos(basename($template), "body{$suffix}.") !== 0
9781  ) {
9782  $result = false;
9783  }
9784  $suffixes[$type][$suffix] = $result;
9785  $this->_site->setCacheEntry($key, $suffixes);
9786  }
9787  }
9788  return $result;
9789  }
9790 
9796  public function getSocialNetworks() {
9797  if (in_array($this->field['type'], explode(',', $this->_site->admin['social']['types']))) {
9798  return $this->_site->getSocialNetworks();
9799  }
9800  return array();
9801  }
9802 
9808  public function compressVideo() {
9809  @set_time_limit(0);
9810 
9811  // Pfad zur Originaldatei (Multimedia)
9812  $media_dir = $GLOBALS['egotec_conf']['var_dir'] . 'media/' . $this->_site->name;
9813  $dest = $media_dir . DIRECTORY_SEPARATOR . $this->getMediaFilename(true);
9814 
9815  // Auflösung der Originaldatei ermitteln
9816  $resolution = Ego_System::exec('ffprobe', array(
9817  '-v',
9818  'error',
9819  '-select_streams',
9820  'v:0',
9821  '-show_entries',
9822  'stream=height',
9823  '-of',
9824  'csv=s=x:p=0',
9825  $dest,
9826  '2>&1'
9827  ));
9828 
9829  // Mediapool Dateien entfernen
9830  $this->getMediapool()->clear();
9831 
9832  foreach (self::VIDEO_RESOLUTIONS as $height => $scale) {
9833  if ($resolution > $height) {
9834  $tmp = tempnam($GLOBALS['egotec_conf']['tmp_dir'], 'video');
9835 
9836  // Verarbeitungsstatus verfolgen
9837  require_once 'base/Ego_Progress.php';
9838  $progress = new Ego_Progress('worker_' . $this->getIdentity() . '_' . $height . 'p');
9839  Ego_System::exec('ffmpeg', array(
9840  '-i',
9841  $dest,
9842  '-vf',
9843  'scale='.$scale,
9844  '-f',
9845  'mp4',
9846  '-strict',
9847  '-2',
9848  '-y',
9849  $tmp,
9850  '-hide_banner',
9851  '2>&1'
9852  ), $output);
9853 
9854  // Komprimierte Datei in den Mediapool der Originaldatei ablegen
9855  if (Ego_System::file_exists($tmp)) {
9856  $this->getMediapool()->put($tmp, "{$height}p.mp4");
9857  @unlink($tmp);
9858  }
9859 
9860  $progress->clear();
9861  }
9862  }
9863  }
9864 
9875  public function getThumbnail($width, $height = 0, $pool = '', $dir = '', $params = []) {
9876  // Pfad, in welchem das generierte Thumbnail zwischengespeichert wird
9877  $thumbnail = $GLOBALS['egotec_conf']['cachemedia_dir']
9878  . $this->_site->name . '/'
9879  . $this->_site->language . '/'
9880  . $this->field['id'] . '/'
9881  . strtotime($this->field['c_date']) . '/'
9882  . 'thumb_' . $width . 'x' . $height . '_' . md5(serialize([$pool, $dir, $params]));
9883 
9884  if (!Ego_System::file_exists($thumbnail)) {
9885  $file = '';
9886  $mime = '';
9887  if ($pool) {
9888  // Mediapool
9889  $info = $this->getMediapool()->get($pool, $dir);
9890  if (!empty($info)) {
9891  $file = $info['file'];
9892  $mime = $info['mime'];
9893  }
9894  } elseif (in_array($this->field['type'], ['multimedia/file', 'multimedia/image'])) {
9895  // Multimedia
9896  $file = $GLOBALS['egotec_conf']['var_dir'] . 'media/' . $this->_site->name . '/' . $this->getMediaFilename();
9897  $mime = $this->extra['mime_type'];
9898  }
9899 
9900  // Pfad erzeugen, falls er nicht existiert
9901  $thumbnail_dir = dirname($thumbnail);
9902  if (!Ego_System::file_exists($thumbnail_dir)) {
9903  Ego_System::mkdir($thumbnail_dir);
9904  }
9905 
9906  // Thumbnail neu generieren
9907  if ($file && Ego_System::file_exists($file)) {
9908  if ($mime == 'application/pdf' || strpos($mime, 'image') === 0) {
9909  // PDF, Animationen und Bilder können über "index" das erste Frame festlegen
9910  require_once 'base/Ego_Image.php';
9911  $image = new Ego_Image($file . '[' . ($params['index'] ?? 0) . ']');
9912  if ($tmp = $image->thumbnail($width, $height, $params)) {
9913  // Temporäres Thumbnail in den Cache verschieben
9914  @rename($tmp, $thumbnail);
9915  } else {
9916  return null;
9917  }
9918  } else {
9919  // TODO Videos mit ffmpeg
9920  return null;
9921  }
9922  }
9923  }
9924 
9925  // Die Thumbnail URL für die Verwendung im Template zurückliefern
9926  if ($params['get_url']) {
9927  return $this->getUrl(array_filter([
9928  'thumbnail' => implode('x', array_filter([$width, $height, (int) $params['index']])),
9929  'pool' => $pool,
9930  'dir' => $dir
9931  ]));
9932  }
9933 
9934  return $thumbnail;
9935  }
9936 }
newChild($field=array(), $extra=array(), $inherit=true)
Definition: Page.php:842
static includeHtml($src, $once=true)
getLinks($recursive=false)
Definition: Page.php:8804
getIndex($index=null)
Definition: Page.php:6460
validateFile($source, $name='', $form=array(), $files_conf=array())
Definition: Page.php:9384
getEditorCSS()
Definition: Page.php:9055
updateUrls($verbose=false, $force_recursive=false)
Definition: Page.php:8084
static pathinfo($string)
Definition: Ego_System.php:275
release()
Definition: Page.php:6852
move($from, $to)
Definition: Page.php:1498
download($recursive=true, $target_dir='', $write_log=true)
Definition: Page.php:7136
static getChecksum($value)
removeListItem($params)
Definition: Page.php:9593
_updateKeywords($asis=false)
Definition: Page.php:1981
isActive()
Definition: Page.php:6926
removeLinks()
Definition: Page.php:8788
static checkLicence($ini_path)
Definition: Ego_System.php:963
static stringEncode($string, $from='UTF-8', $to='UTF-8')
Definition: Ego_System.php:448
static filterData($data)
Definition: Ego_System.php:391
fetch($params=array(), $outputfilter=false, $script=true, $includes=true, $variant='')
Definition: Page.php:9703
static deldir($location, $del=true, $without='', $rename=true)
Definition: Ego_System.php:593
getClones()
Definition: Page.php:2565
isPublic()
Definition: Page.php:6997
reset($self=true)
Definition: Page.php:9483
static getUserRecord($user_id)
Definition: Auth.php:993
_destroyEntry($recursive=true)
Definition: Page.php:1666
setCacheEntry($key, $value)
Definition: Page.php:9548
isCurrentPage($lang=false)
Definition: Page.php:9458
isPublicSave()
Definition: Page.php:6986
$field
Definition: Page.php:41
getFormListConf($orient)
Definition: Page.php:9646
archiveUrls()
Definition: Page.php:8342
extractFile($source)
Definition: Page.php:1104
_getAncestorsIds($page, $query, $param=array())
Definition: Page.php:666
static urltopage($url, $params=array(), $only_site=false, $error_page=false, $commit_params=false)
getValue($name, $orient=null, $index=null, $verbose=false)
Definition: Page.php:6479
static encode_path($url, $id=0)
getThumbnail($width, $height=0, $pool='', $dir='', $params=[])
Definition: Page.php:9875
isValidSuffix($suffix)
Definition: Page.php:9750
getLinkText()
Definition: Page.php:9140
newRelease($date='')
Definition: Page.php:6786
$_updatedLinkLanguages
Definition: Page.php:52
hasFile($name, $suffix='')
Definition: Page.php:968
destroyClone()
Definition: Page.php:2730
const ROOT_PROTECTION
Definition: Page.php:12
static getJSON($path, $values=array(), $combine=false, $ignore=[])
updateLinks($inherited=true)
Definition: Page.php:8458
getNextReplicationDate()
Definition: Page.php:9528
static getAllSites($username='', $perm='', $table=false, $type='')
_destroyChildClones($parent)
Definition: Page.php:2695
getNonPublic()
Definition: Page.php:6940
getArchivePages($query=array())
Definition: Page.php:7055
static flush($string='')
Definition: Ego_System.php:724
addListItem($params)
Definition: Page.php:9579
static file_exists($file)
getFormats($type='')
Definition: Page.php:6182
static filesize($file)
Definition: Page.php:27
isFrontendAdmin($check_rights=true)
Definition: Page.php:9442
getArchivePage($c_date='')
Definition: Page.php:7020
_updateChildren($children)
Definition: Page.php:2069
__call($function, $params)
Definition: Page.php:383
__construct(Site $site, $field)
Definition: Page.php:72
isClone()
Definition: Page.php:6898
getCacheEntry($key)
Definition: Page.php:9537
getUrlNames()
Definition: Page.php:8393
reorderListItem($params)
Definition: Page.php:9622
updateFile($source, $name='')
Definition: Page.php:1139
static getMimeTypes($ext='')
hasRights($rights, $user_id=false)
Definition: Page.php:798
compressVideo()
Definition: Page.php:9808
getIdentity()
Definition: Page.php:9149
static mkdir($dir, $mode=0755, $recursive=true)
Definition: Ego_System.php:497
static getCluster($site=null)
static isIdentity($identity)
Definition: Page.php:9163
_updateClones(&$param)
Definition: Page.php:2330
getHtml($root=false)
Definition: Page.php:6398
copyTo($id, $recursive=false, $params=array(), &$copied_pages=array())
Definition: Page.php:1293
unlinkFrom($remove_from)
Definition: Page.php:1901
newFile($source, $name, $options=array(), $suffix='')
Definition: Page.php:995
getValues($name, $orient=null, $verbose=false)
Definition: Page.php:6522
_updateField($field, $update=true, $asis=false)
Definition: Page.php:1919
static createIdentity($params)
Definition: Page.php:9173
getLinkedPages($recursive=false, $self=true)
Definition: Page.php:8863
const FILE_REPLACE
Definition: Page.php:13
getIconUrl($test=false, $folder=false)
Definition: Page.php:8963
static setAssocValue(&$a, $k, $v)
setCurrentPage()
Definition: Page.php:9469
isLanguageLink()
Definition: Page.php:6907
const EXIF_COPYRIGHT
Definition: Ego_Image.php:20
getSocialNetworks()
Definition: Page.php:9796
getTableSuffix()
Definition: Page.php:427
$extra
Definition: Page.php:42
static getAssocValue($a, $k)
static getUrlInfo($url, $encode=false)
createClone($page, $children=false, $release=false, $multiple=true)
Definition: Page.php:2593
addPiwikSite()
Definition: Page.php:9275
merge($id)
Definition: Page.php:6651
frontendAdmin()
Definition: Page.php:7406
_updateRights($rights)
Definition: Page.php:2776
getBlockValues($block, $name, $orient=null, $verbose=false)
Definition: Page.php:6600
destroy($force=false, $recursive=true)
Definition: Page.php:1748
getBlockValue($block, $name, $orient=null, $index=null, $verbose=false)
Definition: Page.php:6577
static copy($src, $dest, $except='', $useLinks=false)
static byIdentity($identity, $param=array())
Definition: Page.php:9185
getNonPublics($c_user=null)
Definition: Page.php:6967
inheritExtra($keys, $mixed=false, $types=array(), $no_rights=true)
Definition: Page.php:9216
isReleaseCopy()
Definition: Page.php:6889
getListItems($where='')
Definition: Page.php:9559
setTableSuffix($suffix='')
Definition: Page.php:437
isUniqueUrl($url)
Definition: Page.php:9291
getToolbar($type='')
Definition: Page.php:6311
static dateEncode($string)
Definition: Ego_System.php:484
getUser($user_type='c')
Definition: Page.php:447
isWorkflowCopy()
Definition: Page.php:6880
_createClone($page, $children=false, $release=false, $multiple=true)
Definition: Page.php:2607
getOrient($orient=null)
Definition: Page.php:6444
static filterNonUtf8($s, $substitute="", $strict=false)
Definition: Ego_System.php:320
getLastChangeDate()
Definition: Page.php:7010
getTypeInfo()
Definition: Page.php:9024
getFirstBlockValue($block, $name, $orient=null, $verbose=false)
Definition: Page.php:6627
hasRightsOn($perm)
Definition: Page.php:808
export()
Definition: Page.php:7354
_destroyClone()
Definition: Page.php:2740
static exec(String $command, Array $params=array(), Array &$output=null, &$return_var=null)
getFirstValue($name, $orient=null, $verbose=false)
Definition: Page.php:6549
removeSelectedListItem($params)
Definition: Page.php:9607
removeUrls()
Definition: Page.php:8369
_updateParents($parents)
Definition: Page.php:2127
createEditField($name, $setting=array(), $empty=false, $orient='', $index=0, $block='', $replace=false)
Definition: Page.php:7513
linkTo($id)
Definition: Page.php:1511
inheritBlocks()
Definition: Page.php:6151
_createChildClones($parent)
Definition: Page.php:2660
undelete($recursive=false, $query=array())
Definition: Page.php:1823
canChangeType()
Definition: Page.php:9045
Definition: Site.php:29
isArchive()
Definition: Page.php:6917