Failed Conditions
Push — psr2 ( 749c00...b8c09b )
by Andreas
06:25 queued 06:21
created

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * XML feed export
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 *
8
 * @global array $conf
9
 * @global Input $INPUT
10
 */
11
12
use dokuwiki\Cache\Cache;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Cache.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
13
use dokuwiki\ChangeLog\MediaChangeLog;
0 ignored issues
show
This use statement conflicts with another class in this namespace, MediaChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
14
use dokuwiki\ChangeLog\PageChangeLog;
0 ignored issues
show
This use statement conflicts with another class in this namespace, PageChangeLog.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
16
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
17
require_once(DOKU_INC.'inc/init.php');
18
19
//close session
20
session_write_close();
21
22
//feed disabled?
23
if(!actionOK('rss')) {
24
    http_status(404);
25
    echo '<error>RSS feed is disabled.</error>';
26
    exit;
27
}
28
29
// get params
30
$opt = rss_parseOptions();
31
32
// the feed is dynamic - we need a cache for each combo
33
// (but most people just use the default feed so it's still effective)
34
$key   = join('', array_values($opt)).'$'.$_SERVER['REMOTE_USER'].'$'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
35
$cache = new Cache($key, '.feed');
36
37
// prepare cache depends
38
$depends['files'] = getConfigFiles('main');
39
$depends['age']   = $conf['rss_update'];
40
$depends['purge'] = $INPUT->bool('purge');
41
42
// check cacheage and deliver if nothing has changed since last
43
// time or the update interval has not passed, also handles conditional requests
44
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
45
header('Pragma: public');
46
header('Content-Type: application/xml; charset=utf-8');
47
header('X-Robots-Tag: noindex');
48
if($cache->useCache($depends)) {
49
    http_conditionalRequest($cache->getTime());
50
    if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
51
    print $cache->retrieveCache();
52
    exit;
53
} else {
54
    http_conditionalRequest(time());
55
}
56
57
// create new feed
58
$rss                 = new UniversalFeedCreator();
59
$rss->title          = $conf['title'].(($opt['namespace']) ? ' '.$opt['namespace'] : '');
60
$rss->link           = DOKU_URL;
61
$rss->syndicationURL = DOKU_URL.'feed.php';
62
$rss->cssStyleSheet  = DOKU_URL.'lib/exe/css.php?s=feed';
0 ignored issues
show
The property cssStyleSheet does not seem to exist in UniversalFeedCreator.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
63
64
$image        = new FeedImage();
65
$image->title = $conf['title'];
66
$image->url   = tpl_getMediaFile(array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico'), true);
67
$image->link  = DOKU_URL;
68
$rss->image   = $image;
69
70
$data  = null;
71
$modes = array(
72
    'list'   => 'rssListNamespace',
73
    'search' => 'rssSearch',
74
    'recent' => 'rssRecentChanges'
75
);
76
if(isset($modes[$opt['feed_mode']])) {
77
    $data = $modes[$opt['feed_mode']]($opt);
78
} else {
79
    $eventData = array(
80
        'opt'  => &$opt,
81
        'data' => &$data,
82
    );
83
    $event     = new Doku_Event('FEED_MODE_UNKNOWN', $eventData);
84
    if($event->advise_before(true)) {
85
        echo sprintf('<error>Unknown feed mode %s</error>', hsc($opt['feed_mode']));
86
        exit;
87
    }
88
    $event->advise_after();
89
}
90
91
rss_buildItems($rss, $data, $opt);
92
$feed = $rss->createFeed($opt['feed_type']);
0 ignored issues
show
The call to FeedCreator::createFeed() has too many arguments starting with $opt['feed_type'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
93
94
// save cachefile
95
$cache->storeCache($feed);
96
97
// finally deliver
98
print $feed;
99
100
// ---------------------------------------------------------------- //
101
102
/**
103
 * Get URL parameters and config options and return an initialized option array
104
 *
105
 * @author Andreas Gohr <[email protected]>
106
 */
107
function rss_parseOptions() {
108
    global $conf;
109
    global $INPUT;
110
111
    $opt = array();
112
113
    foreach(array(
114
                // Basic feed properties
115
                // Plugins may probably want to add new values to these
116
                // properties for implementing own feeds
117
118
                // One of: list, search, recent
119
                'feed_mode'    => array('str', 'mode', 'recent'),
120
                // One of: diff, page, rev, current
121
                'link_to'      => array('str', 'linkto', $conf['rss_linkto']),
122
                // One of: abstract, diff, htmldiff, html
123
                'item_content' => array('str', 'content', $conf['rss_content']),
124
125
                // Special feed properties
126
                // These are only used by certain feed_modes
127
128
                // String, used for feed title, in list and rc mode
129
                'namespace'    => array('str', 'ns', null),
130
                // Positive integer, only used in rc mode
131
                'items'        => array('int', 'num', $conf['recent']),
132
                // Boolean, only used in rc mode
133
                'show_minor'   => array('bool', 'minor', false),
134
                // String, only used in list mode
135
                'sort'         => array('str', 'sort', 'natural'),
136
                // String, only used in search mode
137
                'search_query' => array('str', 'q', null),
138
                // One of: pages, media, both
139
                'content_type' => array('str', 'view', $conf['rss_media'])
140
141
            ) as $name => $val) {
142
        $opt[$name] = $INPUT->{$val[0]}($val[1], $val[2], true);
143
    }
144
145
    $opt['items']      = max(0, (int) $opt['items']);
146
    $opt['show_minor'] = (bool) $opt['show_minor'];
147
    $opt['sort'] = valid_input_set('sort', array('default' => 'natural', 'date'), $opt);
148
149
    $opt['guardmail'] = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none');
150
151
    $type = $INPUT->valid(
152
        'type',
153
        array( 'rss', 'rss2', 'atom', 'atom1', 'rss1'),
154
        $conf['rss_type']
155
    );
156
    switch($type) {
157
        case 'rss':
158
            $opt['feed_type'] = 'RSS0.91';
159
            $opt['mime_type'] = 'text/xml';
160
            break;
161
        case 'rss2':
162
            $opt['feed_type'] = 'RSS2.0';
163
            $opt['mime_type'] = 'text/xml';
164
            break;
165
        case 'atom':
166
            $opt['feed_type'] = 'ATOM0.3';
167
            $opt['mime_type'] = 'application/xml';
168
            break;
169
        case 'atom1':
170
            $opt['feed_type'] = 'ATOM1.0';
171
            $opt['mime_type'] = 'application/atom+xml';
172
            break;
173
        default:
174
            $opt['feed_type'] = 'RSS1.0';
175
            $opt['mime_type'] = 'application/xml';
176
    }
177
178
    $eventData = array(
179
        'opt' => &$opt,
180
    );
181
    trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
182
    return $opt;
183
}
184
185
/**
186
 * Add recent changed pages to a feed object
187
 *
188
 * @author Andreas Gohr <[email protected]>
189
 * @param  FeedCreator $rss the FeedCreator Object
190
 * @param  array       $data the items to add
191
 * @param  array       $opt  the feed options
192
 */
193
function rss_buildItems(&$rss, &$data, $opt) {
194
    global $conf;
195
    global $lang;
196
    /* @var DokuWiki_Auth_Plugin $auth */
197
    global $auth;
198
199
    $eventData = array(
200
        'rss'  => &$rss,
201
        'data' => &$data,
202
        'opt'  => &$opt,
203
    );
204
    $event     = new Doku_Event('FEED_DATA_PROCESS', $eventData);
205
    if($event->advise_before(false)) {
206
        foreach($data as $ditem) {
207
            if(!is_array($ditem)) {
208
                // not an array? then only a list of IDs was given
209
                $ditem = array('id' => $ditem);
210
            }
211
212
            $item = new FeedItem();
213
            $id   = $ditem['id'];
214
            if(!$ditem['media']) {
215
                $meta = p_get_metadata($id);
216
            } else {
217
                $meta = array();
218
            }
219
220
            // add date
221
            if($ditem['date']) {
222
                $date = $ditem['date'];
223
            } elseif ($ditem['media']) {
224
                $date = @filemtime(mediaFN($id));
225
            } elseif (file_exists(wikiFN($id))) {
226
                $date = @filemtime(wikiFN($id));
227
            } elseif($meta['date']['modified']) {
228
                $date = $meta['date']['modified'];
229
            } else {
230
                $date = 0;
231
            }
232
            if($date) $item->date = date('r', $date);
233
234
            // add title
235
            if($conf['useheading'] && $meta['title']) {
236
                $item->title = $meta['title'];
237
            } else {
238
                $item->title = $ditem['id'];
239
            }
240
            if($conf['rss_show_summary'] && !empty($ditem['sum'])) {
241
                $item->title .= ' - '.strip_tags($ditem['sum']);
242
            }
243
244
            // add item link
245
            switch($opt['link_to']) {
246
                case 'page':
247
                    if($ditem['media']) {
248
                        $item->link = media_managerURL(
249
                            array(
250
                                 'image' => $id,
251
                                 'ns'    => getNS($id),
252
                                 'rev'   => $date
253
                            ), '&', true
254
                        );
255
                    } else {
256
                        $item->link = wl($id, 'rev='.$date, true, '&');
257
                    }
258
                    break;
259
                case 'rev':
260
                    if($ditem['media']) {
261
                        $item->link = media_managerURL(
262
                            array(
263
                                 'image'       => $id,
264
                                 'ns'          => getNS($id),
265
                                 'rev'         => $date,
266
                                 'tab_details' => 'history'
267
                            ), '&', true
268
                        );
269
                    } else {
270
                        $item->link = wl($id, 'do=revisions&rev='.$date, true, '&');
271
                    }
272
                    break;
273
                case 'current':
274
                    if($ditem['media']) {
275
                        $item->link = media_managerURL(
276
                            array(
277
                                 'image' => $id,
278
                                 'ns'    => getNS($id)
279
                            ), '&', true
280
                        );
281
                    } else {
282
                        $item->link = wl($id, '', true, '&');
283
                    }
284
                    break;
285
                case 'diff':
286
                default:
287
                    if($ditem['media']) {
288
                        $item->link = media_managerURL(
289
                            array(
290
                                 'image'       => $id,
291
                                 'ns'          => getNS($id),
292
                                 'rev'         => $date,
293
                                 'tab_details' => 'history',
294
                                 'mediado'     => 'diff'
295
                            ), '&', true
296
                        );
297
                    } else {
298
                        $item->link = wl($id, 'rev='.$date.'&do=diff', true, '&');
299
                    }
300
            }
301
302
            // add item content
303
            switch($opt['item_content']) {
304
                case 'diff':
305
                case 'htmldiff':
306
                    if($ditem['media']) {
307
                        $medialog = new MediaChangeLog($id);
308
                        $revs  = $medialog->getRevisions(0, 1);
309
                        $rev   = $revs[0];
310
                        $src_r = '';
311
                        $src_l = '';
312
313
                        if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)), 300)) {
314
                            $more  = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
315
                            $src_r = ml($id, $more, true, '&amp;', true);
316
                        }
317
                        if($rev && $size = media_image_preview_size($id, $rev, new JpegMeta(mediaFN($id, $rev)), 300)) {
318
                            $more  = 'rev='.$rev.'&w='.$size[0].'&h='.$size[1];
319
                            $src_l = ml($id, $more, true, '&amp;', true);
320
                        }
321
                        $content = '';
322
                        if($src_r) {
323
                            $content = '<table>';
324
                            $content .= '<tr><th width="50%">'.$rev.'</th>';
325
                            $content .= '<th width="50%">'.$lang['current'].'</th></tr>';
326
                            $content .= '<tr align="center"><td><img src="'.$src_l.'" alt="" /></td><td>';
327
                            $content .= '<img src="'.$src_r.'" alt="'.$id.'" /></td></tr>';
328
                            $content .= '</table>';
329
                        }
330
331
                    } else {
332
                        require_once(DOKU_INC.'inc/DifferenceEngine.php');
333
                        $pagelog = new PageChangeLog($id);
334
                        $revs = $pagelog->getRevisions(0, 1);
335
                        $rev  = $revs[0];
336
337
                        if($rev) {
338
                            $df = new Diff(explode("\n", rawWiki($id, $rev)),
339
                                           explode("\n", rawWiki($id, '')));
340
                        } else {
341
                            $df = new Diff(array(''),
342
                                           explode("\n", rawWiki($id, '')));
343
                        }
344
345
                        if($opt['item_content'] == 'htmldiff') {
346
                            // note: no need to escape diff output, TableDiffFormatter provides 'safe' html
347
                            $tdf     = new TableDiffFormatter();
348
                            $content = '<table>';
349
                            $content .= '<tr><th colspan="2" width="50%">'.$rev.'</th>';
350
                            $content .= '<th colspan="2" width="50%">'.$lang['current'].'</th></tr>';
351
                            $content .= $tdf->format($df);
352
                            $content .= '</table>';
353
                        } else {
354
                            // note: diff output must be escaped, UnifiedDiffFormatter provides plain text
355
                            $udf     = new UnifiedDiffFormatter();
356
                            $content = "<pre>\n".hsc($udf->format($df))."\n</pre>";
357
                        }
358
                    }
359
                    break;
360
                case 'html':
361
                    if($ditem['media']) {
362
                        if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
363
                            $more    = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
364
                            $src     = ml($id, $more, true, '&amp;', true);
365
                            $content = '<img src="'.$src.'" alt="'.$id.'" />';
366
                        } else {
367
                            $content = '';
368
                        }
369
                    } else {
370
                        if (@filemtime(wikiFN($id)) === $date) {
371
                            $content = p_wiki_xhtml($id, '', false);
372
                        } else {
373
                            $content = p_wiki_xhtml($id, $date, false);
374
                        }
375
                        // no TOC in feeds
376
                        $content = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s', '', $content);
377
378
                        // add alignment for images
379
                        $content = preg_replace('/(<img .*?class="medialeft")/s', '\\1 align="left"', $content);
380
                        $content = preg_replace('/(<img .*?class="mediaright")/s', '\\1 align="right"', $content);
381
382
                        // make URLs work when canonical is not set, regexp instead of rerendering!
383
                        if(!$conf['canonical']) {
384
                            $base    = preg_quote(DOKU_REL, '/');
385
                            $content = preg_replace('/(<a href|<img src)="('.$base.')/s', '$1="'.DOKU_URL, $content);
386
                        }
387
                    }
388
389
                    break;
390
                case 'abstract':
391
                default:
392
                    if($ditem['media']) {
393
                        if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
394
                            $more    = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
395
                            $src     = ml($id, $more, true, '&amp;', true);
396
                            $content = '<img src="'.$src.'" alt="'.$id.'" />';
397
                        } else {
398
                            $content = '';
399
                        }
400
                    } else {
401
                        $content = $meta['description']['abstract'];
402
                    }
