Failed Conditions
Push — master ( af7ba5...31a58a )
by Andreas
06:52 queued 03:53
created

inc/changelog.php (1 issue)

Severity

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
 * Changelog handling functions
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
// Constants for known core changelog line types.
10
// Use these in place of string literals for more readable code.
11
define('DOKU_CHANGE_TYPE_CREATE',       'C');
12
define('DOKU_CHANGE_TYPE_EDIT',         'E');
13
define('DOKU_CHANGE_TYPE_MINOR_EDIT',   'e');
14
define('DOKU_CHANGE_TYPE_DELETE',       'D');
15
define('DOKU_CHANGE_TYPE_REVERT',       'R');
16
17
/**
18
 * parses a changelog line into it's components
19
 *
20
 * @author Ben Coburn <[email protected]>
21
 *
22
 * @param string $line changelog line
23
 * @return array|bool parsed line or false
24
 */
25
function parseChangelogLine($line) {
26
    $line = rtrim($line, "\n");
27
    $tmp = explode("\t", $line);
28
    if ($tmp!==false && count($tmp)>1) {
29
        $info = array();
30
        $info['date']  = (int)$tmp[0]; // unix timestamp
31
        $info['ip']    = $tmp[1]; // IPv4 address (127.0.0.1)
32
        $info['type']  = $tmp[2]; // log line type
33
        $info['id']    = $tmp[3]; // page id
34
        $info['user']  = $tmp[4]; // user name
35
        $info['sum']   = $tmp[5]; // edit summary (or action reason)
36
        $info['extra'] = $tmp[6]; // extra data (varies by line type)
37
        if(isset($tmp[7]) && $tmp[7] !== '') { //last item has line-end||
38
            $info['sizechange'] = (int) $tmp[7];
39
        } else {
40
            $info['sizechange'] = null;
41
        }
42
        return $info;
43
    } else {
44
        return false;
45
    }
46
}
47
48
/**
49
 * Add's an entry to the changelog and saves the metadata for the page
50
 *
51
 * @param int    $date      Timestamp of the change
52
 * @param String $id        Name of the affected page
53
 * @param String $type      Type of the change see DOKU_CHANGE_TYPE_*
54
 * @param String $summary   Summary of the change
55
 * @param mixed  $extra     In case of a revert the revision (timestmp) of the reverted page
56
 * @param array  $flags     Additional flags in a key value array.
57
 *                             Available flags:
58
 *                             - ExternalEdit - mark as an external edit.
59
 * @param null|int $sizechange Change of filesize
60
 *
61
 * @author Andreas Gohr <[email protected]>
62
 * @author Esther Brunner <[email protected]>
63
 * @author Ben Coburn <[email protected]>
64
 */
65
function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extra='', $flags=null, $sizechange = null){
66
    global $conf, $INFO;
67
    /** @var Input $INPUT */
68
    global $INPUT;
69
70
    // check for special flags as keys
71
    if (!is_array($flags)) { $flags = array(); }
72
    $flagExternalEdit = isset($flags['ExternalEdit']);
73
74
    $id = cleanid($id);
75
    $file = wikiFN($id);
76
    $created = @filectime($file);
77
    $minor = ($type===DOKU_CHANGE_TYPE_MINOR_EDIT);
78
    $wasRemoved = ($type===DOKU_CHANGE_TYPE_DELETE);
79
80
    if(!$date) $date = time(); //use current time if none supplied
81
    $remote = (!$flagExternalEdit)?clientIP(true):'127.0.0.1';
82
    $user   = (!$flagExternalEdit)?$INPUT->server->str('REMOTE_USER'):'';
83
    if($sizechange === null) {
84
        $sizechange = '';
85
    } else {
86
        $sizechange = (int) $sizechange;
87
    }
88
89
    $strip = array("\t", "\n");
90
    $logline = array(
91
        'date'       => $date,
92
        'ip'         => $remote,
93
        'type'       => str_replace($strip, '', $type),
94
        'id'         => $id,
95
        'user'       => $user,
96
        'sum'        => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
97
        'extra'      => str_replace($strip, '', $extra),
98
        'sizechange' => $sizechange
99
    );
100
101
    $wasCreated = ($type===DOKU_CHANGE_TYPE_CREATE);
102
    $wasReverted = ($type===DOKU_CHANGE_TYPE_REVERT);
103
    // update metadata
104
    if (!$wasRemoved) {
105
        $oldmeta = p_read_metadata($id);
106
        $meta    = array();
107
        if ($wasCreated && empty($oldmeta['persistent']['date']['created'])){
108
            // newly created
109
            $meta['date']['created'] = $created;
110
            if ($user){
111
                $meta['creator'] = $INFO['userinfo']['name'];
112
                $meta['user']    = $user;
113
            }
114
        } elseif (($wasCreated || $wasReverted) && !empty($oldmeta['persistent']['date']['created'])) {
115
            // re-created / restored
116
            $meta['date']['created']  = $oldmeta['persistent']['date']['created'];
117
            $meta['date']['modified'] = $created; // use the files ctime here
118
            $meta['creator'] = $oldmeta['persistent']['creator'];
119
            if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name'];
120
        } elseif (!$minor) {   // non-minor modification
121
            $meta['date']['modified'] = $date;
122
            if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name'];
123
        }
124
        $meta['last_change'] = $logline;
125
        p_set_metadata($id, $meta);
126
    }
127
128
    // add changelog lines
129
    $logline = implode("\t", $logline)."\n";
130
    io_saveFile(metaFN($id,'.changes'),$logline,true); //page changelog
131
    io_saveFile($conf['changelog'],$logline,true); //global changelog cache
132
}
133
134
/**
135
 * Add's an entry to the media changelog
136
 *
137
 * @author Michael Hamann <[email protected]>
138
 * @author Andreas Gohr <[email protected]>
139
 * @author Esther Brunner <[email protected]>
140
 * @author Ben Coburn <[email protected]>
141
 *
142
 * @param int    $date      Timestamp of the change
143
 * @param String $id        Name of the affected page
144
 * @param String $type      Type of the change see DOKU_CHANGE_TYPE_*
145
 * @param String $summary   Summary of the change
146
 * @param mixed  $extra     In case of a revert the revision (timestmp) of the reverted page
147
 * @param array  $flags     Additional flags in a key value array.
148
 *                             Available flags:
149
 *                             - (none, so far)
150
 * @param null|int $sizechange Change of filesize
151
 */
