Wiki source for DeleteSpamAction

Show raw source

Ok, this is the translated (with very minor additions) version of the admin action to delete spam from [[ Wikini]] that GmBowen linked to on the ProgrammingHelp in RichardBerg's request for help fixing his site after a spambot attack.

I've changed all the actual variables and documentation to English, and added a couple of order by clauses to clean up the display page. Other than that, it's all [[ his]].

Caveat: I haven't been able to try this out all the way; it loads the first form (where you input the IP or username of the spammer) and the second page listing all the page revisions attributed to that IP or username just fine, but I haven't tested it any further because the only installation I have up right now is live. :\ Maybe it could be tried on the beta site?

There's **no** authentication to make sure it's an admin doing the deleting, so I would suggest using it only on a secured page where you're the only person with access to it, and then I'd delete the function and action page when you're done.

~&The following should do this:
~&just enwrap the whole action after the comment with:
if ($this->IsAdmin())
%% and %%(php)
echo 'Sorry, but because of security reasons, this action is only available for admins.';
%% I just wonder if it is faster to add if(!GetUser) to the if to close out "not logged-in users" in the first point and making IsAdmin needless in this case? --NilsLindenberg
~~& Cool, thanks, good to know. :) --MovieLady

But hey, it's a starting point! :)

Save this as actions/deletespam.php (up to you, I suppose *g*)

// Charles NĂ©pote 2005
// License GPL.
// Version 0.1 du 22/01/2005.
// Translated to English and minor changes by MovieLady 1/23/2005

echo "\n<!-- == Action erase spam ============================= -->\n";
echo "<style type=\"text/css\">",
"p { margin: 0; }",
".action_erasespam { background-color: yellow; }",

// Display the form to enter the spammer's ID or IP address
echo "<div class=\"action_erasespam\">\n",
"<form method=\"get\" action=\"". $this->Href() . "\" name=\"selection\">\n",
"<legend>Revert spammed pages to previous version</legend>\n",
"<input type=\"hidden\" name=\"wiki\" value=\"" . $this->GetPageTag() . "\" />\n",
"<p>Name of the user: <input name=\"spammer\" /> ",
"<button value=\"Valider\">Submit</button></p>\n",

// Results page and form to select which histories to erase
// added order by time ascending to the sql statement to clean up the display list --ML
else if(!isset($_REQUEST['erase']))
// Select all the current pages revised by this user
$request =
"select *
from ".$this->config["table_prefix"]."pages
where user = '" . $_REQUEST['spammer'] . "' and latest = 'Y' order by time asc";
$pagesFromSpammer = $this->LoadAll($request);

// Display the list of pages that have been vandalized
echo "<div class=\"action_erasespam\">\n";
echo "<p>Clean up the pages vandalized by " . $_REQUEST['spammer'] . "</p>\n";
echo "<form method=\"get\" action=\"". $this->Href() . "\">\n",
"<input type=\"hidden\" name=\"wiki\" value=\"" . $this->GetPageTag() . "\" />\n";
foreach ($pagesFromSpammer as $i => $page)
echo "<p><input name=\"" . $page["tag"] . "\" type=\"checkbox\">",
"(", $page["time"], ") ",
"(",$this->ComposeLinkToPage($page["tag"], "revisions", "history", 0),") ",
$this->ComposeLinkToPage($page["tag"], "", "", 0),
" . . . . ",$this->Format($page["user"]),"</p>\n" ;
echo "<input type=\"hidden\" name=\"spammer\" value=\"" . $_REQUEST['spammer'] . "\" />\n";
echo "<input type=\"hidden\" name=\"erase\" value=\"yes\" />\n";
echo "<p><button value=\"Valider\">Delete the selected page revisions</button></p>\n";
echo "</form>\n";
echo "</div>\n";

$deletedPages = "";

// Select all the current pages revised by this user
// added order by time ascending to the sql statement to clean up the display list --ML
$request1 =
"select *
from ".$this->config["table_prefix"]."pages
where user = '" . $_REQUEST['spammer'] . "' and latest = 'Y' order by time asc";
$pagesFromSpammer = $this->LoadAll($request1);