403
            }
404
            $item->description = $content; //FIXME a plugin hook here could be senseful
405
406
            // add user
407
            # FIXME should the user be pulled from metadata as well?
408
            $user         = @$ditem['user']; // the @ spares time repeating lookup
409
            if(blank($user)) {
410
                $item->author = 'Anonymous';
411
                $item->authorEmail = '[email protected]';
412
            } else {
413
                $item->author = $user;
414
                $item->authorEmail = $user . '@undisclosed.example.com';
415
416
                // get real user name if configured
417
                if($conf['useacl'] && $auth) {
418
                    $userInfo = $auth->getUserData($user);
419
                    if($userInfo) {
420
                        switch($conf['showuseras']) {
421
                            case 'username':
422
                            case 'username_link':
423
                                $item->author = $userInfo['name'];
424
                                break;
425
                            default:
426
                                $item->author = $user;
427
                                break;
428
                        }
429
                    } else {
430
                        $item->author = $user;
431
                    }
432
                }
433
            }
434
435
            // add category
436
            if(isset($meta['subject'])) {
437
                $item->category = $meta['subject'];
438
            } else {
439
                $cat = getNS($id);
440
                if($cat) $item->category = $cat;
0 ignored issues
show
Bug Best Practice introduced by
The expression $cat of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
441
            }
