Index: trunk/extensions/regexBlock/regexBlockCore.php |
— | — | @@ -0,0 +1,237 @@ |
| 2 | +<?PHP |
| 3 | +/**#@+ |
| 4 | +* Extension used for blocking users names and IP addresses with regular expressions. Contains both the blocking mechanism and a special page to add/manage blocks |
| 5 | +* |
| 6 | +* @package MediaWiki |
| 7 | +* @subpackage SpecialPage |
| 8 | +* |
| 9 | +* @author Bartek |
| 10 | +* @copyright Copyright © 2007, Wikia Inc. |
| 11 | +* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
| 12 | +*/ |
| 13 | + |
| 14 | +/* add hook */ |
| 15 | +global $wgHooks; |
| 16 | +$wgHooks['GetBlockedStatus'][] = 'wfRegexBlockCheck'; |
| 17 | + |
| 18 | +/* |
| 19 | + prepare data by getting blockers |
| 20 | + @param $current_user User: current user |
| 21 | +*/ |
| 22 | +function wfRegexBlockCheck ($current_user) { |
| 23 | + global $wgMemc, $wgSharedDB ; |
| 24 | + if (!wfSimplifiedRegexCheckSharedDB()) |
| 25 | + return ; |
| 26 | + $ip_to_check = wfGetIP () ; |
| 27 | + $key = "$wgSharedDB:regexBlockCore:blockers" ; |
| 28 | + $cached = $wgMemc->get ($key) ; |
| 29 | + if (!is_array($cached)) { |
| 30 | + /* get from database */ |
| 31 | + $blockers_array = array () ; |
| 32 | + $dbr =& wfGetDB (DB_SLAVE); |
| 33 | + $query = "SELECT blckby_blocker FROM ".wfRegexBlockGetTable()." GROUP BY blckby_blocker" ; |
| 34 | + $res = $dbr->query($query) ; |
| 35 | + while ( $row = $dbr->fetchObject( $res ) ) { |
| 36 | + wfGetRegexBlocked ($row->blckby_blocker, $current_user, $ip_to_check) ; |
| 37 | + array_push ($blockers_array, $row->blckby_blocker) ; |
| 38 | + } |
| 39 | + $dbr->freeResult ($res) ; |
| 40 | + $wgMemc->set ($key, $blockers_array, REGEXBLOCK_EXPIRE) ; |
| 41 | + } else { |
| 42 | + /* get from cache */ |
| 43 | + foreach ($cached as $blocker) { |
| 44 | + wfGetRegexBlocked ($blocker, $current_user, $ip_to_check) ; |
| 45 | + } |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +/* |
| 50 | + fetch usernames or IP addresses to run a match against |
| 51 | + @param $blocker String: the admin who blocked |
| 52 | + @param $user User: current user |
| 53 | + @param $mode integer: REGEXBLOCK_MODE_IPS or REGEXBLOCK_MODE_NAMES |
| 54 | + @return String: string to run a regex match against |
| 55 | +*/ |
| 56 | +function wfGetRegexBlockedData ($blocker, $user, $mode) { |
| 57 | + global $wgMemc, $wgUser, $wgSharedDB ; |
| 58 | + $names = "" ; |
| 59 | + $first = true ; |
| 60 | + |
| 61 | + /* first, check if regex string is already stored in memcache */ |
| 62 | + $key = "$wgSharedDB:regexBlockCore:$mode:blocker:$blocker" ; |
| 63 | + $cached = $wgMemc->get ($key) ; |
| 64 | + if ( "" == $cached ) { |
| 65 | + /* fetch data from db, concatenate into one string, then fill cache */ |
| 66 | + $dbr =& wfGetDB( DB_SLAVE ) ; |
| 67 | + $query = "SELECT blckby_name, blckby_exact FROM ".wfRegexBlockGetTable()." WHERE blckby_blocker = {$dbr->addQuotes($blocker)}" ; |
| 68 | + $res = $dbr->query ($query) ; |
| 69 | + while ( $row = $dbr->fetchObject( $res ) ) { |
| 70 | + $concat = "" ; |
| 71 | + $is_ip = $user->isIP($row->blckby_name) ; |
| 72 | + /* IPs are checked in exact mode, marked as exact also */ |
| 73 | + $simplified = $row->blckby_name ; |
| 74 | + if (( (REGEXBLOCK_MODE_IPS == $mode) && ($is_ip != 0) ) || $row->blckby_exact) { |
| 75 | + $concat = "^{$simplified}$" ; |
| 76 | + } else if ((REGEXBLOCK_MODE_NAMES == $mode)) { |
| 77 | + $concat = $simplified ; |
| 78 | + } |
| 79 | + if ($concat != "") { |
| 80 | + if (!$first) { |
| 81 | + $names .= "|".$concat ; |
| 82 | + } else { |
| 83 | + $names .= $concat ; |
| 84 | + $first = false ; |
| 85 | + } |
| 86 | + } |
| 87 | + } |
| 88 | + $wgMemc->set ($key, $names, REGEXBLOCK_EXPIRE) ; |
| 89 | + $dbr->freeResult ($res) ; |
| 90 | + } else { |
| 91 | + /* take from cache */ |
| 92 | + $names = $cached ; |
| 93 | + } |
| 94 | + return $names ; |
| 95 | +} |
| 96 | + |
| 97 | +/* |
| 98 | + check if the block expired or not (AFTER we found an existing block) |
| 99 | + @param $user User: current user object |
| 100 | + @param $names Array: matched names |
| 101 | + @param $ips Array: matched ips |
| 102 | + @return Array or false |
| 103 | +*/ |
| 104 | +function wfRegexBlockExpireCheck ($user, $names = null, $ips = null) { |
| 105 | + global $wgMemc, $wgSharedDB ; |
| 106 | + /* I will use memcache, with the key being particular block |
| 107 | + */ |
| 108 | + if ( is_array ($ips) ) { |
| 109 | + $array_match = $ips ; |
| 110 | + $username = wfGetIP () ; |
| 111 | + } else { |
| 112 | + $array_match = $names ; |
| 113 | + $username = $user->getName () ; |
| 114 | + } |
| 115 | + $ret = array() ; |
| 116 | + $dbr =& wfGetDB (DB_SLAVE) ; |
| 117 | + /* for EACH match check whether timestamp expired until found VALID timestamp |
| 118 | + but: only for a BLOCKED user, and it will be memcached |
| 119 | + moreover, expired blocks will be consequently deleted |
| 120 | + */ |
| 121 | + foreach ($array_match as $single) { |
| 122 | + $key = "$wgSharedDB:regexBlockCore:blocked:$single" ; |
| 123 | + $cached = $wgMemc->get ($key) ; |
| 124 | + if ( !is_object ($cached) ) { |
| 125 | + /* get from database */ |
| 126 | + $query = "SELECT blckby_timestamp, blckby_expire, blckby_blocker, blckby_create, blckby_exact, blckby_reason |
| 127 | + FROM ".wfRegexBlockGetTable()." |
| 128 | + WHERE blckby_name like {$dbr->addQuotes('%'.$single.'%')}" ; |
| 129 | + |
| 130 | + $res = $dbr->query ($query) ; |
| 131 | + if ($row = $dbr->fetchObject ($res) ) { |
| 132 | + /* if still valid or infinite, ok to block user */ |
| 133 | + if ((wfTimestampNow () <= $row->blckby_expire) || ('infinite' == $row->blckby_expire)) { |
| 134 | + $ret['create'] = $row->blckby_create ; |
| 135 | + $ret['exact'] = $row->blckby_exact ; |
| 136 | + $ret['reason'] = $row->blckby_reason ; |
| 137 | + $wgMemc->set ($key, $row) ; |
| 138 | + $dbr->freeResult ($res) ; |
| 139 | + return $ret ; |
| 140 | + } else { /* clean up an obsolete block */ |
| 141 | + wfRegexBlockClearExpired ($single, $row->blckby_blocker) ; |
| 142 | + } |
| 143 | + } |
| 144 | + $dbr->freeResult ($res) ; |
| 145 | + } else { |
| 146 | + /* get from cache */ |
| 147 | + if ((wfTimestampNow () <= $cached->blckby_expire) || ('infinite' == $cached->blckby_expire)) { |
| 148 | + $ret['create'] = $cached->blckby_create ; |
| 149 | + $ret['exact'] = $cached->blckby_exact ; |
| 150 | + $ret['reason'] = $cached->blckby_reason ; |
| 151 | + return $ret ; |
| 152 | + } else { /* clean up an obsolete block */ |
| 153 | + wfRegexBlockClearExpired ($single, $cached->blckby_blocker) ; |
| 154 | + } |
| 155 | + } |
| 156 | + } |
| 157 | + return false ; |
| 158 | +} |
| 159 | + |
| 160 | +/* clean up an existing expired block |
| 161 | + @param $username String: name of the user |
| 162 | + @param $blocker String: name of the blocker |
| 163 | + |
| 164 | +*/ |
| 165 | +function wfRegexBlockClearExpired ($username, $blocker) { |
| 166 | + $dbw =& wfGetDB( DB_MASTER ); |
| 167 | + $query = "DELETE FROM ".wfRegexBlockGetTable()." WHERE blckby_name = ".$dbw->addQuotes($username) ; |
| 168 | + $dbw->query ($query) ; |
| 169 | + if ( $dbw->affectedRows() ) { |
| 170 | + /* success, remember to delete cache key */ |
| 171 | + wfRegexBlockUnsetKeys ($blocker, $username) ; |
| 172 | + return true ; |
| 173 | + } |
| 174 | + return false ; |
| 175 | +} |
| 176 | + |
| 177 | +/* put the stats about block into database |
| 178 | + @param $username String |
| 179 | + @param $user_ip String: IP of the current user |
| 180 | + @param $blocker String |
| 181 | +*/ |
| 182 | +function wfRegexBlockUpdateStats ($username, $user_ip, $blocker) { |
| 183 | + global $wgSharedDB ; |
| 184 | + $dbw =& wfGetDB( DB_MASTER ); |
| 185 | + $now = wfTimestampNow () ; |
| 186 | + $query = "INSERT INTO ".wfRegexBlockGetStatsTable()." |
| 187 | + (stats_id, stats_user, stats_ip, stats_blocker, stats_timestamp) |
| 188 | + values (null, {$dbw->addQuotes($username)}, '{$user_ip}',{$dbw->addQuotes($blocker)},'{$now}')" ; |
| 189 | + $res = $dbw->query ($query) ; |
| 190 | + if ( $dbw->affectedRows() ) { |
| 191 | + return true ; |
| 192 | + } |
| 193 | + return false ; |
| 194 | +} |
| 195 | + |
| 196 | +/* |
| 197 | + the actual blocking goes here, for each blocker |
| 198 | + @param $blocker String |
| 199 | + @param $user User |
| 200 | + @param $user_ip String |
| 201 | +*/ |
| 202 | +function wfGetRegexBlocked ($blocker, $user, $user_ip) { |
| 203 | + $names = wfGetRegexBlockedData ($blocker,$user,REGEXBLOCK_MODE_NAMES); |
| 204 | + $ips = wfGetRegexBlockedData ($blocker,$user,REGEXBLOCK_MODE_IPS); |
| 205 | + $username = $user->getName () ; |
| 206 | + $matched_name = preg_match ('/'.$names.'/i', $user->getName(), $matches) ; |
| 207 | + $matched_ip = preg_match ('/'.$ips.'/i', $user_ip, $ip_matches ) ; |
| 208 | + |
| 209 | + if ( ( $matched_name && ($names != "") ) || ( $matched_ip && ($ips != "") ) ) { |
| 210 | + /* check if this block hasn't expired already */ |
| 211 | + if ($matched_ip && ($ips != "")) { |
| 212 | + $valid = wfRegexBlockExpireCheck ($user, null, $ip_matches) ; |
| 213 | + } |
| 214 | + else { |
| 215 | + $valid = wfRegexBlockExpireCheck ($user, $matches, null) ; |
| 216 | + } |
| 217 | + if ( is_array ($valid) ) { |
| 218 | + $user->mBlockedby = $blocker ; |
| 219 | + if ($valid['reason'] != "") { /* a reason was given, display it */ |
| 220 | + $user->mBlockreason = $valid['reason'] ; |
| 221 | + } else { /* display generic reasons */ |
| 222 | + if ($matched_ip && ($ips != "") ) { /* we blocked by IP */ |
| 223 | + $user->mBlockreason = REGEXBLOCK_REASON_IP ; |
| 224 | + } else if ($valid['exact'] == 1) { /* we blocked by username exact match */ |
| 225 | + $user->mBlockreason = REGEXBLOCK_REASON_NAME ; |
| 226 | + } else { /* we blocked by regex match */ |
| 227 | + $user->mBlockreason = REGEXBLOCK_REASON_REGEX ; |
| 228 | + } |
| 229 | + } |
| 230 | + /* account creation check goes through the same hook... */ |
| 231 | + if ($valid['create'] == 1) $user->mBlock->mCreateAccount = 1 ; |
| 232 | + |
| 233 | + wfRegexBlockUpdateStats ($username, $user_ip, $blocker) ; |
| 234 | + } |
| 235 | + } |
| 236 | +} |
| 237 | + |
| 238 | +?> |
Index: trunk/extensions/regexBlock/SpecialRegexBlockStats.php |
— | — | @@ -0,0 +1,115 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/**#@+ |
| 5 | +* Extension used for blocking users names and IP addresses with regular expressions. Contains both the blocking mechanism and a special page to add/manage blocks |
| 6 | +* |
| 7 | +* @package MediaWiki |
| 8 | +* @subpackage SpecialPage |
| 9 | +* |
| 10 | +* @author Bartek |
| 11 | +* @copyright Copyright © 2007, Wikia Inc. |
| 12 | +* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
| 13 | +*/ |
| 14 | + |
| 15 | +if(!defined('MEDIAWIKI')) |
| 16 | + die(); |
| 17 | + |
| 18 | +/* add data to tables */ |
| 19 | +$wgExtensionFunctions[] = 'wfRegexBlockStatsPageSetup'; |
| 20 | +$wgExtensionCredits['specialpage'][] = array( |
| 21 | + 'name' => 'Regex Block Stats', |
| 22 | + 'author' => 'Bartek', |
| 23 | + 'description' => 'Displays block statistics for the regexblock extension' |
| 24 | +); |
| 25 | + |
| 26 | +/* special page setup function */ |
| 27 | +function wfRegexBlockStatsPageSetup () { |
| 28 | + global $IP, $wgMessageCache; |
| 29 | + if (!wfSimplifiedRegexCheckSharedDB()) |
| 30 | + return ; |
| 31 | + require_once($IP. '/includes/SpecialPage.php'); |
| 32 | + /* name, restrictions, */ |
| 33 | + SpecialPage::addPage(new SpecialPage('Regexblockstats', 'regexblock', false, 'wfRegexBlockStatsCore', false)); |
| 34 | + $wgMessageCache->addMessage('regexblockstats', 'Regex Block Statistics'); |
| 35 | +} |
| 36 | + |
| 37 | +/* special page core function */ |
| 38 | +function wfRegexBlockStatsCore () { |
| 39 | +global $wgOut, $wgUser, $wgRequest ; |
| 40 | + $wgOut->setPageTitle ("Regex Block Stats") ; |
| 41 | + $username = $wgRequest->getVal ('target') ; |
| 42 | + $wgOut->setSubtitle ("for {$username}") ; |
| 43 | + $scL = new RegexBlockStatsList () ; |
| 44 | + $scL->showList ('',$username) ; |
| 45 | +} |
| 46 | + |
| 47 | +/* list class */ |
| 48 | +class RegexBlockStatsList { |
| 49 | + var $numResults ; |
| 50 | + |
| 51 | + /* constructor */ |
| 52 | + function RegexBlockStatsList () { |
| 53 | + $this->numResults = 0 ; |
| 54 | + } |
| 55 | + |
| 56 | + /* show it up */ |
| 57 | + function showList ($error, $username) { |
| 58 | + global $wgOut, $wgRequest ; |
| 59 | + /* no list when no user */ |
| 60 | + if ("" == $username) |
| 61 | + return false ; |
| 62 | + $this->fetchNumResults ($username) ; |
| 63 | + $this->showPrevNext ($wgOut) ; |
| 64 | + $wgOut->addHTML ("<ul>") ; |
| 65 | + $this->fetchLogs ($username) ; |
| 66 | + $wgOut->addHTML ("</ul>") ; |
| 67 | + $this->showPrevNext ($wgOut) ; |
| 68 | + } |
| 69 | + |
| 70 | + /* fetch number of all rows */ |
| 71 | + function fetchNumResults ($username) { |
| 72 | + global $wgMemc, $wgSharedDB ; |
| 73 | + $dbr = &wfGetDB (DB_SLAVE) ; |
| 74 | + $query_count = "SELECT COUNT(*) as n FROM ".wfRegexBlockGetStatsTable()." WHERE stats_user = ".$dbr->addQuotes ($username) ; |
| 75 | + $res_count = $dbr->query($query_count) ; |
| 76 | + $row_count = $dbr->fetchObject ($res_count); |
| 77 | + $this->numResults = $row_count->n ; |
| 78 | + $dbr->freeResult ($res_count) ; |
| 79 | + } |
| 80 | + |
| 81 | + /* fetch all logs */ |
| 82 | + function fetchLogs ($username) { |
| 83 | + global $wgOut, $wgSharedDB, $wgDBname, $wgRequest, $wgLang ; |
| 84 | + /* from database */ |
| 85 | + list( $limit, $offset ) = $wgRequest->getLimitOffset(); |
| 86 | + $dbr =& wfGetDB (DB_SLAVE); |
| 87 | + $query = "SELECT stats_user, stats_blocker, stats_timestamp, stats_ip |
| 88 | + FROM ".wfRegexBlockGetStatsTable()." |
| 89 | + WHERE stats_user={$dbr->addQuotes($username)} |
| 90 | + ORDER BY stats_timestamp DESC LIMIT $offset,$limit" ; |
| 91 | + $res = $dbr->query ($query) ; |
| 92 | + while ($row = $dbr->fetchObject($res)) { |
| 93 | + $time = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->stats_timestamp ), true ); |
| 94 | + $wgOut->addHTML("<li><b>{$row->stats_user}</b> was blocked on <b>{$time}</b>, logging from address <b>{$row->stats_ip}</b></li>") ; |
| 95 | + } |
| 96 | + $dbr->freeResult ($res) ; |
| 97 | + } |
| 98 | + |
| 99 | + /* init for showprevnext */ |
| 100 | + function showPrevNext( &$out ) { |
| 101 | + global $wgContLang, $wgRequest; |
| 102 | + list( $limit, $offset ) = $wgRequest->getLimitOffset(); |
| 103 | + $target = 'target=' . urlencode ( $wgRequest->getVal ('target') ) ; |
| 104 | + $mode = '&mode=' . urlencode ( $wgRequest->getVal ('mode') ) ; |
| 105 | + $html = wfViewPrevNext( |
| 106 | + $offset, |
| 107 | + $limit, |
| 108 | + $wgContLang->specialpage( 'Regexblockstats' ), |
| 109 | + $target.$mode, |
| 110 | + ($this->numResults - $offset) <= $limit |
| 111 | + ); |
| 112 | + $out->addHTML( '<p>' . $html . '</p>' ); |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +?> |
Index: trunk/extensions/regexBlock/regexBlock.php |
— | — | @@ -0,0 +1,71 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/**#@+ |
| 5 | +* Extension used for blocking users names and IP addresses with regular expressions. Contains both the blocking mechanism and a special page to add/manage blocks |
| 6 | +* |
| 7 | +* @package MediaWiki |
| 8 | +* @subpackage SpecialPage |
| 9 | +* |
| 10 | +* @author Bartek |
| 11 | +* @copyright Copyright © 2007, Wikia Inc. |
| 12 | +* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
| 13 | +*/ |
| 14 | + |
| 15 | + |
| 16 | +/* generic reasons */ |
| 17 | + |
| 18 | + global $wgContactLink; |
| 19 | +if($wgContactLink == ''){ |
| 20 | + $wgContactLink = '[[Special:Contact|contact Wikia]]'; |
| 21 | + } |
| 22 | + |
| 23 | +/* these users may be innocent - we do want them to contact Wikia if they are */ |
| 24 | +define ('REGEXBLOCK_REASON_IP', "This IP address is prevented from editing due to vandalism or other disruption by you or by someone who shares your IP address. If you believe this is in error, please $wgContactLink") ; |
| 25 | + |
| 26 | +/* we do not really want these users to contact Wikia about the problem - those are vandals */ |
| 27 | +define ('REGEXBLOCK_REASON_NAME', "This username is prevented from editing due to vandalism or other disruption. If you believe this is in error, please $wgContactLink") ; |
| 28 | +define ('REGEXBLOCK_REASON_REGEX', "This username is prevented from editing due to vandalism or other disruption by a user with a similar name. Please create an alternate user name or $wgContactLink about the problem.") ; |
| 29 | + |
| 30 | +define ('REGEXBLOCK_PATH', '/') ; |
| 31 | + |
| 32 | + |
| 33 | +/* help displayed on the special page */ |
| 34 | +define ('REGEXBLOCK_HELP', "Use the form below to block write access from a specific IP address or username. This should be done only only to prevent vandalism, and in accordance with policy. <i>This page will allow you to block even non-existing users, and will also block users with names similar to given, i.e. 'Test' will be blocked along with 'Test 2' etc. You can also block full IP addresses, meaning that no one logging from them will be able to edit pages. Note: partial IP addresses will be treated by usernames in determining blocking. If no reason is specified, a default generic reason will be used.</i>") ; |
| 35 | + |
| 36 | +/* get name of the table */ |
| 37 | +function wfRegexBlockGetTable () { |
| 38 | + global $wgSharedDB ; |
| 39 | + if ("" != $wgSharedDB) { |
| 40 | + return "{$wgSharedDB}.blockedby" ; |
| 41 | + } else { |
| 42 | + return 'blockedby' ; |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +/* get the name of the stats table */ |
| 47 | +function wfRegexBlockGetStatsTable () { |
| 48 | + global $wgSharedDB ; |
| 49 | + if ("" != $wgSharedDB) { |
| 50 | + return "{$wgSharedDB}.stats_blockedby" ; |
| 51 | + } else { |
| 52 | + return 'stats_blockedby' ; |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +/* memcached expiration time (0 - infinite) */ |
| 57 | +define ('REGEXBLOCK_EXPIRE', 0) ; |
| 58 | +/* modes for fetching data during blocking */ |
| 59 | +define ('REGEXBLOCK_MODE_NAMES',0) ; |
| 60 | +define ('REGEXBLOCK_MODE_IPS',1) ; |
| 61 | +/* for future use */ |
| 62 | +define ('REGEXBLOCK_USE_STATS', 1) ; |
| 63 | + |
| 64 | +/* core includes */ |
| 65 | +require_once ($IP.REGEXBLOCK_PATH."extensions/regexBlock/regexBlockCore.php") ; |
| 66 | +require_once ($IP.REGEXBLOCK_PATH."extensions/regexBlock/SpecialRegexBlock.php") ; |
| 67 | +require_once ($IP.REGEXBLOCK_PATH."extensions/regexBlock/SpecialRegexBlockStats.php") ; |
| 68 | + |
| 69 | +/* simplified regexes, this is shared with SpamRegex */ |
| 70 | +require_once ($IP.REGEXBLOCK_PATH."extensions/SimplifiedRegex.php") ; |
| 71 | + |
| 72 | +?> |
Index: trunk/extensions/regexBlock/SpecialRegexBlock.php |
— | — | @@ -0,0 +1,460 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/**#@+ |
| 5 | +* A special page with the interface for blocking, viewing and unblocking |
| 6 | + user names and IP addresses |
| 7 | +* |
| 8 | +* @package MediaWiki |
| 9 | +* @subpackage SpecialPage |
| 10 | +* |
| 11 | +* @author Bartek |
| 12 | +* @copyright Copyright © 2007, Wikia Inc. |
| 13 | +* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later |
| 14 | +*/ |
| 15 | + |
| 16 | +if(!defined('MEDIAWIKI')) |
| 17 | + die(); |
| 18 | + |
| 19 | +$wgAvailableRights[] = 'regexblock'; |
| 20 | +$wgGroupPermissions['staff']['regexblock'] = true; |
| 21 | + |
| 22 | +$wgExtensionFunctions[] = 'wfRegexBlockSetup'; |
| 23 | +$wgExtensionCredits['specialpage'][] = array( |
| 24 | + 'name' => 'Regular Expression Name Block', |
| 25 | + 'author' => 'Bartek', |
| 26 | + 'description' => 'alternate user block (by given name, using regular expressions)' |
| 27 | +); |
| 28 | + |
| 29 | +/* special page init */ |
| 30 | +function wfRegexBlockSetup() { |
| 31 | + global $IP, $wgMessageCache; |
| 32 | + if (!wfSimplifiedRegexCheckSharedDB()) |
| 33 | + return ; |
| 34 | + require_once($IP. '/includes/SpecialPage.php'); |
| 35 | + SpecialPage::addPage(new SpecialPage('Regexblock', 'regexblock', true, 'wfRegexBlockSpecial', false)); |
| 36 | + $wgMessageCache->addMessage('regexblock', 'regexBlock'); |
| 37 | +} |
| 38 | + |
| 39 | +/* wrapper for GET values */ |
| 40 | +function wfGetListBits () { |
| 41 | + global $wgRequest ; |
| 42 | + $pieces = array() ; |
| 43 | + list( $limit, $offset ) = $wgRequest->getLimitOffset() ; |
| 44 | + $pieces[] = 'limit=' . $limit ; |
| 45 | + $pieces[] = 'offset=' . $offset ; |
| 46 | + $pieces[] = 'filter=' . urlencode ($wgRequest->getVal ('filter') ); |
| 47 | + $bits = implode( '&', $pieces ) ; |
| 48 | + return $bits ; |
| 49 | +} |
| 50 | + |
| 51 | +/* draws one option for select */ |
| 52 | +function wfRegexBlockMakeOption ($name, $value, $current) { |
| 53 | + global $wgOut ; |
| 54 | + if ($value == $current) { |
| 55 | + $wgOut->addHTML ("<option selected=\"selected\" value=\"{$value}\">{$name}</option>") ; |
| 56 | + } else { |
| 57 | + $wgOut->addHTML ("<option value=\"{$value}\">{$name}</option>") ; |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +/* the core */ |
| 62 | +function wfRegexBlockSpecial( $par ) { |
| 63 | + global $wgOut, $wgUser, $wgRequest ; |
| 64 | + $wgOut->setPageTitle("Regular Expression Name Block"); |
| 65 | + $rBS = new regexBlockForm ($par) ; |
| 66 | + $rBL = new regexBlockList ($par) ; |
| 67 | + |
| 68 | + $action = $wgRequest->getVal( 'action' ); |
| 69 | + if ( 'success_block' == $action ) { |
| 70 | + $rBS->showSuccess() ; |
| 71 | + $rBS->showForm ('') ; |
| 72 | + } else if ( 'success_unblock' == $action ) { |
| 73 | + $rBL->showSuccess() ; |
| 74 | + $rBS->showForm ('') ; |
| 75 | + } else if ( 'failure_unblock' == $action ) { |
| 76 | + $ip = $wgRequest->getVal ('ip') ; |
| 77 | + $rBS->showForm ("Error unblocking \"{$ip}\". Probably there is no such user.") ; |
| 78 | + } else if ( $wgRequest->wasPosted() && 'submit' == $action && |
| 79 | + $wgUser->matchEditToken( $wgRequest->getVal ('wpEditToken') ) ) { |
| 80 | + $rBS->doSubmit () ; |
| 81 | + } else if ('delete' == $action) { |
| 82 | + $rBL->deleteFromRegexBlockList () ; |
| 83 | + } else { |
| 84 | + $rBS->showForm ('') ; |
| 85 | + } |
| 86 | + $rBL->showList ('', $offset ) ; |
| 87 | +} |
| 88 | + |
| 89 | +/* useful for cleaning the memcached keys */ |
| 90 | +function wfRegexBlockUnsetKeys ($blocker, $username) { |
| 91 | + global $wgMemc, $wgSharedDB ; |
| 92 | + $wgMemc->delete ("$wgSharedDB:regexBlockSpecial:numResults") ; |
| 93 | + $wgMemc->delete ("$wgSharedDB:regexBlockCore:".REGEXBLOCK_MODE_NAMES.":blocker:$blocker") ; |
| 94 | + $wgMemc->delete ("$wgSharedDB:regexBlockCore:".REGEXBLOCK_MODE_IPS.":blocker:$blocker") ; |
| 95 | + $wgMemc->delete ("$wgSharedDB:regexBlockCore:blockers") ; |
| 96 | + $wgMemc->delete ("$wgSharedDB:regexBlockCore:blocked:$username") ; |
| 97 | +} |
| 98 | + |
| 99 | +/* the list of blocked names/addresses */ |
| 100 | +class regexBlockList { |
| 101 | + var $mRegexUnblockedAddress ; |
| 102 | + var $numResults = 0 ; |
| 103 | + |
| 104 | + /* constructor */ |
| 105 | + function regexBlockList ( $par ) { |
| 106 | + } |
| 107 | + |
| 108 | + /* output list */ |
| 109 | + function showList ( $err ) { |
| 110 | + global $wgOut, $wgRequest, $wgMemc, $wgLang, $wgUser ; |
| 111 | + |
| 112 | + /* on error, display error */ |
| 113 | + if ( "" != $err ) { |
| 114 | + $wgOut->addHTML ("<p class='error'>{$err}</p>\n") ; |
| 115 | + } |
| 116 | + $titleObj = Title::makeTitle( NS_SPECIAL, 'Regexblock' ); |
| 117 | + $action = $titleObj->escapeLocalURL("") ."?".wfGetListBits() ; |
| 118 | + $action_unblock = $titleObj->escapeLocalURL("action=delete") ."&".wfGetListBits() ; |
| 119 | + list( $limit, $offset ) = $wgRequest->getLimitOffset() ; |
| 120 | + |
| 121 | + $wgOut->addWikiText ("<br/><b>Currently blocked addresses:</b>") ; |
| 122 | + $this->fetchNumResults () ; |
| 123 | + $this->showPrevNext ($wgOut) ; |
| 124 | + |
| 125 | + $wgOut->addHTML ("<form name=\"regexlist\" method=\"get\" action=\"{$action}\">") ; |
| 126 | + |
| 127 | + /* allow display by specific blockers only */ |
| 128 | + $wgOut->addHTML ("View blocked by: <select name=\"filter\"><option value=\"\">All</option>") ; |
| 129 | + $blockers = $this->fetchBlockers () ; |
| 130 | + $wgOut->addHTML("</select> <input type=\"submit\" value=\"Go\"><br/><br/> |
| 131 | + ") ; |
| 132 | + $current = $wgRequest->getVal ('filter') ; |
| 133 | + |
| 134 | + if ($blockers) { |
| 135 | + /* get data and play with data */ |
| 136 | + $dbr = &wfGetDB (DB_SLAVE) ; |
| 137 | + $query = "SELECT * FROM ".wfRegexBlockGetTable() ; |
| 138 | + if ('' != $current) { |
| 139 | + $query .= " WHERE blckby_blocker = {$dbr->addQuotes($current)}" ; |
| 140 | + } |
| 141 | + /* righto, order by name */ |
| 142 | + $query .= " order by blckby_timestamp DESC" ; |
| 143 | + |
| 144 | + $query = $dbr->limitResult ($query, $limit, $offset) ; |
| 145 | + $res = $dbr->query ($query) ; |
| 146 | + $wgOut->addHTML ("<ul>") ; |
| 147 | + |
| 148 | + /* output a single row*/ |
| 149 | + while ( $row = $dbr->fetchObject( $res ) ) { |
| 150 | + $ublock_ip = urlencode ($row->blckby_name) ; |
| 151 | + $ublock_blocker = urlencode ($row->blckby_blocker) ; |
| 152 | + |
| 153 | + $row->blckby_exact ? $exact_match = "(exact match)" : $exact_match = '(regex match)' ; |
| 154 | + $row->blckby_create ? $create_block = "(account creation block)" : $create_block = '' ; |
| 155 | + $row->blckby_reason ? $reason = "<i>reason: {$row->blckby_reason}</i>" : $reason = '<i>generic reason</i>' ; |
| 156 | + |
| 157 | + $time = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->blckby_timestamp ), true ) ; |
| 158 | + |
| 159 | + /* if this block already expired, show it */ |
| 160 | + $expiry = $row->blckby_expire ; |
| 161 | + if ( (wfTimestampNow () <= $expiry) || ('infinite' == $expiry) ) { |
| 162 | + $expiry == 'infinite' ? $expires = 'permanent block' : $expires = "expires on ".$wgLang->timeanddate( wfTimestamp( TS_MW, $expiry ), true ) ; |
| 163 | + } else { |
| 164 | + $expires = "<span style=\"color: #ff0000\">EXPIRED on {$wgLang->timeanddate( wfTimestamp( TS_MW, $expiry ), true )}</span>" ; |
| 165 | + } |
| 166 | + $sk = $wgUser->getSkin () ; |
| 167 | + $stats_link = $sk->makeKnownLinkObj( Title::makeTitle( NS_SPECIAL, 'Regexblockstats' ), '(stats)', 'target=' . urlencode($row->blckby_name)) ; |
| 168 | + $wgOut->addHTML (" |
| 169 | + <li><b>{$row->blckby_name} {$exact_match} {$create_block}</b> (blocked by: <b>{$row->blckby_blocker}</b>, {$reason}) on {$time} (<a href=\"{$action_unblock}&ip={$ublock_ip}&blocker={$ublock_blocker}\">unblock</a>) {$expires} {$stats_link}</li> |
| 170 | + ") ; |
| 171 | + } |
| 172 | + |
| 173 | + $dbr->freeResult ($res) ; |
| 174 | + $wgOut->addHTML ("</ul></form>") ; |
| 175 | + } else { /* empty list */ |
| 176 | + $wgOut->addHTML ("The list of blocked names and addresses is empty.<br/><br/>") ; |
| 177 | + } |
| 178 | + $this->showPrevNext ($wgOut) ; |
| 179 | + } |
| 180 | + |
| 181 | + /* a plain html link wrapper */ |
| 182 | + function produceLink ($url, $link, $text) { |
| 183 | + return $html_link = ("<a href=\"$url$link\">$text</a>") ; |
| 184 | + } |
| 185 | + |
| 186 | + /* remove name or address from list - without confirmation */ |
| 187 | + function deleteFromRegexBlockList () { |
| 188 | + global $wgOut, $wgRequest, $wgMemc, $wgUser ; |
| 189 | + $ip = $wgRequest->getVal('ip'); |
| 190 | + $blocker = $wgRequest->getVal('blocker') ; |
| 191 | + /* delete */ |
| 192 | + $dbw =& wfGetDB( DB_MASTER ); |
| 193 | + $query = "DELETE FROM ".wfRegexBlockGetTable()." WHERE blckby_name = ".$dbw->addQuotes($ip) ; |
| 194 | + $dbw->query ($query) ; |
| 195 | + $titleObj = Title::makeTitle( NS_SPECIAL, 'Regexblock' ) ; |
| 196 | + if ( $dbw->affectedRows() ) { |
| 197 | + /* success */ |
| 198 | + wfRegexBlockUnsetKeys ($blocker, $ip) ; |
| 199 | + $wgOut->redirect( $titleObj->getFullURL( 'action=success_unblock&ip='.urlencode($ip).'&'.wfGetListBits() ) ) ; |
| 200 | + } else { |
| 201 | + $wgOut->redirect( $titleObj->getFullURL( 'action=failure_unblock&ip='.urlencode($ip).'&'.wfGetListBits() ) ) ; |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + /* fetch names of all blockers and write them into select's options */ |
| 206 | + function fetchBlockers () { |
| 207 | + global $wgOut, $wgRequest, $wgMemc, $wgSharedDB ; |
| 208 | + /* memcached */ |
| 209 | + $key = "$wgSharedDB:regexBlockCore:blockers" ; |
| 210 | + $current = $wgRequest->getVal ('filter') ; |
| 211 | + $cached = $wgMemc->get ($key) ; |
| 212 | + $fetched = 0 ; |
| 213 | + if (!is_array($cached)) { |
| 214 | + /* get from database */ |
| 215 | + $blockers_array = array () ; |
| 216 | + $dbr =& wfGetDB (DB_SLAVE); |
| 217 | + $query = "SELECT blckby_blocker FROM ".wfRegexBlockGetTable() ; |
| 218 | + $query .= " GROUP BY blckby_blocker" ; |
| 219 | + $res = $dbr->query($query) ; |
| 220 | + while ( $row = $dbr->fetchObject( $res ) ) { |
| 221 | + wfRegexBlockmakeOption ($row->blckby_blocker, $row->blckby_blocker, $current) ; |
| 222 | + array_push ($blockers_array, $row->blckby_blocker) ; |
| 223 | + } |
| 224 | + $fetched = $dbr->numRows ($res) ; |
| 225 | + $dbr->freeResult ($res) ; |
| 226 | + $wgMemc->set ($key, $blockers_array) ; |
| 227 | + } else { |
| 228 | + /* get from memcached */ |
| 229 | + foreach ($cached as $blocker) { |
| 230 | + wfRegexBlockmakeOption ($blocker, $blocker, $current) ; |
| 231 | + $fetched++ ; |
| 232 | + } |
| 233 | + } |
| 234 | + return $fetched ; |
| 235 | + } |
| 236 | + |
| 237 | + /* fetch number of all rows */ |
| 238 | + function fetchNumResults () { |
| 239 | + global $wgMemc, $wgSharedDB ; |
| 240 | + |
| 241 | + /* we use memcached here */ |
| 242 | + $key = "$wgSharedDB:regexBlockSpecial:numResults" ; |
| 243 | + $cached = $wgMemc->get ($key) ; |
| 244 | + if (is_null ($cached)) { |
| 245 | + $dbr = &wfGetDB (DB_SLAVE) ; |
| 246 | + $query_count = "SELECT COUNT(*) as n FROM ".wfRegexBlockGetTable() ; |
| 247 | + $res_count = $dbr->query($query_count) ; |
| 248 | + $row_count = $dbr->fetchObject ($res_count); |
| 249 | + $this->numResults = $row_count->n ; |
| 250 | + $wgMemc->set ($key, $this->numResults, REGEXBLOCK_EXPIRE) ; |
| 251 | + $dbr->freeResult ($res_count) ; |
| 252 | + } else { |
| 253 | + $this->numResults = $cached ; |
| 254 | + } |
| 255 | + } |
| 256 | + |
| 257 | + /* on success */ |
| 258 | + function showSuccess () { |
| 259 | + global $wgOut, $wgRequest ; |
| 260 | + $wgOut->setPageTitle('Block address using regular expressions') ; |
| 261 | + $wgOut->setSubTitle('Unblock succedeed') ; |
| 262 | + $wgOut->addWikiText('User name or IP address <b>'.htmlspecialchars($wgRequest->getVal('ip', $par)).'</b> has been unblocked.') ; |
| 263 | + } |
| 264 | + |
| 265 | + /* init for showprevnext */ |
| 266 | + function showPrevNext( &$out ) { |
| 267 | + global $wgContLang,$wgRequest; |
| 268 | + list( $limit, $offset ) = $wgRequest->getLimitOffset(); |
| 269 | + $filter = 'filter=' . urlencode ( $wgRequest->getVal ('filter') ) ; |
| 270 | + $html = wfViewPrevNext( |
| 271 | + $offset, |
| 272 | + $limit, |
| 273 | + $wgContLang->specialpage( 'Regexblock' ), |
| 274 | + $filter, |
| 275 | + ($this->numResults - $offset) <= $limit |
| 276 | + ); |
| 277 | + $out->addHTML( '<p>' . $html . '</p>' ); |
| 278 | + } |
| 279 | +} |
| 280 | + |
| 281 | +/* the form for blocking names and addresses */ |
| 282 | +class regexBlockForm { |
| 283 | + var $mRegexBlockedAddress, $mRegexBlockedExact, $mRegexBlockedCreation, $mRegexBlockedExpire ; |
| 284 | + |
| 285 | + /* constructor */ |
| 286 | + function regexBlockForm ( $par ) { |
| 287 | + global $wgRequest ; |
| 288 | + $this->mRegexBlockedAddress = $wgRequest->getVal( 'wpRegexBlockedAddress', $wgRequest->getVal( 'ip', $par ) ); |
| 289 | + $this->mRegexBlockedExact = $wgRequest->getInt ('wpRegexBlockedExact') ; |
| 290 | + $this->mRegexBlockedCreation = $wgRequest->getInt ('wpRegexBlockedCreation') ; |
| 291 | + $this->mRegexBlockedExpire = $wgRequest->getVal ('wpRegexBlockedExpire') ; |
| 292 | + $this->mRegexBlockedReason = $wgRequest->getVal ('wpRegexBlockedReason') ; |
| 293 | + } |
| 294 | + |
| 295 | + /* output */ |
| 296 | + function showForm ( $err ) { |
| 297 | + global $wgOut, $wgUser, $wgRequest ; |
| 298 | + |
| 299 | + $token = htmlspecialchars( $wgUser->editToken() ); |
| 300 | + $titleObj = Title::makeTitle( NS_SPECIAL, 'Regexblock' ); |
| 301 | + $action = $titleObj->escapeLocalURL( "action=submit" )."&".wfGetListBits() ; |
| 302 | + |
| 303 | + if ( "" != $err ) { |
| 304 | + $wgOut->setSubtitle( wfMsgHtml( 'formerror' ) ); |
| 305 | + $wgOut->addHTML( "<p class='error'>{$err}</p>\n" ); |
| 306 | + } |
| 307 | + |
| 308 | + $wgOut->addWikiText (REGEXBLOCK_HELP) ; |
| 309 | + |
| 310 | + if ( 'submit' == $wgRequest->getVal( 'action' )) { |
| 311 | + $scRegexBlockedAddress = htmlspecialchars ($this->mRegexBlockedAddress) ; |
| 312 | + $scRegexBlockedExpire = htmlspecialchars ($this->mRegexBlockedExpire) ; |
| 313 | + $scRegexBlockedReason = htmlspecialchars ($this->mRegexBlockedReason) ; |
| 314 | + $this->mRegexBlockedExact ? $checked_ex = "checked=\"checked\"" : $checked_ex = "" ; |
| 315 | + $this->mRegexBlockedCreation ? $checked_cr = "checked=\"checked\"" : $checked_cr = "" ; |
| 316 | + } else { |
| 317 | + $scRegexBlockedAddress = '' ; |
| 318 | + $checked_ex = '' ; |
| 319 | + $checked_cr = '' ; |
| 320 | + } |
| 321 | + |
| 322 | + $wgOut->addHtml(" |
| 323 | +<form name=\"regexblock\" method=\"post\" action=\"{$action}\"> |
| 324 | + <table border=\"0\"> |
| 325 | + <tr> |
| 326 | + <td align=\"right\">IP Adress or username:</td> |
| 327 | + <td align=\"left\"> |
| 328 | + <input tabindex=\"1\" name=\"wpRegexBlockedAddress\" size=\"40\" value=\"{$scRegexBlockedAddress}\" /> |
| 329 | + </td> |
| 330 | + </tr> |
| 331 | + <tr> |
| 332 | + <td align=\"right\">Reason:</td> |
| 333 | + <td align=\"left\"> |
| 334 | + <input tabindex=\"2\" name=\"wpRegexBlockedReason\" size=\"40\" value=\"{$scRegexBlockedReason}\" /> |
| 335 | + </td> |
| 336 | + </tr> |
| 337 | + <tr> |
| 338 | + <td align=\"right\">Expiry: </td> |
| 339 | + <td align=\"left\"> |
| 340 | + <select name=\"wpRegexBlockedExpire\" tabindex=\"3\">"); |
| 341 | + $expiries = array ( |
| 342 | + '1 hour', |
| 343 | + '2 hours', |
| 344 | + '4 hours', |
| 345 | + '6 hours', |
| 346 | + '1 day', |
| 347 | + '3 days', |
| 348 | + '1 week', |
| 349 | + '2 weeks', |
| 350 | + '1 month', |
| 351 | + '3 months', |
| 352 | + '1 year', |
| 353 | + 'infinite' |
| 354 | + ) ; |
| 355 | + foreach ($expiries as $duration) { |
| 356 | + wfRegexBlockMakeOption ($duration, $duration, $scRegexBlockedExpire) ; |
| 357 | + } |
| 358 | + $wgOut->addHTML("</select> |
| 359 | + </td> |
| 360 | + </tr> |
| 361 | + <tr> |
| 362 | + <td align=\"right\"> </td> |
| 363 | + <td align=\"left\"> |
| 364 | + <input type=\"checkbox\" tabindex=\"4\" name=\"wpRegexBlockedExact\" id=\"wpRegexBlockedExact\" value=\"1\" $checked_ex /> |
| 365 | + <label for=\"wpRegexBlockedExact\">Exact match</label> |
| 366 | + </td> |
| 367 | + </tr> |
| 368 | + <tr> |
| 369 | + <td align=\"right\"> </td> |
| 370 | + <td align=\"left\"> |
| 371 | + <input type=\"checkbox\" tabindex=\"5\" name=\"wpRegexBlockedCreation\" id=\"wpRegexBlockedCreation\" value=\"1\" $checked_cr /> |
| 372 | + <label for=\"wpRegexBlockedCreation\">Block creation of new accounts</label> |
| 373 | + </td> |
| 374 | + </tr> |
| 375 | + <tr> |
| 376 | + <td align=\"right\"> </td> |
| 377 | + <td align=\"left\"> |
| 378 | + <input tabindex=\"6\" name=\"wpRegexBlockedSubmit\" type=\"submit\" value=\"Block this user\" /> |
| 379 | + </td> |
| 380 | + </tr> |
| 381 | + </table> |
| 382 | + <input type='hidden' name='wpEditToken' value=\"{$token}\" /> |
| 383 | +</form>"); |
| 384 | + } |
| 385 | + |
| 386 | + /* on success */ |
| 387 | + function showSuccess () { |
| 388 | + global $wgOut ; |
| 389 | + $wgOut->setPageTitle ('Block address using regular expressions') ; |
| 390 | + $wgOut->setSubTitle ('Block succedeed') ; |
| 391 | + |
| 392 | + $wgOut->addWikiText ('User name or IP address <b>'.htmlspecialchars($this->mRegexBlockedAddress).'</b> has been blocked.') ; |
| 393 | + } |
| 394 | + |
| 395 | + /* on submit */ |
| 396 | + function doSubmit () { |
| 397 | + global $wgOut, $wgUser, $wgMemc ; |
| 398 | + |
| 399 | + /* empty name */ |
| 400 | + if ( strlen($this->mRegexBlockedAddress) == 0 ) { |
| 401 | + $this->showForm ("Give a user name or an IP address to block.") ; |
| 402 | + return ; |
| 403 | + } |
| 404 | + |
| 405 | + /* castrate regexes */ |
| 406 | + if (!$simple_regex = wfValidRegex ($this->mRegexBlockedAddress) ) { |
| 407 | + /* now, very generic comment - should the conditions change, this should too */ |
| 408 | + $this->showForm ("Invalid regular expression.") ; |
| 409 | + return ; |
| 410 | + } |
| 411 | + |
| 412 | + /* check expiry */ |
| 413 | + if ( strlen ($this->mRegexBlockedExpire) == 0 ) { |
| 414 | + $this->showForm ("Please specify an expiration period.") ; |
| 415 | + return ; |
| 416 | + } |
| 417 | + |
| 418 | + /* TODO - check infinite */ |
| 419 | + if ($this->mRegexBlockedExpire != 'infinite') { |
| 420 | + $expiry = strtotime( $this->mRegexBlockedExpire ); |
| 421 | + if ( $expiry < 0 || $expiry === false ) { |
| 422 | + $this->showForm( wfMsg( 'ipb_expiry_invalid' ) ); |
| 423 | + return; |
| 424 | + } |
| 425 | + $expiry = wfTimestamp( TS_MW, $expiry ); |
| 426 | + } else { |
| 427 | + $expiry = $this->mRegexBlockedExpire ; |
| 428 | + } |
| 429 | + |
| 430 | + /* make insert */ |
| 431 | + $dbw =& wfGetDB( DB_MASTER ); |
| 432 | + $name = $wgUser->getName () ; |
| 433 | + $timestamp = wfTimestampNow() ; |
| 434 | + |
| 435 | + $query = "INSERT IGNORE INTO ".wfRegexBlockGetTable()." |
| 436 | + (blckby_id, blckby_name, blckby_blocker, blckby_timestamp, blckby_expire, blckby_exact, blckby_create, blckby_reason) |
| 437 | + VALUES (null, |
| 438 | + {$dbw->addQuotes($this->mRegexBlockedAddress)}, |
| 439 | + {$dbw->addQuotes($name)}, |
| 440 | + '{$timestamp}', |
| 441 | + '{$expiry}', |
| 442 | + {$this->mRegexBlockedExact}, |
| 443 | + {$this->mRegexBlockedCreation}, |
| 444 | + {$dbw->addQuotes($this->mRegexBlockedReason)} |
| 445 | + )" ; |
| 446 | + $dbw->query ($query) ; |
| 447 | + /* duplicate entry */ |
| 448 | + if (!$dbw->affectedRows()) { |
| 449 | + $this->showForm ( "\"".htmlspecialchars($this->mRegexBlockedAddress)."\" is already blocked." ) ; |
| 450 | + return ; |
| 451 | + } |
| 452 | + |
| 453 | + wfRegexBlockUnsetKeys ($name, $this->mRegexBlockedAddress) ; |
| 454 | + |
| 455 | + /* redirect */ |
| 456 | + $titleObj = Title::makeTitle( NS_SPECIAL, 'Regexblock' ) ; |
| 457 | + $wgOut->redirect( $titleObj->getFullURL( 'action=success_block&ip=' .urlencode( $this->mRegexBlockedAddress )."&".wfGetListBits() ) ) ; |
| 458 | + } |
| 459 | +} |
| 460 | + |
| 461 | +?> |
Index: trunk/extensions/regexBlock/README |
— | — | @@ -0,0 +1,46 @@ |
| 2 | + |
| 3 | +# INSTALLATION |
| 4 | + |
| 5 | +# Note: this extension works best when used along with setting shared database and memcached |
| 6 | + |
| 7 | +# 1. Copy the /regexBlock folder and regexBlock.php into the /extensions folder. |
| 8 | +# 2. Add require_once ("/extensions/regexBlock.php") ; |
| 9 | +# to your GlobalSettings.php file. |
| 10 | +# 3. Create required tables. |
| 11 | +# 4. Set $wgSharedDB to the name of a shared database of your choice (in GlobalSettings.php). |
| 12 | +# 5. Set $wgMainCacheType to 'CACHE_MEMCACHED' and $wgMemCachedServers. The latter could look like this: |
| 13 | +# $wgMemCachedServers = array ("127.0.0.1:11000"); (for a memcached server running on IP 127.0.0.1 and |
| 14 | +# port 11000). |
| 15 | + |
| 16 | +# Depending on your previous configuration, you may need to remove or comment a line including the older regexBlock.php |
| 17 | +# (probably in your GlobalSettings.php file). |
| 18 | + |
| 19 | + |
| 20 | +# Required tables |
| 21 | +# total: 2 tables |
| 22 | + |
| 23 | + CREATE TABLE `blockedby` ( |
| 24 | + `blckby_id` int(5) NOT NULL auto_increment, |
| 25 | + `blckby_name` varchar(255) NOT NULL, |
| 26 | + `blckby_blocker` varchar(255) NOT NULL, |
| 27 | + `blckby_timestamp` char(14) NOT NULL, |
| 28 | + `blckby_expire` char(14) NOT NULL, |
| 29 | + `blckby_create` tinyint(1) NOT NULL default '1', |
| 30 | + `blckby_exact` tinyint(1) NOT NULL default '0', |
| 31 | + `blckby_reason` tinyblob NOT NULL, |
| 32 | + PRIMARY KEY (`blckby_id`), |
| 33 | + UNIQUE KEY `blckby_name` (`blckby_name`), |
| 34 | + KEY `blckby_timestamp` (`blckby_timestamp`), |
| 35 | + KEY `blckby_expire` (`blckby_expire`) |
| 36 | + ) ; |
| 37 | + |
| 38 | + CREATE TABLE `stats_blockedby` ( |
| 39 | + `stats_id` int(8) NOT NULL auto_increment, |
| 40 | + `stats_user` varchar(255) NOT NULL, |
| 41 | + `stats_blocker` varchar(255) NOT NULL, |
| 42 | + `stats_timestamp` char(14) NOT NULL, |
| 43 | + `stats_ip` char(15) NOT NULL, |
| 44 | + PRIMARY KEY (`stats_id`), |
| 45 | + KEY `stats_timestamp` (`stats_timestamp`) |
| 46 | + ) ; |
| 47 | + |