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 | namespace dokuwiki\Ui; |
||
4 | |||
5 | use dokuwiki\ChangeLog\PageChangeLog; |
||
6 | use dokuwiki\ChangeLog\MediaChangeLog; |
||
7 | use dokuwiki\Form\Form; |
||
8 | |||
9 | /** |
||
10 | * DokuWiki Revisions Interface |
||
11 | * |
||
12 | * @package dokuwiki\Ui |
||
13 | */ |
||
14 | class Revisions extends Ui |
||
15 | { |
||
16 | protected $first; |
||
17 | protected $media_id; |
||
18 | |||
19 | /** |
||
20 | * Revisions Ui constructor |
||
21 | * |
||
22 | * @param int $first skip the first n changelog lines |
||
23 | * @param bool|string $media_id id of media, or false for current page |
||
24 | */ |
||
25 | public function __construct($first = 0, $media_id = false) |
||
26 | { |
||
27 | $this->first = $first; |
||
28 | $this->media_id = $media_id; |
||
29 | } |
||
30 | |||
31 | /** |
||
32 | * Display list of old revisions |
||
33 | * |
||
34 | * @author Andreas Gohr <[email protected]> |
||
35 | * @author Ben Coburn <[email protected]> |
||
36 | * @author Kate Arzamastseva <[email protected]> |
||
37 | * @author Satoshi Sahara <[email protected]> |
||
38 | * |
||
39 | * @return void |
||
40 | */ |
||
41 | public function show() |
||
42 | { |
||
43 | global $ID; |
||
44 | |||
45 | if ($this->media_id) { |
||
46 | return $this->showMediaRevisions($this->media_id); |
||
0 ignored issues
–
show
|
|||
47 | } else { |
||
48 | return $this->showPageRevisions($ID); |
||
49 | } |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Display a list of Media Revisions in the MediaManager |
||
54 | * |
||
55 | * @param string $id media id |
||
56 | * @return void |
||
57 | */ |
||
58 | protected function showMediaRevisions($id) |
||
59 | { |
||
60 | global $lang; |
||
61 | |||
62 | // get revisions, and set correct pagenation parameters (first, hasNext) |
||
63 | $first = $this->first; |
||
64 | $hasNext = false; |
||
65 | $revisions = $this->getRevisions($first, $hasNext); |
||
66 | |||
67 | // create the form |
||
68 | $form = new Form([ |
||
69 | 'id' => 'page__revisions', // must not be "media__revisions" |
||
70 | 'action' => media_managerURL(['image' => $id], '&'), |
||
71 | 'class' => 'changes', |
||
72 | ]); |
||
73 | $form->setHiddenField('mediado', 'diff'); // required for media revisions |
||
74 | $form->addTagOpen('div')->addClass('no'); |
||
75 | |||
76 | // start listing |
||
77 | $form->addTagOpen('ul'); |
||
78 | foreach ($revisions as $info) { |
||
79 | $rev = $info['date']; |
||
80 | $class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : ''; |
||
81 | $form->addTagOpen('li')->addClass($class); |
||
82 | $form->addTagOpen('div')->addClass('li'); |
||
83 | |||
84 | if (isset($info['current'])) { |
||
85 | $form->addCheckbox('rev2[]')->val('current'); |
||
86 | } elseif (file_exists(mediaFN($id, $rev))) { |
||
87 | $form->addCheckbox('rev2[]')->val($rev); |
||
88 | } else { |
||
89 | $form->addCheckbox('')->val($rev)->attr('disabled','disabled'); |
||
90 | } |
||
91 | $form->addHTML(' '); |
||
92 | |||
93 | $objRevInfo = $this->getObjRevInfo($info); |
||
94 | $html = implode(' ', [ |
||
95 | $objRevInfo->editDate(), // edit date and time |
||
96 | $objRevInfo->difflink(), // link to diffview icon |
||
97 | $objRevInfo->itemName(), // name of page or media |
||
98 | '<div>', |
||
99 | $objRevInfo->editSummary(), // edit summary |
||
100 | $objRevInfo->editor(), // editor info |
||
101 | html_sizechange($info['sizechange']), // size change indicator |
||
102 | $objRevInfo->currentIndicator(), // current indicator (only when k=1) |
||
103 | '</div>', |
||
104 | ]); |
||
105 | $form->addHTML($html); |
||
106 | |||
107 | $form->addTagClose('div'); |
||
108 | $form->addTagClose('li'); |
||
109 | } |
||
110 | $form->addTagClose('ul'); // end of revision list |
||
111 | |||
112 | // show button for diff view |
||
113 | $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit'); |
||
114 | |||
115 | $form->addTagClose('div'); // close div class=no |
||
116 | |||
117 | print $form->toHTML('Revisions'); |
||
118 | |||
119 | // provide navigation for pagenated revision list (of pages and/or media files) |
||
120 | print $this->htmlNavigation($id, $first, $hasNext); |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Display a list of Page Revisions |
||
125 | * |
||
126 | * @return void |
||
127 | */ |
||
128 | protected function showPageRevisions($id) |
||
129 | { |
||
130 | global $lang; |
||
131 | |||
132 | // get revisions, and set correct pagenation parameters (first, hasNext) |
||
133 | $first = $this->first; |
||
134 | $hasNext = false; |
||
135 | $revisions = $this->getRevisions($first, $hasNext); |
||
136 | |||
137 | // print intro |
||
138 | print p_locale_xhtml('revisions'); |
||
139 | |||
140 | // create the form |
||
141 | $form = new Form([ |
||
142 | 'id' => 'page__revisions', |
||
143 | 'class' => 'changes', |
||
144 | ]); |
||
145 | $form->addTagOpen('div')->addClass('no'); |
||
146 | |||
147 | // start listing |
||
148 | $form->addTagOpen('ul'); |
||
149 | foreach ($revisions as $info) { |
||
150 | $rev = $info['date']; |
||
151 | $class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : ''; |
||
152 | $form->addTagOpen('li')->addClass($class); |
||
153 | $form->addTagOpen('div')->addClass('li'); |
||
154 | |||
155 | if (page_exists($id, $rev)) { |
||
156 | $form->addCheckbox('rev2[]')->val($rev); |
||
157 | } else { |
||
158 | $form->addCheckbox('')->val($rev)->attr('disabled','disabled'); |
||
159 | } |
||
160 | $form->addHTML(' '); |
||
161 | |||
162 | $objRevInfo = $this->getObjRevInfo($info); |
||
163 | $html = implode(' ', [ |
||
164 | $objRevInfo->editDate(), // edit date and time |
||
165 | $objRevInfo->difflink(), // link to diffview icon |
||
166 | $objRevInfo->itemName(), // name of page or media |
||
167 | $objRevInfo->editSummary(), // edit summary |
||
168 | $objRevInfo->editor(), // editor info |
||
169 | $objRevInfo->sizechange(), // size change indicator |
||
170 | $objRevInfo->currentIndicator(), // current indicator (only when k=1) |
||
171 | ]); |
||
172 | $form->addHTML($html); |
||
173 | $form->addTagClose('div'); |
||
174 | $form->addTagClose('li'); |
||
175 | } |
||
176 | $form->addTagClose('ul'); // end of revision list |
||
177 | |||
178 | // show button for diff view |
||
179 | $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit'); |
||
180 | |||
181 | $form->addTagClose('div'); // close div class=no |
||
182 | |||
183 | print $form->toHTML('Revisions'); |
||
184 | |||
185 | // provide navigation for pagenated revision list (of pages and/or media files) |
||
186 | print $this->htmlNavigation($id, $first, $hasNext); |
||
187 | } |
||
188 | |||
189 | |||
190 | /** |
||
191 | * Get revisions, and set correct pagenation parameters (first, hasNext) |
||
192 | * |
||
193 | * @param int $first |
||
194 | * @param bool $hasNext |
||
195 | * @return array revisions to be shown in a pagenated list |
||
196 | * @see also https://www.dokuwiki.org/devel:changelog |
||
197 | */ |
||
198 | protected function getRevisions(&$first, &$hasNext) |
||
199 | { |
||
200 | global $INFO, $conf; |
||
201 | |||
202 | if ($this->media_id) { |
||
203 | $changelog = new MediaChangeLog($this->media_id); |
||
0 ignored issues
–
show
It seems like
$this->media_id can also be of type boolean ; however, dokuwiki\ChangeLog\ChangeLog::__construct() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
204 | } else { |
||
205 | $changelog = new PageChangeLog($INFO['id']); |
||
206 | } |
||
207 | |||
208 | $revisions = []; |
||
209 | |||
210 | /* we need to get one additional log entry to be able to |
||
211 | * decide if this is the last page or is there another one. |
||
212 | * see also Ui\Recent::getRecents() |
||
213 | */ |
||
214 | $revlist = $changelog->getRevisions($first, $conf['recent'] +1); |
||
215 | if (count($revlist) == 0 && $first != 0) { |
||
216 | $first = 0; |
||
217 | $revlist = $changelog->getRevisions($first, $conf['recent'] +1); |
||
218 | } |
||
219 | $exists = ($this->media_id) ? file_exists(mediaFN($this->media_id)) : $INFO['exists']; |
||
0 ignored issues
–
show
It seems like
$this->media_id can also be of type boolean ; however, mediaFN() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
220 | if ($first === 0 && $exists) { |
||
221 | // add current page or media as revision[0] |
||
222 | if ($this->media_id) { |
||
223 | $rev = filemtime(fullpath(mediaFN($this->media_id))); |
||
0 ignored issues
–
show
It seems like
$this->media_id can also be of type boolean ; however, mediaFN() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
224 | $changelog->setChunkSize(1024); |
||
225 | $revinfo = $changelog->getRevisionInfo($rev) ?: array( |
||
226 | 'date' => $rev, |
||
227 | 'ip' => null, |
||
228 | 'type' => null, |
||
229 | 'id' => $this->media_id, |
||
230 | 'user' => null, |
||
231 | 'sum' => null, |
||
232 | 'extra' => null, |
||
233 | 'sizechange' => null, |
||
234 | ); |
||
235 | $revisions[] = $revinfo + array( |
||
236 | 'media' => true, |
||
237 | 'current' => true, |
||
238 | ); |
||
239 | } else { |
||
240 | if (isset($INFO['meta']['last_change'])) { |
||
241 | $type = $INFO['meta']['last_change']['type']; |
||
242 | $sizechange = $INFO['meta']['last_change']['sizechange']; |
||
243 | } else { |
||
244 | $type = $sizechange = null; |
||
245 | } |
||
246 | |||
247 | $revisions[] = array( |
||
248 | 'date' => $INFO['lastmod'], |
||
249 | 'ip' => null, |
||
250 | 'type' => $type, |
||
251 | 'id' => $INFO['id'], |
||
252 | 'user' => $INFO['editor'], |
||
253 | 'sum' => $INFO['sum'], |
||
254 | 'extra' => null, |
||
255 | 'sizechange' => $sizechange, |
||
256 | 'current' => true, |
||
257 | ); |
||
258 | } |
||
259 | } |
||
260 | |||
261 | // decide if this is the last page or is there another one |
||
262 | $hasNext = false; |
||
263 | if (count($revlist) > $conf['recent']) { |
||
264 | $hasNext = true; |
||
265 | array_pop($revlist); // remove one additional log entry |
||
266 | } |
||
267 | |||
268 | // append each revison info array to the revisions |
||
269 | foreach ($revlist as $rev) { |
||
270 | if ($this->media_id) { |
||
271 | $revisions[] = $changelog->getRevisionInfo($rev) + array('media' => true); |
||
272 | } else { |
||
273 | $revisions[] = $changelog->getRevisionInfo($rev); |
||
274 | } |
||
275 | } |
||
276 | return $revisions; |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Navigation buttons for Pagenation (prev/next) |
||
281 | * |
||
282 | * @param string $id page id or media id |
||
283 | * @param int $first |
||
284 | * @param bool $hasNext |
||
285 | * @return array html |
||
286 | */ |
||
287 | protected function htmlNavigation($id, $first, $hasNext) |
||
288 | { |
||
289 | global $conf; |
||
290 | |||
291 | $html = '<div class="pagenav">'; |
||
292 | $last = $first + $conf['recent']; |
||
293 | if ($first > 0) { |
||
294 | $first = max($first - $conf['recent'], 0); |
||
295 | $html.= '<div class="pagenav-prev">'; |
||
296 | if ($this->media_id) { |
||
297 | $html.= html_btn('newer', $id, "p", media_managerURL(['first' => $first], '&', false, true)); |
||
0 ignored issues
–
show
media_managerURL(array('...rst), '&', false, true) is of type string|array , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
298 | } else { |
||
299 | $html.= html_btn('newer', $id, "p" ,['do' => 'revisions', 'first' => $first]); |
||
300 | } |
||
301 | $html.= '</div>'; |
||
302 | } |
||
303 | if ($hasNext) { |
||
304 | $html.= '<div class="pagenav-next">'; |
||
305 | if ($this->media_id) { |
||
306 | $html.= html_btn('older', $id, "n", media_managerURL(['first' => $last], '&', false, true)); |
||
0 ignored issues
–
show
media_managerURL(array('...ast), '&', false, true) is of type string|array , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
307 | } else { |
||
308 | $html.= html_btn('older', $id, "n", ['do' => 'revisions', 'first' => $last]); |
||
309 | } |
||
310 | $html.= '</div>'; |
||
311 | } |
||
312 | $html.= '</div>'; |
||
313 | return $html; |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * Returns instance of objRevInfo |
||
318 | * |
||
319 | * @param array $info Revision info structure of a page or media file |
||
320 | * @return objRevInfo object (anonymous class) |
||
321 | */ |
||
322 | protected function getObjRevInfo(array $info) |
||
323 | { |
||
324 | return new class ($info) // anonymous class (objRevInfo) |
||
325 | { |
||
326 | protected $info; |
||
327 | |||
328 | public function __construct(array $info) |
||
329 | { |
||
330 | if (!isset($info['current'])) { |
||
331 | $info['current'] = false; |
||
332 | } |
||
333 | $this->info = $info; |
||
334 | } |
||
335 | |||
336 | // current indicator |
||
337 | public function currentIndicator() |
||
338 | { |
||
339 | global $lang; |
||
340 | return ($this->info['current']) ? '('.$lang['current'].')' : ''; |
||
341 | } |
||
342 | |||
343 | // edit date and time of the page or media file |
||
344 | public function editDate() |
||
345 | { |
||
346 | return '<span class="date">'. dformat($this->info['date']) .'</span>'; |
||
347 | } |
||
348 | |||
349 | // edit summary |
||
350 | public function editSummary() |
||
351 | { |
||
352 | return '<span class="sum">'.' – '. hsc($this->info['sum']).'</span>'; |
||
353 | } |
||
354 | |||
355 | // editor of the page or media file |
||
356 | public function editor() |
||
357 | { |
||
358 | // slightly different with display of Ui\Recent, i.e. external edit |
||
359 | global $lang; |
||
360 | $html = '<span class="user">'; |
||
361 | if (!$this->info['user'] && !$this->info['ip']) { |
||
362 | $html.= '('.$lang['external_edit'].')'; |
||
363 | } elseif ($this->info['user']) { |
||
364 | $html.= '<bdi>'. editorinfo($this->info['user']) .'</bdi>'; |
||
365 | if (auth_ismanager()) $html.= ' <bdo dir="ltr">('. $this->info['ip'] .')</bdo>'; |
||
366 | } else { |
||
367 | $html.= '<bdo dir="ltr">'. $this->info['ip'] .'</bdo>'; |
||
368 | } |
||
369 | $html.= '</span>'; |
||
370 | return $html; |
||
371 | } |
||
372 | |||
373 | // name of the page or media file |
||
374 | public function itemName() |
||
375 | { |
||
376 | // slightly different with display of Ui\Recent, i.e. revison may not exists |
||
377 | $id = $this->info['id']; |
||
378 | $rev = $this->info['date']; |
||
379 | |||
380 | if (isset($this->info['media'])) { |
||
381 | // media file revision |
||
382 | if (isset($this->info['current'])) { |
||
383 | $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view'], '&'); |
||
384 | $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; |
||
385 | } elseif (file_exists(mediaFN($id, $rev))) { |
||
386 | $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view', 'rev'=> $rev], '&'); |
||
387 | $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; |
||
388 | } else { |
||
389 | $html = $id; |
||
390 | } |
||
391 | return $html; |
||
392 | } else { |
||
393 | // page revision |
||
394 | $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id; |
||
395 | if (!$display_name) $display_name = $id; |
||
396 | if ($this->info['current'] || page_exists($id, $rev)) { |
||
397 | $href = wl($id, "rev=$rev", false, '&'); |
||
398 | $html = '<a href="'.$href.'" class="wikilink1">'.$display_name.'</a>'; |
||
399 | } else { |
||
400 | $html = $display_name; |
||
401 | } |
||
402 | return $html; |
||
403 | } |
||
404 | } |
||
405 | |||
406 | // icon difflink |
||
407 | public function difflink() |
||
408 | { |
||
409 | global $lang; |
||
410 | $id = $this->info['id']; |
||
411 | $rev = $this->info['date']; |
||
412 | |||
413 | if (isset($this->info['media'])) { |
||
414 | // media file revision |
||
415 | if (isset($this->info['current']) || !file_exists(mediaFN($id, $rev))) { |
||
416 | $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; |
||
417 | } else { |
||
418 | $href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&'); |
||
419 | $html = '<a href="'.$href.'" class="diff_link">' |
||
420 | . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' |
||
421 | . ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />' |
||
422 | . '</a> '; |
||
423 | } |
||
424 | return $html; |
||
425 | } else { |
||
426 | // page revision |
||
427 | if ($this->info['current'] || !page_exists($id, $rev)) { |
||
428 | $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; |
||
429 | } else { |
||
430 | $href = wl($id, "rev=$rev,do=diff", false, '&'); |
||
431 | $html = '<a href="'.$href.'" class="diff_link">' |
||
432 | . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' |
||
433 | . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />' |
||
434 | . '</a>'; |
||
435 | } |
||
436 | return $html; |
||
437 | } |
||
438 | } |
||
439 | |||
440 | // size change |
||
441 | public function sizeChange() |
||
442 | { |
||
443 | $class = 'sizechange'; |
||
444 | $value = filesize_h(abs($this->info['sizechange'])); |
||
445 | if ($this->info['sizechange'] > 0) { |
||
446 | $class .= ' positive'; |
||
447 | $value = '+' . $value; |
||
448 | } elseif ($this->info['sizechange'] < 0) { |
||
449 | $class .= ' negative'; |
||
450 | $value = '-' . $value; |
||
451 | } else { |
||
452 | $value = '±' . $value; |
||
453 | } |
||
454 | return '<span class="'.$class.'">'.$value.'</span>'; |
||
455 | } |
||
456 | }; // end of anonymous class (objRevInfo) |
||
457 | } |
||
458 | |||
459 | } |
||
460 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.