website2.lib.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. <?php
  2. /* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * \file htdocs/core/lib/website2.lib.php
  19. * \ingroup website
  20. * \brief Library for website module (rare functions not required for execution of website)
  21. */
  22. /**
  23. * Save content of a page on disk
  24. *
  25. * @param string $filemaster Full path of filename master.inc.php for website to generate
  26. * @return boolean True if OK
  27. */
  28. function dolSaveMasterFile($filemaster)
  29. {
  30. global $conf;
  31. // Now generate the master.inc.php page
  32. dol_syslog("We regenerate the master file");
  33. dol_delete_file($filemaster);
  34. $mastercontent = '<?php'."\n";
  35. $mastercontent .= '// File generated to link to the master file - DO NOT MODIFY - It is just an include'."\n";
  36. $mastercontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) {\n";
  37. $mastercontent .= " if (! defined('USEEXTERNALSERVER')) define('USEEXTERNALSERVER', 1);\n";
  38. $mastercontent .= " require_once '".DOL_DOCUMENT_ROOT."/master.inc.php';\n";
  39. $mastercontent .= "}\n";
  40. $mastercontent .= '?>'."\n";
  41. $result = file_put_contents($filemaster, $mastercontent);
  42. if (!empty($conf->global->MAIN_UMASK)) {
  43. @chmod($filemaster, octdec($conf->global->MAIN_UMASK));
  44. }
  45. return $result;
  46. }
  47. /**
  48. * Save an alias page on disk (A page that include the reference page).
  49. * It saves file into the root directory but also into language subdirectory.
  50. *
  51. * @param string $filealias Full path of filename to generate
  52. * @param Website $object Object website
  53. * @param WebsitePage $objectpage Object websitepage
  54. * @return boolean True if OK
  55. * @see dolSavePageContent()
  56. */
  57. function dolSavePageAlias($filealias, $object, $objectpage)
  58. {
  59. global $conf;
  60. // Now create the .tpl file
  61. dol_syslog("dolSavePageAlias We regenerate the alias page filealias=".$filealias);
  62. $aliascontent = '<?php'."\n";
  63. $aliascontent .= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n";
  64. $aliascontent .= 'global $dolibarr_main_data_root;'."\n";
  65. $aliascontent .= 'if (empty($dolibarr_main_data_root)) require \'./page'.$objectpage->id.'.tpl.php\'; ';
  66. $aliascontent .= 'else require $dolibarr_main_data_root.\'/website/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n";
  67. $aliascontent .= '?>'."\n";
  68. $result = file_put_contents($filealias, $aliascontent);
  69. if ($result === false) {
  70. dol_syslog("Failed to write file ".$filealias, LOG_WARNING);
  71. }
  72. if (!empty($conf->global->MAIN_UMASK)) {
  73. @chmod($filealias, octdec($conf->global->MAIN_UMASK));
  74. }
  75. // Save also alias into language subdirectory if it is not a main language
  76. if ($objectpage->lang && in_array($objectpage->lang, explode(',', $object->otherlang))) {
  77. $dirname = dirname($filealias);
  78. $filename = basename($filealias);
  79. $filealiassub = $dirname.'/'.$objectpage->lang.'/'.$filename;
  80. $aliascontent = '<?php'."\n";
  81. $aliascontent .= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n";
  82. $aliascontent .= 'global $dolibarr_main_data_root;'."\n";
  83. $aliascontent .= 'if (empty($dolibarr_main_data_root)) require \'../page'.$objectpage->id.'.tpl.php\'; ';
  84. $aliascontent .= 'else require $dolibarr_main_data_root.\'/website/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n";
  85. $aliascontent .= '?>'."\n";
  86. $result = file_put_contents($filealiassub, $aliascontent);
  87. if ($result === false) {
  88. dol_syslog("Failed to write file ".$filealiassub, LOG_WARNING);
  89. }
  90. if (!empty($conf->global->MAIN_UMASK)) {
  91. @chmod($filealiassub, octdec($conf->global->MAIN_UMASK));
  92. }
  93. } elseif (empty($objectpage->lang) || !in_array($objectpage->lang, explode(',', $object->otherlang))) {
  94. // Save also alias into all language subdirectories if it is a main language
  95. if (empty($conf->global->WEBSITE_DISABLE_MAIN_LANGUAGE_INTO_LANGSUBDIR) && !empty($object->otherlang)) {
  96. $dirname = dirname($filealias);
  97. $filename = basename($filealias);
  98. foreach (explode(',', $object->otherlang) as $sublang) {
  99. // Avoid to erase main alias file if $sublang is empty string
  100. if (empty(trim($sublang))) continue;
  101. $filealiassub = $dirname.'/'.$sublang.'/'.$filename;
  102. $aliascontent = '<?php'."\n";
  103. $aliascontent .= "// File generated to wrap the alias page - DO NOT MODIFY - It is just a wrapper to real page\n";
  104. $aliascontent .= 'global $dolibarr_main_data_root;'."\n";
  105. $aliascontent .= 'if (empty($dolibarr_main_data_root)) require \'../page'.$objectpage->id.'.tpl.php\'; ';
  106. $aliascontent .= 'else require $dolibarr_main_data_root.\'/website/\'.$website->ref.\'/page'.$objectpage->id.'.tpl.php\';'."\n";
  107. $aliascontent .= '?>'."\n";
  108. $result = file_put_contents($filealiassub, $aliascontent);
  109. if ($result === false) {
  110. dol_syslog("Failed to write file ".$filealiassub, LOG_WARNING);
  111. }
  112. if (!empty($conf->global->MAIN_UMASK)) {
  113. @chmod($filealiassub, octdec($conf->global->MAIN_UMASK));
  114. }
  115. }
  116. }
  117. }
  118. return ($result ?true:false);
  119. }
  120. /**
  121. * Save content of a page on disk (page name is generally ID_of_page.php).
  122. * Page contents are always saved into "root" directory. Only aliases pages saved with dolSavePageAlias() can be in root or language subdir.
  123. *
  124. * @param string $filetpl Full path of filename to generate
  125. * @param Website $object Object website
  126. * @param WebsitePage $objectpage Object websitepage
  127. * @param int $backupold 1=Make a backup of old page
  128. * @return boolean True if OK
  129. * @see dolSavePageAlias()
  130. */
  131. function dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage, $backupold = 0)
  132. {
  133. global $conf, $db;
  134. // Now create the .tpl file (duplicate code with actions updatesource or updatecontent but we need this to save new header)
  135. dol_syslog("dolSavePageContent We regenerate the tpl page filetpl=".$filetpl);
  136. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  137. if (dol_is_file($filetpl)) {
  138. if ($backupold) {
  139. dol_delete_file($filetpl.'.old');
  140. $result = dol_move($filetpl, $filetpl.'.old', 0, 1, 0, 0);
  141. if (! $result) {
  142. return false;
  143. }
  144. } else {
  145. dol_delete_file($filetpl);
  146. }
  147. }
  148. $shortlangcode = '';
  149. if ($objectpage->lang) {
  150. $shortlangcode = substr($objectpage->lang, 0, 2); // en_US or en-US -> en
  151. }
  152. if (empty($shortlangcode)) {
  153. $shortlangcode = substr($object->lang, 0, 2); // en_US or en-US -> en
  154. }
  155. $tplcontent = '';
  156. $tplcontent .= "<?php // BEGIN PHP\n";
  157. $tplcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
  158. $tplcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) {\n";
  159. $tplcontent .= ' $pathdepth = count(explode(\'/\', $_SERVER[\'SCRIPT_NAME\'])) - 2;'."\n";
  160. $tplcontent .= ' require_once ($pathdepth ? str_repeat(\'../\', $pathdepth) : \'./\').\'master.inc.php\';'."\n";
  161. $tplcontent .= "} // Not already loaded\n";
  162. $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
  163. $tplcontent .= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
  164. $tplcontent .= "ob_start();\n";
  165. $tplcontent .= "// END PHP ?>\n";
  166. if (!empty($conf->global->WEBSITE_FORCE_DOCTYPE_HTML5)) {
  167. $tplcontent .= "<!DOCTYPE html>\n";
  168. }
  169. $tplcontent .= '<html'.($shortlangcode ? ' lang="'.$shortlangcode.'"' : '').'>'."\n";
  170. $tplcontent .= '<head>'."\n";
  171. $tplcontent .= '<title>'.dol_string_nohtmltag($objectpage->title, 0, 'UTF-8').'</title>'."\n";
  172. $tplcontent .= '<meta charset="utf-8">'."\n";
  173. $tplcontent .= '<meta http-equiv="content-type" content="text/html; charset=utf-8" />'."\n";
  174. $tplcontent .= '<meta name="robots" content="index, follow" />'."\n";
  175. $tplcontent .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">'."\n";
  176. $tplcontent .= '<meta name="keywords" content="'.dol_string_nohtmltag($objectpage->keywords).'" />'."\n";
  177. $tplcontent .= '<meta name="title" content="'.dol_string_nohtmltag($objectpage->title, 0, 'UTF-8').'" />'."\n";
  178. $tplcontent .= '<meta name="description" content="'.dol_string_nohtmltag($objectpage->description, 0, 'UTF-8').'" />'."\n";
  179. $tplcontent .= '<meta name="generator" content="'.DOL_APPLICATION_TITLE.' '.DOL_VERSION.' (https://www.dolibarr.org)" />'."\n";
  180. $tplcontent .= '<meta name="dolibarr:pageid" content="'.dol_string_nohtmltag($objectpage->id).'" />'."\n";
  181. // Add canonical reference
  182. if ($object->virtualhost) {
  183. $tplcontent .= '<link rel="canonical" href="'.(($objectpage->id == $object->fk_default_home) ? '/' : (($shortlangcode != substr($object->lang, 0, 2) ? '/'.$shortlangcode : '').'/'.$objectpage->pageurl.'.php')).'" />'."\n";
  184. }
  185. // Add translation reference (main language)
  186. if ($object->isMultiLang()) {
  187. // Add page "translation of"
  188. $translationof = $objectpage->fk_page;
  189. if ($translationof) {
  190. $tmppage = new WebsitePage($db);
  191. $tmppage->fetch($translationof);
  192. if ($tmppage->id > 0) {
  193. $tmpshortlangcode = '';
  194. if ($tmppage->lang) {
  195. $tmpshortlangcode = preg_replace('/[_-].*$/', '', $tmppage->lang); // en_US or en-US -> en
  196. }
  197. if (empty($tmpshortlangcode)) {
  198. $tmpshortlangcode = preg_replace('/[_-].*$/', '', $object->lang); // en_US or en-US -> en
  199. }
  200. if ($tmpshortlangcode != $shortlangcode) {
  201. $tplcontent .= '<link rel="alternate" hreflang="'.$tmpshortlangcode.'" href="'.($object->fk_default_home == $tmppage->id ? '/' : (($tmpshortlangcode != substr($object->lang, 0, 2)) ? '/'.$tmpshortlangcode : '').'/'.$tmppage->pageurl.'.php').'" />'."\n";
  202. }
  203. }
  204. }
  205. // Add "has translation pages"
  206. $sql = "SELECT rowid as id, lang, pageurl from ".MAIN_DB_PREFIX.'website_page where fk_page IN ('.$db->sanitize($objectpage->id.($translationof ? ", ".$translationof : '')).")";
  207. $resql = $db->query($sql);
  208. if ($resql) {
  209. $num_rows = $db->num_rows($resql);
  210. if ($num_rows > 0) {
  211. while ($obj = $db->fetch_object($resql)) {
  212. $tmpshortlangcode = '';
  213. if ($obj->lang) {
  214. $tmpshortlangcode = preg_replace('/[_-].*$/', '', $obj->lang); // en_US or en-US -> en
  215. }
  216. if ($tmpshortlangcode != $shortlangcode) {
  217. $tplcontent .= '<link rel="alternate" hreflang="'.$tmpshortlangcode.'" href="'.($object->fk_default_home == $obj->id ? '/' : (($tmpshortlangcode != substr($object->lang, 0, 2) ? '/'.$tmpshortlangcode : '')).'/'.$obj->pageurl.'.php').'" />'."\n";
  218. }
  219. }
  220. }
  221. } else {
  222. dol_print_error($db);
  223. }
  224. // Add myself
  225. $tplcontent .= '<?php if ($_SERVER["PHP_SELF"] == "'.(($object->fk_default_home == $objectpage->id) ? '/' : (($shortlangcode != substr($object->lang, 0, 2)) ? '/'.$shortlangcode : '')).'/'.$objectpage->pageurl.'.php") { ?>'."\n";
  226. $tplcontent .= '<link rel="alternate" hreflang="'.$shortlangcode.'" href="'.(($object->fk_default_home == $objectpage->id) ? '/' : (($shortlangcode != substr($object->lang, 0, 2)) ? '/'.$shortlangcode : '').'/'.$objectpage->pageurl.'.php').'" />'."\n";
  227. $tplcontent .= '<?php } ?>'."\n";
  228. }
  229. // Add manifest.json. Do we have to add it only on home page ?
  230. $tplcontent .= '<?php if ($website->use_manifest) { print \'<link rel="manifest" href="/manifest.json.php" />\'."\n"; } ?>'."\n";
  231. $tplcontent .= '<!-- Include link to CSS file -->'."\n";
  232. // Add js
  233. $tplcontent .= '<link rel="stylesheet" href="/styles.css.php?website=<?php echo $websitekey; ?>" type="text/css" />'."\n";
  234. $tplcontent .= '<!-- Include link to JS file -->'."\n";
  235. $tplcontent .= '<script async src="/javascript.js.php"></script>'."\n";
  236. // Add headers
  237. $tplcontent .= '<!-- Include HTML header from common file -->'."\n";
  238. $tplcontent .= '<?php if (file_exists(DOL_DATA_ROOT."/website/".$websitekey."/htmlheader.html")) include DOL_DATA_ROOT."/website/".$websitekey."/htmlheader.html"; ?>'."\n";
  239. $tplcontent .= '<!-- Include HTML header from page header block -->'."\n";
  240. $tplcontent .= preg_replace('/<\/?html>/ims', '', $objectpage->htmlheader)."\n";
  241. $tplcontent .= '</head>'."\n";
  242. $tplcontent .= '<!-- File generated by Dolibarr website module editor -->'."\n";
  243. $tplcontent .= '<body id="bodywebsite" class="bodywebsite bodywebpage-'.$objectpage->ref.'">'."\n";
  244. $tplcontent .= $objectpage->content."\n";
  245. $tplcontent .= '</body>'."\n";
  246. $tplcontent .= '</html>'."\n";
  247. $tplcontent .= '<?php // BEGIN PHP'."\n";
  248. $tplcontent .= '$tmp = ob_get_contents(); ob_end_clean(); dolWebsiteOutput($tmp, "html", '.$objectpage->id.'); dolWebsiteIncrementCounter('.$object->id.', "'.$objectpage->type_container.'", '.$objectpage->id.');'."\n";
  249. $tplcontent .= "// END PHP ?>\n";
  250. //var_dump($filetpl);exit;
  251. $result = file_put_contents($filetpl, $tplcontent);
  252. if (!empty($conf->global->MAIN_UMASK)) {
  253. @chmod($filetpl, octdec($conf->global->MAIN_UMASK));
  254. }
  255. return $result;
  256. }
  257. /**
  258. * Save content of the index.php and/or the wrapper.php page
  259. *
  260. * @param string $pathofwebsite Path of website root
  261. * @param string $fileindex Full path of file index.php
  262. * @param string $filetpl File tpl the index.php page redirect to (used only if $fileindex is provided)
  263. * @param string $filewrapper Full path of file wrapper.php
  264. * @param Website $object Object website
  265. * @return boolean True if OK
  266. */
  267. function dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl, $filewrapper, $object = null)
  268. {
  269. global $conf, $db;
  270. $result1 = false;
  271. $result2 = false;
  272. dol_mkdir($pathofwebsite);
  273. if ($fileindex) {
  274. dol_delete_file($fileindex);
  275. $indexcontent = '<?php'."\n";
  276. $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";
  277. $indexcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
  278. $indexcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once './master.inc.php'; } // Load master if not already loaded\n";
  279. $indexcontent .= 'if (!empty($_GET[\'pageref\']) || !empty($_GET[\'pagealiasalt\']) || !empty($_GET[\'pageid\'])) {'."\n";
  280. $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
  281. $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
  282. $indexcontent .= ' redirectToContainer($_GET[\'pageref\'], $_GET[\'pagealiasalt\'], $_GET[\'pageid\']);'."\n";
  283. $indexcontent .= "}\n";
  284. $indexcontent .= "include_once './".basename($filetpl)."'\n";
  285. $indexcontent .= '// END PHP ?>'."\n";
  286. $result1 = file_put_contents($fileindex, $indexcontent);
  287. if (!empty($conf->global->MAIN_UMASK)) {
  288. @chmod($fileindex, octdec($conf->global->MAIN_UMASK));
  289. }
  290. if (is_object($object) && $object->fk_default_home > 0) {
  291. $objectpage = new WebsitePage($db);
  292. $objectpage->fetch($object->fk_default_home);
  293. // Create a version for sublanguages
  294. if (empty($objectpage->lang) || !in_array($objectpage->lang, explode(',', $object->otherlang))) {
  295. if (empty($conf->global->WEBSITE_DISABLE_MAIN_LANGUAGE_INTO_LANGSUBDIR) && is_object($object) && !empty($object->otherlang)) {
  296. $dirname = dirname($fileindex);
  297. foreach (explode(',', $object->otherlang) as $sublang) {
  298. // Avoid to erase main alias file if $sublang is empty string
  299. if (empty(trim($sublang))) continue;
  300. $fileindexsub = $dirname.'/'.$sublang.'/index.php';
  301. // Same indexcontent than previously but with ../ instead of ./ for master and tpl file include/require_once.
  302. $relpath = '..';
  303. $indexcontent = '<?php'."\n";
  304. $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";
  305. $indexcontent .= '$websitekey=basename(__DIR__); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
  306. $indexcontent .= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once '".$relpath."/master.inc.php'; } // Load master if not already loaded\n";
  307. $indexcontent .= 'if (!empty($_GET[\'pageref\']) || !empty($_GET[\'pagealiasalt\']) || !empty($_GET[\'pageid\'])) {'."\n";
  308. $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
  309. $indexcontent .= " require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
  310. $indexcontent .= ' redirectToContainer($_GET[\'pageref\'], $_GET[\'pagealiasalt\'], $_GET[\'pageid\']);'."\n";
  311. $indexcontent .= "}\n";
  312. $indexcontent .= "include_once '".$relpath."/".basename($filetpl)."'\n"; // use .. instead of .
  313. $indexcontent .= '// END PHP ?>'."\n";
  314. $result = file_put_contents($fileindexsub, $indexcontent);
  315. if ($result === false) {
  316. dol_syslog("Failed to write file ".$fileindexsub, LOG_WARNING);
  317. }
  318. if (!empty($conf->global->MAIN_UMASK)) {
  319. @chmod($fileindexsub, octdec($conf->global->MAIN_UMASK));
  320. }
  321. }
  322. }
  323. }
  324. }
  325. } else {
  326. $result1 = true;
  327. }
  328. if ($filewrapper) {
  329. dol_delete_file($filewrapper);
  330. $wrappercontent = file_get_contents(DOL_DOCUMENT_ROOT.'/website/samples/wrapper.php');
  331. $result2 = file_put_contents($filewrapper, $wrappercontent);
  332. if (!empty($conf->global->MAIN_UMASK)) {
  333. @chmod($filewrapper, octdec($conf->global->MAIN_UMASK));
  334. }
  335. } else {
  336. $result2 = true;
  337. }
  338. return ($result1 && $result2);
  339. }
  340. /**
  341. * Save content of a page on disk
  342. *
  343. * @param string $filehtmlheader Full path of filename to generate
  344. * @param string $htmlheadercontent Content of file
  345. * @return boolean True if OK
  346. */
  347. function dolSaveHtmlHeader($filehtmlheader, $htmlheadercontent)
  348. {
  349. global $conf, $pathofwebsite;
  350. dol_syslog("Save html header into ".$filehtmlheader);
  351. dol_mkdir($pathofwebsite);
  352. $result = file_put_contents($filehtmlheader, $htmlheadercontent);
  353. if (!empty($conf->global->MAIN_UMASK)) {
  354. @chmod($filehtmlheader, octdec($conf->global->MAIN_UMASK));
  355. }
  356. return $result;
  357. }
  358. /**
  359. * Save content of a page on disk
  360. *
  361. * @param string $filecss Full path of filename to generate
  362. * @param string $csscontent Content of file
  363. * @return boolean True if OK
  364. */
  365. function dolSaveCssFile($filecss, $csscontent)
  366. {
  367. global $conf, $pathofwebsite;
  368. dol_syslog("Save css file into ".$filecss);
  369. dol_mkdir($pathofwebsite);
  370. $result = file_put_contents($filecss, $csscontent);
  371. if (!empty($conf->global->MAIN_UMASK)) {
  372. @chmod($filecss, octdec($conf->global->MAIN_UMASK));
  373. }
  374. return $result;
  375. }
  376. /**
  377. * Save content of a page on disk. For example into documents/website/mywebsite/javascript.js.php file.
  378. *
  379. * @param string $filejs Full path of filename to generate
  380. * @param string $jscontent Content of file
  381. * @return boolean True if OK
  382. */
  383. function dolSaveJsFile($filejs, $jscontent)
  384. {
  385. global $conf, $pathofwebsite;
  386. dol_syslog("Save js file into ".$filejs);
  387. dol_mkdir($pathofwebsite);
  388. $result = file_put_contents($filejs, $jscontent);
  389. if (!empty($conf->global->MAIN_UMASK)) {
  390. @chmod($filejs, octdec($conf->global->MAIN_UMASK));
  391. }
  392. return $result;
  393. }
  394. /**
  395. * Save content of a page on disk
  396. *
  397. * @param string $filerobot Full path of filename to generate
  398. * @param string $robotcontent Content of file
  399. * @return boolean True if OK
  400. */
  401. function dolSaveRobotFile($filerobot, $robotcontent)
  402. {
  403. global $conf, $pathofwebsite;
  404. dol_syslog("Save robot file into ".$filerobot);
  405. dol_mkdir($pathofwebsite);
  406. $result = file_put_contents($filerobot, $robotcontent);
  407. if (!empty($conf->global->MAIN_UMASK)) {
  408. @chmod($filerobot, octdec($conf->global->MAIN_UMASK));
  409. }
  410. return $result;
  411. }
  412. /**
  413. * Save content of a page on disk
  414. *
  415. * @param string $filehtaccess Full path of filename to generate
  416. * @param string $htaccess Content of file
  417. * @return boolean True if OK
  418. */
  419. function dolSaveHtaccessFile($filehtaccess, $htaccess)
  420. {
  421. global $conf, $pathofwebsite;
  422. dol_syslog("Save htaccess file into ".$filehtaccess);
  423. dol_mkdir($pathofwebsite);
  424. $result = file_put_contents($filehtaccess, $htaccess);
  425. if (!empty($conf->global->MAIN_UMASK)) {
  426. @chmod($filehtaccess, octdec($conf->global->MAIN_UMASK));
  427. }
  428. return $result;
  429. }
  430. /**
  431. * Save content of a page on disk
  432. *
  433. * @param string $file Full path of filename to generate
  434. * @param string $content Content of file
  435. * @return boolean True if OK
  436. */
  437. function dolSaveManifestJson($file, $content)
  438. {
  439. global $conf, $pathofwebsite;
  440. dol_syslog("Save manifest.js.php file into ".$file);
  441. dol_mkdir($pathofwebsite);
  442. $result = file_put_contents($file, $content);
  443. if (!empty($conf->global->MAIN_UMASK)) {
  444. @chmod($file, octdec($conf->global->MAIN_UMASK));
  445. }
  446. return $result;
  447. }
  448. /**
  449. * Save content of a page on disk
  450. *
  451. * @param string $file Full path of filename to generate
  452. * @param string $content Content of file
  453. * @return boolean True if OK
  454. */
  455. function dolSaveReadme($file, $content)
  456. {
  457. global $conf, $pathofwebsite;
  458. dol_syslog("Save README.md file into ".$file);
  459. dol_mkdir($pathofwebsite);
  460. $result = file_put_contents($file, $content);
  461. if (!empty($conf->global->MAIN_UMASK)) {
  462. @chmod($file, octdec($conf->global->MAIN_UMASK));
  463. }
  464. return $result;
  465. }
  466. /**
  467. * Save content of a page on disk
  468. *
  469. * @param string $file Full path of filename to generate
  470. * @param string $content Content of file
  471. * @return boolean True if OK
  472. */
  473. function dolSaveLicense($file, $content)
  474. {
  475. global $conf, $pathofwebsite;
  476. dol_syslog("Save LICENSE file into ".$file);
  477. dol_mkdir($pathofwebsite);
  478. $result = file_put_contents($file, $content);
  479. if (!empty($conf->global->MAIN_UMASK)) {
  480. @chmod($file, octdec($conf->global->MAIN_UMASK));
  481. }
  482. return $result;
  483. }
  484. /**
  485. * Show list of themes. Show all thumbs of themes/skins
  486. *
  487. * @param Website $website Object website to load the template into
  488. * @return void
  489. */
  490. function showWebsiteTemplates(Website $website)
  491. {
  492. global $conf, $langs, $db, $form, $user;
  493. $dirthemes = array('/doctemplates/websites');
  494. if (!empty($conf->modules_parts['websitetemplates'])) { // Using this feature slow down application
  495. foreach ($conf->modules_parts['websitetemplates'] as $reldir) {
  496. $dirthemes = array_merge($dirthemes, (array) ($reldir.'doctemplates/websites'));
  497. }
  498. }
  499. $dirthemes = array_unique($dirthemes);
  500. // Now dir_themes=array('/themes') or dir_themes=array('/theme','/mymodule/theme')
  501. $colspan = 2;
  502. print '<!-- For website template import -->'."\n";
  503. print '<table class="noborder centpercent">';
  504. // Title
  505. print '<tr class="liste_titre"><th class="titlefield">';
  506. print $form->textwithpicto($langs->trans("Templates"), $langs->trans("ThemeDir").' : '.join(", ", $dirthemes));
  507. print ' ';
  508. print '<a href="'.$_SERVER["PHP_SELF"].'?website='.urlencode($website->ref).'&importsite=1" target="_blank" rel="noopener noreferrer external">';
  509. print img_picto('', 'refresh');
  510. print '</a>';
  511. print '</th>';
  512. print '<th class="right">';
  513. $url = 'https://www.dolistore.com/43-web-site-templates';
  514. print '<a href="'.$url.'" target="_blank" rel="noopener noreferrer external">';
  515. print img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans('DownloadMoreSkins');
  516. print '</a>';
  517. print '</th></tr>';
  518. print '<tr><td colspan="'.$colspan.'">';
  519. print '<table class="nobordernopadding centpercent"><tr><td><div class="center">';
  520. if (count($dirthemes)) {
  521. $i = 0;
  522. foreach ($dirthemes as $dir) {
  523. //print $dirroot.$dir;exit;
  524. $dirtheme = DOL_DATA_ROOT.$dir; // This include loop on $conf->file->dol_document_root
  525. if (is_dir($dirtheme)) {
  526. $handle = opendir($dirtheme);
  527. if (is_resource($handle)) {
  528. while (($subdir = readdir($handle)) !== false) {
  529. if (is_file($dirtheme."/".$subdir) && substr($subdir, 0, 1) <> '.' && substr($subdir, 0, 3) <> 'CVS' && preg_match('/\.zip$/i', $subdir)) {
  530. $subdirwithoutzip = preg_replace('/\.zip$/i', '', $subdir);
  531. // Disable not stable themes (dir ends with _exp or _dev)
  532. if ($conf->global->MAIN_FEATURES_LEVEL < 2 && preg_match('/_dev$/i', $subdir)) {
  533. continue;
  534. }
  535. if ($conf->global->MAIN_FEATURES_LEVEL < 1 && preg_match('/_exp$/i', $subdir)) {
  536. continue;
  537. }
  538. print '<div class="inline-block" style="margin-top: 10px; margin-bottom: 10px; margin-right: 20px; margin-left: 20px;">';
  539. $templatedir = $dirtheme."/".$subdir;
  540. $file = $dirtheme."/".$subdirwithoutzip.".jpg";
  541. $url = DOL_URL_ROOT.'/viewimage.php?modulepart=doctemplateswebsite&file='.$subdirwithoutzip.".jpg";
  542. if (!file_exists($file)) {
  543. $url = DOL_URL_ROOT.'/public/theme/common/nophoto.png';
  544. }
  545. $originalfile = basename($file);
  546. $entity = $conf->entity;
  547. $modulepart = 'doctemplateswebsite';
  548. $cache = '';
  549. $title = $file;
  550. $ret = '';
  551. $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 1, '&entity='.$entity);
  552. if (!empty($urladvanced)) {
  553. $ret .= '<a class="'.$urladvanced['css'].'" target="'.$urladvanced['target'].'" mime="'.$urladvanced['mime'].'" href="'.$urladvanced['url'].'">';
  554. } else {
  555. $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.urlencode($modulepart).'&entity='.((int) $entity).'&file='.urlencode($originalfile).'&cache='.((int) $cache).'">';
  556. }
  557. print $ret;
  558. print '<img class="img-skinthumb shadow" src="'.$url.'" border="0" alt="'.$title.'" title="'.$title.'" style="margin-bottom: 5px;">';
  559. print '</a>';
  560. print '<br>';
  561. print $subdir;
  562. print '<br>';
  563. print '<span class="opacitymedium">'.dol_print_size(dol_filesize($dirtheme."/".$subdir), 1, 1).' - '.dol_print_date(dol_filemtime($templatedir), 'dayhour', 'tzuserrel').'</span>';
  564. if ($user->hasRight('website', 'delete')) {
  565. print ' <a href="'.$_SERVER["PHP_SELF"].'?action=deletetemplate&token='.newToken().'&website='.urlencode($website->ref).'&templateuserfile='.urlencode($subdir).'">'.img_picto('', 'delete').'</a>';
  566. }
  567. print '<br><a href="'.$_SERVER["PHP_SELF"].'?action=importsiteconfirm&token='.newToken().'&website='.urlencode($website->ref).'&templateuserfile='.urlencode($subdir).'" class="button">'.$langs->trans("Load").'</a>';
  568. print '</div>';
  569. $i++;
  570. }
  571. }
  572. }
  573. }
  574. }
  575. } else {
  576. print '<span class="opacitymedium">'.$langs->trans("None").'</span>';
  577. }
  578. print '</div></td></tr></table>';
  579. print '</td></tr>';
  580. print '</table>';
  581. }
  582. /**
  583. * Check a new string containing only php code (including <php tag)
  584. * - Block if bad code in the new string.
  585. * - Block also if user has no permission to change PHP code.
  586. *
  587. * @param string $phpfullcodestringold PHP old string. For exemple "<?php echo 'a' ?><php echo 'b' ?>"
  588. * @param string $phpfullcodestring PHP new string. For exemple "<?php echo 'a' ?><php echo 'c' ?>"
  589. * @return int Error or not
  590. */
  591. function checkPHPCode($phpfullcodestringold, $phpfullcodestring)
  592. {
  593. global $conf, $langs, $user;
  594. $error = 0;
  595. if (empty($phpfullcodestringold) && empty($phpfullcodestring)) {
  596. return 0;
  597. }
  598. // First check forbidden commands
  599. $forbiddenphpcommands = array();
  600. if (empty($conf->global->WEBSITE_PHP_ALLOW_EXEC)) { // If option is not on, we disallow functions to execute commands
  601. $forbiddenphpcommands = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI");
  602. }
  603. if (empty($conf->global->WEBSITE_PHP_ALLOW_WRITE)) { // If option is not on, we disallow functions to write files
  604. $forbiddenphpcommands = array_merge($forbiddenphpcommands, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "unlink", "mkdir", "rmdir", "symlink", "touch", "umask"));
  605. }
  606. foreach ($forbiddenphpcommands as $forbiddenphpcommand) {
  607. if (preg_match('/'.$forbiddenphpcommand.'\s*\(/ms', $phpfullcodestring)) {
  608. $error++;
  609. setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpcommand), null, 'errors');
  610. break;
  611. }
  612. }
  613. // This char can be used to execute RCE for example using with echo `ls`
  614. $forbiddenphpchars = array();
  615. if (empty($conf->global->WEBSITE_PHP_ALLOW_DANGEROUS_CHARS)) { // If option is not on, we disallow functions to execute commands
  616. $forbiddenphpchars = array("`");
  617. }
  618. foreach ($forbiddenphpchars as $forbiddenphpchar) {
  619. if (preg_match('/'.$forbiddenphpchar.'/ms', $phpfullcodestring)) {
  620. $error++;
  621. setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpchar), null, 'errors');
  622. break;
  623. }
  624. }
  625. // Deny dynamic functions '${a}(' or '$a[b](' - So we refuse '}(' and ']('
  626. if (preg_match('/[}\]]\(/ims', $phpfullcodestring)) {
  627. $error++;
  628. setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", ']('), null, 'errors');
  629. }
  630. // Deny dynamic functions $xxx(
  631. if (preg_match('/\$[a-z0-9_]+\(/ims', $phpfullcodestring)) {
  632. $error++;
  633. setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", '$...('), null, 'errors');
  634. }
  635. if ($phpfullcodestringold != $phpfullcodestring) {
  636. if (!$error && empty($user->rights->website->writephp)) {
  637. $error++;
  638. setEventMessages($langs->trans("NotAllowedToAddDynamicContent"), null, 'errors');
  639. }
  640. if (!$error) {
  641. $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
  642. $allowimportsite = true;
  643. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  644. if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
  645. $allowimportsite = false;
  646. }
  647. if (!$allowimportsite) {
  648. $error++;
  649. // Blocked by installmodules.lock
  650. if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) {
  651. // Show clean corporate message
  652. $message = $langs->trans('InstallModuleFromWebHasBeenDisabledContactUs');
  653. } else {
  654. // Show technical generic message
  655. $message = $langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock');
  656. }
  657. setEventMessages($message, null, 'errors');
  658. }
  659. }
  660. }
  661. return $error;
  662. }