This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Contain log classes |
||
4 | * |
||
5 | * Copyright © 2002, 2004 Brion Vibber <[email protected]> |
||
6 | * https://www.mediawiki.org/ |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or modify |
||
9 | * it under the terms of the GNU General Public License as published by |
||
10 | * the Free Software Foundation; either version 2 of the License, or |
||
11 | * (at your option) any later version. |
||
12 | * |
||
13 | * This program is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU General Public License along |
||
19 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
21 | * http://www.gnu.org/copyleft/gpl.html |
||
22 | * |
||
23 | * @file |
||
24 | */ |
||
25 | |||
26 | /** |
||
27 | * Class to simplify the use of log pages. |
||
28 | * The logs are now kept in a table which is easier to manage and trim |
||
29 | * than ever-growing wiki pages. |
||
30 | * |
||
31 | */ |
||
32 | class LogPage { |
||
33 | const DELETED_ACTION = 1; |
||
34 | const DELETED_COMMENT = 2; |
||
35 | const DELETED_USER = 4; |
||
36 | const DELETED_RESTRICTED = 8; |
||
37 | |||
38 | // Convenience fields |
||
39 | const SUPPRESSED_USER = 12; |
||
40 | const SUPPRESSED_ACTION = 9; |
||
41 | |||
42 | /** @var bool */ |
||
43 | public $updateRecentChanges; |
||
44 | |||
45 | /** @var bool */ |
||
46 | public $sendToUDP; |
||
47 | |||
48 | /** @var string Plaintext version of the message for IRC */ |
||
49 | private $ircActionText; |
||
50 | |||
51 | /** @var string Plaintext version of the message */ |
||
52 | private $actionText; |
||
53 | |||
54 | /** @var string One of '', 'block', 'protect', 'rights', 'delete', |
||
55 | * 'upload', 'move' |
||
56 | */ |
||
57 | private $type; |
||
58 | |||
59 | /** @var string One of '', 'block', 'protect', 'rights', 'delete', |
||
60 | * 'upload', 'move', 'move_redir' */ |
||
61 | private $action; |
||
62 | |||
63 | /** @var string Comment associated with action */ |
||
64 | private $comment; |
||
65 | |||
66 | /** @var string Blob made of a parameters array */ |
||
67 | private $params; |
||
68 | |||
69 | /** @var User The user doing the action */ |
||
70 | private $doer; |
||
71 | |||
72 | /** @var Title */ |
||
73 | private $target; |
||
74 | |||
75 | /** |
||
76 | * Constructor |
||
77 | * |
||
78 | * @param string $type One of '', 'block', 'protect', 'rights', 'delete', |
||
79 | * 'upload', 'move' |
||
80 | * @param bool $rc Whether to update recent changes as well as the logging table |
||
81 | * @param string $udp Pass 'UDP' to send to the UDP feed if NOT sent to RC |
||
82 | */ |
||
83 | public function __construct( $type, $rc = true, $udp = 'skipUDP' ) { |
||
84 | $this->type = $type; |
||
85 | $this->updateRecentChanges = $rc; |
||
86 | $this->sendToUDP = ( $udp == 'UDP' ); |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * @return int The log_id of the inserted log entry |
||
91 | */ |
||
92 | protected function saveContent() { |
||
93 | global $wgLogRestrictions; |
||
94 | |||
95 | $dbw = wfGetDB( DB_MASTER ); |
||
96 | $log_id = $dbw->nextSequenceValue( 'logging_log_id_seq' ); |
||
97 | |||
98 | // @todo FIXME private/protected/public property? |
||
99 | $this->timestamp = $now = wfTimestampNow(); |
||
0 ignored issues
–
show
|
|||
100 | $data = [ |
||
101 | 'log_id' => $log_id, |
||
102 | 'log_type' => $this->type, |
||
103 | 'log_action' => $this->action, |
||
104 | 'log_timestamp' => $dbw->timestamp( $now ), |
||
105 | 'log_user' => $this->doer->getId(), |
||
106 | 'log_user_text' => $this->doer->getName(), |
||
107 | 'log_namespace' => $this->target->getNamespace(), |
||
108 | 'log_title' => $this->target->getDBkey(), |
||
109 | 'log_page' => $this->target->getArticleID(), |
||
110 | 'log_comment' => $this->comment, |
||
111 | 'log_params' => $this->params |
||
112 | ]; |
||
113 | $dbw->insert( 'logging', $data, __METHOD__ ); |
||
114 | $newId = !is_null( $log_id ) ? $log_id : $dbw->insertId(); |
||
115 | |||
116 | # And update recentchanges |
||
117 | if ( $this->updateRecentChanges ) { |
||
118 | $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); |
||
119 | |||
120 | RecentChange::notifyLog( |
||
121 | $now, $titleObj, $this->doer, $this->getRcComment(), '', |
||
0 ignored issues
–
show
It seems like
$now defined by wfTimestampNow() on line 99 can also be of type false ; however, RecentChange::notifyLog() does only seem to accept string , did you maybe forget to handle an error condition?
This check looks for type mismatches where the missing type is Consider the follow example <?php
function getDate($date)
{
if ($date !== null) {
return new DateTime($date);
}
return false;
}
This function either returns a new ![]() |
|||
122 | $this->type, $this->action, $this->target, $this->comment, |
||
123 | $this->params, $newId, $this->getRcCommentIRC() |
||
124 | ); |
||
125 | } elseif ( $this->sendToUDP ) { |
||
126 | # Don't send private logs to UDP |
||
127 | if ( isset( $wgLogRestrictions[$this->type] ) && $wgLogRestrictions[$this->type] != '*' ) { |
||
128 | return $newId; |
||
129 | } |
||
130 | |||
131 | # Notify external application via UDP. |
||
132 | # We send this to IRC but do not want to add it the RC table. |
||
133 | $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); |
||
134 | $rc = RecentChange::newLogEntry( |
||
135 | $now, $titleObj, $this->doer, $this->getRcComment(), '', |
||
0 ignored issues
–
show
It seems like
$now defined by wfTimestampNow() on line 99 can also be of type false ; however, RecentChange::newLogEntry() does only seem to accept string , did you maybe forget to handle an error condition?
This check looks for type mismatches where the missing type is Consider the follow example <?php
function getDate($date)
{
if ($date !== null) {
return new DateTime($date);
}
return false;
}
This function either returns a new ![]() |
|||
136 | $this->type, $this->action, $this->target, $this->comment, |
||
137 | $this->params, $newId, $this->getRcCommentIRC() |
||
138 | ); |
||
139 | $rc->notifyRCFeeds(); |
||
140 | } |
||
141 | |||
142 | return $newId; |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * Get the RC comment from the last addEntry() call |
||
147 | * |
||
148 | * @return string |
||
149 | */ |
||
150 | View Code Duplication | public function getRcComment() { |
|
151 | $rcComment = $this->actionText; |
||
152 | |||
153 | if ( $this->comment != '' ) { |
||
154 | if ( $rcComment == '' ) { |
||
155 | $rcComment = $this->comment; |
||
156 | } else { |
||
157 | $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . |
||
158 | $this->comment; |
||
159 | } |
||
160 | } |
||
161 | |||
162 | return $rcComment; |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Get the RC comment from the last addEntry() call for IRC |
||
167 | * |
||
168 | * @return string |
||
169 | */ |
||
170 | View Code Duplication | public function getRcCommentIRC() { |
|
171 | $rcComment = $this->ircActionText; |
||
172 | |||
173 | if ( $this->comment != '' ) { |
||
174 | if ( $rcComment == '' ) { |
||
175 | $rcComment = $this->comment; |
||
176 | } else { |
||
177 | $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . |
||
178 | $this->comment; |
||
179 | } |
||
180 | } |
||
181 | |||
182 | return $rcComment; |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Get the comment from the last addEntry() call |
||
187 | * @return string |
||
188 | */ |
||
189 | public function getComment() { |
||
190 | return $this->comment; |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Get the list of valid log types |
||
195 | * |
||
196 | * @return array Array of strings |
||
197 | */ |
||
198 | public static function validTypes() { |
||
199 | global $wgLogTypes; |
||
200 | |||
201 | return $wgLogTypes; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Is $type a valid log type |
||
206 | * |
||
207 | * @param string $type Log type to check |
||
208 | * @return bool |
||
209 | */ |
||
210 | public static function isLogType( $type ) { |
||
211 | return in_array( $type, LogPage::validTypes() ); |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * Generate text for a log entry. |
||
216 | * Only LogFormatter should call this function. |
||
217 | * |
||
218 | * @param string $type Log type |
||
219 | * @param string $action Log action |
||
220 | * @param Title|null $title Title object or null |
||
221 | * @param Skin|null $skin Skin object or null. If null, we want to use the wiki |
||
222 | * content language, since that will go to the IRC feed. |
||
223 | * @param array $params Parameters |
||
224 | * @param bool $filterWikilinks Whether to filter wiki links |
||
225 | * @return string HTML |
||
226 | */ |
||
227 | public static function actionText( $type, $action, $title = null, $skin = null, |
||
228 | $params = [], $filterWikilinks = false |
||
229 | ) { |
||
230 | global $wgLang, $wgContLang, $wgLogActions; |
||
231 | |||
232 | if ( is_null( $skin ) ) { |
||
233 | $langObj = $wgContLang; |
||
234 | $langObjOrNull = null; |
||
235 | } else { |
||
236 | $langObj = $wgLang; |
||
237 | $langObjOrNull = $wgLang; |
||
238 | } |
||
239 | |||
240 | $key = "$type/$action"; |
||
241 | |||
242 | if ( isset( $wgLogActions[$key] ) ) { |
||
243 | if ( is_null( $title ) ) { |
||
244 | $rv = wfMessage( $wgLogActions[$key] )->inLanguage( $langObj )->escaped(); |
||
245 | } else { |
||
246 | $titleLink = self::getTitleLink( $type, $langObjOrNull, $title, $params ); |
||
247 | |||
248 | if ( count( $params ) == 0 ) { |
||
249 | $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink ) |
||
250 | ->inLanguage( $langObj )->escaped(); |
||
251 | } else { |
||
252 | array_unshift( $params, $titleLink ); |
||
253 | |||
254 | $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params ) |
||
255 | ->inLanguage( $langObj )->escaped(); |
||
256 | } |
||
257 | } |
||
258 | } else { |
||
259 | global $wgLogActionsHandlers; |
||
260 | |||
261 | if ( isset( $wgLogActionsHandlers[$key] ) ) { |
||
262 | $args = func_get_args(); |
||
263 | $rv = call_user_func_array( $wgLogActionsHandlers[$key], $args ); |
||
264 | } else { |
||
265 | wfDebug( "LogPage::actionText - unknown action $key\n" ); |
||
266 | $rv = "$action"; |
||
267 | } |
||
268 | } |
||
269 | |||
270 | // For the perplexed, this feature was added in r7855 by Erik. |
||
271 | // The feature was added because we liked adding [[$1]] in our log entries |
||
272 | // but the log entries are parsed as Wikitext on RecentChanges but as HTML |
||
273 | // on Special:Log. The hack is essentially that [[$1]] represented a link |
||
274 | // to the title in question. The first parameter to the HTML version (Special:Log) |
||
275 | // is that link in HTML form, and so this just gets rid of the ugly [[]]. |
||
276 | // However, this is a horrible hack and it doesn't work like you expect if, say, |
||
277 | // you want to link to something OTHER than the title of the log entry. |
||
278 | // The real problem, which Erik was trying to fix (and it sort-of works now) is |
||
279 | // that the same messages are being treated as both wikitext *and* HTML. |
||
280 | if ( $filterWikilinks ) { |
||
281 | $rv = str_replace( '[[', '', $rv ); |
||
282 | $rv = str_replace( ']]', '', $rv ); |
||
283 | } |
||
284 | |||
285 | return $rv; |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * @todo Document |
||
290 | * @param string $type |
||
291 | * @param Language|null $lang |
||
292 | * @param Title $title |
||
293 | * @param array $params |
||
294 | * @return string |
||
295 | */ |
||
296 | protected static function getTitleLink( $type, $lang, $title, &$params ) { |
||
297 | if ( !$lang ) { |
||
298 | return $title->getPrefixedText(); |
||
299 | } |
||
300 | |||
301 | if ( $title->isSpecialPage() ) { |
||
302 | list( $name, $par ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); |
||
303 | |||
304 | # Use the language name for log titles, rather than Log/X |
||
305 | if ( $name == 'Log' ) { |
||
306 | $logPage = new LogPage( $par ); |
||
307 | $titleLink = Linker::link( $title, $logPage->getName()->escaped() ); |
||
308 | $titleLink = wfMessage( 'parentheses' ) |
||
309 | ->inLanguage( $lang ) |
||
310 | ->rawParams( $titleLink ) |
||
311 | ->escaped(); |
||
312 | } else { |
||
313 | $titleLink = Linker::link( $title ); |
||
314 | } |
||
315 | } else { |
||
316 | $titleLink = Linker::link( $title ); |
||
317 | } |
||
318 | |||
319 | return $titleLink; |
||
320 | } |
||
321 | |||
322 | /** |
||
323 | * Add a log entry |
||
324 | * |
||
325 | * @param string $action One of '', 'block', 'protect', 'rights', 'delete', |
||
326 | * 'upload', 'move', 'move_redir' |
||
327 | * @param Title $target Title object |
||
328 | * @param string $comment Description associated |
||
329 | * @param array $params Parameters passed later to wfMessage function |
||
330 | * @param null|int|User $doer The user doing the action. null for $wgUser |
||
331 | * |
||
332 | * @return int The log_id of the inserted log entry |
||
333 | */ |
||
334 | public function addEntry( $action, $target, $comment, $params = [], $doer = null ) { |
||
335 | global $wgContLang; |
||
336 | |||
337 | if ( !is_array( $params ) ) { |
||
338 | $params = [ $params ]; |
||
339 | } |
||
340 | |||
341 | if ( $comment === null ) { |
||
342 | $comment = ''; |
||
343 | } |
||
344 | |||
345 | # Trim spaces on user supplied text |
||
346 | $comment = trim( $comment ); |
||
347 | |||
348 | # Truncate for whole multibyte characters. |
||
349 | $comment = $wgContLang->truncate( $comment, 255 ); |
||
350 | |||
351 | $this->action = $action; |
||
352 | $this->target = $target; |
||
353 | $this->comment = $comment; |
||
354 | $this->params = LogPage::makeParamBlob( $params ); |
||
355 | |||
356 | if ( $doer === null ) { |
||
357 | global $wgUser; |
||
358 | $doer = $wgUser; |
||
359 | } elseif ( !is_object( $doer ) ) { |
||
360 | $doer = User::newFromId( $doer ); |
||
361 | } |
||
362 | |||
363 | $this->doer = $doer; |
||
364 | |||
365 | $logEntry = new ManualLogEntry( $this->type, $action ); |
||
366 | $logEntry->setTarget( $target ); |
||
367 | $logEntry->setPerformer( $doer ); |
||
368 | $logEntry->setParameters( $params ); |
||
369 | // All log entries using the LogPage to insert into the logging table |
||
370 | // are using the old logging system and therefore the legacy flag is |
||
371 | // needed to say the LogFormatter the parameters have numeric keys |
||
372 | $logEntry->setLegacy( true ); |
||
373 | |||
374 | $formatter = LogFormatter::newFromEntry( $logEntry ); |
||
375 | $context = RequestContext::newExtraneousContext( $target ); |
||
376 | $formatter->setContext( $context ); |
||
377 | |||
378 | $this->actionText = $formatter->getPlainActionText(); |
||
379 | $this->ircActionText = $formatter->getIRCActionText(); |
||
380 | |||
381 | return $this->saveContent(); |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * Add relations to log_search table |
||
386 | * |
||
387 | * @param string $field |
||
388 | * @param array $values |
||
389 | * @param int $logid |
||
390 | * @return bool |
||
391 | */ |
||
392 | public function addRelations( $field, $values, $logid ) { |
||
393 | if ( !strlen( $field ) || empty( $values ) ) { |
||
394 | return false; // nothing |
||
395 | } |
||
396 | |||
397 | $data = []; |
||
398 | |||
399 | View Code Duplication | foreach ( $values as $value ) { |
|
400 | $data[] = [ |
||
401 | 'ls_field' => $field, |
||
402 | 'ls_value' => $value, |
||
403 | 'ls_log_id' => $logid |
||
404 | ]; |
||
405 | } |
||
406 | |||
407 | $dbw = wfGetDB( DB_MASTER ); |
||
408 | $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' ); |
||
409 | |||
410 | return true; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Create a blob from a parameter array |
||
415 | * |
||
416 | * @param array $params |
||
417 | * @return string |
||
418 | */ |
||
419 | public static function makeParamBlob( $params ) { |
||
420 | return implode( "\n", $params ); |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * Extract a parameter array from a blob |
||
425 | * |
||
426 | * @param string $blob |
||
427 | * @return array |
||
428 | */ |
||
429 | public static function extractParams( $blob ) { |
||
430 | if ( $blob === '' ) { |
||
431 | return []; |
||
432 | } else { |
||
433 | return explode( "\n", $blob ); |
||
434 | } |
||
435 | } |
||
436 | |||
437 | /** |
||
438 | * Name of the log. |
||
439 | * @return Message |
||
440 | * @since 1.19 |
||
441 | */ |
||
442 | public function getName() { |
||
443 | global $wgLogNames; |
||
444 | |||
445 | // BC |
||
446 | if ( isset( $wgLogNames[$this->type] ) ) { |
||
447 | $key = $wgLogNames[$this->type]; |
||
448 | } else { |
||
449 | $key = 'log-name-' . $this->type; |
||
450 | } |
||
451 | |||
452 | return wfMessage( $key ); |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * Description of this log type. |
||
457 | * @return Message |
||
458 | * @since 1.19 |
||
459 | */ |
||
460 | public function getDescription() { |
||
461 | global $wgLogHeaders; |
||
462 | // BC |
||
463 | if ( isset( $wgLogHeaders[$this->type] ) ) { |
||
464 | $key = $wgLogHeaders[$this->type]; |
||
465 | } else { |
||
466 | $key = 'log-description-' . $this->type; |
||
467 | } |
||
468 | |||
469 | return wfMessage( $key ); |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * Returns the right needed to read this log type. |
||
474 | * @return string |
||
475 | * @since 1.19 |
||
476 | */ |
||
477 | public function getRestriction() { |
||
478 | global $wgLogRestrictions; |
||
479 | if ( isset( $wgLogRestrictions[$this->type] ) ) { |
||
480 | $restriction = $wgLogRestrictions[$this->type]; |
||
481 | } else { |
||
482 | // '' always returns true with $user->isAllowed() |
||
483 | $restriction = ''; |
||
484 | } |
||
485 | |||
486 | return $restriction; |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * Tells if this log is not viewable by all. |
||
491 | * @return bool |
||
492 | * @since 1.19 |
||
493 | */ |
||
494 | public function isRestricted() { |
||
495 | $restriction = $this->getRestriction(); |
||
496 | |||
497 | return $restriction !== '' && $restriction !== '*'; |
||
498 | } |
||
499 | } |
||
500 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: