Index: trunk/phase3/maintenance/archives/patch-ipb_range_start.sql |
— | — | @@ -0,0 +1,25 @@ |
| 2 | +-- Add the range handling fields |
| 3 | +ALTER TABLE /*$wgDBprefix*/ipblocks |
| 4 | + ADD ipb_range_start varchar(32) NOT NULL default '', |
| 5 | + ADD ipb_range_end varchar(32) NOT NULL default '', |
| 6 | + ADD INDEX ipb_range (ipb_range_start(8), ipb_range_end(8)); |
| 7 | + |
| 8 | + |
| 9 | +-- Initialise fields |
| 10 | +-- Only range blocks match ipb_address LIKE '%/%', this fact is used in the code already |
| 11 | +UPDATE /*$wgDBprefix*/ipblocks |
| 12 | + SET |
| 13 | + ipb_range_start = LPAD(HEX( |
| 14 | + (SUBSTRING_INDEX(ipb_address, '.', 1) << 24) |
| 15 | + + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 2), '.', -1) << 16) |
| 16 | + + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 3), '.', -1) << 24) |
| 17 | + + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '/', 1), '.', -1)) ), 8, '0' ), |
| 18 | + |
| 19 | + ipb_range_end = LPAD(HEX( |
| 20 | + (SUBSTRING_INDEX(ipb_address, '.', 1) << 24) |
| 21 | + + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 2), '.', -1) << 16) |
| 22 | + + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 3), '.', -1) << 24) |
| 23 | + + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '/', 1), '.', -1)) |
| 24 | + + ((1 << (32 - SUBSTRING_INDEX(ipb_address, '/', -1))) - 1) ), 8, '0' ) |
| 25 | + |
| 26 | + WHERE ipb_address LIKE '%/%'; |
Property changes on: trunk/phase3/maintenance/archives/patch-ipb_range_start.sql |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 27 | + native |
Added: svn:keywords |
2 | 28 | + Author Date Id Revision |
Index: trunk/phase3/maintenance/updaters.inc |
— | — | @@ -49,7 +49,8 @@ |
50 | 50 | array( 'image', 'img_media_type', 'patch-img_media_type.sql' ), |
51 | 51 | array( 'validate', 'val_ip', 'patch-val_ip.sql' ), |
52 | 52 | array( 'site_stats', 'ss_total_pages', 'patch-ss_total_articles.sql' ), |
53 | | - array( 'interwiki', 'iw_trans', 'patch-interwiki-trans.sql' ), |
| 53 | + array( 'interwiki', 'iw_trans', 'patch-interwiki-trans.sql' ), |
| 54 | + array( 'ipblocks', 'ipb_range_start', 'patch-ipb_range_start.sql' ), |
54 | 55 | ); |
55 | 56 | |
56 | 57 | function rename_table( $from, $to, $patch ) { |
Index: trunk/phase3/maintenance/tables.sql |
— | — | @@ -502,10 +502,16 @@ |
503 | 503 | |
504 | 504 | -- Time at which the block will expire. |
505 | 505 | ipb_expiry char(14) binary NOT NULL default '', |
506 | | - |
| 506 | + |
| 507 | + -- Start and end of an address range, in hexadecimal |
| 508 | + -- Size chosen to allow IPv6 |
| 509 | + ipb_range_start varchar(32) NOT NULL default '', |
| 510 | + ipb_range_end varchar(32) NOT NULL default '', |
| 511 | + |
507 | 512 | PRIMARY KEY ipb_id (ipb_id), |
508 | 513 | INDEX ipb_address (ipb_address), |
509 | | - INDEX ipb_user (ipb_user) |
| 514 | + INDEX ipb_user (ipb_user), |
| 515 | + INDEX ipb_range (ipb_range_start(8), ipb_range_end(8)), |
510 | 516 | |
511 | 517 | ) TYPE=InnoDB; |
512 | 518 | |
Index: trunk/phase3/includes/BlockCache.php |
— | — | @@ -1,153 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Contain the blockcache class |
5 | | - * @package Cache |
6 | | - */ |
7 | | - |
8 | | -/** |
9 | | - * Object for fast lookup of IP blocks |
10 | | - * Represents a memcached value, and in some sense, the entire ipblocks table |
11 | | - * @package MediaWiki |
12 | | - */ |
13 | | -class BlockCache |
14 | | -{ |
15 | | - var $mData = false, $mMemcKey; |
16 | | - |
17 | | - /** |
18 | | - * Constructor |
19 | | - * Create a new BlockCache object |
20 | | - * |
21 | | - * @param Boolean $deferLoad specifies whether to immediately load the data from memcached. |
22 | | - * @param String $dbName specifies the memcached dbName prefix to be used. Defaults to $wgDBname. |
23 | | - */ |
24 | | - function BlockCache( $deferLoad = false, $dbName = '' ) { |
25 | | - global $wgDBname; |
26 | | - |
27 | | - if ( $dbName == '' ) { |
28 | | - $dbName = $wgDBname; |
29 | | - } |
30 | | - |
31 | | - $this->mMemcKey = $dbName.':ipblocks'; |
32 | | - |
33 | | - if ( !$deferLoad ) { |
34 | | - $this->load(); |
35 | | - } |
36 | | - } |
37 | | - |
38 | | - /** |
39 | | - * Load the blocks from the database and save them to memcached |
40 | | - * @param bool $bFromSlave Whether to load data from slaves or master |
41 | | - */ |
42 | | - function loadFromDB( $bFromSlave = false ) { |
43 | | - global $wgUseMemCached, $wgMemc; |
44 | | - $fname = 'BlockCache::loadFromDB'; |
45 | | - wfProfileIn( $fname ); |
46 | | - |
47 | | - $this->mData = array(); |
48 | | - # Selecting FOR UPDATE is a convenient way to serialise the memcached and DB operations, |
49 | | - # which is necessary even though we don't update the DB |
50 | | - if ( !$bFromSlave ) { |
51 | | - Block::enumBlocks( 'wfBlockCacheInsert', '', EB_FOR_UPDATE | EB_RANGE_ONLY ); |
52 | | - #$wgMemc->set( $this->mMemcKey, $this->mData, 0 ); |
53 | | - } else { |
54 | | - Block::enumBlocks( 'wfBlockCacheInsert', '', EB_RANGE_ONLY ); |
55 | | - } |
56 | | - wfProfileOut( $fname ); |
57 | | - } |
58 | | - |
59 | | - /** |
60 | | - * Load the cache from memcached or, if that's not possible, from the DB |
61 | | - */ |
62 | | - function load( $bFromSlave ) { |
63 | | - global $wgUseMemCached, $wgMemc; |
64 | | - |
65 | | - if ( $this->mData === false) { |
66 | | - $this->loadFromDB( $bFromSlave ); |
67 | | -/* |
68 | | - // Memcache disabled for performance issues. |
69 | | - # Try memcached |
70 | | - if ( $wgUseMemCached ) { |
71 | | - $this->mData = $wgMemc->get( $this->mMemcKey ); |
72 | | - } |
73 | | - |
74 | | - if ( !is_array( $this->mData ) ) { |
75 | | - $this->loadFromDB( $bFromSlave ); |
76 | | - }*/ |
77 | | - } |
78 | | - } |
79 | | - |
80 | | - /** |
81 | | - * Add a block to the cache |
82 | | - * |
83 | | - * @param Object &$block Reference to a "Block" object. |
84 | | - */ |
85 | | - function insert( &$block ) { |
86 | | - if ( $block->mUser == 0 ) { |
87 | | - $nb = $block->getNetworkBits(); |
88 | | - $ipint = $block->getIntegerAddr(); |
89 | | - $index = $ipint >> ( 32 - $nb ); |
90 | | - |
91 | | - if ( !array_key_exists( $nb, $this->mData ) ) { |
92 | | - $this->mData[$nb] = array(); |
93 | | - } |
94 | | - |
95 | | - $this->mData[$nb][$index] = 1; |
96 | | - } |
97 | | - } |
98 | | - |
99 | | - /** |
100 | | - * Find out if a given IP address is blocked |
101 | | - * |
102 | | - * @param String $ip IP address |
103 | | - * @param bool $bFromSlave True means to load check against slave, else check against master. |
104 | | - */ |
105 | | - function get( $ip, $bFromSlave ) { |
106 | | - $fname = 'BlockCache::get'; |
107 | | - wfProfileIn( $fname ); |
108 | | - |
109 | | - $this->load( $bFromSlave ); |
110 | | - $ipint = ip2long( $ip ); |
111 | | - $blocked = false; |
112 | | - |
113 | | - foreach ( $this->mData as $networkBits => $blockInts ) { |
114 | | - if ( array_key_exists( $ipint >> ( 32 - $networkBits ), $blockInts ) ) { |
115 | | - $blocked = true; |
116 | | - break; |
117 | | - } |
118 | | - } |
119 | | - if ( $blocked ) { |
120 | | - # Clear low order bits |
121 | | - if ( $networkBits != 32 ) { |
122 | | - $ip .= '/'.$networkBits; |
123 | | - $ip = Block::normaliseRange( $ip ); |
124 | | - } |
125 | | - $block = new Block(); |
126 | | - $block->forUpdate( $bFromSlave ); |
127 | | - $block->load( $ip ); |
128 | | - } else { |
129 | | - $block = false; |
130 | | - } |
131 | | - |
132 | | - wfProfileOut( $fname ); |
133 | | - return $block; |
134 | | - } |
135 | | - |
136 | | - /** |
137 | | - * Clear the local cache |
138 | | - * There was once a clear() to clear memcached too, but I deleted it |
139 | | - */ |
140 | | - function clearLocal() { |
141 | | - $this->mData = false; |
142 | | - } |
143 | | -} |
144 | | - |
145 | | -/** |
146 | | - * Add a block to the global $wgBlockCache |
147 | | - * |
148 | | - * @param Object $block A "Block"-object |
149 | | - * @param Any $tag unused |
150 | | - */ |
151 | | -function wfBlockCacheInsert( $block, $tag ) { |
152 | | - global $wgBlockCache; |
153 | | - $wgBlockCache->insert( $block ); |
154 | | -} |
Index: trunk/phase3/includes/ProxyTools.php |
— | — | @@ -55,7 +55,10 @@ |
56 | 56 | return $ip; |
57 | 57 | } |
58 | 58 | |
59 | | -/** */ |
| 59 | +/** |
| 60 | + * Given an IP address in dotted-quad notation, returns an unsigned integer. |
| 61 | + * Like ip2long() except that it actually works and has a consistent error return value. |
| 62 | + */ |
60 | 63 | function wfIP2Unsigned( $ip ) { |
61 | 64 | $n = ip2long( $ip ); |
62 | 65 | if ( $n == -1 || $n === false ) { # Return value on error depends on PHP version |
— | — | @@ -67,6 +70,17 @@ |
68 | 71 | } |
69 | 72 | |
70 | 73 | /** |
| 74 | + * Return a zero-padded hexadecimal representation of an IP address |
| 75 | + */ |
| 76 | +function wfIP2Hex( $ip ) { |
| 77 | + $n = wfIP2Unsigned( $ip ); |
| 78 | + if ( $n !== false ) { |
| 79 | + $n = sprintf( '%08X', $n ); |
| 80 | + } |
| 81 | + return $n; |
| 82 | +} |
| 83 | + |
| 84 | +/** |
71 | 85 | * Determine if an IP address really is an IP address, and if it is public, |
72 | 86 | * i.e. not RFC 1918 or similar |
73 | 87 | */ |
— | — | @@ -143,4 +157,22 @@ |
144 | 158 | } |
145 | 159 | } |
146 | 160 | |
| 161 | +/** |
| 162 | + * Convert a network specification in CIDR notation to an integer network and a number of bits |
| 163 | + */ |
| 164 | +function wfParseCIDR( $range ) { |
| 165 | + $parts = explode( '/', $range, 2 ); |
| 166 | + if ( count( $parts ) != 2 ) { |
| 167 | + return array( false, false ); |
| 168 | + } |
| 169 | + $network = wfIP2Unsigned( $parts[0] ); |
| 170 | + if ( $network !== false && is_numeric( $parts[1] ) && $parts[1] >= 0 && $parts[1] <= 32 ) { |
| 171 | + $bits = $parts[1]; |
| 172 | + } else { |
| 173 | + $network = false; |
| 174 | + $bits = false; |
| 175 | + } |
| 176 | + return array( $network, $bits ); |
| 177 | +} |
| 178 | + |
147 | 179 | ?> |
Index: trunk/phase3/includes/User.php |
— | — | @@ -372,14 +372,9 @@ |
373 | 373 | * @param bool $bFromSlave Specify whether to check slave or master. To improve performance, |
374 | 374 | * non-critical checks are done against slaves. Check when actually saving should be done against |
375 | 375 | * master. |
376 | | - * |
377 | | - * Note that even if $bFromSlave is false, the check is done first against slave, then master. |
378 | | - * The logic is that if blocked on slave, we'll assume it's either blocked on master or |
379 | | - * just slightly outta sync and soon corrected - safer to block slightly more that less. |
380 | | - * And it's cheaper to check slave first, then master if needed, than master always. |
381 | 376 | */ |
382 | 377 | function getBlockedStatus( $bFromSlave = true ) { |
383 | | - global $wgBlockCache, $wgProxyList, $wgEnableSorbs, $wgProxyWhitelist; |
| 378 | + global $wgProxyList, $wgEnableSorbs, $wgProxyWhitelist; |
384 | 379 | |
385 | 380 | if ( -1 != $this->mBlockedby ) { |
386 | 381 | wfDebug( "User::getBlockedStatus: already loaded.\n" ); |
— | — | @@ -395,7 +390,7 @@ |
396 | 391 | |
397 | 392 | # User/IP blocking |
398 | 393 | $block = new Block(); |
399 | | - $block->forUpdate( $bFromSlave ); |
| 394 | + $block->fromMaster( !$bFromSlave ); |
400 | 395 | if ( $block->load( $ip , $this->mId ) ) { |
401 | 396 | wfDebug( "$fname: Found block.\n" ); |
402 | 397 | $this->mBlockedby = $block->mBy; |
— | — | @@ -407,23 +402,6 @@ |
408 | 403 | wfDebug( "$fname: No block.\n" ); |
409 | 404 | } |
410 | 405 | |
411 | | - # Range blocking |
412 | | - if ( !$this->mBlockedby ) { |
413 | | - # Check first against slave, and optionally from master. |
414 | | - wfDebug( "$fname: Checking range blocks\n" ); |
415 | | - $block = $wgBlockCache->get( $ip, true ); |
416 | | - if ( !$block && !$bFromSlave ) |
417 | | - { |
418 | | - # Not blocked: check against master, to make sure. |
419 | | - $wgBlockCache->clearLocal( ); |
420 | | - $block = $wgBlockCache->get( $ip, false ); |
421 | | - } |
422 | | - if ( $block !== false ) { |
423 | | - $this->mBlockedby = $block->mBy; |
424 | | - $this->mBlockreason = $block->mReason; |
425 | | - } |
426 | | - } |
427 | | - |
428 | 406 | # Proxy blocking |
429 | 407 | if ( !$this->isSysop() && !in_array( $ip, $wgProxyWhitelist ) ) { |
430 | 408 | |
Index: trunk/phase3/includes/Setup.php |
— | — | @@ -62,7 +62,6 @@ |
63 | 63 | require_once( 'MagicWord.php' ); |
64 | 64 | require_once( 'Block.php' ); |
65 | 65 | require_once( 'MessageCache.php' ); |
66 | | -require_once( 'BlockCache.php' ); |
67 | 66 | require_once( 'Parser.php' ); |
68 | 67 | require_once( 'ParserCache.php' ); |
69 | 68 | require_once( 'WebRequest.php' ); |
— | — | @@ -269,11 +268,6 @@ |
270 | 269 | $wgOut = new OutputPage(); |
271 | 270 | |
272 | 271 | wfProfileOut( $fname.'-OutputPage' ); |
273 | | -wfProfileIn( $fname.'-BlockCache' ); |
274 | | - |
275 | | -$wgBlockCache = new BlockCache( true ); |
276 | | - |
277 | | -wfProfileOut( $fname.'-BlockCache' ); |
278 | 272 | wfProfileIn( $fname.'-misc2' ); |
279 | 273 | |
280 | 274 | $wgDeferredUpdateList = array(); |
Index: trunk/phase3/includes/Block.php |
— | — | @@ -17,15 +17,16 @@ |
18 | 18 | * loaded or filled. It is not load-on-demand. There are no accessors. |
19 | 19 | * |
20 | 20 | * To use delete(), you only need to fill $mAddress |
21 | | - * Globals used: $wgBlockCache, $wgAutoblockExpiry |
| 21 | + * Globals used: $wgAutoblockExpiry, $wgAntiLockFlags |
22 | 22 | * |
23 | 23 | * @todo This could be used everywhere, but it isn't. |
24 | 24 | * @package MediaWiki |
25 | 25 | */ |
26 | 26 | class Block |
27 | 27 | { |
28 | | - /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry; |
29 | | - /* private */ var $mNetworkBits, $mIntegerAddr, $mForUpdate, $mByName; |
| 28 | + /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry, |
| 29 | + $mRangeStart, $mRangeEnd; |
| 30 | + /* private */ var $mNetworkBits, $mIntegerAddr, $mForUpdate, $mFromMaster, $mByName; |
30 | 31 | |
31 | 32 | function Block( $address = '', $user = '', $by = 0, $reason = '', |
32 | 33 | $timestamp = '' , $auto = 0, $expiry = '' ) |
— | — | @@ -43,6 +44,7 @@ |
44 | 45 | } |
45 | 46 | |
46 | 47 | $this->mForUpdate = false; |
| 48 | + $this->mFromMaster = false; |
47 | 49 | $this->mByName = false; |
48 | 50 | $this->initialiseRange(); |
49 | 51 | } |
— | — | @@ -63,19 +65,14 @@ |
64 | 66 | } |
65 | 67 | |
66 | 68 | /** |
67 | | - * Get a ban from the DB, with either the given address or the given username |
| 69 | + * Get the DB object and set the reference parameter to the query options |
68 | 70 | */ |
69 | | - function load( $address = '', $user = 0, $killExpired = true ) |
| 71 | + function &getDBOptions( &$options ) |
70 | 72 | { |
71 | 73 | global $wgAntiLockFlags; |
72 | | - $fname = 'Block::load'; |
73 | | - wfDebug( "Block::load: '$address', '$user', $killExpired\n" ); |
74 | | - |
75 | | - $ret = false; |
76 | | - $killed = false; |
77 | | - if ( $this->forUpdate() ) { |
| 74 | + if ( $this->mForUpdate || $this->mFromMaster ) { |
78 | 75 | $db =& wfGetDB( DB_MASTER ); |
79 | | - if ( $wgAntiLockFlags & ALF_NO_BLOCK_LOCK ) { |
| 76 | + if ( !$this->mForUpdate || ($wgAntiLockFlags & ALF_NO_BLOCK_LOCK) ) { |
80 | 77 | $options = ''; |
81 | 78 | } else { |
82 | 79 | $options = 'FOR UPDATE'; |
— | — | @@ -84,15 +81,33 @@ |
85 | 82 | $db =& wfGetDB( DB_SLAVE ); |
86 | 83 | $options = ''; |
87 | 84 | } |
| 85 | + return $db; |
| 86 | + } |
| 87 | + |
| 88 | + /** |
| 89 | + * Get a ban from the DB, with either the given address or the given username |
| 90 | + */ |
| 91 | + function load( $address = '', $user = 0, $killExpired = true ) |
| 92 | + { |
| 93 | + $fname = 'Block::load'; |
| 94 | + wfDebug( "Block::load: '$address', '$user', $killExpired\n" ); |
| 95 | + |
| 96 | + $options = ''; |
| 97 | + $db =& $this->getDBOptions( $options ); |
| 98 | + |
| 99 | + $ret = false; |
| 100 | + $killed = false; |
88 | 101 | $ipblocks = $db->tableName( 'ipblocks' ); |
89 | 102 | |
90 | | - if ( 0 == $user && $address=='' ) { |
91 | | - $sql = "SELECT * from $ipblocks $options"; |
92 | | - } elseif ($address=="") { |
| 103 | + if ( 0 == $user && $address == '' ) { |
| 104 | + # Invalid user specification, not blocked |
| 105 | + $this->clear(); |
| 106 | + return false; |
| 107 | + } elseif ( $address == '' ) { |
93 | 108 | $sql = "SELECT * FROM $ipblocks WHERE ipb_user={$user} $options"; |
94 | | - } elseif ($user=="") { |
95 | | - $sql = "SELECT * FROM $ipblocks WHERE ipb_address='" . $db->strencode( $address ) . "' $options"; |
96 | | - } elseif ( $options=='' ) { |
| 109 | + } elseif ( $user == '' ) { |
| 110 | + $sql = "SELECT * FROM $ipblocks WHERE ipb_address=" . $db->addQuotes( $address ) . " $options"; |
| 111 | + } elseif ( $options == '' ) { |
97 | 112 | # If there are no options (e.g. FOR UPDATE), use a UNION |
98 | 113 | # so that the query can make efficient use of indices |
99 | 114 | $sql = "SELECT * FROM $ipblocks WHERE ipb_address='" . $db->strencode( $address ) . |
— | — | @@ -105,10 +120,7 @@ |
106 | 121 | } |
107 | 122 | |
108 | 123 | $res = $db->query( $sql, $fname ); |
109 | | - if ( 0 == $db->numRows( $res ) ) { |
110 | | - # User is not blocked |
111 | | - $this->clear(); |
112 | | - } else { |
| 124 | + if ( 0 != $db->numRows( $res ) ) { |
113 | 125 | # Get first block |
114 | 126 | $row = $db->fetchObject( $res ); |
115 | 127 | $this->initFromRow( $row ); |
— | — | @@ -137,9 +149,72 @@ |
138 | 150 | } |
139 | 151 | } |
140 | 152 | $db->freeResult( $res ); |
| 153 | + |
| 154 | + # No blocks found yet? Try looking for range blocks |
| 155 | + if ( !$ret && $address != '' ) { |
| 156 | + $ret = $this->loadRange( $address, $killExpired ); |
| 157 | + } |
| 158 | + if ( !$ret ) { |
| 159 | + $this->clear(); |
| 160 | + } |
| 161 | + |
141 | 162 | return $ret; |
142 | 163 | } |
143 | 164 | |
| 165 | + /** |
| 166 | + * Search the database for any range blocks matching the given address, and |
| 167 | + * load the row if one is found. |
| 168 | + */ |
| 169 | + function loadRange( $address, $killExpired = true ) |
| 170 | + { |
| 171 | + $fname = 'Block::loadRange'; |
| 172 | + |
| 173 | + $iaddr = wfIP2Hex( $address ); |
| 174 | + if ( $iaddr === false ) { |
| 175 | + # Invalid address |
| 176 | + return false; |
| 177 | + } |
| 178 | + |
| 179 | + # Only scan ranges which start in this /16, this improves search speed |
| 180 | + # Blocks should not cross a /16 boundary. |
| 181 | + $range = substr( $iaddr, 0, 4 ); |
| 182 | + |
| 183 | + $options = ''; |
| 184 | + $db =& $this->getDBOptions( $options ); |
| 185 | + $ipblocks = $db->tableName( 'ipblocks' ); |
| 186 | + $sql = "SELECT * FROM $ipblocks WHERE ipb_range_start LIKE '$range%' ". |
| 187 | + "AND ipb_range_start <= '$iaddr' AND ipb_range_end >= '$iaddr' $options"; |
| 188 | + $res = $db->query( $sql, $fname ); |
| 189 | + $row = $db->fetchObject( $res ); |
| 190 | + |
| 191 | + $success = false; |
| 192 | + if ( $row ) { |
| 193 | + # Found a row, initialise this object |
| 194 | + $this->initFromRow( $row ); |
| 195 | + |
| 196 | + # Is it expired? |
| 197 | + if ( !$killExpired || !$this->deleteIfExpired() ) { |
| 198 | + # No, return true |
| 199 | + $success = true; |
| 200 | + } |
| 201 | + } |
| 202 | + |
| 203 | + $db->freeResult( $res ); |
| 204 | + return $success; |
| 205 | + } |
| 206 | + |
| 207 | + /** |
| 208 | + * Determine if a given integer IPv4 address is in a given CIDR network |
| 209 | + */ |
| 210 | + function isAddressInRange( $addr, $range ) { |
| 211 | + list( $network, $bits ) = wfParseCIDR( $range ); |
| 212 | + if ( $network !== false && $addr >> ( 32 - $bits ) == $network >> ( 32 - $bits ) ) { |
| 213 | + return true; |
| 214 | + } else { |
| 215 | + return false; |
| 216 | + } |
| 217 | + } |
| 218 | + |
144 | 219 | function initFromRow( $row ) |
145 | 220 | { |
146 | 221 | $this->mAddress = $row->ipb_address; |
— | — | @@ -157,24 +232,21 @@ |
158 | 233 | } else { |
159 | 234 | $this->mByName = false; |
160 | 235 | } |
161 | | - |
162 | | - $this->initialiseRange(); |
| 236 | + $this->mRangeStart = $row->ipb_range_start; |
| 237 | + $this->mRangeEnd = $row->ipb_range_end; |
163 | 238 | } |
164 | 239 | |
165 | 240 | function initialiseRange() |
166 | 241 | { |
| 242 | + $this->mRangeStart = ''; |
| 243 | + $this->mRangeEnd = ''; |
167 | 244 | if ( $this->mUser == 0 ) { |
168 | | - $rangeParts = explode( '/', $this->mAddress ); |
169 | | - if ( count( $rangeParts ) == 2 ) { |
170 | | - $this->mNetworkBits = $rangeParts[1]; |
171 | | - } else { |
172 | | - $this->mNetworkBits = 32; |
| 245 | + list( $network, $bits ) = wfParseCIDR( $this->mAddress ); |
| 246 | + if ( $network !== false ) { |
| 247 | + $this->mRangeStart = sprintf( '%08X', $network ); |
| 248 | + $this->mRangeEnd = sprintf( '%08X', $network + (1 << (32 - $bits)) - 1 ); |
173 | 249 | } |
174 | | - $this->mIntegerAddr = ip2long( $rangeParts[0] ); |
175 | | - } else { |
176 | | - $this->mNetworkBits = false; |
177 | | - $this->mIntegerAddr = false; |
178 | | - } |
| 250 | + } |
179 | 251 | } |
180 | 252 | |
181 | 253 | /** |
— | — | @@ -199,7 +271,7 @@ |
200 | 272 | $options = ''; |
201 | 273 | } |
202 | 274 | if ( $flags & EB_RANGE_ONLY ) { |
203 | | - $cond = " AND ipb_address LIKE '%/%'"; |
| 275 | + $cond = " AND ipb_range_start <> ''"; |
204 | 276 | } else { |
205 | 277 | $cond = ''; |
206 | 278 | } |
— | — | @@ -215,7 +287,7 @@ |
216 | 288 | |
217 | 289 | while ( $row = $db->fetchObject( $res ) ) { |
218 | 290 | $block->initFromRow( $row ); |
219 | | - if ( ( $flags & EB_RANGE_ONLY ) && $block->getNetworkBits() == 32 ) { |
| 291 | + if ( ( $flags & EB_RANGE_ONLY ) && $block->mRangeStart == '' ) { |
220 | 292 | continue; |
221 | 293 | } |
222 | 294 | |
— | — | @@ -247,7 +319,6 @@ |
248 | 320 | $condition = array( 'ipb_address' => $this->mAddress ); |
249 | 321 | } |
250 | 322 | $dbw->delete( 'ipblocks', $condition, $fname ); |
251 | | - $this->clearCache(); |
252 | 323 | } |
253 | 324 | |
254 | 325 | function insert() |
— | — | @@ -267,10 +338,10 @@ |
268 | 339 | 'ipb_expiry' => $this->mExpiry ? |
269 | 340 | $dbw->timestamp($this->mExpiry) : |
270 | 341 | $this->mExpiry, |
| 342 | + 'ipb_range_start' => $this->mRangeStart, |
| 343 | + 'ipb_range_end' => $this->mRangeEnd, |
271 | 344 | ), 'Block::insert' |
272 | 345 | ); |
273 | | - |
274 | | - $this->clearCache(); |
275 | 346 | } |
276 | 347 | |
277 | 348 | function deleteIfExpired() |
— | — | @@ -319,19 +390,10 @@ |
320 | 391 | 'ipb_address' => $this->mAddress |
321 | 392 | ), 'Block::updateTimestamp' |
322 | 393 | ); |
323 | | - |
324 | | - $this->clearCache(); |
325 | 394 | } |
326 | 395 | } |
327 | 396 | |
328 | | - /* private */ function clearCache() |
329 | | - { |
330 | | - global $wgBlockCache; |
331 | | - if ( is_object( $wgBlockCache ) ) { |
332 | | - $wgBlockCache->loadFromDB(); |
333 | | - } |
334 | | - } |
335 | | - |
| 397 | + /* |
336 | 398 | function getIntegerAddr() |
337 | 399 | { |
338 | 400 | return $this->mIntegerAddr; |
— | — | @@ -340,7 +402,7 @@ |
341 | 403 | function getNetworkBits() |
342 | 404 | { |
343 | 405 | return $this->mNetworkBits; |
344 | | - } |
| 406 | + }*/ |
345 | 407 | |
346 | 408 | function getByName() |
347 | 409 | { |
— | — | @@ -354,6 +416,10 @@ |
355 | 417 | return wfSetVar( $this->mForUpdate, $x ); |
356 | 418 | } |
357 | 419 | |
| 420 | + function fromMaster( $x = NULL ) { |
| 421 | + return wfSetVar( $this->mFromMaster, $x ); |
| 422 | + } |
| 423 | + |
358 | 424 | /* static */ function getAutoblockExpiry( $timestamp ) |
359 | 425 | { |
360 | 426 | global $wgAutoblockExpiry; |
— | — | @@ -365,7 +431,7 @@ |
366 | 432 | $parts = explode( '/', $range ); |
367 | 433 | if ( count( $parts ) == 2 ) { |
368 | 434 | $shift = 32 - $parts[1]; |
369 | | - $ipint = ip2long( $parts[0] ); |
| 435 | + $ipint = wfIP2Unsigned( $parts[0] ); |
370 | 436 | $ipint = $ipint >> $shift << $shift; |
371 | 437 | $newip = long2ip( $ipint ); |
372 | 438 | $range = "$newip/{$parts[1]}"; |