Failed Conditions
Push — stable ( d0fffb...879d2b )
by
unknown
03:27
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
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
13
require_once(DOKU_INC.'inc/init.php');
14
15
//close session
16
session_write_close();
17
18
//feed disabled?
19
if(!actionOK('rss')) {
20
    http_status(404);
21
    echo '<error>RSS feed is disabled.</error>';
22
    exit;
23
}
24
25
// get params
26
$opt = rss_parseOptions();
27
28
// the feed is dynamic - we need a cache for each combo
29
// (but most people just use the default feed so it's still effective)
30
$key   = join('', array_values($opt)).'$'.$_SERVER['REMOTE_USER'].'$'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
31
$cache = new cache($key, '.feed');
32
33
// prepare cache depends
34
$depends['files'] = getConfigFiles('main');
35
$depends['age']   = $conf['rss_update'];
36
$depends['purge'] = $INPUT->bool('purge');
37
38
// check cacheage and deliver if nothing has changed since last
39
// time or the update interval has not passed, also handles conditional requests
40
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
41
header('Pragma: public');
42
header('Content-Type: application/xml; charset=utf-8');
43
header('X-Robots-Tag: noindex');
44
if($cache->useCache($depends)) {
45
    http_conditionalRequest($cache->_time);
46
    if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
47
    print $cache->retrieveCache();
48
    exit;
49
} else {
50
    http_conditionalRequest(time());
51
}
52
53
// create new feed
54
$rss                 = new UniversalFeedCreator();
55
$rss->title          = $conf['title'].(($opt['namespace']) ? ' '.$opt['namespace'] : '');
56
$rss->link           = DOKU_URL;
57
$rss->syndicationURL = DOKU_URL.'feed.php';
58
$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...
59
60
$image        = new FeedImage();
61
$image->title = $conf['title'];
62
$image->url   = tpl_getMediaFile(array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico'), true);
63
$image->link  = DOKU_URL;
64
$rss->image   = $image;
65
66
$data  = null;
67
$modes = array(
68
    'list'   => 'rssListNamespace',
69
    'search' => 'rssSearch',
70
    'recent' => 'rssRecentChanges'
71
);
72
if(isset($modes[$opt['feed_mode']])) {
73
    $data = $modes[$opt['feed_mode']]($opt);
74
} else {
75
    $eventData = array(
76
        'opt'  => &$opt,
77
        'data' => &$data,
78
    );
79
    $event     = new Doku_Event('FEED_MODE_UNKNOWN', $eventData);
80
    if($event->advise_before(true)) {
81
        echo sprintf('<error>Unknown feed mode %s</error>', hsc($opt['feed_mode']));
82
        exit;
83
    }
84
    $event->advise_after();
85
}
86
87
rss_buildItems($rss, $data, $opt);
88
$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...
89
90
// save cachefile
91
$cache->storeCache($feed);
92
93
// finally deliver
94
print $feed;
95
96
// ---------------------------------------------------------------- //
97
98
/**
99
 * Get URL parameters and config options and return an initialized option array
100
 *
101
 * @author Andreas Gohr <[email protected]>
102
 */
103
function rss_parseOptions() {
104
    global $conf;
105
    global $INPUT;
106
107
    $opt = array();
108
109
    foreach(array(
110
                // Basic feed properties
111
                // Plugins may probably want to add new values to these
112
                // properties for implementing own feeds
113
114
                // One of: list, search, recent
115
                'feed_mode'    => array('str', 'mode', 'recent'),
116
                // One of: diff, page, rev, current
117
                'link_to'      => array('str', 'linkto', $conf['rss_linkto']),
118
                // One of: abstract, diff, htmldiff, html
119
                'item_content' => array('str', 'content', $conf['rss_content']),
120
121
                // Special feed properties
122
                // These are only used by certain feed_modes
123
124
                // String, used for feed title, in list and rc mode
125
                'namespace'    => array('str', 'ns', null),
126
                // Positive integer, only used in rc mode
127
                'items'        => array('int', 'num', $conf['recent']),
128
                // Boolean, only used in rc mode
129
                'show_minor'   => array('bool', 'minor', false),
130
                // String, only used in list mode
131
                'sort'         => array('str', 'sort', 'natural'),
132
                // String, only used in search mode
133
                'search_query' => array('str', 'q', null),
134
                // One of: pages, media, both
135
                'content_type' => array('str', 'view', $conf['rss_media'])
136
137
            ) as $name => $val) {
138
        $opt[$name] = $INPUT->{$val[0]}($val[1], $val[2], true);
139
    }
140
141
    $opt['items']      = max(0, (int) $opt['items']);
142
    $opt['show_minor'] = (bool) $opt['show_minor'];
143
    $opt['sort'] = valid_input_set('sort', array('default' => 'natural', 'date'), $opt);
144
145
    $opt['guardmail'] = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none');
146
147
    $type = $INPUT->valid(
148
        'type',
149
        array( 'rss', 'rss2', 'atom', 'atom1', 'rss1'),
150
        $conf['rss_type']
151
    );
152
    switch($type) {
153
        case 'rss':
154
            $opt['feed_type'] = 'RSS0.91';
155
            $opt['mime_type'] = 'text/xml';
156
            break;
157
        case 'rss2':
158
            $opt['feed_type'] = 'RSS2.0';
159
            $opt['mime_type'] = 'text/xml';
160
            break;
161
        case 'atom':
162
            $opt['feed_type'] = 'ATOM0.3';
163
            $opt['mime_type'] = 'application/xml';
164
            break;
165
        case 'atom1':
166
            $opt['feed_type'] = 'ATOM1.0';
167
            $opt['mime_type'] = 'application/atom+xml';
168
            break;
169
        default:
170
            $opt['feed_type'] = 'RSS1.0';
171
            $opt['mime_type'] = 'application/xml';
172
    }
173
174
    $eventData = array(
175
        'opt' => &$opt,
176
    );
177
    trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
178
    return $opt;
179
}
180
181
/**
182
 * Add recent changed pages to a feed object
183
 *
184
 * @author Andreas Gohr <[email protected]>
185
 * @param  FeedCreator $rss the FeedCreator Object
186
 * @param  array       $data the items to add
187
 * @param  array       $opt  the feed options
188
 */
189
function rss_buildItems(&$rss, &$data, $opt) {
190
    global $conf;
191
    global $lang;
192
    /* @var DokuWiki_Auth_Plugin $auth */
193
    global $auth;
194
195
    $eventData = array(
196
        'rss'  => &$rss,
197
        'data' => &$data,
198
        'opt'  => &$opt,
199
    );
200
    $event     = new Doku_Event('FEED_DATA_PROCESS', $eventData);
201
    if($event->advise_before(false)) {
202
        foreach($data as $ditem) {
203
            if(!is_array($ditem)) {
204
                // not an array? then only a list of IDs was given
205
                $ditem = array('id' => $ditem);
206
            }
207
208
            $item = new FeedItem();
209
            $id   = $ditem['id'];
210
            if(!$ditem['media']) {
211
                $meta = p_get_metadata($id);
212
            } else {
213
                $meta = array();
214
            }
215
216
            // add date
217
            if($ditem['date']) {
218
                $date = $ditem['date'];
219
            } elseif ($ditem['media']) {
220
                $date = @filemtime(mediaFN($id));
221
            } elseif (file_exists(wikiFN($id))) {
222
                $date = @filemtime(wikiFN($id));
223
            } elseif($meta['date']['modified']) {
224
                $date = $meta['date']['modified'];
225
            } else {
226
                $date = 0;
227
            }
228
            if($date) $item->date = date('r', $date);
229
230
            // add title
231
            if($conf['useheading'] && $meta['title']) {
232
                $item->title = $meta['title'];
233
            } else {
234
                $item->title = $ditem['id'];
235
            }
236
            if($conf['rss_show_summary'] && !empty($ditem['sum'])) {
237
                $item->title .= ' - '.strip_tags($ditem['sum']);
238
            }
239
240
            // add item link
241
            switch($opt['link_to']) {
242
                case 'page':
243
                    if($ditem['media']) {
244
                        $item->link = media_managerURL(
245
                            array(
246
                                 'image' => $id,
247
                                 'ns'    => getNS($id),
248
                                 'rev'   => $date
249
                            ), '&', true
250
                        );
251
                    } else {
252
                        $item->link = wl($id, 'rev='.$date, true, '&');
253
                    }
254
                    break;
255
                case 'rev':
256
                    if($ditem['media']) {
257
                        $item->link = media_managerURL(
258
                            array(
259
                                 'image'       => $id,
260
                                 'ns'          => getNS($id),
261
                                 'rev'         => $date,
262
                                 'tab_details' => 'history'
263
                            ), '&', true
264
                        );
265
                    } else {
266
                        $item->link = wl($id, 'do=revisions&rev='.$date, true, '&');
267
                    }
268
                    break;
269
                case 'current':
270
                    if($ditem['media']) {
271
                        $item->link = media_managerURL(
272
                            array(
273
                                 'image' => $id,
274
                                 'ns'    => getNS($id)
275
                            ), '&', true
276
                        );
277
                    } else {
278
                        $item->link = wl($id, '', true, '&');
279
                    }
280
                    break;
281
                case 'diff':
282
                default:
283
                    if($ditem['media']) {
284
                        $item->link = media_managerURL(
285
                            array(
286
                                 'image'       => $id,
287
                                 'ns'          => getNS($id),
288
                                 'rev'         => $date,
289
                                 'tab_details' => 'history',
290
                                 'mediado'     => 'diff'
291
                            ), '&', true
292
                        );
293
                    } else {
294
                        $item->link = wl($id, 'rev='.$date.'&do=diff', true, '&');
295
                    }
296
            }
297
298
            // add item content
299
            switch($opt['item_content']) {
300
                case 'diff':
301
                case 'htmldiff':
302
                    if($ditem['media']) {
303
                        $medialog = new MediaChangeLog($id);
304
                        $revs  = $medialog->getRevisions(0, 1);
305
                        $rev   = $revs[0];
306
                        $src_r = '';
307
                        $src_l = '';
308
309
                        if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)), 300)) {
310
                            $more  = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
311
                            $src_r = ml($id, $more, true, '&amp;', true);
312
                        }
313
                        if($rev && $size = media_image_preview_size($id, $rev, new JpegMeta(mediaFN($id, $rev)), 300)) {
314
                            $more  = 'rev='.$rev.'&w='.$size[0].'&h='.$size[1];
315
                            $src_l = ml($id, $more, true, '&amp;', true);
316
                        }
317
                        $content = '';
318
                        if($src_r) {
319
                            $content = '<table>';
320
                            $content .= '<tr><th width="50%">'.$rev.'</th>';
321
                            $content .= '<th width="50%">'.$lang['current'].'</th></tr>';
322
                            $content .= '<tr align="center"><td><img src="'.$src_l.'" alt="" /></td><td>';
323
                            $content .= '<img src="'.$src_r.'" alt="'.$id.'" /></td></tr>';
324
                            $content .= '</table>';
325
                        }
326
327
                    } else {
328
                        require_once(DOKU_INC.'inc/DifferenceEngine.php');
329
                        $pagelog = new PageChangeLog($id);
330
                        $revs = $pagelog->getRevisions(0, 1);
331
                        $rev  = $revs[0];
332
333
                        if($rev) {
334
                            $df = new Diff(explode("\n", rawWiki($id, $rev)),
335
                                           explode("\n", rawWiki($id, '')));
336
                        } else {
337
                            $df = new Diff(array(''),
338
                                           explode("\n", rawWiki($id, '')));
339
                        }
340
341
                        if($opt['item_content'] == 'htmldiff') {
342
                            // note: no need to escape diff output, TableDiffFormatter provides 'safe' html
343
                            $tdf     = new TableDiffFormatter();
344
                            $content = '<table>';
345
                            $content .= '<tr><th colspan="2" width="50%">'.$rev.'</th>';
346
                            $content .= '<th colspan="2" width="50%">'.$lang['current'].'</th></tr>';
347
                            $content .= $tdf->format($df);
348
                            $content .= '</table>';
349
                        } else {
350
                            // note: diff output must be escaped, UnifiedDiffFormatter provides plain text
351
                            $udf     = new UnifiedDiffFormatter();
352
                            $content = "<pre>\n".hsc($udf->format($df))."\n</pre>";
353
                        }
354
                    }
355
                    break;
356
                case 'html':
357
                    if($ditem['media']) {
358
                        if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
359
                            $more    = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
360
                            $src     = ml($id, $more, true, '&amp;', true);
361
                            $content = '<img src="'.$src.'" alt="'.$id.'" />';
362
                        } else {
363
                            $content = '';
364
                        }
365
                    } else {
366
                        if (@filemtime(wikiFN($id)) === $date) {
367
                            $content = p_wiki_xhtml($id, '', false);
368
                        } else {
369
                            $content = p_wiki_xhtml($id, $date, false);
370
                        }
371
                        // no TOC in feeds
372
                        $content = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s', '', $content);
373
374
                        // add alignment for images
375
                        $content = preg_replace('/(<img .*?class="medialeft")/s', '\\1 align="left"', $content);
376
                        $content = preg_replace('/(<img .*?class="mediaright")/s', '\\1 align="right"', $content);
377
378
                        // make URLs work when canonical is not set, regexp instead of rerendering!
379
                        if(!$conf['canonical']) {
380
                            $base    = preg_quote(DOKU_REL, '/');
381
                            $content = preg_replace('/(<a href|<img src)="('.$base.')/s', '$1="'.DOKU_URL, $content);
382
                        }
383
                    }
