xref: /plugin/pagesicon/helper.php (revision da933f899c3fc9c630c3a0106c319fb606ed9385)
1*da933f89SLORTET<?php
2*da933f89SLORTETif (!defined('DOKU_INC')) die();
3*da933f89SLORTET
4*da933f89SLORTETclass helper_plugin_pagesicon extends DokuWiki_Plugin
5*da933f89SLORTET{
6*da933f89SLORTET    private function getMediaMTime(string $mediaID): int
7*da933f89SLORTET    {
8*da933f89SLORTET        $mediaID = cleanID($mediaID);
9*da933f89SLORTET        if ($mediaID === '') return 0;
10*da933f89SLORTET        $file = mediaFN($mediaID);
11*da933f89SLORTET        if (!@file_exists($file)) return 0;
12*da933f89SLORTET        $mtime = @filemtime($file);
13*da933f89SLORTET        return $mtime ? (int)$mtime : 0;
14*da933f89SLORTET    }
15*da933f89SLORTET
16*da933f89SLORTET    private function appendVersionToUrl(string $url, int $mtime): string
17*da933f89SLORTET    {
18*da933f89SLORTET        if ($url === '' || $mtime <= 0) return $url;
19*da933f89SLORTET        $sep = strpos($url, '?') === false ? '?' : '&';
20*da933f89SLORTET        return $url . $sep . 'pi_ts=' . $mtime;
21*da933f89SLORTET    }
22*da933f89SLORTET
23*da933f89SLORTET    public function notifyIconUpdated(string $targetPage, string $action = 'update', string $mediaID = ''): void
24*da933f89SLORTET    {
25*da933f89SLORTET        global $conf;
26*da933f89SLORTET
27*da933f89SLORTET        @io_saveFile($conf['cachedir'] . '/purgefile', time());
28*da933f89SLORTET
29*da933f89SLORTET        $data = [
30*da933f89SLORTET            'target_page' => cleanID($targetPage),
31*da933f89SLORTET            'action' => $action,
32*da933f89SLORTET            'media_id' => cleanID($mediaID),
33*da933f89SLORTET        ];
34*da933f89SLORTET        \dokuwiki\Extension\Event::createAndTrigger('PLUGIN_PAGESICON_UPDATED', $data);
35*da933f89SLORTET    }
36*da933f89SLORTET
37*da933f89SLORTET    private function buildConfiguredCandidatesFromRaw(string $raw, string $namespace, string $pageID): array
38*da933f89SLORTET    {
39*da933f89SLORTET        $configured = [];
40*da933f89SLORTET        $entries = array_filter(array_map('trim', explode(';', $raw)));
41*da933f89SLORTET
42*da933f89SLORTET        foreach ($entries as $entry) {
43*da933f89SLORTET            $name = str_replace('~pagename~', $pageID, $entry);
44*da933f89SLORTET            if ($name === '') continue;
45*da933f89SLORTET
46*da933f89SLORTET            if (strpos($name, ':') === false && $namespace !== '') {
47*da933f89SLORTET                $configured[] = $namespace . ':' . $name;
48*da933f89SLORTET            } else {
49*da933f89SLORTET                $configured[] = ltrim($name, ':');
50*da933f89SLORTET            }
51*da933f89SLORTET        }
52*da933f89SLORTET
53*da933f89SLORTET        return array_values(array_unique($configured));
54*da933f89SLORTET    }
55*da933f89SLORTET
56*da933f89SLORTET    private function buildConfiguredCandidates(string $namespace, string $pageID, string $sizeMode): array
57*da933f89SLORTET    {
58*da933f89SLORTET        $bigRaw = trim((string)$this->getConf('icon_name'));
59*da933f89SLORTET        $smallRaw = trim((string)$this->getConf('icon_thumbnail_name'));
60*da933f89SLORTET
61*da933f89SLORTET        $big = $this->buildConfiguredCandidatesFromRaw($bigRaw, $namespace, $pageID);
62*da933f89SLORTET        $small = $this->buildConfiguredCandidatesFromRaw($smallRaw, $namespace, $pageID);
63*da933f89SLORTET
64*da933f89SLORTET        if ($sizeMode === 'big') return $big;
65*da933f89SLORTET        if ($sizeMode === 'small') return $small;
66*da933f89SLORTET        if ($sizeMode === 'smallorbig') return array_values(array_unique(array_merge($small, $big)));
67*da933f89SLORTET
68*da933f89SLORTET        // Default: bigorsmall
69*da933f89SLORTET        return array_values(array_unique(array_merge($big, $small)));
70*da933f89SLORTET    }
71*da933f89SLORTET
72*da933f89SLORTET    private function normalizeSizeMode(string $size): string
73*da933f89SLORTET    {
74*da933f89SLORTET        $size = strtolower(trim($size));
75*da933f89SLORTET        $allowed = ['big', 'small', 'bigorsmall', 'smallorbig'];
76*da933f89SLORTET        if (in_array($size, $allowed, true)) return $size;
77*da933f89SLORTET        return 'bigorsmall';
78*da933f89SLORTET    }
79*da933f89SLORTET
80*da933f89SLORTET    private function getExtensions(): array
81*da933f89SLORTET    {
82*da933f89SLORTET        $raw = trim((string)$this->getConf('extensions'));
83*da933f89SLORTET        if ($raw === '') return ['svg', 'png', 'jpg', 'jpeg'];
84*da933f89SLORTET
85*da933f89SLORTET        $extensions = array_values(array_unique(array_filter(array_map(function ($ext) {
86*da933f89SLORTET            return strtolower(ltrim(trim((string)$ext), '.'));
87*da933f89SLORTET        }, explode(';', $raw)))));
88*da933f89SLORTET
89*da933f89SLORTET        return $extensions ?: ['svg', 'png', 'jpg', 'jpeg'];
90*da933f89SLORTET    }
91*da933f89SLORTET
92*da933f89SLORTET    private function hasKnownExtension(string $name, array $extensions): bool
93*da933f89SLORTET    {
94*da933f89SLORTET        $fileExt = strtolower((string)pathinfo($name, PATHINFO_EXTENSION));
95*da933f89SLORTET        return $fileExt !== '' && in_array($fileExt, $extensions, true);
96*da933f89SLORTET    }
97*da933f89SLORTET
98*da933f89SLORTET    public function getPageImage(string $namespace, string $pageID, string $size = 'bigorsmall')
99*da933f89SLORTET    {
100*da933f89SLORTET        $sizeMode = $this->normalizeSizeMode($size);
101*da933f89SLORTET        $extensions = $this->getExtensions();
102*da933f89SLORTET        $namespace = $namespace ?: '';
103*da933f89SLORTET        $pageBase = $namespace ? ($namespace . ':' . $pageID) : $pageID;
104*da933f89SLORTET        $nsBase = $namespace ? ($namespace . ':') : '';
105*da933f89SLORTET
106*da933f89SLORTET        $genericBig = [
107*da933f89SLORTET            $pageBase,
108*da933f89SLORTET            $pageBase . ':logo',
109*da933f89SLORTET            $nsBase . 'logo',
110*da933f89SLORTET        ];
111*da933f89SLORTET        $genericSmall = [
112*da933f89SLORTET            $pageBase . ':thumbnail',
113*da933f89SLORTET            $nsBase . 'thumbnail',
114*da933f89SLORTET        ];
115*da933f89SLORTET
116*da933f89SLORTET        if ($sizeMode === 'big') {
117*da933f89SLORTET            $generic = $genericBig;
118*da933f89SLORTET        } elseif ($sizeMode === 'small') {
119*da933f89SLORTET            $generic = $genericSmall;
120*da933f89SLORTET        } elseif ($sizeMode === 'smallorbig') {
121*da933f89SLORTET            $generic = array_merge($genericSmall, $genericBig);
122*da933f89SLORTET        } else {
123*da933f89SLORTET            $generic = array_merge($genericBig, $genericSmall);
124*da933f89SLORTET        }
125*da933f89SLORTET
126*da933f89SLORTET        $imageNames = array_merge($this->buildConfiguredCandidates($namespace, $pageID, $sizeMode), $generic);
127*da933f89SLORTET
128*da933f89SLORTET        foreach ($imageNames as $name) {
129*da933f89SLORTET            if ($this->hasKnownExtension($name, $extensions)) {
130*da933f89SLORTET                if (@file_exists(mediaFN($name))) return $name;
131*da933f89SLORTET                continue;
132*da933f89SLORTET            }
133*da933f89SLORTET
134*da933f89SLORTET            foreach ($extensions as $ext) {
135*da933f89SLORTET                $path = $name . '.' . $ext;
136*da933f89SLORTET                if (@file_exists(mediaFN($path))) return $path;
137*da933f89SLORTET            }
138*da933f89SLORTET        }
139*da933f89SLORTET
140*da933f89SLORTET        return false;
141*da933f89SLORTET    }
142*da933f89SLORTET
143*da933f89SLORTET    public function getUploadIconPage(string $targetPage = '')
144*da933f89SLORTET    {
145*da933f89SLORTET        global $ID;
146*da933f89SLORTET
147*da933f89SLORTET        $targetPage = cleanID($targetPage);
148*da933f89SLORTET        if ($targetPage === '') {
149*da933f89SLORTET            $targetPage = cleanID(getNS((string)$ID));
150*da933f89SLORTET        }
151*da933f89SLORTET        if ($targetPage === '') {
152*da933f89SLORTET            $targetPage = cleanID((string)$ID);
153*da933f89SLORTET        }
154*da933f89SLORTET        if ($targetPage === '') return null;
155*da933f89SLORTET
156*da933f89SLORTET        if (auth_quickaclcheck($targetPage) < AUTH_UPLOAD) {
157*da933f89SLORTET            return null;
158*da933f89SLORTET        }
159*da933f89SLORTET
160*da933f89SLORTET        return wl($targetPage, ['do' => 'pagesicon']);
161*da933f89SLORTET    }
162*da933f89SLORTET
163*da933f89SLORTET    public function getMediaImage(string $mediaID, string $size = 'bigorsmall')
164*da933f89SLORTET    {
165*da933f89SLORTET        $mediaID = cleanID($mediaID);
166*da933f89SLORTET        if ($mediaID === '') return false;
167*da933f89SLORTET
168*da933f89SLORTET        $namespace = getNS($mediaID);
169*da933f89SLORTET        $filename = noNS($mediaID);
170*da933f89SLORTET        $base = (string)pathinfo($filename, PATHINFO_FILENAME);
171*da933f89SLORTET        $pageID = cleanID($base);
172*da933f89SLORTET        if ($pageID === '') return false;
173*da933f89SLORTET
174*da933f89SLORTET        return $this->getPageImage($namespace, $pageID, $size);
175*da933f89SLORTET    }
176*da933f89SLORTET
177*da933f89SLORTET    public function getImageIcon(
178*da933f89SLORTET        string $namespace,
179*da933f89SLORTET        string $pageID,
180*da933f89SLORTET        string $size = 'bigorsmall',
181*da933f89SLORTET        array $params = ['width' => 55],
182*da933f89SLORTET        ?int &$mtime = null
183*da933f89SLORTET    ) {
184*da933f89SLORTET        $mediaID = $this->getPageImage($namespace, $pageID, $size);
185*da933f89SLORTET        if (!$mediaID) {
186*da933f89SLORTET            $mtime = 0;
187*da933f89SLORTET            return false;
188*da933f89SLORTET        }
189*da933f89SLORTET
190*da933f89SLORTET        $mtime = $this->getMediaMTime((string)$mediaID);
191*da933f89SLORTET        $url = (string)ml((string)$mediaID, $params);
192*da933f89SLORTET        if ($url === '') return false;
193*da933f89SLORTET        return $this->appendVersionToUrl($url, $mtime);
194*da933f89SLORTET    }
195*da933f89SLORTET
196*da933f89SLORTET    public function getMediaIcon(
197*da933f89SLORTET        string $mediaID,
198*da933f89SLORTET        string $size = 'bigorsmall',
199*da933f89SLORTET        array $params = ['width' => 55],
200*da933f89SLORTET        ?int &$mtime = null
201*da933f89SLORTET    ) {
202*da933f89SLORTET        $iconMediaID = $this->getMediaImage($mediaID, $size);
203*da933f89SLORTET        if (!$iconMediaID) {
204*da933f89SLORTET            $mtime = 0;
205*da933f89SLORTET            return false;
206*da933f89SLORTET        }
207*da933f89SLORTET
208*da933f89SLORTET        $mtime = $this->getMediaMTime((string)$iconMediaID);
209*da933f89SLORTET        $url = (string)ml((string)$iconMediaID, $params);
210*da933f89SLORTET        if ($url === '') return false;
211*da933f89SLORTET        return $this->appendVersionToUrl($url, $mtime);
212*da933f89SLORTET    }
213*da933f89SLORTET
214*da933f89SLORTET    public function getUploadMediaIconPage(string $mediaID = '')
215*da933f89SLORTET    {
216*da933f89SLORTET        $mediaID = cleanID($mediaID);
217*da933f89SLORTET        if ($mediaID === '') return null;
218*da933f89SLORTET
219*da933f89SLORTET        $namespace = getNS($mediaID);
220*da933f89SLORTET        $filename = noNS($mediaID);
221*da933f89SLORTET        $base = (string)pathinfo($filename, PATHINFO_FILENAME);
222*da933f89SLORTET        $targetPage = cleanID($namespace !== '' ? ($namespace . ':' . $base) : $base);
223*da933f89SLORTET        if ($targetPage === '') return null;
224*da933f89SLORTET
225*da933f89SLORTET        return $this->getUploadIconPage($targetPage);
226*da933f89SLORTET    }
227*da933f89SLORTET}
228