442
443
            // finally add the item to the feed object, after handing it to registered plugins
444
            $evdata = array(
445
                'item'  => &$item,
446
                'opt'   => &$opt,
447
                'ditem' => &$ditem,
448
                'rss'   => &$rss
449
            );
450
            $evt    = new Doku_Event('FEED_ITEM_ADD', $evdata);
451
            if($evt->advise_before()) {
452
                $rss->addItem($item);
453
            }
454
            $evt->advise_after(); // for completeness
455
        }
456
    }
457
    $event->advise_after();
458
}
459
460
/**
461
 * Add recent changed pages to the feed object
462
 *
463
 * @author Andreas Gohr <[email protected]>
464
 */
465
function rssRecentChanges($opt) {
466
    global $conf;
467
    $flags = RECENTS_SKIP_DELETED;
468
    if(!$opt['show_minor']) $flags += RECENTS_SKIP_MINORS;
469
    if($opt['content_type'] == 'media' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_CHANGES;
470
    if($opt['content_type'] == 'both' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_PAGES_MIXED;
471
472
    $recents = getRecents(0, $opt['items'], $opt['namespace'], $flags);
473
    return $recents;
474
}
475
476
/**
477
 * Add all pages of a namespace to the feed object
478
 *
479
 * @author Andreas Gohr <[email protected]>
480
 */
481
function rssListNamespace($opt) {
482
    require_once(DOKU_INC.'inc/search.php');
483
    global $conf;
484
485
    $ns = ':'.cleanID($opt['namespace']);
486
    $ns = utf8_encodeFN(str_replace(':', '/', $ns));
487
488
    $data = array();
489
    $search_opts = array(
490
        'depth' => 1,
491
        'pagesonly' => true,
492
        'listfiles' => true
493
    );
494
    search($data, $conf['datadir'], 'search_universal', $search_opts, $ns, $lvl = 1, $opt['sort']);
495
496
    return $data;
497
}
498
499
/**
500
 * Add the result of a full text search to the feed object
501
 *
502
 * @author Andreas Gohr <[email protected]>
503
 */
504
function rssSearch($opt) {
505
    if(!$opt['search_query']) return array();
506
507
    require_once(DOKU_INC.'inc/fulltext.php');
508
    $data = ft_pageSearch($opt['search_query'], $poswords);
509
    $data = array_keys($data);
510
511
    return $data;
512
}
513
514
//Setup VIM: ex: et ts=4 :
515