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 $clogRev timestamp of the last recorded revision 78 * @return int size in bytes (0 when it cannot be determined) 79 */ 80 protected function lastRevisionSize($clogRev) 81 { 82 $revInfo = $this->getRevisionInfo($clogRev, false); 83 $sizechange = is_array($revInfo) ? (int) $revInfo['sizechange'] : 0; 84 85 $prev = $this->getRelativeRevision($clogRev, -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