Failed Conditions
Push — interwiki-remove-golucky ( 52fcdb...768be5 )
by Henry
12:48 queued 09:48
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 (
108
            $wasCreated && (
109
                empty($oldmeta['persistent']['date']['created']) ||
110
                $oldmeta['persistent']['date']['created'] === $created
111
            )
112
        ){
113
            // newly created
114
            $meta['date']['created'] = $created;
115
            if ($user){
116
                $meta['creator'] = $INFO['userinfo']['name'];
117
                $meta['user']    = $user;
118
            }
119
        } elseif (($wasCreated || $wasReverted) && !empty($oldmeta['persistent']['date']['created'])) {
120
            // re-created / restored
121
            $meta['date']['created']  = $oldmeta['persistent']['date']['created'];
122
            $meta['date']['modified'] = $created; // use the files ctime here
123
            $meta['creator'] = $oldmeta['persistent']['creator'];
124
            if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name'];
125
        } elseif (!$minor) {   // non-minor modification
126
            $meta['date']['modified'] = $date;
127
            if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name'];
128
        }
129
        $meta['last_change'] = $logline;
130
        p_set_metadata($id, $meta);
131
    }
132
133
    // add changelog lines
134
    $logline = implode("\t", $logline)."\n";
135
    io_saveFile(metaFN($id,'.changes'),$logline,true); //page changelog
136
    io_saveFile($conf['changelog'],$logline,true); //global changelog cache
137
}
138
139
/**
140
 * Add's an entry to the media changelog
141
 *
142
 * @author Michael Hamann <[email protected]>
143
 * @author Andreas Gohr <[email protected]>
144
 * @author Esther Brunner <[email protected]>
145
 * @author Ben Coburn <[email protected]>
146
 *
147
 * @param int    $date      Timestamp of the change
148
 * @param String $id        Name of the affected page
149
 * @param String $type      Type of the change see DOKU_CHANGE_TYPE_*
150
 * @param String $summary   Summary of the change
151
 * @param mixed  $extra     In case of a revert the revision (timestmp) of the reverted page
152
 * @param array  $flags     Additional flags in a key value array.
153
 *                             Available flags:
154
 *                             - (none, so far)
155
 * @param null|int $sizechange Change of filesize
156
 */
157
function addMediaLogEntry(
158
    $date,
159
    $id,
160
    $type=DOKU_CHANGE_TYPE_EDIT,
161
    $summary='',
162
    $extra='',
163
    $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...
164
    $sizechange = null)
165
{
166
    global $conf;
167
    /** @var Input $INPUT */
168
    global $INPUT;
169
170
    $id = cleanid($id);
171
172
    if(!$date) $date = time(); //use current time if none supplied
173
    $remote = clientIP(true);
174
    $user   = $INPUT->server->str('REMOTE_USER');
175
    if($sizechange === null) {
176
        $sizechange = '';
177
    } else {
178
        $sizechange = (int) $sizechange;
179
    }
180
181
    $strip = array("\t", "\n");
182
    $logline = array(
183
        'date'       => $date,
184
        'ip'         => $remote,
185
        'type'       => str_replace($strip, '', $type),
186
        'id'         => $id,
187
        'user'       => $user,
188
        'sum'        => \dokuwiki\Utf8\PhpString::substr(str_replace($strip, '', $summary), 0, 255),
189
        'extra'      => str_replace($strip, '', $extra),
190
        'sizechange' => $sizechange
191
    );
192
193
    // add changelog lines
194
    $logline = implode("\t", $logline)."\n";
195
    io_saveFile($conf['media_changelog'],$logline,true); //global media changelog cache
196
    io_saveFile(mediaMetaFN($id,'.changes'),$logline,true); //media file's changelog
197
}
198
199
/**
200
 * returns an array of recently changed files using the
201
 * changelog
202
 *
203
 * The following constants can be used to control which changes are
204
 * included. Add them together as needed.
205
 *
206
 * RECENTS_SKIP_DELETED   - don't include deleted pages
207
 * RECENTS_SKIP_MINORS    - don't include minor changes
208
 * RECENTS_SKIP_SUBSPACES - don't include subspaces
209
 * RECENTS_MEDIA_CHANGES  - return media changes instead of page changes
210
 * RECENTS_MEDIA_PAGES_MIXED  - return both media changes and page changes
211
 *
212
 * @param int    $first   number of first entry returned (for paginating
213
 * @param int    $num     return $num entries
214
 * @param string $ns      restrict to given namespace
215
 * @param int    $flags   see above
216
 * @return array recently changed files
217
 *
218
 * @author Ben Coburn <[email protected]>
219
 * @author Kate Arzamastseva <[email protected]>
220
 */