384
385
                    break;
386
                case 'abstract':
387
                default:
388
                    if($ditem['media']) {
389
                        if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
390
                            $more    = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
391
                            $src     = ml($id, $more, true, '&amp;', true);
392
                            $content = '<img src="'.$src.'" alt="'.$id.'" />';
393
                        } else {
394
                            $content = '';
395
                        }
396
                    } else {
397
                        $content = $meta['description']['abstract'];
398
                    }
399
            }
400
            $item->description = $content; //FIXME a plugin hook here could be senseful
401
402
            // add user
403
            # FIXME should the user be pulled from metadata as well?
404
            $user         = @$ditem['user']; // the @ spares time repeating lookup
405
            if(blank($user)) {
406
                $item->author = 'Anonymous';
407
                $item->authorEmail = '[email protected]';
408
            } else {
409
                $item->author = $user;
410
                $item->authorEmail = $user . '@undisclosed.example.com';
411
412
                // get real user name if configured
413
                if($conf['useacl'] && $auth) {
414
                    $userInfo = $auth->getUserData($user);
415
                    if($userInfo) {
416
                        switch($conf['showuseras']) {
417
                            case 'username':
418
                            case 'username_link':
419
                                $item->author = $userInfo['name'];
420
                                break;
421
                            default:
422
                                $item->author = $user;
423
                                break;
424
                        }
425
                    } else {
426
                        $item->author = $user;
427
                    }
428
                }
429
            }
