dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
dbxTPL.class.php
Go to the documentation of this file.
1<?php
277
278class dbxTPL extends \dbxObj {
279
283 private $maxDepth = 10;
284 public $_modul = 'dbx';
285
286
287 /* =========================================================
288 BASIC REPLACE
289 ========================================================= */
290
294 function replaces(string $tpl, $replaces): string {
295
296 if (!is_array($replaces)) {
297 $replaces = dbx()->parse_url($replaces);
298 }
299
300 if (!is_array($replaces) || !$replaces) {
301 return $tpl;
302 }
303
304 $map = array();
305 foreach ($replaces as $key => $value) {
306 if (is_array($value) || is_object($value)) {
307 $value = '';
308 }
309
310 $map['{' . $key . '}'] = (string) ($value ?? '');
311 }
312
313 return $map ? strtr($tpl, $map) : $tpl;
314 }
315
316
320 public function replaces_dbx(string $tpl): string {
321
322 $tpl = str_replace('{dbx:base_href}', dbx()->get_base_url(), $tpl);
323 $tpl = str_replace('{dbx:design}' , dbx()->get_system_var('dbx_activ_design', dbx()->get_system_var('dbx_design')), $tpl);
324 $tpl = str_replace('{dbx:color}' , dbx()->get_skin(), $tpl);
325 $tpl = str_replace('{dbx:skin_css}' , dbx()->get_skin_css(), $tpl);
326 $tpl = str_replace('{dbx:skin_class}', dbx()->get_skin_class(), $tpl);
327 $tpl = str_replace('{dbx:page}' , dbx()->get_system_var('dbx_activ_page', dbx()->get_system_var('dbx_page')), $tpl);
328 $tpl = str_replace('{dbx:lng}' , dbx()->get_system_var('dbx_activ_lng', dbx()->get_system_var('dbx_lng')), $tpl);
329 $tpl = str_replace('{dbx:title}' , htmlspecialchars((string)dbx()->get_system_var('dbx_title'), ENT_QUOTES, 'UTF-8'), $tpl);
330 $tpl = str_replace('{dbx:perma}' , dbx()->get_system_var('dbx_perma'), $tpl);
331
332 $meta_description = (string)dbx()->get_system_var('dbx_meta_description', '');
333 $meta_keywords = (string)dbx()->get_system_var('dbx_meta_keywords', '');
334 $canonical = (string)dbx()->get_system_var('dbx_canonical', '');
335 $robots = $this->effective_robots_meta();
336 $og_title = (string)dbx()->get_system_var('dbx_og_title', '');
337 $og_description = (string)dbx()->get_system_var('dbx_og_description', '');
338 $og_url = (string)dbx()->get_system_var('dbx_og_url', '');
339 $og_image = (string)dbx()->get_system_var('dbx_og_image', '');
340
341 $tpl = str_replace('{dbx:meta_description}', $this->seo_attr_esc($meta_description), $tpl);
342 $tpl = str_replace('{dbx:meta_keywords}' , $this->seo_attr_esc($meta_keywords), $tpl);
343 $tpl = str_replace('{dbx:canonical}' , $this->seo_attr_esc($canonical), $tpl);
344 $tpl = str_replace('{dbx:robots}' , $this->seo_attr_esc($robots), $tpl);
345 $tpl = str_replace('{dbx:og_title}' , $this->seo_attr_esc($og_title), $tpl);
346 $tpl = str_replace('{dbx:og_description}' , $this->seo_attr_esc($og_description), $tpl);
347 $tpl = str_replace('{dbx:og_url}' , $this->seo_attr_esc($og_url), $tpl);
348 $tpl = str_replace('{dbx:og_image}' , $this->seo_attr_esc($og_image), $tpl);
349 $tpl = str_replace('{dbx:head_meta}' , $this->build_head_meta_block(), $tpl);
350
351 return $tpl;
352 }
353
354 private function seo_attr_esc($value): string {
355 return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
356 }
357
358 private function build_head_meta_block(): string {
359 $lines = array();
360
361 $description = trim((string)dbx()->get_system_var('dbx_meta_description', ''));
362 if ($description !== '') {
363 $lines[] = '<meta name="description" content="' . $this->seo_attr_esc($description) . '">';
364 }
365
366 $keywords = trim((string)dbx()->get_system_var('dbx_meta_keywords', ''));
367 if ($keywords !== '') {
368 $lines[] = '<meta name="keywords" content="' . $this->seo_attr_esc($keywords) . '">';
369 }
370
371 $canonical = trim((string)dbx()->get_system_var('dbx_canonical', ''));
372 if ($canonical !== '') {
373 $lines[] = '<link rel="canonical" href="' . $this->seo_attr_esc($canonical) . '">';
374 }
375
376 $robots = $this->effective_robots_meta();
377 if ($robots !== '') {
378 $lines[] = '<meta name="robots" content="' . $this->seo_attr_esc($robots) . '">';
379 }
380
381 $og_title = trim((string)dbx()->get_system_var('dbx_og_title', ''));
382 if ($og_title !== '') {
383 $lines[] = '<meta property="og:title" content="' . $this->seo_attr_esc($og_title) . '">';
384 }
385
386 $og_description = trim((string)dbx()->get_system_var('dbx_og_description', ''));
387 if ($og_description !== '') {
388 $lines[] = '<meta property="og:description" content="' . $this->seo_attr_esc($og_description) . '">';
389 }
390
391 $og_url = trim((string)dbx()->get_system_var('dbx_og_url', ''));
392 if ($og_url !== '') {
393 $lines[] = '<meta property="og:url" content="' . $this->seo_attr_esc($og_url) . '">';
394 }
395
396 $og_image = trim((string)dbx()->get_system_var('dbx_og_image', ''));
397 if ($og_image !== '') {
398 $lines[] = '<meta property="og:image" content="' . $this->seo_attr_esc($og_image) . '">';
399 }
400
401 if ($og_title !== '' || $og_description !== '' || $og_url !== '' || $og_image !== '') {
402 $lines[] = '<meta property="og:type" content="website">';
403 }
404
405 $hreflang = (string)dbx()->get_system_var('dbx_hreflang', '');
406 if (trim($hreflang) !== '') {
407 $lines[] = ltrim($hreflang);
408 }
409
410 $jsonLd = trim((string)dbx()->get_system_var('dbx_json_ld', ''));
411 if ($jsonLd !== '') {
412 $lines[] = $jsonLd;
413 }
414
415 if (!$lines) {
416 return '';
417 }
418
419 return "\n " . implode("\n ", $lines);
420 }
421
422 private function effective_robots_meta(): string {
423 $robots = trim((string)dbx()->get_system_var('dbx_robots', ''));
424 if ($robots !== '') {
425 return $robots;
426 }
427
428 $modul = trim((string)dbx()->get_request_var('dbx_modul', '', 'parameter'));
429 $action = trim((string)dbx()->get_request_var('dbx_action', '', 'parameter'));
430 $ajax = (int)dbx()->get_system_var('dbx_ajax', 0, 'int');
431 $window = (int)dbx()->get_system_var('dbx_window', 0, 'int');
432
433 if ($modul !== '' || $action !== '' || $ajax > 0 || $window > 0) {
434 return 'noindex,follow';
435 }
436
437 return '';
438 }
439
448 public function cleanup_optional_placeholders(string $content): string {
449 return str_replace(
450 array('{bar_middle}', '[dbx:js]'),
451 '',
452 $content
453 );
454 }
455
456
457 /* =========================================================
458 TEMPLATE LOADER (MIT CACHE + LANGUAGE)
459 ========================================================= */
460
464 function read_tpl($modul, $file, $type = 'htm') {
465 //dbx_debug("## read_tpl Modul=($modul) file=($file) typ=($type)");
466 $file = strtolower($file);
467 $lng = dbx()->get_system_var('dbx_lng', '');
468
469 if (!isset($_SESSION['dbx']['cache']['tpl'])) {
470 $_SESSION['dbx']['cache']['tpl'] = [];
471 }
472
473 $cache =& $_SESSION['dbx']['cache']['tpl'];
474
475 // --- CACHE HIT ---
476 if (isset($cache[$modul][$file][$type][$lng])) {
477 return $cache[$modul][$file][$type][$lng]['tpl'];
478 }
479
480 $base = dbx_get_base_dir() . "dbx/modules/$modul/tpl/$type/";
481
482 $path = function_exists('dbx_lng_resolve_file')
483 ? dbx_lng_resolve_file($base, $file, $type, '', true)
484 : '';
485
486 if ($path === '') {
487 $file_lng = $base . $file . '_' . $lng . '.' . $type;
488 $file_def = $base . $file . '.' . $type;
489
490 if ($lng && file_exists($file_lng)) {
491 $path = $file_lng;
492 } elseif (file_exists($file_def)) {
493 $path = $file_def;
494 }
495 }
496
497 if (!$path) {
498 return "<div class='alert alert-danger'>TPL ($modul/$file.$type) not found</div>";
499 }
500
501 $tpl = file_get_contents($path);
502
503 // 🔥 DBX Replace direkt im Cache
504 $tpl = $this->replaces_dbx($tpl);
505
506 $relPath = dbx()->editor_file_path($path);
507
508 // Cache speichern
509 $cache[$modul][$file][$type][$lng] = [
510 'tpl' => $tpl,
511 'path' => $relPath // 🔥 HIER NICHT MEHR $path!
512 ];
513
514 return $tpl;
515 }
516
517
518 /* =========================================================
519 EDITOR (MARKER SYSTEM)
520 ========================================================= */
521
525 private function has_editor($modul, $isDesign, $edit, $path = ''): bool {
526 if ((int)dbx()->get_system_var('dbx_editor', 0, 'int') > 0) {
527 return false;
528 }
529
530 if ((string)dbx()->get_system_var('dbx_page', '') === '_tpledit') {
531 return false;
532 }
533
534 $isDbxModule = $this->is_dbx_template_path($path);
535
536 if ($path === '') {
537 $isDbxModule = strtolower(trim((string) $modul)) === 'dbx';
538 }
539
540 switch ($edit) {
541 case 1: return !$isDesign && !$isDbxModule;
542 case 2: return !$isDesign && $isDbxModule;
543 case 3: return !$isDesign;
544 case 9: return true;
545 }
546
547 return false;
548 }
549
550 private function is_dbx_template_path($path): bool {
551 $path = strtolower(str_replace('\\', '/', trim((string) $path)));
552 return strpos($path, 'dbx/modules/dbx/tpl/') === 0;
553 }
554
555 private function get_cached_tpl_path($modul, $file, $type): string {
556 $lng = dbx()->get_system_var('dbx_lng', '');
557 $path = $_SESSION['dbx']['cache']['tpl'][$modul][$file][$type][$lng]['path'] ?? '';
558
559 // Auch alte Session-Cache-Eintraege mit absoluten Windows-Pfaden bereinigen.
560 return $path !== '' ? dbx()->editor_file_path($path) : '';
561 }
562
563
567 private function add_marker($tpl, $modul, $file, $type) {
568 $path = $this->get_cached_tpl_path($modul, $file, $type);
569
570 if ($path) {
571 dbx()->register_editor_file('tpl', $path);
572 }
573
574 if (!$path) {
575 return $tpl;
576 }
577
578 // Tabellen-Zellen: Marker IN <td>/<th>, nicht als Geschwister davor/dahinter.
579 // Sonst zerlegt der Browser die Zuordnung in <tr> und die Markierung stimmt nicht.
580 if (preg_match('/^<t([dh])\b([^>]*)>(.*)<\/t\1>\s*$/is', $tpl, $m)) {
581 return '<t' . $m[1] . $m[2] . '><!-- DBX-TPL-START|' . $path . ' -->'
582 . $m[3] . '<!-- DBX-TPL-END --></t' . $m[1] . '>';
583 }
584
585 return "<!-- DBX-TPL-START|$path -->" . $tpl . "<!-- DBX-TPL-END -->";
586 }
587
588
589 /* =========================================================
590 INC SYSTEM
591 ========================================================= */
592
596 private function process_inc($tpl) {
597
598 $allowed = ['has_group', 'is_dbx_edit'];
599
600 return preg_replace_callback('/\‍[inc=([^\‍]]+)\‍](.*?)\‍[\/inc\‍]/s', function ($m) use ($allowed) {
601
602 $cond = trim($m[1]);
603 $content = $m[2];
604
605 if ($cond === '1') return $content;
606 if ($cond === '0') return '';
607
608 // Funktion prüfen
609 if (preg_match('/(\w+)\‍((.*?)\‍)/', $cond, $f)) {
610
611 $fn = $f[1];
612 $args = array_map('trim', explode(',', $f[2]));
613
614 // Template-Quotes entfernen:
615 // has_group('admin') -> admin
616 // has_group("admin") -> admin
617 $args = array_map(function ($arg) {
618 $arg = trim($arg);
619
620 if (
621 (substr($arg, 0, 1) === "'" && substr($arg, -1) === "'") ||
622 (substr($arg, 0, 1) === '"' && substr($arg, -1) === '"')
623 ) {
624 $arg = substr($arg, 1, -1);
625 }
626
627 return $arg;
628 }, $args);
629
630 if (in_array($fn, $allowed, true)) {
631
632 $dbx = dbx();
633
634 if (is_object($dbx) && is_callable([$dbx, $fn])) {
635 return call_user_func_array([$dbx, $fn], $args) ? $content : '';
636 }
637
638 if (function_exists($fn)) {
639 return call_user_func_array($fn, $args) ? $content : '';
640 }
641 }
642 }
643
644 return '';
645 }, $tpl);
646 }
647
648
649 /* =========================================================
650 TPL SYSTEM (REKURSIV)
651 ========================================================= */
652
656 private function process_tpl($tpl, $data, $depth) {
657
658 if ($depth > $this->maxDepth) {
659 return "<!-- MAX DEPTH -->";
660 }
661
662 return preg_replace_callback('/\‍[tpl=([^\‍]]+)\‍]/', function ($m) use ($data, $depth) {
663
664 $parts = explode('|', $m[1], 3);
665
666 $modul = $this->_modul;
667 $file = $m[1];
668
669 if (count($parts) > 1) {
670 $modul = $parts[0];
671 $file = $parts[1];
672 }
673
674 $type = $parts[2] ?? 'htm';
675
676 return $this->get_tpl($modul . '|' . $file, $data, $type, 0, $depth + 1);
677
678 }, $tpl);
679 }
680
681
682 /* =========================================================
683 MAIN ENTRY
684 ========================================================= */
685
697 public function get_tpl($file, $data = '', $type = 'htm', $i = 0, $depth = 0) {
698 if ($depth > $this->maxDepth) {
699 return "<!-- MAX DEPTH -->";
700 }
701
702 // "modul|file" Shortcut
703 $modul = 'dbx';
704 $parts = explode('|', $file);
705
706 if (count($parts) > 1) {
707 $modul = $parts[0];
708 $file = $parts[1];
709 }
710
711 // Modul Alias
712 if ($modul === 'modul') {
713 $modul = dbx()->get_system_var('dbx_activ_modul', 'dbx');
714 }
715
716 // 🔥 FIX: Nur beim ROOT setzen (Kontext stabil halten)
717 if ($depth === 0) {
718 $this->_modul = $modul;
719 }
720
721 $edit = dbx()->get_system_var('dbx_edit', 0);
722 $isDesign = 0;
723
724 // --- LOAD ---
725 $tpl = $this->read_tpl($modul, $file, $type);
726
727 // --- DATA ---
728 $tpl = $this->replaces($tpl, $data);
729
730 // --- INC ---
731 if (strpos($tpl, '[inc=') !== false) {
732 $tpl = $this->process_inc($tpl);
733 }
734
735 // --- TPL ---
736 if (strpos($tpl, '[tpl=') !== false) {
737 $tpl = $this->process_tpl($tpl, $data, $depth);
738 }
739
740 // --- MARKER ---
741 $path = $this->get_cached_tpl_path($modul, $file, $type);
742
743 if ($edit && $this->has_editor($modul, $isDesign, $edit, $path)) {
744 $tpl = $this->add_marker($tpl, $modul, $file, $type);
745 }
746
747 return $tpl;
748 }
749
750 // design template
767 function get_design_tpl($design, $page, $language = 'de', $type = 'htm', $repurl = 1) {
768
769 if (!$page) $page = 'default';
770 if (substr($page, 0, 1) == "_") $design = 'admin';
771
772 // Design Mapping (user/admin)
773 if ($design == 'admin' || $design == 'user') {
774 $config = dbx()->get_config('dbx');
775 if ($design == 'admin') $design = $config['default_design_admin'];
776 if ($design == 'user') $design = $config['default_design_user'];
777 }
778
779 $page_content = '';
780 $requested_page = $page;
781 $dir_file = $this->get_design_tpl_dir_file($type, $design, $page, false);
782
783 if (!$dir_file) {
784 if ($requested_page != 'default') {
785 dbx()->sys_msg('info', "Page ($requested_page) not exist. Use (default)");
786 }
787
788 $dir_file = $this->get_design_tpl_dir_file($type, $design, 'default', false);
789
790 if ($dir_file) {
791 $page = 'default';
792 } else {
793 dbx()->sys_msg('error', "Default page (default) not exist");
794 }
795 }
796
797 $home_url = dbx()->get_base_url();
798
799 if ($dir_file && file_exists($dir_file)) {
800
801 $dir_file = dbx_os_path_file($dir_file);
802
803 // --- LOAD ---
804 $page_content = file_get_contents($dir_file);
805
806 $page_content = $this->process_inc($page_content);
807
808 // --- SET SYSTEM STATE ---
809 dbx()->set_system_var('dbx_activ_design', $design);
810 dbx()->set_system_var('dbx_activ_page', $page);
811 dbx()->set_system_var('dbx_activ_lng', $language);
812 dbx()->register_editor_file('design', $dir_file);
813
814 // --- URL FIX ---
815 if ($repurl == 1 && $type == 'htm') {
816 $url = "dbx/design/$design/";
817 $new_url = '="' . $url;
818 $i = dbx()->next_id(); $page_content = str_replace("<head>", "<head>\n <base href=\"" . $home_url . "\"/>", $page_content);
819 $page_content = str_replace('{base_url}', $home_url, $page_content);
820 $page_content = str_replace('="../', $new_url, $page_content);
821 $page_content = str_replace('{i}', $i, $page_content);
822
823 $page_content = $this->process_tpl($page_content, [], 1); // [tpl] im Design-Template verarbeiten
824 }
825
826 // --- DBX REPLACE ---
827 $page_content = $this->replaces_dbx($page_content);
828
829 // =====================================================
830 // 🔥 DESIGN EDITOR (NEU)
831 // =====================================================
832 $edit = dbx()->get_system_var('dbx_edit', 0);
833
834 if (false && $edit == 4) {
835
836 $url =
837 '?dbx_modul=dbxAdmin' .
838 '&dbx_run1=_edittpl_file' .
839 '&file=' . urlencode($dir_file);
840
841 $icon =
842 '<a href="' . $url . '" class="dbx-win" ' .
843 'data-url="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" data-title="Template bearbeiten" data-width="900" data-height="80%" ' .
844 'style="
845 position:absolute;
846 top:10px;
847 left:10px;
848 z-index:9999;
849 background:rgba(0,0,0,0.7);
850 color:#fff;
851 font-size:12px;
852 padding:2px 5px;
853 border-radius:3px;
854 text-decoration:none;
855 ">✎</a>';
856
857 // 👉 direkt nach <body> einfügen
858 $page_content = preg_replace(
859 '/<body([^>]*)>/i',
860 '<body$1>' . "\n" . $icon,
861 $page_content,
862 1
863 );
864 }
865 }
866
867 // --- PHP TEMPLATE ---
868 if ($type == 'php') {
869 $dir_file = $this->get_design_tpl_dir_file('php', $design, $page, false);
870 if ($dir_file && file_exists($dir_file)) {
871 include $dir_file;
872 }
873 }
874
875 return $page_content;
876 }
877
878 function get_design_tpl_dir_file($type, $design, $file, $fallback = true) {
879
880 // Basisverzeichnis
881 $base = dbx_get_base_dir() . "dbx/design/$design/$type/";
882
883 // 1. gewünschte Datei (mit Sprachsuffix)
884 $dir_file = function_exists('dbx_lng_resolve_file')
885 ? dbx_lng_resolve_file($base, $file, $type, '', false)
886 : '';
887
888 if ($dir_file === '' && file_exists($base . $file . '.' . $type)) {
889 $dir_file = $base . $file . '.' . $type;
890 }
891
892 if ($dir_file) {
893 return $dir_file;
894 }
895
896 if (!$fallback) {
897 return '';
898 }
899
900 // 2. fallback: default (mit Sprachsuffix)
901 $dir_file = function_exists('dbx_lng_resolve_file')
902 ? dbx_lng_resolve_file($base, 'default', $type, '', false)
903 : '';
904
905 if ($dir_file === '' && file_exists($base . 'default.' . $type)) {
906 $dir_file = $base . 'default.' . $type;
907 }
908
909 if ($dir_file) {
910 return $dir_file;
911 }
912
913 // 3. nichts gefunden
914 return '';
915 }
916
917}
918
919
920
921
922
Gemeinsame Basisklasse fuer dbXapp-System-, Modul- und Include-Objekte.
Definition dbxKernel.php:63
get_tpl($file, $data='', $type='htm', $i=0, $depth=0)
Zentrale Template-Funktion.
get_design_tpl_dir_file($type, $design, $file, $fallback=true)
cleanup_optional_placeholders(string $content)
Entfernt optionale Template-Slots, die bis zur finalen Ausgabe absichtlich unverarbeitet bleiben duer...
read_tpl($modul, $file, $type='htm')
Lädt Template + cached es (inkl.
get_design_tpl($design, $page, $language='de', $type='htm', $repurl=1)
Lädt das Design-Template für eine bestimmte Seite und Sprache.
replaces(string $tpl, $replaces)
Ersetzt {var} durch Werte aus $data.
replaces_dbx(string $tpl)
Ersetzt DBX-Systemvariablen (CACHEBAR!).
$config['version']
Definition config.php:2
dbx_os_path_file($path_file)
Definition index.php:164
if( $syncRequest)
Definition index.php:520
dbx_get_base_dir($cut_Data=0)
Definition index.php:157
DBX schema administration.