elkarte /
Elkarte
| 1 | <?php |
||||
| 2 | |||||
| 3 | /** |
||||
| 4 | * This file takes care of all administration of smileys. |
||||
| 5 | * |
||||
| 6 | * @package ElkArte Forum |
||||
| 7 | * @copyright ElkArte Forum contributors |
||||
| 8 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||||
| 9 | * |
||||
| 10 | * This file contains code covered by: |
||||
| 11 | * copyright: 2011 Simple Machines (http://www.simplemachines.org) |
||||
| 12 | * |
||||
| 13 | * @version 2.0 dev |
||||
| 14 | * |
||||
| 15 | */ |
||||
| 16 | |||||
| 17 | namespace ElkArte\AdminController; |
||||
| 18 | |||||
| 19 | use BBC\ParserWrapper; |
||||
| 20 | use ElkArte\AbstractController; |
||||
| 21 | use ElkArte\Action; |
||||
| 22 | use ElkArte\Cache\Cache; |
||||
| 23 | use ElkArte\Errors\Errors; |
||||
|
0 ignored issues
–
show
|
|||||
| 24 | use ElkArte\Exceptions\Exception; |
||||
| 25 | use ElkArte\Helper\FileFunctions; |
||||
| 26 | use ElkArte\Helper\Util; |
||||
| 27 | use ElkArte\Languages\Txt; |
||||
| 28 | use ElkArte\Packages\PackageChmod; |
||||
| 29 | use ElkArte\Packages\PackageParser; |
||||
| 30 | use ElkArte\SettingsForm\SettingsForm; |
||||
| 31 | |||||
| 32 | /** |
||||
| 33 | * This class is in charge with administration of smileys and message icons. |
||||
| 34 | * It handles actions from the Smileys pages in admin panel. |
||||
| 35 | */ |
||||
| 36 | class ManageSmileys extends AbstractController |
||||
| 37 | { |
||||
| 38 | /** @var array Contextual information about smiley sets. */ |
||||
| 39 | private array $_smiley_context = []; |
||||
| 40 | |||||
| 41 | /** @var string[] allowed extensions for smiles */ |
||||
| 42 | private array $_smiley_types = ['jpg', 'gif', 'jpeg', 'png', 'webp', 'svg']; |
||||
| 43 | |||||
| 44 | /** |
||||
| 45 | * This is the dispatcher of smileys administration. |
||||
| 46 | * |
||||
| 47 | * @uses ManageSmileys language |
||||
| 48 | * @uses ManageSmileys template |
||||
| 49 | * @see AbstractController::action_index() |
||||
| 50 | */ |
||||
| 51 | public function action_index() |
||||
| 52 | { |
||||
| 53 | global $context, $txt, $modSettings; |
||||
| 54 | |||||
| 55 | Txt::load('ManageSmileys'); |
||||
| 56 | theme()->getTemplates()->load('ManageSmileys'); |
||||
| 57 | |||||
| 58 | $subActions = [ |
||||
| 59 | 'addsmiley' => [$this, 'action_addsmiley', 'permission' => 'manage_smileys'], |
||||
| 60 | 'editicon' => [$this, 'action_editicon', 'enabled' => !empty($modSettings['messageIcons_enable']), 'permission' => 'manage_smileys'], |
||||
| 61 | 'editicons' => [$this, 'action_editicon', 'enabled' => !empty($modSettings['messageIcons_enable']), 'permission' => 'manage_smileys'], |
||||
| 62 | 'editsets' => [$this, 'action_edit', 'permission' => 'admin_forum'], |
||||
| 63 | 'editsmileys' => [$this, 'action_editsmiley', 'permission' => 'manage_smileys'], |
||||
| 64 | 'import' => [$this, 'action_edit', 'permission' => 'manage_smileys'], |
||||
| 65 | 'modifyset' => [$this, 'action_edit', 'permission' => 'manage_smileys'], |
||||
| 66 | 'modifysmiley' => [$this, 'action_editsmiley', 'permission' => 'manage_smileys'], |
||||
| 67 | 'setorder' => [$this, 'action_setorder', 'permission' => 'manage_smileys'], |
||||
| 68 | 'settings' => [$this, 'action_smileySettings_display', 'permission' => 'manage_smileys'], |
||||
| 69 | 'install' => [$this, 'action_install', 'permission' => 'manage_smileys'] |
||||
| 70 | ]; |
||||
| 71 | |||||
| 72 | // Action controller |
||||
| 73 | $action = new Action('manage_smileys'); |
||||
| 74 | |||||
| 75 | // Set the smiley context. |
||||
| 76 | $this->_initSmileyContext(); |
||||
| 77 | |||||
| 78 | // Load up all the tabs... |
||||
| 79 | $context[$context['admin_menu_name']]['object']->prepareTabData([ |
||||
| 80 | 'title' => 'smileys_manage', |
||||
| 81 | 'help' => 'smileys', |
||||
| 82 | 'description' => 'smiley_settings_explain', |
||||
| 83 | 'prefix' => 'smiley', |
||||
| 84 | 'tabs' => [ |
||||
| 85 | 'editicons' => [ |
||||
| 86 | 'description' => $txt['icons_edit_icons_explain'], |
||||
| 87 | ], |
||||
| 88 | ], |
||||
| 89 | ]); |
||||
| 90 | |||||
| 91 | // Default the sub-action to 'edit smiley settings'. call integrate_sa_manage_smileys |
||||
| 92 | $subAction = $action->initialize($subActions, 'editsets'); |
||||
| 93 | |||||
| 94 | // Set up the template |
||||
| 95 | $context['page_title'] = $txt['smileys_manage']; |
||||
| 96 | $context['sub_action'] = $subAction; |
||||
| 97 | |||||
| 98 | // Some settings may not be enabled, disallow these from the tabs as appropriate. |
||||
| 99 | if (empty($modSettings['messageIcons_enable'])) |
||||
| 100 | { |
||||
| 101 | $context[$context['admin_menu_name']]['tab_data']['tabs']['editicons']['disabled'] = true; |
||||
| 102 | } |
||||
| 103 | |||||
| 104 | // Call the right function for this sub-action. |
||||
| 105 | $action->dispatch($subAction); |
||||
| 106 | } |
||||
| 107 | |||||
| 108 | /** |
||||
| 109 | * Sets our internal smiley context. |
||||
| 110 | */ |
||||
| 111 | private function _initSmileyContext(): void |
||||
| 112 | { |
||||
| 113 | global $modSettings; |
||||
| 114 | |||||
| 115 | // Validate the smiley set name. |
||||
| 116 | $set_paths = explode(',', $modSettings['smiley_sets_known']); |
||||
| 117 | $set_names = explode("\n", $modSettings['smiley_sets_names']); |
||||
| 118 | |||||
| 119 | foreach ($set_paths as $i => $set) |
||||
| 120 | { |
||||
| 121 | $this->_smiley_context[$set] = $set_names[$i]; |
||||
| 122 | } |
||||
| 123 | } |
||||
| 124 | |||||
| 125 | /** |
||||
| 126 | * Displays and allows modification to smileys settings. |
||||
| 127 | * |
||||
| 128 | * @uses show_settings sub template |
||||
| 129 | */ |
||||
| 130 | public function action_smileySettings_display(): void |
||||
| 131 | { |
||||
| 132 | global $context; |
||||
| 133 | |||||
| 134 | // initialize the form |
||||
| 135 | $settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER); |
||||
| 136 | $settingsForm->setConfigVars($this->_settings()); |
||||
| 137 | |||||
| 138 | // For the basics of the settings. |
||||
| 139 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 140 | $context['sub_template'] = 'show_settings'; |
||||
| 141 | |||||
| 142 | // Finish up the form... |
||||
| 143 | $context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'save', 'sa' => 'settings']); |
||||
| 144 | |||||
| 145 | // Saving the settings? |
||||
| 146 | if (isset($this->_req->query->save)) |
||||
| 147 | { |
||||
| 148 | checkSession(); |
||||
| 149 | |||||
| 150 | $this->_req->post->smiley_sets_default = $this->_req->getPost('smiley_sets_default', 'trim|strval', 'default'); |
||||
| 151 | |||||
| 152 | call_integration_hook('integrate_save_smiley_settings'); |
||||
| 153 | |||||
| 154 | // Save away |
||||
| 155 | $settingsForm->setConfigValues((array) $this->_req->post); |
||||
| 156 | $settingsForm->save(); |
||||
| 157 | |||||
| 158 | // Flush the cache so the new settings take effect |
||||
| 159 | $this->clearSmileyCache(); |
||||
| 160 | |||||
| 161 | redirectexit('action=admin;area=smileys;sa=settings'); |
||||
| 162 | } |
||||
| 163 | |||||
| 164 | $settingsForm->prepare(); |
||||
| 165 | } |
||||
| 166 | |||||
| 167 | /** |
||||
| 168 | * Retrieve and return smiley administration settings. |
||||
| 169 | */ |
||||
| 170 | private function _settings() |
||||
| 171 | { |
||||
| 172 | global $txt, $modSettings, $context; |
||||
| 173 | |||||
| 174 | // The directories... |
||||
| 175 | $context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir']; |
||||
| 176 | $context['smileys_dir_found'] = FileFunctions::instance()->isDir($context['smileys_dir']); |
||||
| 177 | |||||
| 178 | // All the settings for the page... |
||||
| 179 | $config_vars = [ |
||||
| 180 | ['title', 'settings'], |
||||
| 181 | ['select', 'smiley_sets_default', $this->_smiley_context], |
||||
| 182 | ['text', 'smileys_url', 40], |
||||
| 183 | ['text', 'smileys_dir', 'invalid' => !$context['smileys_dir_found'], 40], |
||||
| 184 | '', |
||||
| 185 | // Message icons. |
||||
| 186 | ['check', 'messageIcons_enable', 'subtext' => $txt['setting_messageIcons_enable_note']], |
||||
| 187 | // Inline permissions. |
||||
| 188 | '', |
||||
| 189 | ['permissions', 'manage_smileys'], |
||||
| 190 | ]; |
||||
| 191 | |||||
| 192 | call_integration_hook('integrate_modify_smiley_settings', [&$config_vars]); |
||||
| 193 | 2 | ||||
| 194 | return $config_vars; |
||||
| 195 | 2 | } |
|||
| 196 | |||||
| 197 | /** |
||||
| 198 | 2 | * Clear the cache to avoid changes not immediately appearing |
|||
| 199 | 2 | */ |
|||
| 200 | protected function clearSmileyCache(): void |
||||
| 201 | { |
||||
| 202 | Cache::instance()->remove('parsing_smileys'); |
||||
| 203 | 2 | Cache::instance()->remove('posting_smileys'); |
|||
| 204 | |||||
| 205 | $this->createCustomTagsFile(); |
||||
| 206 | 2 | } |
|||
| 207 | 2 | ||||
| 208 | /** |
||||
| 209 | 2 | * For any :emoji: codes in the current set, that have an image in the smile set directory, |
|||
| 210 | * write the information to custom_tags.js so the emoji selector reflects the new or replacement image |
||||
| 211 | 2 | * |
|||
| 212 | 2 | * @return void |
|||
| 213 | */ |
||||
| 214 | 2 | protected function createCustomTagsFile(): void |
|||
| 215 | { |
||||
| 216 | global $context, $settings; |
||||
| 217 | 2 | ||||
| 218 | $fileFunc = FileFunctions::instance(); |
||||
| 219 | 2 | $custom = []; |
|||
| 220 | $smileys = list_getSmileys(0, 2000, 'code'); |
||||
| 221 | foreach ($smileys as $smile) |
||||
| 222 | { |
||||
| 223 | if (preg_match('~:[\w-]{2,}:~u', $smile['code'], $match) === 1) |
||||
| 224 | { |
||||
| 225 | // If the emoji IS an image file in the currently selected set |
||||
| 226 | $filename = $context['smiley_dir'] . $smile['filename'] . '.' . $context['smiley_extension']; |
||||
| 227 | if ($fileFunc->fileExists($filename)) |
||||
| 228 | { |
||||
| 229 | $custom[] = [ |
||||
| 230 | 'name' => trim($smile['code'], ':'), |
||||
| 231 | 2 | 'key' => $smile['filename'], |
|||
| 232 | 'type' => $context['smiley_extension'] |
||||
| 233 | 2 | ]; |
|||
| 234 | } |
||||
| 235 | } |
||||
| 236 | } |
||||
| 237 | |||||
| 238 | // Whatever we have, save it |
||||
| 239 | $header = '/*! |
||||
| 240 | * Auto-generated file, DO NOT manually edit |
||||
| 241 | * |
||||
| 242 | * @package ElkArte Forum |
||||
| 243 | * @copyright ElkArte Forum contributors |
||||
| 244 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||||
| 245 | * |
||||
| 246 | */ |
||||
| 247 | |||||
| 248 | let custom = [ |
||||
| 249 | '; |
||||
| 250 | foreach ($custom as $emoji) |
||||
| 251 | { |
||||
| 252 | $header .= "\t" . '{name: \'' . $emoji['name'] . '\', key: \'' . $emoji['key'] . '\', type: \'' . $emoji['type'] . "'},\n"; |
||||
| 253 | } |
||||
| 254 | |||||
| 255 | $header .= '];'; |
||||
| 256 | |||||
| 257 | file_put_contents($settings['default_theme_dir'] . '/scripts/custom_tags.js', $header); |
||||
| 258 | } |
||||
| 259 | |||||
| 260 | /** |
||||
| 261 | * Return the smiley settings for use in admin search |
||||
| 262 | */ |
||||
| 263 | public function settings_search() |
||||
| 264 | { |
||||
| 265 | return $this->_settings(); |
||||
| 266 | } |
||||
| 267 | |||||
| 268 | /** |
||||
| 269 | * List, add, remove, modify smiley sets. |
||||
| 270 | * |
||||
| 271 | * @event integrate_list_smiley_set_list |
||||
| 272 | */ |
||||
| 273 | public function action_edit(): void |
||||
| 274 | { |
||||
| 275 | global $modSettings, $context, $txt; |
||||
| 276 | |||||
| 277 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 278 | |||||
| 279 | // Set the right tab to be selected. |
||||
| 280 | $context[$context['admin_menu_name']]['current_subsection'] = 'editsets'; |
||||
| 281 | $context['sub_template'] = $context['sub_action']; |
||||
| 282 | |||||
| 283 | // Have they submitted a form? |
||||
| 284 | $this->_subActionSubmit(); |
||||
| 285 | |||||
| 286 | // Load all available smileysets... |
||||
| 287 | $this->loadSmileySets(); |
||||
| 288 | |||||
| 289 | // Importing any smileys from an existing set? |
||||
| 290 | $this->_subActionImport(); |
||||
| 291 | |||||
| 292 | // If we're modifying or adding a smileyset, some context info needs to be set. |
||||
| 293 | $this->_subActionModifySet(); |
||||
| 294 | |||||
| 295 | // This is our save haven. |
||||
| 296 | createToken('admin-mss', 'request'); |
||||
| 297 | |||||
| 298 | $listOptions = [ |
||||
| 299 | 'id' => 'smiley_set_list', |
||||
| 300 | 'title' => $txt['smiley_sets'], |
||||
| 301 | 'no_items_label' => $txt['smiley_sets_none'], |
||||
| 302 | 'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editsets']), |
||||
| 303 | 'default_sort_col' => 'name', |
||||
| 304 | 'get_items' => [ |
||||
| 305 | 'function' => 'list_getSmileySets', |
||||
| 306 | ], |
||||
| 307 | 'get_count' => [ |
||||
| 308 | 'function' => 'list_getNumSmileySets', |
||||
| 309 | ], |
||||
| 310 | 'columns' => [ |
||||
| 311 | 'default' => [ |
||||
| 312 | 'header' => [ |
||||
| 313 | 'value' => $txt['smiley_sets_default'], |
||||
| 314 | 'class' => 'centertext', |
||||
| 315 | ], |
||||
| 316 | 'data' => [ |
||||
| 317 | 'function' => static fn($rowData) => $rowData['selected'] ? '<i class="icon i-check"></i>' : '', |
||||
| 318 | 'class' => 'centertext', |
||||
| 319 | ], |
||||
| 320 | 'sort' => [ |
||||
| 321 | 'default' => 'selected', |
||||
| 322 | 'reverse' => 'selected DESC', |
||||
| 323 | ], |
||||
| 324 | ], |
||||
| 325 | 'name' => [ |
||||
| 326 | 'header' => [ |
||||
| 327 | 'value' => $txt['smiley_sets_name'], |
||||
| 328 | ], |
||||
| 329 | 'data' => [ |
||||
| 330 | 'db_htmlsafe' => 'name', |
||||
| 331 | ], |
||||
| 332 | 'sort' => [ |
||||
| 333 | 'default' => 'name', |
||||
| 334 | 'reverse' => 'name DESC', |
||||
| 335 | ], |
||||
| 336 | ], |
||||
| 337 | 'ext' => [ |
||||
| 338 | 'header' => [ |
||||
| 339 | 'value' => $txt['smiley_sets_ext'], |
||||
| 340 | ], |
||||
| 341 | 'data' => [ |
||||
| 342 | 'db_htmlsafe' => 'ext', |
||||
| 343 | ], |
||||
| 344 | 'sort' => [ |
||||
| 345 | 'default' => 'ext', |
||||
| 346 | 'reverse' => 'ext DESC', |
||||
| 347 | ], |
||||
| 348 | ], |
||||
| 349 | 'url' => [ |
||||
| 350 | 'header' => [ |
||||
| 351 | 'value' => $txt['smiley_sets_url'], |
||||
| 352 | ], |
||||
| 353 | 'data' => [ |
||||
| 354 | 'sprintf' => [ |
||||
| 355 | 'format' => $modSettings['smileys_url'] . '/<strong>%1$s</strong>/...', |
||||
| 356 | 'params' => [ |
||||
| 357 | 'path' => true, |
||||
| 358 | ], |
||||
| 359 | ], |
||||
| 360 | ], |
||||
| 361 | 'sort' => [ |
||||
| 362 | 'default' => 'path', |
||||
| 363 | 'reverse' => 'path DESC', |
||||
| 364 | ], |
||||
| 365 | ], |
||||
| 366 | 'modify' => [ |
||||
| 367 | 'header' => [ |
||||
| 368 | 'value' => $txt['smiley_set_modify'], |
||||
| 369 | ], |
||||
| 370 | 'data' => [ |
||||
| 371 | 'sprintf' => [ |
||||
| 372 | 'format' => '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'modifyset', 'set' => '']) . '%1$d">' . $txt['smiley_set_modify'] . '</a>', |
||||
| 373 | 'params' => [ |
||||
| 374 | 'id' => true, |
||||
| 375 | ], |
||||
| 376 | ], |
||||
| 377 | ], |
||||
| 378 | ], |
||||
| 379 | 'check' => [ |
||||
| 380 | 'header' => [ |
||||
| 381 | 'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />', |
||||
| 382 | 'class' => 'centertext', |
||||
| 383 | ], |
||||
| 384 | 'data' => [ |
||||
| 385 | 'function' => static fn($rowData) => $rowData['id'] == 0 ? '' : sprintf('<input type="checkbox" name="smiley_set[%1$d]" class="input_check" />', $rowData['id']), |
||||
| 386 | 'class' => 'centertext', |
||||
| 387 | ], |
||||
| 388 | ], |
||||
| 389 | ], |
||||
| 390 | 'form' => [ |
||||
| 391 | 'href' => getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editsets']), |
||||
| 392 | 'token' => 'admin-mss', |
||||
| 393 | ], |
||||
| 394 | 'additional_rows' => [ |
||||
| 395 | [ |
||||
| 396 | 'position' => 'below_table_data', |
||||
| 397 | 'class' => 'submitbutton', |
||||
| 398 | 'value' => ' |
||||
| 399 | <a class="linkbutton" href="' . getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'modifyset']) . '">' . $txt['smiley_sets_add'] . '</a> |
||||
| 400 | <input type="submit" name="delete_set" value="' . $txt['smiley_sets_delete'] . '" onclick="return confirm(\'' . $txt['smiley_sets_confirm'] . '\');" />', |
||||
| 401 | ], |
||||
| 402 | ], |
||||
| 403 | ]; |
||||
| 404 | |||||
| 405 | createList($listOptions); |
||||
| 406 | } |
||||
| 407 | |||||
| 408 | /** |
||||
| 409 | * Submitted a smiley form, determine what actions are required. |
||||
| 410 | * |
||||
| 411 | * - Handle deleting of a smiley set |
||||
| 412 | * - Adding a new set |
||||
| 413 | * - Modifying an existing set, such as setting it as the default |
||||
| 414 | */ |
||||
| 415 | private function _subActionSubmit(): void |
||||
| 416 | { |
||||
| 417 | global $context, $modSettings; |
||||
| 418 | |||||
| 419 | if (isset($this->_req->post->smiley_save) || isset($this->_req->post->delete_set)) |
||||
| 420 | { |
||||
| 421 | // Security first |
||||
| 422 | checkSession(); |
||||
| 423 | validateToken('admin-mss', 'request'); |
||||
| 424 | |||||
| 425 | // Delete selected smiley sets. |
||||
| 426 | if (!empty($this->_req->post->delete_set) && !empty($this->_req->post->smiley_set)) |
||||
| 427 | { |
||||
| 428 | $set_paths = explode(',', $modSettings['smiley_sets_known']); |
||||
| 429 | $set_names = explode("\n", $modSettings['smiley_sets_names']); |
||||
| 430 | $set_extensions = explode(',', $modSettings['smiley_sets_extensions']); |
||||
| 431 | foreach ($this->_req->post->smiley_set as $id => $val) |
||||
| 432 | { |
||||
| 433 | if (!isset($set_paths[$id], $set_names[$id])) |
||||
| 434 | { |
||||
| 435 | continue; |
||||
| 436 | } |
||||
| 437 | if (empty($id)) |
||||
| 438 | { |
||||
| 439 | continue; |
||||
| 440 | } |
||||
| 441 | unset($set_paths[$id], $set_names[$id], $set_extensions[$id]); |
||||
| 442 | } |
||||
| 443 | |||||
| 444 | // Update the modSettings with the new values |
||||
| 445 | updateSettings([ |
||||
| 446 | 'smiley_sets_known' => implode(',', $set_paths), |
||||
| 447 | 'smiley_sets_names' => implode("\n", $set_names), |
||||
| 448 | 'smiley_sets_extensions' => implode(',', $set_extensions), |
||||
| 449 | 'smiley_sets_default' => in_array($modSettings['smiley_sets_default'], $set_paths, true) ? $modSettings['smiley_sets_default'] : $set_paths[0], |
||||
| 450 | ]); |
||||
| 451 | } |
||||
| 452 | // Add a new smiley set. |
||||
| 453 | elseif (!empty($this->_req->post->add)) |
||||
| 454 | { |
||||
| 455 | $context['sub_action'] = 'modifyset'; |
||||
| 456 | } |
||||
| 457 | // Create or modify a smiley set. |
||||
| 458 | elseif (isset($this->_req->post->set)) |
||||
| 459 | { |
||||
| 460 | $set = $this->_req->getPost('set', 'intval', 0); |
||||
| 461 | $set_paths = explode(',', $modSettings['smiley_sets_known']); |
||||
| 462 | $set_names = explode("\n", $modSettings['smiley_sets_names']); |
||||
| 463 | |||||
| 464 | // Create a new smiley set. |
||||
| 465 | if ($set === -1 && isset($this->_req->post->smiley_sets_path)) |
||||
| 466 | { |
||||
| 467 | if (in_array($this->_req->post->smiley_sets_path, $set_paths, true)) |
||||
| 468 | { |
||||
| 469 | throw new Exception('smiley_set_already_exists', false); |
||||
| 470 | } |
||||
| 471 | |||||
| 472 | updateSettings([ |
||||
| 473 | 'smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . $this->_req->post->smiley_sets_path, |
||||
| 474 | 'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $this->_req->post->smiley_sets_name, |
||||
| 475 | 'smiley_sets_extensions' => $modSettings['smiley_sets_extensions'] . ',' . $this->_req->post->smiley_sets_ext, |
||||
| 476 | 'smiley_sets_default' => empty($this->_req->post->smiley_sets_default) ? $modSettings['smiley_sets_default'] : $this->_req->post->smiley_sets_path, |
||||
| 477 | ]); |
||||
| 478 | } |
||||
| 479 | // Modify an existing smiley set. |
||||
| 480 | else |
||||
| 481 | { |
||||
| 482 | // Make sure the smiley set exists. |
||||
| 483 | if (!isset($set_paths[$set], $set_names[$set])) |
||||
| 484 | { |
||||
| 485 | throw new Exception('smiley_set_not_found', false); |
||||
| 486 | } |
||||
| 487 | |||||
| 488 | // Make sure the path is not yet used by another smileyset. |
||||
| 489 | if (in_array($this->_req->post->smiley_sets_path, $set_paths, true) && $this->_req->post->smiley_sets_path !== $set_paths[$set]) |
||||
| 490 | { |
||||
| 491 | throw new Exception('smiley_set_path_already_used', false); |
||||
| 492 | } |
||||
| 493 | |||||
| 494 | $set_paths[$set] = $this->_req->post->smiley_sets_path; |
||||
| 495 | $set_names[$set] = $this->_req->post->smiley_sets_name; |
||||
| 496 | updateSettings([ |
||||
| 497 | 'smiley_sets_known' => implode(',', $set_paths), |
||||
| 498 | 'smiley_sets_names' => implode("\n", $set_names), |
||||
| 499 | 'smiley_sets_default' => empty($this->_req->post->smiley_sets_default) ? $modSettings['smiley_sets_default'] : $this->_req->post->smiley_sets_path |
||||
| 500 | ]); |
||||
| 501 | } |
||||
| 502 | |||||
| 503 | // The user might have checked to also import smileys. |
||||
| 504 | if (!empty($this->_req->post->smiley_sets_import)) |
||||
| 505 | { |
||||
| 506 | $this->importSmileys($this->_req->post->smiley_sets_path); |
||||
| 507 | } |
||||
| 508 | } |
||||
| 509 | |||||
| 510 | // Reset $context as the default set may have changed |
||||
| 511 | loadSmileyEmojiData(); |
||||
| 512 | |||||
| 513 | // No matter what, reset the cache |
||||
| 514 | $this->clearSmileyCache(); |
||||
| 515 | } |
||||
| 516 | } |
||||
| 517 | |||||
| 518 | /** |
||||
| 519 | * A function to import new smileys from an existing directory into the database. |
||||
| 520 | * |
||||
| 521 | * @param string $smileyPath |
||||
| 522 | * |
||||
| 523 | * @throws Exception smiley_set_unable_to_import |
||||
| 524 | */ |
||||
| 525 | public function importSmileys(string $smileyPath): void |
||||
| 526 | { |
||||
| 527 | global $modSettings; |
||||
| 528 | |||||
| 529 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 530 | $fileFunc = FileFunctions::instance(); |
||||
| 531 | |||||
| 532 | if (empty($modSettings['smileys_dir']) || !$fileFunc->isDir($modSettings['smileys_dir'] . '/' . $smileyPath)) |
||||
| 533 | { |
||||
| 534 | throw new Exception('smiley_set_unable_to_import', false); |
||||
| 535 | } |
||||
| 536 | |||||
| 537 | // Fetch all smileys in the directory |
||||
| 538 | $foundSmileys = $fileFunc->listTree($modSettings['smileys_dir'] . '/' . $smileyPath); |
||||
| 539 | |||||
| 540 | // Exclude the smileys that are already in the database. |
||||
| 541 | $smileys = $this->_getUniqueSmileys($foundSmileys); |
||||
| 542 | |||||
| 543 | $smiley_order = getMaxSmileyOrder(); |
||||
| 544 | |||||
| 545 | $new_smileys = []; |
||||
| 546 | foreach ($smileys as $smiley) |
||||
| 547 | { |
||||
| 548 | if (strlen($smiley) <= 48) |
||||
| 549 | { |
||||
| 550 | $new_smileys[] = [':' . strtok($smiley, '.') . ':', $smiley, strtok($smiley, '.'), 0, ++$smiley_order]; |
||||
| 551 | } |
||||
| 552 | } |
||||
| 553 | |||||
| 554 | if (!empty($new_smileys)) |
||||
| 555 | { |
||||
| 556 | addSmiley($new_smileys); |
||||
| 557 | |||||
| 558 | $this->clearSmileyCache(); |
||||
| 559 | } |
||||
| 560 | } |
||||
| 561 | |||||
| 562 | /** |
||||
| 563 | * Returns smile names in a directory that *do not* exist in the DB |
||||
| 564 | * |
||||
| 565 | * @param array $foundSmileys array as returned from file functions listTree |
||||
| 566 | * @return array |
||||
| 567 | * @throws Exception |
||||
| 568 | */ |
||||
| 569 | private function _getUniqueSmileys(array $foundSmileys): array |
||||
| 570 | { |
||||
| 571 | global $context; |
||||
| 572 | |||||
| 573 | $smileys = []; |
||||
| 574 | foreach ($foundSmileys as $smile) |
||||
| 575 | { |
||||
| 576 | if (in_array($smile['filename'], ['.', '..', '.htaccess', 'index.php'], true)) |
||||
| 577 | { |
||||
| 578 | continue; |
||||
| 579 | } |
||||
| 580 | |||||
| 581 | // Get the name and extension |
||||
| 582 | $filename = pathinfo($smile['filename'], PATHINFO_FILENAME); |
||||
| 583 | if (in_array(strtolower(pathinfo($smile['filename'], PATHINFO_EXTENSION)), $this->_smiley_types, true)) |
||||
|
0 ignored issues
–
show
It seems like
pathinfo($smile['filenam...ler\PATHINFO_EXTENSION) can also be of type array; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 584 | { |
||||
| 585 | $smileys[strtolower($filename)] = $filename; |
||||
| 586 | } |
||||
| 587 | } |
||||
| 588 | |||||
| 589 | if (empty($smileys)) |
||||
| 590 | { |
||||
| 591 | throw new Exception('smiley_set_dir_not_found', false, [$context['current_set']['name']]); |
||||
| 592 | } |
||||
| 593 | |||||
| 594 | // Exclude the smileys that are already in the database. |
||||
| 595 | $duplicates = smileyExists($smileys); |
||||
| 596 | foreach ($duplicates as $duplicate) |
||||
| 597 | { |
||||
| 598 | if (isset($smileys[strtolower($duplicate)])) |
||||
| 599 | { |
||||
| 600 | unset($smileys[strtolower($duplicate)]); |
||||
| 601 | } |
||||
| 602 | } |
||||
| 603 | |||||
| 604 | return $smileys; |
||||
| 605 | } |
||||
| 606 | |||||
| 607 | /** |
||||
| 608 | * Importing smileys from an existing smiley set |
||||
| 609 | */ |
||||
| 610 | private function _subActionImport(): void |
||||
| 611 | { |
||||
| 612 | global $context; |
||||
| 613 | |||||
| 614 | // Importing any smileys from an existing set? |
||||
| 615 | if ($context['sub_action'] === 'import') |
||||
| 616 | { |
||||
| 617 | checkSession('get'); |
||||
| 618 | validateToken('admin-mss', 'request'); |
||||
| 619 | |||||
| 620 | $set = (int) $this->_req->query->set; |
||||
| 621 | |||||
| 622 | // Sanity check - then import. |
||||
| 623 | if (isset($context['smiley_sets'][$set])) |
||||
| 624 | { |
||||
| 625 | $this->importSmileys(un_htmlspecialchars($context['smiley_sets'][$set]['path'])); |
||||
| 626 | } |
||||
| 627 | |||||
| 628 | // Force the process to continue. |
||||
| 629 | $context['sub_action'] = 'modifyset'; |
||||
| 630 | $context['sub_template'] = 'modifyset'; |
||||
| 631 | } |
||||
| 632 | } |
||||
| 633 | |||||
| 634 | /** |
||||
| 635 | * If we're modifying or adding a smileyset, or if we imported from another |
||||
| 636 | * set, then some context info needs to be set. |
||||
| 637 | */ |
||||
| 638 | private function _subActionModifySet(): void |
||||
| 639 | { |
||||
| 640 | global $context, $txt, $modSettings; |
||||
| 641 | |||||
| 642 | $fileFunc = FileFunctions::instance(); |
||||
| 643 | |||||
| 644 | if ($context['sub_action'] === 'modifyset') |
||||
| 645 | { |
||||
| 646 | $set = $this->_req->getQuery('set', 'intval', -1); |
||||
| 647 | if ($set === -1 || !isset($context['smiley_sets'][$set])) |
||||
| 648 | { |
||||
| 649 | $context['current_set'] = [ |
||||
| 650 | 'id' => '-1', |
||||
| 651 | 'path' => '', |
||||
| 652 | 'name' => '', |
||||
| 653 | 'ext' => '', |
||||
| 654 | 'selected' => false, |
||||
| 655 | 'is_new' => true, |
||||
| 656 | ]; |
||||
| 657 | } |
||||
| 658 | else |
||||
| 659 | { |
||||
| 660 | $context['current_set'] = &$context['smiley_sets'][$set]; |
||||
| 661 | $context['current_set']['is_new'] = false; |
||||
| 662 | $context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir']; |
||||
| 663 | $context['selected_set'] = $modSettings['smiley_sets_default']; |
||||
| 664 | |||||
| 665 | // Calculate whether there are any smileys in the directory that can be imported. |
||||
| 666 | if (!empty($modSettings['smileys_dir']) |
||||
| 667 | && $fileFunc->isDir($modSettings['smileys_dir'] . '/' . $context['current_set']['path'])) |
||||
| 668 | { |
||||
| 669 | $foundSmileys = $fileFunc->listTree($modSettings['smileys_dir'] . '/' . $context['current_set']['path']); |
||||
| 670 | $smileys = $this->_getUniqueSmileys($foundSmileys); |
||||
| 671 | $context['current_set']['can_import'] = count($smileys); |
||||
| 672 | |||||
| 673 | // Setup this string to look nice. |
||||
| 674 | $txt['smiley_set_import_multiple'] = sprintf($txt['smiley_set_import_multiple'], $context['current_set']['can_import']); |
||||
| 675 | } |
||||
| 676 | } |
||||
| 677 | |||||
| 678 | // Retrieve all potential smiley set directories. |
||||
| 679 | $context['smiley_set_dirs'] = []; |
||||
| 680 | if (!empty($modSettings['smileys_dir']) && $fileFunc->isDir($modSettings['smileys_dir'])) |
||||
| 681 | { |
||||
| 682 | // Do not include our emoji directories |
||||
| 683 | $disallow = ['.', '..', 'open-moji', 'tw-emoji', 'noto-emoji']; |
||||
| 684 | |||||
| 685 | $dir = dir($modSettings['smileys_dir']); |
||||
| 686 | while (($entry = $dir->read()) !== false) |
||||
| 687 | { |
||||
| 688 | if (!in_array($entry, $disallow, true) |
||||
| 689 | && $fileFunc->isDir($modSettings['smileys_dir'] . '/' . $entry)) |
||||
| 690 | { |
||||
| 691 | $context['smiley_set_dirs'][] = [ |
||||
| 692 | 'id' => $entry, |
||||
| 693 | 'path' => $modSettings['smileys_dir'] . '/' . $entry, |
||||
| 694 | 'selectable' => $entry === $context['current_set']['path'] || !in_array($entry, explode(',', $modSettings['smiley_sets_known']), true), |
||||
| 695 | 'current' => $entry === $context['current_set']['path'], |
||||
| 696 | ]; |
||||
| 697 | } |
||||
| 698 | } |
||||
| 699 | |||||
| 700 | $dir->close(); |
||||
| 701 | } |
||||
| 702 | } |
||||
| 703 | } |
||||
| 704 | |||||
| 705 | /** |
||||
| 706 | * Add a smiley, that's right. |
||||
| 707 | */ |
||||
| 708 | public function action_addsmiley(): void |
||||
| 709 | { |
||||
| 710 | global $modSettings, $context, $txt; |
||||
| 711 | |||||
| 712 | $fileFunc = FileFunctions::instance(); |
||||
| 713 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 714 | |||||
| 715 | // Get a list of all known smiley sets. |
||||
| 716 | $context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir']; |
||||
| 717 | $context['sub_template'] = 'addsmiley'; |
||||
| 718 | |||||
| 719 | $this->loadSmileySets(); |
||||
| 720 | |||||
| 721 | // Submitting a form? |
||||
| 722 | if (isset($this->_req->post->{$context['session_var']}, $this->_req->post->smiley_code)) |
||||
| 723 | { |
||||
| 724 | checkSession(); |
||||
| 725 | |||||
| 726 | // Some useful arrays... types we allow - and ports we don't! |
||||
| 727 | $disabledFiles = ['con', 'com1', 'com2', 'com3', 'com4', 'prn', 'aux', 'lpt1', '.htaccess', 'index.php']; |
||||
| 728 | |||||
| 729 | $this->_req->post->smiley_code = $this->_req->getPost('smiley_code', '\\ElkArte\\Helper\\Util::htmltrim', ''); |
||||
| 730 | $this->_req->post->smiley_filename = $this->_req->getPost('smiley_filename', '\\ElkArte\\Helper\\Util::htmltrim', ''); |
||||
| 731 | $this->_req->post->smiley_location = $this->_req->getPost('smiley_location', 'intval', 0); |
||||
| 732 | $this->_req->post->smiley_location = min(max($this->_req->post->smiley_location, 0), 2); |
||||
| 733 | |||||
| 734 | // Make sure some code was entered. |
||||
| 735 | if (empty($this->_req->post->smiley_code)) |
||||
| 736 | { |
||||
| 737 | throw new Exception('smiley_has_no_code', false); |
||||
| 738 | } |
||||
| 739 | |||||
| 740 | // Check whether the new code has duplicates. It should be unique. |
||||
| 741 | if (validateDuplicateSmiley($this->_req->post->smiley_code)) |
||||
| 742 | { |
||||
| 743 | throw new Exception('smiley_not_unique', false); |
||||
| 744 | } |
||||
| 745 | |||||
| 746 | // If we are uploading - check all the smiley sets are writable! |
||||
| 747 | if ($this->_req->post->method !== 'existing') |
||||
| 748 | { |
||||
| 749 | $writeErrors = []; |
||||
| 750 | foreach ($context['smiley_sets'] as $set) |
||||
| 751 | { |
||||
| 752 | if (!$fileFunc->isWritable($context['smileys_dir'] . '/' . un_htmlspecialchars($set['path']))) |
||||
| 753 | { |
||||
| 754 | $writeErrors[] = $set['path']; |
||||
| 755 | } |
||||
| 756 | } |
||||
| 757 | |||||
| 758 | if (!empty($writeErrors)) |
||||
| 759 | { |
||||
| 760 | throw new Exception('smileys_upload_error_notwritable', true, [implode(', ', $writeErrors)]); |
||||
| 761 | } |
||||
| 762 | } |
||||
| 763 | |||||
| 764 | // Uploading just one smiley for all of them? |
||||
| 765 | if (isset($this->_req->post->sameall, $_FILES['uploadSmiley']['name']) && $_FILES['uploadSmiley']['name'] != '') |
||||
| 766 | { |
||||
| 767 | if (!is_uploaded_file($_FILES['uploadSmiley']['tmp_name']) |
||||
| 768 | || (ini_get('open_basedir') === '' && !$fileFunc->fileExists($_FILES['uploadSmiley']['tmp_name']))) |
||||
| 769 | { |
||||
| 770 | throw new Exception('smileys_upload_error'); |
||||
| 771 | } |
||||
| 772 | |||||
| 773 | // Sorry, no spaces, dots, or anything else but letters allowed. |
||||
| 774 | $_FILES['uploadSmiley']['name'] = preg_replace(['/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'], ['_', '.', ''], $_FILES['uploadSmiley']['name']); |
||||
| 775 | |||||
| 776 | // We only allow image files - it's THAT simple - no messing around here... |
||||
| 777 | if (!in_array(strtolower(pathinfo($_FILES['uploadSmiley']['name'], PATHINFO_EXTENSION)), $this->_smiley_types)) |
||||
| 778 | { |
||||
| 779 | throw new Exception('smileys_upload_error_types', false, [implode(', ', $this->_smiley_types)]); |
||||
| 780 | } |
||||
| 781 | |||||
| 782 | // We only need the filename... |
||||
| 783 | $destName = basename($_FILES['uploadSmiley']['name']); |
||||
| 784 | |||||
| 785 | // Make sure they aren't trying to upload a nasty file - for their own good here! |
||||
| 786 | if (in_array(strtolower($destName), $disabledFiles)) |
||||
| 787 | { |
||||
| 788 | throw new Exception('smileys_upload_error_illegal'); |
||||
| 789 | } |
||||
| 790 | |||||
| 791 | // Check if the file already exists... and if not move it to EVERY smiley set directory. |
||||
| 792 | $i = 0; |
||||
| 793 | |||||
| 794 | // Keep going until we find a set the file doesn't exist in. (or maybe it exists in all of them?) |
||||
| 795 | while (isset($context['smiley_sets'][$i]) |
||||
| 796 | && $fileFunc->fileExists($context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName)) |
||||
| 797 | { |
||||
| 798 | $i++; |
||||
| 799 | } |
||||
| 800 | |||||
| 801 | // Okay, we're going to put the smiley right here, since it's not there yet! |
||||
| 802 | if (isset($context['smiley_sets'][$i]['path'])) |
||||
| 803 | { |
||||
| 804 | $smileyLocation = $context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName; |
||||
| 805 | move_uploaded_file($_FILES['uploadSmiley']['tmp_name'], $smileyLocation); |
||||
| 806 | $fileFunc->chmod($smileyLocation); |
||||
| 807 | |||||
| 808 | // Now, we want to move it from there to all the other sets. |
||||
| 809 | for ($n = count($context['smiley_sets']); $i < $n; $i++) |
||||
| 810 | { |
||||
| 811 | $currentPath = $context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName; |
||||
| 812 | |||||
| 813 | // The file is already there! Don't overwrite it! |
||||
| 814 | if ($fileFunc->fileExists($currentPath)) |
||||
| 815 | { |
||||
| 816 | continue; |
||||
| 817 | } |
||||
| 818 | |||||
| 819 | // Okay, so copy the first one we made to here. |
||||
| 820 | copy($smileyLocation, $currentPath); |
||||
| 821 | $fileFunc->chmod($currentPath); |
||||
| 822 | } |
||||
| 823 | } |
||||
| 824 | |||||
| 825 | // Finally, make sure it's saved correctly! |
||||
| 826 | $this->_req->post->smiley_filename = $destName; |
||||
| 827 | } |
||||
| 828 | // What about uploading several files? |
||||
| 829 | elseif ($this->_req->post->method !== 'existing') |
||||
| 830 | { |
||||
| 831 | $newName = ''; |
||||
| 832 | foreach ($_FILES as $file) |
||||
| 833 | { |
||||
| 834 | if ($file['name'] === '') |
||||
| 835 | { |
||||
| 836 | throw new Exception('smileys_upload_error_blank', false); |
||||
| 837 | } |
||||
| 838 | |||||
| 839 | if (empty($newName)) |
||||
| 840 | { |
||||
| 841 | $newName = basename($file['name']); |
||||
| 842 | } |
||||
| 843 | elseif (basename($file['name']) !== $newName) |
||||
| 844 | { |
||||
| 845 | throw new Exception('smileys_upload_error_name', false); |
||||
| 846 | } |
||||
| 847 | } |
||||
| 848 | |||||
| 849 | foreach ($context['smiley_sets'] as $set) |
||||
| 850 | { |
||||
| 851 | $set['name'] = un_htmlspecialchars($set['name']); |
||||
| 852 | $set['path'] = un_htmlspecialchars($set['path']); |
||||
| 853 | |||||
| 854 | if (!isset($_FILES['individual_' . $set['name']]['name']) || $_FILES['individual_' . $set['name']]['name'] === '') |
||||
| 855 | { |
||||
| 856 | continue; |
||||
| 857 | } |
||||
| 858 | |||||
| 859 | // Got one... |
||||
| 860 | if (!is_uploaded_file($_FILES['individual_' . $set['name']]['tmp_name']) || (ini_get('open_basedir') === '' |
||||
| 861 | && !$fileFunc->fileExists($_FILES['individual_' . $set['name']]['tmp_name']))) |
||||
| 862 | { |
||||
| 863 | throw new Exception('smileys_upload_error'); |
||||
| 864 | } |
||||
| 865 | |||||
| 866 | // Sorry, no spaces, dots, or anything else but letters allowed. |
||||
| 867 | $_FILES['individual_' . $set['name']]['name'] = preg_replace(['/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'], ['_', '.', ''], $_FILES['individual_' . $set['name']]['name']); |
||||
| 868 | |||||
| 869 | // We only allow image files - it's THAT simple - no messing around here... |
||||
| 870 | if (!in_array(strtolower(pathinfo($_FILES['individual_' . $set['name']]['name'], PATHINFO_EXTENSION)), $this->_smiley_types)) |
||||
| 871 | { |
||||
| 872 | throw new Exception('smileys_upload_error_types', false, [implode(', ', $this->_smiley_types)]); |
||||
| 873 | } |
||||
| 874 | |||||
| 875 | // We only need the filename... |
||||
| 876 | $destName = basename($_FILES['individual_' . $set['name']]['name']); |
||||
| 877 | |||||
| 878 | // Make sure they aren't trying to upload a nasty file - for their own good here! |
||||
| 879 | if (in_array(strtolower($destName), $disabledFiles)) |
||||
| 880 | { |
||||
| 881 | throw new Exception('smileys_upload_error_illegal'); |
||||
| 882 | } |
||||
| 883 | |||||
| 884 | // If the file exists - ignore it. |
||||
| 885 | $smileyLocation = $context['smileys_dir'] . '/' . $set['path'] . '/' . $destName; |
||||
| 886 | if ($fileFunc->fileExists($smileyLocation)) |
||||
| 887 | { |
||||
| 888 | continue; |
||||
| 889 | } |
||||
| 890 | |||||
| 891 | // Finally - move the image! |
||||
| 892 | move_uploaded_file($_FILES['individual_' . $set['name']]['tmp_name'], $smileyLocation); |
||||
| 893 | $fileFunc->chmod($smileyLocation); |
||||
| 894 | |||||
| 895 | // Should always be saved correctly! |
||||
| 896 | $this->_req->post->smiley_filename = $destName; |
||||
| 897 | } |
||||
| 898 | } |
||||
| 899 | |||||
| 900 | // Also make sure a filename was given. |
||||
| 901 | if (empty($this->_req->post->smiley_filename)) |
||||
| 902 | { |
||||
| 903 | throw new Exception('smiley_has_no_filename', false); |
||||
| 904 | } |
||||
| 905 | |||||
| 906 | // Find the position on the right. |
||||
| 907 | $smiley_order = '0'; |
||||
| 908 | if ($this->_req->post->smiley_location != 1) |
||||
| 909 | { |
||||
| 910 | $this->_req->post->smiley_location = (int) $this->_req->post->smiley_location; |
||||
| 911 | $smiley_order = nextSmileyLocation($this->_req->post->smiley_location); |
||||
| 912 | |||||
| 913 | if (empty($smiley_order)) |
||||
| 914 | { |
||||
| 915 | $smiley_order = '0'; |
||||
| 916 | } |
||||
| 917 | } |
||||
| 918 | |||||
| 919 | $param = [ |
||||
| 920 | $this->_req->post->smiley_code, |
||||
| 921 | $this->_req->post->smiley_filename, |
||||
| 922 | $this->_req->post->smiley_description, |
||||
| 923 | (int) $this->_req->post->smiley_location, |
||||
| 924 | $smiley_order, |
||||
| 925 | ]; |
||||
| 926 | addSmiley($param); |
||||
| 927 | |||||
| 928 | $this->clearSmileyCache(); |
||||
| 929 | |||||
| 930 | // No errors? Out of here! |
||||
| 931 | redirectexit('action=admin;area=smileys;sa=editsmileys'); |
||||
| 932 | } |
||||
| 933 | |||||
| 934 | $context['selected_set'] = $modSettings['smiley_sets_default']; |
||||
| 935 | |||||
| 936 | // Get all possible filenames for the smileys. |
||||
| 937 | $context['filenames'] = $this->getAllPossibleFilenamesForTheSmileys($context['smiley_sets']); |
||||
| 938 | |||||
| 939 | // Create a new smiley from scratch. |
||||
| 940 | $context['filenames'] = array_values($context['filenames']); |
||||
| 941 | $context['current_smiley'] = [ |
||||
| 942 | 'id' => 0, |
||||
| 943 | 'code' => '', |
||||
| 944 | 'filename' => $context['filenames'][0]['id'], |
||||
| 945 | 'description' => $txt['smileys_default_description'], |
||||
| 946 | 'location' => 0, |
||||
| 947 | 'is_new' => true, |
||||
| 948 | ]; |
||||
| 949 | } |
||||
| 950 | |||||
| 951 | /** |
||||
| 952 | * Add, remove, edit smileys. |
||||
| 953 | * |
||||
| 954 | * @event integrate_list_smiley_list |
||||
| 955 | */ |
||||
| 956 | public function action_editsmiley(): void |
||||
| 957 | { |
||||
| 958 | global $modSettings, $context, $txt; |
||||
| 959 | |||||
| 960 | $fileFunc = FileFunctions::instance(); |
||||
| 961 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 962 | |||||
| 963 | // Force the correct tab to be displayed. |
||||
| 964 | $context[$context['admin_menu_name']]['current_subsection'] = 'editsmileys'; |
||||
| 965 | $context['sub_template'] = $context['sub_action']; |
||||
| 966 | |||||
| 967 | // Submitting a form? |
||||
| 968 | if (isset($this->_req->post->smiley_save) || isset($this->_req->post->smiley_action)) |
||||
| 969 | { |
||||
| 970 | checkSession(); |
||||
| 971 | |||||
| 972 | // Changing the selected smileys? |
||||
| 973 | if (isset($this->_req->post->smiley_action) && !empty($this->_req->post->checked_smileys)) |
||||
| 974 | { |
||||
| 975 | foreach ($this->_req->post->checked_smileys as $id => $smiley_id) |
||||
| 976 | { |
||||
| 977 | $this->_req->post->checked_smileys[$id] = (int) $smiley_id; |
||||
| 978 | } |
||||
| 979 | |||||
| 980 | if ($this->_req->post->smiley_action === 'delete') |
||||
| 981 | { |
||||
| 982 | deleteSmileys($this->_req->post->checked_smileys); |
||||
| 983 | } |
||||
| 984 | // Changing the status of the smiley? |
||||
| 985 | else |
||||
| 986 | { |
||||
| 987 | // Check it's a valid type. |
||||
| 988 | $displayTypes = [ |
||||
| 989 | 'post' => 0, |
||||
| 990 | 'hidden' => 1, |
||||
| 991 | 'popup' => 2 |
||||
| 992 | ]; |
||||
| 993 | if (isset($displayTypes[$this->_req->post->smiley_action])) |
||||
| 994 | { |
||||
| 995 | updateSmileyDisplayType($this->_req->post->checked_smileys, $displayTypes[$this->_req->post->smiley_action]); |
||||
| 996 | } |
||||
| 997 | } |
||||
| 998 | } |
||||
| 999 | // Create/modify a smiley. |
||||
| 1000 | elseif (isset($this->_req->post->smiley)) |
||||
| 1001 | { |
||||
| 1002 | $this->_req->post->smiley = (int) $this->_req->post->smiley; |
||||
| 1003 | |||||
| 1004 | // Is it a delete? |
||||
| 1005 | if (!empty($this->_req->post->deletesmiley)) |
||||
| 1006 | { |
||||
| 1007 | deleteSmileys([$this->_req->post->smiley]); |
||||
| 1008 | } |
||||
| 1009 | // Otherwise an edit. |
||||
| 1010 | else |
||||
| 1011 | { |
||||
| 1012 | $this->_req->post->smiley_code = $this->_req->getPost('smiley_code', '\\ElkArte\\Helper\\Util::htmltrim', ''); |
||||
| 1013 | $this->_req->post->smiley_filename = $this->_req->getPost('smiley_filename', '\\ElkArte\\Helper\\Util::htmltrim', ''); |
||||
| 1014 | $this->_req->post->smiley_location = empty($this->_req->post->smiley_location) |
||||
| 1015 | || $this->_req->post->smiley_location > 2 |
||||
| 1016 | || $this->_req->post->smiley_location < 0 ? 0 : (int) $this->_req->post->smiley_location; |
||||
| 1017 | |||||
| 1018 | // Make sure some code was entered. |
||||
| 1019 | if (empty($this->_req->post->smiley_code)) |
||||
| 1020 | { |
||||
| 1021 | throw new Exception('smiley_has_no_code', false); |
||||
| 1022 | } |
||||
| 1023 | |||||
| 1024 | // Also make sure a filename was given. |
||||
| 1025 | if (empty($this->_req->post->smiley_filename)) |
||||
| 1026 | { |
||||
| 1027 | throw new Exception('smiley_has_no_filename', false); |
||||
| 1028 | } |
||||
| 1029 | |||||
| 1030 | // Check whether the new code has duplicates. It should be unique. |
||||
| 1031 | if (validateDuplicateSmiley($this->_req->post->smiley_code, $this->_req->post->smiley)) |
||||
| 1032 | { |
||||
| 1033 | throw new Exception('smiley_not_unique', false); |
||||
| 1034 | } |
||||
| 1035 | |||||
| 1036 | $param = [ |
||||
| 1037 | 'smiley_location' => $this->_req->post->smiley_location, |
||||
| 1038 | 'smiley' => $this->_req->post->smiley, |
||||
| 1039 | 'smiley_code' => $this->_req->post->smiley_code, |
||||
| 1040 | 'smiley_filename' => $this->_req->post->smiley_filename, |
||||
| 1041 | 'smiley_description' => $this->_req->post->smiley_description, |
||||
| 1042 | ]; |
||||
| 1043 | updateSmiley($param); |
||||
| 1044 | } |
||||
| 1045 | } |
||||
| 1046 | |||||
| 1047 | $this->clearSmileyCache(); |
||||
| 1048 | } |
||||
| 1049 | |||||
| 1050 | // Load all known smiley sets. |
||||
| 1051 | $this->loadSmileySets(); |
||||
| 1052 | |||||
| 1053 | // Prepare overview of all (custom) smileys. |
||||
| 1054 | if ($context['sub_action'] === 'editsmileys') |
||||
| 1055 | { |
||||
| 1056 | theme()->addJavascriptVar([ |
||||
| 1057 | 'txt_remove' => JavaScriptEscape($txt['smileys_confirm']), |
||||
| 1058 | ]); |
||||
| 1059 | |||||
| 1060 | // Determine the language specific sort order of smiley locations. |
||||
| 1061 | $smiley_locations = [ |
||||
| 1062 | $txt['smileys_location_form'], |
||||
| 1063 | $txt['smileys_location_hidden'], |
||||
| 1064 | $txt['smileys_location_popup'], |
||||
| 1065 | ]; |
||||
| 1066 | asort($smiley_locations); |
||||
| 1067 | |||||
| 1068 | // Create a list of options for selecting smiley sets. |
||||
| 1069 | $smileyset_option_list = ' |
||||
| 1070 | <select id="set" name="set" onchange="changeSet(this.options[this.selectedIndex].value);">'; |
||||
| 1071 | |||||
| 1072 | foreach ($context['smiley_sets'] as $smiley_set) |
||||
| 1073 | { |
||||
| 1074 | $smileyset_option_list .= ' |
||||
| 1075 | <option data-ext="' . $smiley_set['ext'] . '" value="' . $smiley_set['path'] . '"' . ($modSettings['smiley_sets_default'] === $smiley_set['path'] ? ' selected="selected"' : '') . '>' . $smiley_set['name'] . '</option>'; |
||||
| 1076 | } |
||||
| 1077 | |||||
| 1078 | $smileyset_option_list .= ' |
||||
| 1079 | </select>'; |
||||
| 1080 | |||||
| 1081 | $listOptions = [ |
||||
| 1082 | 'id' => 'smiley_list', |
||||
| 1083 | 'title' => $txt['smileys_edit'], |
||||
| 1084 | 'items_per_page' => 40, |
||||
| 1085 | 'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editsmileys']), |
||||
| 1086 | 'default_sort_col' => 'filename', |
||||
| 1087 | 'get_items' => [ |
||||
| 1088 | 'function' => 'list_getSmileys', |
||||
| 1089 | ], |
||||
| 1090 | 'get_count' => [ |
||||
| 1091 | 'function' => 'list_getNumSmileys', |
||||
| 1092 | ], |
||||
| 1093 | 'no_items_label' => $txt['smileys_no_entries'], |
||||
| 1094 | 'columns' => [ |
||||
| 1095 | 'picture' => [ |
||||
| 1096 | 'data' => [ |
||||
| 1097 | 'function' => static fn($rowData) => ' |
||||
| 1098 | <a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'modifysmiley', 'smiley' => '']) . $rowData['id_smiley'] . '"> |
||||
| 1099 | <img class="smiley" src="' . $context['smiley_path'] . $rowData['filename'] . '.' . $context['smiley_extension'] . '" alt="' . $rowData['description'] . '" id="smiley' . $rowData['id_smiley'] . '" /> |
||||
| 1100 | <input type="hidden" name="smileys[' . $rowData['id_smiley'] . '][filename]" value="' . $rowData['filename'] . '" /> |
||||
| 1101 | </a>' |
||||
| 1102 | ], |
||||
| 1103 | 'class' => 'imagecolumn', |
||||
| 1104 | ], |
||||
| 1105 | 'code' => [ |
||||
| 1106 | 'header' => [ |
||||
| 1107 | 'value' => $txt['smileys_code'], |
||||
| 1108 | ], |
||||
| 1109 | 'data' => [ |
||||
| 1110 | 'db_htmlsafe' => 'code', |
||||
| 1111 | ], |
||||
| 1112 | 'sort' => [ |
||||
| 1113 | 'default' => 'code', |
||||
| 1114 | 'reverse' => 'code DESC', |
||||
| 1115 | ], |
||||
| 1116 | ], |
||||
| 1117 | 'filename' => [ |
||||
| 1118 | 'header' => [ |
||||
| 1119 | 'value' => $txt['smileys_filename'], |
||||
| 1120 | ], |
||||
| 1121 | 'data' => [ |
||||
| 1122 | 'db_htmlsafe' => 'filename', |
||||
| 1123 | ], |
||||
| 1124 | 'sort' => [ |
||||
| 1125 | 'default' => 'filename', |
||||
| 1126 | 'reverse' => 'filename DESC', |
||||
| 1127 | ], |
||||
| 1128 | ], |
||||
| 1129 | 'location' => [ |
||||
| 1130 | 'header' => [ |
||||
| 1131 | 'value' => $txt['smileys_location'], |
||||
| 1132 | ], |
||||
| 1133 | 'data' => [ |
||||
| 1134 | 'function' => static fn($rowData) => $smiley_locations[$rowData['hidden']], |
||||
| 1135 | ], |
||||
| 1136 | 'sort' => [ |
||||
| 1137 | 'default' => 'hidden', |
||||
| 1138 | 'reverse' => 'hidden DESC', |
||||
| 1139 | ], |
||||
| 1140 | ], |
||||
| 1141 | 'description' => [ |
||||
| 1142 | 'header' => [ |
||||
| 1143 | 'value' => $txt['smileys_description'], |
||||
| 1144 | ], |
||||
| 1145 | 'data' => [ |
||||
| 1146 | 'function' => static function ($rowData) use ($fileFunc) { |
||||
| 1147 | global $context, $txt, $modSettings; |
||||
| 1148 | |||||
| 1149 | if (empty($modSettings['smileys_dir']) || !$fileFunc->isDir($modSettings['smileys_dir'])) |
||||
| 1150 | { |
||||
| 1151 | return htmlspecialchars($rowData['description'], ENT_COMPAT, 'UTF-8'); |
||||
| 1152 | } |
||||
| 1153 | |||||
| 1154 | // Check if there are smileys missing in some sets. |
||||
| 1155 | $missing_sets = []; |
||||
| 1156 | $found_replacement = ''; |
||||
| 1157 | foreach ($context['smiley_sets'] as $smiley_set) |
||||
| 1158 | { |
||||
| 1159 | $filename = $rowData['filename'] . '.' . $smiley_set['ext']; |
||||
| 1160 | if (!$fileFunc->fileExists($modSettings['smileys_dir'] . '/' . $smiley_set['path'] . '/' . $filename)) |
||||
| 1161 | { |
||||
| 1162 | $missing_sets[] = $smiley_set['path']; |
||||
| 1163 | if (possibleSmileEmoji($rowData, $modSettings['smileys_dir'] . '/' . $smiley_set['path'], $smiley_set['ext'])) |
||||
| 1164 | { |
||||
| 1165 | $found_replacement = $rowData['emoji'] . '.svg'; |
||||
| 1166 | } |
||||
| 1167 | } |
||||
| 1168 | } |
||||
| 1169 | |||||
| 1170 | $description = htmlspecialchars($rowData['description'], ENT_COMPAT, 'UTF-8'); |
||||
| 1171 | |||||
| 1172 | if (!empty($missing_sets)) |
||||
| 1173 | { |
||||
| 1174 | $description .= ' |
||||
| 1175 | |||||
| 1176 | <p class="smalltext"> |
||||
| 1177 | <strong>' . $txt['smileys_not_found_in_set'] . '</strong> ' . implode(', ', $missing_sets); |
||||
| 1178 | |||||
| 1179 | if ($found_replacement !== '' && $found_replacement !== '0') |
||||
| 1180 | { |
||||
| 1181 | $description .= '<br />' . sprintf($txt['smileys_emoji_found'], '<img class="smiley emoji" src="' . $context['emoji_path'] . $found_replacement . '" /> '); |
||||
| 1182 | } |
||||
| 1183 | |||||
| 1184 | $description .= ' |
||||
| 1185 | </p>'; |
||||
| 1186 | } |
||||
| 1187 | |||||
| 1188 | return $description; |
||||
| 1189 | }, |
||||
| 1190 | ], |
||||
| 1191 | 'sort' => [ |
||||
| 1192 | 'default' => 'description', |
||||
| 1193 | 'reverse' => 'description DESC', |
||||
| 1194 | ], |
||||
| 1195 | ], |
||||
| 1196 | 'modify' => [ |
||||
| 1197 | 'header' => [ |
||||
| 1198 | 'value' => $txt['smileys_modify'], |
||||
| 1199 | 'class' => 'centertext', |
||||
| 1200 | ], |
||||
| 1201 | 'data' => [ |
||||
| 1202 | 'sprintf' => [ |
||||
| 1203 | 'format' => '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'modifysmiley', 'smiley' => '']) . '%1$d">' . $txt['smileys_modify'] . '</a>', |
||||
| 1204 | 'params' => [ |
||||
| 1205 | 'id_smiley' => false, |
||||
| 1206 | ], |
||||
| 1207 | ], |
||||
| 1208 | 'class' => 'centertext', |
||||
| 1209 | ], |
||||
| 1210 | ], |
||||
| 1211 | 'check' => [ |
||||
| 1212 | 'header' => [ |
||||
| 1213 | 'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />', |
||||
| 1214 | 'class' => 'centertext', |
||||
| 1215 | ], |
||||
| 1216 | 'data' => [ |
||||
| 1217 | 'sprintf' => [ |
||||
| 1218 | 'format' => '<input type="checkbox" name="checked_smileys[]" value="%1$d" class="input_check" />', |
||||
| 1219 | 'params' => [ |
||||
| 1220 | 'id_smiley' => false, |
||||
| 1221 | ], |
||||
| 1222 | ], |
||||
| 1223 | 'class' => 'centertext', |
||||
| 1224 | ], |
||||
| 1225 | ], |
||||
| 1226 | ], |
||||
| 1227 | 'form' => [ |
||||
| 1228 | 'href' => getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editsmileys']), |
||||
| 1229 | 'name' => 'smileyForm', |
||||
| 1230 | ], |
||||
| 1231 | 'additional_rows' => [ |
||||
| 1232 | [ |
||||
| 1233 | 'position' => 'above_column_headers', |
||||
| 1234 | 'value' => $txt['smiley_sets'] . $smileyset_option_list, |
||||
| 1235 | 'class' => 'flow_flex_right', |
||||
| 1236 | ], |
||||
| 1237 | [ |
||||
| 1238 | 'position' => 'below_table_data', |
||||
| 1239 | 'value' => ' |
||||
| 1240 | <select name="smiley_action" onchange="makeChanges(this.value);"> |
||||
| 1241 | <option value="-1">' . $txt['smileys_with_selected'] . ':</option> |
||||
| 1242 | <option value="-1">--------------</option> |
||||
| 1243 | <option value="hidden">' . $txt['smileys_make_hidden'] . '</option> |
||||
| 1244 | <option value="post">' . $txt['smileys_show_on_post'] . '</option> |
||||
| 1245 | <option value="popup">' . $txt['smileys_show_on_popup'] . '</option> |
||||
| 1246 | <option value="delete">' . $txt['smileys_remove'] . '</option> |
||||
| 1247 | </select> |
||||
| 1248 | <noscript> |
||||
| 1249 | <input type="submit" name="perform_action" value="' . $txt['go'] . '" class="right_submit" /> |
||||
| 1250 | </noscript>', |
||||
| 1251 | 'class' => 'righttext', |
||||
| 1252 | ], |
||||
| 1253 | ], |
||||
| 1254 | ]; |
||||
| 1255 | |||||
| 1256 | createList($listOptions); |
||||
| 1257 | |||||
| 1258 | // The list is the only thing to show, so make it the main template. |
||||
| 1259 | $context['default_list'] = 'smiley_list'; |
||||
| 1260 | $context['sub_template'] = 'show_list'; |
||||
| 1261 | } |
||||
| 1262 | // Modifying smileys. |
||||
| 1263 | elseif ($context['sub_action'] === 'modifysmiley') |
||||
| 1264 | { |
||||
| 1265 | // Get a list of all known smiley sets. |
||||
| 1266 | $context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir']; |
||||
| 1267 | $context['selected_set'] = $modSettings['smiley_sets_default']; |
||||
| 1268 | |||||
| 1269 | $this->loadSmileySets(); |
||||
| 1270 | |||||
| 1271 | // Get all possible filenames for the smileys. |
||||
| 1272 | $context['filenames'] = $this->getAllPossibleFilenamesForTheSmileys($context['smiley_sets']); |
||||
| 1273 | |||||
| 1274 | $thisSmiley = (int) $this->_req->query->smiley; |
||||
| 1275 | $context['current_smiley'] = getSmiley($thisSmiley); |
||||
| 1276 | $context['current_smiley']['code'] = htmlspecialchars($context['current_smiley']['code'], ENT_COMPAT, 'UTF-8'); |
||||
| 1277 | $context['current_smiley']['filename'] = htmlspecialchars($context['current_smiley']['filename'], ENT_COMPAT, 'UTF-8'); |
||||
| 1278 | $context['current_smiley']['description'] = htmlspecialchars($context['current_smiley']['description'], ENT_COMPAT, 'UTF-8'); |
||||
| 1279 | |||||
| 1280 | if (isset($context['filenames'][strtolower($context['current_smiley']['filename'])])) |
||||
| 1281 | { |
||||
| 1282 | $context['filenames'][strtolower($context['current_smiley']['filename'])]['selected'] = true; |
||||
| 1283 | } |
||||
| 1284 | } |
||||
| 1285 | } |
||||
| 1286 | |||||
| 1287 | /** |
||||
| 1288 | * Allows to edit the message icons. |
||||
| 1289 | * |
||||
| 1290 | * @event integrate_list_message_icon_list |
||||
| 1291 | */ |
||||
| 1292 | public function action_editicon(): void |
||||
| 1293 | { |
||||
| 1294 | global $context, $settings, $txt; |
||||
| 1295 | |||||
| 1296 | $fileFunc = FileFunctions::instance(); |
||||
| 1297 | require_once(SUBSDIR . '/MessageIcons.subs.php'); |
||||
| 1298 | |||||
| 1299 | // Get a list of icons. |
||||
| 1300 | $context['icons'] = fetchMessageIconsDetails(); |
||||
| 1301 | |||||
| 1302 | // Submitting a form? |
||||
| 1303 | if (isset($this->_req->post->icons_save)) |
||||
| 1304 | { |
||||
| 1305 | checkSession(); |
||||
| 1306 | |||||
| 1307 | // Deleting icons? |
||||
| 1308 | if (isset($this->_req->post->delete) && !empty($this->_req->post->checked_icons)) |
||||
| 1309 | { |
||||
| 1310 | $deleteIcons = []; |
||||
| 1311 | foreach ($this->_req->post->checked_icons as $icon) |
||||
| 1312 | { |
||||
| 1313 | $deleteIcons[] = (int) $icon; |
||||
| 1314 | } |
||||
| 1315 | |||||
| 1316 | // Do the actual delete! |
||||
| 1317 | deleteMessageIcons($deleteIcons); |
||||
| 1318 | } |
||||
| 1319 | // Editing/Adding an icon? |
||||
| 1320 | elseif ($context['sub_action'] === 'editicon' && isset($this->_req->query->icon)) |
||||
| 1321 | { |
||||
| 1322 | $this->_req->query->icon = (int) $this->_req->query->icon; |
||||
| 1323 | |||||
| 1324 | // Do some preparation with the data... like check the icon exists *somewhere* |
||||
| 1325 | if (strpos($this->_req->post->icon_filename, '.png') !== false) |
||||
| 1326 | { |
||||
| 1327 | $this->_req->post->icon_filename = substr($this->_req->post->icon_filename, 0, -4); |
||||
| 1328 | } |
||||
| 1329 | |||||
| 1330 | if (!$fileFunc->fileExists($settings['default_theme_dir'] . '/images/post/' . $this->_req->post->icon_filename . '.png')) |
||||
| 1331 | { |
||||
| 1332 | throw new Exception('icon_not_found', false); |
||||
| 1333 | } |
||||
| 1334 | |||||
| 1335 | // There is a 16-character limit on message icons... |
||||
| 1336 | if (strlen($this->_req->post->icon_filename) > 16) |
||||
| 1337 | { |
||||
| 1338 | throw new Exception('icon_name_too_long', false); |
||||
| 1339 | } |
||||
| 1340 | |||||
| 1341 | if ($this->_req->post->icon_location === $this->_req->query->icon && $this->_req->query->icon !== 0) |
||||
| 1342 | { |
||||
| 1343 | throw new Exception('icon_after_itself', false); |
||||
| 1344 | } |
||||
| 1345 | |||||
| 1346 | // First do the sorting... if this is an edit reduce the order of everything after it by one ;) |
||||
| 1347 | if ($this->_req->query->icon !== 0) |
||||
| 1348 | { |
||||
| 1349 | $oldOrder = $context['icons'][$this->_req->query->icon]['true_order']; |
||||
| 1350 | foreach ($context['icons'] as $id => $data) |
||||
| 1351 | { |
||||
| 1352 | if ($data['true_order'] > $oldOrder) |
||||
| 1353 | { |
||||
| 1354 | $context['icons'][$id]['true_order']--; |
||||
| 1355 | } |
||||
| 1356 | } |
||||
| 1357 | } |
||||
| 1358 | |||||
| 1359 | // If there are no existing icons and this is a new one, set the id to 1 (mainly for non-mysql) |
||||
| 1360 | if ($this->_req->query->icon === 0 && empty($context['icons'])) |
||||
| 1361 | { |
||||
| 1362 | $this->_req->query->icon = 1; |
||||
| 1363 | } |
||||
| 1364 | |||||
| 1365 | // Get the new order. |
||||
| 1366 | $newOrder = $this->_req->post->icon_location == 0 ? 0 : $context['icons'][$this->_req->post->icon_location]['true_order'] + 1; |
||||
| 1367 | |||||
| 1368 | // Do the same, but with the one that used to be after this icon, done to avoid conflict. |
||||
| 1369 | foreach ($context['icons'] as $id => $data) |
||||
| 1370 | { |
||||
| 1371 | if ($data['true_order'] >= $newOrder) |
||||
| 1372 | { |
||||
| 1373 | $context['icons'][$id]['true_order']++; |
||||
| 1374 | } |
||||
| 1375 | } |
||||
| 1376 | |||||
| 1377 | // Finally set the current icon's position! |
||||
| 1378 | $context['icons'][$this->_req->query->icon]['true_order'] = $newOrder; |
||||
| 1379 | |||||
| 1380 | // Simply replace the existing data for the other bits. |
||||
| 1381 | $context['icons'][$this->_req->query->icon]['title'] = $this->_req->post->icon_description; |
||||
| 1382 | $context['icons'][$this->_req->query->icon]['filename'] = $this->_req->post->icon_filename; |
||||
| 1383 | $context['icons'][$this->_req->query->icon]['board_id'] = (int) $this->_req->post->icon_board; |
||||
| 1384 | |||||
| 1385 | // Do a huge replace ;) |
||||
| 1386 | $iconInsert = []; |
||||
| 1387 | $iconInsert_new = []; |
||||
| 1388 | foreach ($context['icons'] as $id => $icon) |
||||
| 1389 | { |
||||
| 1390 | if ($id != 0) |
||||
| 1391 | { |
||||
| 1392 | $iconInsert[] = [$id, $icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']]; |
||||
| 1393 | } |
||||
| 1394 | else |
||||
| 1395 | { |
||||
| 1396 | $iconInsert_new[] = [$icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']]; |
||||
| 1397 | } |
||||
| 1398 | } |
||||
| 1399 | |||||
| 1400 | updateMessageIcon($iconInsert); |
||||
| 1401 | |||||
| 1402 | if (!empty($iconInsert_new)) |
||||
| 1403 | { |
||||
| 1404 | addMessageIcon($iconInsert_new); |
||||
| 1405 | |||||
| 1406 | // Flush the cache so the changes are reflected |
||||
| 1407 | Cache::instance()->remove('posting_icons-' . (int) $this->_req->post->icon_board); |
||||
| 1408 | } |
||||
| 1409 | } |
||||
| 1410 | |||||
| 1411 | // Unless we're adding a new thing, we'll escape |
||||
| 1412 | if (!isset($this->_req->post->add)) |
||||
| 1413 | { |
||||
| 1414 | Cache::instance()->remove('posting_icons-0'); |
||||
| 1415 | redirectexit('action=admin;area=smileys;sa=editicons'); |
||||
| 1416 | } |
||||
| 1417 | } |
||||
| 1418 | |||||
| 1419 | $context[$context['admin_menu_name']]['current_subsection'] = 'editicons'; |
||||
| 1420 | $token = createToken('admin-sort'); |
||||
| 1421 | $listOptions = [ |
||||
| 1422 | 'id' => 'message_icon_list', |
||||
| 1423 | 'title' => $txt['icons_edit_message_icons'], |
||||
| 1424 | 'sortable' => true, |
||||
| 1425 | 'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editicons']), |
||||
| 1426 | 'get_items' => [ |
||||
| 1427 | 'function' => fn() => $this->list_fetchMessageIconsDetails(), |
||||
| 1428 | ], |
||||
| 1429 | 'no_items_label' => $txt['icons_no_entries'], |
||||
| 1430 | 'columns' => [ |
||||
| 1431 | 'icon' => [ |
||||
| 1432 | 'data' => [ |
||||
| 1433 | 'sprintf' => [ |
||||
| 1434 | 'format' => '<img src="%1$s" alt="%2$s" />', |
||||
| 1435 | 'params' => [ |
||||
| 1436 | 'image_url' => false, |
||||
| 1437 | 'filename' => true, |
||||
| 1438 | ], |
||||
| 1439 | ], |
||||
| 1440 | 'class' => 'centertext', |
||||
| 1441 | ], |
||||
| 1442 | ], |
||||
| 1443 | 'filename' => [ |
||||
| 1444 | 'header' => [ |
||||
| 1445 | 'value' => $txt['smileys_filename'], |
||||
| 1446 | ], |
||||
| 1447 | 'data' => [ |
||||
| 1448 | 'sprintf' => [ |
||||
| 1449 | 'format' => '%1$s.png', |
||||
| 1450 | 'params' => [ |
||||
| 1451 | 'filename' => true, |
||||
| 1452 | ], |
||||
| 1453 | ], |
||||
| 1454 | ], |
||||
| 1455 | ], |
||||
| 1456 | 'tooltip' => [ |
||||
| 1457 | 'header' => [ |
||||
| 1458 | 'value' => $txt['smileys_description'], |
||||
| 1459 | ], |
||||
| 1460 | 'data' => [ |
||||
| 1461 | 'db_htmlsafe' => 'title', |
||||
| 1462 | ], |
||||
| 1463 | ], |
||||
| 1464 | 'board' => [ |
||||
| 1465 | 'header' => [ |
||||
| 1466 | 'value' => $txt['icons_board'], |
||||
| 1467 | ], |
||||
| 1468 | 'data' => [ |
||||
| 1469 | 'db' => 'board', |
||||
| 1470 | ], |
||||
| 1471 | ], |
||||
| 1472 | 'modify' => [ |
||||
| 1473 | 'header' => [ |
||||
| 1474 | 'value' => $txt['smileys_modify'], |
||||
| 1475 | ], |
||||
| 1476 | 'data' => [ |
||||
| 1477 | 'sprintf' => [ |
||||
| 1478 | 'format' => '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editicon', 'icon' => '']) . '%1$s">' . $txt['smileys_modify'] . '</a>', |
||||
| 1479 | 'params' => [ |
||||
| 1480 | 'id' => false, |
||||
| 1481 | ], |
||||
| 1482 | ], |
||||
| 1483 | ], |
||||
| 1484 | ], |
||||
| 1485 | 'check' => [ |
||||
| 1486 | 'header' => [ |
||||
| 1487 | 'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />', |
||||
| 1488 | 'class' => 'centertext', |
||||
| 1489 | ], |
||||
| 1490 | 'data' => [ |
||||
| 1491 | 'sprintf' => [ |
||||
| 1492 | 'format' => '<input type="checkbox" name="checked_icons[]" value="%1$d" class="input_check" />', |
||||
| 1493 | 'params' => [ |
||||
| 1494 | 'id' => false, |
||||
| 1495 | ], |
||||
| 1496 | ], |
||||
| 1497 | 'class' => 'centertext', |
||||
| 1498 | ], |
||||
| 1499 | ], |
||||
| 1500 | ], |
||||
| 1501 | 'form' => [ |
||||
| 1502 | 'href' => getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editicons']), |
||||
| 1503 | 'hidden_fields' => [ |
||||
| 1504 | 'icons_save' => 1, |
||||
| 1505 | ] |
||||
| 1506 | ], |
||||
| 1507 | 'additional_rows' => [ |
||||
| 1508 | [ |
||||
| 1509 | 'position' => 'below_table_data', |
||||
| 1510 | 'class' => 'submitbutton', |
||||
| 1511 | 'value' => ' |
||||
| 1512 | <a class="linkbutton" href="' . getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'editicon']) . '">' . $txt['icons_add_new'] . '</a> |
||||
| 1513 | <input type="submit" name="delete" value="' . $txt['quickmod_delete_selected'] . '" onclick="return confirm(\'' . $txt['icons_confirm'] . '\');" />', |
||||
| 1514 | ], |
||||
| 1515 | [ |
||||
| 1516 | 'position' => 'after_title', |
||||
| 1517 | 'value' => $txt['icons_reorder_note'], |
||||
| 1518 | ], |
||||
| 1519 | ], |
||||
| 1520 | 'javascript' => ' |
||||
| 1521 | $().elkSortable({ |
||||
| 1522 | sa: "messageiconorder", |
||||
| 1523 | error: "' . $txt['admin_order_error'] . '", |
||||
| 1524 | title: "' . $txt['admin_order_title'] . '", |
||||
| 1525 | placeholder: "ui-state-highlight", |
||||
| 1526 | href: "?action=admin;area=smileys;sa=editicons", |
||||
| 1527 | token: {token_var: "' . $token['admin-sort_token_var'] . '", token_id: "' . $token['admin-sort_token'] . '"} |
||||
| 1528 | }); |
||||
| 1529 | ', |
||||
| 1530 | ]; |
||||
| 1531 | |||||
| 1532 | createList($listOptions); |
||||
| 1533 | |||||
| 1534 | // If we're adding/editing an icon we'll need a list of boards |
||||
| 1535 | if ($context['sub_action'] === 'editicon' || isset($this->_req->post->add)) |
||||
| 1536 | { |
||||
| 1537 | // Force the sub_template just in case. |
||||
| 1538 | $context['sub_template'] = 'editicon'; |
||||
| 1539 | $context['new_icon'] = !isset($this->_req->query->icon); |
||||
| 1540 | |||||
| 1541 | // Get the properties of the current icon from the icon list. |
||||
| 1542 | if (!$context['new_icon']) |
||||
| 1543 | { |
||||
| 1544 | $context['icon'] = $context['icons'][$this->_req->query->icon]; |
||||
| 1545 | } |
||||
| 1546 | |||||
| 1547 | // Get a list of boards needed for assigning this icon to a specific board. |
||||
| 1548 | $boardListOptions = [ |
||||
| 1549 | 'selected_board' => $context['icon']['board_id'] ?? 0, |
||||
| 1550 | ]; |
||||
| 1551 | require_once(SUBSDIR . '/Boards.subs.php'); |
||||
| 1552 | $context += getBoardList($boardListOptions); |
||||
| 1553 | } |
||||
| 1554 | } |
||||
| 1555 | |||||
| 1556 | /** |
||||
| 1557 | * Callback function for createList(). |
||||
| 1558 | */ |
||||
| 1559 | public function list_fetchMessageIconsDetails() |
||||
| 1560 | { |
||||
| 1561 | return fetchMessageIconsDetails(); |
||||
| 1562 | } |
||||
| 1563 | |||||
| 1564 | /** |
||||
| 1565 | * Allows to edit smileys order. |
||||
| 1566 | */ |
||||
| 1567 | public function action_setorder(): void |
||||
| 1568 | { |
||||
| 1569 | global $context, $txt; |
||||
| 1570 | |||||
| 1571 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 1572 | $context['sub_template'] = 'setorder'; |
||||
| 1573 | |||||
| 1574 | // Move smileys to another position. |
||||
| 1575 | if (isset($this->_req->query->reorder)) |
||||
| 1576 | { |
||||
| 1577 | $location = empty($this->_req->query->location) || $this->_req->query->location !== 'popup' ? 0 : 2; |
||||
| 1578 | $source = $this->_req->getQuery('source', 'intval', 0); |
||||
| 1579 | $after = $this->_req->getQuery('after', 'intval', 0); |
||||
| 1580 | $row = $this->_req->getQuery('row', 'intval', 0); |
||||
| 1581 | |||||
| 1582 | checkSession('get'); |
||||
| 1583 | |||||
| 1584 | if (empty($source)) |
||||
| 1585 | { |
||||
| 1586 | throw new Exception('smiley_not_found', false); |
||||
| 1587 | } |
||||
| 1588 | |||||
| 1589 | $smiley = []; |
||||
| 1590 | |||||
| 1591 | if (!empty($after)) |
||||
| 1592 | { |
||||
| 1593 | $smiley = getSmileyPosition($location, $after); |
||||
| 1594 | if (empty($smiley)) |
||||
| 1595 | { |
||||
| 1596 | throw new Exception('smiley_not_found'); |
||||
| 1597 | } |
||||
| 1598 | } |
||||
| 1599 | else |
||||
| 1600 | { |
||||
| 1601 | $smiley['row'] = $row; |
||||
| 1602 | $smiley['order'] = -1; |
||||
| 1603 | $smiley['location'] = $location; |
||||
| 1604 | } |
||||
| 1605 | |||||
| 1606 | moveSmileyPosition($smiley, $source); |
||||
| 1607 | } |
||||
| 1608 | |||||
| 1609 | $context['smileys'] = getSmileys(); |
||||
| 1610 | $context['move_smiley'] = $this->_req->getQuery('move', 'intval', 0); |
||||
| 1611 | |||||
| 1612 | // Make sure all rows are sequential. |
||||
| 1613 | foreach (array_keys($context['smileys']) as $location) |
||||
| 1614 | { |
||||
| 1615 | $context['smileys'][$location] = [ |
||||
| 1616 | 'id' => $location, |
||||
| 1617 | 'title' => $location === 'postform' ? $txt['smileys_location_form'] : $txt['smileys_location_popup'], |
||||
| 1618 | 'description' => $location === 'postform' ? $txt['smileys_location_form_description'] : $txt['smileys_location_popup_description'], |
||||
| 1619 | 'last_row' => count($context['smileys'][$location]['rows']), |
||||
| 1620 | 'rows' => array_values($context['smileys'][$location]['rows']), |
||||
| 1621 | ]; |
||||
| 1622 | } |
||||
| 1623 | |||||
| 1624 | // Check & fix smileys that are not ordered properly in the database. |
||||
| 1625 | foreach (array_keys($context['smileys']) as $location) |
||||
| 1626 | { |
||||
| 1627 | foreach ($context['smileys'][$location]['rows'] as $id => $smiley_row) |
||||
| 1628 | { |
||||
| 1629 | // Fix empty rows if any. |
||||
| 1630 | if ($id != $smiley_row[0]['row']) |
||||
| 1631 | { |
||||
| 1632 | updateSmileyRow($id, $smiley_row[0]['row'], $location); |
||||
| 1633 | |||||
| 1634 | // Only change the first row value of the first smiley (we don't need the others :P). |
||||
| 1635 | $context['smileys'][$location]['rows'][$id][0]['row'] = $id; |
||||
| 1636 | } |
||||
| 1637 | |||||
| 1638 | // Make sure the smiley order is always sequential. |
||||
| 1639 | foreach ($smiley_row as $order_id => $smiley) |
||||
| 1640 | { |
||||
| 1641 | if ($order_id != $smiley['order']) |
||||
| 1642 | { |
||||
| 1643 | updateSmileyOrder($smiley['id'], $order_id); |
||||
| 1644 | } |
||||
| 1645 | } |
||||
| 1646 | } |
||||
| 1647 | } |
||||
| 1648 | |||||
| 1649 | $this->clearSmileyCache(); |
||||
| 1650 | |||||
| 1651 | createToken('admin-sort'); |
||||
| 1652 | } |
||||
| 1653 | |||||
| 1654 | /** |
||||
| 1655 | * Install a smiley set. |
||||
| 1656 | */ |
||||
| 1657 | public function action_install(): void |
||||
| 1658 | { |
||||
| 1659 | global $modSettings, $context, $txt, $scripturl; |
||||
| 1660 | |||||
| 1661 | isAllowedTo('manage_smileys'); |
||||
| 1662 | checkSession('request'); |
||||
| 1663 | |||||
| 1664 | // One of these two may be necessary |
||||
| 1665 | Txt::load('Errors'); |
||||
| 1666 | Txt::load('Packages'); |
||||
| 1667 | |||||
| 1668 | $fileFunc = FileFunctions::instance(); |
||||
| 1669 | require_once(SUBSDIR . '/Smileys.subs.php'); |
||||
| 1670 | require_once(SUBSDIR . '/Package.subs.php'); |
||||
| 1671 | |||||
| 1672 | // Installing unless proven otherwise |
||||
| 1673 | $testing = false; |
||||
| 1674 | $destination = ''; |
||||
| 1675 | $name = ''; |
||||
| 1676 | $base_name = ''; |
||||
| 1677 | |||||
| 1678 | if (isset($this->_req->query->set_gz)) |
||||
| 1679 | { |
||||
| 1680 | $base_name = strtr(basename($this->_req->query->set_gz), ':/', '-_'); |
||||
| 1681 | $name = Util::htmlspecialchars(strtok(basename($this->_req->query->set_gz), '.')); |
||||
| 1682 | $context['filename'] = $base_name; |
||||
| 1683 | |||||
| 1684 | $destination = BOARDDIR . '/packages/' . $base_name; |
||||
| 1685 | |||||
| 1686 | if ($fileFunc->fileExists($destination)) |
||||
| 1687 | { |
||||
| 1688 | throw new Exception('package_upload_error_exists'); |
||||
| 1689 | } |
||||
| 1690 | |||||
| 1691 | // Let's copy it to the packages directory |
||||
| 1692 | file_put_contents($destination, fetch_web_data($this->_req->query->set_gz)); |
||||
| 1693 | $testing = true; |
||||
| 1694 | } |
||||
| 1695 | elseif (isset($this->_req->query->package)) |
||||
| 1696 | { |
||||
| 1697 | $base_name = basename($this->_req->query->package); |
||||
| 1698 | $name = Util::htmlspecialchars(strtok(basename($this->_req->query->package), '.')); |
||||
| 1699 | $context['filename'] = $base_name; |
||||
| 1700 | |||||
| 1701 | $destination = BOARDDIR . '/packages/' . basename($this->_req->query->package); |
||||
| 1702 | } |
||||
| 1703 | |||||
| 1704 | if (!$fileFunc->fileExists($destination)) |
||||
| 1705 | { |
||||
| 1706 | throw new Exception('package_no_file', false); |
||||
| 1707 | } |
||||
| 1708 | |||||
| 1709 | // Make sure temp directory exists and is empty. |
||||
| 1710 | if ($fileFunc->fileExists(BOARDDIR . '/packages/temp')) |
||||
| 1711 | { |
||||
| 1712 | deltree(BOARDDIR . '/packages/temp', false); |
||||
| 1713 | } |
||||
| 1714 | |||||
| 1715 | if (!mktree(BOARDDIR . '/packages/temp')) |
||||
| 1716 | { |
||||
| 1717 | deltree(BOARDDIR . '/packages/temp', false); |
||||
| 1718 | $chmod_control = new PackageChmod(); |
||||
| 1719 | $chmod_control->createChmodControl( |
||||
| 1720 | [BOARDDIR . '/packages/temp/delme.tmp'], |
||||
| 1721 | [ |
||||
| 1722 | 'destination_url' => $scripturl . '?action=admin;area=smileys;sa=install;set_gz=' . $this->_req->query->set_gz, |
||||
| 1723 | 'crash_on_error' => true |
||||
| 1724 | ] |
||||
| 1725 | ); |
||||
| 1726 | |||||
| 1727 | deltree(BOARDDIR . '/packages/temp', false); |
||||
| 1728 | throw new Exception('package_cant_download', false); |
||||
| 1729 | } |
||||
| 1730 | |||||
| 1731 | $extracted = read_tgz_file($destination, BOARDDIR . '/packages/temp'); |
||||
| 1732 | |||||
| 1733 | // @todo needs to change the URL in the next line ;) |
||||
| 1734 | if (!$extracted) |
||||
| 1735 | { |
||||
| 1736 | throw new Exception('packageget_unable', false, ['https://custom.elkarte.net/index.php?action=search;type=12;basic_search=' . $name]); |
||||
| 1737 | } |
||||
| 1738 | |||||
| 1739 | if (!$fileFunc->fileExists(BOARDDIR . '/packages/temp/package-info.xml')) |
||||
| 1740 | { |
||||
| 1741 | foreach ($extracted as $file) |
||||
| 1742 | { |
||||
| 1743 | if (basename($file['filename']) === 'package-info.xml') |
||||
| 1744 | { |
||||
| 1745 | $base_path = dirname($file['filename']) . '/'; |
||||
| 1746 | break; |
||||
| 1747 | } |
||||
| 1748 | } |
||||
| 1749 | } |
||||
| 1750 | |||||
| 1751 | if (!isset($base_path)) |
||||
| 1752 | { |
||||
| 1753 | $base_path = ''; |
||||
| 1754 | } |
||||
| 1755 | |||||
| 1756 | if (!$fileFunc->fileExists(BOARDDIR . '/packages/temp/' . $base_path . 'package-info.xml')) |
||||
| 1757 | { |
||||
| 1758 | throw new Exception('package_get_error_missing_xml', false); |
||||
| 1759 | } |
||||
| 1760 | |||||
| 1761 | $smileyInfo = getPackageInfo($context['filename']); |
||||
| 1762 | if (!is_array($smileyInfo)) |
||||
| 1763 | { |
||||
| 1764 | throw new Exception($smileyInfo); |
||||
| 1765 | } |
||||
| 1766 | |||||
| 1767 | // See if it is installed? |
||||
| 1768 | if (isSmileySetInstalled($smileyInfo['id'])) |
||||
| 1769 | { |
||||
| 1770 | Errors::instance()->fatal_lang_error('package_installed_warning1'); |
||||
| 1771 | } |
||||
| 1772 | |||||
| 1773 | // Everything is fine, now it's time to do something, first we test |
||||
| 1774 | $parser = new PackageParser(); |
||||
| 1775 | $actions = $parser->parsePackageInfo($smileyInfo['xml'], true); |
||||
| 1776 | |||||
| 1777 | $context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'smileys', 'sa' => 'install', 'package' => $base_name]); |
||||
| 1778 | $context['has_failure'] = false; |
||||
| 1779 | $context['actions'] = []; |
||||
| 1780 | $context['ftp_needed'] = false; |
||||
| 1781 | |||||
| 1782 | $bbc_parser = ParserWrapper::instance(); |
||||
| 1783 | |||||
| 1784 | foreach ($actions as $action) |
||||
| 1785 | { |
||||
| 1786 | if ($action['type'] === 'readme' || $action['type'] === 'license') |
||||
| 1787 | { |
||||
| 1788 | $type = 'package_' . $action['type']; |
||||
| 1789 | if ($fileFunc->fileExists(BOARDDIR . '/packages/temp/' . $base_path . $action['filename'])) |
||||
| 1790 | { |
||||
| 1791 | $context[$type] = htmlspecialchars(trim(file_get_contents(BOARDDIR . '/packages/temp/' . $base_path . $action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8'); |
||||
| 1792 | } |
||||
| 1793 | elseif ($fileFunc->fileExists($action['filename'])) |
||||
| 1794 | { |
||||
| 1795 | $context[$type] = htmlspecialchars(trim(file_get_contents($action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8'); |
||||
| 1796 | } |
||||
| 1797 | |||||
| 1798 | if (!empty($action['parse_bbc'])) |
||||
| 1799 | { |
||||
| 1800 | require_once(SUBSDIR . '/Post.subs.php'); |
||||
| 1801 | preparsecode($context[$type]); |
||||
| 1802 | $context[$type] = $bbc_parser->parsePackage($context[$type]); |
||||
| 1803 | } |
||||
| 1804 | else |
||||
| 1805 | { |
||||
| 1806 | $context[$type] = nl2br($context[$type]); |
||||
| 1807 | } |
||||
| 1808 | } |
||||
| 1809 | elseif ($action['type'] === 'require-dir') |
||||
| 1810 | { |
||||
| 1811 | // Do this one... |
||||
| 1812 | $thisAction = [ |
||||
| 1813 | 'type' => $txt['package_extract'] . ' ' . $txt['package_tree'], |
||||
| 1814 | 'action' => Util::htmlspecialchars(strtr($action['destination'], [BOARDDIR => '.'])) |
||||
| 1815 | ]; |
||||
| 1816 | |||||
| 1817 | $file = BOARDDIR . '/packages/temp/' . $base_path . $action['filename']; |
||||
| 1818 | if (isset($action['filename']) && (!$fileFunc->fileExists($file) || !$fileFunc->isWritable(dirname($action['destination'])))) |
||||
| 1819 | { |
||||
| 1820 | $context['has_failure'] = true; |
||||
| 1821 | |||||
| 1822 | $thisAction += [ |
||||
| 1823 | 'description' => $txt['package_action_error'], |
||||
| 1824 | 'failed' => true, |
||||
| 1825 | ]; |
||||
| 1826 | } |
||||
| 1827 | |||||
| 1828 | // Show a description for the action if one is provided |
||||
| 1829 | if (empty($thisAction['description'])) |
||||
| 1830 | { |
||||
| 1831 | $thisAction['description'] = $action['description'] ?? ''; |
||||
| 1832 | } |
||||
| 1833 | |||||
| 1834 | $context['actions'][] = $thisAction; |
||||
| 1835 | } |
||||
| 1836 | elseif ($action['type'] === 'credits') |
||||
| 1837 | { |
||||
| 1838 | // Time to build the billboard |
||||
| 1839 | $credits_tag = [ |
||||
| 1840 | 'url' => $action['url'], |
||||
| 1841 | 'license' => $action['license'], |
||||
| 1842 | 'copyright' => $action['copyright'], |
||||
| 1843 | 'title' => $action['title'], |
||||
| 1844 | ]; |
||||
| 1845 | } |
||||
| 1846 | } |
||||
| 1847 | |||||
| 1848 | if ($testing) |
||||
| 1849 | { |
||||
| 1850 | $context['sub_template'] = 'view_package'; |
||||
| 1851 | $context['uninstalling'] = false; |
||||
| 1852 | $context['is_installed'] = false; |
||||
| 1853 | $context['package_name'] = $smileyInfo['name']; |
||||
| 1854 | theme()->getTemplates()->load('Packages'); |
||||
| 1855 | } |
||||
| 1856 | // Do the actual install |
||||
| 1857 | else |
||||
| 1858 | { |
||||
| 1859 | foreach ($context['actions'] as $action) |
||||
| 1860 | { |
||||
| 1861 | updateSettings([ |
||||
| 1862 | 'smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . basename($action['action']), |
||||
| 1863 | 'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $smileyInfo['name'] . (count($context['actions']) > 1 ? ' ' . (empty($action['description']) ? basename($action['action']) : Util::htmlspecialchars($action['description'])) : ''), |
||||
| 1864 | ]); |
||||
| 1865 | } |
||||
| 1866 | |||||
| 1867 | package_flush_cache(); |
||||
| 1868 | |||||
| 1869 | // Time to tell pacman we have a new package installed! |
||||
| 1870 | package_put_contents(BOARDDIR . '/packages/installed.list', time()); |
||||
| 1871 | |||||
| 1872 | // Credits tag? |
||||
| 1873 | $credits_tag = (empty($credits_tag)) ? '' : serialize($credits_tag); |
||||
| 1874 | $installed = [ |
||||
| 1875 | 'filename' => $smileyInfo['filename'], |
||||
| 1876 | 'name' => $smileyInfo['name'], |
||||
| 1877 | 'package_id' => $smileyInfo['id'], |
||||
| 1878 | 'version' => $smileyInfo['filename'], |
||||
| 1879 | 'id_member' => $this->user->id, |
||||
| 1880 | 'member_name' => $this->user->name, |
||||
| 1881 | 'credits_tag' => $credits_tag, |
||||
| 1882 | ]; |
||||
| 1883 | logPackageInstall($installed); |
||||
| 1884 | |||||
| 1885 | logAction('install_package', ['package' => Util::htmlspecialchars($smileyInfo['name']), 'version' => Util::htmlspecialchars($smileyInfo['version'])], 'admin'); |
||||
| 1886 | |||||
| 1887 | $this->clearSmileyCache(); |
||||
| 1888 | } |
||||
| 1889 | |||||
| 1890 | if ($fileFunc->fileExists(BOARDDIR . '/packages/temp')) |
||||
| 1891 | { |
||||
| 1892 | deltree(BOARDDIR . '/packages/temp'); |
||||
| 1893 | } |
||||
| 1894 | |||||
| 1895 | if (!$testing) |
||||
| 1896 | { |
||||
| 1897 | redirectexit('action=admin;area=smileys'); |
||||
| 1898 | } |
||||
| 1899 | } |
||||
| 1900 | |||||
| 1901 | /** |
||||
| 1902 | * Load known smiley set information into context |
||||
| 1903 | * |
||||
| 1904 | * @return void |
||||
| 1905 | */ |
||||
| 1906 | public function loadSmileySets(): void |
||||
| 1907 | { |
||||
| 1908 | global $context, $modSettings; |
||||
| 1909 | |||||
| 1910 | $set_paths = explode(',', $modSettings['smiley_sets_known']); |
||||
| 1911 | $set_names = explode("\n", $modSettings['smiley_sets_names']); |
||||
| 1912 | $set_exts = isset($modSettings['smiley_sets_extensions']) |
||||
| 1913 | ? explode(',', $modSettings['smiley_sets_extensions']) |
||||
| 1914 | : setSmileyExtensionArray(); |
||||
| 1915 | |||||
| 1916 | foreach ($set_paths as $i => $set) |
||||
| 1917 | { |
||||
| 1918 | $context['smiley_sets'][$i] = [ |
||||
| 1919 | 'id' => $i, |
||||
| 1920 | 'path' => htmlspecialchars($set, ENT_COMPAT), |
||||
| 1921 | 'name' => htmlspecialchars(stripslashes($set_names[$i]), ENT_COMPAT), |
||||
| 1922 | 'selected' => $set === $modSettings['smiley_sets_default'], |
||||
| 1923 | 'ext' => Util::htmlspecialchars($set_exts[$i]), |
||||
| 1924 | ]; |
||||
| 1925 | } |
||||
| 1926 | } |
||||
| 1927 | |||||
| 1928 | /** |
||||
| 1929 | * Perhaps a longer name for the function would better describe what this does. So it will |
||||
| 1930 | * search group of directories and return just the unique filenames, dis-regarding the extension. |
||||
| 1931 | * this allows us to match by name across sets that have different extensions |
||||
| 1932 | * |
||||
| 1933 | * @param array $smiley_sets array of smiley sets (end directory names) to search |
||||
| 1934 | * @return array of unique smiley names across one or many "sets" |
||||
| 1935 | */ |
||||
| 1936 | public function getAllPossibleFilenamesForTheSmileys(array $smiley_sets): array |
||||
| 1937 | { |
||||
| 1938 | global $context, $modSettings; |
||||
| 1939 | |||||
| 1940 | $filenames = []; |
||||
| 1941 | $fileFunc = FileFunctions::instance(); |
||||
| 1942 | |||||
| 1943 | $smileys_dir = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir']; |
||||
| 1944 | if (!$fileFunc->isDir($smileys_dir)) |
||||
| 1945 | { |
||||
| 1946 | return []; |
||||
| 1947 | } |
||||
| 1948 | |||||
| 1949 | foreach ($smiley_sets as $smiley_set) |
||||
| 1950 | { |
||||
| 1951 | $smiles = $fileFunc->listTree($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path'])); |
||||
| 1952 | foreach ($smiles as $smile) |
||||
| 1953 | { |
||||
| 1954 | if (in_array($smile['filename'], ['.', '..', '.htaccess', 'index.php'], true)) |
||||
| 1955 | { |
||||
| 1956 | continue; |
||||
| 1957 | } |
||||
| 1958 | |||||
| 1959 | $key = strtolower(pathinfo($smile['filename'], PATHINFO_FILENAME)); |
||||
|
0 ignored issues
–
show
It seems like
pathinfo($smile['filenam...ller\PATHINFO_FILENAME) can also be of type array; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 1960 | if (in_array($key, $filenames, true)) |
||||
| 1961 | { |
||||
| 1962 | continue; |
||||
| 1963 | } |
||||
| 1964 | |||||
| 1965 | if (!in_array(strtolower(pathinfo($smile['filename'], PATHINFO_EXTENSION)), $this->_smiley_types, true)) |
||||
| 1966 | { |
||||
| 1967 | continue; |
||||
| 1968 | } |
||||
| 1969 | |||||
| 1970 | $filenames[strtolower($key)] = [ |
||||
| 1971 | 'id' => Util::htmlspecialchars($key, ENT_COMPAT, 'UTF-8'), |
||||
| 1972 | 'selected' => false, |
||||
| 1973 | ]; |
||||
| 1974 | } |
||||
| 1975 | } |
||||
| 1976 | |||||
| 1977 | ksort($filenames); |
||||
| 1978 | |||||
| 1979 | return $filenames; |
||||
| 1980 | } |
||||
| 1981 | } |
||||
| 1982 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths