1<?php
2
3use dokuwiki\Extension\SyntaxPlugin;
4
5/**
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Andreas Gohr <andi@splitbrain.org>
8 */
9class syntax_plugin_aclinfo extends SyntaxPlugin
10{
11    /** @inheritdoc */
12    public function getType()
13    {
14        return 'substition';
15    }
16
17    /** @inheritdoc */
18    public function getPType()
19    {
20        return 'block';
21    }
22
23    /** @inheritdoc */
24    public function getSort()
25    {
26        return 155;
27    }
28
29    /** @inheritdoc */
30    public function connectTo($mode)
31    {
32        $this->Lexer->addSpecialPattern('~~ACLINFO!?[^~]*?~~', $mode, 'plugin_aclinfo');
33    }
34
35    /** @inheritdoc */
36    public function handle($match, $state, $pos, Doku_Handler $handler)
37    {
38        $match = substr($match, 10, -2);
39        return [$match];
40    }
41
42    /** @inheritdoc */
43    public function render($format, Doku_Renderer $R, $data)
44    {
45        global $INFO;
46        if ($format != 'xhtml') return false;
47
48        if (!$data[0]) {
49            $page = $INFO['id'];
50        } else {
51            $page = $data[0];
52        }
53
54        $perms = $this->aclCheck($page);
55        $R->doc .= '<div class="plugin_aclinfo">';
56        $R->listu_open();
57        foreach ($perms as $who => $p) {
58            $R->listitem_open(1);
59            $R->listcontent_open();
60            $R->cdata(sprintf($this->getLang('perm' . $p), urldecode($who)));
61            $R->listcontent_close();
62            $R->listitem_close();
63        }
64        $R->listu_close();
65        $R->doc .= '</div>';
66        return true;
67    }
68
69    /**
70     * Parse the ACL setup and return the permissions for the given page ID.
71     *
72     * @param string $id The page ID to check
73     * @return array
74     */
75    protected function aclCheck($id)
76    {
77        global $AUTH_ACL;
78
79        $id    = cleanID($id);
80        $ns    = getNS($id);
81        $perms = [];
82
83        //check exact match first
84        $matches = preg_grep('/^' . preg_quote($id, '/') . '\s+/', $AUTH_ACL);
85        $perms = array_merge($perms, $this->processAclMatches($matches));
86
87        //still here? do the namespace checks
88        if ($ns) {
89            $path = $ns . ':\*';
90        } else {
91            $path = '\*'; //root document
92        }
93
94        do {
95            $matches = preg_grep('/^' . $path . '\s+/', $AUTH_ACL);
96            $perms = array_merge($perms, $this->processAclMatches($matches));
97
98            //get next higher namespace
99            $ns   = getNS($ns);
100
101            if ($path != '\*') {
102                $path = $ns . ':\*';
103                if ($path == ':\*') $path = '\*';
104            } else {
105                //we did this already
106                //break here
107                break;
108            }
109        } while (1); //this should never loop endless
110
111        return $perms;
112    }
113
114    /**
115     * Process ACL matches and return parsed permissions.
116     *
117     * @param array $matches Array of ACL lines to process
118     * @return array Parsed permissions array
119     */
120    protected function processAclMatches(array $matches)
121    {
122        $perms = [];
123        foreach ($matches as $match) {
124            $match = preg_replace('/#.*$/', '', $match); //ignore comments
125            $acl   = preg_split('/\s+/', $match);
126            if ($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL!
127            if (!isset($perms[$acl[1]])) $perms[$acl[1]] = $acl[2];
128        }
129        return $perms;
130    }
131}
132