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