// For each selected page
foreach ($pagesFromSpammer as $i => $page)
// If the box is checked (marking that version of the page as having been spammed)
if (isset($_REQUEST[$page["tag"]]))
$requestPageBefore =
"select * " .
"from " . $this->config["table_prefix"] . "pages " .
"where tag = '" . $page["tag"] . "' " .
"and time < '" . $page["time"] . "' " .
"order by `time` desc limit 1";
$pageBefore = $this->LoadSingle($requestPageBefore);
if (!empty($pageBefore))
// Delete the selected page history
$requestDelete =
"delete from " . $this->config["table_prefix"] . "pages " .
"where id = '" . $page["id"] . "' and tag = '" . $page["tag"] . "' " .
"limit 1";
//echo "$$$$$$$$$$$$$$";
$deletedPages .= $page["tag"] . " ";

// Make the previous revision the latest version
$makeLatest =
"update " . $this->config["table_prefix"] . "pages " .
"set latest = 'Y' where id = '" . $pageBefore["id"] . "' and tag = '" . $page["tag"] . "' " .
"limit 1";
echo "<div class=\"action_erasespam\">\n";
echo "Pages deleted : ", $this->Format($deletedPages), "\n";
echo "</div>\n\n";


Ok, now in /wakka.php, you need to add the following (after backing up the file!):

function ComposeLinkToPage($tag, $method = "", $text = "", $track = 1)
if (!$text) $text = $tag;
$text = htmlentities($text);
if ($_SESSION["linktracking"] && $track)
return '<a href="'.$this->href($method, $tag).'">'.$text.'</a>';

I added it right after where "function Link" closed and before the commented out "function ""PregPageLink""" - it was about line 475.

So, there's the jumping off point.

~&Looking through the code, one thing I note is that this will only "catch" and clear **current** pages that are spammed/defaced; if they have been changed by someone else afterwards already, they will remain in the archive... I was thinking of a different approach (without this problem) but a "jumping off point" like this will certainly help. Thanks for the contribution, MovieLady! --JavaWoman
~~& (Welcome. *g*) Yep, it does. If you changed the where clauses to grab pages where latest = 'N', you could delete the $makelatest statement and then have a separate action to delete only spammed history, rather than the active pages. Kind of a pain to have them separated like that, but it could work until something is written from scratch to combine the two. :) --MovieLady
~~~& Thinking about it, though (and talking to myself *g*), I think all you'd need would be an if/else statement around the $makelatest command - if latest = 'Y' make the previous version the active page, else don't. --MovieLady
~~~~& And probably should separate the pages in the display list by whether they're history or the latest version of the page, so that it's visibly obvious to the admin which is which. -- MovieLady
~~&Offtopic: We do need a "page in work flag" :) --NilsLindenberg
~~~&Yes :) --JavaWoman

Ahem, I published a 0.5 version with much improvements. I will think about your remarks. I plan to finish the action in about 2 or 3 weeks ; with :
- [done] a reporting page where the action log automatically who done what : ex :
- (2005-01-27 18:35:41) This pages have been cleaned by CharlesNepote [SPAM from linking on porn sites] : DeleteSpamAction, SandBox.
- (note this is very important to prevent abuses if there are other admins)
- [done] possibility to add a comment in the log
- [done] possibility to choose the log page :
- from a parameter : ""{{erasespam logpage="SpamReport"}}""
- or, by default, the current page
- possibility to list pages between two dates
- possibility to clean older versions of a page
- and so on
-- CharlesNepote

==== To do list ====

(Some of which is already done, but needs a little adjusting or testing)

1) Encorporate the admin-access-only code
1) Expand this so it:
a) brings up //all// of the pages that have been altered by the user
a) marks them as current or previous version, and
i) if it's a history page, just delete it
i) if it's the most recent version of the page, delete the page and mark the previous version of the page as the current version
1) Add a tick box that selects all the pages for ease of mass spam removal

Valid XHTML :: Valid CSS: :: Powered by WikkaWiki