dolibarr 22.0.5
website2.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
32function dolSaveMasterFile($filemaster)
33{
34 // Now generate the master.inc.php page
35 dol_syslog("We regenerate the master.inc.php file");
36
37 dol_delete_file($filemaster);
38
39 $mastercontent = '<?php'."\n";
40 $mastercontent .= '// File generated to link to the master file - DO NOT MODIFY - It is just an include'."\n";
41 $mastercontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) {\n";
42 $mastercontent .= " if (! defined('USEEXTERNALSERVER')) define('USEEXTERNALSERVER', 1);\n";
43 $mastercontent .= " require_once '".DOL_DOCUMENT_ROOT."/master.inc.php';\n";
44 $mastercontent .= "}\n";
45 $mastercontent .= '?>'."\n";
46 $result = file_put_contents($filemaster, $mastercontent);
47 dolChmod($filemaster);
48
49 return $result;
50}
51
62function dolSavePageAlias($filealias, $object, $objectpage)
63{
64 // Now create the .tpl file
65 dol_syslog("dolSavePageAlias We regenerate the alias page filealias=".$filealias." and a wrapper into all language subdirectories");
66
67 $aliascontent = '<?php'."\n";
68 $aliascontent .= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n";
69 $aliascontent .= 'global $dolibarr_main_data_root;'."\n";
70 $aliascontent .= 'if (empty($dolibarr_main_data_root)) $res=include \'./page'.$objectpage->id.'.tpl.php\'; ';
71 $aliascontent .= 'else $res=include $dolibarr_main_data_root.\'/website/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n";
72 $aliascontent .= 'if ($res === false) { http_response_code(500); print \'Failed to make include\'; }'."\n";
73 $aliascontent .= '?>'."\n";
74 $result = file_put_contents($filealias, $aliascontent);
75 if ($result === false) {
76 dol_syslog("Failed to write file ".$filealias, LOG_WARNING);
77 }
78 dolChmod($filealias);
79
80 // Save also alias into language subdirectory if it is not a main language
81 if ($objectpage->lang && in_array($objectpage->lang, explode(',', $object->otherlang))) {
82 $dirname = dirname($filealias);
83 $filename = basename($filealias);
84 $filealiassub = $dirname.'/'.$objectpage->lang.'/'.$filename;
85
86 dol_mkdir($dirname.'/'.$objectpage->lang, DOL_DATA_ROOT);
87
88 $aliascontent = '<?php'."\n";
89 $aliascontent .= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n";
90 $aliascontent .= 'global $dolibarr_main_data_root;'."\n";
91 $aliascontent .= 'if (empty($dolibarr_main_data_root)) $res=include \'../page'.$objectpage->id.'.tpl.php\'; ';
92 $aliascontent .= 'else $res=include $dolibarr_main_data_root.\'/website/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n";
93 $aliascontent .= 'if ($res === false) { http_response_code(500); print \'Failed to make include\'; }'."\n";
94 $aliascontent .= '?>'."\n";
95 $result = file_put_contents($filealiassub, $aliascontent);
96 if ($result === false) {
97 dol_syslog("Failed to write file ".$filealiassub, LOG_WARNING);
98 }
99 dolChmod($filealiassub);
100 } elseif (empty($objectpage->lang) || !in_array($objectpage->lang, explode(',', $object->otherlang))) {
101 // Save also alias into all language subdirectories if it is a main language
102 if (!getDolGlobalString('WEBSITE_DISABLE_MAIN_LANGUAGE_INTO_LANGSUBDIR') && !empty($object->otherlang)) {
103 $dirname = dirname($filealias);
104 $filename = basename($filealias);
105 foreach (explode(',', $object->otherlang) as $sublang) {
106 // Avoid to erase main alias file if $sublang is empty string
107 if (empty(trim($sublang))) {
108 continue;
109 }
110 $filealiassub = $dirname.'/'.$sublang.'/'.$filename;
111
112 $aliascontent = '<?php'."\n";
113 $aliascontent .= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n";
114 $aliascontent .= 'global $dolibarr_main_data_root;'."\n";
115 $aliascontent .= 'if (empty($dolibarr_main_data_root)) $res=include \'../page'.$objectpage->id.'.tpl.php\'; ';
116 $aliascontent .= 'else $res=include $dolibarr_main_data_root.\'/website/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n";
117 $aliascontent .= 'if ($res === false) { http_response_code(500); print \'Failed to make include\'; }'."\n";
118 $aliascontent .= '?>'."\n";
119
120 dol_mkdir($dirname.'/'.$sublang);
121 $result = file_put_contents($filealiassub, $aliascontent);
122 if ($result === false) {
123 dol_syslog("Failed to write file ".$filealiassub, LOG_WARNING);
124 }
125 dolChmod($filealiassub);
126 }
127 }
128 }
129
130 return ($result ? true : false);
131}
132
133
145function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage, $backupold = 0)
146{
147 global $db;
148
149 // Now create the .tpl file (duplicate code with actions updatesource or updatecontent but we need this to save new header)
150 dol_syslog("dolSavePageContent We regenerate the tpl page filetpl=".$filetpl);
151
152 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
153
154 if (dol_is_file($filetpl)) {
155 if ($backupold) {
156 $result = archiveOrBackupFile($filetpl);
157 if (! $result) {
158 return false;
159 }
160 } else {
161 dol_delete_file($filetpl);
162 }
163 }
164
165 $shortlangcode = '';
166 if ($objectpage->lang) {
167 $shortlangcode = substr($objectpage->lang, 0, 2); // en_US or en-US -> en
168 }
169 if (empty($shortlangcode)) {
170 // Take the language of website
171 $shortlangcode = substr($object->lang, 0, 2); // en_US or en-US -> en
172 }
173
174 if (!empty($objectpage->type_container) && in_array($objectpage->type_container, array('library', 'service'))) {
175 $originalcontentonly = 1;
176 }
177
178 $tplcontent = '';
179 if (!isset($originalcontentonly)) {
180 // If we want to generate a page with some code to manage PHP content
181 $tplcontent .= "<?php // BEGIN PHP\n";
182 $tplcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
183 $tplcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) {\n";
184 $tplcontent .= ' $pathdepth = count(explode(\'/\', $_SERVER[\'SCRIPT_NAME\'])) - 2;'."\n";
185 $tplcontent .= ' require_once ($pathdepth ? str_repeat(\'../\', $pathdepth) : \'./\').\'master.inc.php\';'."\n";
186 if ($objectpage->disable_waf != 'all') {
187 if (strpos($objectpage->disable_waf, 'NOSCANAUDIOFORINJECTION') !== false) {
188 $tplcontent .= ' define(\'NOSCANAUDIOFORINJECTION\', 1);'."\n";
189 }
190 if (strpos($objectpage->disable_waf, 'NOSCANIFRAMEFORINJECTION') !== false) {
191 $tplcontent .= ' define(\'NOSCANIFRAMEFORINJECTION\', 1);'."\n";
192 }
193 if (strpos($objectpage->disable_waf, 'NOSCANOBJECTFORINJECTION') !== false) {
194 $tplcontent .= ' define(\'NOSCANOBJECTFORINJECTION\', 1);'."\n";
195 }
196 $tplcontent .= ' require_once DOL_DOCUMENT_ROOT.\'/waf.inc.php\';'."\n";
197 }
198 $tplcontent .= "}\n";
199 $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
200 $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
201 if (in_array($objectpage->type_container, array('page', 'blogpost', 'service'))) {
202 $tplcontent .= 'dol_syslog("--- Prepare content of page '.((int) $objectpage->id).' - '.$objectpage->pageurl.'");'."\n";
203 }
204 $tplcontent .= "ob_start();\n";
205 $tplcontent .= "try {\n";
206 $tplcontent .= "// END PHP ?>\n";
207 if (getDolGlobalString('WEBSITE_FORCE_DOCTYPE_HTML5')) {
208 $tplcontent .= "<!DOCTYPE html>\n";
209 }
210 // If a language was forced on page, we use it, else we use the lang of visitor else the lang of web site
211 $tplcontent .= '<html'.($objectpage->lang ? ' lang="'.substr($objectpage->lang, 0, 2).'"' : '<?php echo $weblangs->shortlang ? \' lang="\'.$weblangs->shortlang.\'"\' : \'\' ?>').'>'."\n";
212 $tplcontent .= '<head>'."\n";
213 $tplcontent .= '<title>'.dol_string_nohtmltag($objectpage->title, 1, 'UTF-8').'</title>'."\n";
214 $tplcontent .= '<meta charset="utf-8">'."\n";
215 $tplcontent .= '<meta http-equiv="content-type" content="text/html; charset=utf-8" />'."\n";
216 $tplcontent .= '<meta name="robots" content="index, follow" />'."\n";
217 $tplcontent .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">'."\n";
218 $tplcontent .= '<meta name="keywords" content="'.dol_string_nohtmltag($objectpage->keywords, 1, 'UTF-8').'" />'."\n";
219 $tplcontent .= '<meta name="title" content="'.dol_string_nohtmltag($objectpage->title, 1, 'UTF-8').'" />'."\n";
220 $tplcontent .= '<meta name="description" content="'.dol_string_nohtmltag($objectpage->description, 1, 'UTF-8').'" />'."\n";
221 $tplcontent .= '<meta name="generator" content="'.DOL_APPLICATION_TITLE.' '.DOL_VERSION.' (https://www.dolibarr.org)" />'."\n";
222 $tplcontent .= '<meta name="dolibarr:pageid" content="'.((int) $objectpage->id).'" />'."\n";
223
224 // Add favicon
225 if (in_array($objectpage->type_container, array('page', 'blogpost'))) {
226 $tplcontent .= '<link rel="icon" type="image/png" href="/favicon.png" />'."\n";
227 }
228
229 $listofaltlang = $object->otherlang;
230
231 // Note: $object is website, $objectpage is website page
232 if ($object->virtualhost) {
233 // Add the link of the canonical reference
234 $canonicalurladdidlang = '';
235 if ($objectpage->lang) { // A language is forced on the page, it means we may have other language files with hard links into properties of page
236 $canonicalurl = (($objectpage->id == $object->fk_default_home) ? '/' : (($shortlangcode != substr($object->lang, 0, 2) ? '/'.$shortlangcode : '').'/'.$objectpage->pageurl.'.php'));
237 } else { // No language forced, it means the canonical is the one with params making url unique
238 $canonicalurl = '/'.$objectpage->pageurl.'.php';
239
240 if ($object->lang && $listofaltlang) {
241 // Add parameter ID required to be unique/canonical
242 $canonicalurladdidlang = '?__SEO_CANONICAL_URL_PARAMS__';
243 $canonicalurladdidlang .= '&l=__SEO_CANONICAL_LANG__';
244 } else {
245 // Add parameter ID required to be unique/canonical
246 $canonicalurladdidlang = '?__SEO_CANONICAL_URL_PARAMS__';
247 }
248 }
249
250 $tplcontent .= '<link rel="canonical" href="<?php echo $website->virtualhost; ?>'.$canonicalurl.$canonicalurladdidlang.'" />'."\n";
251
252 // Add the link of alternate translation reference
253 if ($listofaltlang) { // If website has other languages to support
254 if ($objectpage->lang) { // A language is forced on the page, it means we may have other language files with hard links into properties of page
255 // Add page "translation of"
256 $translationof = $objectpage->fk_page;
257 if ($translationof) {
258 $tmppage = new WebsitePage($db);
259 $tmppage->fetch($translationof);
260 if ($tmppage->id > 0) {
261 $tmpshortlangcode = '';
262 if ($tmppage->lang) {
263 $tmpshortlangcode = preg_replace('/[_-].*$/', '', $tmppage->lang); // en_US or en-US -> en
264 }
265 if (empty($tmpshortlangcode)) {
266 $tmpshortlangcode = preg_replace('/[_-].*$/', '', $object->lang); // en_US or en-US -> en
267 }
268 if ($tmpshortlangcode != $shortlangcode) {
269 $tplcontent .= '<link rel="alternate" hreflang="'.$tmpshortlangcode.'" href="<?php echo $website->virtualhost; ?>'.($object->fk_default_home == $tmppage->id ? '/' : (($tmpshortlangcode != substr($object->lang, 0, 2)) ? '/'.$tmpshortlangcode : '').'/'.$tmppage->pageurl.'.php').'" />'."\n";
270 }
271 }
272 }
273
274 // Add "has translation pages"
275 $sql = "SELECT rowid as id, lang, pageurl from ".MAIN_DB_PREFIX.'website_page where fk_page IN ('.$db->sanitize($objectpage->id.($translationof ? ", ".$translationof : '')).")";
276 $resql = $db->query($sql);
277 if ($resql) {
278 $num_rows = $db->num_rows($resql);
279 if ($num_rows > 0) {
280 while ($obj = $db->fetch_object($resql)) {
281 $tmpshortlangcode = '';
282 if ($obj->lang) {
283 $tmpshortlangcode = preg_replace('/[_-].*$/', '', $obj->lang); // en_US or en-US -> en
284 }
285 if ($tmpshortlangcode != $shortlangcode) {
286 $tplcontent .= '<link rel="alternate" hreflang="'.$tmpshortlangcode.'" href="<?php echo $website->virtualhost; ?>'.($object->fk_default_home == $obj->id ? '/' : (($tmpshortlangcode != substr($object->lang, 0, 2) ? '/'.$tmpshortlangcode : '')).'/'.$obj->pageurl.'.php').'" />'."\n";
287 }
288 }
289 }
290 } else {
291 dol_print_error($db);
292 }
293
294 // Add myself
295 $tplcontent .= '<?php if ($_SERVER["PHP_SELF"] == "'.(($object->fk_default_home == $objectpage->id) ? '/' : (($shortlangcode != substr($object->lang, 0, 2)) ? '/'.$shortlangcode : '')).'/'.$objectpage->pageurl.'.php") { ?>'."\n";
296 $tplcontent .= '<link rel="alternate" hreflang="'.$shortlangcode.'" href="<?php echo $website->virtualhost; ?>'.(($object->fk_default_home == $objectpage->id) ? '/' : (($shortlangcode != substr($object->lang, 0, 2)) ? '/'.$shortlangcode : '').'/'.$objectpage->pageurl.'.php').'" />'."\n";
297
298 $tplcontent .= '<?php } ?>'."\n";
299 } else { // No language forced, it means the canonical is the one withparams making url unique
300 $canonicalurl = '/'.$objectpage->pageurl.'.php';
301 $arrayofaltlang = explode(',', $listofaltlang);
302
303 foreach ($arrayofaltlang as $altlang) {
304 // Add parameter ID required to be unique/canonical
305 $canonicalurladdidlang = '?__SEO_CANONICAL_URL_PARAMS__';
306 $canonicalurladdidlang .= '&l='.$altlang;
307 $tplcontent .= '<link rel="alternate" hreflang="'.$altlang.'" href="<?php echo $website->virtualhost; ?>'.$canonicalurl.$canonicalurladdidlang.'" />'."\n";
308 }
309
310 $tmpshortlangcode = preg_replace('/[_-].*$/', '', $object->lang); // en_US or en-US -> en
311 $canonicalurladdidlang = '?__SEO_CANONICAL_URL_PARAMS__';
312 $canonicalurladdidlang .= '&l='.$tmpshortlangcode;
313 $tplcontent .= '<link rel="alternate" hreflang="'.$tmpshortlangcode.'" href="<?php echo $website->virtualhost; ?>'.$canonicalurl.$canonicalurladdidlang.'" />'."\n";
314 }
315 }
316 }
317
318 // Add manifest.json. Do we have to add it only on home page ?
319 $tplcontent .= '<?php if ($website->use_manifest) { print \'<link rel="manifest" href="/manifest.json.php" />\'."\n"; } ?>'."\n";
320
321 // Add HTML headers (must be before the Add of the common CSS and js). The common js may content javascript using jquery or a framework loaded by the HTML header.
322 $tplcontent .= '<!-- Include HTML header from common file -->'."\n";
323 $tplcontent .= '<?php if (file_exists(DOL_DATA_ROOT."/website/".$websitekey."/htmlheader.html")) include DOL_DATA_ROOT."/website/".$websitekey."/htmlheader.html"; ?>'."\n";
324 $tplcontent .= '<!-- Include HTML header from page header block -->'."\n";
325 $tplcontent .= preg_replace('/<\/?html>/ims', '', $objectpage->htmlheader)."\n";
326
327 // Add css
328 $tplcontent .= '<!-- Include link to common CSS file -->'."\n";
329 $tplcontent .= '<link rel="stylesheet" href="/styles.css.php?website=<?php echo $websitekey; ?>" type="text/css" />'."\n";
330
331 // Add js
332 $tplcontent .= '<!-- Include link to common JS file -->'."\n";
333 $tplcontent .= '<script nonce="'.getNonce().'" async src="/javascript.js.php?website=<?php echo $websitekey; ?>"></script>'."\n";
334 $tplcontent .= '</head>'."\n";
335
336 // Page content
337 $tplcontent .= '<!-- File content defined in Dolibarr website module editor -->'."\n";
338 $tplcontent .= '<body id="bodywebsite" class="bodywebsite bodywebpage-'.$objectpage->ref.'">'."\n";
339
340 // Import necessary environment for the config page
341 if ($objectpage->type_container == 'setup') {
342 $content = '';
343 $content .= '<?php'."\n";
344 $content .= 'require_once DOL_DOCUMENT_ROOT.\'/core/class/html.formsetup.class.php\';'."\n";
345 $content .= '$formSetup = new FormSetup($db);'."\n";
346 $content .= '?>'."\n";
347 $tplcontent .= $content."\n";
348 }
349
350 $tplcontent .= $objectpage->content."\n";
351
352 // Add logic to handle view and actions for managing parameters in the config page
353 if ($objectpage->type_container == 'setup') {
354 $content = '<div id="websitetemplateconfigpage">'."\n";
355 $content .= '<?php'."\n";
356 $content .= '/*' . "\n";
357 $content .= ' * Actions' . "\n";
358 $content .= ' */' . "\n";
359 $content .= '$websitetemplateconf = GETPOSTINT(\'websitetemplateconf\');' . "\n";
360 $content .= 'include DOL_DOCUMENT_ROOT.\'/core/actions_setmoduleoptions.inc.php\';' . "\n";
361 $content .= '' . "\n";
362 $content .= '/*' . "\n";
363 $content .= ' * View' . "\n";
364 $content .= ' */' . "\n";
365 $content .= 'print load_fiche_titre($langs->trans(\'SetupAndProperties\'), \'\', \'title_setup\');' . "\n";
366 $content .= '' . "\n";
367 $content .= 'if (!empty($message)) {' . "\n";
368 $content .= ' print $message;' . "\n";
369 $content .= '}' . "\n";
370 $content .= '' . "\n";
371 $content .= 'if (!empty($formSetup->items)) {' . "\n";
372 $content .= ' $html = \'\';' . "\n";
373 $content .= '' . "\n";
374 $content .= ' $html .= \'<form action="config.php" method="POST">\';' . "\n";
375 $content .= ' // Generate hidden values from $formSetup->formHiddenInputs' . "\n";
376 $content .= ' if (!empty($formSetup->formHiddenInputs) && is_array($formSetup->formHiddenInputs)) {' . "\n";
377 $content .= ' foreach ($formSetup->formHiddenInputs as $hiddenKey => $hiddenValue) {' . "\n";
378 $content .= ' $html .= \'<input type="hidden" name="\' . dol_escape_htmltag($hiddenKey) . \'" value="\' . dol_escape_htmltag($hiddenValue) . \'">\';' . "\n";
379 $content .= ' }' . "\n";
380 $content .= ' }' . "\n";
381 $content .= '' . "\n";
382 $content .= ' // Generate output table' . "\n";
383 $content .= ' $html .= $formSetup->generateTableOutput(true);' . "\n";
384 $content .= '' . "\n";
385 $content .= ' // Submit button' . "\n";
386 $content .= ' $html .= \'<input type="hidden" name="action" value="preview">\';' . "\n";
387 $content .= ' $html .= \'<input type="hidden" name="websitetemplateconf" value="1">\';' . "\n";
388 $content .= ' $html .= \'<br>\';' . "\n";
389 $content .= ' $html .= \'<div class="form-setup-button-container center">\';' . "\n";
390 $content .= ' $html .= \'<input class="button button-submit" type="submit" value="\' . $langs->trans("Save") . \'">\';' . "\n";
391 $content .= ' $html .= \'</div>\';' . "\n";
392 $content .= ' $html .= \'</form>\';' . "\n";
393 $content .= '' . "\n";
394 $content .= ' print $html;' . "\n";
395 $content .= '}' . "\n";
396 $content .= '?>' . "\n";
397 $content .= '</div>' . "\n";
398 $tplcontent .= $content."\n";
399 }
400
401
402 $tplcontent .= '</body>'."\n";
403 $tplcontent .= '</html>'."\n";
404
405 $tplcontent .= '<?php // BEGIN PHP'."\n";
406 $tplcontent .= '} catch(Exception $e) { print $e->getMessage(); }'."\n";
407 $tplcontent .= '$tmp = ob_get_contents(); ob_end_clean();'."\n"; // replace with ob_get_clean ?
408
409 $tplcontent .= "// Now fix the content for SEO or multilanguage\n";
410 // Old method for custom SEO
411 if (strpos($objectpage->content, '$__PAGE__KEYWORDS__') !== false) {
412 $tplcontent .= '$tmp = preg_replace("/^<meta name=\"keywords\" content=\".*?\" \/>/ms", "<meta name=\"keywords\" content=\"" . dolPrintHTMLForAttribute($__PAGE__KEYWORDS__ ?? "", 1) . "\" />", $tmp);'."\n";
413 }
414 if (strpos($objectpage->content, '$__PAGE__TITLE__') !== false) {
415 $tplcontent .= '$tmp = preg_replace("/^<title>.*?<\/title>/ms", "<title>" . dolPrintHTMLForAttribute($__PAGE__TITLE__ ?? "", 1) . "</title>", $tmp);'."\n";
416 $tplcontent .= '$tmp = preg_replace("/^<meta name=\"title\" content=\".*?\" \/>/ms", "<meta name=\"title\" content=\"" . dolPrintHTMLForAttribute($__PAGE__TITLE__ ?? "", 1) . "\" />", $tmp);'."\n";
417 }
418 if (strpos($objectpage->content, '$__PAGE__DESC__') !== false) {
419 $tplcontent .= '$tmp = preg_replace("/^<meta name=\"description\" content=\".*?\" \/>/ms", "<meta name=\"description\" content=\"" . dolPrintHTMLForAttribute($__PAGE__DESC__ ?? "", 1) . "\" />", $tmp);'."\n";
420 }
421 // New method for custom SEO
422 if (strpos($objectpage->content, 'define("__SEO_PAGE_LANG__"') !== false) {
423 $tmpshortlangcode = preg_replace('/[_-].*$/', '', $object->lang); // en_US or en-US -> en
424 $tplcontent .= '$tmp = preg_replace("/^<html lang=\"[a-z]+\"/ms", "<html lang=\"" . dolPrintHTMLForAttribute(defined("__SEO_PAGE_LANG__") ? preg_replace(\'/\[_-\].*$/\', "", constant("__SEO_PAGE_LANG__")) : (empty($weblangs->shortlang) ? "'.$tmpshortlangcode.'" : $weblangs->shortlang), 1) . "\"", $tmp);'."\n";
425 }
426 if (strpos($objectpage->content, 'define("__SEO_PAGE_KEYWORDS__"') !== false) {
427 $tplcontent .= '$tmp = preg_replace("/^<meta name=\"keywords\" content=\".*?\" \/>/ms", "<meta name=\"keywords\" content=\"" . dolPrintHTMLForAttribute(constant("__SEO_PAGE_KEYWORDS__"), 1) . "\" />", $tmp);'."\n";
428 }
429 if (strpos($objectpage->content, 'define("__SEO_PAGE_TITLE__"') !== false) {
430 $tplcontent .= '$tmp = preg_replace("/^<title>.*?<\/title>/ms", "<title>" . dolPrintHTMLForAttribute(constant("__SEO_PAGE_TITLE__"), 1) . "</title>", $tmp);'."\n";
431 $tplcontent .= '$tmp = preg_replace("/^<meta name=\"title\" content=\".*?\" \/>/ms", "<meta name=\"title\" content=\"" . dolPrintHTMLForAttribute(constant("__SEO_PAGE_TITLE__"), 1) . "\" />", $tmp);'."\n";
432 }
433 if (strpos($objectpage->content, 'define("__SEO_PAGE_DESC__"') !== false) {
434 $tplcontent .= '$tmp = preg_replace("/^<meta name=\"description\" content=\".*?\" \/>/ms", "<meta name=\"description\" content=\"" . dolPrintHTMLForAttribute(constant("__SEO_PAGE_DESC__"), 1) . "\" />", $tmp);'."\n";
435 }
436 if (empty($objectpage->lang)) { // We may need to use param into the canonical url
437 $tplcontent .= 'defined("__SEO_CANONICAL_URL_PARAMS__") ? ($tmp = preg_replace("/__SEO_CANONICAL_URL_PARAMS__/", dolPrintHTMLForAttributeUrl(constant("__SEO_CANONICAL_URL_PARAMS__")), $tmp)) : ($tmp = preg_replace("/\?__SEO_CANONICAL_URL_PARAMS__\"/", "\"", preg_replace("/\?__SEO_CANONICAL_URL_PARAMS__&/", "?", $tmp)));'."\n";
438
439 $tmpshortlangcode = preg_replace('/[_-].*$/', '', $object->lang); // en_US or en-US -> en
440 $tplcontent .= '$tmp = preg_replace("/__SEO_CANONICAL_LANG__/", (defined("__SEO_PAGE_LANG__") ? preg_replace(\'/\[_-\].*$/\', "", constant("__SEO_PAGE_LANG__")) : (empty($weblangs->shortlang) ? "'.$tmpshortlangcode.'" : $weblangs->shortlang)), $tmp);'."\n";
441 }
442
443 $tplcontent .= "// Now output the generated page content\n";
444 $tplcontent .= 'dolWebsiteOutput($tmp, "html", '.((int) $objectpage->id).'); dolWebsiteIncrementCounter('.((int) $object->id).', "'.$objectpage->type_container.'", '.((int) $objectpage->id).');'."\n";
445 $tplcontent .= "// END PHP ?>\n";
446 } else {
447 $tplcontent .= "<?php // BEGIN PHP\n";
448 $tplcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
449 $tplcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) {\n";
450 $tplcontent .= ' $pathdepth = count(explode(\'/\', $_SERVER[\'SCRIPT_NAME\'])) - 2;'."\n";
451 $tplcontent .= ' require_once ($pathdepth ? str_repeat(\'../\', $pathdepth) : \'./\').\'master.inc.php\';'."\n";
452 if ($objectpage->disable_waf != 'all') {
453 if (strpos($objectpage->disable_waf, 'NOSCANAUDIOFORINJECTION') !== false) {
454 $tplcontent .= ' define(\'NOSCANAUDIOFORINJECTION\', 1);'."\n";
455 }
456 if (strpos($objectpage->disable_waf, 'NOSCANIFRAMEFORINJECTION') !== false) {
457 $tplcontent .= ' define(\'NOSCANIFRAMEFORINJECTION\', 1);'."\n";
458 }
459 if (strpos($objectpage->disable_waf, 'NOSCANOBJECTFORINJECTION') !== false) {
460 $tplcontent .= ' define(\'NOSCANOBJECTFORINJECTION\', 1);'."\n";
461 }
462 $tplcontent .= ' require_once DOL_DOCUMENT_ROOT.\'/waf.inc.php\';'."\n";
463 }
464 $tplcontent .= "}\n";
465 $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
466 $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
467 if (in_array($objectpage->type_container, array('page', 'blogpost', 'service'))) {
468 $tplcontent .= 'dol_syslog("--- Prepare content of page '.((int) $objectpage->id).' - '.$objectpage->pageurl.'");'."\n";
469 }
470 $tplcontent .= "// END PHP ?>\n";
471
472 $tplcontent .= $objectpage->content;
473 }
474
475 //var_dump($filetpl);exit;
476 $result = file_put_contents($filetpl, $tplcontent);
477
478 dolChmod($filetpl);
479
480 return $result;
481}
482
483
494function dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl, $filewrapper, $object = null)
495{
496 global $db;
497
498 $result1 = false;
499 $result2 = false;
500
501 dol_mkdir($pathofwebsite);
502
503 if ($fileindex) {
504 dol_delete_file($fileindex);
505 $indexcontent = '<?php'."\n";
506 $indexcontent .= "// BEGIN PHP File generated to provide an index.php as Home Page or alias redirector - DO NOT MODIFY - It is just a generated wrapper.\n";
507 $indexcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
508 $indexcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once './master.inc.php'; } // Load master if not already loaded\n";
509 $indexcontent .= 'if (!empty($_GET[\'pageref\']) || !empty($_GET[\'pagealiasalt\']) || !empty($_GET[\'pageid\'])) {'."\n";
510 $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
511 $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
512 $indexcontent .= ' redirectToContainer($_GET[\'pageref\'], $_GET[\'pagealiasalt\'], $_GET[\'pageid\']);'."\n";
513 $indexcontent .= "}\n";
514 $indexcontent .= "include_once './".basename($filetpl)."'\n";
515 $indexcontent .= '// END PHP ?>'."\n";
516
517 $result1 = file_put_contents($fileindex, $indexcontent);
518
519 dolChmod($fileindex);
520
521 if (is_object($object) && $object->fk_default_home > 0) {
522 $objectpage = new WebsitePage($db);
523 $objectpage->fetch($object->fk_default_home);
524
525 // Create a version for sublanguages
526 if (empty($objectpage->lang) || !in_array($objectpage->lang, explode(',', $object->otherlang))) {
527 if (!getDolGlobalString('WEBSITE_DISABLE_MAIN_LANGUAGE_INTO_LANGSUBDIR') && is_object($object) && !empty($object->otherlang)) {
528 $dirname = dirname($fileindex);
529 foreach (explode(',', $object->otherlang) as $sublang) {
530 // Avoid to erase main alias file if $sublang is empty string
531 if (empty(trim($sublang))) {
532 continue;
533 }
534 $fileindexsub = $dirname.'/'.$sublang.'/index.php';
535
536 // Same indexcontent than previously but with ../ instead of ./ for master and tpl file include/require_once.
537 $relpath = '..';
538 $indexcontent = '<?php'."\n";
539 $indexcontent .= "// BEGIN PHP File generated to provide an index.php as Home Page or alias redirector - DO NOT MODIFY - It is just a generated wrapper.\n";
540 $indexcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
541 $indexcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once '".$relpath."/master.inc.php'; } // Load master if not already loaded\n";
542 $indexcontent .= 'if (!empty($_GET[\'pageref\']) || !empty($_GET[\'pagealiasalt\']) || !empty($_GET[\'pageid\'])) {'."\n";
543 $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
544 $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
545 $indexcontent .= ' redirectToContainer($_GET[\'pageref\'], $_GET[\'pagealiasalt\'], $_GET[\'pageid\']);'."\n";
546 $indexcontent .= "}\n";
547 $indexcontent .= "include_once '".$relpath."/".basename($filetpl)."'\n"; // use .. instead of .
548 $indexcontent .= '// END PHP ?>'."\n";
549 $result = file_put_contents($fileindexsub, $indexcontent);
550 if ($result === false) {
551 dol_syslog("Failed to write file ".$fileindexsub, LOG_WARNING);
552 }
553 dolChmod($fileindexsub);
554 }
555 }
556 }
557 }
558 } else {
559 $result1 = true;
560 }
561
562 if ($filewrapper) {
563 dol_delete_file($filewrapper);
564 $wrappercontent = file_get_contents(DOL_DOCUMENT_ROOT.'/website/samples/wrapper.php');
565
566 $result2 = file_put_contents($filewrapper, $wrappercontent);
567 dolChmod($filewrapper);
568 } else {
569 $result2 = true;
570 }
571
572 return ($result1 && $result2);
573}
574
575
583function dolSaveHtmlHeader($filehtmlheader, $htmlheadercontent)
584{
585 global $pathofwebsite;
586
587 dol_syslog("Save html header into ".$filehtmlheader);
588
589 dol_mkdir($pathofwebsite);
590 $result = file_put_contents($filehtmlheader, $htmlheadercontent);
591 dolChmod($filehtmlheader);
592
593 return $result;
594}
595
603function dolSaveCssFile($filecss, $csscontent)
604{
605 global $pathofwebsite;
606
607 dol_syslog("Save css file into ".$filecss);
608
609 dol_mkdir($pathofwebsite);
610 $result = file_put_contents($filecss, $csscontent);
611 dolChmod($filecss);
612
613 return $result;
614}
615
623function dolSaveJsFile($filejs, $jscontent)
624{
625 global $pathofwebsite;
626
627 dol_syslog("Save js file into ".$filejs);
628
629 dol_mkdir($pathofwebsite);
630 $result = file_put_contents($filejs, $jscontent);
631 dolChmod($filejs);
632
633 return $result;
634}
635
643function dolSaveRobotFile($filerobot, $robotcontent)
644{
645 global $pathofwebsite;
646
647 dol_syslog("Save robot file into ".$filerobot);
648
649 dol_mkdir($pathofwebsite);
650 $result = file_put_contents($filerobot, $robotcontent);
651 dolChmod($filerobot);
652
653 return $result;
654}
655
663function dolSaveHtaccessFile($filehtaccess, $htaccess)
664{
665 global $pathofwebsite;
666
667 dol_syslog("Save htaccess file into ".$filehtaccess);
668
669 dol_mkdir($pathofwebsite);
670 $result = file_put_contents($filehtaccess, $htaccess);
671 dolChmod($filehtaccess);
672
673 return $result;
674}
675
683function dolSaveManifestJson($file, $content)
684{
685 global $pathofwebsite;
686
687 dol_syslog("Save manifest.js.php file into ".$file);
688
689 dol_mkdir($pathofwebsite);
690 $result = file_put_contents($file, $content);
691 dolChmod($file);
692
693 return $result;
694}
695
703function dolSaveReadme($file, $content)
704{
705 global $pathofwebsite;
706
707 dol_syslog("Save README.md file into ".$file);
708
709 dol_mkdir($pathofwebsite);
710 $result = file_put_contents($file, $content);
711 dolChmod($file);
712
713 return $result;
714}
715
723function dolSaveLicense($file, $content)
724{
725 global $pathofwebsite;
726
727 dol_syslog("Save LICENSE file into ".$file);
728
729 dol_mkdir($pathofwebsite);
730 $result = file_put_contents($file, $content);
731 dolChmod($file);
732
733 return $result;
734}
735
743function showWebsiteTemplates(Website $website, int $refresh)
744{
745 global $conf, $langs, $form, $user;
746
747 // We want only one directory for dir of website templates. If an external module need to provide a template, the template must be copied into this directory
748 // when module is enabled.
749 $dirthemes = array('/doctemplates/websites');
750
751 $warningtoshow = '';
752 $arrayoftemplatesfound = array();
753
754 if (count($dirthemes)) {
755 $i = 0;
756 // Scan dir to get all deployed qualified templates
757 foreach ($dirthemes as $dir) {
758 $dirtheme = DOL_DATA_ROOT.$dir;
759
760 if (is_dir($dirtheme)) {
761 $handle = opendir($dirtheme);
762 if (is_resource($handle)) {
763 while (($subdir = readdir($handle)) !== false) { // Scan files of directory
764 //var_dump($dirtheme.'/'.$subdir);
765 if (dol_is_file($dirtheme."/".$subdir) && substr($subdir, 0, 1) != '.' && substr($subdir, 0, 3) != 'CVS' && preg_match('/\.zip$/i', $subdir)) {
766 $subdirwithoutzip = preg_replace('/\.zip$/i', '', $subdir);
767 $subdirwithoutzipwithoutver = preg_replace('/(_exp|_dev)$/i', '', $subdirwithoutzip);
768
769 // Disable not stable themes (dir ends with _exp or _dev)
770 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2 && preg_match('/_dev$/i', $subdirwithoutzip)) {
771 continue;
772 }
773 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1 && preg_match('/_exp$/i', $subdirwithoutzip)) {
774 continue;
775 }
776
777 $arrayoftemplatesfound[$subdirwithoutzip] = array('id' => $subdirwithoutzip);
778 $i++;
779 }
780 }
781 }
782 }
783 }
784
785 // Now test if we found template available into source not copied into documents
786 $arrayofsourcetemplates = dol_dir_list(DOL_DOCUMENT_ROOT.'/install/doctemplates/websites', 'directories', 0, 'website_.*$');
787 $arrayofsourcetemplatesnotdeployed = array();
788 foreach ($arrayofsourcetemplates as $val) {
789 // Disable not stable themes (dir ends with _exp or _dev)
790 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2 && preg_match('/_dev$/i', $val['relativename'])) {
791 continue;
792 }
793 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1 && preg_match('/_exp$/i', $val['relativename'])) {
794 continue;
795 }
796
797 if (empty($arrayoftemplatesfound[$val['relativename']])) {
798 // We found a template into sources that is not into documents
799 if ($refresh) { // We copy it
800 $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/websites/'.$val['name'];
801 $dest = DOL_DATA_ROOT.'/doctemplates/websites/'.$val['name'];
802
803 dol_delete_file($dest.'.zip');
804
805 // Compress it
806 global $errormsg; // Used by dol_compress_dir
807 $errormsg = '';
808 $result = dol_compress_dir($src, $dest.'.zip', 'zip');
809 if ($result < 0) {
810 dol_syslog("Error in compress of dir ".$src, LOG_ERR);
811 }
812
813 $srcfile = DOL_DOCUMENT_ROOT.'/install/doctemplates/websites/'.preg_replace('/(_exp|_dev)$/', '', $val['name']).'.jpg';
814 $destfile = DOL_DATA_ROOT.'/doctemplates/websites/'.preg_replace('/(_exp|_dev)$/', '', $val['name']).'.jpg';
815
816 dol_copy($srcfile, $destfile);
817 } else {
818 $arrayofsourcetemplatesnotdeployed[$val['relativename']] = $val;
819 }
820 }
821 }
822
823 if (count($arrayofsourcetemplatesnotdeployed)) {
824 $warningtoshow = img_picto($langs->trans("WarningTemplatesFoundNotDeployedClickRefresh").': '.implode(', ', array_keys($arrayofsourcetemplatesnotdeployed)).'. '.$langs->trans("WarningTemplatesFoundNotDeployedClickRefresh2"), 'warning', 'class="valignmiddle paddingright"');
825 }
826 }
827
828 $colspan = 2;
829
830 print '<!-- For website template import -->'."\n";
831 print '<table class="noborder centpercent">';
832
833 // Title
834 print '<tr class="liste_titre"><th class="titlefield">';
835 print $form->textwithpicto($langs->trans("Templates"), $langs->trans("ThemeDir").' : '.implode(", ", $dirthemes));
836 print ' ';
837 print '<a class="valignmiddle" href="'.$_SERVER["PHP_SELF"].'?website='.urlencode($website->ref).'&importsite=2" rel="noopener noreferrer external">';
838 print $warningtoshow;
839 print img_picto($langs->trans("Refresh"), 'refresh', 'class="valignmiddle"');
840 print '</a>';
841 print '</th>';
842 print '<th class="right">';
843 $url = 'https://www.dolistore.com/index.php?cat=84';
844 print '<a href="'.$url.'" target="_blank" rel="noopener noreferrer external">';
845 print img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans('DownloadMoreSkins');
846 print '</a>';
847 print '</th></tr>';
848
849 print '<tr><td colspan="'.$colspan.'">';
850
851 print '<table class="nobordernopadding centpercent"><tr><td><div class="display-flex">';
852
853 if (count($dirthemes)) {
854 $i = 0;
855 foreach ($dirthemes as $dir) {
856 $dirtheme = DOL_DATA_ROOT.$dir;
857
858 if (is_dir($dirtheme)) {
859 $handle = opendir($dirtheme);
860 if (is_resource($handle)) {
861 while (($subdir = readdir($handle)) !== false) { // Scan files of directory
862 //var_dump($dirtheme.'/'.$subdir);
863 if (dol_is_file($dirtheme."/".$subdir) && substr($subdir, 0, 1) != '.' && substr($subdir, 0, 3) != 'CVS' && preg_match('/\.zip$/i', $subdir)) {
864 $subdirwithoutzip = preg_replace('/\.zip$/i', '', $subdir);
865 $subdirwithoutzipwithoutver = preg_replace('/(_exp|_dev)$/i', '', $subdirwithoutzip);
866
867 // Disable not stable themes (dir ends with _exp or _dev)
868 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2 && preg_match('/_dev$/i', $subdirwithoutzip)) {
869 continue;
870 }
871 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1 && preg_match('/_exp$/i', $subdirwithoutzip)) {
872 continue;
873 }
874
875 $arrayoftemplatesfound[$subdirwithoutzip] = array('id' => $subdirwithoutzip);
876
877 print '<div class="inline-block center flex-item" style="min-width: 250px; max-width: 400px; margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;">';
878
879 $templatedir = $dirtheme."/".$subdir;
880 $file = $dirtheme."/".$subdirwithoutzipwithoutver.".jpg";
881 $url = DOL_URL_ROOT.'/viewimage.php?modulepart=doctemplateswebsite&file='.$subdirwithoutzipwithoutver.".jpg";
882
883 if (!file_exists($file)) {
884 $url = DOL_URL_ROOT.'/public/theme/common/nophoto.png';
885 }
886
887 $originalimgfile = basename($file);
888 $entity = $conf->entity;
889 $modulepart = 'doctemplateswebsite';
890 $cache = '';
891 $title = $file;
892
893 $ret = '';
894 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalimgfile, 1, '&entity='.$entity);
895 if (!empty($urladvanced)) {
896 $ret .= '<a class="'.$urladvanced['css'].'" target="'.$urladvanced['target'].'" mime="'.$urladvanced['mime'].'" href="'.$urladvanced['url'].'">';
897 } else {
898 $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.urlencode($modulepart).'&entity='.((int) $entity).'&file='.urlencode($originalimgfile).'&cache='.((int) $cache).'">';
899 }
900 print $ret;
901 print '<img class="img-skinthumb shadow" src="'.$url.'" border="0" alt="'.$title.'" title="'.$title.'" style="margin-bottom: 5px;">';
902 print '</a>';
903
904 print '<br>';
905 print $subdir;
906 print '<br>';
907 print '<span class="opacitymedium">'.dol_print_size(dol_filesize($dirtheme."/".$subdir), 1, 1).' - '.dol_print_date(dol_filemtime($templatedir), 'dayhour', 'tzuserrel').'</span>';
908 if ($user->hasRight('website', 'delete')) {
909 print ' <a href="'.$_SERVER["PHP_SELF"].'?action=deletetemplate&token='.newToken().'&website='.urlencode($website->ref).'&templateuserfile='.urlencode($subdir).'">'.img_picto('', 'delete').'</a>';
910 }
911 print '<br><a href="'.$_SERVER["PHP_SELF"].'?action=importsiteconfirm&token='.newToken().'&website='.urlencode($website->ref).'&templateuserfile='.urlencode($subdir).'" class="button">'.$langs->trans("Load").'</a>';
912 print '</div>';
913
914 $i++;
915 }
916 }
917 print '<div class="inline-block center flex-item" style="min-width: 250px; max-width: 400px;margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;"></div>';
918 print '<div class="inline-block center flex-item" style="min-width: 250px; max-width: 400px;margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;"></div>';
919 print '<div class="inline-block center flex-item" style="min-width: 250px; max-width: 400px;margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;"></div>';
920 print '<div class="inline-block center flex-item" style="min-width: 250px; max-width: 400px;margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;"></div>';
921 print '<div class="inline-block center flex-item" style="min-width: 250px; max-width: 400px;margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;"></div>';
922 }
923 }
924 }
925 } else {
926 print '<span class="opacitymedium">'.$langs->trans("None").'</span>';
927 }
928
929 print '</div></td></tr></table>';
930
931 print '</td></tr>';
932 print '</table>';
933}
934
935
946function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
947{
948 global $langs, $user;
949
950 $error = 0;
951
952 if (empty($phpfullcodestringold) && empty($phpfullcodestring)) {
953 return 0;
954 }
955
956 // First check permission
957 if ($phpfullcodestringold != $phpfullcodestring) {
958 if (!$error && !$user->hasRight('website', 'writephp')) {
959 $error++;
960 setEventMessages($langs->trans("NotAllowedToAddDynamicContent"), null, 'errors');
961 }
962 }
963
964 $phpfullcodestringnew = $phpfullcodestring;
965
966 // Then check forbidden commands
967 if (!$error) {
968 if (getDolGlobalString("WEBSITE_DISALLOW_DOLLAR_UNDERSCORE")) {
969 $phpfullcodestring = preg_replace('/\$_COOKIE\[/', '__DOLLARCOOKIE__', $phpfullcodestring);
970 $phpfullcodestring = preg_replace('/\$_FILES\[/', '__DOLLARFILES__', $phpfullcodestring);
971 $phpfullcodestring = preg_replace('/\$_SESSION\[/', '__DOLLARSESSION__', $phpfullcodestring);
972 $forbiddenphpstrings = array('$$', '$_', '}[');
973 } else {
974 $forbiddenphpstrings = array('$$', '}[');
975 }
976 //$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_FILES', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
977 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', 'ReflectionFunction'));
978
979 $forbiddenphpfunctions = array();
980 //$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64"."_"."decode", "rawurl"."decode", "url"."decode", "str"."_rot13", "hex"."2bin")); // name of forbidden functions are split to avoid false positive
981 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
982 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
983 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("call_user_func", "call_user_func_array"));
984 //$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
985 if (!getDolGlobalString('WEBSITE_PHP_ALLOW_EXEC')) { // If option is not on, we disallow functions to execute commands
986 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
987 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
988 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
989 }
990 if (!getDolGlobalString('WEBSITE_PHP_ALLOW_WRITE')) { // If option is not on, we disallow functions to write files
991 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_compress_dir", "dol_decode", "dol_delete_file", "dol_delete_dir", "dol_delete_dir_recursive", "dol_copy", "archiveOrBackupFile")); // more dolibarr functions
992 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
993 }
994 //$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include"));
995
996 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
997
998 foreach ($forbiddenphpstrings as $forbiddenphpstring) {
999 if (preg_match('/'.preg_quote($forbiddenphpstring, '/').'/ims', $phpfullcodestring)) {
1000 $error++;
1001 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpstring), null, 'errors');
1002 break;
1003 }
1004 }
1005 /* replaced with next block
1006 foreach ($forbiddenphpfunctions as $forbiddenphpfunction) { // Check "function(" but also "'function'(" and "function ("
1007 if (preg_match('/'.$forbiddenphpfunction.'[\'\s]*\‍(/ims', $phpfullcodestring)) {
1008 $error++;
1009 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpfunction), null, 'errors');
1010 break;
1011 }
1012 }*/
1013 foreach ($forbiddenphpfunctions as $forbiddenphpfunction) { // Check "function" whatever is "function(" or "function'(" or "function (" or "function"
1014 if (preg_match('/\b'.$forbiddenphpfunction.'\b/ims', $phpfullcodestring)) {
1015 $error++;
1016 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpfunction), null, 'errors');
1017 break;
1018 }
1019 }
1020
1021 foreach ($forbiddenphpmethods as $forbiddenphpmethod) {
1022 if (preg_match('/->'.$forbiddenphpmethod.'/ims', $phpfullcodestring)) {
1023 $error++;
1024 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpmethod), null, 'errors');
1025 break;
1026 }
1027 }
1028 }
1029
1030 // This char can be used to execute RCE for example by using echo `ls`
1031 if (!$error) {
1032 $forbiddenphpchars = array();
1033 if (!getDolGlobalString('WEBSITE_PHP_ALLOW_DANGEROUS_CHARS')) { // If option is not on, we disallow functions to execute commands
1034 $forbiddenphpchars = array("`");
1035 }
1036 foreach ($forbiddenphpchars as $forbiddenphpchar) {
1037 if (preg_match('/'.$forbiddenphpchar.'/ims', $phpfullcodestring)) {
1038 $error++;
1039 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpchar), null, 'errors');
1040 break;
1041 }
1042 }
1043 }
1044
1045 // Deny code to call a function obfuscated with comment, like "exec/*...*/ ('ls')";
1046 if (!$error) {
1047 if (preg_match('/\*\/\s*\‍(/ims', $phpfullcodestring)) {
1048 $error++;
1049 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", "exec/*...*/ ('ls')"), null, 'errors');
1050 }
1051 }
1052
1053 // Deny dynamic functions '${a}(' or '$a[b](' => So we refuse '}(' and ']('
1054 if (!$error) {
1055 if (preg_match('/[}\]]\s*\‍(/ims', $phpfullcodestring)) {
1056 $error++;
1057 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", ']('), null, 'errors');
1058 }
1059 }
1060
1061 // Deny dynamic functions '$xxx(' or '$xxx (' or '$xxx" ('
1062 if (!$error) {
1063 if (preg_match('/\$[a-z0-9_\-\/\*\"]+\s*\‍(/ims', $phpfullcodestring)) {
1064 $error++;
1065 setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", '$...('), null, 'errors');
1066 }
1067 }
1068
1069 // No need to block $conf->global->aaa() because PHP try to run the method aaa of $conf->global and not the function into $conf->global->aaa.
1070
1071 // Then check if installmodules.lock does not block dynamic PHP code change.
1072 if ($phpfullcodestringold != $phpfullcodestringnew) {
1073 if (!$error) {
1074 $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
1075 $allowimportsite = true;
1076 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1077 if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
1078 $allowimportsite = false;
1079 }
1080
1081 if (!$allowimportsite) {
1082 $error++;
1083 // Blocked by installmodules.lock
1084 if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) {
1085 // Show clean corporate message
1086 $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs');
1087 } else {
1088 // Show technical generic message
1089 $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock');
1090 }
1091 setEventMessages($message, null, 'errors');
1092 }
1093 }
1094 }
1095
1096 return $error;
1097}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
Class Website.
Class Websitepage.
dol_filemtime($pathoffile)
Return time of a file.
dol_filesize($pathoffile)
Return size of a file.
dol_copy($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
archiveOrBackupFile($srcfile, $max_versions=5, $archivedir='', $suffix="v", $moveorcopy='move')
Manage backup versions for a given file, ensuring only a maximum number of versions are kept.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:63
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
newToken()
Return the value of token currently saved into session with name 'newtoken'.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
dolSaveMasterFile($filemaster)
Save content of a page on disk.
dolSaveLicense($file, $content)
Save content of a page on disk.
checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
Check a new string containing only php code (including <php tag)
dolSaveHtmlHeader($filehtmlheader, $htmlheadercontent)
Save content of a page on disk.
dolSaveReadme($file, $content)
Save content of a page on disk.
dolSaveManifestJson($file, $content)
Save content of a page on disk.
dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl, $filewrapper, $object=null)
Save content of the index.php and/or the wrapper.php page.
dolSavePageAlias($filealias, $object, $objectpage)
Save an alias page on disk (A page that include the reference page).
dolSaveHtaccessFile($filehtaccess, $htaccess)
Save content of a page on disk.
dolSaveJsFile($filejs, $jscontent)
Save content of a page on disk.
dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage, $backupold=0)
Save content of a page on disk (page name is generally ID_of_page.php).
showWebsiteTemplates(Website $website, int $refresh)
Show list of themes.
dolSaveCssFile($filecss, $csscontent)
Save content of a page on disk.
dolSaveRobotFile($filerobot, $robotcontent)
Save content of a page on disk.