152
function addMediaLogEntry(
153
    $date,
154
    $id,
155
    $type=DOKU_CHANGE_TYPE_EDIT,
156
    $summary='',
157
    $extra='',
158
    $flags=null,
0 ignored issues
show
The parameter $flags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
159
    $sizechange = null)
160
{
161
    global $conf;
162
    /** @var Input $INPUT */
163
    global $INPUT;
164
165
    $id = cleanid($id);
166
167
    if(!$date) $date = time(); //use current time if none supplied
168
    $remote = clientIP(true);
169
    $user   = $INPUT->server->str('REMOTE_USER');
170
    if($sizechange === null) {
171
        $sizechange = '';
172
    } else {
173
        $sizechange = (int) $sizechange;
174
    }
175
176
    $strip = array("\t", "\n");
177
    $logline = array(
178
        'date'       => $date,
179
        'ip'         => $remote,
180
        'type'       => str_replace($strip, '', $type),
181
        'id'         => $id,
182
        'user'       => $user,
183
        'sum'        => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
184
        'extra'      => str_replace($strip, '', $extra),
185
        'sizechange' => $sizechange
186
    );
187
188
    // add changelog lines
189
    $logline = implode("\t", $logline)."\n";
190
    io_saveFile($conf['media_changelog'],$logline,true); //global media changelog cache
191
    io_saveFile(mediaMetaFN($id,'.changes'),$logline,true); //media file's changelog
192
}
193
194
/**
195
 * returns an array of recently changed files using the
196
 * changelog
197
 *
198
 * The following constants can be used to control which changes are
199
 * included. Add them together as needed.
200
 *
201
 * RECENTS_SKIP_DELETED   - don't include deleted pages
202
 * RECENTS_SKIP_MINORS    - don't include minor changes
203
 * RECENTS_SKIP_SUBSPACES - don't include subspaces
204
 * RECENTS_MEDIA_CHANGES  - return media changes instead of page changes
205
 * RECENTS_MEDIA_PAGES_MIXED  - return both media changes and page changes
206
 *
207
 * @param int    $first   number of first entry returned (for paginating
208
 * @param int    $num     return $num entries
209
 * @param string $ns      restrict to given namespace
210
 * @param int    $flags   see above
211
 * @return array recently changed files
212
 *
213
 * @author Ben Coburn <[email protected]>
214
 * @author Kate Arzamastseva <[email protected]>
215
 */
