1da933f89SLORTET<?php 2da933f89SLORTETif (!defined('DOKU_INC')) die(); 3da933f89SLORTET 4da933f89SLORTETclass helper_plugin_pagesicon extends DokuWiki_Plugin 5da933f89SLORTET{ 6*74a9e763SLORTET private function getBundledDefaultImagePath(): string 7*74a9e763SLORTET { 8*74a9e763SLORTET return DOKU_INC . 'lib/plugins/pagesicon/images/default_image.png'; 9*74a9e763SLORTET } 10*74a9e763SLORTET 11*74a9e763SLORTET private function getBundledDefaultImageUrl(): string 12*74a9e763SLORTET { 13*74a9e763SLORTET $path = $this->getBundledDefaultImagePath(); 14*74a9e763SLORTET if (!@file_exists($path)) return ''; 15*74a9e763SLORTET 16*74a9e763SLORTET $base = rtrim((string)DOKU_BASE, '/'); 17*74a9e763SLORTET $url = $base . '/lib/plugins/pagesicon/images/default_image.png'; 18*74a9e763SLORTET $mtime = @filemtime($path); 19*74a9e763SLORTET return $this->appendVersionToUrl($url, $mtime ? (int)$mtime : 0); 20*74a9e763SLORTET } 21*74a9e763SLORTET 22*74a9e763SLORTET private function getConfiguredDefaultImageMediaID() 23*74a9e763SLORTET { 24*74a9e763SLORTET $mediaID = cleanID((string)$this->getConf('default_image')); 25*74a9e763SLORTET if ($mediaID === '') return false; 26*74a9e763SLORTET if (!@file_exists(mediaFN($mediaID))) return false; 27*74a9e763SLORTET return $mediaID; 28*74a9e763SLORTET } 29*74a9e763SLORTET 30da933f89SLORTET private function getMediaMTime(string $mediaID): int 31da933f89SLORTET { 32da933f89SLORTET $mediaID = cleanID($mediaID); 33da933f89SLORTET if ($mediaID === '') return 0; 34da933f89SLORTET $file = mediaFN($mediaID); 35da933f89SLORTET if (!@file_exists($file)) return 0; 36da933f89SLORTET $mtime = @filemtime($file); 37da933f89SLORTET return $mtime ? (int)$mtime : 0; 38da933f89SLORTET } 39da933f89SLORTET 40da933f89SLORTET private function appendVersionToUrl(string $url, int $mtime): string 41da933f89SLORTET { 42da933f89SLORTET if ($url === '' || $mtime <= 0) return $url; 43da933f89SLORTET $sep = strpos($url, '?') === false ? '?' : '&'; 44da933f89SLORTET return $url . $sep . 'pi_ts=' . $mtime; 45da933f89SLORTET } 46da933f89SLORTET 47da933f89SLORTET public function notifyIconUpdated(string $targetPage, string $action = 'update', string $mediaID = ''): void 48da933f89SLORTET { 49da933f89SLORTET global $conf; 50da933f89SLORTET 51da933f89SLORTET @io_saveFile($conf['cachedir'] . '/purgefile', time()); 52da933f89SLORTET 53da933f89SLORTET $data = [ 54da933f89SLORTET 'target_page' => cleanID($targetPage), 55da933f89SLORTET 'action' => $action, 56da933f89SLORTET 'media_id' => cleanID($mediaID), 57da933f89SLORTET ]; 58da933f89SLORTET \dokuwiki\Extension\Event::createAndTrigger('PLUGIN_PAGESICON_UPDATED', $data); 59da933f89SLORTET } 60da933f89SLORTET 61da933f89SLORTET private function buildConfiguredCandidatesFromRaw(string $raw, string $namespace, string $pageID): array 62da933f89SLORTET { 63da933f89SLORTET $configured = []; 64da933f89SLORTET $entries = array_filter(array_map('trim', explode(';', $raw))); 65da933f89SLORTET 66da933f89SLORTET foreach ($entries as $entry) { 67da933f89SLORTET $name = str_replace('~pagename~', $pageID, $entry); 68da933f89SLORTET if ($name === '') continue; 69da933f89SLORTET 70da933f89SLORTET if (strpos($name, ':') === false && $namespace !== '') { 71da933f89SLORTET $configured[] = $namespace . ':' . $name; 72da933f89SLORTET } else { 73da933f89SLORTET $configured[] = ltrim($name, ':'); 74da933f89SLORTET } 75da933f89SLORTET } 76da933f89SLORTET 77da933f89SLORTET return array_values(array_unique($configured)); 78da933f89SLORTET } 79da933f89SLORTET 80da933f89SLORTET private function buildConfiguredCandidates(string $namespace, string $pageID, string $sizeMode): array 81da933f89SLORTET { 82da933f89SLORTET $bigRaw = trim((string)$this->getConf('icon_name')); 83da933f89SLORTET $smallRaw = trim((string)$this->getConf('icon_thumbnail_name')); 84da933f89SLORTET 85da933f89SLORTET $big = $this->buildConfiguredCandidatesFromRaw($bigRaw, $namespace, $pageID); 86da933f89SLORTET $small = $this->buildConfiguredCandidatesFromRaw($smallRaw, $namespace, $pageID); 87da933f89SLORTET 88da933f89SLORTET if ($sizeMode === 'big') return $big; 89da933f89SLORTET if ($sizeMode === 'small') return $small; 90da933f89SLORTET if ($sizeMode === 'smallorbig') return array_values(array_unique(array_merge($small, $big))); 91da933f89SLORTET 92da933f89SLORTET // Default: bigorsmall 93da933f89SLORTET return array_values(array_unique(array_merge($big, $small))); 94da933f89SLORTET } 95da933f89SLORTET 96da933f89SLORTET private function normalizeSizeMode(string $size): string 97da933f89SLORTET { 98da933f89SLORTET $size = strtolower(trim($size)); 99da933f89SLORTET $allowed = ['big', 'small', 'bigorsmall', 'smallorbig']; 100da933f89SLORTET if (in_array($size, $allowed, true)) return $size; 101da933f89SLORTET return 'bigorsmall'; 102da933f89SLORTET } 103da933f89SLORTET 104da933f89SLORTET private function getExtensions(): array 105da933f89SLORTET { 106da933f89SLORTET $raw = trim((string)$this->getConf('extensions')); 107da933f89SLORTET if ($raw === '') return ['svg', 'png', 'jpg', 'jpeg']; 108da933f89SLORTET 109da933f89SLORTET $extensions = array_values(array_unique(array_filter(array_map(function ($ext) { 110da933f89SLORTET return strtolower(ltrim(trim((string)$ext), '.')); 111da933f89SLORTET }, explode(';', $raw))))); 112da933f89SLORTET 113da933f89SLORTET return $extensions ?: ['svg', 'png', 'jpg', 'jpeg']; 114da933f89SLORTET } 115da933f89SLORTET 116da933f89SLORTET private function hasKnownExtension(string $name, array $extensions): bool 117da933f89SLORTET { 118da933f89SLORTET $fileExt = strtolower((string)pathinfo($name, PATHINFO_EXTENSION)); 119da933f89SLORTET return $fileExt !== '' && in_array($fileExt, $extensions, true); 120da933f89SLORTET } 121da933f89SLORTET 122*74a9e763SLORTET public function getPageIconId( 123*74a9e763SLORTET string $namespace, 124*74a9e763SLORTET string $pageID, 125*74a9e763SLORTET string $size = 'bigorsmall' 126*74a9e763SLORTET ) 127da933f89SLORTET { 128da933f89SLORTET $sizeMode = $this->normalizeSizeMode($size); 129da933f89SLORTET $extensions = $this->getExtensions(); 130da933f89SLORTET $namespace = $namespace ?: ''; 131da933f89SLORTET $pageBase = $namespace ? ($namespace . ':' . $pageID) : $pageID; 132da933f89SLORTET $nsBase = $namespace ? ($namespace . ':') : ''; 133da933f89SLORTET 134da933f89SLORTET $genericBig = [ 135da933f89SLORTET $pageBase, 136da933f89SLORTET $pageBase . ':logo', 137da933f89SLORTET $nsBase . 'logo', 138da933f89SLORTET ]; 139da933f89SLORTET $genericSmall = [ 140da933f89SLORTET $pageBase . ':thumbnail', 141da933f89SLORTET $nsBase . 'thumbnail', 142da933f89SLORTET ]; 143da933f89SLORTET 144da933f89SLORTET if ($sizeMode === 'big') { 145da933f89SLORTET $generic = $genericBig; 146da933f89SLORTET } elseif ($sizeMode === 'small') { 147da933f89SLORTET $generic = $genericSmall; 148da933f89SLORTET } elseif ($sizeMode === 'smallorbig') { 149da933f89SLORTET $generic = array_merge($genericSmall, $genericBig); 150da933f89SLORTET } else { 151da933f89SLORTET $generic = array_merge($genericBig, $genericSmall); 152da933f89SLORTET } 153da933f89SLORTET 154da933f89SLORTET $imageNames = array_merge($this->buildConfiguredCandidates($namespace, $pageID, $sizeMode), $generic); 155da933f89SLORTET 156da933f89SLORTET foreach ($imageNames as $name) { 157da933f89SLORTET if ($this->hasKnownExtension($name, $extensions)) { 158da933f89SLORTET if (@file_exists(mediaFN($name))) return $name; 159da933f89SLORTET continue; 160da933f89SLORTET } 161da933f89SLORTET 162da933f89SLORTET foreach ($extensions as $ext) { 163da933f89SLORTET $path = $name . '.' . $ext; 164da933f89SLORTET if (@file_exists(mediaFN($path))) return $path; 165da933f89SLORTET } 166da933f89SLORTET } 167da933f89SLORTET 168da933f89SLORTET return false; 169da933f89SLORTET } 170da933f89SLORTET 171*74a9e763SLORTET // Legacy alias kept for backward compatibility. 172*74a9e763SLORTET public function getPageImage( 173*74a9e763SLORTET string $namespace, 174*74a9e763SLORTET string $pageID, 175*74a9e763SLORTET string $size = 'bigorsmall', 176*74a9e763SLORTET bool $withDefault = false 177*74a9e763SLORTET ) { 178*74a9e763SLORTET return $this->getPageIconId($namespace, $pageID, $size); 179*74a9e763SLORTET } 180*74a9e763SLORTET 181da933f89SLORTET public function getUploadIconPage(string $targetPage = '') 182da933f89SLORTET { 183da933f89SLORTET global $ID; 184da933f89SLORTET 185da933f89SLORTET $targetPage = cleanID($targetPage); 186da933f89SLORTET if ($targetPage === '') { 187da933f89SLORTET $targetPage = cleanID(getNS((string)$ID)); 188da933f89SLORTET } 189da933f89SLORTET if ($targetPage === '') { 190da933f89SLORTET $targetPage = cleanID((string)$ID); 191da933f89SLORTET } 192da933f89SLORTET if ($targetPage === '') return null; 193da933f89SLORTET 194da933f89SLORTET if (auth_quickaclcheck($targetPage) < AUTH_UPLOAD) { 195da933f89SLORTET return null; 196da933f89SLORTET } 197da933f89SLORTET 198da933f89SLORTET return wl($targetPage, ['do' => 'pagesicon']); 199da933f89SLORTET } 200da933f89SLORTET 201*74a9e763SLORTET public function getMediaIconId(string $mediaID, string $size = 'bigorsmall') 202da933f89SLORTET { 203da933f89SLORTET $mediaID = cleanID($mediaID); 204da933f89SLORTET if ($mediaID === '') return false; 205da933f89SLORTET 206da933f89SLORTET $namespace = getNS($mediaID); 207da933f89SLORTET $filename = noNS($mediaID); 208da933f89SLORTET $base = (string)pathinfo($filename, PATHINFO_FILENAME); 209da933f89SLORTET $pageID = cleanID($base); 210da933f89SLORTET if ($pageID === '') return false; 211da933f89SLORTET 212*74a9e763SLORTET return $this->getPageIconId($namespace, $pageID, $size); 213da933f89SLORTET } 214da933f89SLORTET 215*74a9e763SLORTET // Legacy alias kept for backward compatibility. 216*74a9e763SLORTET public function getMediaImage(string $mediaID, string $size = 'bigorsmall', bool $withDefault = false) 217*74a9e763SLORTET { 218*74a9e763SLORTET return $this->getMediaIconId($mediaID, $size); 219*74a9e763SLORTET } 220*74a9e763SLORTET 221*74a9e763SLORTET public function getDefaultIconUrl(array $params = ['width' => 55], ?int &$mtime = null) 222*74a9e763SLORTET { 223*74a9e763SLORTET $mediaID = $this->getConfiguredDefaultImageMediaID(); 224*74a9e763SLORTET if ($mediaID) { 225*74a9e763SLORTET $mtime = $this->getMediaMTime((string)$mediaID); 226*74a9e763SLORTET $url = (string)ml((string)$mediaID, $params); 227*74a9e763SLORTET if ($url === '') return false; 228*74a9e763SLORTET return $this->appendVersionToUrl($url, $mtime); 229*74a9e763SLORTET } 230*74a9e763SLORTET 231*74a9e763SLORTET $mtime = 0; 232*74a9e763SLORTET $bundled = $this->getBundledDefaultImageUrl(); 233*74a9e763SLORTET if ($bundled !== '') return $bundled; 234*74a9e763SLORTET 235*74a9e763SLORTET return false; 236*74a9e763SLORTET } 237*74a9e763SLORTET 238*74a9e763SLORTET // Legacy alias kept for backward compatibility. 239*74a9e763SLORTET public function getDefaultImageIcon(array $params = ['width' => 55], ?int &$mtime = null) 240*74a9e763SLORTET { 241*74a9e763SLORTET return $this->getDefaultIconUrl($params, $mtime); 242*74a9e763SLORTET } 243*74a9e763SLORTET 244*74a9e763SLORTET public function getPageIconUrl( 245da933f89SLORTET string $namespace, 246da933f89SLORTET string $pageID, 247da933f89SLORTET string $size = 'bigorsmall', 248da933f89SLORTET array $params = ['width' => 55], 249*74a9e763SLORTET ?int &$mtime = null, 250*74a9e763SLORTET bool $withDefault = false 251da933f89SLORTET ) { 252*74a9e763SLORTET $mediaID = $this->getPageIconId($namespace, $pageID, $size); 253da933f89SLORTET if (!$mediaID) { 254*74a9e763SLORTET if ($withDefault) { 255*74a9e763SLORTET return $this->getDefaultIconUrl($params, $mtime); 256*74a9e763SLORTET } 257da933f89SLORTET $mtime = 0; 258da933f89SLORTET return false; 259da933f89SLORTET } 260da933f89SLORTET 261da933f89SLORTET $mtime = $this->getMediaMTime((string)$mediaID); 262da933f89SLORTET $url = (string)ml((string)$mediaID, $params); 263da933f89SLORTET if ($url === '') return false; 264da933f89SLORTET return $this->appendVersionToUrl($url, $mtime); 265da933f89SLORTET } 266da933f89SLORTET 267*74a9e763SLORTET // Legacy alias kept for backward compatibility. 268*74a9e763SLORTET public function getImageIcon( 269*74a9e763SLORTET string $namespace, 270*74a9e763SLORTET string $pageID, 271*74a9e763SLORTET string $size = 'bigorsmall', 272*74a9e763SLORTET array $params = ['width' => 55], 273*74a9e763SLORTET ?int &$mtime = null, 274*74a9e763SLORTET bool $withDefault = false 275*74a9e763SLORTET ) { 276*74a9e763SLORTET return $this->getPageIconUrl($namespace, $pageID, $size, $params, $mtime, $withDefault); 277*74a9e763SLORTET } 278*74a9e763SLORTET 279*74a9e763SLORTET public function getMediaIconUrl( 280da933f89SLORTET string $mediaID, 281da933f89SLORTET string $size = 'bigorsmall', 282da933f89SLORTET array $params = ['width' => 55], 283*74a9e763SLORTET ?int &$mtime = null, 284*74a9e763SLORTET bool $withDefault = false 285da933f89SLORTET ) { 286*74a9e763SLORTET $iconMediaID = $this->getMediaIconId($mediaID, $size); 287da933f89SLORTET if (!$iconMediaID) { 288*74a9e763SLORTET if ($withDefault) { 289*74a9e763SLORTET return $this->getDefaultIconUrl($params, $mtime); 290*74a9e763SLORTET } 291da933f89SLORTET $mtime = 0; 292da933f89SLORTET return false; 293da933f89SLORTET } 294da933f89SLORTET 295da933f89SLORTET $mtime = $this->getMediaMTime((string)$iconMediaID); 296da933f89SLORTET $url = (string)ml((string)$iconMediaID, $params); 297da933f89SLORTET if ($url === '') return false; 298da933f89SLORTET return $this->appendVersionToUrl($url, $mtime); 299da933f89SLORTET } 300da933f89SLORTET 301*74a9e763SLORTET // Legacy alias kept for backward compatibility. 302*74a9e763SLORTET public function getMediaIcon( 303*74a9e763SLORTET string $mediaID, 304*74a9e763SLORTET string $size = 'bigorsmall', 305*74a9e763SLORTET array $params = ['width' => 55], 306*74a9e763SLORTET ?int &$mtime = null, 307*74a9e763SLORTET bool $withDefault = false 308*74a9e763SLORTET ) { 309*74a9e763SLORTET return $this->getMediaIconUrl($mediaID, $size, $params, $mtime, $withDefault); 310*74a9e763SLORTET } 311*74a9e763SLORTET 312da933f89SLORTET public function getUploadMediaIconPage(string $mediaID = '') 313da933f89SLORTET { 314da933f89SLORTET $mediaID = cleanID($mediaID); 315da933f89SLORTET if ($mediaID === '') return null; 316da933f89SLORTET 317da933f89SLORTET $namespace = getNS($mediaID); 318da933f89SLORTET $filename = noNS($mediaID); 319da933f89SLORTET $base = (string)pathinfo($filename, PATHINFO_FILENAME); 320da933f89SLORTET $targetPage = cleanID($namespace !== '' ? ($namespace . ':' . $base) : $base); 321da933f89SLORTET if ($targetPage === '') return null; 322da933f89SLORTET 323da933f89SLORTET return $this->getUploadIconPage($targetPage); 324da933f89SLORTET } 325da933f89SLORTET} 326