website.lib.php 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298
  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/website.lib.php
  19. * \ingroup website
  20. * \brief Library for website module
  21. */
  22. /**
  23. * Remove PHP code part from a string.
  24. *
  25. * @param string $str String to clean
  26. * @param string $replacewith String to use as replacement
  27. * @return string Result string without php code
  28. * @see dolKeepOnlyPhpCode()
  29. */
  30. function dolStripPhpCode($str, $replacewith = '')
  31. {
  32. $str = str_replace('<?=', '<?php', $str);
  33. $newstr = '';
  34. // Split on each opening tag
  35. //$parts = explode('<?php', $str);
  36. $parts = preg_split('/'.preg_quote('<?php', '/').'/i', $str);
  37. if (!empty($parts)) {
  38. $i = 0;
  39. foreach ($parts as $part) {
  40. if ($i == 0) { // The first part is never php code
  41. $i++;
  42. $newstr .= $part;
  43. continue;
  44. }
  45. // The second part is the php code. We split on closing tag
  46. $partlings = explode('?>', $part);
  47. if (!empty($partlings)) {
  48. //$phppart = $partlings[0];
  49. //remove content before closing tag
  50. if (count($partlings) > 1) {
  51. $partlings[0] = ''; // Todo why a count > 1 and not >= 1 ?
  52. }
  53. //append to out string
  54. //$newstr .= '<span class="phptag" class="tooltip" title="'.dol_escape_htmltag(dolGetFirstLineOfText($phppart).'...').'">'.$replacewith.'<!-- '.$phppart.' --></span>'.implode('', $partlings);
  55. //$newstr .= '<span>'.$replacewith.'<!-- '.$phppart.' --></span>'.implode('', $partlings);
  56. $newstr .= '<span phptag>'.$replacewith.'</span>'.implode('', $partlings);
  57. //$newstr .= $replacewith.implode('', $partlings);
  58. }
  59. }
  60. }
  61. return $newstr;
  62. }
  63. /**
  64. * Keep only PHP code part from a HTML string page.
  65. *
  66. * @param string $str String to clean
  67. * @return string Result string with php code only
  68. * @see dolStripPhpCode(), checkPHPCode()
  69. */
  70. function dolKeepOnlyPhpCode($str)
  71. {
  72. $str = str_replace('<?=', '<?php', $str);
  73. $str = str_replace('<?php', '__LTINTPHP__', $str);
  74. $str = str_replace('<?', '<?php', $str); // replace the short_open_tag. It is recommended to set this is Off in php.ini
  75. $str = str_replace('__LTINTPHP__', '<?php', $str);
  76. $newstr = '';
  77. // Split on each opening tag
  78. //$parts = explode('<?php', $str);
  79. $parts = preg_split('/'.preg_quote('<?php', '/').'/i', $str);
  80. if (!empty($parts)) {
  81. $i = 0;
  82. foreach ($parts as $part) {
  83. if ($i == 0) { // The first part is never php code
  84. $i++;
  85. continue;
  86. }
  87. $newstr .= '<?php';
  88. //split on closing tag
  89. $partlings = explode('?>', $part, 2);
  90. if (!empty($partlings)) {
  91. $newstr .= $partlings[0].'?>';
  92. } else {
  93. $newstr .= $part.'?>';
  94. }
  95. }
  96. }
  97. return $newstr;
  98. }
  99. /**
  100. * Convert a page content to have correct links (based on DOL_URL_ROOT) into an html content. It replaces also dynamic content with '...php...'
  101. * Used to ouput the page on the Preview from backoffice.
  102. *
  103. * @param Website $website Web site object
  104. * @param string $content Content to replace
  105. * @param int $removephppart 0=Replace PHP sections with a PHP badge. 1=Remove completely PHP sections.
  106. * @param string $contenttype Content type
  107. * @param int $containerid Contenair id
  108. * @return boolean True if OK
  109. * @see dolWebsiteOutput() for function used to replace content in a web server context
  110. */
  111. function dolWebsiteReplacementOfLinks($website, $content, $removephppart = 0, $contenttype = 'html', $containerid = '')
  112. {
  113. $nbrep = 0;
  114. dol_syslog('dolWebsiteReplacementOfLinks start (contenttype='.$contenttype." containerid=".$containerid." USEDOLIBARREDITOR=".(defined('USEDOLIBARREDITOR') ? '1' : '')." USEDOLIBARRSERVER=".(defined('USEDOLIBARRSERVER') ? '1' : '').')', LOG_DEBUG);
  115. //if ($contenttype == 'html') { print $content;exit; }
  116. // Replace php code. Note $content may come from database and does not contain body tags.
  117. $replacewith = '...php...';
  118. if ($removephppart) {
  119. $replacewith = '';
  120. }
  121. $content = preg_replace('/value="<\?php((?!\?>).)*\?>\n*/ims', 'value="'.$replacewith.'"', $content);
  122. $replacewith = '"callto=#';
  123. if ($removephppart) {
  124. $replacewith = '';
  125. }
  126. $content = preg_replace('/"callto:<\?php((?!\?>).)*\?>\n*/ims', $replacewith, $content);
  127. $replacewith = '"mailto=#';
  128. if ($removephppart) {
  129. $replacewith = '';
  130. }
  131. $content = preg_replace('/"mailto:<\?php((?!\?>).)*\?>\n*/ims', $replacewith, $content);
  132. $replacewith = 'src="php';
  133. if ($removephppart) {
  134. $replacewith = '';
  135. }
  136. $content = preg_replace('/src="<\?php((?!\?>).)*\?>\n*/ims', $replacewith, $content);
  137. $replacewith = 'href="php';
  138. if ($removephppart) {
  139. $replacewith = '';
  140. }
  141. $content = preg_replace('/href="<\?php((?!\?>).)*\?>\n*/ims', $replacewith, $content);
  142. //$replacewith='<span class="phptag">...php...</span>';
  143. $replacewith = '...php...';
  144. if ($removephppart) {
  145. $replacewith = '';
  146. }
  147. //$content = preg_replace('/<\?php((?!\?toremove>).)*\?toremove>\n*/ims', $replacewith, $content);
  148. /*if ($content === null) {
  149. if (preg_last_error() == PREG_JIT_STACKLIMIT_ERROR) $content = 'preg_replace error (when removing php tags) PREG_JIT_STACKLIMIT_ERROR';
  150. }*/
  151. $content = dolStripPhpCode($content, $replacewith);
  152. //var_dump($content);
  153. // Protect the link styles.css.php to any replacement that we make after.
  154. $content = str_replace('href="styles.css.php', 'href="!~!~!~styles.css.php', $content);
  155. $content = str_replace('href="http', 'href="!~!~!~http', $content);
  156. $content = str_replace('href="//', 'href="!~!~!~//', $content);
  157. $content = str_replace('src="viewimage.php', 'src="!~!~!~/viewimage.php', $content);
  158. $content = str_replace('src="/viewimage.php', 'src="!~!~!~/viewimage.php', $content);
  159. $content = str_replace('src="'.DOL_URL_ROOT.'/viewimage.php', 'src="!~!~!~'.DOL_URL_ROOT.'/viewimage.php', $content);
  160. $content = str_replace('href="document.php', 'href="!~!~!~/document.php', $content);
  161. $content = str_replace('href="/document.php', 'href="!~!~!~/document.php', $content);
  162. $content = str_replace('href="'.DOL_URL_ROOT.'/document.php', 'href="!~!~!~'.DOL_URL_ROOT.'/document.php', $content);
  163. // Replace relative link '/' with dolibarr URL
  164. $content = preg_replace('/(href=")\/(#[^\"<>]*)?\"/', '\1!~!~!~'.DOL_URL_ROOT.'/website/index.php?website='.$website->ref.'&pageid='.$website->fk_default_home.'\2"', $content, -1, $nbrep);
  165. // Replace relative link /xxx.php#aaa or /xxx.php with dolibarr URL (we discard param ?...)
  166. $content = preg_replace('/(href=")\/?([^:\"\!]*)\.php(#[^\"<>]*)?\"/', '\1!~!~!~'.DOL_URL_ROOT.'/website/index.php?website='.$website->ref.'&pageref=\2\3"', $content, -1, $nbrep);
  167. // Replace relative link /xxx.php?a=b&c=d#aaa or /xxx.php?a=b&c=d with dolibarr URL
  168. $content = preg_replace('/(href=")\/?([^:\"\!]*)\.php\?([^#\"<>]*)(#[^\"<>]*)?\"/', '\1!~!~!~'.DOL_URL_ROOT.'/website/index.php?website='.$website->ref.'&pageref=\2&\3\4"', $content, -1, $nbrep);
  169. // Fix relative link into medias with correct URL after the DOL_URL_ROOT: ../url("medias/
  170. $content = preg_replace('/url\((["\']?)\/?medias\//', 'url(\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  171. $content = preg_replace('/data-slide-bg=(["\']?)\/?medias\//', 'data-slide-bg=\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  172. // <img src="medias/...image.png... => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png...
  173. // <img src="...image.png... => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png...
  174. $content = preg_replace('/(<img[^>]*src=")\/?medias\//', '\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  175. // <img src="image.png... => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png...
  176. $content = preg_replace('/(<img[^>]*src=")\/?([^:\"\!]+)\"/', '\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=\2"', $content, -1, $nbrep);
  177. // <img src="viewimage.php/modulepart=medias&file=image.png" => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png"
  178. $content = preg_replace('/(<img[^>]*src=")(\/?viewimage\.php)/', '\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php', $content, -1, $nbrep);
  179. // action="newpage.php" => action="dolibarr/website/index.php?website=...&pageref=newpage
  180. $content = preg_replace('/(action=")\/?([^:\"]*)(\.php\")/', '\1!~!~!~'.DOL_URL_ROOT.'/website/index.php?website='.$website->ref.'&pageref=\2"', $content, -1, $nbrep);
  181. // Fix relative link /document.php with correct URL after the DOL_URL_ROOT: ...href="/document.php?modulepart="
  182. $content = preg_replace('/(href=")(\/?document\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  183. $content = preg_replace('/(src=")(\/?document\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  184. // Fix relative link /viewimage.php with correct URL after the DOL_URL_ROOT: ...href="/viewimage.php?modulepart="
  185. $content = preg_replace('/(url\(")(\/?viewimage\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  186. // Fix relative URL
  187. $content = str_replace('src="!~!~!~/viewimage.php', 'src="!~!~!~'.DOL_URL_ROOT.'/viewimage.php', $content);
  188. $content = str_replace('href="!~!~!~/document.php', 'href="!~!~!~'.DOL_URL_ROOT.'/document.php', $content);
  189. // Remove the protection tag !~!~!~
  190. $content = str_replace('!~!~!~', '', $content);
  191. dol_syslog('dolWebsiteReplacementOfLinks end', LOG_DEBUG);
  192. //if ($contenttype == 'html') { print $content;exit; }
  193. return $content;
  194. }
  195. /**
  196. * Converts smiley string into the utf8 sequence.
  197. * @param string $content Content to replace
  198. * @return string Replacement of all smiley strings with their utf8 code
  199. * @see dolWebsiteOutput()
  200. */
  201. function dolReplaceSmileyCodeWithUTF8($content)
  202. {
  203. $map = array(
  204. ":face_with_tears_of_joy:" => "\xF0\x9F\x98\x82",
  205. ":grinning_face_with_smiling_eyes:" => "\xF0\x9F\x98\x81",
  206. ":smiling_face_with_open_mouth:" => "\xF0\x9F\x98\x83",
  207. ":smiling_face_with_open_mouth_and_cold_sweat:" => "\xF0\x9F\x98\x85",
  208. ":smiling_face_with_open_mouth_and_tightly_closed_eyes:" => "\xF0\x9F\x98\x86",
  209. ":winking_face:" => "\xF0\x9F\x98\x89",
  210. ":smiling_face_with_smiling_eyes:" => "\xF0\x9F\x98\x8A",
  211. ":face_savouring_delicious_food:" => "\xF0\x9F\x98\x8B",
  212. ":relieved_face:" => "\xF0\x9F\x98\x8C",
  213. ":smiling_face_with_heart_shaped_eyes:" => "\xF0\x9F\x98\x8D",
  214. ":smiling_face_with_sunglasses:" => "\xF0\x9F\x98\x8E",
  215. ":smirking_face:" => "\xF0\x9F\x98\x8F",
  216. ":neutral_face:" => "\xF0\x9F\x98\x90",
  217. ":expressionless_face:" => "\xF0\x9F\x98\x91",
  218. ":unamused_face:" => "\xF0\x9F\x98\x92",
  219. ":face_with_cold_sweat:" => "\xF0\x9F\x98\x93",
  220. ":pensive_face:" => "\xF0\x9F\x98\x94",
  221. ":confused_face:" => "\xF0\x9F\x98\x95",
  222. ":confounded_face:" => "\xF0\x9F\x98\x96",
  223. ":kissing_face:" => "\xF0\x9F\x98\x97",
  224. ":face_throwing_a_kiss:" => "\xF0\x9F\x98\x98",
  225. ":kissing_face_with_smiling_eyes:" => "\xF0\x9F\x98\x99",
  226. ":kissing_face_with_closed_eyes:" => "\xF0\x9F\x98\x9A",
  227. ":face_with_stuck_out_tongue:" => "\xF0\x9F\x98\x9B",
  228. ":face_with_stuck_out_tongue_and_winking_eye:" => "\xF0\x9F\x98\x9C",
  229. ":face_with_stuck_out_tongue_and_tightly_closed_eyes:" => "\xF0\x9F\x98\x9D",
  230. ":disappointed_face:" => "\xF0\x9F\x98\x9E",
  231. ":worried_face:" => "\xF0\x9F\x98\x9F",
  232. ":angry_face:" => "\xF0\x9F\x98\xA0",
  233. ":face_with_symbols_on_mouth:" => "\xF0\x9F\x98\xA1",
  234. );
  235. foreach ($map as $key => $value) {
  236. $content = str_replace($key, $value, $content);
  237. }
  238. return $content;
  239. }
  240. /**
  241. * Render a string of an HTML content and output it.
  242. * Used to ouput the page when viewed from a server (Dolibarr or Apache).
  243. *
  244. * @param string $content Content string
  245. * @param string $contenttype Content type
  246. * @param int $containerid Contenair id
  247. * @return void
  248. * @see dolWebsiteReplacementOfLinks() for function used to replace content in the backoffice context.
  249. */
  250. function dolWebsiteOutput($content, $contenttype = 'html', $containerid = '')
  251. {
  252. global $db, $langs, $conf, $user;
  253. global $dolibarr_main_url_root, $dolibarr_main_data_root;
  254. global $website;
  255. global $includehtmlcontentopened;
  256. $nbrep = 0;
  257. dol_syslog("dolWebsiteOutput start - contenttype=".$contenttype." containerid=".$containerid." USEDOLIBARREDITOR=".(defined('USEDOLIBARREDITOR') ? '1' : '')." USEDOLIBARRSERVER=".(defined('USEDOLIBARRSERVER') ? '1' : '').' includehtmlcontentopened='.$includehtmlcontentopened);
  258. //print $containerid.' '.$content;
  259. // Define $urlwithroot
  260. $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
  261. $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  262. //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
  263. if (defined('USEDOLIBARREDITOR')) { // REPLACEMENT OF LINKS When page called from Dolibarr editor
  264. // We remove the <head> part of content
  265. if ($contenttype == 'html') {
  266. $content = preg_replace('/<head>.*<\/head>/ims', '', $content);
  267. $content = preg_replace('/^.*<body(\s[^>]*)*>/ims', '', $content);
  268. $content = preg_replace('/<\/body(\s[^>]*)*>.*$/ims', '', $content);
  269. }
  270. } elseif (defined('USEDOLIBARRSERVER')) { // REPLACEMENT OF LINKS When page called from Dolibarr server
  271. $content = str_replace('<link rel="stylesheet" href="/styles.css', '<link rel="stylesheet" href="styles.css', $content);
  272. // Protect the link styles.css.php to any replacement that we make after.
  273. $content = str_replace('href="styles.css.php', 'href="!~!~!~styles.css.php', $content);
  274. $content = str_replace('href="http', 'href="!~!~!~http', $content);
  275. $content = str_replace('href="//', 'href="!~!~!~//', $content);
  276. $content = str_replace(array('src="viewimage.php', 'src="/viewimage.php'), 'src="!~!~!~/viewimage.php', $content);
  277. $content = str_replace('src="'.DOL_URL_ROOT.'/viewimage.php', 'src="!~!~!~'.DOL_URL_ROOT.'/viewimage.php', $content);
  278. $content = str_replace(array('href="document.php', 'href="/document.php'), 'href="!~!~!~/document.php', $content);
  279. $content = str_replace('href="'.DOL_URL_ROOT.'/document.php', 'href="!~!~!~'.DOL_URL_ROOT.'/document.php', $content);
  280. // Replace relative link / with dolibarr URL: ...href="/"...
  281. $content = preg_replace('/(href=")\/\"/', '\1!~!~!~'.DOL_URL_ROOT.'/public/website/index.php?website='.$website->ref.'"', $content, -1, $nbrep);
  282. // Replace relative link /xxx.php#aaa or /xxx.php with dolibarr URL: ...href="....php" (we discard param ?...)
  283. $content = preg_replace('/(href=")\/?([^:\"\!]*)\.php(#[^\"<>]*)?\"/', '\1!~!~!~'.DOL_URL_ROOT.'/public/website/index.php?website='.$website->ref.'&pageref=\2\3"', $content, -1, $nbrep);
  284. // Replace relative link /xxx.php?a=b&c=d#aaa or /xxx.php?a=b&c=d with dolibarr URL
  285. // Warning: we may replace twice if href="..." was inside an include (dolWebsiteOutput called by include and the by final page), that's why
  286. // at end we replace the '!~!~!~' only if we are in final parent page.
  287. $content = preg_replace('/(href=")\/?([^:\"\!]*)\.php\?([^#\"<>]*)(#[^\"<>]*)?\"/', '\1!~!~!~'.DOL_URL_ROOT.'/public/website/index.php?website='.$website->ref.'&pageref=\2&\3\4"', $content, -1, $nbrep);
  288. // Replace relative link without .php like /xxx#aaa or /xxx with dolibarr URL: ...href="....php"
  289. $content = preg_replace('/(href=")\/?([a-zA-Z0-9\-_#]+)(\"|\?)/', '\1!~!~!~'.DOL_URL_ROOT.'/public/website/index.php?website='.$website->ref.'&pageref=\2\3', $content, -1, $nbrep);
  290. // Fix relative link /document.php with correct URL after the DOL_URL_ROOT: href="/document.php?modulepart=" => href="/dolibarr/document.php?modulepart="
  291. $content = preg_replace('/(href=")(\/?document\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  292. $content = preg_replace('/(src=")(\/?document\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  293. // Fix relative link /viewimage.php with correct URL after the DOL_URL_ROOT: href="/viewimage.php?modulepart=" => href="/dolibarr/viewimage.php?modulepart="
  294. $content = preg_replace('/(href=")(\/?viewimage\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  295. $content = preg_replace('/(src=")(\/?viewimage\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  296. $content = preg_replace('/(url\(")(\/?viewimage\.php\?[^\"]*modulepart=[^\"]*)(\")/', '\1!~!~!~'.DOL_URL_ROOT.'\2\3', $content, -1, $nbrep);
  297. // Fix relative link into medias with correct URL after the DOL_URL_ROOT: ../url("medias/
  298. $content = preg_replace('/url\((["\']?)\/?medias\//', 'url(\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  299. $content = preg_replace('/data-slide-bg=(["\']?)\/?medias\//', 'data-slide-bg=\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  300. // <img src="medias/...image.png... => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png...
  301. // <img src="...image.png... => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png...
  302. $content = preg_replace('/(<img[^>]*src=")\/?medias\//', '\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  303. // <img src="image.png... => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png...
  304. $content = preg_replace('/(<img[^>]*src=")\/?([^:\"\!]+)\"/', '\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=\2"', $content, -1, $nbrep);
  305. // <img src="viewimage.php/modulepart=medias&file=image.png" => <img src="dolibarr/viewimage.php/modulepart=medias&file=image.png"
  306. $content = preg_replace('/(<img[^>]*src=")(\/?viewimage\.php)/', '\1!~!~!~'.DOL_URL_ROOT.'/viewimage.php', $content, -1, $nbrep);
  307. // action="newpage.php" => action="dolibarr/website/index.php?website=...&pageref=newpage
  308. $content = preg_replace('/(action=")\/?([^:\"]*)(\.php\")/', '\1!~!~!~'.DOL_URL_ROOT.'/public/website/index.php?website='.$website->ref.'&pageref=\2"', $content, -1, $nbrep);
  309. // Fix relative URL
  310. $content = str_replace('src="!~!~!~/viewimage.php', 'src="!~!~!~'.DOL_URL_ROOT.'/viewimage.php', $content);
  311. $content = str_replace('href="!~!~!~/document.php', 'href="!~!~!~'.DOL_URL_ROOT.'/document.php', $content);
  312. // Remove the protection tag !~!~!~, but only if this is the parent page and not an include
  313. if (empty($includehtmlcontentopened)) {
  314. $content = str_replace('!~!~!~', '', $content);
  315. }
  316. } else // REPLACEMENT OF LINKS When page called from virtual host web server
  317. {
  318. $symlinktomediaexists = 1;
  319. if ($website->virtualhost) {
  320. $content = preg_replace('/^(<link[^>]*rel="canonical" href=")\//m', '\1'.$website->virtualhost.'/', $content, -1, $nbrep);
  321. }
  322. //print 'rrrrrrrrr'.$website->virtualhost.$content;
  323. // Make a change into HTML code to allow to include images from medias directory correct with direct link for virtual server
  324. // <img alt="" src="/dolibarr_dev/htdocs/viewimage.php?modulepart=medias&amp;entity=1&amp;file=image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
  325. // become
  326. // <img alt="" src="'.$urlwithroot.'/medias/image/ldestailleur_166x166.jpg" style="height:166px; width:166px" />
  327. if (!$symlinktomediaexists) {
  328. // <img src="image.png... => <img src="medias/image.png...
  329. $content = preg_replace('/(<img[^>]*src=")\/?image\//', '\1/wrapper.php?modulepart=medias&file=medias/image/', $content, -1, $nbrep);
  330. $content = preg_replace('/(url\(["\']?)\/?image\//', '\1/wrapper.php?modulepart=medias&file=medias/image/', $content, -1, $nbrep);
  331. $content = preg_replace('/(<script[^>]*src=")[^\"]*document\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2modulepart=medias\3file=\4\5', $content, -1, $nbrep);
  332. $content = preg_replace('/(<a[^>]*href=")[^\"]*document\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2modulepart=medias\3file=\4\5', $content, -1, $nbrep);
  333. $content = preg_replace('/(<a[^>]*href=")[^\"]*viewimage\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2modulepart=medias\3file=\4\5', $content, -1, $nbrep);
  334. $content = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2modulepart=medias\3file=\4\5', $content, -1, $nbrep);
  335. $content = preg_replace('/(url\(["\']?)[^\)]*viewimage\.php([^\)]*)modulepart=medias([^\)]*)file=([^\)]*)(["\']?\))/', '\1/wrapper.php\2modulepart=medias\3file=\4\5', $content, -1, $nbrep);
  336. $content = preg_replace('/(<a[^>]*href=")[^\"]*viewimage\.php([^\"]*)hashp=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2hashp=\3\4', $content, -1, $nbrep);
  337. $content = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php([^\"]*)hashp=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2hashp=\3\4', $content, -1, $nbrep);
  338. $content = preg_replace('/(url\(["\']?)[^\)]*viewimage\.php([^\)]*)hashp=([^\)]*)(["\']?\))/', '\1/wrapper.php\2hashp\3\4', $content, -1, $nbrep);
  339. $content = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php([^\"]*)modulepart=mycompany([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2modulepart=mycompany\3file=\4\5', $content, -1, $nbrep);
  340. // If some links to documents or viewimage remains, we replace with wrapper
  341. $content = preg_replace('/(<img[^>]*src=")\/?viewimage\.php/', '\1/wrapper.php', $content, -1, $nbrep);
  342. $content = preg_replace('/(<a[^>]*href=")\/?documents\.php/', '\1/wrapper.php', $content, -1, $nbrep);
  343. } else {
  344. // <img src="image.png... => <img src="medias/image.png...
  345. $content = preg_replace('/(<img[^>]*src=")\/?image\//', '\1/medias/image/', $content, -1, $nbrep);
  346. $content = preg_replace('/(url\(["\']?)\/?image\//', '\1/medias/image/', $content, -1, $nbrep);
  347. $content = preg_replace('/(<script[^>]*src=")[^\"]*document\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/medias/\4\5', $content, -1, $nbrep);
  348. $content = preg_replace('/(<a[^>]*href=")[^\"]*document\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/medias/\4\5', $content, -1, $nbrep);
  349. $content = preg_replace('/(<a[^>]*href=")[^\"]*viewimage\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/medias/\4\5', $content, -1, $nbrep);
  350. $content = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php([^\"]*)modulepart=medias([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/medias/\4\5', $content, -1, $nbrep);
  351. $content = preg_replace('/(url\(["\']?)[^\)]*viewimage\.php([^\)]*)modulepart=medias([^\)]*)file=([^\)]*)(["\']?\))/', '\1/medias/\4\5', $content, -1, $nbrep);
  352. $content = preg_replace('/(<a[^>]*href=")[^\"]*viewimage\.php([^\"]*)hashp=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2hashp=\3\4', $content, -1, $nbrep);
  353. $content = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php([^\"]*)hashp=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2hashp=\3\4', $content, -1, $nbrep);
  354. $content = preg_replace('/(url\(["\']?)[^\)]*viewimage\.php([^\)]*)hashp=([^\)]*)(["\']?\))/', '\1/wrapper.php\2hashp=\3\4', $content, -1, $nbrep);
  355. $content = preg_replace('/(<img[^>]*src=")[^\"]*viewimage\.php([^\"]*)modulepart=mycompany([^\"]*)file=([^\"]*)("[^>]*>)/', '\1/wrapper.php\2modulepart=mycompany\3file=\4\5', $content, -1, $nbrep);
  356. // If some links to documents or viewimage remains, we replace with wrapper
  357. $content = preg_replace('/(<img[^>]*src=")\/?viewimage\.php/', '\1/wrapper.php', $content, -1, $nbrep);
  358. $content = preg_replace('/(<a[^>]*href=")\/?document\.php/', '\1/wrapper.php', $content, -1, $nbrep);
  359. }
  360. }
  361. if (!defined('USEDOLIBARREDITOR')) {
  362. $content = str_replace(' contenteditable="true"', ' contenteditable="false"', $content);
  363. }
  364. if (!empty($conf->global->WEBSITE_ADD_CSS_TO_BODY)) {
  365. $content = str_replace('<body id="bodywebsite" class="bodywebsite', '<body id="bodywebsite" class="bodywebsite '.$conf->global->WEBSITE_ADD_CSS_TO_BODY, $content);
  366. }
  367. $content = dolReplaceSmileyCodeWithUTF8($content);
  368. dol_syslog("dolWebsiteOutput end");
  369. print $content;
  370. }
  371. /**
  372. * Increase the website counter of page access.
  373. *
  374. * @param int $websiteid ID of website
  375. * @param string $websitepagetype Type of page ('blogpost', 'page', ...)
  376. * @param int $websitepageid ID of page
  377. * @return int <0 if KO, >0 if OK
  378. */
  379. function dolWebsiteIncrementCounter($websiteid, $websitepagetype, $websitepageid)
  380. {
  381. if (!getDolGlobalInt('WEBSITE_PERF_DISABLE_COUNTERS')) {
  382. //dol_syslog("dolWebsiteIncrementCounter websiteid=".$websiteid." websitepagetype=".$websitepagetype." websitepageid=".$websitepageid);
  383. if (in_array($websitepagetype, array('blogpost', 'page'))) {
  384. global $db;
  385. $tmpnow = dol_getdate(dol_now('gmt'), true, 'gmt');
  386. $sql = "UPDATE ".$db->prefix()."website SET ";
  387. $sql .= " pageviews_total = pageviews_total + 1,";
  388. $sql .= " pageviews_month = pageviews_month + 1,";
  389. // if last access was done during previous month, we save pageview_month into pageviews_previous_month
  390. $sql .= " pageviews_previous_month = ".$db->ifsql("lastaccess < '".$db->idate(dol_mktime(0, 0, 0, $tmpnow['mon'], 1, $tmpnow['year'], 'gmt', 0), 'gmt')."'", 'pageviews_month', 'pageviews_previous_month').",";
  391. $sql .= " lastaccess = '".$db->idate(dol_now('gmt'), 'gmt')."'";
  392. $sql .= " WHERE rowid = ".((int) $websiteid);
  393. $resql = $db->query($sql);
  394. if (! $resql) {
  395. return -1;
  396. }
  397. }
  398. }
  399. return 1;
  400. }
  401. /**
  402. * Format img tags to introduce viewimage on img src.
  403. *
  404. * @param string $content Content string
  405. * @return void
  406. * @see dolWebsiteOutput()
  407. */
  408. /*
  409. function dolWebsiteSaveContent($content)
  410. {
  411. global $db, $langs, $conf, $user;
  412. global $dolibarr_main_url_root, $dolibarr_main_data_root;
  413. //dol_syslog("dolWebsiteSaveContent start (mode=".(defined('USEDOLIBARRSERVER')?'USEDOLIBARRSERVER':'').')');
  414. // Define $urlwithroot
  415. $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
  416. $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  417. //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
  418. //$content = preg_replace('/(<img.*src=")(?!(http|'.preg_quote(DOL_URL_ROOT,'/').'\/viewimage))/', '\1'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file=', $content, -1, $nbrep);
  419. return $content;
  420. }
  421. */
  422. /**
  423. * Make a redirect to another container.
  424. *
  425. * @param string $containerref Ref of container to redirect to (Example: 'mypage' or 'mypage.php').
  426. * @param string $containeraliasalt Ref of alternative aliases to redirect to.
  427. * @param int $containerid Id of container.
  428. * @param int $permanent 0=Use temporary redirect 302, 1=Use permanent redirect 301
  429. * @return void
  430. */
  431. function redirectToContainer($containerref, $containeraliasalt = '', $containerid = 0, $permanent = 0)
  432. {
  433. global $db, $website;
  434. $newurl = '';
  435. $result = 0;
  436. // We make redirect using the alternative alias, we must find the real $containerref
  437. if ($containeraliasalt) {
  438. include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
  439. $tmpwebsitepage = new WebsitePage($db);
  440. $result = $tmpwebsitepage->fetch(0, $website->id, '', $containeraliasalt);
  441. if ($result > 0) {
  442. $containerref = $tmpwebsitepage->pageurl;
  443. } else {
  444. print "Error, page contains a redirect to the alternative alias '".$containeraliasalt."' that does not exists in web site (".$website->id." / ".$website->ref.")";
  445. exit;
  446. }
  447. }
  448. if (defined('USEDOLIBARREDITOR')) {
  449. /*print '<div class="margintoponly marginleftonly">';
  450. print "This page contains dynamic code that make a redirect to '".$containerref."' in your current context. Redirect has been canceled as it is not supported in edition mode.";
  451. print '</div>';*/
  452. $text = "This page contains dynamic code that make a redirect to '".$containerref."' in your current context. Redirect has been canceled as it is not supported in edition mode.";
  453. setEventMessages($text, null, 'warnings', 'WEBSITEREDIRECTDISABLED'.$containerref);
  454. return;
  455. }
  456. if (defined('USEDOLIBARRSERVER')) { // When page called from Dolibarr server
  457. // Check new container exists
  458. if (!$containeraliasalt) { // If containeraliasalt set, we already did the test
  459. include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
  460. $tmpwebsitepage = new WebsitePage($db);
  461. $result = $tmpwebsitepage->fetch(0, $website->id, $containerref);
  462. unset($tmpwebsitepage);
  463. }
  464. if ($result > 0) {
  465. $currenturi = $_SERVER["REQUEST_URI"];
  466. $regtmp = array();
  467. if (preg_match('/&pageref=([^&]+)/', $currenturi, $regtmp)) {
  468. if ($regtmp[0] == $containerref) {
  469. print "Error, page with uri '.$currenturi.' try a redirect to the same alias page '".$containerref."' in web site '".$website->ref."'";
  470. exit;
  471. } else {
  472. $newurl = preg_replace('/&pageref=([^&]+)/', '&pageref='.$containerref, $currenturi);
  473. }
  474. } else {
  475. $newurl = $currenturi.'&pageref='.urlencode($containerref);
  476. }
  477. }
  478. } else // When page called from virtual host server
  479. {
  480. $newurl = '/'.$containerref.'.php';
  481. }
  482. if ($newurl) {
  483. if ($permanent) {
  484. header("Status: 301 Moved Permanently", false, 301);
  485. }
  486. header("Location: ".$newurl.(empty($_SERVER["QUERY_STRING"]) ? '' : '?'.$_SERVER["QUERY_STRING"]));
  487. exit;
  488. } else {
  489. print "Error, page contains a redirect to the alias page '".$containerref."' that does not exists in web site (".$website->id." / ".$website->ref.")";
  490. exit;
  491. }
  492. }
  493. /**
  494. * Clean an HTML page to report only content, so we can include it into another page.
  495. * It outputs content of file sanitized from html and body part.
  496. *
  497. * @param string $containerref Path to file to include (must be a page from website root. Example: 'mypage.php' means 'mywebsite/mypage.php')
  498. * @return void
  499. */
  500. function includeContainer($containerref)
  501. {
  502. global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $websitepage, $weblangs; // Very important. Required to have var available when running included containers.
  503. global $includehtmlcontentopened;
  504. global $websitekey, $websitepagefile;
  505. $MAXLEVEL = 20;
  506. if (!preg_match('/\.php$/i', $containerref)) {
  507. $containerref .= '.php';
  508. }
  509. $fullpathfile = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/'.$websitekey.'/'.$containerref;
  510. if (empty($includehtmlcontentopened)) {
  511. $includehtmlcontentopened = 0;
  512. }
  513. $includehtmlcontentopened++;
  514. if ($includehtmlcontentopened > $MAXLEVEL) {
  515. print 'ERROR: RECURSIVE CONTENT LEVEL. Depth of recursive call is more than the limit of '.((int) $MAXLEVEL).".\n";
  516. return;
  517. }
  518. //dol_syslog("Include container ".$containerref.' includehtmlcontentopened='.$includehtmlcontentopened);
  519. // file_get_contents is not possible. We must execute code with include
  520. //$content = file_get_contents($fullpathfile);
  521. //print preg_replace(array('/^.*<body[^>]*>/ims','/<\/body>.*$/ims'), array('', ''), $content);*/
  522. ob_start();
  523. $res = include $fullpathfile; // Include because we want to execute code content
  524. $tmpoutput = ob_get_contents();
  525. ob_end_clean();
  526. print "\n".'<!-- include '.$websitekey.'/'.$containerref.(is_object($websitepage) ? ' parent id='.$websitepage->id : '').' level = '.$includehtmlcontentopened.' -->'."\n";
  527. print preg_replace(array('/^.*<body[^>]*>/ims', '/<\/body>.*$/ims'), array('', ''), $tmpoutput);
  528. if (!$res) {
  529. print 'ERROR: FAILED TO INCLUDE PAGE '.$containerref.".\n";
  530. }
  531. $includehtmlcontentopened--;
  532. }
  533. /**
  534. * Return HTML content to add structured data for an article, news or Blog Post. Use the json-ld format.
  535. * Example:
  536. * <?php getStructureData('blogpost'); ?>
  537. * <?php getStructureData('software', array('name'=>'Name', 'os'=>'Windows', 'price'=>10)); ?>
  538. *
  539. * @param string $type 'blogpost', 'product', 'software', 'organization', 'qa', ...
  540. * @param array $data Array of data parameters for structured data
  541. * @return string HTML content
  542. */
  543. function getStructuredData($type, $data = array())
  544. {
  545. global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $websitepage, $weblangs, $pagelangs; // Very important. Required to have var available when running inluded containers.
  546. $type = strtolower($type);
  547. if ($type == 'software') {
  548. $ret = '<!-- Add structured data for entry in a software annuary -->'."\n";
  549. $ret .= '<script nonce="'.getNonce().'" type="application/ld+json">'."\n";
  550. $ret .= '{
  551. "@context": "https://schema.org",
  552. "@type": "SoftwareApplication",
  553. "name": "'.dol_escape_json($data['name']).'",
  554. "operatingSystem": "'.dol_escape_json($data['os']).'",
  555. "applicationCategory": "https://schema.org/'.dol_escape_json($data['applicationCategory']).'",';
  556. if (!empty($data['ratingcount'])) {
  557. $ret .= '
  558. "aggregateRating": {
  559. "@type": "AggregateRating",
  560. "ratingValue": "'.dol_escape_json($data['ratingvalue']).'",
  561. "ratingCount": "'.dol_escape_json($data['ratingcount']).'"
  562. },';
  563. }
  564. $ret .= '
  565. "offers": {
  566. "@type": "Offer",
  567. "price": "'.dol_escape_json($data['price']).'",
  568. "priceCurrency": "'.dol_escape_json($data['currency'] ? $data['currency'] : $conf->currency).'"
  569. }
  570. }'."\n";
  571. $ret .= '</script>'."\n";
  572. } elseif ($type == 'organization') {
  573. $companyname = $mysoc->name;
  574. $url = $mysoc->url;
  575. $ret = '<!-- Add structured data for organization -->'."\n";
  576. $ret .= '<script nonce="'.getNonce().'" type="application/ld+json">'."\n";
  577. $ret .= '{
  578. "@context": "https://schema.org",
  579. "@type": "Organization",
  580. "name": "'.dol_escape_json($data['name'] ? $data['name'] : $companyname).'",
  581. "url": "'.dol_escape_json($data['url'] ? $data['url'] : $url).'",
  582. "logo": "'.($data['logo'] ? dol_escape_json($data['logo']) : '/wrapper.php?modulepart=mycompany&file=logos%2F'.urlencode($mysoc->logo)).'",
  583. "contactPoint": {
  584. "@type": "ContactPoint",
  585. "contactType": "Contact",
  586. "email": "'.dol_escape_json($data['email'] ? $data['email'] : $mysoc->email).'"
  587. }'."\n";
  588. if (is_array($mysoc->socialnetworks) && count($mysoc->socialnetworks) > 0) {
  589. $ret .= ",\n";
  590. $ret .= '"sameAs": [';
  591. $i = 0;
  592. foreach ($mysoc->socialnetworks as $key => $value) {
  593. if ($key == 'linkedin') {
  594. $ret .= '"https://www.'.$key.'.com/company/'.dol_escape_json($value).'"';
  595. } elseif ($key == 'youtube') {
  596. $ret .= '"https://www.'.$key.'.com/user/'.dol_escape_json($value).'"';
  597. } else {
  598. $ret .= '"https://www.'.$key.'.com/'.dol_escape_json($value).'"';
  599. }
  600. $i++;
  601. if ($i < count($mysoc->socialnetworks)) {
  602. $ret .= ', ';
  603. }
  604. }
  605. $ret .= ']'."\n";
  606. }
  607. $ret .= '}'."\n";
  608. $ret .= '</script>'."\n";
  609. } elseif ($type == 'blogpost') {
  610. if (!empty($websitepage->author_alias)) {
  611. //include_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
  612. //$tmpuser = new User($db);
  613. //$restmpuser = $tmpuser->fetch($websitepage->fk_user_creat);
  614. $pageurl = $websitepage->pageurl;
  615. $title = $websitepage->title;
  616. $image = $websitepage->image;
  617. $companyname = $mysoc->name;
  618. $description = $websitepage->description;
  619. $pageurl = str_replace('__WEBSITE_KEY__', $website->ref, $pageurl);
  620. $title = str_replace('__WEBSITE_KEY__', $website->ref, $title);
  621. $image = '/medias'.(preg_match('/^\//', $image) ? '' : '/').str_replace('__WEBSITE_KEY__', $website->ref, $image);
  622. $companyname = str_replace('__WEBSITE_KEY__', $website->ref, $companyname);
  623. $description = str_replace('__WEBSITE_KEY__', $website->ref, $description);
  624. $ret = '<!-- Add structured data for blog post -->'."\n";
  625. $ret .= '<script nonce="'.getNonce().'" type="application/ld+json">'."\n";
  626. $ret .= '{
  627. "@context": "https://schema.org",
  628. "@type": "NewsArticle",
  629. "mainEntityOfPage": {
  630. "@type": "WebPage",
  631. "@id": "'.dol_escape_json($pageurl).'"
  632. },
  633. "headline": "'.dol_escape_json($title).'",
  634. "image": [
  635. "'.dol_escape_json($image).'"
  636. ],
  637. "dateCreated": "'.dol_print_date($websitepage->date_creation, 'dayhourrfc').'",
  638. "datePublished": "'.dol_print_date($websitepage->date_creation, 'dayhourrfc').'",
  639. "dateModified": "'.dol_print_date($websitepage->date_modification, 'dayhourrfc').'",
  640. "author": {
  641. "@type": "Person",
  642. "name": "'.dol_escape_json($websitepage->author_alias).'"
  643. },
  644. "publisher": {
  645. "@type": "Organization",
  646. "name": "'.dol_escape_json($companyname).'",
  647. "logo": {
  648. "@type": "ImageObject",
  649. "url": "/wrapper.php?modulepart=mycompany&file=logos%2F'.urlencode($mysoc->logo).'"
  650. }
  651. },'."\n";
  652. if ($websitepage->keywords) {
  653. $ret .= '"keywords": [';
  654. $i = 0;
  655. $arrayofkeywords = explode(',', $websitepage->keywords);
  656. foreach ($arrayofkeywords as $keyword) {
  657. $ret .= '"'.dol_escape_json($keyword).'"';
  658. $i++;
  659. if ($i < count($arrayofkeywords)) {
  660. $ret .= ', ';
  661. }
  662. }
  663. $ret .= '],'."\n";
  664. }
  665. $ret .= '"description": "'.dol_escape_json($description).'"';
  666. $ret .= "\n".'}'."\n";
  667. $ret .= '</script>'."\n";
  668. } else {
  669. $ret = '<!-- no structured data inserted inline inside blogpost because no author_alias defined -->'."\n";
  670. }
  671. } elseif ($type == 'product') {
  672. $ret = '<!-- Add structured data for product -->'."\n";
  673. $ret .= '<script nonce="'.getNonce().'" type="application/ld+json">'."\n";
  674. $ret .= '{
  675. "@context": "https://schema.org/",
  676. "@type": "Product",
  677. "name": "'.dol_escape_json($data['label']).'",
  678. "image": [
  679. "'.dol_escape_json($data['image']).'",
  680. ],
  681. "description": "'.dol_escape_json($data['description']).'",
  682. "sku": "'.dol_escape_json($data['ref']).'",
  683. "brand": {
  684. "@type": "Thing",
  685. "name": "'.dol_escape_json($data['brand']).'"
  686. },
  687. "author": {
  688. "@type": "Person",
  689. "name": "'.dol_escape_json($data['author']).'"
  690. }
  691. },
  692. "offers": {
  693. "@type": "Offer",
  694. "url": "https://example.com/anvil",
  695. "priceCurrency": "'.dol_escape_json($data['currency'] ? $data['currency'] : $conf->currency).'",
  696. "price": "'.dol_escape_json($data['price']).'",
  697. "itemCondition": "https://schema.org/UsedCondition",
  698. "availability": "https://schema.org/InStock",
  699. "seller": {
  700. "@type": "Organization",
  701. "name": "'.dol_escape_json($mysoc->name).'"
  702. }
  703. }
  704. }'."\n";
  705. $ret .= '</script>'."\n";
  706. } elseif ($type == 'qa') {
  707. $ret = '<!-- Add structured data for QA -->'."\n";
  708. $ret .= '<script nonce="'.getNonce().'" type="application/ld+json">'."\n";
  709. $ret .= '{
  710. "@context": "https://schema.org/",
  711. "@type": "QAPage",
  712. "mainEntity": {
  713. "@type": "Question",
  714. "name": "'.dol_escape_json($data['name']).'",
  715. "text": "'.dol_escape_json($data['name']).'",
  716. "answerCount": 1,
  717. "author": {
  718. "@type": "Person",
  719. "name": "'.dol_escape_json($data['author']).'"
  720. }
  721. "acceptedAnswer": {
  722. "@type": "Answer",
  723. "text": "'.dol_escape_json(dol_string_nohtmltag(dolStripPhpCode($data['description']))).'",
  724. "author": {
  725. "@type": "Person",
  726. "name": "'.dol_escape_json($data['author']).'"
  727. }
  728. }
  729. }
  730. }'."\n";
  731. $ret .= '</script>'."\n";
  732. }
  733. return $ret;
  734. }
  735. /**
  736. * Return HTML content to add as header card for an article, news or Blog Post or home page.
  737. *
  738. * @param array $params Array of parameters
  739. * @return string HTML content
  740. */
  741. function getSocialNetworkHeaderCards($params = null)
  742. {
  743. global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $websitepage, $weblangs; // Very important. Required to have var available when running inluded containers.
  744. $out = '';
  745. if ($website->virtualhost) {
  746. $pageurl = $websitepage->pageurl;
  747. $title = $websitepage->title;
  748. $image = $websitepage->image;
  749. $companyname = $mysoc->name;
  750. $description = $websitepage->description;
  751. $pageurl = str_replace('__WEBSITE_KEY__', $website->ref, $pageurl);
  752. $title = str_replace('__WEBSITE_KEY__', $website->ref, $title);
  753. $image = '/medias'.(preg_match('/^\//', $image) ? '' : '/').str_replace('__WEBSITE_KEY__', $website->ref, $image);
  754. $companyname = str_replace('__WEBSITE_KEY__', $website->ref, $companyname);
  755. $description = str_replace('__WEBSITE_KEY__', $website->ref, $description);
  756. $shortlangcode = '';
  757. if ($websitepage->lang) {
  758. $shortlangcode = substr($websitepage->lang, 0, 2); // en_US or en-US -> en
  759. }
  760. if (empty($shortlangcode)) {
  761. $shortlangcode = substr($website->lang, 0, 2); // en_US or en-US -> en
  762. }
  763. $fullurl = $website->virtualhost.'/'.$websitepage->pageurl.'.php';
  764. $canonicalurl = $website->virtualhost.(($websitepage->id == $website->fk_default_home) ? '/' : (($shortlangcode != substr($website->lang, 0, 2) ? '/'.$shortlangcode : '').'/'.$websitepage->pageurl.'.php'));
  765. $hashtags = trim(join(' #', array_map('trim', explode(',', $websitepage->keywords))));
  766. // Open Graph
  767. $out .= '<meta name="og:type" content="website">'."\n"; // TODO If blogpost, use type article
  768. $out .= '<meta name="og:title" content="'.$websitepage->title.'">'."\n";
  769. if ($websitepage->image) {
  770. $out .= '<meta name="og:image" content="'.$website->virtualhost.$image.'">'."\n";
  771. }
  772. $out .= '<meta name="og:url" content="'.$canonicalurl.'">'."\n";
  773. // Twitter
  774. $out .= '<meta name="twitter:card" content="summary">'."\n";
  775. if (!empty($params) && !empty($params['twitter_account'])) {
  776. $out .= '<meta name="twitter:site" content="@'.$params['twitter_account'].'">'."\n";
  777. $out .= '<meta name="twitter:creator" content="@'.$params['twitter_account'].'">'."\n";
  778. }
  779. $out .= '<meta name="twitter:title" content="'.$websitepage->title.'">'."\n";
  780. if ($websitepage->description) {
  781. $out .= '<meta name="twitter:description" content="'.$websitepage->description.'">'."\n";
  782. }
  783. if ($websitepage->image) {
  784. $out .= '<meta name="twitter:image" content="'.$website->virtualhost.$image.'">'."\n";
  785. }
  786. //$out .= '<meta name="twitter:domain" content="'.getDomainFromURL($website->virtualhost, 1).'">';
  787. /*
  788. $out .= '<meta name="twitter:app:name:iphone" content="">';
  789. $out .= '<meta name="twitter:app:name:ipad" content="">';
  790. $out .= '<meta name="twitter:app:name:googleplay" content="">';
  791. $out .= '<meta name="twitter:app:url:iphone" content="">';
  792. $out .= '<meta name="twitter:app:url:ipad" content="">';
  793. $out .= '<meta name="twitter:app:url:googleplay" content="">';
  794. $out .= '<meta name="twitter:app:id:iphone" content="">';
  795. $out .= '<meta name="twitter:app:id:ipad" content="">';
  796. $out .= '<meta name="twitter:app:id:googleplay" content="">';
  797. */
  798. }
  799. return $out;
  800. }
  801. /**
  802. * Return HTML content to add structured data for an article, news or Blog Post.
  803. *
  804. * @return string HTML content
  805. */
  806. function getSocialNetworkSharingLinks()
  807. {
  808. global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $websitepage, $weblangs; // Very important. Required to have var available when running inluded containers.
  809. $out = '<!-- section for social network sharing of page -->'."\n";
  810. if ($website->virtualhost) {
  811. $fullurl = $website->virtualhost.'/'.$websitepage->pageurl.'.php';
  812. $hashtags = trim(join(' #', array_map('trim', explode(',', $websitepage->keywords))));
  813. $out .= '<div class="dol-social-share">'."\n";
  814. // Twitter
  815. $out .= '<div class="dol-social-share-tw">'."\n";
  816. $out .= '<a href="https://twitter.com/share" class="twitter-share-button" data-url="'.$fullurl.'" data-text="'.dol_escape_htmltag($websitepage->description).'" data-lang="'.$websitepage->lang.'" data-size="small" data-related="" data-hashtags="'.preg_replace('/^#/', '', $hashtags).'" data-count="horizontal">Tweet</a>';
  817. $out .= '<script nonce="'.getNonce().'">!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?\'http\':\'https\';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+\'://platform.twitter.com/widgets.js\';fjs.parentNode.insertBefore(js,fjs);}}(document, \'script\', \'twitter-wjs\');</script>';
  818. $out .= '</div>'."\n";
  819. // Reddit
  820. $out .= '<div class="dol-social-share-reddit">'."\n";
  821. $out .= '<a href="https://www.reddit.com/submit" target="_blank" rel="noopener noreferrer external" onclick="window.location = \'https://www.reddit.com/submit?url='.$fullurl.'\'; return false">';
  822. $out .= '<span class="dol-social-share-reddit-span">Reddit</span>';
  823. $out .= '</a>';
  824. $out .= '</div>'."\n";
  825. // Facebook
  826. $out .= '<div class="dol-social-share-fbl">'."\n";
  827. $out .= '<div id="fb-root"></div>'."\n";
  828. $out .= '<script nonce="'.getNonce().'">(function(d, s, id) {
  829. var js, fjs = d.getElementsByTagName(s)[0];
  830. if (d.getElementById(id)) return;
  831. js = d.createElement(s); js.id = id;
  832. js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.0&amp;appId=dolibarr.org";
  833. fjs.parentNode.insertBefore(js, fjs);
  834. }(document, \'script\', \'facebook-jssdk\'));</script>
  835. <fb:like
  836. href="'.$fullurl.'"
  837. layout="button_count"
  838. show_faces="false"
  839. width="90"
  840. colorscheme="light"
  841. share="1"
  842. action="like" ></fb:like>'."\n";
  843. $out .= '</div>'."\n";
  844. $out .= "\n</div>\n";
  845. } else {
  846. $out .= '<!-- virtual host not defined in CMS. No way to add sharing buttons -->'."\n";
  847. }
  848. $out .= '<!-- section end for social network sharing of page -->'."\n";
  849. return $out;
  850. }
  851. /**
  852. * Return list of containers object that match a criteria.
  853. * WARNING: This function can be used by websites.
  854. *
  855. * @param string $type Type of container to search into (Example: '', 'page', 'blogpost', 'page,blogpost', ...)
  856. * @param string $algo Algorithm used for search (Example: 'meta' is searching into meta information like title and description, 'content', 'sitefiles', or any combination 'meta,content,...')
  857. * @param string $searchstring Search string
  858. * @param int $max Max number of answers
  859. * @param string $sortfield Sort Fields
  860. * @param string $sortorder Sort order ('DESC' or 'ASC')
  861. * @param string $langcode Language code ('' or 'en', 'fr', 'es', ...)
  862. * @param array $otherfilters Other filters
  863. * @param int $status 0 or 1, or -1 for both
  864. * @return array Array with results of search
  865. */
  866. function getPagesFromSearchCriterias($type, $algo, $searchstring, $max = 25, $sortfield = 'date_creation', $sortorder = 'DESC', $langcode = '', $otherfilters = 'null', $status = 1)
  867. {
  868. global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $websitepage, $weblangs; // Very important. Required to have var available when running inluded containers.
  869. $error = 0;
  870. $arrayresult = array('code'=>'', 'list'=>array());
  871. if (!is_object($weblangs)) {
  872. $weblangs = $langs;
  873. }
  874. if (empty($searchstring) && empty($type) && empty($langcode) && empty($otherfilters)) {
  875. $error++;
  876. $arrayresult['code'] = 'KO';
  877. $arrayresult['message'] = $weblangs->trans("EmptySearchString");
  878. } elseif ($searchstring && dol_strlen($searchstring) < 2) {
  879. $weblangs->load("errors");
  880. $error++;
  881. $arrayresult['code'] = 'KO';
  882. $arrayresult['message'] = $weblangs->trans("ErrorSearchCriteriaTooSmall");
  883. } else {
  884. $tmparrayoftype = explode(',', $type);
  885. /*foreach ($tmparrayoftype as $tmptype) {
  886. if (!in_array($tmptype, array('', 'page', 'blogpost'))) {
  887. $error++;
  888. $arrayresult['code'] = 'KO';
  889. $arrayresult['message'] = 'Bad value for parameter type';
  890. break;
  891. }
  892. }*/
  893. }
  894. $searchdone = 0;
  895. $found = 0;
  896. if (!$error && (empty($max) || ($found < $max)) && (preg_match('/meta/', $algo) || preg_match('/content/', $algo))) {
  897. include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
  898. $sql = 'SELECT wp.rowid FROM '.MAIN_DB_PREFIX.'website_page as wp';
  899. if (is_array($otherfilters) && !empty($otherfilters['category'])) {
  900. $sql .= ', '.MAIN_DB_PREFIX.'categorie_website_page as cwp';
  901. }
  902. $sql .= " WHERE wp.fk_website = ".((int) $website->id);
  903. if ($status >= 0) {
  904. $sql .= " AND wp.status = ".((int) $status);
  905. }
  906. if ($langcode) {
  907. $sql .= " AND wp.lang = '".$db->escape($langcode)."'";
  908. }
  909. if ($type) {
  910. $tmparrayoftype = explode(',', $type);
  911. $typestring = '';
  912. foreach ($tmparrayoftype as $tmptype) {
  913. $typestring .= ($typestring ? ", " : "")."'".$db->escape(trim($tmptype))."'";
  914. }
  915. $sql .= " AND wp.type_container IN (".$db->sanitize($typestring, 1).")";
  916. }
  917. $sql .= " AND (";
  918. $searchalgo = '';
  919. if (preg_match('/meta/', $algo)) {
  920. $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.title LIKE '%".$db->escape($db->escapeforlike($searchstring))."%' OR wp.description LIKE '%".$db->escape($db->escapeforlike($searchstring))."%'";
  921. $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.keywords LIKE '".$db->escape($db->escapeforlike($searchstring)).",%' OR wp.keywords LIKE '% ".$db->escape($db->escapeforlike($searchstring))."%'"; // TODO Use a better way to scan keywords
  922. }
  923. if (preg_match('/content/', $algo)) {
  924. $searchalgo .= ($searchalgo ? ' OR ' : '')."wp.content LIKE '%".$db->escape($db->escapeforlike($searchstring))."%'";
  925. }
  926. $sql .= $searchalgo;
  927. if (is_array($otherfilters) && !empty($otherfilters['category'])) {
  928. $sql .= ' AND cwp.fk_website_page = wp.rowid AND cwp.fk_categorie = '.((int) $otherfilters['category']);
  929. }
  930. $sql .= ")";
  931. $sql .= $db->order($sortfield, $sortorder);
  932. $sql .= $db->plimit($max);
  933. //print $sql;
  934. $resql = $db->query($sql);
  935. if ($resql) {
  936. $i = 0;
  937. while (($obj = $db->fetch_object($resql)) && ($i < $max || $max == 0)) {
  938. if ($obj->rowid > 0) {
  939. $tmpwebsitepage = new WebsitePage($db);
  940. $tmpwebsitepage->fetch($obj->rowid);
  941. if ($tmpwebsitepage->id > 0) {
  942. $arrayresult['list'][$obj->rowid] = $tmpwebsitepage;
  943. }
  944. $found++;
  945. }
  946. $i++;
  947. }
  948. } else {
  949. $error++;
  950. $arrayresult['code'] = $db->lasterrno();
  951. $arrayresult['message'] = $db->lasterror();
  952. }
  953. $searchdone = 1;
  954. }
  955. if (!$error && (empty($max) || ($found < $max)) && (preg_match('/sitefiles/', $algo))) {
  956. global $dolibarr_main_data_root;
  957. $pathofwebsite = $dolibarr_main_data_root.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/'.$website->ref;
  958. $filehtmlheader = $pathofwebsite.'/htmlheader.html';
  959. $filecss = $pathofwebsite.'/styles.css.php';
  960. $filejs = $pathofwebsite.'/javascript.js.php';
  961. $filerobot = $pathofwebsite.'/robots.txt';
  962. $filehtaccess = $pathofwebsite.'/.htaccess';
  963. $filemanifestjson = $pathofwebsite.'/manifest.json.php';
  964. $filereadme = $pathofwebsite.'/README.md';
  965. $filecontent = file_get_contents($filehtmlheader);
  966. if ((empty($max) || ($found < $max)) && preg_match('/'.preg_quote($searchstring, '/').'/', $filecontent)) {
  967. $arrayresult['list'][] = array('type'=>'website_htmlheadercontent');
  968. }
  969. $filecontent = file_get_contents($filecss);
  970. if ((empty($max) || ($found < $max)) && preg_match('/'.preg_quote($searchstring, '/').'/', $filecontent)) {
  971. $arrayresult['list'][] = array('type'=>'website_csscontent');
  972. }
  973. $filecontent = file_get_contents($filejs);
  974. if ((empty($max) || ($found < $max)) && preg_match('/'.preg_quote($searchstring, '/').'/', $filecontent)) {
  975. $arrayresult['list'][] = array('type'=>'website_jscontent');
  976. }
  977. $filerobot = file_get_contents($filerobot);
  978. if ((empty($max) || ($found < $max)) && preg_match('/'.preg_quote($searchstring, '/').'/', $filecontent)) {
  979. $arrayresult['list'][] = array('type'=>'website_robotcontent');
  980. }
  981. $searchdone = 1;
  982. }
  983. if (!$error) {
  984. if ($searchdone) {
  985. $arrayresult['code'] = 'OK';
  986. if (empty($arrayresult['list'])) {
  987. $arrayresult['code'] = 'KO';
  988. $arrayresult['message'] = $weblangs->trans("NoRecordFound");
  989. }
  990. } else {
  991. $error++;
  992. $arrayresult['code'] = 'KO';
  993. $arrayresult['message'] = 'No supported algorithm found';
  994. }
  995. }
  996. return $arrayresult;
  997. }
  998. /**
  999. * Download all images found into page content $tmp.
  1000. * If $modifylinks is set, links to images will be replace with a link to viewimage wrapper.
  1001. *
  1002. * @param Website $object Object website
  1003. * @param WebsitePage $objectpage Object website page
  1004. * @param string $urltograb URL to grab (exemple: http://www.nltechno.com/ or http://www.nltechno.com/dir1/ or http://www.nltechno.com/dir1/mapage1)
  1005. * @param string $tmp Content to parse
  1006. * @param string $action Var $action
  1007. * @param string $modifylinks 0=Do not modify content, 1=Replace links with a link to viewimage
  1008. * @param int $grabimages 0=Do not grab images, 1=Grab images
  1009. * @param string $grabimagesinto 'root' or 'subpage'
  1010. * @return void
  1011. */
  1012. function getAllImages($object, $objectpage, $urltograb, &$tmp, &$action, $modifylinks = 0, $grabimages = 1, $grabimagesinto = 'subpage')
  1013. {
  1014. global $conf;
  1015. $error = 0;
  1016. dol_syslog("Call getAllImages with grabimagesinto=".$grabimagesinto);
  1017. $alreadygrabbed = array();
  1018. if (preg_match('/\/$/', $urltograb)) {
  1019. $urltograb .= '.';
  1020. }
  1021. $urltograb = dirname($urltograb); // So urltograb is now http://www.nltechno.com or http://www.nltechno.com/dir1
  1022. // Search X in "img...src=X"
  1023. $regs = array();
  1024. preg_match_all('/<img([^\.\/]+)src="([^>"]+)"([^>]*)>/i', $tmp, $regs);
  1025. foreach ($regs[0] as $key => $val) {
  1026. if (preg_match('/^data:image/i', $regs[2][$key])) {
  1027. continue; // We do nothing for such images
  1028. }
  1029. if (preg_match('/^\//', $regs[2][$key])) {
  1030. $urltograbdirrootwithoutslash = getRootURLFromURL($urltograb);
  1031. $urltograbbis = $urltograbdirrootwithoutslash.$regs[2][$key]; // We use dirroot
  1032. } else {
  1033. $urltograbbis = $urltograb.'/'.$regs[2][$key]; // We use dir of grabbed file
  1034. }
  1035. $linkwithoutdomain = $regs[2][$key];
  1036. $dirforimages = '/'.$objectpage->pageurl;
  1037. if ($grabimagesinto == 'root') {
  1038. $dirforimages = '';
  1039. }
  1040. // Define $filetosave and $filename
  1041. $filetosave = $conf->medias->multidir_output[$conf->entity].'/image/'.$object->ref.$dirforimages.(preg_match('/^\//', $regs[2][$key]) ? '' : '/').$regs[2][$key];
  1042. if (preg_match('/^http/', $regs[2][$key])) {
  1043. $urltograbbis = $regs[2][$key];
  1044. $linkwithoutdomain = preg_replace('/^https?:\/\/[^\/]+\//i', '', $regs[2][$key]);
  1045. $filetosave = $conf->medias->multidir_output[$conf->entity].'/image/'.$object->ref.$dirforimages.(preg_match('/^\//', $linkwithoutdomain) ? '' : '/').$linkwithoutdomain;
  1046. }
  1047. $filename = 'image/'.$object->ref.$dirforimages.(preg_match('/^\//', $linkwithoutdomain) ? '' : '/').$linkwithoutdomain;
  1048. // Clean the aa/bb/../cc into aa/cc
  1049. $filetosave = preg_replace('/\/[^\/]+\/\.\./', '', $filetosave);
  1050. $filename = preg_replace('/\/[^\/]+\/\.\./', '', $filename);
  1051. //var_dump($filetosave);
  1052. //var_dump($filename);
  1053. //exit;
  1054. if (empty($alreadygrabbed[$urltograbbis])) {
  1055. if ($grabimages) {
  1056. $tmpgeturl = getURLContent($urltograbbis, 'GET', '', 1, array(), array('http', 'https'), 0);
  1057. if ($tmpgeturl['curl_error_no']) {
  1058. $error++;
  1059. setEventMessages('Error getting '.$urltograbbis.': '.$tmpgeturl['curl_error_msg'], null, 'errors');
  1060. $action = 'create';
  1061. } elseif ($tmpgeturl['http_code'] != '200') {
  1062. $error++;
  1063. setEventMessages('Error getting '.$urltograbbis.': '.$tmpgeturl['http_code'], null, 'errors');
  1064. $action = 'create';
  1065. } else {
  1066. $alreadygrabbed[$urltograbbis] = 1; // Track that file was alreay grabbed.
  1067. dol_mkdir(dirname($filetosave));
  1068. $fp = fopen($filetosave, "w");
  1069. fputs($fp, $tmpgeturl['content']);
  1070. fclose($fp);
  1071. dolChmod($filetosave);
  1072. }
  1073. }
  1074. }
  1075. if ($modifylinks) {
  1076. $tmp = preg_replace('/'.preg_quote($regs[0][$key], '/').'/i', '<img'.$regs[1][$key].'src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file='.$filename.'"'.$regs[3][$key].'>', $tmp);
  1077. }
  1078. }
  1079. // Search X in "background...url(X)"
  1080. preg_match_all('/background([^\.\/\(;]+)url\([\"\']?([^\)\"\']*)[\"\']?\)/i', $tmp, $regs);
  1081. foreach ($regs[0] as $key => $val) {
  1082. if (preg_match('/^data:image/i', $regs[2][$key])) {
  1083. continue; // We do nothing for such images
  1084. }
  1085. if (preg_match('/^\//', $regs[2][$key])) {
  1086. $urltograbdirrootwithoutslash = getRootURLFromURL($urltograb);
  1087. $urltograbbis = $urltograbdirrootwithoutslash.$regs[2][$key]; // We use dirroot
  1088. } else {
  1089. $urltograbbis = $urltograb.'/'.$regs[2][$key]; // We use dir of grabbed file
  1090. }
  1091. $linkwithoutdomain = $regs[2][$key];
  1092. $dirforimages = '/'.$objectpage->pageurl;
  1093. if ($grabimagesinto == 'root') {
  1094. $dirforimages = '';
  1095. }
  1096. $filetosave = $conf->medias->multidir_output[$conf->entity].'/image/'.$object->ref.$dirforimages.(preg_match('/^\//', $regs[2][$key]) ? '' : '/').$regs[2][$key];
  1097. if (preg_match('/^http/', $regs[2][$key])) {
  1098. $urltograbbis = $regs[2][$key];
  1099. $linkwithoutdomain = preg_replace('/^https?:\/\/[^\/]+\//i', '', $regs[2][$key]);
  1100. $filetosave = $conf->medias->multidir_output[$conf->entity].'/image/'.$object->ref.$dirforimages.(preg_match('/^\//', $linkwithoutdomain) ? '' : '/').$linkwithoutdomain;
  1101. }
  1102. $filename = 'image/'.$object->ref.$dirforimages.(preg_match('/^\//', $linkwithoutdomain) ? '' : '/').$linkwithoutdomain;
  1103. // Clean the aa/bb/../cc into aa/cc
  1104. $filetosave = preg_replace('/\/[^\/]+\/\.\./', '', $filetosave);
  1105. $filename = preg_replace('/\/[^\/]+\/\.\./', '', $filename);
  1106. //var_dump($filetosave);
  1107. //var_dump($filename);
  1108. //exit;
  1109. if (empty($alreadygrabbed[$urltograbbis])) {
  1110. if ($grabimages) {
  1111. $tmpgeturl = getURLContent($urltograbbis, 'GET', '', 1, array(), array('http', 'https'), 0);
  1112. if ($tmpgeturl['curl_error_no']) {
  1113. $error++;
  1114. setEventMessages('Error getting '.$urltograbbis.': '.$tmpgeturl['curl_error_msg'], null, 'errors');
  1115. $action = 'create';
  1116. } elseif ($tmpgeturl['http_code'] != '200') {
  1117. $error++;
  1118. setEventMessages('Error getting '.$urltograbbis.': '.$tmpgeturl['http_code'], null, 'errors');
  1119. $action = 'create';
  1120. } else {
  1121. $alreadygrabbed[$urltograbbis] = 1; // Track that file was alreay grabbed.
  1122. dol_mkdir(dirname($filetosave));
  1123. $fp = fopen($filetosave, "w");
  1124. fputs($fp, $tmpgeturl['content']);
  1125. fclose($fp);
  1126. dolChmod($filetosave);
  1127. }
  1128. }
  1129. }
  1130. if ($modifylinks) {
  1131. $tmp = preg_replace('/'.preg_quote($regs[0][$key], '/').'/i', 'background'.$regs[1][$key].'url("'.DOL_URL_ROOT.'/viewimage.php?modulepart=medias&file='.$filename.'")', $tmp);
  1132. }
  1133. }
  1134. }