e17f6cc69b7c87e928f3a92c65389ff8b26358bb
[atutor.git] / mods / wiki / plugins / admin / page_searchandreplace.php
1 <?php
2
3 /*
4    This plugin provides a SearchAndReplace dialog page, which allows
5    to grep for pages and to replace content/text using regular expression
6    matching and replacing (as well as ordinary string replacing). It is
7    very powerful, even if the interface and description make it appear
8    difficult to use.
9
10    Only moderators and superusers can use it ($ewiki_ring level must not
11    be lower than 1).
12
13    WARNING: security leak! moderates may be able to use the /e modifier
14    to execute arbitrary code -- There is now a check for this, which logs
15    such attempts.
16 */
17
18
19 #-- plugin glue
20 $ewiki_plugins["page"]["SearchAndReplace"] = "ewiki_page_searchandreplace";
21
22
23 #-- impl
24 function ewiki_page_searchandreplace($id, $data, $action) {
25
26    global $ewiki_ring, $ewiki_plugins;
27
28    $o = ewiki_make_title($id, $id, 2);
29
30    #-- admin requ. ---------------------------------------------------------
31    if (!ewiki_auth($id,$data,$action, $ring=1, "_FORCE_LOGIN=1") || !isset($ewiki_ring) || ($ewiki_ring > 1)) {
32       if (is_array($data)) {
33          $data = "You'll need moderator/administrator privileges to use this.";
34       }
35       return($o .= $data);
36    }
37
38    #-- form ----------------------------------------------------------------
39    if (empty($_REQUEST["snr_go"]) && empty($_REQUEST["snr_test"])) {
40       $url = ewiki_script("", $id);
41       $o .= ewiki_t(<<<END
42 Use this form to replace all occourences of a phrase in all WikiPages.
43 <br /><br />
44 <form action="$url" method="POST" enctype="multipart/form-data">
45 search for string<br />
46 <input type="text" name="snr_search_string" value="" size="30"><br />
47 <small>this text snippet always matches case-insensitive, used as
48 <b>first-stage</b> search string; leave it empty to use only the regular
49 expression matching (slower)</small><br />
50 look this string up only in <select name="snr_search_string_where"><option selected="selected" value="content">page content / body</option> <option value="id">page name / title</option></select><br />
51 <br />
52 <i>and/or</i> with <tt>/Perl/i</tt> regular expression<br />
53 <input type="text" name="snr_search_regex" value="" size="30"><br />
54 <small>this is <b>optional</b>, and is anyhow only used as second-stage search
55 pattern; if used allows to use regex backreferences in the replacement
56 string field</small><br />
57 <br />
58 then replace with string<br />
59 <input type="text" name="snr_replace" value="" size="30"><br />
60 <small>can contain backreferences \1 and \$1 if the regex search field was
61 used</small><br />
62 <br />
63 <input type="submit" name="snr_test" value="dry run / test regex"> &nbsp;
64 <input type="submit" name="snr_go" value="Replace All">
65 </form>
66 <br />
67 <br />
68 The regular expression matching is optional, you'll often only need the
69 simple string search field and another simple string in the replacement
70 field.
71 <br />
72 <br />
73 Please note, that this form allows to initially search for a simple string,
74 but you can leave this empty and only use a regex search. And as it is a
75 two stage searching, both patterns can be completely different.
76 <br />
77 <br />
78 Text replacement always happens in the WikiPages body, even if the simple
79 search string can be used to search for page names - if you do so, you
80 certainly need a second regular expression pattern for content replacement.
81 <br />
82 END
83         );
84    }
85    else {
86       $do = $_REQUEST["snr_go"];
87
88       #-- prepare vars
89       $search_where = $_REQUEST["snr_search_string_where"];
90       $search_string = $_REQUEST["snr_search_string"];
91       $search_regex = $_REQUEST["snr_search_regex"];
92       $replacement = $_REQUEST["snr_replace"];
93       if ($search_string == "*") {
94          $search_string = "";
95       }
96       $search_string2 = preg_quote($search_string, "/");
97       $replacement2 = addcslashes($replacement, "\$");
98
99       #-- security check in search_regex      
100       if (preg_match('/([\w\s]+)$/', $search_regex, $uu) && strstr($uu[0],"e")) {
101          ewiki_log("use of regex '$search_regex' could be security circumvention attempt", 1);
102          return($o . "wrong regex delimiter");
103       }
104
105       #-- complain
106       if (empty($search_string) && empty($search_regex) || empty($replacement)) {
107          return($o . "too few parameters, needs at least one search and a replacement string");
108       }
109
110       #-- initial database string search
111       if (empty($search_string)) {
112          $result = ewiki_db::GETALL(array("id", "version", "flags"));
113       }
114       else {
115          $result = ewiki_db::SEARCH($search_where,$search_string);
116       }
117
118       #-- walk through pages
119       while ($row=$result->get()) {
120
121          #-- skip binary entries
122          if (EWIKI_DB_F_TEXT != ($row["flags"] & EWIKI_DB_F_TYPE)) {
123             continue;
124          }
125          $id = $row["id"];
126          $save = false;
127          $row = ewiki_db::GET($id);
128
129          /*
130             if (!ewiki_auth($id, $row, "edit", ...
131             ...
132          */
133
134          if ($search_regex) {
135             if (preg_match($search_regex, $row[$search_where], $uu)) {
136                $save = true;
137                $row["content"] = preg_replace($search_regex, $replacement, $row["content"]);
138             }
139          }
140          elseif ($search_string) {
141             if (stristr($row[$search_where], $search_string)) {
142                $save = true;
143                $row["content"] = preg_replace("/$search_string2/i", $replacement, $row["content"]);
144             }
145          }
146
147          if ($save) {
148             $o .= "ยท <a href=\"" . ewiki_script("", $id) . "\">" . htmlentities($id)
149                . "</a> matched given search pattern<br />\n";
150             if ($do) {
151                $row["lastmodified"] = time();
152                $row["author"] = ewiki_author("SearchAndReplace");
153                $row["version"]++;
154                if (ewiki_db::WRITE($row)) {
155                   $o .= "&nbsp; changed.<br />\n";
156                }
157                else {
158                   $o .= "&nbsp; database store error<br />\n";
159                   $o .= "&nbsp; " . mysql_error() . "<br />\n";
160                }
161             }
162          }
163          
164       }#-- while $result
165
166       if ($do) {
167          ewiki_log("SearchAndReplace for '$search_strinmg' and '$search_regex' to replace with '$replacement'");
168       }
169    }
170
171    return($o);
172 }
173
174
175 ?>