xref: /plugin/discussion/action.php (revision c3413364e899c9a3fd349480069bbe9b8c803d5a)
1f0fda08aSwikidesign<?php
2f0fda08aSwikidesign/**
3f0fda08aSwikidesign * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4f0fda08aSwikidesign * @author     Esther Brunner <wikidesign@gmail.com>
5f0fda08aSwikidesign */
6f0fda08aSwikidesign
7*c3413364SGerrit Uitslaguse dokuwiki\Extension\Event;
8*c3413364SGerrit Uitslaguse dokuwiki\Subscriptions\SubscriberManager;
9*c3413364SGerrit Uitslaguse dokuwiki\Utf8\PhpString;
10*c3413364SGerrit Uitslag
11de7e6f00SGerrit Uitslag/**
12de7e6f00SGerrit Uitslag * Class action_plugin_discussion
13*c3413364SGerrit Uitslag *
14*c3413364SGerrit Uitslag * Data format of file metadir/<id>.comments:
15*c3413364SGerrit Uitslag * array = [
16*c3413364SGerrit Uitslag *  'status' => int whether comments are 0=disabled/1=open/2=closed,
17*c3413364SGerrit Uitslag *  'number' => int number of visible comments,
18*c3413364SGerrit Uitslag *  'title' => string alternative title for discussion section
19*c3413364SGerrit Uitslag *  'comments' => [
20*c3413364SGerrit Uitslag *      '<cid>'=> [
21*c3413364SGerrit Uitslag *          'cid' => string comment id - long random string
22*c3413364SGerrit Uitslag *          'raw' => string comment text,
23*c3413364SGerrit Uitslag *          'xhtml' => string rendered html,
24*c3413364SGerrit Uitslag *          'parent' => null|string null or empty string at highest level, otherwise comment id of parent
25*c3413364SGerrit Uitslag *          'replies' => string[] array with comment ids
26*c3413364SGerrit Uitslag *          'user' => [
27*c3413364SGerrit Uitslag *              'id' => string,
28*c3413364SGerrit Uitslag *              'name' => string,
29*c3413364SGerrit Uitslag *              'mail' => string,
30*c3413364SGerrit Uitslag *              'address' => string,
31*c3413364SGerrit Uitslag *              'url' => string
32*c3413364SGerrit Uitslag *          ],
33*c3413364SGerrit Uitslag *          'date' => [
34*c3413364SGerrit Uitslag *              'created' => int timestamp,
35*c3413364SGerrit Uitslag *              'modified' => int (not defined if not modified)
36*c3413364SGerrit Uitslag *          ],
37*c3413364SGerrit Uitslag *          'show' => bool, whether shown (still be moderated, or hidden by moderator or user self)
38*c3413364SGerrit Uitslag *      ],
39*c3413364SGerrit Uitslag *      ...
40*c3413364SGerrit Uitslag *   ]
41*c3413364SGerrit Uitslag *   'subscribers' => [
42*c3413364SGerrit Uitslag *      '<mail>' => [
43*c3413364SGerrit Uitslag *          'hash' => string unique token,
44*c3413364SGerrit Uitslag *          'active' => bool, true if confirmed
45*c3413364SGerrit Uitslag *          'confirmsent' => bool, true if confirmation mail is sent
46*c3413364SGerrit Uitslag *      ],
47*c3413364SGerrit Uitslag *      ...
48*c3413364SGerrit Uitslag *   ]
49de7e6f00SGerrit Uitslag */
50f0fda08aSwikidesignclass action_plugin_discussion extends DokuWiki_Action_Plugin{
51f0fda08aSwikidesign
52de7e6f00SGerrit Uitslag    /** @var helper_plugin_avatar */
53*c3413364SGerrit Uitslag    protected $avatar = null;
54*c3413364SGerrit Uitslag    /** @var null|string */
55*c3413364SGerrit Uitslag    protected $style = null;
56*c3413364SGerrit Uitslag    /** @var null|bool */
57*c3413364SGerrit Uitslag    protected $useAvatar = null;
58de7e6f00SGerrit Uitslag    /** @var helper_plugin_discussion */
59*c3413364SGerrit Uitslag    protected $helper = null;
60e6b2f142Slupo49
61de7e6f00SGerrit Uitslag    /**
62de7e6f00SGerrit Uitslag     * load helper
63de7e6f00SGerrit Uitslag     */
64e6b2f142Slupo49    public function __construct() {
65e6b2f142Slupo49        $this->helper = plugin_load('helper', 'discussion');
66e6b2f142Slupo49    }
67f1c6610eSpierre.spring
68de7e6f00SGerrit Uitslag    /**
69de7e6f00SGerrit Uitslag     * Register the handlers
70de7e6f00SGerrit Uitslag     *
71*c3413364SGerrit Uitslag     * @param Doku_Event_Handler $controller DokuWiki's event controller object.
72de7e6f00SGerrit Uitslag     */
73*c3413364SGerrit Uitslag    public function register(Doku_Event_Handler $controller) {
74*c3413364SGerrit Uitslag        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleCommentActions');
75*c3413364SGerrit Uitslag        $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'renderCommentsSection');
76*c3413364SGerrit Uitslag        $controller->register_hook('INDEXER_PAGE_ADD', 'AFTER', $this, 'addCommentsToIndex', ['id' => 'page', 'text' => 'body']);
77*c3413364SGerrit Uitslag        $controller->register_hook('FULLTEXT_SNIPPET_CREATE', 'BEFORE', $this, 'addCommentsToIndex', ['id' => 'id', 'text' => 'text']);
78*c3413364SGerrit Uitslag        $controller->register_hook('INDEXER_VERSION_GET', 'BEFORE', $this, 'addIndexVersion', []);
79*c3413364SGerrit Uitslag        $controller->register_hook('FULLTEXT_PHRASE_MATCH', 'AFTER', $this, 'fulltextPhraseMatchInComments', []);
80*c3413364SGerrit Uitslag        $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, 'update_comment_status', []);
81*c3413364SGerrit Uitslag        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'addToolbarToCommentfield', []);
82*c3413364SGerrit Uitslag        $controller->register_hook('TOOLBAR_DEFINE', 'AFTER', $this, 'modifyToolbar', []);
83*c3413364SGerrit Uitslag        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'ajaxPreviewComments', []);
84*c3413364SGerrit Uitslag        $controller->register_hook('TPL_TOC_RENDER', 'BEFORE', $this, 'addDiscussionToTOC', []);
85b8fdc796SMichael Klier    }
86b8fdc796SMichael Klier
87b8fdc796SMichael Klier    /**
88b8fdc796SMichael Klier     * Preview Comments
89b8fdc796SMichael Klier     *
90b8fdc796SMichael Klier     * @author Michael Klier <chi@chimeric.de>
91de7e6f00SGerrit Uitslag     *
92de7e6f00SGerrit Uitslag     * @param Doku_Event $event
93de7e6f00SGerrit Uitslag     * @param $params
94b8fdc796SMichael Klier     */
95*c3413364SGerrit Uitslag    public function ajaxPreviewComments(Doku_Event $event, $params) {
96*c3413364SGerrit Uitslag        global $INPUT;
97b8fdc796SMichael Klier        if($event->data != 'discussion_preview') return;
98*c3413364SGerrit Uitslag
99b8fdc796SMichael Klier        $event->preventDefault();
100b8fdc796SMichael Klier        $event->stopPropagation();
101b8fdc796SMichael Klier        print p_locale_xhtml('preview');
102b8fdc796SMichael Klier        print '<div class="comment_preview">';
103*c3413364SGerrit Uitslag        if(!$INPUT->server->str('REMOTE_USER') && !$this->getConf('allowguests')) {
104b8fdc796SMichael Klier            print p_locale_xhtml('denied');
105b8fdc796SMichael Klier        } else {
106*c3413364SGerrit Uitslag            print $this->renderComment($INPUT->post->str('comment'));
107b8fdc796SMichael Klier        }
108b8fdc796SMichael Klier        print '</div>';
1092d4bee9aSMichael Klier    }
1102d4bee9aSMichael Klier
1112d4bee9aSMichael Klier    /**
1125886c85bSMichael Klier     * Adds a TOC item if a discussion exists
1135886c85bSMichael Klier     *
1145886c85bSMichael Klier     * @author Michael Klier <chi@chimeric.de>
115de7e6f00SGerrit Uitslag     *
116de7e6f00SGerrit Uitslag     * @param Doku_Event $event
117de7e6f00SGerrit Uitslag     * @param $params
1185886c85bSMichael Klier     */
119*c3413364SGerrit Uitslag    public function addDiscussionToTOC(Doku_Event $event, $params) {
1208c057533SMichael Klier        global $ACT;
121*c3413364SGerrit Uitslag        if($this->hasDiscussion($title) && $event->data && $ACT != 'admin') {
122*c3413364SGerrit Uitslag            $tocitem = ['hid' => 'discussion__section',
1235886c85bSMichael Klier                              'title' => $this->getLang('discussion'),
1245886c85bSMichael Klier                              'type' => 'ul',
125*c3413364SGerrit Uitslag                              'level' => 1];
1265886c85bSMichael Klier
127*c3413364SGerrit Uitslag            $event->data[] = $tocitem;
1285886c85bSMichael Klier        }
1295886c85bSMichael Klier    }
1305886c85bSMichael Klier
1315886c85bSMichael Klier    /**
132*c3413364SGerrit Uitslag     * Modify Toolbar for use with discussion plugin
1332d4bee9aSMichael Klier     *
1342d4bee9aSMichael Klier     * @author Michael Klier <chi@chimeric.de>
135de7e6f00SGerrit Uitslag     *
136de7e6f00SGerrit Uitslag     * @param Doku_Event $event
137de7e6f00SGerrit Uitslag     * @param $param
1382d4bee9aSMichael Klier     */
139*c3413364SGerrit Uitslag    public function modifyToolbar(Doku_Event $event, $param) {
1402d4bee9aSMichael Klier        global $ACT;
1412d4bee9aSMichael Klier        if($ACT != 'show') return;
1422d4bee9aSMichael Klier
143*c3413364SGerrit Uitslag        if($this->hasDiscussion($title) && $this->getConf('wikisyntaxok')) {
144*c3413364SGerrit Uitslag            $toolbar = [];
1452d4bee9aSMichael Klier            foreach($event->data as $btn) {
1462d4bee9aSMichael Klier                if($btn['type'] == 'mediapopup') continue;
1472d4bee9aSMichael Klier                if($btn['type'] == 'signature') continue;
148310210d6SGina Haeussge                if($btn['type'] == 'linkwiz') continue;
1491dc736fbSGerrit Uitslag                if($btn['type'] == 'NewTable') continue; //skip button for Edittable Plugin
150*c3413364SGerrit Uitslag                if(isset($btn['open']) && preg_match("/=+?/", $btn['open'])) continue;
151*c3413364SGerrit Uitslag
152*c3413364SGerrit Uitslag                $toolbar[] = $btn;
1532d4bee9aSMichael Klier            }
1542d4bee9aSMichael Klier            $event->data = $toolbar;
1552d4bee9aSMichael Klier        }
1562d4bee9aSMichael Klier    }
1572d4bee9aSMichael Klier
1582d4bee9aSMichael Klier    /**
1592d4bee9aSMichael Klier     * Dirty workaround to add a toolbar to the discussion plugin
1602d4bee9aSMichael Klier     *
1612d4bee9aSMichael Klier     * @author Michael Klier <chi@chimeric.de>
162de7e6f00SGerrit Uitslag     *
163de7e6f00SGerrit Uitslag     * @param Doku_Event $event
164de7e6f00SGerrit Uitslag     * @param $param
1652d4bee9aSMichael Klier     */
166*c3413364SGerrit Uitslag    public function addToolbarToCommentfield(Doku_Event $event, $param) {
1672d4bee9aSMichael Klier        global $ACT;
1682d4bee9aSMichael Klier        global $ID;
1692d4bee9aSMichael Klier        if($ACT != 'show') return;
1702d4bee9aSMichael Klier
171*c3413364SGerrit Uitslag        if($this->hasDiscussion($title) && $this->getConf('wikisyntaxok')) {
1722d4bee9aSMichael Klier            // FIXME ugly workaround, replace this once DW the toolbar code is more flexible
1732d4bee9aSMichael Klier            @require_once(DOKU_INC.'inc/toolbar.php');
1742d4bee9aSMichael Klier            ob_start();
1752d4bee9aSMichael Klier            print 'NS = "' . getNS($ID) . '";'; // we have to define NS, otherwise we get get JS errors
1762d4bee9aSMichael Klier            toolbar_JSdefines('toolbar');
1772d4bee9aSMichael Klier            $script = ob_get_clean();
178*c3413364SGerrit Uitslag            $event->data['script'][] = ['type' => 'text/javascript', 'charset' => "utf-8", '_data' => $script];
1792d4bee9aSMichael Klier        }
180f0fda08aSwikidesign    }
181f0fda08aSwikidesign
182f0fda08aSwikidesign    /**
183a1d93126SGina Haeussge     * Handles comment actions, dispatches data processing routines
184de7e6f00SGerrit Uitslag     *
185de7e6f00SGerrit Uitslag     * @param Doku_Event $event
186de7e6f00SGerrit Uitslag     * @param $param
187*c3413364SGerrit Uitslag     * @return void
188f0fda08aSwikidesign     */
189*c3413364SGerrit Uitslag    public function handleCommentActions(Doku_Event $event, $param) {
190*c3413364SGerrit Uitslag        global $ID, $INFO, $lang, $INPUT;
191573e23a1Swikidesign
192a1d93126SGina Haeussge        // handle newthread ACTs
193a1d93126SGina Haeussge        if ($event->data == 'newthread') {
194a1d93126SGina Haeussge            // we can handle it -> prevent others
195*c3413364SGerrit Uitslag            $event->data = $this->newThread();
196a1d93126SGina Haeussge        }
197a1d93126SGina Haeussge
198a1d93126SGina Haeussge        // enable captchas
199*c3413364SGerrit Uitslag        if (in_array($INPUT->str('comment'), ['add', 'save'])) {
200*c3413364SGerrit Uitslag            $this->captchaCheck();
201*c3413364SGerrit Uitslag            $this->recaptchaCheck();
202bd6dc08eSAdrian Schlegel        }
203a1d93126SGina Haeussge
2043011fb8bSMichael Klier        // if we are not in show mode or someone wants to unsubscribe, that was all for now
205*c3413364SGerrit Uitslag        if ($event->data != 'show'
206*c3413364SGerrit Uitslag            && $event->data != 'discussion_unsubscribe'
207*c3413364SGerrit Uitslag            && $event->data != 'discussion_confirmsubscribe') {
208*c3413364SGerrit Uitslag            return;
209*c3413364SGerrit Uitslag        }
210a1d93126SGina Haeussge
211b2f2e866SMichael Klier        if ($event->data == 'discussion_unsubscribe' or $event->data == 'discussion_confirmsubscribe') {
212*c3413364SGerrit Uitslag            if ($INPUT->has('hash')) {
2133011fb8bSMichael Klier                $file = metaFN($ID, '.comments');
2143011fb8bSMichael Klier                $data = unserialize(io_readFile($file));
215*c3413364SGerrit Uitslag                $matchedMail = '';
2169881d835SMichael Klier                foreach ($data['subscribers'] as $mail => $info) {
2179881d835SMichael Klier                    // convert old style subscribers just in case
2189881d835SMichael Klier                    if (!is_array($info)) {
2199881d835SMichael Klier                        $hash = $data['subscribers'][$mail];
2209881d835SMichael Klier                        $data['subscribers'][$mail]['hash'] = $hash;
2219881d835SMichael Klier                        $data['subscribers'][$mail]['active'] = true;
2229881d835SMichael Klier                        $data['subscribers'][$mail]['confirmsent'] = true;
2239881d835SMichael Klier                    }
2249881d835SMichael Klier
225*c3413364SGerrit Uitslag                    if ($data['subscribers'][$mail]['hash'] == $INPUT->str('hash')) {
226*c3413364SGerrit Uitslag                        $matchedMail = $mail;
2270c54624fSGina Haeussge                    }
2280c54624fSGina Haeussge                }
2290c54624fSGina Haeussge
230*c3413364SGerrit Uitslag                if ($matchedMail != '') {
231b2f2e866SMichael Klier                    if ($event->data == 'discussion_unsubscribe') {
232*c3413364SGerrit Uitslag                        unset($data['subscribers'][$matchedMail]);
233*c3413364SGerrit Uitslag                        msg(sprintf($lang['subscr_unsubscribe_success'], $matchedMail, $ID), 1);
234*c3413364SGerrit Uitslag                    } else { //$event->data == 'discussion_confirmsubscribe'
235*c3413364SGerrit Uitslag                        $data['subscribers'][$matchedMail]['active'] = true;
236*c3413364SGerrit Uitslag                        msg(sprintf($lang['subscr_subscribe_success'], $matchedMail, $ID), 1);
2379881d835SMichael Klier                    }
2389881d835SMichael Klier                    io_saveFile($file, serialize($data));
2393011fb8bSMichael Klier                    $event->data = 'show';
2403011fb8bSMichael Klier                }
241de7e6f00SGerrit Uitslag
2429881d835SMichael Klier            }
243*c3413364SGerrit Uitslag            return;
2443011fb8bSMichael Klier        } else {
245a1d93126SGina Haeussge            // do the data processing for comments
246*c3413364SGerrit Uitslag            $cid  = $INPUT->str('cid');
247*c3413364SGerrit Uitslag            switch ($INPUT->str('comment')) {
248f0fda08aSwikidesign                case 'add':
249*c3413364SGerrit Uitslag                    if(empty($INPUT->str('text'))) return; // don't add empty comments
250*c3413364SGerrit Uitslag
251*c3413364SGerrit Uitslag                    if($INPUT->server->has('REMOTE_USER') && !$this->getConf('adminimport')) {
252*c3413364SGerrit Uitslag                        $comment['user']['id'] = $INPUT->server->str('REMOTE_USER');
25394c5d164SMichael Klier                        $comment['user']['name'] = $INFO['userinfo']['name'];
25494c5d164SMichael Klier                        $comment['user']['mail'] = $INFO['userinfo']['mail'];
255*c3413364SGerrit Uitslag                    } elseif(($INPUT->server->has('REMOTE_USER') && $this->getConf('adminimport') && $this->helper->isDiscussionMod())
256*c3413364SGerrit Uitslag                        || !$INPUT->server->has('REMOTE_USER')) {
257*c3413364SGerrit Uitslag                        // don't add anonymous comments
258*c3413364SGerrit Uitslag                        if(empty($INPUT->str('name')) or empty($INPUT->str('mail'))) {
259*c3413364SGerrit Uitslag                            return;
260*c3413364SGerrit Uitslag                        }
261*c3413364SGerrit Uitslag
262*c3413364SGerrit Uitslag                        if(!mail_isvalid($INPUT->str('mail'))) {
263c9d36b5eSMichael Klier                            msg($lang['regbadmail'], -1);
264c9d36b5eSMichael Klier                            return;
265c9d36b5eSMichael Klier                        } else {
266*c3413364SGerrit Uitslag                            $comment['user']['id'] = 'test'.hsc($INPUT->str('user'));
267*c3413364SGerrit Uitslag                            $comment['user']['name'] = hsc($INPUT->str('name'));
268*c3413364SGerrit Uitslag                            $comment['user']['mail'] = hsc($INPUT->str('mail'));
26994c5d164SMichael Klier                        }
270c9d36b5eSMichael Klier                    }
271*c3413364SGerrit Uitslag                    $comment['user']['address'] = ($this->getConf('addressfield')) ? hsc($INPUT->str('address')) : '';
272*c3413364SGerrit Uitslag                    $comment['user']['url'] = ($this->getConf('urlfield')) ? $this->checkURL($INPUT->str('url')) : '';
273*c3413364SGerrit Uitslag                    $comment['subscribe'] = ($this->getConf('subscribe')) ? $INPUT->has('subscribe') : '';
274*c3413364SGerrit Uitslag                    $comment['date'] = ['created' => $INPUT->str('date')];
275*c3413364SGerrit Uitslag                    $comment['raw'] = cleanText($INPUT->str('text'));
276*c3413364SGerrit Uitslag                    $reply = $INPUT->str('reply');
277e6b2f142Slupo49                    if($this->getConf('moderate') && !$this->helper->isDiscussionMod()) {
278a44bc9f7SMichael Klier                        $comment['show'] = false;
279a44bc9f7SMichael Klier                    } else {
280a44bc9f7SMichael Klier                        $comment['show'] = true;
281a44bc9f7SMichael Klier                    }
282*c3413364SGerrit Uitslag                    $this->add($comment, $reply);
283f0fda08aSwikidesign                    break;
284f0fda08aSwikidesign
285f0fda08aSwikidesign                case 'save':
286*c3413364SGerrit Uitslag                    $raw  = cleanText($INPUT->str('text'));
287*c3413364SGerrit Uitslag                    $this->save([$cid], $raw);
288f0fda08aSwikidesign                    break;
289f0fda08aSwikidesign
2901e46d176Swikidesign                case 'delete':
291*c3413364SGerrit Uitslag                    $this->save([$cid], '');
2922ee3dca3Swikidesign                    break;
2931e46d176Swikidesign
294f0fda08aSwikidesign                case 'toogle':
295*c3413364SGerrit Uitslag                    $this->save([$cid], '', 'toogle');
296f0fda08aSwikidesign                    break;
297a1d93126SGina Haeussge            }
2983011fb8bSMichael Klier        }
299a1d93126SGina Haeussge    }
300a1d93126SGina Haeussge
301a1d93126SGina Haeussge    /**
302a1d93126SGina Haeussge     * Main function; dispatches the visual comment actions
303a1d93126SGina Haeussge     */
304*c3413364SGerrit Uitslag    public function renderCommentsSection(Doku_Event $event, $param) {
305*c3413364SGerrit Uitslag        global $INPUT;
306a1d93126SGina Haeussge        if ($event->data != 'show') return; // nothing to do for us
307a1d93126SGina Haeussge
308*c3413364SGerrit Uitslag        $cid  = $INPUT->str('cid');
309*c3413364SGerrit Uitslag
310aa0d6cd7SGerrit Uitslag        if(!$cid) {
311*c3413364SGerrit Uitslag            $cid = $INPUT->str('reply');
312aa0d6cd7SGerrit Uitslag        }
313*c3413364SGerrit Uitslag        var_dump($cid);
314*c3413364SGerrit Uitslag        var_dump($INPUT->str('comment'));
315*c3413364SGerrit Uitslag        switch ($INPUT->str('comment')) {
316a1d93126SGina Haeussge            case 'edit':
317*c3413364SGerrit Uitslag                $this->showDiscussionSection(null, $cid);
318a1d93126SGina Haeussge                break;
319*c3413364SGerrit Uitslag            default: //'reply' or no action specifiec
320*c3413364SGerrit Uitslag                $this->showDiscussionSection($cid);
3212b18adb9SMichael Klier                break;
322f0fda08aSwikidesign        }
323f0fda08aSwikidesign    }
324f0fda08aSwikidesign
325f0fda08aSwikidesign    /**
326a1d93126SGina Haeussge     * Redirects browser to given comment anchor
327a1d93126SGina Haeussge     */
328*c3413364SGerrit Uitslag    protected function redirect($cid) {
329a1d93126SGina Haeussge        global $ID;
330a1d93126SGina Haeussge        global $ACT;
331a1d93126SGina Haeussge
332a1d93126SGina Haeussge        if ($ACT !== 'show') return;
333a44bc9f7SMichael Klier
334e6b2f142Slupo49        if($this->getConf('moderate') && !$this->helper->isDiscussionMod()) {
335a44bc9f7SMichael Klier            msg($this->getLang('moderation'), 1);
336a44bc9f7SMichael Klier            @session_start();
337a44bc9f7SMichael Klier            global $MSG;
338a44bc9f7SMichael Klier            $_SESSION[DOKU_COOKIE]['msg'] = $MSG;
339a44bc9f7SMichael Klier            session_write_close();
340a44bc9f7SMichael Klier            $url = wl($ID);
341a44bc9f7SMichael Klier        } else {
342a44bc9f7SMichael Klier            $url = wl($ID) . '#comment_' . $cid;
343a44bc9f7SMichael Klier        }
344e88de38aSAxel Beckert
345e88de38aSAxel Beckert        if (function_exists('send_redirect')) {
346e88de38aSAxel Beckert            send_redirect($url);
347e88de38aSAxel Beckert        } else {
34869f42a0bSAxel Beckert            header('Location: ' . $url);
349e88de38aSAxel Beckert        }
3506d1f4f20SGina Haeussge        exit();
351a1d93126SGina Haeussge    }
352a1d93126SGina Haeussge
353a1d93126SGina Haeussge    /**
354d406a452SGerrit Uitslag     * Checks config settings to enable/disable discussions
355f0bcde18SGerrit Uitslag     *
356f0bcde18SGerrit Uitslag     * @return bool
357f0bcde18SGerrit Uitslag     */
358f0bcde18SGerrit Uitslag    public function isDiscussionEnabled() {
359f0bcde18SGerrit Uitslag        global $INFO;
360f0bcde18SGerrit Uitslag
361d406a452SGerrit Uitslag        if($this->getConf('excluded_ns') == '') {
362d406a452SGerrit Uitslag            $isNamespaceExcluded = false;
363d406a452SGerrit Uitslag        } else {
364f0bcde18SGerrit Uitslag            $isNamespaceExcluded = preg_match($this->getConf('excluded_ns'), $INFO['namespace']);
365d406a452SGerrit Uitslag        }
366f0bcde18SGerrit Uitslag
367f0bcde18SGerrit Uitslag        if($this->getConf('automatic')) {
368f0bcde18SGerrit Uitslag            if($isNamespaceExcluded) {
369f0bcde18SGerrit Uitslag                return false;
370f0bcde18SGerrit Uitslag            } else {
371f0bcde18SGerrit Uitslag                return true;
372f0bcde18SGerrit Uitslag            }
373f0bcde18SGerrit Uitslag        } else {
374f0bcde18SGerrit Uitslag            if($isNamespaceExcluded) {
375f0bcde18SGerrit Uitslag                return true;
376f0bcde18SGerrit Uitslag            } else {
377f0bcde18SGerrit Uitslag                return false;
378f0bcde18SGerrit Uitslag            }
379f0bcde18SGerrit Uitslag        }
380f0bcde18SGerrit Uitslag    }
381f0bcde18SGerrit Uitslag
382f0bcde18SGerrit Uitslag    /**
383*c3413364SGerrit Uitslag     * Shows all comments of the current page, if no reply or edit requested, then comment form is shown on the end
384*c3413364SGerrit Uitslag     *
385*c3413364SGerrit Uitslag     * @param null|string $reply comment id on which the user requested a reply
386*c3413364SGerrit Uitslag     * @param null|string $edit comment id which the user requested for editing
387f0fda08aSwikidesign     */
388*c3413364SGerrit Uitslag    protected function showDiscussionSection($reply = null, $edit = null) {
389*c3413364SGerrit Uitslag        global $ID, $INFO, $INPUT;
390573e23a1Swikidesign
391479dd10fSwikidesign        // get .comments meta file name
392f0fda08aSwikidesign        $file = metaFN($ID, '.comments');
393f0fda08aSwikidesign
394*c3413364SGerrit Uitslag        if (!$INFO['exists']) return;
395*c3413364SGerrit Uitslag        if (!@file_exists($file) && !$this->isDiscussionEnabled()) return;
396*c3413364SGerrit Uitslag        if (!$INPUT->server->has('REMOTE_USER') && !$this->getConf('showguests')) return;
397f0fda08aSwikidesign
3982b18adb9SMichael Klier        // load data
399*c3413364SGerrit Uitslag        $data = [];
4002b18adb9SMichael Klier        if (@file_exists($file)) {
4012b18adb9SMichael Klier            $data = unserialize(io_readFile($file, false));
402*c3413364SGerrit Uitslag            // comments are turned off
403*c3413364SGerrit Uitslag            if (!$data['status']) {
404*c3413364SGerrit Uitslag                return;
405*c3413364SGerrit Uitslag            }
406*c3413364SGerrit Uitslag            var_dump($data);
407f0bcde18SGerrit Uitslag        } elseif (!@file_exists($file) && $this->isDiscussionEnabled() && $INFO['exists']) {
4082b18adb9SMichael Klier            // set status to show the comment form
4092b18adb9SMichael Klier            $data['status'] = 1;
4102b18adb9SMichael Klier            $data['number'] = 0;
4112b18adb9SMichael Klier        }
412f0fda08aSwikidesign
413a1599850SMichael Klier        // show discussion wrapper only on certain circumstances
414*c3413364SGerrit Uitslag        if(empty($data['comments']) || !is_array($data['comments'])) {
415*c3413364SGerrit Uitslag            $cnt = 0;
4163e19949cSMark Prins            $keys = [];
417*c3413364SGerrit Uitslag        } else {
418*c3413364SGerrit Uitslag            $cnt = count($data['comments']);
419*c3413364SGerrit Uitslag            $keys = array_keys($data['comments']);
4203e19949cSMark Prins        }
421*c3413364SGerrit Uitslag
422de7e6f00SGerrit Uitslag        $show = false;
423*c3413364SGerrit Uitslag        if($cnt > 1 || ($cnt == 1 && $data['comments'][$keys[0]]['show'] == 1)
424*c3413364SGerrit Uitslag            || $this->getConf('allowguests') || $INPUT->server->has('REMOTE_USER')) {
425a1599850SMichael Klier            $show = true;
426f0fda08aSwikidesign            // section title
42707c376bbSwikidesign            $title = ($data['title'] ? hsc($data['title']) : $this->getLang('discussion'));
42846178401Slupo49            ptln('<div class="comment_wrapper" id="comment_wrapper">'); // the id value is used for visibility toggling the section
4294a0a1bd2Swikidesign            ptln('<h2><a name="discussion__section" id="discussion__section">', 2);
4304a0a1bd2Swikidesign            ptln($title, 4);
4314a0a1bd2Swikidesign            ptln('</a></h2>', 2);
4324a0a1bd2Swikidesign            ptln('<div class="level2 hfeed">', 2);
433a1599850SMichael Klier        }
434a1599850SMichael Klier
435f0fda08aSwikidesign        // now display the comments
436f0fda08aSwikidesign        if (isset($data['comments'])) {
43731aab30eSGina Haeussge            if (!$this->getConf('usethreading')) {
438*c3413364SGerrit Uitslag                $data['comments'] = $this->flattenThreads($data['comments']);
439*c3413364SGerrit Uitslag                uasort($data['comments'], [$this, 'sortCallback']);
44031aab30eSGina Haeussge            }
441dbd9d5cdSMichael Klier            if($this->getConf('newestfirst')) {
442dbd9d5cdSMichael Klier                $data['comments'] = array_reverse($data['comments']);
443dbd9d5cdSMichael Klier            }
444*c3413364SGerrit Uitslag            foreach ($data['comments'] as $cid => $value) {
445*c3413364SGerrit Uitslag                if ($cid == $edit) { // edit form
446*c3413364SGerrit Uitslag                    $this->showCommentForm($value['raw'], 'save', $edit);
447*c3413364SGerrit Uitslag                } else {
448*c3413364SGerrit Uitslag                    $this->showCommentWithReplies($cid, $data, '', $reply);
449*c3413364SGerrit Uitslag                }
450f0fda08aSwikidesign            }
451f0fda08aSwikidesign        }
452f0fda08aSwikidesign
453*c3413364SGerrit Uitslag        // comment form shown on the end, if no comment form of $reply or $edit is requested before
454*c3413364SGerrit Uitslag        if ($data['status'] == 1 && (!$reply || !$this->getConf('usethreading')) && !$edit) {
455*c3413364SGerrit Uitslag            $this->showCommentForm('');
456*c3413364SGerrit Uitslag        }
457f0fda08aSwikidesign
458a1599850SMichael Klier        if($show) {
4594a0a1bd2Swikidesign            ptln('</div>', 2); // level2 hfeed
4604a0a1bd2Swikidesign            ptln('</div>'); // comment_wrapper
461a1599850SMichael Klier        }
462f0fda08aSwikidesign
46346178401Slupo49        // check for toggle print configuration
46446178401Slupo49        if($this->getConf('visibilityButton')) {
46546178401Slupo49            // print the hide/show discussion section button
466*c3413364SGerrit Uitslag            $this->showDiscussionToggleButton();
46746178401Slupo49        }
468f0fda08aSwikidesign    }
469f0fda08aSwikidesign
470de7e6f00SGerrit Uitslag    /**
471*c3413364SGerrit Uitslag     * Remove the parent-child relation, such that the comment structure becomes flat
472*c3413364SGerrit Uitslag     *
473*c3413364SGerrit Uitslag     * @param array $comments  array with all comments
474*c3413364SGerrit Uitslag     * @param null|array $cids comment ids of replies, which should be flatten
475*c3413364SGerrit Uitslag     * @return array returned array with flattened comment structure
476de7e6f00SGerrit Uitslag     */
477*c3413364SGerrit Uitslag    protected function flattenThreads($comments, $cids = null) {
478*c3413364SGerrit Uitslag        if (is_null($cids)) {
479*c3413364SGerrit Uitslag            $cids = array_keys($comments);
480*c3413364SGerrit Uitslag        }
48131aab30eSGina Haeussge
482*c3413364SGerrit Uitslag        foreach($cids as $cid) {
48331aab30eSGina Haeussge            if (!empty($comments[$cid]['replies'])) {
48431aab30eSGina Haeussge                $rids = $comments[$cid]['replies'];
485*c3413364SGerrit Uitslag                $comments = $this->flattenThreads($comments, $rids);
486*c3413364SGerrit Uitslag                $comments[$cid]['replies'] = [];
48731aab30eSGina Haeussge            }
48831aab30eSGina Haeussge            $comments[$cid]['parent'] = '';
48931aab30eSGina Haeussge        }
49031aab30eSGina Haeussge        return $comments;
49131aab30eSGina Haeussge    }
49231aab30eSGina Haeussge
493f0fda08aSwikidesign    /**
494f0fda08aSwikidesign     * Adds a new comment and then displays all comments
495de7e6f00SGerrit Uitslag     *
496*c3413364SGerrit Uitslag     * @param array $comment with
497*c3413364SGerrit Uitslag     *  'raw' => string comment text,
498*c3413364SGerrit Uitslag     *  'user' => [
499*c3413364SGerrit Uitslag     *      'id' => string,
500*c3413364SGerrit Uitslag     *      'name' => string,
501*c3413364SGerrit Uitslag     *      'mail' => string
502*c3413364SGerrit Uitslag     *  ],
503*c3413364SGerrit Uitslag     *  'date' => [
504*c3413364SGerrit Uitslag     *      'created' => int timestamp
505*c3413364SGerrit Uitslag     *  ]
506*c3413364SGerrit Uitslag     *  'show' => bool
507*c3413364SGerrit Uitslag     *  'subscribe' => bool
508*c3413364SGerrit Uitslag     * @param string $parent comment id of parent
509de7e6f00SGerrit Uitslag     * @return bool
510f0fda08aSwikidesign     */
511*c3413364SGerrit Uitslag    protected function add($comment, $parent) {
512*c3413364SGerrit Uitslag        global $ID, $TEXT, $INPUT;
513f0fda08aSwikidesign
514*c3413364SGerrit Uitslag        $originalTxt = $TEXT; // set $TEXT to comment text for wordblock check
515f0fda08aSwikidesign        $TEXT = $comment['raw'];
516f0fda08aSwikidesign
517f0fda08aSwikidesign        // spamcheck against the DokuWiki blacklist
518f0fda08aSwikidesign        if (checkwordblock()) {
519f0fda08aSwikidesign            msg($this->getLang('wordblock'), -1);
520f0fda08aSwikidesign            return false;
521f0fda08aSwikidesign        }
522f0fda08aSwikidesign
523*c3413364SGerrit Uitslag        if (!$this->getConf('allowguests')
524*c3413364SGerrit Uitslag                && $comment['user']['id'] != $INPUT->server->str('REMOTE_USER')
5254cded5e1SGerrit Uitslag        ) {
5263011fb8bSMichael Klier            return false; // guest comments not allowed
5274cded5e1SGerrit Uitslag        }
5283011fb8bSMichael Klier
529*c3413364SGerrit Uitslag        $TEXT = $originalTxt; // restore global $TEXT
530f0fda08aSwikidesign
531f0fda08aSwikidesign        // get discussion meta file name
532f0fda08aSwikidesign        $file = metaFN($ID, '.comments');
533f0fda08aSwikidesign
5342b18adb9SMichael Klier        // create comments file if it doesn't exist yet
5352b18adb9SMichael Klier        if(!@file_exists($file)) {
536*c3413364SGerrit Uitslag            $data = ['status' => 1, 'number' => 0];
5372b18adb9SMichael Klier            io_saveFile($file, serialize($data));
5382b18adb9SMichael Klier        } else {
539f0fda08aSwikidesign            $data = unserialize(io_readFile($file, false));
540*c3413364SGerrit Uitslag            // comments off or closed
541*c3413364SGerrit Uitslag            if ($data['status'] != 1) {
542*c3413364SGerrit Uitslag                return false;
543*c3413364SGerrit Uitslag            }
5442b18adb9SMichael Klier        }
5452b18adb9SMichael Klier
5463011fb8bSMichael Klier        if ($comment['date']['created']) {
5473011fb8bSMichael Klier            $date = strtotime($comment['date']['created']);
5483011fb8bSMichael Klier        } else {
5493011fb8bSMichael Klier            $date = time();
5503011fb8bSMichael Klier        }
551f0fda08aSwikidesign
5523011fb8bSMichael Klier        if ($date == -1) {
5533011fb8bSMichael Klier            $date = time();
5543011fb8bSMichael Klier        }
5553011fb8bSMichael Klier
5566046f25cSwikidesign        $cid  = md5($comment['user']['id'].$date); // create a unique id
557f0fda08aSwikidesign
5583011fb8bSMichael Klier        if (!is_array($data['comments'][$parent])) {
559*c3413364SGerrit Uitslag            $parent = null; // invalid parent comment
5603011fb8bSMichael Klier        }
561f0fda08aSwikidesign
562f0fda08aSwikidesign        // render the comment
563*c3413364SGerrit Uitslag        $xhtml = $this->renderComment($comment['raw']);
564f0fda08aSwikidesign
565f0fda08aSwikidesign        // fill in the new comment
566*c3413364SGerrit Uitslag        $data['comments'][$cid] = [
5676046f25cSwikidesign                'user'    => $comment['user'],
568*c3413364SGerrit Uitslag                'date'    => ['created' => $date],
5696046f25cSwikidesign                'raw'     => $comment['raw'],
570f0fda08aSwikidesign                'xhtml'   => $xhtml,
571f0fda08aSwikidesign                'parent'  => $parent,
572*c3413364SGerrit Uitslag                'replies' => [],
573a44bc9f7SMichael Klier                'show'    => $comment['show']
574*c3413364SGerrit Uitslag        ];
575f0fda08aSwikidesign
5763011fb8bSMichael Klier        if($comment['subscribe']) {
5773011fb8bSMichael Klier            $mail = $comment['user']['mail'];
5783011fb8bSMichael Klier            if($data['subscribers']) {
5793011fb8bSMichael Klier                if(!$data['subscribers'][$mail]) {
5809881d835SMichael Klier                    $data['subscribers'][$mail]['hash'] = md5($mail . mt_rand());
5819881d835SMichael Klier                    $data['subscribers'][$mail]['active'] = false;
5829881d835SMichael Klier                    $data['subscribers'][$mail]['confirmsent'] = false;
5839881d835SMichael Klier                } else {
5849881d835SMichael Klier                    // convert old style subscribers and set them active
5859881d835SMichael Klier                    if(!is_array($data['subscribers'][$mail])) {
5869881d835SMichael Klier                        $hash = $data['subscribers'][$mail];
5879881d835SMichael Klier                        $data['subscribers'][$mail]['hash'] = $hash;
5889881d835SMichael Klier                        $data['subscribers'][$mail]['active'] = true;
5899881d835SMichael Klier                        $data['subscribers'][$mail]['confirmsent'] = true;
5909881d835SMichael Klier                    }
5913011fb8bSMichael Klier                }
5923011fb8bSMichael Klier            } else {
5939881d835SMichael Klier                $data['subscribers'][$mail]['hash']   = md5($mail . mt_rand());
5949881d835SMichael Klier                $data['subscribers'][$mail]['active'] = false;
5959881d835SMichael Klier                $data['subscribers'][$mail]['confirmsent'] = false;
5963011fb8bSMichael Klier            }
5973011fb8bSMichael Klier        }
5983011fb8bSMichael Klier
599f0fda08aSwikidesign        // update parent comment
6004cded5e1SGerrit Uitslag        if ($parent) {
6014cded5e1SGerrit Uitslag            $data['comments'][$parent]['replies'][] = $cid;
6024cded5e1SGerrit Uitslag        }
603f0fda08aSwikidesign
604f0fda08aSwikidesign        // update the number of comments
605f0fda08aSwikidesign        $data['number']++;
606f0fda08aSwikidesign
607f0fda08aSwikidesign        // notify subscribers of the page
6088b42cefbSMichael Klier        $data['comments'][$cid]['cid'] = $cid;
609*c3413364SGerrit Uitslag        $this->notify($data['comments'][$cid], $data['subscribers']);
610f0fda08aSwikidesign
6119881d835SMichael Klier        // save the comment metadata file
6129881d835SMichael Klier        io_saveFile($file, serialize($data));
613*c3413364SGerrit Uitslag        $this->addLogEntry($date, $ID, 'cc', '', $cid);
6149881d835SMichael Klier
615*c3413364SGerrit Uitslag        $this->redirect($cid);
616f0fda08aSwikidesign        return true;
617f0fda08aSwikidesign    }
618f0fda08aSwikidesign
619f0fda08aSwikidesign    /**
620f0fda08aSwikidesign     * Saves the comment with the given ID and then displays all comments
621de7e6f00SGerrit Uitslag     *
622*c3413364SGerrit Uitslag     * @param array|string $cids array with comment ids to save, or a single string comment id
623*c3413364SGerrit Uitslag     * @param string $raw if empty comment is deleted, otherwise edited text is stored (note: storing is per one cid!)
624*c3413364SGerrit Uitslag     * @param string|null $act 'toogle', 'show', 'hide', null. If null, it depends on $raw
625*c3413364SGerrit Uitslag     * @return bool succeed?
626f0fda08aSwikidesign     */
627*c3413364SGerrit Uitslag    public function save($cids, $raw, $act = null) {
628*c3413364SGerrit Uitslag        global $ID, $INPUT;
629f0fda08aSwikidesign
630*c3413364SGerrit Uitslag        if(empty($cids)) return false; // do nothing if we get no comment id
631757550e8SMichael Klier
6322ee3dca3Swikidesign        if ($raw) {
6332ee3dca3Swikidesign            global $TEXT;
6342ee3dca3Swikidesign
635f0fda08aSwikidesign            $otxt = $TEXT; // set $TEXT to comment text for wordblock check
636f0fda08aSwikidesign            $TEXT = $raw;
637f0fda08aSwikidesign
638f0fda08aSwikidesign            // spamcheck against the DokuWiki blacklist
639f0fda08aSwikidesign            if (checkwordblock()) {
640f0fda08aSwikidesign                msg($this->getLang('wordblock'), -1);
641f0fda08aSwikidesign                return false;
642f0fda08aSwikidesign            }
643f0fda08aSwikidesign
644f0fda08aSwikidesign            $TEXT = $otxt; // restore global $TEXT
6452ee3dca3Swikidesign        }
646f0fda08aSwikidesign
647f0fda08aSwikidesign        // get discussion meta file name
648f0fda08aSwikidesign        $file = metaFN($ID, '.comments');
649f0fda08aSwikidesign        $data = unserialize(io_readFile($file, false));
650f0fda08aSwikidesign
651*c3413364SGerrit Uitslag        if (!is_array($cids)) {
652*c3413364SGerrit Uitslag            $cids = [$cids];
653*c3413364SGerrit Uitslag        }
654264b7327Swikidesign        foreach ($cids as $cid) {
655264b7327Swikidesign
6566046f25cSwikidesign            if (is_array($data['comments'][$cid]['user'])) {
6576046f25cSwikidesign                $user    = $data['comments'][$cid]['user']['id'];
6586046f25cSwikidesign                $convert = false;
6596046f25cSwikidesign            } else {
6606046f25cSwikidesign                $user    = $data['comments'][$cid]['user'];
6616046f25cSwikidesign                $convert = true;
6626046f25cSwikidesign            }
6636046f25cSwikidesign
664f0fda08aSwikidesign            // someone else was trying to edit our comment -> abort
665*c3413364SGerrit Uitslag            if ($user != $INPUT->server->str('REMOTE_USER') && !$this->helper->isDiscussionMod()) {
666*c3413364SGerrit Uitslag                return false;
667*c3413364SGerrit Uitslag            }
668f0fda08aSwikidesign
669f0fda08aSwikidesign            $date = time();
670f0fda08aSwikidesign
6716046f25cSwikidesign            // need to convert to new format?
6726046f25cSwikidesign            if ($convert) {
673*c3413364SGerrit Uitslag                $data['comments'][$cid]['user'] = [
6746046f25cSwikidesign                        'id'      => $user,
6756046f25cSwikidesign                        'name'    => $data['comments'][$cid]['name'],
6766046f25cSwikidesign                        'mail'    => $data['comments'][$cid]['mail'],
6776046f25cSwikidesign                        'url'     => $data['comments'][$cid]['url'],
6786046f25cSwikidesign                        'address' => $data['comments'][$cid]['address'],
679*c3413364SGerrit Uitslag                ];
680*c3413364SGerrit Uitslag                $data['comments'][$cid]['date'] = [
6816046f25cSwikidesign                        'created' => $data['comments'][$cid]['date']
682*c3413364SGerrit Uitslag                ];
6836046f25cSwikidesign            }
6846046f25cSwikidesign
685264b7327Swikidesign            if ($act == 'toogle') {     // toogle visibility
686f0fda08aSwikidesign                $now = $data['comments'][$cid]['show'];
687f0fda08aSwikidesign                $data['comments'][$cid]['show'] = !$now;
688*c3413364SGerrit Uitslag                $data['number'] = $this->countVisibleComments($data);
689f0fda08aSwikidesign
690f0fda08aSwikidesign                $type = ($data['comments'][$cid]['show'] ? 'sc' : 'hc');
691f0fda08aSwikidesign
692264b7327Swikidesign            } elseif ($act == 'show') { // show comment
693264b7327Swikidesign                $data['comments'][$cid]['show'] = true;
694*c3413364SGerrit Uitslag                $data['number'] = $this->countVisibleComments($data);
695264b7327Swikidesign
696573e23a1Swikidesign                $type = 'sc'; // show comment
697264b7327Swikidesign
698264b7327Swikidesign            } elseif ($act == 'hide') { // hide comment
699264b7327Swikidesign                $data['comments'][$cid]['show'] = false;
700*c3413364SGerrit Uitslag                $data['number'] = $this->countVisibleComments($data);
701264b7327Swikidesign
702573e23a1Swikidesign                $type = 'hc'; // hide comment
703264b7327Swikidesign
704f0fda08aSwikidesign            } elseif (!$raw) {          // remove the comment
705*c3413364SGerrit Uitslag                $data['comments'] = $this->removeComment($cid, $data['comments']);
706*c3413364SGerrit Uitslag                $data['number'] = $this->countVisibleComments($data);
707f0fda08aSwikidesign
708573e23a1Swikidesign                $type = 'dc'; // delete comment
709f0fda08aSwikidesign
710f0fda08aSwikidesign            } else {                   // save changed comment
711*c3413364SGerrit Uitslag                $xhtml = $this->renderComment($raw);
712f0fda08aSwikidesign
713f0fda08aSwikidesign                // now change the comment's content
7146046f25cSwikidesign                $data['comments'][$cid]['date']['modified'] = $date;
7156046f25cSwikidesign                $data['comments'][$cid]['raw']              = $raw;
716f0fda08aSwikidesign                $data['comments'][$cid]['xhtml']            = $xhtml;
717f0fda08aSwikidesign
718573e23a1Swikidesign                $type = 'ec'; // edit comment
719f0fda08aSwikidesign            }
720264b7327Swikidesign        }
721264b7327Swikidesign
722f0fda08aSwikidesign        // save the comment metadata file
723f0fda08aSwikidesign        io_saveFile($file, serialize($data));
724*c3413364SGerrit Uitslag        $this->addLogEntry($date, $ID, $type, '', $cid);
725f0fda08aSwikidesign
726*c3413364SGerrit Uitslag        $this->redirect($cid);
727f0fda08aSwikidesign        return true;
728f0fda08aSwikidesign    }
729f0fda08aSwikidesign
730f0fda08aSwikidesign    /**
731*c3413364SGerrit Uitslag     * Recursive function to remove a comment from the data array
732*c3413364SGerrit Uitslag     *
733*c3413364SGerrit Uitslag     * @param string $cid comment id to be removed
734*c3413364SGerrit Uitslag     * @param array $comments array with all comments
735*c3413364SGerrit Uitslag     * @return array returns modified array with all remaining comments
736efbe59d0Swikidesign     */
737*c3413364SGerrit Uitslag    protected function removeComment($cid, $comments) {
738efbe59d0Swikidesign        if (is_array($comments[$cid]['replies'])) {
739efbe59d0Swikidesign            foreach ($comments[$cid]['replies'] as $rid) {
740*c3413364SGerrit Uitslag                $comments = $this->removeComment($rid, $comments);
741efbe59d0Swikidesign            }
742efbe59d0Swikidesign        }
743efbe59d0Swikidesign        unset($comments[$cid]);
744efbe59d0Swikidesign        return $comments;
745efbe59d0Swikidesign    }
746efbe59d0Swikidesign
747efbe59d0Swikidesign    /**
748f0fda08aSwikidesign     * Prints an individual comment
749de7e6f00SGerrit Uitslag     *
750*c3413364SGerrit Uitslag     * @param string $cid comment id
751*c3413364SGerrit Uitslag     * @param array $data array with all comments by reference
752*c3413364SGerrit Uitslag     * @param string $parent comment id of parent
753*c3413364SGerrit Uitslag     * @param string $reply comment id on which the user requested a reply
754*c3413364SGerrit Uitslag     * @param bool $isVisible is marked as visible
755f0fda08aSwikidesign     */
756*c3413364SGerrit Uitslag    protected function showCommentWithReplies($cid, &$data, $parent = '', $reply = '', $isVisible = true) {
757*c3413364SGerrit Uitslag        // comment was removed
758*c3413364SGerrit Uitslag        if (!isset($data['comments'][$cid])) {
759*c3413364SGerrit Uitslag            return;
760*c3413364SGerrit Uitslag        }
761f0fda08aSwikidesign        $comment = $data['comments'][$cid];
762f0fda08aSwikidesign
763*c3413364SGerrit Uitslag        // corrupt datatype
764*c3413364SGerrit Uitslag        if (!is_array($comment)) {
765*c3413364SGerrit Uitslag            return;
766*c3413364SGerrit Uitslag        }
767f0fda08aSwikidesign
768*c3413364SGerrit Uitslag        // handle only replies to given parent comment
769*c3413364SGerrit Uitslag        if ($comment['parent'] != $parent) {
770*c3413364SGerrit Uitslag            return;
771*c3413364SGerrit Uitslag        }
772f0fda08aSwikidesign
773*c3413364SGerrit Uitslag        // comment hidden
774*c3413364SGerrit Uitslag        if (!$comment['show']) {
775*c3413364SGerrit Uitslag            if ($this->helper->isDiscussionMod()) {
776*c3413364SGerrit Uitslag                $hidden = ' comment_hidden';
777*c3413364SGerrit Uitslag            } else {
778*c3413364SGerrit Uitslag                return;
779*c3413364SGerrit Uitslag            }
7804a0a1bd2Swikidesign        } else {
7814a0a1bd2Swikidesign            $hidden = '';
782f0fda08aSwikidesign        }
783f0fda08aSwikidesign
784f1c6610eSpierre.spring        // print the actual comment
785*c3413364SGerrit Uitslag        $this->showComment($cid, $data, $parent, $reply, $isVisible, $hidden);
786f1c6610eSpierre.spring        // replies to this comment entry?
787*c3413364SGerrit Uitslag        $this->showReplies($cid, $data, $reply, $isVisible);
788f1c6610eSpierre.spring        // reply form
789*c3413364SGerrit Uitslag        $this->showReplyForm($cid, $reply);
790f1c6610eSpierre.spring    }
791f1c6610eSpierre.spring
792de7e6f00SGerrit Uitslag    /**
793*c3413364SGerrit Uitslag     * Print the comment
794*c3413364SGerrit Uitslag     *
795*c3413364SGerrit Uitslag     * @param string $cid comment id
796*c3413364SGerrit Uitslag     * @param array $data array with all comments by reference
797*c3413364SGerrit Uitslag     * @param string $parent comment id of parent
798*c3413364SGerrit Uitslag     * @param string $reply comment id on which the user requested a reply
799*c3413364SGerrit Uitslag     * @param bool $isVisible is marked as visible
800*c3413364SGerrit Uitslag     * @param string $hidden extra class, for the admin only hidden view
801de7e6f00SGerrit Uitslag     */
802*c3413364SGerrit Uitslag    protected function showComment($cid, &$data, $parent, $reply, $isVisible, $hidden) {
803*c3413364SGerrit Uitslag        global $conf, $lang, $HIGH, $INPUT;
804f1c6610eSpierre.spring        $comment = $data['comments'][$cid];
805f1c6610eSpierre.spring
806f0fda08aSwikidesign        // comment head with date and user data
8074a0a1bd2Swikidesign        ptln('<div class="hentry'.$hidden.'">', 4);
8084a0a1bd2Swikidesign        ptln('<div class="comment_head">', 6);
8091810ba9cSMichael Klier        ptln('<a name="comment_'.$cid.'" id="comment_'.$cid.'"></a>', 8);
8104a0a1bd2Swikidesign        $head = '<span class="vcard author">';
811f0fda08aSwikidesign
8126046f25cSwikidesign        // prepare variables
8136046f25cSwikidesign        if (is_array($comment['user'])) { // new format
8146046f25cSwikidesign            $user    = $comment['user']['id'];
8156046f25cSwikidesign            $name    = $comment['user']['name'];
8166046f25cSwikidesign            $mail    = $comment['user']['mail'];
8176046f25cSwikidesign            $url     = $comment['user']['url'];
8186046f25cSwikidesign            $address = $comment['user']['address'];
8196046f25cSwikidesign        } else {                         // old format
8206046f25cSwikidesign            $user    = $comment['user'];
8216046f25cSwikidesign            $name    = $comment['name'];
8226046f25cSwikidesign            $mail    = $comment['mail'];
8236046f25cSwikidesign            $url     = $comment['url'];
8246046f25cSwikidesign            $address = $comment['address'];
8256046f25cSwikidesign        }
8266046f25cSwikidesign        if (is_array($comment['date'])) { // new format
8276046f25cSwikidesign            $created  = $comment['date']['created'];
828*c3413364SGerrit Uitslag            $modified = $comment['date']['modified'] ?: null;
8296046f25cSwikidesign        } else {                         // old format
8306046f25cSwikidesign            $created  = $comment['date'];
8316046f25cSwikidesign            $modified = $comment['edited'];
8326046f25cSwikidesign        }
8336046f25cSwikidesign
8340ff5ab97SMichael Klier        // show username or real name?
835*c3413364SGerrit Uitslag        if (!$this->getConf('userealname') && $user) {
8360ff5ab97SMichael Klier            $showname = $user;
8370ff5ab97SMichael Klier        } else {
8380ff5ab97SMichael Klier            $showname = $name;
8390ff5ab97SMichael Klier        }
8400ff5ab97SMichael Klier
841ce7b17cfSwikidesign        // show avatar image?
842*c3413364SGerrit Uitslag        if ($this->useAvatar()) {
84312ca6034SMichael Klier            $user_data['name'] = $name;
84412ca6034SMichael Klier            $user_data['user'] = $user;
84512ca6034SMichael Klier            $user_data['mail'] = $mail;
84612ca6034SMichael Klier            $avatar = $this->avatar->getXHTML($user_data, $name, 'left');
847*c3413364SGerrit Uitslag            if($avatar) {
848*c3413364SGerrit Uitslag                $head .= $avatar;
849*c3413364SGerrit Uitslag            }
850f0fda08aSwikidesign        }
851f0fda08aSwikidesign
8526046f25cSwikidesign        if ($this->getConf('linkemail') && $mail) {
8530ff5ab97SMichael Klier            $head .= $this->email($mail, $showname, 'email fn');
8546046f25cSwikidesign        } elseif ($url) {
855*c3413364SGerrit Uitslag            $head .= $this->external_link($this->checkURL($url), $showname, 'urlextern url fn');
856f0fda08aSwikidesign        } else {
8570ff5ab97SMichael Klier            $head .= '<span class="fn">'.$showname.'</span>';
858f0fda08aSwikidesign        }
8596f1f13d6SMatthias Schulte
8604cded5e1SGerrit Uitslag        if ($address) {
8614cded5e1SGerrit Uitslag            $head .= ', <span class="adr">'.$address.'</span>';
8624cded5e1SGerrit Uitslag        }
8634a0a1bd2Swikidesign        $head .= '</span>, '.
864f014bc86SMichael Klier            '<abbr class="published" title="'. strftime('%Y-%m-%dT%H:%M:%SZ', $created) .'">'.
8656f1f13d6SMatthias Schulte            dformat($created, $conf['dformat']).'</abbr>';
8669c0e06f3SMoisés Braga Ribeiro        if ($modified) {
8679c0e06f3SMoisés Braga Ribeiro            $head .= ', <abbr class="updated" title="'.
8686f1f13d6SMatthias Schulte                strftime('%Y-%m-%dT%H:%M:%SZ', $modified).'">'.dformat($modified, $conf['dformat']).
8699c0e06f3SMoisés Braga Ribeiro                '</abbr>';
8704cded5e1SGerrit Uitslag        }
871f014bc86SMichael Klier        ptln($head, 8);
8724a0a1bd2Swikidesign        ptln('</div>', 6); // class="comment_head"
873f0fda08aSwikidesign
874f0fda08aSwikidesign        // main comment content
8754a0a1bd2Swikidesign        ptln('<div class="comment_body entry-content"'.
876*c3413364SGerrit Uitslag                ($this->useAvatar() ? $this->getWidthStyle() : '').'>', 6);
87715cdad37Spierre.spring        echo ($HIGH?html_hilight($comment['xhtml'],$HIGH):$comment['xhtml']).DOKU_LF;
8784a0a1bd2Swikidesign        ptln('</div>', 6); // class="comment_body"
879f0fda08aSwikidesign
880*c3413364SGerrit Uitslag        if ($isVisible) {
8811184c36aSwikidesign            ptln('<div class="comment_buttons">', 6);
882f0fda08aSwikidesign
883f0fda08aSwikidesign            // show reply button?
884*c3413364SGerrit Uitslag            if ($data['status'] == 1 && !$reply && $comment['show']
885*c3413364SGerrit Uitslag                && ($this->getConf('allowguests') || $INPUT->server->has('REMOTE_USER'))
886*c3413364SGerrit Uitslag                && $this->getConf('usethreading')
8874cded5e1SGerrit Uitslag            ) {
888*c3413364SGerrit Uitslag                $this->showButton($cid, $this->getLang('btn_reply'), 'reply', true);
8894cded5e1SGerrit Uitslag            }
890f0fda08aSwikidesign
8911184c36aSwikidesign            // show edit, show/hide and delete button?
892*c3413364SGerrit Uitslag            if (($user == $INPUT->server->str('REMOTE_USER') && $user != '') || $this->helper->isDiscussionMod()) {
893*c3413364SGerrit Uitslag                $this->showButton($cid, $lang['btn_secedit'], 'edit', true);
8941184c36aSwikidesign                $label = ($comment['show'] ? $this->getLang('btn_hide') : $this->getLang('btn_show'));
895*c3413364SGerrit Uitslag                $this->showButton($cid, $label, 'toogle');
896*c3413364SGerrit Uitslag                $this->showButton($cid, $lang['btn_delete'], 'delete');
897f0fda08aSwikidesign            }
8981184c36aSwikidesign            ptln('</div>', 6); // class="comment_buttons"
8991184c36aSwikidesign        }
9001184c36aSwikidesign        ptln('</div>', 4); // class="hentry"
901f0fda08aSwikidesign    }
902f0fda08aSwikidesign
903de7e6f00SGerrit Uitslag    /**
904*c3413364SGerrit Uitslag     * If requested by user, show comment form to write a reply
905*c3413364SGerrit Uitslag     *
906*c3413364SGerrit Uitslag     * @param string $cid current comment id
907*c3413364SGerrit Uitslag     * @param string $reply comment id on which the user requested a reply
908de7e6f00SGerrit Uitslag     */
909*c3413364SGerrit Uitslag    protected function showReplyForm($cid, $reply)
910f1c6610eSpierre.spring    {
91131aab30eSGina Haeussge        if ($this->getConf('usethreading') && $reply == $cid) {
9124a0a1bd2Swikidesign            ptln('<div class="comment_replies">', 4);
913*c3413364SGerrit Uitslag            $this->showCommentForm('', 'add', $cid);
9144a0a1bd2Swikidesign            ptln('</div>', 4); // class="comment_replies"
915f0fda08aSwikidesign        }
916f0fda08aSwikidesign    }
917f0fda08aSwikidesign
918de7e6f00SGerrit Uitslag    /**
919*c3413364SGerrit Uitslag     *
920*c3413364SGerrit Uitslag     *
921*c3413364SGerrit Uitslag     * @param string $cid comment id
922*c3413364SGerrit Uitslag     * @param array  $data array with all comments by reference
923de7e6f00SGerrit Uitslag     * @param string $reply
924*c3413364SGerrit Uitslag     * @param bool $isVisible
925de7e6f00SGerrit Uitslag     */
926*c3413364SGerrit Uitslag    protected function showReplies($cid, &$data, $reply, &$isVisible)
927f1c6610eSpierre.spring    {
928f1c6610eSpierre.spring        $comment = $data['comments'][$cid];
929f1c6610eSpierre.spring        if (!count($comment['replies'])) {
930f1c6610eSpierre.spring            return;
931f1c6610eSpierre.spring        }
932*c3413364SGerrit Uitslag        ptln('<div class="comment_replies"'.$this->getWidthStyle().'>', 4);
933*c3413364SGerrit Uitslag        $isVisible = ($comment['show'] && $isVisible);
934f1c6610eSpierre.spring        foreach ($comment['replies'] as $rid) {
935*c3413364SGerrit Uitslag            $this->showCommentWithReplies($rid, $data, $cid, $reply, $isVisible);
936f1c6610eSpierre.spring        }
937f1c6610eSpierre.spring        ptln('</div>', 4);
938f1c6610eSpierre.spring    }
939f1c6610eSpierre.spring
940de7e6f00SGerrit Uitslag    /**
941de7e6f00SGerrit Uitslag     * Is an avatar displayed?
942de7e6f00SGerrit Uitslag     *
943de7e6f00SGerrit Uitslag     * @return bool
944de7e6f00SGerrit Uitslag     */
945*c3413364SGerrit Uitslag    protected function useAvatar()
946f1c6610eSpierre.spring    {
947*c3413364SGerrit Uitslag        if (is_null($this->useAvatar)) {
948*c3413364SGerrit Uitslag            $this->useAvatar = $this->getConf('useavatar')
949*c3413364SGerrit Uitslag                               && ($this->avatar = $this->loadHelper('avatar', false));
950f1c6610eSpierre.spring        }
951*c3413364SGerrit Uitslag        return $this->useAvatar;
952f1c6610eSpierre.spring    }
953f1c6610eSpierre.spring
954de7e6f00SGerrit Uitslag    /**
955de7e6f00SGerrit Uitslag     * Calculate width of indent
956de7e6f00SGerrit Uitslag     *
957de7e6f00SGerrit Uitslag     * @return string
958de7e6f00SGerrit Uitslag     */
959*c3413364SGerrit Uitslag    protected function getWidthStyle() {
960f1c6610eSpierre.spring        if (is_null($this->style)){
961*c3413364SGerrit Uitslag            if ($this->useAvatar()) {
962f1c6610eSpierre.spring                $this->style = ' style="margin-left: '.($this->avatar->getConf('size') + 14).'px;"';
963f1c6610eSpierre.spring            } else {
964f1c6610eSpierre.spring                $this->style = ' style="margin-left: 20px;"';
965f1c6610eSpierre.spring            }
966f1c6610eSpierre.spring        }
967f1c6610eSpierre.spring        return $this->style;
968f1c6610eSpierre.spring    }
969f1c6610eSpierre.spring
970f0fda08aSwikidesign    /**
971*c3413364SGerrit Uitslag     * Show the button which toggles between show/hide of the entire discussion section
97246178401Slupo49     */
973*c3413364SGerrit Uitslag    protected function showDiscussionToggleButton() {
97446178401Slupo49        ptln('<div id="toggle_button" class="toggle_button" style="text-align: right;">');
97511711461Shaobug        ptln('<input type="submit" id="discussion__btn_toggle_visibility" title="Toggle Visibiliy" class="button" value="'.$this->getLang('toggle_display').'">');
97646178401Slupo49        ptln('</div>');
97746178401Slupo49    }
97846178401Slupo49
97946178401Slupo49    /**
980f0fda08aSwikidesign     * Outputs the comment form
981f0fda08aSwikidesign     */
982*c3413364SGerrit Uitslag    protected function showCommentForm($raw = '', $act = 'add', $cid = null) {
983*c3413364SGerrit Uitslag        global $lang, $conf, $ID, $INPUT;
984f0fda08aSwikidesign
985f0fda08aSwikidesign        // not for unregistered users when guest comments aren't allowed
986*c3413364SGerrit Uitslag        if (!$INPUT->server->has('REMOTE_USER') && !$this->getConf('allowguests')) {
9877c8e18ffSGina Haeussge            ?>
9887c8e18ffSGina Haeussge            <div class="comment_form">
9897c8e18ffSGina Haeussge                <?php echo $this->getLang('noguests'); ?>
9907c8e18ffSGina Haeussge            </div>
9917c8e18ffSGina Haeussge            <?php
992de7e6f00SGerrit Uitslag            return;
9937c8e18ffSGina Haeussge        }
994f0fda08aSwikidesign
995*c3413364SGerrit Uitslag        // fill $raw with $INPUT->str('text') if it's empty (for failed CAPTCHA check)
996*c3413364SGerrit Uitslag        if (!$raw && $INPUT->str('comment') == 'show') {
997*c3413364SGerrit Uitslag            $raw = $INPUT->str('text');
9984cded5e1SGerrit Uitslag        }
999f0fda08aSwikidesign        ?>
10005ef1705fSiLoveiDo
1001f0fda08aSwikidesign        <div class="comment_form">
1002bea69264SMichael Klier          <form id="discussion__comment_form" method="post" action="<?php echo script() ?>" accept-charset="<?php echo $lang['encoding'] ?>">
1003f0fda08aSwikidesign            <div class="no">
1004f0fda08aSwikidesign              <input type="hidden" name="id" value="<?php echo $ID ?>" />
100561437513Swikidesign              <input type="hidden" name="do" value="show" />
1006f0fda08aSwikidesign              <input type="hidden" name="comment" value="<?php echo $act ?>" />
1007530693fbSMichael Klier        <?php
1008f0fda08aSwikidesign        // for adding a comment
1009f0fda08aSwikidesign        if ($act == 'add') {
1010f0fda08aSwikidesign        ?>
1011f0fda08aSwikidesign              <input type="hidden" name="reply" value="<?php echo $cid ?>" />
1012f0fda08aSwikidesign        <?php
101320c152acSMichael Klier        // for guest/adminimport: show name, e-mail and subscribe to comments fields
1014*c3413364SGerrit Uitslag        if(!$INPUT->server->has('REMOTE_USER') or ($this->getConf('adminimport') && $this->helper->isDiscussionMod())) {
1015f0fda08aSwikidesign        ?>
1016f0fda08aSwikidesign              <input type="hidden" name="user" value="<?php echo clientIP() ?>" />
1017f0fda08aSwikidesign              <div class="comment_name">
1018f0fda08aSwikidesign                <label class="block" for="discussion__comment_name">
1019f0fda08aSwikidesign                  <span><?php echo $lang['fullname'] ?>:</span>
1020*c3413364SGerrit Uitslag                  <input type="text" class="edit<?php if($INPUT->str('comment') == 'add' && empty($INPUT->str('name'))) echo ' error'?>" name="name" id="discussion__comment_name" size="50" tabindex="1" value="<?php echo hsc($INPUT->str('name'))?>" />
1021f0fda08aSwikidesign                </label>
1022f0fda08aSwikidesign              </div>
1023f0fda08aSwikidesign              <div class="comment_mail">
1024f0fda08aSwikidesign                <label class="block" for="discussion__comment_mail">
1025f0fda08aSwikidesign                  <span><?php echo $lang['email'] ?>:</span>
1026*c3413364SGerrit Uitslag                  <input type="text" class="edit<?php if($INPUT->str('comment') == 'add' && empty($INPUT->str('mail'))) echo ' error'?>" name="mail" id="discussion__comment_mail" size="50" tabindex="2" value="<?php echo hsc($INPUT->str('mail'))?>" />
1027f0fda08aSwikidesign                </label>
1028f0fda08aSwikidesign              </div>
1029f0fda08aSwikidesign        <?php
1030f0fda08aSwikidesign        }
1031f0fda08aSwikidesign
1032f0fda08aSwikidesign        // allow entering an URL
1033f0fda08aSwikidesign        if ($this->getConf('urlfield')) {
1034f0fda08aSwikidesign        ?>
1035f0fda08aSwikidesign              <div class="comment_url">
1036f0fda08aSwikidesign                <label class="block" for="discussion__comment_url">
1037f0fda08aSwikidesign                  <span><?php echo $this->getLang('url') ?>:</span>
1038*c3413364SGerrit Uitslag                  <input type="text" class="edit" name="url" id="discussion__comment_url" size="50" tabindex="3" value="<?php echo hsc($INPUT->str('url'))?>" />
1039f0fda08aSwikidesign                </label>
1040f0fda08aSwikidesign              </div>
1041f0fda08aSwikidesign        <?php
1042f0fda08aSwikidesign        }
1043f0fda08aSwikidesign
1044f0fda08aSwikidesign        // allow entering an address
1045f0fda08aSwikidesign        if ($this->getConf('addressfield')) {
1046f0fda08aSwikidesign        ?>
1047f0fda08aSwikidesign              <div class="comment_address">
1048f0fda08aSwikidesign                <label class="block" for="discussion__comment_address">
1049f0fda08aSwikidesign                  <span><?php echo $this->getLang('address') ?>:</span>
1050*c3413364SGerrit Uitslag                  <input type="text" class="edit" name="address" id="discussion__comment_address" size="50" tabindex="4" value="<?php echo hsc($INPUT->str('address'))?>" />
1051f0fda08aSwikidesign                </label>
1052f0fda08aSwikidesign              </div>
1053f0fda08aSwikidesign        <?php
1054f0fda08aSwikidesign        }
1055f0fda08aSwikidesign
1056f0fda08aSwikidesign        // allow setting the comment date
1057e6b2f142Slupo49        if ($this->getConf('adminimport') && ($this->helper->isDiscussionMod())) {
1058f0fda08aSwikidesign        ?>
1059f0fda08aSwikidesign              <div class="comment_date">
1060f0fda08aSwikidesign                <label class="block" for="discussion__comment_date">
1061f0fda08aSwikidesign                  <span><?php echo $this->getLang('date') ?>:</span>
1062f0fda08aSwikidesign                  <input type="text" class="edit" name="date" id="discussion__comment_date" size="50" />
1063f0fda08aSwikidesign                </label>
1064f0fda08aSwikidesign              </div>
1065f0fda08aSwikidesign        <?php
1066f0fda08aSwikidesign        }
1067f0fda08aSwikidesign
1068f0fda08aSwikidesign        // for saving a comment
1069f0fda08aSwikidesign        } else {
1070f0fda08aSwikidesign        ?>
1071f0fda08aSwikidesign              <input type="hidden" name="cid" value="<?php echo $cid ?>" />
1072f0fda08aSwikidesign        <?php
1073f0fda08aSwikidesign        }
1074f0fda08aSwikidesign        ?>
1075f0fda08aSwikidesign                <div class="comment_text">
107643ade360Slupo49                  <?php echo $this->getLang('entercomment'); echo ($this->getConf('wikisyntaxok') ? "" : ":");
107743ade360Slupo49                        if($this->getConf('wikisyntaxok')) echo '. ' . $this->getLang('wikisyntax') . ':'; ?>
107843ade360Slupo49
107943ade360Slupo49                  <!-- Fix for disable the toolbar when wikisyntaxok is set to false. See discussion's script.jss -->
108043ade360Slupo49                  <?php if($this->getConf('wikisyntaxok')) { ?>
108164901b8eSGerrit Uitslag                    <div id="discussion__comment_toolbar" class="toolbar group">
108243ade360Slupo49                  <?php } else { ?>
108343ade360Slupo49                    <div id="discussion__comment_toolbar_disabled">
108443ade360Slupo49                  <?php } ?>
10851de52da1SMichael Klier                </div>
1086*c3413364SGerrit Uitslag                <textarea class="edit<?php if($INPUT->str('comment') == 'add' && empty($INPUT->str('text'))) echo ' error'?>" name="text" cols="80" rows="10" id="discussion__comment_text" tabindex="5"><?php
108737e3c825SMichael Klier                  if($raw) {
108837e3c825SMichael Klier                      echo formText($raw);
108937e3c825SMichael Klier                  } else {
1090*c3413364SGerrit Uitslag                      echo hsc($INPUT->str('text'));
109137e3c825SMichael Klier                  }
109237e3c825SMichael Klier                ?></textarea>
1093f0fda08aSwikidesign              </div>
10940c613822SMichael Hamann
10950c613822SMichael Hamann              <?php
10960c613822SMichael Hamann              /** @var helper_plugin_captcha $captcha */
10970c613822SMichael Hamann              $captcha = $this->loadHelper('captcha', false);
10980c613822SMichael Hamann              if ($captcha && $captcha->isEnabled()) {
10990c613822SMichael Hamann                  echo $captcha->getHTML();
11000c613822SMichael Hamann              }
11010c613822SMichael Hamann
11020c613822SMichael Hamann              /** @var helper_plugin_recaptcha $recaptcha */
11030c613822SMichael Hamann              $recaptcha = $this->loadHelper('recaptcha', false);
11040c613822SMichael Hamann              if ($recaptcha && $recaptcha->isEnabled()) {
11050c613822SMichael Hamann                  echo $recaptcha->getHTML();
11060c613822SMichael Hamann              }
1107e7c760b3Swikidesign              ?>
11080c613822SMichael Hamann
1109bea69264SMichael Klier              <input class="button comment_submit" id="discussion__btn_submit" type="submit" name="submit" accesskey="s" value="<?php echo $lang['btn_save'] ?>" title="<?php echo $lang['btn_save']?> [S]" tabindex="7" />
11100c3df1b0SMichael Klier              <input class="button comment_preview_button" id="discussion__btn_preview" type="button" name="preview" accesskey="p" value="<?php echo $lang['btn_preview'] ?>" title="<?php echo $lang['btn_preview']?> [P]" />
11113011fb8bSMichael Klier
1112*c3413364SGerrit Uitslag        <?php if((!$INPUT->server->has('REMOTE_USER') || $INPUT->server->has('REMOTE_USER') && !$conf['subscribers']) && $this->getConf('subscribe')) { ?>
11133011fb8bSMichael Klier              <div class="comment_subscribe">
111411b1339eSGina Haeussge                <input type="checkbox" id="discussion__comment_subscribe" name="subscribe" tabindex="6" />
11153011fb8bSMichael Klier                <label class="block" for="discussion__comment_subscribe">
11163011fb8bSMichael Klier                  <span><?php echo $this->getLang('subscribe') ?></span>
11173011fb8bSMichael Klier                </label>
11183011fb8bSMichael Klier              </div>
11193011fb8bSMichael Klier        <?php } ?>
11203011fb8bSMichael Klier
11213011fb8bSMichael Klier              <div class="clearer"></div>
1122ed4846efSMichael Klier              <div id="discussion__comment_preview">&nbsp;</div>
1123f0fda08aSwikidesign            </div>
1124f0fda08aSwikidesign          </form>
1125f0fda08aSwikidesign        </div>
1126f0fda08aSwikidesign        <?php
1127f0fda08aSwikidesign    }
1128f0fda08aSwikidesign
1129f0fda08aSwikidesign    /**
1130*c3413364SGerrit Uitslag     * Action button below a comment
1131de7e6f00SGerrit Uitslag     *
1132*c3413364SGerrit Uitslag     * @param string $cid comment id
1133*c3413364SGerrit Uitslag     * @param string $label translated label
1134*c3413364SGerrit Uitslag     * @param string $act action
1135*c3413364SGerrit Uitslag     * @param bool $jump whether to scroll to the commentform
1136f0fda08aSwikidesign     */
1137*c3413364SGerrit Uitslag    protected function showButton($cid, $label, $act, $jump = false) {
1138f0fda08aSwikidesign        global $ID;
11395ef1705fSiLoveiDo
11401e46d176Swikidesign        $anchor = ($jump ? '#discussion__comment_form' : '' );
1141f0fda08aSwikidesign
1142f0fda08aSwikidesign        ?>
11436d1f4f20SGina Haeussge        <form class="button discussion__<?php echo $act?>" method="get" action="<?php echo script().$anchor ?>">
1144f0fda08aSwikidesign          <div class="no">
1145f0fda08aSwikidesign            <input type="hidden" name="id" value="<?php echo $ID ?>" />
114661437513Swikidesign            <input type="hidden" name="do" value="show" />
1147f0fda08aSwikidesign            <input type="hidden" name="comment" value="<?php echo $act ?>" />
1148f0fda08aSwikidesign            <input type="hidden" name="cid" value="<?php echo $cid ?>" />
1149f0fda08aSwikidesign            <input type="submit" value="<?php echo $label ?>" class="button" title="<?php echo $label ?>" />
1150f0fda08aSwikidesign          </div>
1151f0fda08aSwikidesign        </form>
1152f0fda08aSwikidesign        <?php
1153f0fda08aSwikidesign    }
1154f0fda08aSwikidesign
1155f0fda08aSwikidesign    /**
1156f0fda08aSwikidesign     * Adds an entry to the comments changelog
1157f0fda08aSwikidesign     *
1158f0fda08aSwikidesign     * @author Esther Brunner <wikidesign@gmail.com>
1159f0fda08aSwikidesign     * @author Ben Coburn <btcoburn@silicodon.net>
1160de7e6f00SGerrit Uitslag     *
1161de7e6f00SGerrit Uitslag     * @param int    $date
1162de7e6f00SGerrit Uitslag     * @param string $id page id
1163*c3413364SGerrit Uitslag     * @param string $type create/edit/delete/show/hide comment 'cc', 'ec', 'dc', 'sc', 'hc'
1164de7e6f00SGerrit Uitslag     * @param string $summary
1165de7e6f00SGerrit Uitslag     * @param string $extra
1166f0fda08aSwikidesign     */
1167*c3413364SGerrit Uitslag    protected function addLogEntry($date, $id, $type = 'cc', $summary = '', $extra = '') {
1168*c3413364SGerrit Uitslag        global $conf, $INPUT;
1169f0fda08aSwikidesign
1170f0fda08aSwikidesign        $changelog = $conf['metadir'].'/_comments.changes';
1171f0fda08aSwikidesign
11724cded5e1SGerrit Uitslag        //use current time if none supplied
11734cded5e1SGerrit Uitslag        if(!$date) {
11744cded5e1SGerrit Uitslag            $date = time();
11754cded5e1SGerrit Uitslag        }
1176*c3413364SGerrit Uitslag        $remote = $INPUT->server->str('REMOTE_ADDR');
1177*c3413364SGerrit Uitslag        $user   = $INPUT->server->str('REMOTE_USER');
1178f0fda08aSwikidesign
1179*c3413364SGerrit Uitslag        $strip = ["\t", "\n"];
1180*c3413364SGerrit Uitslag        $logline = [
1181f0fda08aSwikidesign                'date'  => $date,
1182f0fda08aSwikidesign                'ip'    => $remote,
1183f0fda08aSwikidesign                'type'  => str_replace($strip, '', $type),
1184f0fda08aSwikidesign                'id'    => $id,
1185f0fda08aSwikidesign                'user'  => $user,
1186f0fda08aSwikidesign                'sum'   => str_replace($strip, '', $summary),
1187f0fda08aSwikidesign                'extra' => str_replace($strip, '', $extra)
1188*c3413364SGerrit Uitslag        ];
1189f0fda08aSwikidesign
1190f0fda08aSwikidesign        // add changelog line
1191f0fda08aSwikidesign        $logline = implode("\t", $logline)."\n";
1192f0fda08aSwikidesign        io_saveFile($changelog, $logline, true); //global changelog cache
1193*c3413364SGerrit Uitslag        $this->trimRecentCommentsLog($changelog);
119477a22ba2Swikidesign
119577a22ba2Swikidesign        // tell the indexer to re-index the page
119677a22ba2Swikidesign        @unlink(metaFN($id, '.indexed'));
1197f0fda08aSwikidesign    }
1198f0fda08aSwikidesign
1199f0fda08aSwikidesign    /**
1200f0fda08aSwikidesign     * Trims the recent comments cache to the last $conf['changes_days'] recent
1201f0fda08aSwikidesign     * changes or $conf['recent'] items, which ever is larger.
1202f0fda08aSwikidesign     * The trimming is only done once a day.
1203f0fda08aSwikidesign     *
1204f0fda08aSwikidesign     * @author Ben Coburn <btcoburn@silicodon.net>
1205de7e6f00SGerrit Uitslag     *
1206de7e6f00SGerrit Uitslag     * @param string $changelog file path
1207de7e6f00SGerrit Uitslag     * @return bool
1208f0fda08aSwikidesign     */
1209*c3413364SGerrit Uitslag    protected function trimRecentCommentsLog($changelog) {
1210f0fda08aSwikidesign        global $conf;
1211f0fda08aSwikidesign
1212f0fda08aSwikidesign        if (@file_exists($changelog) &&
1213f0fda08aSwikidesign                (filectime($changelog) + 86400) < time() &&
12144cded5e1SGerrit Uitslag                !@file_exists($changelog.'_tmp')
12154cded5e1SGerrit Uitslag        ) {
1216f0fda08aSwikidesign
1217f0fda08aSwikidesign            io_lock($changelog);
1218f0fda08aSwikidesign            $lines = file($changelog);
1219f0fda08aSwikidesign            if (count($lines)<$conf['recent']) {
1220f0fda08aSwikidesign                // nothing to trim
1221f0fda08aSwikidesign                io_unlock($changelog);
1222f0fda08aSwikidesign                return true;
1223f0fda08aSwikidesign            }
1224f0fda08aSwikidesign
1225f0fda08aSwikidesign            io_saveFile($changelog.'_tmp', '');                  // presave tmp as 2nd lock
1226f0fda08aSwikidesign            $trim_time = time() - $conf['recent_days']*86400;
1227*c3413364SGerrit Uitslag            $out_lines = [];
1228f0fda08aSwikidesign
1229e49085a2SMichael Klier            $num = count($lines);
1230e49085a2SMichael Klier            for ($i=0; $i<$num; $i++) {
1231f0fda08aSwikidesign                $log = parseChangelogLine($lines[$i]);
1232f0fda08aSwikidesign                if ($log === false) continue;                      // discard junk
1233f0fda08aSwikidesign                if ($log['date'] < $trim_time) {
1234f0fda08aSwikidesign                    $old_lines[$log['date'].".$i"] = $lines[$i];     // keep old lines for now (append .$i to prevent key collisions)
1235f0fda08aSwikidesign                } else {
1236f0fda08aSwikidesign                    $out_lines[$log['date'].".$i"] = $lines[$i];     // definitely keep these lines
1237f0fda08aSwikidesign                }
1238f0fda08aSwikidesign            }
1239f0fda08aSwikidesign
1240f0fda08aSwikidesign            // sort the final result, it shouldn't be necessary,
1241f0fda08aSwikidesign            // however the extra robustness in making the changelog cache self-correcting is worth it
1242f0fda08aSwikidesign            ksort($out_lines);
1243f0fda08aSwikidesign            $extra = $conf['recent'] - count($out_lines);        // do we need extra lines do bring us up to minimum
1244f0fda08aSwikidesign            if ($extra > 0) {
1245f0fda08aSwikidesign                ksort($old_lines);
1246f0fda08aSwikidesign                $out_lines = array_merge(array_slice($old_lines,-$extra),$out_lines);
1247f0fda08aSwikidesign            }
1248f0fda08aSwikidesign
1249f0fda08aSwikidesign            // save trimmed changelog
1250f0fda08aSwikidesign            io_saveFile($changelog.'_tmp', implode('', $out_lines));
1251f0fda08aSwikidesign            @unlink($changelog);
1252f0fda08aSwikidesign            if (!rename($changelog.'_tmp', $changelog)) {
1253f0fda08aSwikidesign                // rename failed so try another way...
1254f0fda08aSwikidesign                io_unlock($changelog);
1255f0fda08aSwikidesign                io_saveFile($changelog, implode('', $out_lines));
1256f0fda08aSwikidesign                @unlink($changelog.'_tmp');
1257f0fda08aSwikidesign            } else {
1258f0fda08aSwikidesign                io_unlock($changelog);
1259f0fda08aSwikidesign            }
1260f0fda08aSwikidesign            return true;
1261f0fda08aSwikidesign        }
1262de7e6f00SGerrit Uitslag        return true;
1263f0fda08aSwikidesign    }
1264f0fda08aSwikidesign
1265f0fda08aSwikidesign    /**
1266f0fda08aSwikidesign     * Sends a notify mail on new comment
1267f0fda08aSwikidesign     *
1268f0fda08aSwikidesign     * @param  array  $comment  data array of the new comment
1269*c3413364SGerrit Uitslag     * @param  array  $subscribers data of the subscribers by reference
1270f0fda08aSwikidesign     *
1271f0fda08aSwikidesign     * @author Andreas Gohr <andi@splitbrain.org>
1272f0fda08aSwikidesign     * @author Esther Brunner <wikidesign@gmail.com>
1273f0fda08aSwikidesign     */
1274*c3413364SGerrit Uitslag    protected function notify($comment, &$subscribers) {
1275*c3413364SGerrit Uitslag        global $conf, $ID, $INPUT, $auth;
1276f0fda08aSwikidesign
12779881d835SMichael Klier        $notify_text = io_readfile($this->localfn('subscribermail'));
12789881d835SMichael Klier        $confirm_text = io_readfile($this->localfn('confirmsubscribe'));
12799881d835SMichael Klier        $subject_notify = '['.$conf['title'].'] '.$this->getLang('mail_newcomment');
12809881d835SMichael Klier        $subject_subscribe = '['.$conf['title'].'] '.$this->getLang('subscribe');
1281f0fda08aSwikidesign
1282451c1100SMichael Hamann        $mailer = new Mailer();
1283*c3413364SGerrit Uitslag        if (!$INPUT->server->has('REMOTE_USER')) {
1284451c1100SMichael Hamann            $mailer->from($conf['mailfromnobody']);
1285f4a5ed1cSMatthias Schulte        }
1286f4a5ed1cSMatthias Schulte
1287*c3413364SGerrit Uitslag        $replace = [
12883c4953e9SMichael Hamann            'PAGE' => $ID,
12893c4953e9SMichael Hamann            'TITLE' => $conf['title'],
12903c4953e9SMichael Hamann            'DATE' => dformat($comment['date']['created'], $conf['dformat']),
12913c4953e9SMichael Hamann            'NAME' => $comment['user']['name'],
12923c4953e9SMichael Hamann            'TEXT' => $comment['raw'],
12933c4953e9SMichael Hamann            'COMMENTURL' => wl($ID, '', true) . '#comment_' . $comment['cid'],
129406644a74SMichael Hamann            'UNSUBSCRIBE' => wl($ID, 'do=subscribe', true, '&'),
12953c4953e9SMichael Hamann            'DOKUWIKIURL' => DOKU_URL
1296*c3413364SGerrit Uitslag        ];
1297451c1100SMichael Hamann
1298*c3413364SGerrit Uitslag        $confirm_replace = [
12993c4953e9SMichael Hamann            'PAGE' => $ID,
13003c4953e9SMichael Hamann            'TITLE' => $conf['title'],
13013c4953e9SMichael Hamann            'DOKUWIKIURL' => DOKU_URL
1302*c3413364SGerrit Uitslag        ];
1303451c1100SMichael Hamann
1304451c1100SMichael Hamann
1305451c1100SMichael Hamann        $mailer->subject($subject_notify);
1306451c1100SMichael Hamann        $mailer->setBody($notify_text, $replace);
1307451c1100SMichael Hamann
1308f4a5ed1cSMatthias Schulte        // send mail to notify address
1309f4a5ed1cSMatthias Schulte        if ($conf['notify']) {
1310451c1100SMichael Hamann            $mailer->bcc($conf['notify']);
1311451c1100SMichael Hamann            $mailer->send();
1312f4a5ed1cSMatthias Schulte        }
1313f4a5ed1cSMatthias Schulte
1314ca785d71SMichael Hamann        // send email to moderators
1315ca785d71SMichael Hamann        if ($this->getConf('moderatorsnotify')) {
1316*c3413364SGerrit Uitslag            $moderatorgrpsString = trim($this->getConf('moderatorgroups'));
1317*c3413364SGerrit Uitslag            if (!empty($moderatorgrpsString)) {
1318ca785d71SMichael Hamann                // create a clean mods list
1319*c3413364SGerrit Uitslag                $moderatorgroups = explode(',', $moderatorgrpsString);
1320*c3413364SGerrit Uitslag                $moderatorgroups = array_map('trim', $moderatorgroups);
1321*c3413364SGerrit Uitslag                $moderatorgroups = array_unique($moderatorgroups);
1322*c3413364SGerrit Uitslag                $moderatorgroups = array_filter($moderatorgroups);
1323ca785d71SMichael Hamann                // search for moderators users
1324*c3413364SGerrit Uitslag                foreach($moderatorgroups as $moderatorgroup) {
1325*c3413364SGerrit Uitslag                    if(!$auth->isCaseSensitive()) {
1326*c3413364SGerrit Uitslag                        $moderatorgroup = PhpString::strtolower($moderatorgroup);
1327*c3413364SGerrit Uitslag                    }
1328ca785d71SMichael Hamann                    // create a clean mailing list
1329*c3413364SGerrit Uitslag                    $bccs = [];
1330*c3413364SGerrit Uitslag                    if($moderatorgroup[0] == '@') {
1331*c3413364SGerrit Uitslag                        foreach($auth->retrieveUsers(0, 0, ['grps' => $auth->cleanGroup(substr($moderatorgroup, 1))]) as $user) {
1332ca785d71SMichael Hamann                            if (!empty($user['mail'])) {
1333*c3413364SGerrit Uitslag                                $bccs[] = $user['mail'];
1334ca785d71SMichael Hamann                            }
1335ca785d71SMichael Hamann                        }
1336ca785d71SMichael Hamann                    } else {
1337*c3413364SGerrit Uitslag                        //it is an user
1338*c3413364SGerrit Uitslag                        $userdata = $auth->getUserData($auth->cleanUser($moderatorgroup));
1339ca785d71SMichael Hamann                        if (!empty($userdata['mail'])) {
1340*c3413364SGerrit Uitslag                            $bccs[] = $userdata['mail'];
1341ca785d71SMichael Hamann                        }
1342ca785d71SMichael Hamann                    }
1343*c3413364SGerrit Uitslag                    $bccs = array_unique($bccs);
1344ca785d71SMichael Hamann                    // notify the users
1345*c3413364SGerrit Uitslag                    $mailer->bcc(implode(',', $bccs));
1346ca785d71SMichael Hamann                    $mailer->send();
1347ca785d71SMichael Hamann                }
1348ca785d71SMichael Hamann            }
1349ca785d71SMichael Hamann        }
1350ca785d71SMichael Hamann
1351f4a5ed1cSMatthias Schulte        // notify page subscribers
1352451c1100SMichael Hamann        if (actionOK('subscribe')) {
1353*c3413364SGerrit Uitslag            $data = ['id' => $ID, 'addresslist' => '', 'self' => false];
1354*c3413364SGerrit Uitslag            //FIXME default callback, needed to mentioned it again?
1355*c3413364SGerrit Uitslag            Event::createAndTrigger(
1356451c1100SMichael Hamann                'COMMON_NOTIFY_ADDRESSLIST', $data,
1357*c3413364SGerrit Uitslag                [new SubscriberManager(), 'notifyAddresses']
1358451c1100SMichael Hamann            );
1359*c3413364SGerrit Uitslag
1360451c1100SMichael Hamann            $to = $data['addresslist'];
1361451c1100SMichael Hamann            if(!empty($to)) {
1362451c1100SMichael Hamann                $mailer->bcc($to);
1363451c1100SMichael Hamann                $mailer->send();
1364451c1100SMichael Hamann            }
13653011fb8bSMichael Klier        }
1366f0fda08aSwikidesign
13673011fb8bSMichael Klier        // notify comment subscribers
13683011fb8bSMichael Klier        if (!empty($subscribers)) {
13693011fb8bSMichael Klier
13709881d835SMichael Klier            foreach($subscribers as $mail => $data) {
1371451c1100SMichael Hamann                $mailer->bcc($mail);
13729881d835SMichael Klier                if($data['active']) {
13733c4953e9SMichael Hamann                    $replace['UNSUBSCRIBE'] = wl($ID, 'do=discussion_unsubscribe&hash=' . $data['hash'], true, '&');
13743011fb8bSMichael Klier
1375451c1100SMichael Hamann                    $mailer->subject($subject_notify);
1376451c1100SMichael Hamann                    $mailer->setBody($notify_text, $replace);
1377451c1100SMichael Hamann                    $mailer->send();
1378*c3413364SGerrit Uitslag                } elseif(!$data['confirmsent']) {
13793c4953e9SMichael Hamann                    $confirm_replace['SUBSCRIBE'] = wl($ID, 'do=discussion_confirmsubscribe&hash=' . $data['hash'], true, '&');
13809881d835SMichael Klier
1381451c1100SMichael Hamann                    $mailer->subject($subject_subscribe);
1382451c1100SMichael Hamann                    $mailer->setBody($confirm_text, $confirm_replace);
1383451c1100SMichael Hamann                    $mailer->send();
13849881d835SMichael Klier                    $subscribers[$mail]['confirmsent'] = true;
13859881d835SMichael Klier                }
13863011fb8bSMichael Klier            }
13873011fb8bSMichael Klier        }
1388f0fda08aSwikidesign    }
1389f0fda08aSwikidesign
1390f0fda08aSwikidesign    /**
1391f0fda08aSwikidesign     * Counts the number of visible comments
1392de7e6f00SGerrit Uitslag     *
1393*c3413364SGerrit Uitslag     * @param array $data array with all comments
1394de7e6f00SGerrit Uitslag     * @return int
1395f0fda08aSwikidesign     */
1396*c3413364SGerrit Uitslag    protected function countVisibleComments($data) {
1397f0fda08aSwikidesign        $number = 0;
1398de7e6f00SGerrit Uitslag        foreach ($data['comments'] as $comment) {
1399f0fda08aSwikidesign            if ($comment['parent']) continue;
1400f0fda08aSwikidesign            if (!$comment['show']) continue;
1401*c3413364SGerrit Uitslag
1402f0fda08aSwikidesign            $number++;
1403f0fda08aSwikidesign            $rids = $comment['replies'];
14044cded5e1SGerrit Uitslag            if (count($rids)) {
1405*c3413364SGerrit Uitslag                $number = $number + $this->countVisibleReplies($data, $rids);
14064cded5e1SGerrit Uitslag            }
1407f0fda08aSwikidesign        }
1408f0fda08aSwikidesign        return $number;
1409f0fda08aSwikidesign    }
1410f0fda08aSwikidesign
1411de7e6f00SGerrit Uitslag    /**
1412*c3413364SGerrit Uitslag     * Count visible replies on the comments
1413*c3413364SGerrit Uitslag     *
1414de7e6f00SGerrit Uitslag     * @param array $data
1415de7e6f00SGerrit Uitslag     * @param array $rids
1416*c3413364SGerrit Uitslag     * @return int counted replies
1417de7e6f00SGerrit Uitslag     */
1418*c3413364SGerrit Uitslag    protected function countVisibleReplies(&$data, $rids) {
1419f0fda08aSwikidesign        $number = 0;
1420f0fda08aSwikidesign        foreach ($rids as $rid) {
14212ee3dca3Swikidesign            if (!isset($data['comments'][$rid])) continue; // reply was removed
1422f0fda08aSwikidesign            if (!$data['comments'][$rid]['show']) continue;
1423*c3413364SGerrit Uitslag
1424f0fda08aSwikidesign            $number++;
1425f0fda08aSwikidesign            $rids = $data['comments'][$rid]['replies'];
14264cded5e1SGerrit Uitslag            if (count($rids)) {
1427*c3413364SGerrit Uitslag                $number = $number + $this->countVisibleReplies($data, $rids);
14284cded5e1SGerrit Uitslag            }
1429f0fda08aSwikidesign        }
1430f0fda08aSwikidesign        return $number;
1431f0fda08aSwikidesign    }
1432f0fda08aSwikidesign
1433f0fda08aSwikidesign    /**
1434*c3413364SGerrit Uitslag     * Renders the raw comment (wiki)text to html
1435de7e6f00SGerrit Uitslag     *
1436*c3413364SGerrit Uitslag     * @param string $raw comment text
1437de7e6f00SGerrit Uitslag     * @return null|string
1438f0fda08aSwikidesign     */
1439*c3413364SGerrit Uitslag    protected function renderComment($raw) {
1440f0fda08aSwikidesign        if ($this->getConf('wikisyntaxok')) {
1441efccf6b0SJeffrey Bergamini            // Note the warning for render_text:
1442efccf6b0SJeffrey Bergamini            //   "very ineffecient for small pieces of data - try not to use"
1443efccf6b0SJeffrey Bergamini            // in dokuwiki/inc/plugin.php
1444efccf6b0SJeffrey Bergamini            $xhtml = $this->render_text($raw);
1445f0fda08aSwikidesign        } else { // wiki syntax not allowed -> just encode special chars
144687bb4e97SMichael Klier            $xhtml = hsc(trim($raw));
144787bb4e97SMichael Klier            $xhtml = str_replace("\n", '<br />', $xhtml);
1448f0fda08aSwikidesign        }
1449f0fda08aSwikidesign        return $xhtml;
1450f0fda08aSwikidesign    }
1451f0fda08aSwikidesign
1452f0fda08aSwikidesign    /**
1453479dd10fSwikidesign     * Finds out whether there is a discussion section for the current page
1454de7e6f00SGerrit Uitslag     *
1455de7e6f00SGerrit Uitslag     * @param string $title
1456de7e6f00SGerrit Uitslag     * @return bool
1457479dd10fSwikidesign     */
1458*c3413364SGerrit Uitslag    protected function hasDiscussion(&$title) {
1459b2ac3b3bSwikidesign        global $ID;
14604a0a1bd2Swikidesign
1461*c3413364SGerrit Uitslag        $file = metaFN($ID, '.comments');
1462479dd10fSwikidesign
1463*c3413364SGerrit Uitslag        if (!@file_exists($file)) {
1464f0bcde18SGerrit Uitslag            if ($this->isDiscussionEnabled()) {
14652b18adb9SMichael Klier                return true;
14662b18adb9SMichael Klier            } else {
14672b18adb9SMichael Klier                return false;
14682b18adb9SMichael Klier            }
1469479dd10fSwikidesign        }
1470479dd10fSwikidesign
1471*c3413364SGerrit Uitslag        $comments = unserialize(io_readFile($file, false));
1472479dd10fSwikidesign
14734cded5e1SGerrit Uitslag        if ($comments['title']) {
14744cded5e1SGerrit Uitslag            $title = hsc($comments['title']);
14754cded5e1SGerrit Uitslag        }
1476479dd10fSwikidesign        $num = $comments['number'];
1477*c3413364SGerrit Uitslag        if (!$comments['status'] || ($comments['status'] == 2 && $num == 0)) {
1478*c3413364SGerrit Uitslag            //disabled, or closed and no comments
1479*c3413364SGerrit Uitslag            return false;
1480*c3413364SGerrit Uitslag        } else {
1481*c3413364SGerrit Uitslag            return true;
1482*c3413364SGerrit Uitslag        }
1483479dd10fSwikidesign    }
1484479dd10fSwikidesign
1485479dd10fSwikidesign    /**
1486e7c760b3Swikidesign     * Creates a new thread page
1487de7e6f00SGerrit Uitslag     *
1488de7e6f00SGerrit Uitslag     * @return string
1489e7c760b3Swikidesign     */
1490*c3413364SGerrit Uitslag    protected function newThread() {
1491*c3413364SGerrit Uitslag        global $ID, $INFO, $INPUT;
1492f0fda08aSwikidesign
1493*c3413364SGerrit Uitslag        $ns    = cleanID($INPUT->str('ns'));
1494*c3413364SGerrit Uitslag        $title = str_replace(':', '', $INPUT->str('title'));
14952e80cd5fSwikidesign        $back  = $ID;
14962e80cd5fSwikidesign        $ID    = ($ns ? $ns.':' : '').cleanID($title);
14972e80cd5fSwikidesign        $INFO  = pageinfo();
1498f0fda08aSwikidesign
1499f0fda08aSwikidesign        // check if we are allowed to create this file
15002e80cd5fSwikidesign        if ($INFO['perm'] >= AUTH_CREATE) {
1501f0fda08aSwikidesign
1502f0fda08aSwikidesign            //check if locked by anyone - if not lock for my self
15034cded5e1SGerrit Uitslag            if ($INFO['locked']) {
15044cded5e1SGerrit Uitslag                return 'locked';
15054cded5e1SGerrit Uitslag            } else {
15064cded5e1SGerrit Uitslag                lock($ID);
15074cded5e1SGerrit Uitslag            }
1508f0fda08aSwikidesign
1509f0fda08aSwikidesign            // prepare the new thread file with default stuff
15102e80cd5fSwikidesign            if (!@file_exists($INFO['filepath'])) {
1511f0fda08aSwikidesign                global $TEXT;
1512f0fda08aSwikidesign
1513*c3413364SGerrit Uitslag                $TEXT = pageTemplate(($ns ? $ns.':' : '').$title);
15141433886fSwikidesign                if (!$TEXT) {
1515*c3413364SGerrit Uitslag                    $data = ['id' => $ID, 'ns' => $ns, 'title' => $title, 'back' => $back];
1516*c3413364SGerrit Uitslag                    $TEXT = $this->pageTemplate($data);
15172e80cd5fSwikidesign                }
15182e80cd5fSwikidesign                return 'preview';
1519f0fda08aSwikidesign            } else {
15202e80cd5fSwikidesign                return 'edit';
1521f0fda08aSwikidesign            }
1522f0fda08aSwikidesign        } else {
15232e80cd5fSwikidesign            return 'show';
1524f0fda08aSwikidesign        }
1525f0fda08aSwikidesign    }
1526f0fda08aSwikidesign
1527e7c760b3Swikidesign    /**
152861437513Swikidesign     * Adapted version of pageTemplate() function
1529de7e6f00SGerrit Uitslag     *
1530de7e6f00SGerrit Uitslag     * @param array $data
1531de7e6f00SGerrit Uitslag     * @return string
153261437513Swikidesign     */
1533*c3413364SGerrit Uitslag    protected function pageTemplate($data) {
1534*c3413364SGerrit Uitslag        global $conf, $INFO, $INPUT;
153561437513Swikidesign
153661437513Swikidesign        $id   = $data['id'];
1537*c3413364SGerrit Uitslag        $user = $INPUT->server->str('REMOTE_USER');
153861437513Swikidesign        $tpl  = io_readFile(DOKU_PLUGIN.'discussion/_template.txt');
153961437513Swikidesign
154061437513Swikidesign        // standard replacements
1541*c3413364SGerrit Uitslag        $replace = [
154261437513Swikidesign                '@NS@'   => $data['ns'],
154361437513Swikidesign                '@PAGE@' => strtr(noNS($id),'_',' '),
154461437513Swikidesign                '@USER@' => $user,
154561437513Swikidesign                '@NAME@' => $INFO['userinfo']['name'],
154661437513Swikidesign                '@MAIL@' => $INFO['userinfo']['mail'],
1547d5530824SMichael Hamann                '@DATE@' => dformat(time(), $conf['dformat']),
1548*c3413364SGerrit Uitslag        ];
154961437513Swikidesign
155061437513Swikidesign        // additional replacements
155161437513Swikidesign        $replace['@BACK@']  = $data['back'];
155261437513Swikidesign        $replace['@TITLE@'] = $data['title'];
155361437513Swikidesign
155461437513Swikidesign        // avatar if useavatar and avatar plugin available
1555*c3413364SGerrit Uitslag        if ($this->getConf('useavatar') && !plugin_isdisabled('avatar')) {
155661437513Swikidesign            $replace['@AVATAR@'] = '{{avatar>'.$user.' }} ';
155761437513Swikidesign        } else {
155861437513Swikidesign            $replace['@AVATAR@'] = '';
155961437513Swikidesign        }
156061437513Swikidesign
156161437513Swikidesign        // tag if tag plugin is available
1562*c3413364SGerrit Uitslag        if (!plugin_isdisabled('tag')){
156361437513Swikidesign            $replace['@TAG@'] = "\n\n{{tag>}}";
156461437513Swikidesign        } else {
156561437513Swikidesign            $replace['@TAG@'] = '';
156661437513Swikidesign        }
156761437513Swikidesign
1568*c3413364SGerrit Uitslag        // perform the replacements in tpl
1569*c3413364SGerrit Uitslag        return str_replace(array_keys($replace), array_values($replace), $tpl);
157061437513Swikidesign    }
157161437513Swikidesign
157261437513Swikidesign    /**
1573e7c760b3Swikidesign     * Checks if the CAPTCHA string submitted is valid
1574e7c760b3Swikidesign     */
1575*c3413364SGerrit Uitslag    protected function captchaCheck() {
1576*c3413364SGerrit Uitslag        global $INPUT;
157796bc68a7SMichael Hamann        /** @var helper_plugin_captcha $captcha */
1578*c3413364SGerrit Uitslag        if (!$captcha = $this->loadHelper('captcha', false)) {
1579*c3413364SGerrit Uitslag            // CAPTCHA is disabled or not available
1580*c3413364SGerrit Uitslag            return;
1581*c3413364SGerrit Uitslag        }
1582e7c760b3Swikidesign
1583d578a059SMichael Hamann        if ($captcha->isEnabled() && !$captcha->check()) {
1584*c3413364SGerrit Uitslag            if ($INPUT->str('comment') == 'save') {
1585*c3413364SGerrit Uitslag                $INPUT->set('comment', 'edit');
1586*c3413364SGerrit Uitslag            } elseif ($INPUT->str('comment') == 'add') {
1587*c3413364SGerrit Uitslag                $INPUT->set('comment', 'show');
15884cded5e1SGerrit Uitslag            }
1589e7c760b3Swikidesign        }
1590e7c760b3Swikidesign    }
1591e7c760b3Swikidesign
1592a1ca9e44Swikidesign    /**
1593bd6dc08eSAdrian Schlegel     * checks if the submitted reCAPTCHA string is valid
1594bd6dc08eSAdrian Schlegel     *
1595bd6dc08eSAdrian Schlegel     * @author Adrian Schlegel <adrian@liip.ch>
1596bd6dc08eSAdrian Schlegel     */
1597*c3413364SGerrit Uitslag    protected function recaptchaCheck() {
1598*c3413364SGerrit Uitslag        global $INPUT;
1599*c3413364SGerrit Uitslag        /** @var helper_plugin_recaptcha $recaptcha */
1600*c3413364SGerrit Uitslag        if (!$recaptcha = plugin_load('helper', 'recaptcha'))
1601bd6dc08eSAdrian Schlegel            return; // reCAPTCHA is disabled or not available
1602bd6dc08eSAdrian Schlegel
1603bd6dc08eSAdrian Schlegel        // do nothing if logged in user and no reCAPTCHA required
1604*c3413364SGerrit Uitslag        if (!$recaptcha->getConf('forusers') && $INPUT->server->has('REMOTE_USER')) return;
1605bd6dc08eSAdrian Schlegel
1606*c3413364SGerrit Uitslag        $response = $recaptcha->check();
1607*c3413364SGerrit Uitslag        if (!$response->is_valid) {
1608bd6dc08eSAdrian Schlegel            msg($recaptcha->getLang('testfailed'),-1);
1609*c3413364SGerrit Uitslag            if ($INPUT->str('comment') == 'save') {
1610*c3413364SGerrit Uitslag                $INPUT->str('comment', 'edit');
1611*c3413364SGerrit Uitslag            } elseif ($INPUT->str('comment') == 'add') {
1612*c3413364SGerrit Uitslag                $INPUT->str('comment', 'show');
16134cded5e1SGerrit Uitslag            }
1614bd6dc08eSAdrian Schlegel        }
1615bd6dc08eSAdrian Schlegel    }
1616bd6dc08eSAdrian Schlegel
1617bd6dc08eSAdrian Schlegel    /**
1618ac818938SMichael Hamann     * Add discussion plugin version to the indexer version
1619ac818938SMichael Hamann     * This means that all pages will be indexed again in order to add the comments
1620ac818938SMichael Hamann     * to the index whenever there has been a change that concerns the index content.
1621de7e6f00SGerrit Uitslag     *
1622de7e6f00SGerrit Uitslag     * @param Doku_Event $event
1623de7e6f00SGerrit Uitslag     * @param $param
1624ac818938SMichael Hamann     */
1625*c3413364SGerrit Uitslag    public function addIndexVersion(Doku_Event $event, $param) {
1626ac818938SMichael Hamann        $event->data['discussion'] = '0.1';
1627ac818938SMichael Hamann    }
1628ac818938SMichael Hamann
1629ac818938SMichael Hamann    /**
1630a1ca9e44Swikidesign     * Adds the comments to the index
1631de7e6f00SGerrit Uitslag     *
1632de7e6f00SGerrit Uitslag     * @param Doku_Event $event
1633*c3413364SGerrit Uitslag     * @param array $param with
1634*c3413364SGerrit Uitslag     *  'id' => string 'page'/'id' for respectively INDEXER_PAGE_ADD and FULLTEXT_SNIPPET_CREATE event
1635*c3413364SGerrit Uitslag     *  'text' => string 'body'/'text'
1636a1ca9e44Swikidesign     */
1637*c3413364SGerrit Uitslag    public function addCommentsToIndex(Doku_Event $event, $param) {
1638a1ca9e44Swikidesign        // get .comments meta file name
163910b5d61eSMichael Hamann        $file = metaFN($event->data[$param['id']], '.comments');
1640a1ca9e44Swikidesign
164196b3951aSMichael Hamann        if (!@file_exists($file)) return;
164296b3951aSMichael Hamann        $data = unserialize(io_readFile($file, false));
1643*c3413364SGerrit Uitslag
1644*c3413364SGerrit Uitslag        // comments are turned off or no comments available to index
1645*c3413364SGerrit Uitslag        if (!$data['status'] || $data['number'] == 0) return;
1646a1ca9e44Swikidesign
1647a1ca9e44Swikidesign        // now add the comments
1648a1ca9e44Swikidesign        if (isset($data['comments'])) {
1649a1ca9e44Swikidesign            foreach ($data['comments'] as $key => $value) {
1650*c3413364SGerrit Uitslag                $event->data[$param['text']] .= DOKU_LF.$this->addCommentWords($key, $data);
1651a1ca9e44Swikidesign            }
1652a1ca9e44Swikidesign        }
1653a1ca9e44Swikidesign    }
1654a1ca9e44Swikidesign
1655*c3413364SGerrit Uitslag    /**
1656*c3413364SGerrit Uitslag     * Checks if the phrase occurs in the comments and return event result true if matching
1657*c3413364SGerrit Uitslag     *
1658*c3413364SGerrit Uitslag     * @param Doku_Event $event
1659*c3413364SGerrit Uitslag     * @param $param
1660*c3413364SGerrit Uitslag     * @return void
1661*c3413364SGerrit Uitslag     */
1662*c3413364SGerrit Uitslag    public function fulltextPhraseMatchInComments(Doku_Event $event, $param) {
166310b5d61eSMichael Hamann        if ($event->result === true) return;
166410b5d61eSMichael Hamann
166510b5d61eSMichael Hamann        // get .comments meta file name
166610b5d61eSMichael Hamann        $file = metaFN($event->data['id'], '.comments');
166710b5d61eSMichael Hamann
166810b5d61eSMichael Hamann        if (!@file_exists($file)) return;
166910b5d61eSMichael Hamann        $data = unserialize(io_readFile($file, false));
1670*c3413364SGerrit Uitslag
1671*c3413364SGerrit Uitslag        // comments are turned off or no comments available to match
1672*c3413364SGerrit Uitslag        if (!$data['status'] || $data['number'] == 0) return;
167310b5d61eSMichael Hamann
167410b5d61eSMichael Hamann        $matched = false;
167510b5d61eSMichael Hamann
167610b5d61eSMichael Hamann        // now add the comments
167710b5d61eSMichael Hamann        if (isset($data['comments'])) {
1678*c3413364SGerrit Uitslag            foreach ($data['comments'] as $cid => $value) {
1679*c3413364SGerrit Uitslag                $matched = $this->phraseMatchInComment($event->data['phrase'], $cid, $data);
168010b5d61eSMichael Hamann                if ($matched) break;
168110b5d61eSMichael Hamann            }
168210b5d61eSMichael Hamann        }
168310b5d61eSMichael Hamann
1684*c3413364SGerrit Uitslag        if ($matched) {
168510b5d61eSMichael Hamann            $event->result = true;
168610b5d61eSMichael Hamann        }
1687*c3413364SGerrit Uitslag    }
168810b5d61eSMichael Hamann
1689*c3413364SGerrit Uitslag    /**
1690*c3413364SGerrit Uitslag     * Match the phrase in the comment and its replies
1691*c3413364SGerrit Uitslag     *
1692*c3413364SGerrit Uitslag     * @param string $phrase phrase to search
1693*c3413364SGerrit Uitslag     * @param string $cid comment id
1694*c3413364SGerrit Uitslag     * @param array $data array with all comments by reference
1695*c3413364SGerrit Uitslag     * @param string $parent cid of parent
1696*c3413364SGerrit Uitslag     * @return bool if match true, otherwise false
1697*c3413364SGerrit Uitslag     */
1698*c3413364SGerrit Uitslag    protected function phraseMatchInComment($phrase, $cid, &$data, $parent = '') {
169910b5d61eSMichael Hamann        if (!isset($data['comments'][$cid])) return false; // comment was removed
1700*c3413364SGerrit Uitslag
170110b5d61eSMichael Hamann        $comment = $data['comments'][$cid];
170210b5d61eSMichael Hamann
170310b5d61eSMichael Hamann        if (!is_array($comment)) return false;             // corrupt datatype
170410b5d61eSMichael Hamann        if ($comment['parent'] != $parent) return false;   // reply to an other comment
170510b5d61eSMichael Hamann        if (!$comment['show']) return false;               // hidden comment
170610b5d61eSMichael Hamann
1707*c3413364SGerrit Uitslag        $text = PhpString::strtolower($comment['raw']);
170810b5d61eSMichael Hamann        if (strpos($text, $phrase) !== false) {
170910b5d61eSMichael Hamann            return true;
171010b5d61eSMichael Hamann        }
171110b5d61eSMichael Hamann
171210b5d61eSMichael Hamann        if (is_array($comment['replies'])) {             // and the replies
171310b5d61eSMichael Hamann            foreach ($comment['replies'] as $rid) {
1714*c3413364SGerrit Uitslag                if ($this->phraseMatchInComment($phrase, $rid, $data, $cid)) {
171510b5d61eSMichael Hamann                    return true;
171610b5d61eSMichael Hamann                }
171710b5d61eSMichael Hamann            }
171810b5d61eSMichael Hamann        }
171910b5d61eSMichael Hamann        return false;
172010b5d61eSMichael Hamann    }
172110b5d61eSMichael Hamann
1722a1ca9e44Swikidesign    /**
1723*c3413364SGerrit Uitslag     * Saves the current comment status and title from metadata into the .comments file
1724de7e6f00SGerrit Uitslag     *
1725de7e6f00SGerrit Uitslag     * @param Doku_Event $event
1726de7e6f00SGerrit Uitslag     * @param $param
1727c1530f74SMichael Hamann     */
1728de7e6f00SGerrit Uitslag    public function update_comment_status(Doku_Event $event, $param) {
1729c1530f74SMichael Hamann        global $ID;
1730c1530f74SMichael Hamann
1731c1530f74SMichael Hamann        $meta = $event->data['current'];
1732c1530f74SMichael Hamann        $file = metaFN($ID, '.comments');
1733f0bcde18SGerrit Uitslag        $status = ($this->isDiscussionEnabled() ? 1 : 0);
1734*c3413364SGerrit Uitslag        $title = null;
1735c1530f74SMichael Hamann        if (isset($meta['plugin_discussion'])) {
1736*c3413364SGerrit Uitslag            $status = $meta['plugin_discussion']['status']; // 0, 1 or 2
1737c1530f74SMichael Hamann            $title = $meta['plugin_discussion']['title'];
1738c1530f74SMichael Hamann        } else if ($status == 1) {
1739c1530f74SMichael Hamann            // Don't enable comments when automatic comments are on - this already happens automatically
1740c1530f74SMichael Hamann            // and if comments are turned off in the admin this only updates the .comments file
1741c1530f74SMichael Hamann            return;
1742c1530f74SMichael Hamann        }
1743c1530f74SMichael Hamann
1744c1530f74SMichael Hamann        if ($status || @file_exists($file)) {
1745*c3413364SGerrit Uitslag            $data = [];
1746c1530f74SMichael Hamann            if (@file_exists($file)) {
1747c1530f74SMichael Hamann                $data = unserialize(io_readFile($file, false));
1748c1530f74SMichael Hamann            }
1749c1530f74SMichael Hamann
1750c1530f74SMichael Hamann            if (!array_key_exists('title', $data) || $data['title'] !== $title || !isset($data['status']) || $data['status'] !== $status) {
1751c1530f74SMichael Hamann                $data['title']  = $title;
1752c1530f74SMichael Hamann                $data['status'] = $status;
1753*c3413364SGerrit Uitslag                if (!isset($data['number'])) {
1754c1530f74SMichael Hamann                    $data['number'] = 0;
1755*c3413364SGerrit Uitslag                }
1756c1530f74SMichael Hamann                io_saveFile($file, serialize($data));
1757c1530f74SMichael Hamann            }
1758c1530f74SMichael Hamann        }
1759c1530f74SMichael Hamann    }
1760c1530f74SMichael Hamann
1761c1530f74SMichael Hamann    /**
1762*c3413364SGerrit Uitslag     * Return words of a given comment and its replies, suitable to be added to the index
1763de7e6f00SGerrit Uitslag     *
1764*c3413364SGerrit Uitslag     * @param string $cid comment id
1765*c3413364SGerrit Uitslag     * @param array  $data array with all comments by reference
1766*c3413364SGerrit Uitslag     * @param string $parent cid of parent
1767de7e6f00SGerrit Uitslag     * @return string
1768a1ca9e44Swikidesign     */
1769*c3413364SGerrit Uitslag    protected function addCommentWords($cid, &$data, $parent = '') {
1770a1ca9e44Swikidesign
1771efbe59d0Swikidesign        if (!isset($data['comments'][$cid])) return ''; // comment was removed
1772*c3413364SGerrit Uitslag
1773a1ca9e44Swikidesign        $comment = $data['comments'][$cid];
1774a1ca9e44Swikidesign
1775efbe59d0Swikidesign        if (!is_array($comment)) return '';             // corrupt datatype
1776efbe59d0Swikidesign        if ($comment['parent'] != $parent) return '';   // reply to an other comment
1777efbe59d0Swikidesign        if (!$comment['show']) return '';               // hidden comment
1778a1ca9e44Swikidesign
1779efbe59d0Swikidesign        $text = $comment['raw'];                        // we only add the raw comment text
1780efbe59d0Swikidesign        if (is_array($comment['replies'])) {             // and the replies
1781efbe59d0Swikidesign            foreach ($comment['replies'] as $rid) {
1782*c3413364SGerrit Uitslag                $text .= $this->addCommentWords($rid, $data, $cid);
1783a1ca9e44Swikidesign            }
1784a1ca9e44Swikidesign        }
1785efbe59d0Swikidesign        return ' '.$text;
1786efbe59d0Swikidesign    }
1787a10b5c98SMichael Klier
1788a10b5c98SMichael Klier    /**
1789a10b5c98SMichael Klier     * Only allow http(s) URLs and append http:// to URLs if needed
1790de7e6f00SGerrit Uitslag     *
1791de7e6f00SGerrit Uitslag     * @param string $url
1792de7e6f00SGerrit Uitslag     * @return string
1793a10b5c98SMichael Klier     */
1794*c3413364SGerrit Uitslag    protected function checkURL($url) {
1795a10b5c98SMichael Klier        if(preg_match("#^http://|^https://#", $url)) {
1796a10b5c98SMichael Klier            return hsc($url);
1797a10b5c98SMichael Klier        } elseif(substr($url, 0, 4) == 'www.') {
1798*c3413364SGerrit Uitslag            return hsc('https://' . $url);
1799a10b5c98SMichael Klier        } else {
1800a10b5c98SMichael Klier            return '';
1801a10b5c98SMichael Klier        }
1802a10b5c98SMichael Klier    }
180331aab30eSGina Haeussge
1804de7e6f00SGerrit Uitslag    /**
1805de7e6f00SGerrit Uitslag     * Sort threads
1806de7e6f00SGerrit Uitslag     *
1807de7e6f00SGerrit Uitslag     * @param $a
1808de7e6f00SGerrit Uitslag     * @param $b
1809de7e6f00SGerrit Uitslag     * @return int
1810de7e6f00SGerrit Uitslag     */
1811*c3413364SGerrit Uitslag    function sortCallback($a, $b) {
18127e018cb6Slpaulsen93        if (is_array($a['date'])) {
18137e018cb6Slpaulsen93            // new format
181431aab30eSGina Haeussge            $createdA  = $a['date']['created'];
18157e018cb6Slpaulsen93        } else {
18167e018cb6Slpaulsen93            // old format
181731aab30eSGina Haeussge            $createdA  = $a['date'];
181831aab30eSGina Haeussge        }
181931aab30eSGina Haeussge
18207e018cb6Slpaulsen93        if (is_array($b['date'])) {
18217e018cb6Slpaulsen93            // new format
182231aab30eSGina Haeussge            $createdB  = $b['date']['created'];
18237e018cb6Slpaulsen93        } else {
18247e018cb6Slpaulsen93            // old format
182531aab30eSGina Haeussge            $createdB  = $b['date'];
182631aab30eSGina Haeussge        }
182731aab30eSGina Haeussge
18284cded5e1SGerrit Uitslag        if ($createdA == $createdB) {
182931aab30eSGina Haeussge            return 0;
18304cded5e1SGerrit Uitslag        } else {
183131aab30eSGina Haeussge            return ($createdA < $createdB) ? -1 : 1;
183231aab30eSGina Haeussge        }
18334cded5e1SGerrit Uitslag    }
183431aab30eSGina Haeussge
1835*c3413364SGerrit Uitslag}
1836*c3413364SGerrit Uitslag
1837*c3413364SGerrit Uitslag
1838