1<?php 2 3/** 4 * The main glossary class. 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public License, 7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can 8 * obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * @package phpMyFAQ 11 * @author Thorsten Rinne <thorsten@phpmyfaq.de> 12 * @copyright 2005-2020 phpMyFAQ Team 13 * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 14 * @link https://www.phpmyfaq.de 15 * @since 2005-09-15 16 */ 17 18namespace phpMyFAQ; 19 20/** 21 * Class Glossary 22 * 23 * @package phpMyFAQ 24 */ 25class Glossary 26{ 27 /** 28 * @var Configuration 29 */ 30 private $config; 31 32 /** 33 * Item. 34 * 35 * @var array 36 */ 37 private $item = []; 38 39 /** 40 * Definition of an item. 41 * 42 * @var string 43 */ 44 private $definition = ''; 45 46 /** 47 * Constructor. 48 * 49 * @param Configuration $config 50 */ 51 public function __construct(Configuration $config) 52 { 53 $this->config = $config; 54 } 55 56 /** 57 * Fill the passed string with the current Glossary items. 58 * 59 * @param string $content Content 60 * 61 * @return string 62 */ 63 public function insertItemsIntoContent($content = '') 64 { 65 if ('' == $content) { 66 return ''; 67 } 68 69 $attributes = [ 70 'href', 71 'src', 72 'title', 73 'alt', 74 'class', 75 'style', 76 'id', 77 'name', 78 'face', 79 'size', 80 'dir', 81 'rel', 82 'rev', 83 'onmouseenter', 84 'onmouseleave', 85 'onafterprint', 86 'onbeforeprint', 87 'onbeforeunload', 88 'onhashchange', 89 'onmessage', 90 'onoffline', 91 'ononline', 92 'onpopstate', 93 'onpagehide', 94 'onpageshow', 95 'onresize', 96 'onunload', 97 'ondevicemotion', 98 'ondeviceorientation', 99 'onabort', 100 'onblur', 101 'oncanplay', 102 'oncanplaythrough', 103 'onchange', 104 'onclick', 105 'oncontextmenu', 106 'ondblclick', 107 'ondrag', 108 'ondragend', 109 'ondragenter', 110 'ondragleave', 111 'ondragover', 112 'ondragstart', 113 'ondrop', 114 'ondurationchange', 115 'onemptied', 116 'onended', 117 'onerror', 118 'onfocus', 119 'oninput', 120 'oninvalid', 121 'onkeydown', 122 'onkeypress', 123 'onkeyup', 124 'onload', 125 'onloadeddata', 126 'onloadedmetadata', 127 'onloadstart', 128 'onmousedown', 129 'onmousemove', 130 'onmouseout', 131 'onmouseover', 132 'onmouseup', 133 'onpause', 134 'onplay', 135 'onplaying', 136 'onprogress', 137 'onratechange', 138 'onreset', 139 'onscroll', 140 'onseeked', 141 'onseeking', 142 'onselect', 143 'onshow', 144 'onstalled', 145 'onsubmit', 146 'onsuspend', 147 'ontimeupdate', 148 'onvolumechange', 149 'onwaiting', 150 'oncopy', 151 'oncut', 152 'onpaste', 153 'onbeforescriptexecute', 154 'onafterscriptexecute', 155 ]; 156 157 foreach ($this->getAllGlossaryItems() as $item) { 158 $this->definition = $item['definition']; 159 $item['item'] = preg_quote($item['item'], '/'); 160 $content = Strings::preg_replace_callback( 161 '/' 162 // a. the glossary item could be an attribute name 163 . '(' . $item['item'] . '="[^"]*")|' 164 // b. the glossary item could be inside an attribute value 165 . '((' . implode('|', $attributes) . ')="[^"]*' . $item['item'] . '[^"]*")|' 166 // c. the glossary item could be everywhere as a distinct word 167 . '(\W+)(' . $item['item'] . ')(\W+)|' 168 // d. the glossary item could be at the beginning of the string as a distinct word 169 . '^(' . $item['item'] . ')(\W+)|' 170 // e. the glossary item could be at the end of the string as a distinct word 171 . '(\W+)(' . $item['item'] . ')$' 172 . '/mis', 173 [$this, 'setTooltip'], 174 $content, 175 1 176 ); 177 } 178 179 return $content; 180 } 181 182 /** 183 * Gets all items and definitions from the database. 184 * 185 * @return array 186 */ 187 public function getAllGlossaryItems() 188 { 189 $items = []; 190 191 $query = sprintf( 192 " 193 SELECT 194 id, item, definition 195 FROM 196 %sfaqglossary 197 WHERE 198 lang = '%s' 199 ORDER BY item ASC", 200 Database::getTablePrefix(), 201 $this->config->getLanguage()->getLanguage() 202 ); 203 204 $result = $this->config->getDb()->query($query); 205 206 while ($row = $this->config->getDb()->fetchObject($result)) { 207 $items[] = [ 208 'id' => $row->id, 209 'item' => stripslashes($row->item), 210 'definition' => stripslashes($row->definition), 211 ]; 212 } 213 214 return $items; 215 } 216 217 /** 218 * Callback function for filtering HTML from URLs and images. 219 * 220 * @param array $matches Matches 221 * 222 * @return string 223 */ 224 public function setTooltip(array $matches) 225 { 226 $prefix = $postfix = ''; 227 228 if (count($matches) > 9) { 229 // if the word is at the end of the string 230 $prefix = $matches[9]; 231 $item = $matches[10]; 232 $postfix = ''; 233 } elseif (count($matches) > 7) { 234 // if the word is at the beginning of the string 235 $prefix = ''; 236 $item = $matches[7]; 237 $postfix = $matches[8]; 238 } elseif (count($matches) > 4) { 239 // if the word is else where in the string 240 $prefix = $matches[4]; 241 $item = $matches[5]; 242 $postfix = $matches[6]; 243 } 244 245 if (!empty($item)) { 246 return sprintf( 247 '%s<abbr data-toggle="tooltip" data-placement="bottom" title="%s">%s</abbr>%s', 248 $prefix, 249 $this->definition, 250 $item, 251 $postfix 252 ); 253 } 254 255 // Fallback: the original matched string 256 return $matches[0]; 257 } 258 259 /** 260 * Gets one item and definition from the database. 261 * 262 * @param int $id Glossary ID 263 * 264 * @return array 265 */ 266 public function getGlossaryItem($id) 267 { 268 $item = []; 269 270 $query = sprintf( 271 " 272 SELECT 273 id, item, definition 274 FROM 275 %sfaqglossary 276 WHERE 277 id = %d AND lang = '%s'", 278 Database::getTablePrefix(), 279 (int)$id, 280 $this->config->getLanguage()->getLanguage() 281 ); 282 283 $result = $this->config->getDb()->query($query); 284 285 while ($row = $this->config->getDb()->fetchObject($result)) { 286 $item = [ 287 'id' => $row->id, 288 'item' => stripslashes($row->item), 289 'definition' => stripslashes($row->definition), 290 ]; 291 } 292 293 return $item; 294 } 295 296 /** 297 * Inserts an item and definition into the database. 298 * 299 * @param string $item Item 300 * @param string $definition Definition 301 * 302 * @return bool 303 */ 304 public function addGlossaryItem($item, $definition) 305 { 306 $this->item = $this->config->getDb()->escape($item); 307 $this->definition = $this->config->getDb()->escape($definition); 308 309 $query = sprintf( 310 " 311 INSERT INTO 312 %sfaqglossary 313 (id, lang, item, definition) 314 VALUES 315 (%d, '%s', '%s', '%s')", 316 Database::getTablePrefix(), 317 $this->config->getDb()->nextId(Database::getTablePrefix() . 'faqglossary', 'id'), 318 $this->config->getLanguage()->getLanguage(), 319 Strings::htmlspecialchars($this->item), 320 Strings::htmlspecialchars($this->definition) 321 ); 322 323 if ($this->config->getDb()->query($query)) { 324 return true; 325 } 326 327 return false; 328 } 329 330 /** 331 * Updates an item and definition into the database. 332 * 333 * @param int $id Glossary ID 334 * @param string $item Item 335 * @param string $definition Definition 336 * 337 * @return bool 338 */ 339 public function updateGlossaryItem($id, $item, $definition) 340 { 341 $this->item = $this->config->getDb()->escape($item); 342 $this->definition = $this->config->getDb()->escape($definition); 343 344 $query = sprintf( 345 " 346 UPDATE 347 %sfaqglossary 348 SET 349 item = '%s', 350 definition = '%s' 351 WHERE 352 id = %d AND lang = '%s'", 353 Database::getTablePrefix(), 354 Strings::htmlspecialchars($this->item), 355 Strings::htmlspecialchars($this->definition), 356 (int)$id, 357 $this->config->getLanguage()->getLanguage() 358 ); 359 360 if ($this->config->getDb()->query($query)) { 361 return true; 362 } 363 364 return false; 365 } 366 367 /** 368 * Deletes an item and definition into the database. 369 * 370 * @param int $id Glossary ID 371 * 372 * @return bool 373 */ 374 public function deleteGlossaryItem($id) 375 { 376 $query = sprintf( 377 " 378 DELETE FROM 379 %sfaqglossary 380 WHERE 381 id = %d AND lang = '%s'", 382 Database::getTablePrefix(), 383 (int)$id, 384 $this->config->getLanguage()->getLanguage() 385 ); 386 387 if ($this->config->getDb()->query($query)) { 388 return true; 389 } 390 391 return false; 392 } 393} 394