1<?php
2/**
3 * @package tikiwiki
4 */
5// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
6//
7// All Rights Reserved. See copyright.txt for details and a complete list of authors.
8// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
9// $Id$
10
11$inputConfiguration = [
12	[ 'staticKeyFilters' => [
13				'searchtext' => 'xss',
14				'replacetext' => 'xss',
15				'maxRecords' => 'digits',
16				'offset' => 'digits',
17				'paddingLength' => 'digits',
18		]
19	]
20];
21
22require_once('tiki-setup.php');
23
24$wikilib = TikiLib::lib('wiki');
25
26$access->check_feature(['feature_wiki']);
27$access->check_permission(['tiki_p_admin_wiki']);
28
29// Search input
30$searchtext = '';
31$replacetext = '';
32if (! empty($_REQUEST['replacetext'])) {
33	$replacetext = $_REQUEST['replacetext'];
34} else {
35	$replacetext = '';
36}
37if (! empty($_REQUEST['searchtext'])) {
38	$searchtext = $_REQUEST['searchtext'];
39}
40if (! isset($_REQUEST["offset"])) {
41	$offset = 0;
42} else {
43	$offset = $_REQUEST["offset"];
44}
45$smarty->assign('offset', $offset);
46
47if (! empty($_REQUEST['categId'])) {
48	$categFilter = [$_REQUEST['categId']];
49	$smarty->assign('find_categId', $_REQUEST['categId']);
50} else {
51	$categFilter = [];
52	$smarty->assign('find_categId', '');
53}
54if ($prefs['feature_categories'] == 'y') {
55	$categlib = TikiLib::lib('categ');
56	$categories = $categlib->getCategories(null, true, false);
57	$smarty->assign('categories', $categories);
58}
59if (isset($_REQUEST["maxRecords"])) {
60	$maxRecords = $_REQUEST["maxRecords"];
61} else {
62	$maxRecords = 10;
63}
64$smarty->assign('maxRecords', $maxRecords);
65
66if (! isset($_REQUEST["paddingLength"])) {
67	$paddingLength = 50;
68} else {
69	$paddingLength = $_REQUEST["paddingLength"];
70}
71$smarty->assign('paddingLength', $paddingLength);
72if (isset($_REQUEST["casesensitive"]) && $_REQUEST["casesensitive"] == 'y') {
73	$casesensitive = 'y';
74} else {
75	$casesensitive = 'n';
76}
77$smarty->assign('casesensitive', $casesensitive);
78
79if (isset($_REQUEST['search']) && $searchtext) {
80	$results = $wikilib->get_pages_contains($searchtext, $offset, $maxRecords, 'pageName_asc', $categFilter);
81	$searchtextLength = strlen($searchtext);
82	foreach ($results["data"] as &$r) {
83		$pageLength = strlen($r["data"]);
84		$curpos = -1;
85		while ($curpos < $pageLength) {
86			if ($casesensitive == 'y') {
87				$curpos = strpos($r["data"], $searchtext, $curpos + 1);
88			} else {
89				$curpos = stripos($r["data"], $searchtext, $curpos + 1);
90			}
91			if ($curpos === false) {
92				$r["beforeSnippet"][] = tra('This match was not case sensitive');
93				$r["afterSnippet"][] = tra('This match was not case sensitive');
94				$r["searchreplace"][] = '0:0:0';
95				break;
96			}
97			// can't use str_replace because it replaces all: we need to be more precise
98			$snippetStart = max(0, $curpos - $paddingLength);
99			$leftpartLength = $curpos - $snippetStart;
100			$rightpartLength = min($paddingLength, $pageLength - $curpos - $searchtextLength);
101			$rightpartStart = $curpos + $searchtextLength;
102			$foundtext = substr($r["data"], $curpos, $searchtextLength);
103
104			$lefthash = md5($r["page_id"] . $r["version"] . $searchtext . $curpos);
105			$righthash = md5($curpos . $searchtext . $r["version"] . $r["page_id"]);
106
107			$beforeSnippet = substr($r["data"], $snippetStart, $leftpartLength) . $lefthash . $foundtext . $righthash . substr($r["data"], $rightpartStart, $rightpartLength);
108			$beforeSnippet = htmlentities($beforeSnippet);
109			$beforeSnippet = str_replace($lefthash, '<strong>', $beforeSnippet);
110			$beforeSnippet = str_replace($righthash, '</strong>', $beforeSnippet);
111
112			$afterSnippet = substr($r["data"], $snippetStart, $leftpartLength) . $lefthash . $replacetext . $righthash . substr($r["data"], $rightpartStart, $rightpartLength);
113			$afterSnippet = htmlentities($afterSnippet);
114			$afterSnippet = str_replace($lefthash, '<strong>', $afterSnippet);
115			$afterSnippet = str_replace($righthash, '</strong>', $afterSnippet);
116
117			$r["beforeSnippet"][] = $beforeSnippet;
118			$r["afterSnippet"][] = $afterSnippet;
119			$r["searchreplace"][] = ($r["page_id"] . ":" . $r["version"] . ":" . $curpos);
120		}
121	}
122	$smarty->assign('cant', $results['cant']);
123	$smarty->assign('results', $results['data']);
124}
125
126if (isset($_REQUEST['replace']) && $searchtext) {
127	if (empty($_REQUEST['checked'])) {
128		$message = tra('No items selected');
129	} else {
130		$last_page_id = 0;
131		foreach ($_REQUEST['checked'] as $c) {
132			list($page_id, $version, $curpos) = explode(":", $c);
133			if ($last_page_id && $page_id == $last_page_id) {
134				$version = $version + $versionadjuster;
135				$curpos = $curpos + $curposadjuster;
136			} else {
137				$last_page_id = 0;
138				$curposadjuster = 0;
139				$versionadjuster = 0;
140			}
141			$page_info = $tikilib->get_page_info_from_id($page_id);
142			if (! $page_info) {
143				$message .= tra("Page cannot be found: ") . $page_id . "<br />";
144				continue;
145			}
146			if ($page_info["version"] != $version) {
147				$message .= tra("Page has changed since preview: ") . htmlentities($page_info["pageName"]) . "<br />";
148				continue;
149			}
150			// do replacing
151			$searchtextLength = strlen($searchtext);
152			$data = $page_info["data"];
153			$firstpart = substr($data, 0, $curpos);
154			$lastpart = substr($data, $curpos + $searchtextLength);
155			if (strtolower(substr($data, $curpos, $searchtextLength)) != strtolower($searchtext)) {
156				$message .= tra("Page not updated due to error in replacing: ") . htmlentities($page_info["pageName"]) . "<br />";
157				continue;
158			}
159			$data = $firstpart . $replacetext . $lastpart;
160			$tikilib->update_page($page_info["pageName"], $data, tra('Mass search and replace'), $user, $tikilib->get_ip_address());
161			$message .= tra("Page updated: ") . htmlentities($page_info["pageName"]) . "<br />";
162			$versionadjuster++;
163			$curposadjuster = $curposadjuster + strlen($replacetext) - $searchtextLength;
164			$last_page_id = $page_id;
165		}
166	}
167	if (empty($message)) {
168		$message = tra('Nothing was replaced. Try selecting fewer items or increasing the limit change max_input_vars in php.ini.');
169	}
170	$smarty->assign('message', $message);
171}
172
173$smarty->assign('searchtext', $searchtext);
174$smarty->assign('replacetext', $replacetext);
175
176$smarty->assign('mid', 'tiki-search_replace.tpl');
177$smarty->display("tiki.tpl");
178