1 <?php 2 3 /** 4 * Spam Cleaner 5 * 6 * Helps an admin to clean up spam in Moodle 7 * 8 * @author Dongsheng Cai 9 * @author Martin Dougiamas 10 * @author Amr Hourani 11 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 12 */ 13 14 // List of known spammy keywords, please add more here 15 16 ///////////////////////////////////////////////////////////////////////////////// 17 18 require_once('../../../config.php'); 19 require_once($CFG->libdir.'/adminlib.php'); 20 21 22 // Configuration 23 24 $autokeywords = array( 25 "<img", 26 "fuck", 27 "casino", 28 "porn", 29 "xxx", 30 "cialis", 31 "viagra", 32 "poker", 33 "warcraft" 34 ); 35 36 $keyword = optional_param('keyword', '', PARAM_RAW); 37 $autodetect = optional_param('autodetect', '', PARAM_RAW); 38 $del = optional_param('del', '', PARAM_RAW); 39 $delall = optional_param('delall', '', PARAM_RAW); 40 $ignore = optional_param('ignore', '', PARAM_RAW); 41 $reset = optional_param('reset', '', PARAM_RAW); 42 $id = optional_param('id', '', PARAM_INT); 43 44 admin_externalpage_setup('toolspamcleaner'); 45 46 // Delete one user 47 if (!empty($del) && confirm_sesskey() && ($id != $USER->id)) { 48 if (isset($SESSION->users_result[$id])) { 49 $user = $SESSION->users_result[$id]; 50 if (delete_user($user)) { 51 unset($SESSION->users_result[$id]); 52 echo json_encode(true); 53 } else { 54 echo json_encode(false); 55 } 56 } else { 57 echo json_encode(false); 58 } 59 exit; 60 } 61 62 // Delete lots of users 63 if (!empty($delall) && confirm_sesskey()) { 64 if (!empty($SESSION->users_result)) { 65 foreach ($SESSION->users_result as $userid => $user) { 66 if ($userid != $USER->id) { 67 if (delete_user($user)) { 68 unset($SESSION->users_result[$userid]); 69 } 70 } 71 } 72 } 73 echo json_encode(true); 74 exit; 75 } 76 77 if (!empty($ignore) && confirm_sesskey()) { 78 unset($SESSION->users_result[$id]); 79 echo json_encode(true); 80 exit; 81 } 82 83 $PAGE->requires->js_init_call('M.tool_spamcleaner.init', array(me()), true); 84 $strings = Array('spaminvalidresult','spamdeleteallconfirm','spamcannotdelete','spamdeleteconfirm'); 85 $PAGE->requires->strings_for_js($strings, 'tool_spamcleaner'); 86 87 echo $OUTPUT->header(); 88 89 // Print headers and things 90 echo $OUTPUT->box(get_string('spamcleanerintro', 'tool_spamcleaner')); 91 92 echo $OUTPUT->box_start(); // The forms section at the top 93 94 ?> 95 96 <div class="mdl-align"> 97 98 <form method="post" action="index.php" class="form-inline spamcleanerform"> 99 <div> 100 <label class="accesshide" for="keyword_el"><?php print_string('spamkeyword', 'tool_spamcleaner') ?></label> 101 <input type="text" class="form-control" name="keyword" id="keyword_el" value="<?php p($keyword) ?>" /> 102 <input type="hidden" name="sesskey" value="<?php echo sesskey();?>" /> 103 <input type="submit" class="btn btn-primary" value="<?php echo get_string('spamsearch', 'tool_spamcleaner')?>" /> 104 </div> 105 </form> 106 <p><?php echo get_string('spameg', 'tool_spamcleaner');?></p> 107 108 <hr /> 109 110 <form method="post" action="index.php"> 111 <div> 112 <input type="submit" class="btn btn-primary" name="autodetect" 113 value="<?php echo get_string('spamauto', 'tool_spamcleaner');?>" /> 114 </div> 115 </form> 116 117 118 </div> 119 120 <?php 121 echo $OUTPUT->box_end(); 122 123 echo '<div id="result" class="mdl-align">'; 124 125 // Print list of resulting profiles 126 127 if (!empty($keyword)) { // Use the keyword(s) supplied by the user 128 $keywords = explode(',', $keyword); 129 foreach ($keywords as $key => $keyword) { 130 $keywords[$key] = trim($keyword); 131 } 132 search_spammers($keywords); 133 134 } else if (!empty($autodetect)) { // Use the inbuilt keyword list to detect users 135 search_spammers($autokeywords); 136 } 137 138 echo '</div>'; 139 140 ///////////////////////////////////////////////////////////////////////////////// 141 142 143 /// Functions 144 145 146 function search_spammers($keywords) { 147 148 global $CFG, $USER, $DB, $OUTPUT; 149 150 if (!is_array($keywords)) { 151 $keywords = array($keywords); // Make it into an array 152 } 153 154 $params = array('userid'=>$USER->id); 155 156 $keywordfull = array(); 157 $i = 0; 158 foreach ($keywords as $keyword) { 159 $keywordfull[] = $DB->sql_like('description', ':descpat'.$i, false); 160 $params['descpat'.$i] = "%$keyword%"; 161 $keywordfull2[] = $DB->sql_like('p.summary', ':sumpat'.$i, false); 162 $params['sumpat'.$i] = "%$keyword%"; 163 $keywordfull3[] = $DB->sql_like('p.subject', ':subpat'.$i, false); 164 $params['subpat'.$i] = "%$keyword%"; 165 $keywordfull4[] = $DB->sql_like('c.content', ':contpat'.$i, false); 166 $params['contpat'.$i] = "%$keyword%"; 167 $keywordfull5[] = $DB->sql_like('m.fullmessage', ':msgpat'.$i, false); 168 $params['msgpat'.$i] = "%$keyword%"; 169 $keywordfull6[] = $DB->sql_like('fp.message', ':forumpostpat'.$i, false); 170 $params['forumpostpat'.$i] = "%$keyword%"; 171 $keywordfull7[] = $DB->sql_like('fp.subject', ':forumpostsubpat'.$i, false); 172 $params['forumpostsubpat'.$i] = "%$keyword%"; 173 $i++; 174 } 175 $conditions = '( '.implode(' OR ', $keywordfull).' )'; 176 $conditions2 = '( '.implode(' OR ', $keywordfull2).' )'; 177 $conditions3 = '( '.implode(' OR ', $keywordfull3).' )'; 178 $conditions4 = '( '.implode(' OR ', $keywordfull4).' )'; 179 $conditions5 = '( '.implode(' OR ', $keywordfull5).' )'; 180 $conditions6 = '( '.implode(' OR ', $keywordfull6).' )'; 181 $conditions7 = '( '.implode(' OR ', $keywordfull7).' )'; 182 183 $sql = "SELECT * 184 FROM {user} 185 WHERE deleted = 0 186 AND id <> :userid 187 AND $conditions"; // Exclude oneself 188 $sql2 = "SELECT u.*, p.summary 189 FROM {user} u, {post} p 190 WHERE $conditions2 191 AND u.deleted = 0 192 AND u.id=p.userid 193 AND u.id <> :userid"; 194 $sql3 = "SELECT u.*, p.subject AS postsubject 195 FROM {user} u, {post} p 196 WHERE $conditions3 197 AND u.deleted = 0 198 AND u.id=p.userid 199 AND u.id <> :userid"; 200 $sql4 = "SELECT u.*, c.content 201 FROM {user} u, {comments} c 202 WHERE $conditions4 203 AND u.deleted = 0 204 AND u.id=c.userid 205 AND u.id <> :userid"; 206 $sql5 = "SELECT u.*, m.fullmessage 207 FROM {user} u, {message} m 208 WHERE $conditions5 209 AND u.deleted = 0 210 AND u.id=m.useridfrom 211 AND u.id <> :userid"; 212 $sql6 = "SELECT u.*, fp.message 213 FROM {user} u, {forum_posts} fp 214 WHERE $conditions6 215 AND u.deleted = 0 216 AND u.id=fp.userid 217 AND u.id <> :userid"; 218 $sql7 = "SELECT u.*, fp.subject 219 FROM {user} u, {forum_posts} fp 220 WHERE $conditions7 221 AND u.deleted = 0 222 AND u.id=fp.userid 223 AND u.id <> :userid"; 224 225 $spamusers_desc = $DB->get_recordset_sql($sql, $params); 226 $spamusers_blog = $DB->get_recordset_sql($sql2, $params); 227 $spamusers_blogsub = $DB->get_recordset_sql($sql3, $params); 228 $spamusers_comment = $DB->get_recordset_sql($sql4, $params); 229 $spamusers_message = $DB->get_recordset_sql($sql5, $params); 230 $spamusers_forumpost = $DB->get_recordset_sql($sql6, $params); 231 $spamusers_forumpostsub = $DB->get_recordset_sql($sql7, $params); 232 233 $keywordlist = implode(', ', $keywords); 234 echo $OUTPUT->box(get_string('spamresult', 'tool_spamcleaner').s($keywordlist)).' ...'; 235 236 $recordsets = [ 237 $spamusers_desc, 238 $spamusers_blog, 239 $spamusers_blogsub, 240 $spamusers_comment, 241 $spamusers_message, 242 $spamusers_forumpost, 243 $spamusers_forumpostsub 244 ]; 245 print_user_list($recordsets, $keywords); 246 foreach ($recordsets as $rs) { 247 $rs->close(); 248 } 249 } 250 251 252 253 function print_user_list($users_rs, $keywords) { 254 global $CFG, $SESSION; 255 256 // reset session everytime this function is called 257 $SESSION->users_result = array(); 258 $count = 0; 259 260 foreach ($users_rs as $rs){ 261 foreach ($rs as $user) { 262 if (!$count) { 263 echo '<table class="table table-bordered" border="1" width="100%" id="data-grid"><tr><th> </th> 264 <th>'.get_string('user', 'admin').'</th><th>'.get_string('spamdesc', 'tool_spamcleaner').'</th> 265 <th>'.get_string('spamoperation', 'tool_spamcleaner').'</th></tr>'; 266 } 267 $count++; 268 filter_user($user, $keywords, $count); 269 } 270 } 271 272 if (!$count) { 273 echo get_string('spamcannotfinduser', 'tool_spamcleaner'); 274 275 } else { 276 echo '</table>'; 277 echo '<div class="mld-align"> 278 <button id="removeall_btn" class="btn btn-secondary">'.get_string('spamdeleteall', 'tool_spamcleaner').'</button> 279 </div>'; 280 } 281 } 282 function filter_user($user, $keywords, $count) { 283 global $CFG; 284 $image_search = false; 285 if (in_array('<img', $keywords)) { 286 $image_search = true; 287 } 288 if (isset($user->summary)) { 289 $user->description = '<h3>'.get_string('spamfromblog', 'tool_spamcleaner').'</h3>'.$user->summary; 290 unset($user->summary); 291 } else if (isset($user->postsubject)) { 292 $user->description = '<h3>'.get_string('spamfromblog', 'tool_spamcleaner').'</h3>'.$user->postsubject; 293 unset($user->postsubject); 294 } else if (isset($user->content)) { 295 $user->description = '<h3>'.get_string('spamfromcomments', 'tool_spamcleaner').'</h3>'.$user->content; 296 unset($user->content); 297 } else if (isset($user->fullmessage)) { 298 $user->description = '<h3>'.get_string('spamfrommessages', 'tool_spamcleaner').'</h3>'.$user->fullmessage; 299 unset($user->fullmessage); 300 } else if (isset($user->message)) { 301 $user->description = '<h3>'.get_string('spamfromforumpost', 'tool_spamcleaner').'</h3>'.$user->message; 302 unset($user->message); 303 } else if (isset($user->subject)) { 304 $user->description = '<h3>'.get_string('spamfromforumpost', 'tool_spamcleaner').'</h3>'.$user->subject; 305 unset($user->subject); 306 } 307 308 if (preg_match('#<img.*src=[\"\']('.$CFG->wwwroot.')#', $user->description, $matches) 309 && $image_search) { 310 $result = false; 311 foreach ($keywords as $keyword) { 312 if (preg_match('#'.$keyword.'#', $user->description) 313 && ($keyword != '<img')) { 314 $result = true; 315 } 316 } 317 if ($result) { 318 echo print_user_entry($user, $keywords, $count); 319 } else { 320 unset($user); 321 } 322 } else { 323 echo print_user_entry($user, $keywords, $count); 324 } 325 } 326 327 328 function print_user_entry($user, $keywords, $count) { 329 330 global $SESSION, $CFG; 331 332 $smalluserobject = new stdClass(); // All we need to delete them later 333 $smalluserobject->id = $user->id; 334 $smalluserobject->email = $user->email; 335 $smalluserobject->auth = $user->auth; 336 $smalluserobject->firstname = $user->firstname; 337 $smalluserobject->lastname = $user->lastname; 338 $smalluserobject->username = $user->username; 339 340 if (empty($SESSION->users_result[$user->id])) { 341 $SESSION->users_result[$user->id] = $smalluserobject; 342 $html = '<tr valign="top" id="row-'.$user->id.'" class="result-row">'; 343 $html .= '<td width="10">'.$count.'</td>'; 344 $html .= '<td width="30%" align="left"><a href="'.$CFG->wwwroot."/user/view.php?course=1&id=".$user->id.'" title="'.s($user->username).'">'.fullname($user).'</a>'; 345 346 $html .= "<ul>"; 347 $profile_set = array('city'=>true, 'country'=>true, 'email'=>true); 348 foreach ($profile_set as $key=>$value) { 349 if (isset($user->$key)){ 350 $html .= '<li>'.$user->$key.'</li>'; 351 } 352 } 353 $html .= "</ul>"; 354 $html .= '</td>'; 355 356 foreach ($keywords as $keyword) { 357 $user->description = highlight($keyword, $user->description); 358 } 359 360 if (!isset($user->descriptionformat)) { 361 $user->descriptionformat = FORMAT_MOODLE; 362 } 363 364 $html .= '<td align="left">'.format_text($user->description, $user->descriptionformat, array('overflowdiv'=>true)).'</td>'; 365 $html .= '<td width="100px" align="center">'; 366 $html .= '<button class="btn btn-primary" onclick="M.tool_spamcleaner.del_user(this,'.$user->id.')">'. 367 get_string('deleteuser', 'admin').'</button><br />'; 368 $html .= '<button class="btn btn-secondary" onclick="M.tool_spamcleaner.ignore_user(this,'.$user->id.')">'. 369 get_string('ignore', 'admin').'</button>'; 370 $html .= '</td>'; 371 $html .= '</tr>'; 372 return $html; 373 } else { 374 return null; 375 } 376 377 378 } 379 380 echo $OUTPUT->footer();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body