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