xref: /dokuwiki/inc/ChangeLog/MediaChangeLog.php (revision 057ab5a057a76df652cfe4176512a550ca9937f6)
1<?php
2
3namespace dokuwiki\ChangeLog;
4
5/**
6 * Class MediaChangeLog; handles changelog of a media file
7 */
8class MediaChangeLog extends ChangeLog
9{
10    /**
11     * Returns path to changelog
12     *
13     * @return string path to file
14     */
15    protected function getChangelogFilename()
16    {
17        return mediaMetaFN($this->id, '.changes');
18    }
19
20    /**
21     * Returns path to current page/media
22     *
23     * @param string|int $rev empty string or revision timestamp
24     * @return string path to file
25     */
26    protected function getFilename($rev = '')
27    {
28        return mediaFN($this->id, $rev);
29    }
30
31    /**
32     * Returns mode
33     *
34     * @return string RevisionInfo::MODE_PAGE
35     */
36    protected function getMode()
37    {
38        return RevisionInfo::MODE_MEDIA;
39    }
40
41    /**
42     * Returns path to the global media-changelog file
43     *
44     * @return string path to file
45     */
46    protected function getGlobalChangelogFilename()
47    {
48        global $conf;
49        return $conf['media_changelog'];
50    }
51
52    /**
53     * Media deliberately does not keep an archive of its current revision — only the previous
54     * content is copied to the attic when a file is replaced or deleted (to save space). A
55     * detected external edit is the new current revision, so it is not snapshotted either: it
56     * will be archived like any other revision if and when it is later replaced. The changelog
57     * entry is still recorded by the caller, and the file-mtime repair for an unreliable date
58     * is handled by the base class.
59     *
60     * @param array $revInfo synthesized revision info (unused: nothing is archived)
61     * @return bool always true
62     */
63    protected function saveExternalAttic(array $revInfo)
64    {
65        return true;
66    }
67
68    /**
69     * Byte size of the last recorded revision.
70     *
71     * Media never archives its current revision (only the previous content is copied to the
72     * attic on replace or delete), so the last revision has no attic copy and its size cannot
73     * be read from disk. It is reconstructed instead as the previous revision's archived size
74     * plus the size change logged for the last revision. The first revision has no previous
75     * one, so its logged change is already its full size.
76     *
77     * @param int $recordedRev timestamp of the last recorded revision
78     * @return int size in bytes (0 when it cannot be determined)
79     */
80    protected function lastRevisionSize($recordedRev)
81    {
82        $revInfo = $this->getRevisionInfo($recordedRev, false);
83        $sizechange = is_array($revInfo) ? (int) $revInfo['sizechange'] : 0;
84
85        $prev = $this->getRelativeRevision($recordedRev, -1);
86        $prevSize = ($prev === false) ? 0 : io_getSizeFile($this->getFilename($prev));
87
88        return max($prevSize + $sizechange, 0);
89    }
90
91    /**
92     * Tell a real external edit from a mere mtime bump (touch, rsync --times, unzip of
93     * identical bytes, ...).
94     *
95     * The current media revision is never archived, so there is no stored copy to compare the
96     * current file against byte for byte. Its expected size is reconstructed instead (see
97     * lastRevisionSize()) and compared to the current file's size: a pure mtime bump leaves the
98     * size unchanged, so an equal size means the content did not change. A same-size external
99     * replacement cannot be told apart this way and is (rarely) treated as unchanged.
100     *
101     * @param int $rev revision timestamp to compare the current file against (the last revision)
102     * @return bool true if the content is considered unchanged
103     */
104    protected function currentContentMatchesRevision($rev)
105    {
106        $current = $this->getFilename();
107        if (!file_exists($current)) return false;
108
109        return filesize($current) === $this->lastRevisionSize($rev);
110    }
111}
112