xref: /dokuwiki/inc/File/PageFile.php (revision 7fba736b01498c2e738ca032b1b76fcd50dd2009)
1b24e9c4aSSatoshi Sahara<?php
2b24e9c4aSSatoshi Sahara
3b24e9c4aSSatoshi Saharanamespace dokuwiki\File;
4b24e9c4aSSatoshi Sahara
5b24e9c4aSSatoshi Saharause dokuwiki\Cache\CacheInstructions;
6b24e9c4aSSatoshi Saharause dokuwiki\ChangeLog\PageChangeLog;
7b24e9c4aSSatoshi Saharause dokuwiki\Extension\Event;
8b24e9c4aSSatoshi Saharause dokuwiki\Logger;
9b24e9c4aSSatoshi Sahara
10b24e9c4aSSatoshi Sahara/**
11b24e9c4aSSatoshi Sahara * Class PageFile : handles wiki text file and its change management for specific page
12b24e9c4aSSatoshi Sahara */
13b24e9c4aSSatoshi Saharaclass PageFile
14b24e9c4aSSatoshi Sahara{
15b24e9c4aSSatoshi Sahara    protected $id;
16b24e9c4aSSatoshi Sahara
17b24e9c4aSSatoshi Sahara    /* @var PageChangeLog $changelog */
18b24e9c4aSSatoshi Sahara    public $changelog;
19b24e9c4aSSatoshi Sahara
20b24e9c4aSSatoshi Sahara    /* @var array $data  initial data when event COMMON_WIKIPAGE_SAVE triggered */
21b24e9c4aSSatoshi Sahara    protected $data;
22b24e9c4aSSatoshi Sahara
23b24e9c4aSSatoshi Sahara    /**
24b24e9c4aSSatoshi Sahara     * PageFile constructor.
25b24e9c4aSSatoshi Sahara     *
26b24e9c4aSSatoshi Sahara     * @param string $id
27b24e9c4aSSatoshi Sahara     */
28b24e9c4aSSatoshi Sahara    public function __construct($id)
29b24e9c4aSSatoshi Sahara    {
30b24e9c4aSSatoshi Sahara        $this->id = $id;
31b24e9c4aSSatoshi Sahara        $this->changelog = new PageChangeLog($this->id);
32b24e9c4aSSatoshi Sahara    }
33b24e9c4aSSatoshi Sahara
34b24e9c4aSSatoshi Sahara    /** @return string */
35b24e9c4aSSatoshi Sahara    public function getId()
36b24e9c4aSSatoshi Sahara    {
37b24e9c4aSSatoshi Sahara        return $this->id;
38b24e9c4aSSatoshi Sahara    }
39b24e9c4aSSatoshi Sahara
40b24e9c4aSSatoshi Sahara    /** @return string */
41b24e9c4aSSatoshi Sahara    public function getPath($rev = '')
42b24e9c4aSSatoshi Sahara    {
43b24e9c4aSSatoshi Sahara        return wikiFN($this->id, $rev);
44b24e9c4aSSatoshi Sahara    }
45b24e9c4aSSatoshi Sahara
46b24e9c4aSSatoshi Sahara    /**
47b24e9c4aSSatoshi Sahara     * Get raw WikiText of the page, considering change type at revision date
48b24e9c4aSSatoshi Sahara     * similar to function rawWiki($id, $rev = '')
49b24e9c4aSSatoshi Sahara     *
50b24e9c4aSSatoshi Sahara     * @param int|false $rev  timestamp when a revision of wikitext is desired
51b24e9c4aSSatoshi Sahara     * @return string
52b24e9c4aSSatoshi Sahara     */
53b24e9c4aSSatoshi Sahara    public function rawWikiText($rev = null)
54b24e9c4aSSatoshi Sahara    {
55b24e9c4aSSatoshi Sahara        if ($rev !== null) {
56b24e9c4aSSatoshi Sahara            $revInfo = $rev ? $this->changelog->getRevisionInfo($rev) : false;
57b24e9c4aSSatoshi Sahara            return (!$revInfo || $revInfo['type'] == DOKU_CHANGE_TYPE_DELETE)
58b24e9c4aSSatoshi Sahara                ? '' // attic stores complete last page version for a deleted page
59b24e9c4aSSatoshi Sahara                : io_readWikiPage($this->getPath($rev), $this->id, $rev); // retrieve from attic
60b24e9c4aSSatoshi Sahara        } else {
61b24e9c4aSSatoshi Sahara            return io_readWikiPage($this->getPath(), $this->id, '');
62b24e9c4aSSatoshi Sahara        }
63b24e9c4aSSatoshi Sahara    }
64b24e9c4aSSatoshi Sahara
65b24e9c4aSSatoshi Sahara    /**
66b24e9c4aSSatoshi Sahara     * Saves a wikitext by calling io_writeWikiPage.
67b24e9c4aSSatoshi Sahara     * Also directs changelog and attic updates.
68b24e9c4aSSatoshi Sahara     *
69b24e9c4aSSatoshi Sahara     * @author Andreas Gohr <andi@splitbrain.org>
70b24e9c4aSSatoshi Sahara     * @author Ben Coburn <btcoburn@silicodon.net>
71b24e9c4aSSatoshi Sahara     *
72b24e9c4aSSatoshi Sahara     * @param string $text     wikitext being saved
73b24e9c4aSSatoshi Sahara     * @param string $summary  summary of text update
74b24e9c4aSSatoshi Sahara     * @param bool   $minor    mark this saved version as minor update
7536454bb5SSatoshi Sahara     * @return array data of event COMMON_WIKIPAGE_SAVE
76b24e9c4aSSatoshi Sahara     */
77b24e9c4aSSatoshi Sahara    public function saveWikiText($text, $summary, $minor = false)
78b24e9c4aSSatoshi Sahara    {
79b24e9c4aSSatoshi Sahara        /* Note to developers:
80b24e9c4aSSatoshi Sahara           This code is subtle and delicate. Test the behavior of
81b24e9c4aSSatoshi Sahara           the attic and changelog with dokuwiki and external edits
82b24e9c4aSSatoshi Sahara           after any changes. External edits change the wiki page
83b24e9c4aSSatoshi Sahara           directly without using php or dokuwiki.
84b24e9c4aSSatoshi Sahara         */
85b24e9c4aSSatoshi Sahara        global $conf;
86b24e9c4aSSatoshi Sahara        global $lang;
87b24e9c4aSSatoshi Sahara        global $REV;
88b24e9c4aSSatoshi Sahara        /* @var Input $INPUT */
89b24e9c4aSSatoshi Sahara        global $INPUT;
90b24e9c4aSSatoshi Sahara
91b24e9c4aSSatoshi Sahara        // prevent recursive call
92b24e9c4aSSatoshi Sahara        if (isset($this->data)) return;
93b24e9c4aSSatoshi Sahara
94b24e9c4aSSatoshi Sahara        $pagefile = $this->getPath();
95b24e9c4aSSatoshi Sahara        $currentRevision = @filemtime($pagefile);       // int or false
96b24e9c4aSSatoshi Sahara        $currentContent = $this->rawWikiText();
97b24e9c4aSSatoshi Sahara        $currentSize = file_exists($pagefile) ? filesize($pagefile) : 0;
98b24e9c4aSSatoshi Sahara
99b24e9c4aSSatoshi Sahara        // prepare data for event COMMON_WIKIPAGE_SAVE
100b24e9c4aSSatoshi Sahara        $data = array(
101b24e9c4aSSatoshi Sahara            'id'             => $this->id, // should not be altered by any handlers
102b24e9c4aSSatoshi Sahara            'file'           => $pagefile, // same above
103b24e9c4aSSatoshi Sahara            'changeType'     => null,      // set prior to event, and confirm later
104b24e9c4aSSatoshi Sahara            'revertFrom'     => $REV,
105b24e9c4aSSatoshi Sahara            'oldRevision'    => $currentRevision,
106b24e9c4aSSatoshi Sahara            'oldContent'     => $currentContent,
107b24e9c4aSSatoshi Sahara            'newRevision'    => 0,         // only available in the after hook
108b24e9c4aSSatoshi Sahara            'newContent'     => $text,
109b24e9c4aSSatoshi Sahara            'summary'        => $summary,
110b24e9c4aSSatoshi Sahara            'contentChanged' => (bool)($text != $currentContent), // confirm later
111b24e9c4aSSatoshi Sahara            'changeInfo'     => '',        // automatically determined by revertFrom
112b24e9c4aSSatoshi Sahara            'sizechange'     => strlen($text) - strlen($currentContent), // TBD
113b24e9c4aSSatoshi Sahara        );
114b24e9c4aSSatoshi Sahara
115b24e9c4aSSatoshi Sahara        // determine tentatively change type and relevant elements of event data
116b24e9c4aSSatoshi Sahara        if ($data['revertFrom']) {
117b24e9c4aSSatoshi Sahara            // new text may differ from exact revert revision
118b24e9c4aSSatoshi Sahara            $data['changeType'] = DOKU_CHANGE_TYPE_REVERT;
119b24e9c4aSSatoshi Sahara            $data['changeInfo'] = $REV;
120b24e9c4aSSatoshi Sahara        } elseif (trim($data['newContent']) == '') {
121b24e9c4aSSatoshi Sahara            // empty or whitespace only content deletes
122b24e9c4aSSatoshi Sahara            $data['changeType'] = DOKU_CHANGE_TYPE_DELETE;
123b24e9c4aSSatoshi Sahara        } elseif (!file_exists($pagefile)) {
124b24e9c4aSSatoshi Sahara            $data['changeType'] = DOKU_CHANGE_TYPE_CREATE;
125b24e9c4aSSatoshi Sahara        } else {
126b24e9c4aSSatoshi Sahara            // minor edits allowable only for logged in users
127b24e9c4aSSatoshi Sahara            $is_minor_change = ($minor && $conf['useacl'] && $INPUT->server->str('REMOTE_USER'));
128b24e9c4aSSatoshi Sahara            $data['changeType'] = $is_minor_change
129b24e9c4aSSatoshi Sahara                ? DOKU_CHANGE_TYPE_MINOR_EDIT
130b24e9c4aSSatoshi Sahara                : DOKU_CHANGE_TYPE_EDIT;
131b24e9c4aSSatoshi Sahara        }
132b24e9c4aSSatoshi Sahara
133b24e9c4aSSatoshi Sahara        $this->data = $data;
13436454bb5SSatoshi Sahara        $data['page'] = $this; // allow event handlers to use this class methods
13536454bb5SSatoshi Sahara
136b24e9c4aSSatoshi Sahara        $event = new Event('COMMON_WIKIPAGE_SAVE', $data);
137b24e9c4aSSatoshi Sahara        if (!$event->advise_before()) return;
138b24e9c4aSSatoshi Sahara
139b24e9c4aSSatoshi Sahara        // if the content has not been changed, no save happens (plugins may override this)
140b24e9c4aSSatoshi Sahara        if (!$data['contentChanged']) return;
141b24e9c4aSSatoshi Sahara
142b24e9c4aSSatoshi Sahara        // Check whether the pagefile has modified during $event->advise_before()
143b24e9c4aSSatoshi Sahara        clearstatcache();
144b24e9c4aSSatoshi Sahara        $fileRev = @filemtime($pagefile);
145b24e9c4aSSatoshi Sahara        if ($fileRev === $currentRevision) {
146b24e9c4aSSatoshi Sahara            // pagefile has not touched by plugin's event handler
147b24e9c4aSSatoshi Sahara            // add a potential external edit entry to changelog and store it into attic
148b24e9c4aSSatoshi Sahara            $this->detectExternalEdit();
149b24e9c4aSSatoshi Sahara            $filesize_old = $currentSize;
150b24e9c4aSSatoshi Sahara        } else {
151b24e9c4aSSatoshi Sahara            // pagefile has modified by plugin's event handler, confirm sizechange
152b24e9c4aSSatoshi Sahara            $filesize_old = (
153b24e9c4aSSatoshi Sahara                $data['changeType'] == DOKU_CHANGE_TYPE_CREATE || (
154b24e9c4aSSatoshi Sahara                $data['changeType'] == DOKU_CHANGE_TYPE_REVERT && !file_exists($pagefile))
155b24e9c4aSSatoshi Sahara            ) ? 0 : filesize($pagefile);
156b24e9c4aSSatoshi Sahara        }
157b24e9c4aSSatoshi Sahara
158b24e9c4aSSatoshi Sahara        // make change to the current file
159b24e9c4aSSatoshi Sahara        if ($data['changeType'] == DOKU_CHANGE_TYPE_DELETE) {
160b24e9c4aSSatoshi Sahara            // nothing to do when the file has already deleted
161b24e9c4aSSatoshi Sahara            if (!file_exists($pagefile)) return;
162b24e9c4aSSatoshi Sahara            // autoset summary on deletion
163b24e9c4aSSatoshi Sahara            if (blank($data['summary'])) {
164b24e9c4aSSatoshi Sahara                $data['summary'] = $lang['deleted'];
165b24e9c4aSSatoshi Sahara            }
166b24e9c4aSSatoshi Sahara            // send "update" event with empty data, so plugins can react to page deletion
167666bc21dSSatoshi Sahara            $ioData = array([$pagefile, '', false], getNS($this->id), noNS($this->id), false);
168b24e9c4aSSatoshi Sahara            Event::createAndTrigger('IO_WIKIPAGE_WRITE', $ioData);
169b24e9c4aSSatoshi Sahara            // pre-save deleted revision
170b24e9c4aSSatoshi Sahara            @touch($pagefile);
171b24e9c4aSSatoshi Sahara            clearstatcache();
172b24e9c4aSSatoshi Sahara            $data['newRevision'] = $this->saveOldRevision();
173b24e9c4aSSatoshi Sahara            // remove empty file
174b24e9c4aSSatoshi Sahara            @unlink($pagefile);
175b24e9c4aSSatoshi Sahara            $filesize_new = 0;
176b24e9c4aSSatoshi Sahara            // don't remove old meta info as it should be saved, plugins can use
177b24e9c4aSSatoshi Sahara            // IO_WIKIPAGE_WRITE for removing their metadata...
178b24e9c4aSSatoshi Sahara            // purge non-persistant meta data
179b24e9c4aSSatoshi Sahara            p_purge_metadata($this->id);
180b24e9c4aSSatoshi Sahara            // remove empty namespaces
181b24e9c4aSSatoshi Sahara            io_sweepNS($this->id, 'datadir');
182b24e9c4aSSatoshi Sahara            io_sweepNS($this->id, 'mediadir');
183b24e9c4aSSatoshi Sahara        } else {
184b24e9c4aSSatoshi Sahara            // save file (namespace dir is created in io_writeWikiPage)
185b24e9c4aSSatoshi Sahara            io_writeWikiPage($pagefile, $data['newContent'], $this->id);
186b24e9c4aSSatoshi Sahara            // pre-save the revision, to keep the attic in sync
187b24e9c4aSSatoshi Sahara            $data['newRevision'] = $this->saveOldRevision();
188b24e9c4aSSatoshi Sahara            $filesize_new = filesize($pagefile);
189b24e9c4aSSatoshi Sahara        }
190b24e9c4aSSatoshi Sahara        $data['sizechange'] = $filesize_new - $filesize_old;
191b24e9c4aSSatoshi Sahara
192b24e9c4aSSatoshi Sahara        $event->advise_after();
193b24e9c4aSSatoshi Sahara
194*7fba736bSSatoshi Sahara        unset($data['page']);
195*7fba736bSSatoshi Sahara
196b24e9c4aSSatoshi Sahara        // adds an entry to the changelog and saves the metadata for the page
197*7fba736bSSatoshi Sahara        $logEntry = $this->changelog->addLogEntry([
198*7fba736bSSatoshi Sahara            'date'       => $data['newRevision'],
199*7fba736bSSatoshi Sahara            'ip'         => clientIP(true),
200*7fba736bSSatoshi Sahara            'type'       => $data['changeType'],
201*7fba736bSSatoshi Sahara            'id'         => $this->id,
202*7fba736bSSatoshi Sahara            'user'       => $INPUT->server->str('REMOTE_USER'),
203*7fba736bSSatoshi Sahara            'sum'        => $data['summary'],
204*7fba736bSSatoshi Sahara            'extra'      => $data['changeInfo'],
205*7fba736bSSatoshi Sahara            'sizechange' => $data['sizechange'],
206*7fba736bSSatoshi Sahara        ]);
207*7fba736bSSatoshi Sahara        // update metadata
208*7fba736bSSatoshi Sahara        $this->updateMetadata($logEntry);
209b24e9c4aSSatoshi Sahara
210b24e9c4aSSatoshi Sahara        // update the purgefile (timestamp of the last time anything within the wiki was changed)
211b24e9c4aSSatoshi Sahara        io_saveFile($conf['cachedir'].'/purgefile', time());
212b24e9c4aSSatoshi Sahara
213b24e9c4aSSatoshi Sahara        return $data;
214b24e9c4aSSatoshi Sahara    }
215b24e9c4aSSatoshi Sahara
216b24e9c4aSSatoshi Sahara    /**
217b24e9c4aSSatoshi Sahara     * Checks if the current page version is newer than the last entry in the page's changelog.
218b24e9c4aSSatoshi Sahara     * If so, we assume it has been an external edit and we create an attic copy and add a proper
219b24e9c4aSSatoshi Sahara     * changelog line.
220b24e9c4aSSatoshi Sahara     *
221b24e9c4aSSatoshi Sahara     * This check is only executed when the page is about to be saved again from the wiki,
222b24e9c4aSSatoshi Sahara     * triggered in @see saveWikiText()
223b24e9c4aSSatoshi Sahara     */
224b24e9c4aSSatoshi Sahara    public function detectExternalEdit()
225b24e9c4aSSatoshi Sahara    {
226b24e9c4aSSatoshi Sahara        $revInfo = $this->changelog->getCurrentRevisionInfo();
227b24e9c4aSSatoshi Sahara
228b24e9c4aSSatoshi Sahara        // only interested in external revision
229b24e9c4aSSatoshi Sahara        if (empty($revInfo) || !array_key_exists('timestamp', $revInfo)) return;
230b24e9c4aSSatoshi Sahara
231b24e9c4aSSatoshi Sahara        if ($revInfo['type'] != DOKU_CHANGE_TYPE_DELETE && !$revInfo['timestamp']) {
232b24e9c4aSSatoshi Sahara            // file is older than last revision, that is erroneous/incorrect occurence.
233b24e9c4aSSatoshi Sahara            // try to change file modification time
234b24e9c4aSSatoshi Sahara            $fileLastMod = $this->getPath();
235b24e9c4aSSatoshi Sahara            $wrong_timestamp = filemtime($fileLastMod);
236b24e9c4aSSatoshi Sahara            if (touch($fileLastMod, $revInfo['date'])) {
237b24e9c4aSSatoshi Sahara                clearstatcache();
238b24e9c4aSSatoshi Sahara                $msg = "detectExternalEdit($id): timestamp successfully modified";
239b24e9c4aSSatoshi Sahara                $details = '('.$wrong_timestamp.' -> '.$revInfo['date'].')';
240b24e9c4aSSatoshi Sahara                Logger::error($msg, $details, $fileLastMod);
241b24e9c4aSSatoshi Sahara            } else {
242b24e9c4aSSatoshi Sahara                // runtime error
243b24e9c4aSSatoshi Sahara                $msg = "detectExternalEdit($id): page file should be newer than last revision "
244b24e9c4aSSatoshi Sahara                      .'('.filemtime($fileLastMod).' < '. $this->changelog->lastRevision() .')';
245b24e9c4aSSatoshi Sahara                throw new \RuntimeException($msg);
246b24e9c4aSSatoshi Sahara            }
247b24e9c4aSSatoshi Sahara        }
248b24e9c4aSSatoshi Sahara
249b24e9c4aSSatoshi Sahara        // keep at least 1 sec before new page save
250b24e9c4aSSatoshi Sahara        if ($revInfo['date'] == time()) sleep(1); // wait a tick
251b24e9c4aSSatoshi Sahara
252b24e9c4aSSatoshi Sahara        // store externally edited file to the attic folder
253b24e9c4aSSatoshi Sahara        $this->saveOldRevision();
254b24e9c4aSSatoshi Sahara        // add a changelog entry for externally edited file
255b24e9c4aSSatoshi Sahara        $revInfo = $this->changelog->addLogEntry($revInfo);
256b24e9c4aSSatoshi Sahara        // remove soon to be stale instructions
257b24e9c4aSSatoshi Sahara        $cache = new CacheInstructions($this->id, $this->getPath());
258b24e9c4aSSatoshi Sahara        $cache->removeCache();
259b24e9c4aSSatoshi Sahara    }
260b24e9c4aSSatoshi Sahara
261b24e9c4aSSatoshi Sahara    /**
262b24e9c4aSSatoshi Sahara     * Moves the current version to the attic and returns its revision date
263b24e9c4aSSatoshi Sahara     *
264b24e9c4aSSatoshi Sahara     * @author Andreas Gohr <andi@splitbrain.org>
265b24e9c4aSSatoshi Sahara     *
266b24e9c4aSSatoshi Sahara     * @return int|string revision timestamp
267b24e9c4aSSatoshi Sahara     */
268b24e9c4aSSatoshi Sahara    public function saveOldRevision()
269b24e9c4aSSatoshi Sahara    {
270b24e9c4aSSatoshi Sahara        $oldfile = $this->getPath();
271b24e9c4aSSatoshi Sahara        if (!file_exists($oldfile)) return '';
272b24e9c4aSSatoshi Sahara        $date = filemtime($oldfile);
273b24e9c4aSSatoshi Sahara        $newfile = $this->getPath($date);
274b24e9c4aSSatoshi Sahara        io_writeWikiPage($newfile, $this->rawWikiText(), $this->id, $date);
275b24e9c4aSSatoshi Sahara        return $date;
276b24e9c4aSSatoshi Sahara    }
277b24e9c4aSSatoshi Sahara
278*7fba736bSSatoshi Sahara    /**
279*7fba736bSSatoshi Sahara     * Update metadata of changed page
280*7fba736bSSatoshi Sahara     *
281*7fba736bSSatoshi Sahara     * @param array $logEntry  changelog entry
282*7fba736bSSatoshi Sahara     */
283*7fba736bSSatoshi Sahara    public function updateMetadata(array $logEntry)
284*7fba736bSSatoshi Sahara    {
285*7fba736bSSatoshi Sahara        global $INFO;
286*7fba736bSSatoshi Sahara
287*7fba736bSSatoshi Sahara        list(
288*7fba736bSSatoshi Sahara            'date' => $date,
289*7fba736bSSatoshi Sahara            'type' => $changeType,
290*7fba736bSSatoshi Sahara            'user' => $user,
291*7fba736bSSatoshi Sahara        ) = $logEntry;
292*7fba736bSSatoshi Sahara
293*7fba736bSSatoshi Sahara        $wasRemoved   = ($changeType === DOKU_CHANGE_TYPE_DELETE);
294*7fba736bSSatoshi Sahara        $wasCreated   = ($changeType === DOKU_CHANGE_TYPE_CREATE);
295*7fba736bSSatoshi Sahara        $wasReverted  = ($changeType === DOKU_CHANGE_TYPE_REVERT);
296*7fba736bSSatoshi Sahara        $wasMinorEdit = ($changeType === DOKU_CHANGE_TYPE_MINOR_EDIT);
297*7fba736bSSatoshi Sahara
298*7fba736bSSatoshi Sahara        $created = @filectime($pagefile); // @filectime($this->getPath())
299*7fba736bSSatoshi Sahara
300*7fba736bSSatoshi Sahara        if ($wasRemoved) return;
301*7fba736bSSatoshi Sahara
302*7fba736bSSatoshi Sahara        $oldmeta = p_read_metadata($this->id)['persistent'];
303*7fba736bSSatoshi Sahara        $meta    = array();
304*7fba736bSSatoshi Sahara
305*7fba736bSSatoshi Sahara        if ($wasCreated &&
306*7fba736bSSatoshi Sahara            (empty($oldmeta['date']['created']) || $oldmeta['date']['created'] === $created)
307*7fba736bSSatoshi Sahara        ) {
308*7fba736bSSatoshi Sahara            // newly created
309*7fba736bSSatoshi Sahara            $meta['date']['created'] = $created;
310*7fba736bSSatoshi Sahara            if ($user) {
311*7fba736bSSatoshi Sahara                $meta['creator'] = isset($INFO) ? $INFO['userinfo']['name'] : null;
312*7fba736bSSatoshi Sahara                $meta['user']    = $user;
313*7fba736bSSatoshi Sahara            }
314*7fba736bSSatoshi Sahara        } elseif (($wasCreated || $wasReverted) && !empty($oldmeta['date']['created'])) {
315*7fba736bSSatoshi Sahara            // re-created / restored
316*7fba736bSSatoshi Sahara            $meta['date']['created']  = $oldmeta['date']['created'];
317*7fba736bSSatoshi Sahara            $meta['date']['modified'] = $created; // use the files ctime here
318*7fba736bSSatoshi Sahara            $meta['creator'] = isset($oldmeta['creator']) ? $oldmeta['creator'] : null;
319*7fba736bSSatoshi Sahara            if ($user) {
320*7fba736bSSatoshi Sahara                $meta['contributor'][$user] = isset($INFO) ? $INFO['userinfo']['name'] : null;
321*7fba736bSSatoshi Sahara            }
322*7fba736bSSatoshi Sahara        } elseif (!$wasMinorEdit) {   // non-minor modification
323*7fba736bSSatoshi Sahara            $meta['date']['modified'] = $date;
324*7fba736bSSatoshi Sahara            if ($user) {
325*7fba736bSSatoshi Sahara                $meta['contributor'][$user] = isset($INFO) ? $INFO['userinfo']['name'] : null;
326*7fba736bSSatoshi Sahara            }
327*7fba736bSSatoshi Sahara        }
328*7fba736bSSatoshi Sahara        $meta['last_change'] = $logEntry;
329*7fba736bSSatoshi Sahara        p_set_metadata($this->id, $meta);
330*7fba736bSSatoshi Sahara    }
331*7fba736bSSatoshi Sahara
332b24e9c4aSSatoshi Sahara}
333