430
431
            // add category
432
            if(isset($meta['subject'])) {
433
                $item->category = $meta['subject'];
434
            } else {
435
                $cat = getNS($id);
436
                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...
437
            }
438
439
            // finally add the item to the feed object, after handing it to registered plugins
440
            $evdata = array(
441
                'item'  => &$item,
442
                'opt'   => &$opt,
443
                'ditem' => &$ditem,
444
                'rss'   => &$rss
445
            );
446
            $evt    = new Doku_Event('FEED_ITEM_ADD', $evdata);
447
            if($evt->advise_before()) {
448
                $rss->addItem($item);
449
            }
450
            $evt->advise_after(); // for completeness
451
        }
452
    }
453
    $event->advise_after();
454
}
455
456
/**
457
 * Add recent changed pages to the feed object
458
 *
459
 * @author Andreas Gohr <[email protected]>
460
 */
461
function rssRecentChanges($opt) {
462
    global $conf;
463
    $flags = RECENTS_SKIP_DELETED;
464
    if(!$opt['show_minor']) $flags += RECENTS_SKIP_MINORS;
465
    if($opt['content_type'] == 'media' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_CHANGES;
466
    if($opt['content_type'] == 'both' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_PAGES_MIXED;
467
468
    $recents = getRecents(0, $opt['items'], $opt['namespace'], $flags);
469
    return $recents;
470
}
471
472
/**
473
 * Add all pages of a namespace to the feed object
474
 *
475
 * @author Andreas Gohr <[email protected]>
476
 */
477
function rssListNamespace($opt) {
478
    require_once(DOKU_INC.'inc/search.php');
479
    global $conf;
480
481
    $ns = ':'.cleanID($opt['namespace']);
482
    $ns = utf8_encodeFN(str_replace(':', '/', $ns));
483
484
    $data = array();
485
    $search_opts = array(
486
        'depth' => 1,
487
        'pagesonly' => true,
488
        'listfiles' => true
489
    );
490
    search($data, $conf['datadir'], 'search_universal', $search_opts, $ns, $lvl = 1, $opt['sort']);
491
492
    return $data;
493
}
494
495
/**
496
 * Add the result of a full text search to the feed object
497
 *
498
 * @author Andreas Gohr <[email protected]>
499
 */
500
function rssSearch($opt) {
501
    if(!$opt['search_query']) return array();
502
503
    require_once(DOKU_INC.'inc/fulltext.php');
504
    $data = ft_pageSearch($opt['search_query'], $poswords);
505
    $data = array_keys($data);
506
507
    return $data;
508
}
509
510
//Setup VIM: ex: et ts=4 :
511