dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
dbxDesignService_contract_test.php
Go to the documentation of this file.
1<?php
2
4 public string $root;
5 public string $files;
6 public array $config = array(
7 'dbx' => array('default_design_user' => 'source', 'default_design_admin' => 'source'),
8 );
9
10 public function get_base_dir(): string {
11 return rtrim($this->root, '/\\') . DIRECTORY_SEPARATOR;
12 }
13
14 public function get_file_dir(): string {
15 return $this->files;
16 }
17
18 public function os_path(string $path): string {
19 return str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
20 }
21
22 public function get_config(string $module, string $key = '', $default = 'undef') {
23 if ($key === '') {
24 return $this->config[$module] ?? $default;
25 }
26 return $this->config[$module][$key] ?? $default;
27 }
28
29 public function set_config(string $module, array $config): void {
30 $this->config[$module] = $config;
31 }
32}
33
35 static $api;
36 if (!$api) {
38 }
39 return $api;
40}
41
42$remove = static function(string $dir) use (&$remove): void {
43 if (!is_dir($dir)) return;
44 foreach (new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS) as $file) {
45 if ($file->isDir()) $remove($file->getPathname());
46 else unlink($file->getPathname());
47 }
48 rmdir($dir);
49};
50
51$tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'dbx-design-service-test-' . bin2hex(random_bytes(5));
52dbx()->root = $tmp;
53dbx()->files = $tmp . DIRECTORY_SEPARATOR . 'files';
54$source = $tmp . DIRECTORY_SEPARATOR . 'dbx' . DIRECTORY_SEPARATOR . 'design' . DIRECTORY_SEPARATOR . 'source';
55foreach (array('htm', 'css', 'js', 'img') as $sub) {
56 mkdir($source . DIRECTORY_SEPARATOR . $sub, 0777, true);
57}
58file_put_contents($source . '/htm/default.htm', '<html><head><title>{dbx:title}</title><link href="{dbx:skin_css}"></head><body class="{dbx:skin_class}" data-dbx-design="{dbx:design}">[dbx:content]<script src="dbx/js/lib/core.js?design={dbx:design}"></script></body></html>');
59file_put_contents($source . '/css/colors.css', ':root{--dbx-primary:#123456}');
60file_put_contents($source . '/css/base.css', '.source{background:url("../img/a.png")}');
61file_put_contents($source . '/css/theme.css', '.card{}');
62
63require_once dirname(__DIR__) . '/include/dbxDesignService.class.php';
64$service = new \dbx\dbxDesign_admin\dbxDesignService();
65
66$result = $service->createFromWizard(array_merge($service->defaults('source'), array(
67 'source_design' => 'source',
68 'target_design' => 'customer-design',
69 'title' => 'Customer Design',
70 'brand_name' => 'Customer',
71 'tagline' => 'Einfach gut',
72 'layout' => 'sidebar',
73 'set_default' => 1,
74)));
75
76$target = $tmp . '/dbx/design/customer-design';
77$defaultHtml = (string)file_get_contents($target . '/htm/default.htm');
78$metadata = json_decode((string)file_get_contents($target . '/design.json'), true);
79
80$fail = static function(string $message, int $code) use ($remove, $tmp): void {
81 fwrite(STDERR, "FAIL: $message\n");
83 exit($code);
84};
85
86if (($result['name'] ?? '') !== 'customer-design' || !is_dir($target)) {
87 $fail('Wizard hat das Zielpaket nicht angelegt.', 1);
88}
89if (substr_count($defaultHtml, '[dbx:content]') !== 1) {
90 $fail('Content-Slot ist nicht exakt einmal vorhanden.', 2);
91}
92foreach (array('[dbx:logo]', '[dbx:branding]', '[dbx:footer]') as $slot) {
93 if (strpos($defaultHtml, $slot) === false) {
94 $fail('Design-Slot fehlt: ' . $slot, 3);
95 }
96}
97if (($metadata['contract'] ?? '') !== \dbx\dbxDesign_admin\dbxDesignService::CONTRACT) {
98 $fail('design.json hat nicht den verbindlichen Vertrag.', 4);
99}
100if ((dbx()->config['dbx']['default_design_user'] ?? '') !== 'customer-design') {
101 $fail('Explizites Setzen als Frontend-Standard wurde nicht gespeichert.', 5);
102}
103$validation = $service->validateDesignDirectory($target, true);
104if (!empty($validation['errors'])) {
105 $fail('Erzeugtes Design ist ungueltig: ' . implode(' ', $validation['errors']), 6);
106}
107if ($service->isAllowedDesignFile('../escape.php') || $service->isAllowedDesignFile('htm/evil.php')) {
108 $fail('Dateigrenze akzeptiert einen unzulaessigen Pfad.', 7);
109}
110
111$delta = $tmp . '/result/design';
112mkdir($delta . '/htm', 0777, true);
113file_put_contents($delta . '/htm/branding.htm', '<strong>Customer Update</strong>');
114$evil = $delta . '/htm/evil.htm';
115file_put_contents($evil, '<button onclick="fetch(\'https://evil.invalid\')">x</button>');
116if ($service->validateResultFile('htm/evil.htm', $evil) === '') {
117 $fail('Aktiver Inline-/Fremdcode wurde im KI-Ergebnis akzeptiert.', 8);
118}
119unlink($evil);
120$updated = $service->applyResult('source', 'customer-design', $delta, 'update');
121if (empty($updated['backup']) || !is_file($updated['backup'])) {
122 $fail('Update hat kein wiederherstellbares ZIP-Backup erstellt.', 9);
123}
124if ((string)file_get_contents($target . '/htm/branding.htm') !== '<strong>Customer Update</strong>') {
125 $fail('Validiertes Update wurde nicht atomar uebernommen.', 10);
126}
127
129echo "OK dbxDesignService contract\n";
if(!is_array( $before)||(int)( $before[ 'id'] ?? 0) !==$mediaId) if((string)($before['media_type'] ?? '') !=='video') $updated
get_config(string $module, string $key='', $default='undef')
set_config(string $module, array $config)
if(($result['name'] ?? '') !=='customer-design'||!is_dir($target)) if(substr_count( $defaultHtml, '[dbx:content]') !==1) foreach(array('[dbx:logo]', '[dbx:branding]', '[dbx:footer]') as $slot) if(( $metadata[ 'contract'] ?? '') !==\dbx\dbxDesign_admin\dbxDesignService::CONTRACT) if((dbx() ->config['dbx']['default_design_user'] ?? '') !=='customer-design') $validation
if(!empty( $validation[ 'errors'])) if($service->isAllowedDesignFile('../escape.php')|| $service->isAllowedDesignFile('htm/evil.php')) $delta
exit
Definition index.php:146
DBX schema administration.