10c3a5702SAndreas Gohr<?php 20c3a5702SAndreas Gohr 30c3a5702SAndreas Gohrnamespace dokuwiki\ChangeLog; 40c3a5702SAndreas Gohr 50c3a5702SAndreas Gohr/** 607869ee7SSatoshi Sahara * Class MediaChangeLog; handles changelog of a media file 70c3a5702SAndreas Gohr */ 80c3a5702SAndreas Gohrclass MediaChangeLog extends ChangeLog 90c3a5702SAndreas Gohr{ 100c3a5702SAndreas Gohr /** 110c3a5702SAndreas Gohr * Returns path to changelog 120c3a5702SAndreas Gohr * 130c3a5702SAndreas Gohr * @return string path to file 140c3a5702SAndreas Gohr */ 150c3a5702SAndreas Gohr protected function getChangelogFilename() 160c3a5702SAndreas Gohr { 170c3a5702SAndreas Gohr return mediaMetaFN($this->id, '.changes'); 180c3a5702SAndreas Gohr } 190c3a5702SAndreas Gohr 200c3a5702SAndreas Gohr /** 210c3a5702SAndreas Gohr * Returns path to current page/media 220c3a5702SAndreas Gohr * 23e49fa56bSSatoshi Sahara * @param string|int $rev empty string or revision timestamp 240c3a5702SAndreas Gohr * @return string path to file 250c3a5702SAndreas Gohr */ 26e49fa56bSSatoshi Sahara protected function getFilename($rev = '') 270c3a5702SAndreas Gohr { 28e49fa56bSSatoshi Sahara return mediaFN($this->id, $rev); 290c3a5702SAndreas Gohr } 30c7192766SSatoshi Sahara 31a835c93aSGerrit Uitslag /** 32a835c93aSGerrit Uitslag * Returns mode 33a835c93aSGerrit Uitslag * 34a835c93aSGerrit Uitslag * @return string RevisionInfo::MODE_PAGE 35a835c93aSGerrit Uitslag */ 36a835c93aSGerrit Uitslag protected function getMode() 37a835c93aSGerrit Uitslag { 38a835c93aSGerrit Uitslag return RevisionInfo::MODE_MEDIA; 39a835c93aSGerrit Uitslag } 40c7192766SSatoshi Sahara 4101e8d739SAndreas Gohr /** 4201e8d739SAndreas Gohr * Returns path to the global media-changelog file 4301e8d739SAndreas Gohr * 4401e8d739SAndreas Gohr * @return string path to file 4501e8d739SAndreas Gohr */ 4601e8d739SAndreas Gohr protected function getGlobalChangelogFilename() 4701e8d739SAndreas Gohr { 4801e8d739SAndreas Gohr global $conf; 4901e8d739SAndreas Gohr return $conf['media_changelog']; 5001e8d739SAndreas Gohr } 51c7192766SSatoshi Sahara 52c7192766SSatoshi Sahara /** 535a285debSAndreas Gohr * Media deliberately does not keep an archive of its current revision — only the previous 545a285debSAndreas Gohr * content is copied to the attic when a file is replaced or deleted (to save space). A 555a285debSAndreas Gohr * detected external edit is the new current revision, so it is not snapshotted either: it 565a285debSAndreas Gohr * will be archived like any other revision if and when it is later replaced. The changelog 575a285debSAndreas Gohr * entry is still recorded by the caller, and the file-mtime repair for an unreliable date 585a285debSAndreas Gohr * is handled by the base class. 59c7192766SSatoshi Sahara * 605a285debSAndreas Gohr * @param array $revInfo synthesized revision info (unused: nothing is archived) 615a285debSAndreas Gohr * @return bool always true 62c7192766SSatoshi Sahara */ 6301e8d739SAndreas Gohr protected function saveExternalAttic(array $revInfo) 64c7192766SSatoshi Sahara { 6501e8d739SAndreas Gohr return true; 66c7192766SSatoshi Sahara } 670a245329SAndreas Gohr 680a245329SAndreas Gohr /** 695a285debSAndreas Gohr * Byte size of the last recorded revision. 700a245329SAndreas Gohr * 715a285debSAndreas Gohr * Media never archives its current revision (only the previous content is copied to the 725a285debSAndreas Gohr * attic on replace or delete), so the last revision has no attic copy and its size cannot 735a285debSAndreas Gohr * be read from disk. It is reconstructed instead as the previous revision's archived size 745a285debSAndreas Gohr * plus the size change logged for the last revision. The first revision has no previous 755a285debSAndreas Gohr * one, so its logged change is already its full size. 760a245329SAndreas Gohr * 77*6f10c544SAndreas Gohr * @param int $recordedRev timestamp of the last recorded revision 785a285debSAndreas Gohr * @return int size in bytes (0 when it cannot be determined) 795a285debSAndreas Gohr */ 80*6f10c544SAndreas Gohr protected function lastRevisionSize($recordedRev) 815a285debSAndreas Gohr { 82*6f10c544SAndreas Gohr $revInfo = $this->getRevisionInfo($recordedRev, false); 835a285debSAndreas Gohr $sizechange = is_array($revInfo) ? (int) $revInfo['sizechange'] : 0; 845a285debSAndreas Gohr 85*6f10c544SAndreas Gohr $prev = $this->getRelativeRevision($recordedRev, -1); 865a285debSAndreas Gohr $prevSize = ($prev === false) ? 0 : io_getSizeFile($this->getFilename($prev)); 875a285debSAndreas Gohr 885a285debSAndreas Gohr return max($prevSize + $sizechange, 0); 895a285debSAndreas Gohr } 905a285debSAndreas Gohr 915a285debSAndreas Gohr /** 925a285debSAndreas Gohr * Tell a real external edit from a mere mtime bump (touch, rsync --times, unzip of 935a285debSAndreas Gohr * identical bytes, ...). 945a285debSAndreas Gohr * 955a285debSAndreas Gohr * The current media revision is never archived, so there is no stored copy to compare the 965a285debSAndreas Gohr * current file against byte for byte. Its expected size is reconstructed instead (see 975a285debSAndreas Gohr * lastRevisionSize()) and compared to the current file's size: a pure mtime bump leaves the 985a285debSAndreas Gohr * size unchanged, so an equal size means the content did not change. A same-size external 995a285debSAndreas Gohr * replacement cannot be told apart this way and is (rarely) treated as unchanged. 1005a285debSAndreas Gohr * 1015a285debSAndreas Gohr * @param int $rev revision timestamp to compare the current file against (the last revision) 1025a285debSAndreas Gohr * @return bool true if the content is considered unchanged 1030a245329SAndreas Gohr */ 1040a245329SAndreas Gohr protected function currentContentMatchesRevision($rev) 1050a245329SAndreas Gohr { 1060a245329SAndreas Gohr $current = $this->getFilename(); 1075a285debSAndreas Gohr if (!file_exists($current)) return false; 1080a245329SAndreas Gohr 1095a285debSAndreas Gohr return filesize($current) === $this->lastRevisionSize($rev); 1100a245329SAndreas Gohr } 1110c3a5702SAndreas Gohr} 112