221
function getRecents($first,$num,$ns='',$flags=0){
222
    global $conf;
223
    $recent = array();
224
    $count  = 0;
225
226
    if(!$num)
227
        return $recent;
228
229
    // read all recent changes. (kept short)
230
    if ($flags & RECENTS_MEDIA_CHANGES) {
231
        $lines = @file($conf['media_changelog']);
232
    } else {
233
        $lines = @file($conf['changelog']);
234
    }
235
    if (!is_array($lines)) {
236
        $lines = array();
237
    }
238
    $lines_position = count($lines)-1;
239
    $media_lines_position = 0;
240
    $media_lines = array();
241
242
    if ($flags & RECENTS_MEDIA_PAGES_MIXED) {
243
        $media_lines = @file($conf['media_changelog']);
244
        if (!is_array($media_lines)) {
245
            $media_lines = array();
246
        }
247
        $media_lines_position = count($media_lines)-1;
248
    }
249
250
    $seen = array(); // caches seen lines, _handleRecent() skips them
251
252
    // handle lines
253
    while ($lines_position >= 0 || (($flags & RECENTS_MEDIA_PAGES_MIXED) && $media_lines_position >=0)) {
254
        if (empty($rec) && $lines_position >= 0) {
255
            $rec = _handleRecent(@$lines[$lines_position], $ns, $flags, $seen);
256
            if (!$rec) {
257
                $lines_position --;
258
                continue;
259
            }
260
        }
261
        if (($flags & RECENTS_MEDIA_PAGES_MIXED) && empty($media_rec) && $media_lines_position >= 0) {
262
            $media_rec = _handleRecent(
263
                @$media_lines[$media_lines_position],
264
                $ns,
265
                $flags | RECENTS_MEDIA_CHANGES,
266
                $seen
267
            );
268
            if (!$media_rec) {
269
                $media_lines_position --;
270
                continue;
271
            }
272
        }
273
        if (($flags & RECENTS_MEDIA_PAGES_MIXED) && @$media_rec['date'] >= @$rec['date']) {
274
            $media_lines_position--;
275
            $x = $media_rec;
276
            $x['media'] = true;
277
            $media_rec = false;
278
        } else {
279
            $lines_position--;
280
            $x = $rec;
281
            if ($flags & RECENTS_MEDIA_CHANGES) $x['media'] = true;
282
            $rec = false;
283
        }
284
        if(--$first >= 0) continue; // skip first entries
285
        $recent[] = $x;
286
        $count++;
287
        // break when we have enough entries
288
        if($count >= $num){ break; }
289
    }
290
    return $recent;
291
}
292
293
/**
294
 * returns an array of files changed since a given time using the
295
 * changelog
296
 *
297
 * The following constants can be used to control which changes are
298
 * included. Add them together as needed.
299
 *
300
 * RECENTS_SKIP_DELETED   - don't include deleted pages
301
 * RECENTS_SKIP_MINORS    - don't include minor changes
302
 * RECENTS_SKIP_SUBSPACES - don't include subspaces
303
 * RECENTS_MEDIA_CHANGES  - return media changes instead of page changes
304
 *
305
 * @param int    $from    date of the oldest entry to return
306
 * @param int    $to      date of the newest entry to return (for pagination, optional)
307
 * @param string $ns      restrict to given namespace (optional)
308
 * @param int    $flags   see above (optional)
309
 * @return array of files
310
 *
311
 * @author Michael Hamann <[email protected]>
312
 * @author Ben Coburn <[email protected]>
313
 */
314
function getRecentsSince($from,$to=null,$ns='',$flags=0){
315
    global $conf;
316
    $recent = array();
317
318
    if($to && $to < $from)
319
        return $recent;
320
321
    // read all recent changes. (kept short)
322
    if ($flags & RECENTS_MEDIA_CHANGES) {
323
        $lines = @file($conf['media_changelog']);
324
    } else {
325
        $lines = @file($conf['changelog']);
326
    }
327
    if(!$lines) return $recent;
328
329
    // we start searching at the end of the list
330
    $lines = array_reverse($lines);
331
332
    // handle lines
333
    $seen = array(); // caches seen lines, _handleRecent() skips them
334
335
    foreach($lines as $line){
336
        $rec = _handleRecent($line, $ns, $flags, $seen);
337
        if($rec !== false) {
338
            if ($rec['date'] >= $from) {
339
                if (!$to || $rec['date'] <= $to) {
340
                    $recent[] = $rec;
341
                }
342
            } else {
343
                break;
344
            }
345
        }
346
    }
347
348
    return array_reverse($recent);
349
}
350
351
/**
352
 * Internal function used by getRecents
353
 *
354
 * don't call directly
355
 *
356
 * @see getRecents()
357
 * @author Andreas Gohr <[email protected]>
358
 * @author Ben Coburn <[email protected]>
359
 *
360
 * @param string $line   changelog line
361
 * @param string $ns     restrict to given namespace
362
 * @param int    $flags  flags to control which changes are included
363
 * @param array  $seen   listing of seen pages
364
 * @return array|bool    false or array with info about a change
365
 */
366
function _handleRecent($line,$ns,$flags,&$seen){
367
    if(empty($line)) return false;   //skip empty lines
368
369
    // split the line into parts
370
    $recent = parseChangelogLine($line);
371
    if ($recent===false) { return false; }
372
373
    // skip seen ones
374
    if(isset($seen[$recent['id']])) return false;
375
376
    // skip minors
377
    if($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false;
378
379
    // remember in seen to skip additional sights
380
    $seen[$recent['id']] = 1;
381
382
    // check if it's a hidden page
383
    if(isHiddenPage($recent['id'])) return false;
384
385
    // filter namespace
386
    if (($ns) && (strpos($recent['id'],$ns.':') !== 0)) return false;
387
388
    // exclude subnamespaces
389
    if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false;
390
391
    // check ACL
392
    if ($flags & RECENTS_MEDIA_CHANGES) {
393
        $recent['perms'] = auth_quickaclcheck(getNS($recent['id']).':*');
394
    } else {
395
        $recent['perms'] = auth_quickaclcheck($recent['id']);
396
    }
397
    if ($recent['perms'] < AUTH_READ) return false;
398
399
    // check existance
400
    if($flags & RECENTS_SKIP_DELETED){
401
        $fn = (($flags & RECENTS_MEDIA_CHANGES) ? mediaFN($recent['id']) : wikiFN($recent['id']));
402
        if(!file_exists($fn)) return false;
403
    }
404
405
    return $recent;
406
}
407