216
function getRecents($first,$num,$ns='',$flags=0){
217
    global $conf;
218
    $recent = array();
219
    $count  = 0;
220
221
    if(!$num)
222
        return $recent;
223
224
    // read all recent changes. (kept short)
225
    if ($flags & RECENTS_MEDIA_CHANGES) {
226
        $lines = @file($conf['media_changelog']);
227
    } else {
228
        $lines = @file($conf['changelog']);
229
    }
230
    if (!is_array($lines)) {
231
        $lines = array();
232
    }
233
    $lines_position = count($lines)-1;
234
    $media_lines_position = 0;
235
    $media_lines = array();
236
237
    if ($flags & RECENTS_MEDIA_PAGES_MIXED) {
238
        $media_lines = @file($conf['media_changelog']);
239
        if (!is_array($media_lines)) {
240
            $media_lines = array();
241
        }
242
        $media_lines_position = count($media_lines)-1;
243
    }
244
245
    $seen = array(); // caches seen lines, _handleRecent() skips them
246
247
    // handle lines
248
    while ($lines_position >= 0 || (($flags & RECENTS_MEDIA_PAGES_MIXED) && $media_lines_position >=0)) {
249
        if (empty($rec) && $lines_position >= 0) {
250
            $rec = _handleRecent(@$lines[$lines_position], $ns, $flags, $seen);
251
            if (!$rec) {
252
                $lines_position --;
253
                continue;
254
            }
255
        }
256
        if (($flags & RECENTS_MEDIA_PAGES_MIXED) && empty($media_rec) && $media_lines_position >= 0) {
257
            $media_rec = _handleRecent(
258
                @$media_lines[$media_lines_position],
259
                $ns,
260
                $flags | RECENTS_MEDIA_CHANGES,
261
                $seen
262
            );
263
            if (!$media_rec) {
264
                $media_lines_position --;
265
                continue;
266
            }
267
        }
268
        if (($flags & RECENTS_MEDIA_PAGES_MIXED) && @$media_rec['date'] >= @$rec['date']) {
269
            $media_lines_position--;
270
            $x = $media_rec;
271
            $x['media'] = true;
272
            $media_rec = false;
273
        } else {
274
            $lines_position--;
275
            $x = $rec;
276
            if ($flags & RECENTS_MEDIA_CHANGES) $x['media'] = true;
277
            $rec = false;
278
        }
279
        if(--$first >= 0) continue; // skip first entries
280
        $recent[] = $x;
281
        $count++;
282
        // break when we have enough entries
283
        if($count >= $num){ break; }
284
    }
285
    return $recent;
286
}
287
288
/**
289
 * returns an array of files changed since a given time using the
290
 * changelog
291
 *
292
 * The following constants can be used to control which changes are
293
 * included. Add them together as needed.
294
 *
295
 * RECENTS_SKIP_DELETED   - don't include deleted pages
296
 * RECENTS_SKIP_MINORS    - don't include minor changes
297
 * RECENTS_SKIP_SUBSPACES - don't include subspaces
298
 * RECENTS_MEDIA_CHANGES  - return media changes instead of page changes
299
 *
300
 * @param int    $from    date of the oldest entry to return
301
 * @param int    $to      date of the newest entry to return (for pagination, optional)
302
 * @param string $ns      restrict to given namespace (optional)
303
 * @param int    $flags   see above (optional)
304
 * @return array of files
305
 *
306
 * @author Michael Hamann <[email protected]>
307
 * @author Ben Coburn <[email protected]>
308
 */
309
function getRecentsSince($from,$to=null,$ns='',$flags=0){
310
    global $conf;
311
    $recent = array();
312
313
    if($to && $to < $from)
314
        return $recent;
315
316
    // read all recent changes. (kept short)
317
    if ($flags & RECENTS_MEDIA_CHANGES) {
318
        $lines = @file($conf['media_changelog']);
319
    } else {
320
        $lines = @file($conf['changelog']);
321
    }
322
    if(!$lines) return $recent;
323
324
    // we start searching at the end of the list
325
    $lines = array_reverse($lines);
326
327
    // handle lines
328
    $seen = array(); // caches seen lines, _handleRecent() skips them
329
330
    foreach($lines as $line){
331
        $rec = _handleRecent($line, $ns, $flags, $seen);
332
        if($rec !== false) {
333
            if ($rec['date'] >= $from) {
334
                if (!$to || $rec['date'] <= $to) {
335
                    $recent[] = $rec;
336
                }
337
            } else {
338
                break;
339
            }
340
        }
341
    }
342
343
    return array_reverse($recent);
344
}
345
346
/**
347
 * Internal function used by getRecents
348
 *
349
 * don't call directly
350
 *
351
 * @see getRecents()
352
 * @author Andreas Gohr <[email protected]>
353
 * @author Ben Coburn <[email protected]>
354
 *
355
 * @param string $line   changelog line
356
 * @param string $ns     restrict to given namespace
357
 * @param int    $flags  flags to control which changes are included
358
 * @param array  $seen   listing of seen pages
359
 * @return array|bool    false or array with info about a change
360
 */
361
function _handleRecent($line,$ns,$flags,&$seen){
362
    if(empty($line)) return false;   //skip empty lines
363
364
    // split the line into parts
365
    $recent = parseChangelogLine($line);
366
    if ($recent===false) { return false; }
367
368
    // skip seen ones
369
    if(isset($seen[$recent['id']])) return false;
370
371
    // skip minors
372
    if($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false;
373
374
    // remember in seen to skip additional sights
375
    $seen[$recent['id']] = 1;
376
377
    // check if it's a hidden page
378
    if(isHiddenPage($recent['id'])) return false;
379
380
    // filter namespace
381
    if (($ns) && (strpos($recent['id'],$ns.':') !== 0)) return false;
382
383
    // exclude subnamespaces
384
    if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false;
385
386
    // check ACL
387
    if ($flags & RECENTS_MEDIA_CHANGES) {
388
        $recent['perms'] = auth_quickaclcheck(getNS($recent['id']).':*');
389
    } else {
390
        $recent['perms'] = auth_quickaclcheck($recent['id']);
391
    }
392
    if ($recent['perms'] < AUTH_READ) return false;
393
394
    // check existance
395
    if($flags & RECENTS_SKIP_DELETED){
396
        $fn = (($flags & RECENTS_MEDIA_CHANGES) ? mediaFN($recent['id']) : wikiFN($recent['id']));
397
        if(!file_exists($fn)) return false;
398
    }
399
400
    return $recent;
401
}
402