FOR UPDATE mode for Article class, and for getArticleID function of Title. Using...
[lhc/web/wiklou.git] / includes / Block.php
1 <?php
2 # Blocks and bans object
3 #
4 #TODO: This could be used everywhere, but it isn't.
5 #
6 # All the functions in this class assume the object is either explicitly
7 # loaded or filled. It is not load-on-demand. There are no accessors.
8 #
9 # To use delete(), you only need to fill $mAddress
10
11 # Globals used: $wgBlockCache, $wgAutoblockExpiry
12
13 define ( 'EB_KEEP_EXPIRED', 1 );
14 define ( 'EB_FOR_UPDATE', 2 );
15
16 class Block
17 {
18 /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry;
19 /* private */ var $mNetworkBits, $mIntegerAddr, $mForUpdate;
20
21 function Block( $address = '', $user = '', $by = 0, $reason = '',
22 $timestamp = '' , $auto = 0, $expiry = '' )
23 {
24 $this->mAddress = $address;
25 $this->mUser = $user;
26 $this->mBy = $by;
27 $this->mReason = $reason;
28 $this->mTimestamp = $timestamp;
29 $this->mAuto = $auto;
30 $this->mExpiry = $expiry;
31
32 $this->mForUpdate = false;
33 $this->initialiseRange();
34 }
35
36 /*static*/ function newFromDB( $address, $user = 0, $killExpired = true )
37 {
38 $ban = new Block();
39 $ban->load( $address, $user, $killExpired );
40 return $ban;
41 }
42
43 function clear()
44 {
45 $mAddress = $mReason = $mTimestamp = '';
46 $mUser = $mBy = 0;
47 }
48
49 # Get a ban from the DB, with either the given address or the given username
50 function load( $address = "", $user = 0, $killExpired = true )
51 {
52 $fname = 'Block::load';
53
54 $ret = false;
55 $killed = false;
56 if ( $this->forUpdate() ) {
57 $db =& wfGetDB( DB_MASTER );
58 $options = 'FOR UPDATE';
59 } else {
60 $db =& wfGetDB( DB_SLAVE );
61 $options = '';
62 }
63 $ipblocks = $db->tableName( 'ipblocks' );
64
65 if ( 0 == $user && $address=="" ) {
66 $sql = "SELECT * from $ipblocks $options";
67 } elseif ($address=="") {
68 $sql = "SELECT * FROM $ipblocks WHERE ipb_user={$user} $options";
69 } elseif ($user=="") {
70 $sql = "SELECT * FROM $ipblocks WHERE ipb_address='" . $db->strencode( $address ) . "' $options";
71 } else {
72 $sql = "SELECT * FROM $ipblocks WHERE (ipb_address='" . $db->strencode( $address ) .
73 "' OR ipb_user={$user}) $options";
74 }
75
76 $res = $db->query( $sql, $fname );
77 if ( 0 == $db->numRows( $res ) ) {
78 # User is not blocked
79 $this->clear();
80 } else {
81 # Get first block
82 $row = $db->fetchObject( $res );
83 $this->initFromRow( $row );
84
85 if ( $killExpired ) {
86 # If requested, delete expired rows
87 do {
88 $killed = $this->deleteIfExpired();
89 if ( $killed ) {
90 $row = $db->fetchObject( $res );
91 if ( $row ) {
92 $this->initFromRow( $row );
93 }
94 }
95 } while ( $killed && $row );
96
97 # If there were any left after the killing finished, return true
98 if ( !$row ) {
99 $ret = false;
100 $this->clear();
101 } else {
102 $ret = true;
103 }
104 } else {
105 $ret = true;
106 }
107 }
108 $db->freeResult( $res );
109 return $ret;
110 }
111
112 function initFromRow( $row )
113 {
114 $this->mAddress = $row->ipb_address;
115 $this->mReason = $row->ipb_reason;
116 $this->mTimestamp = $row->ipb_timestamp;
117 $this->mUser = $row->ipb_user;
118 $this->mBy = $row->ipb_by;
119 $this->mAuto = $row->ipb_auto;
120 $this->mId = $row->ipb_id;
121 $this->mExpiry = $row->ipb_expiry;
122
123 $this->initialiseRange();
124 }
125
126 function initialiseRange()
127 {
128 if ( $this->mUser == 0 ) {
129 $rangeParts = explode( '/', $this->mAddress );
130 if ( count( $rangeParts ) == 2 ) {
131 $this->mNetworkBits = $rangeParts[1];
132 } else {
133 $this->mNetworkBits = 32;
134 }
135 $this->mIntegerAddr = ip2long( $rangeParts[0] );
136 } else {
137 $this->mNetworkBits = false;
138 $this->mIntegerAddr = false;
139 }
140 }
141
142 # Callback with a Block object for every block
143 /*static*/ function enumBlocks( $callback, $tag, $flags = 0 )
144 {
145 $block = new Block();
146 if ( $flags & EB_FOR_UPDATE ) {
147 $db =& wfGetDB( DB_MASTER );
148 $options = 'FOR UPDATE';
149 $block->forUpdate( true );
150 } else {
151 $db =& wfGetDB( DB_SLAVE );
152 $options = '';
153 }
154 $ipblocks = $db->tableName( 'ipblocks' );
155
156 $sql = "SELECT * FROM $ipblocks ORDER BY ipb_timestamp DESC $options";
157 $res = $db->query( $sql, 'Block::enumBans' );
158
159 while ( $row = $db->fetchObject( $res ) ) {
160 $block->initFromRow( $row );
161 if ( !( $flags & EB_KEEP_EXPIRED ) ) {
162 if ( !$block->deleteIfExpired() ) {
163 $callback( $block, $tag );
164 }
165 } else {
166 $callback( $block, $tag );
167 }
168 }
169 wfFreeResult( $res );
170 }
171
172 function delete()
173 {
174 $fname = 'Block::delete';
175 $dbw =& wfGetDB( DB_MASTER );
176
177 if ( $this->mAddress == "" ) {
178 $condition = array( 'ipb_id' => $this->mId );
179 } else {
180 $condition = array( 'ipb_address' => $this->mAddress );
181 }
182 $dbw->delete( 'ipblocks', $condition, $fname );
183 $this->clearCache();
184 }
185
186 function insert()
187 {
188 $dbw =& wfGetDB( DB_MASTER );
189 $dbw->insertArray( 'ipblocks',
190 array(
191 'ipb_address' => $this->mAddress,
192 'ipb_user' => $this->mUser,
193 'ipb_by' => $this->mBy,
194 'ipb_reason' => $this->mReason,
195 'ipb_timestamp' => $this->mTimestamp,
196 'ipb_auto' => $this->mAuto,
197 'ipb_expiry' => $this->mExpiry,
198 ), 'Block::insert'
199 );
200
201 $this->clearCache();
202 }
203
204 function deleteIfExpired()
205 {
206 if ( $this->isExpired() ) {
207 $this->delete();
208 return true;
209 } else {
210 return false;
211 }
212 }
213
214 function isExpired()
215 {
216 if ( !$this->mExpiry ) {
217 return false;
218 } else {
219 return wfTimestampNow() > $this->mExpiry;
220 }
221 }
222
223 function isValid()
224 {
225 return $this->mAddress != '';
226 }
227
228 function updateTimestamp()
229 {
230 if ( $this->mAuto ) {
231 $this->mTimestamp = wfTimestampNow();
232 $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
233
234 $dbw =& wfGetDB( DB_MASTER );
235 $dbw->updateArray( 'ipblocks',
236 array( /* SET */
237 'ipb_timestamp' => $this->mTimestamp,
238 'ipb_expiry' => $this->mExpiry,
239 ), array( /* WHERE */
240 'ipb_address' => $this->mAddress
241 ), 'Block::updateTimestamp'
242 );
243
244 $this->clearCache();
245 }
246 }
247
248 /* private */ function clearCache()
249 {
250 global $wgBlockCache;
251 if ( is_object( $wgBlockCache ) ) {
252 $wgBlockCache->loadFromDB();
253 }
254 }
255
256 function getIntegerAddr()
257 {
258 return $this->mIntegerAddr;
259 }
260
261 function getNetworkBits()
262 {
263 return $this->mNetworkBits;
264 }
265
266 function forUpdate( $x = NULL ) {
267 return wfSetVar( $this->mForUpdate, $x );
268 }
269
270 /* static */ function getAutoblockExpiry( $timestamp )
271 {
272 global $wgAutoblockExpiry;
273 return wfUnix2Timestamp( wfTimestamp2Unix( $timestamp ) + $wgAutoblockExpiry );
274 }
275
276 /* static */ function normaliseRange( $range )
277 {
278 $parts = explode( '/', $range );
279 if ( count( $parts ) == 2 ) {
280 $shift = 32 - $parts[1];
281 $ipint = ip2long( $parts[0] );
282 $ipint = $ipint >> $shift << $shift;
283 $newip = long2ip( $ipint );
284 $range = "$newip/{$parts[1]}";
285 }
286 return $range;
287 }
288
289 }
290 ?>