[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 /** 15 * @ignore 16 */ 17 if (!defined('IN_PHPBB')) 18 { 19 exit; 20 } 21 22 class acp_styles 23 { 24 public $u_action; 25 26 protected $u_base_action; 27 protected $s_hidden_fields; 28 protected $mode; 29 protected $styles_path; 30 protected $styles_path_absolute = 'styles'; 31 protected $default_style = 0; 32 protected $styles_list_cols = 0; 33 protected $reserved_style_names = array('adm', 'admin', 'all'); 34 35 /** @var \phpbb\db\driver\driver_interface */ 36 protected $db; 37 38 /** @var \phpbb\user */ 39 protected $user; 40 41 /** @var \phpbb\template\template */ 42 protected $template; 43 44 /** @var \phpbb\request\request_interface */ 45 protected $request; 46 47 /** @var \phpbb\cache\driver\driver_interface */ 48 protected $cache; 49 50 /** @var \phpbb\auth\auth */ 51 protected $auth; 52 53 /** @var string */ 54 protected $phpbb_root_path; 55 56 /** @var string */ 57 protected $php_ext; 58 59 /** @var \phpbb\event\dispatcher_interface */ 60 protected $dispatcher; 61 62 public function main($id, $mode) 63 { 64 global $db, $user, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config, $phpbb_dispatcher; 65 66 $this->db = $db; 67 $this->user = $user; 68 $this->template = $template; 69 $this->request = $request; 70 $this->cache = $cache; 71 $this->auth = $auth; 72 $this->config = $config; 73 $this->phpbb_root_path = $phpbb_root_path; 74 $this->php_ext = $phpEx; 75 $this->dispatcher = $phpbb_dispatcher; 76 77 $this->default_style = $config['default_style']; 78 $this->styles_path = $this->phpbb_root_path . $this->styles_path_absolute . '/'; 79 80 $this->u_base_action = append_sid("{$phpbb_admin_path}index.{$this->php_ext}", "i={$id}"); 81 $this->s_hidden_fields = array( 82 'mode' => $mode, 83 ); 84 85 $this->user->add_lang('acp/styles'); 86 87 $this->tpl_name = 'acp_styles'; 88 $this->page_title = 'ACP_CAT_STYLES'; 89 $this->mode = $mode; 90 91 $action = $this->request->variable('action', ''); 92 $post_actions = array('install', 'activate', 'deactivate', 'uninstall'); 93 94 foreach ($post_actions as $key) 95 { 96 if ($this->request->is_set_post($key)) 97 { 98 $action = $key; 99 } 100 } 101 102 // The uninstall action uses confirm_box() to verify the validity of the request, 103 // so there is no need to check for a valid token here. 104 if (in_array($action, $post_actions) && $action != 'uninstall') 105 { 106 $is_valid_request = check_link_hash($request->variable('hash', ''), $action) || check_form_key('styles_management'); 107 108 if (!$is_valid_request) 109 { 110 trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); 111 } 112 } 113 114 if ($action != '') 115 { 116 $this->s_hidden_fields['action'] = $action; 117 } 118 119 $this->template->assign_vars(array( 120 'U_ACTION' => $this->u_base_action, 121 'S_HIDDEN_FIELDS' => build_hidden_fields($this->s_hidden_fields) 122 ) 123 ); 124 125 /** 126 * Run code before ACP styles action execution 127 * 128 * @event core.acp_styles_action_before 129 * @var int id Module ID 130 * @var string mode Active module 131 * @var string action Module that should be run 132 * @since 3.1.7-RC1 133 */ 134 $vars = array('id', 'mode', 'action'); 135 extract($this->dispatcher->trigger_event('core.acp_styles_action_before', compact($vars))); 136 137 // Execute actions 138 switch ($action) 139 { 140 case 'install': 141 $this->action_install(); 142 return; 143 case 'uninstall': 144 $this->action_uninstall(); 145 return; 146 case 'activate': 147 $this->action_activate(); 148 return; 149 case 'deactivate': 150 $this->action_deactivate(); 151 return; 152 case 'details': 153 $this->action_details(); 154 return; 155 default: 156 $this->frontend(); 157 } 158 } 159 160 /** 161 * Main page 162 */ 163 protected function frontend() 164 { 165 add_form_key('styles_management'); 166 167 // Check mode 168 switch ($this->mode) 169 { 170 case 'style': 171 $this->welcome_message('ACP_STYLES', 'ACP_STYLES_EXPLAIN'); 172 $this->show_installed(); 173 return; 174 case 'install': 175 $this->welcome_message('INSTALL_STYLES', 'INSTALL_STYLES_EXPLAIN'); 176 $this->show_available(); 177 return; 178 } 179 trigger_error($this->user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING); 180 } 181 182 /** 183 * Install style(s) 184 */ 185 protected function action_install() 186 { 187 // Get list of styles to install 188 $dirs = $this->request_vars('dir', '', true); 189 190 // Get list of styles that can be installed 191 $styles = $this->find_available(false); 192 193 // Install each style 194 $messages = array(); 195 $installed_names = array(); 196 $installed_dirs = array(); 197 $last_installed = false; 198 foreach ($dirs as $dir) 199 { 200 if (in_array($dir, $this->reserved_style_names)) 201 { 202 $messages[] = $this->user->lang('STYLE_NAME_RESERVED', htmlspecialchars($dir)); 203 continue; 204 } 205 206 $found = false; 207 foreach ($styles as &$style) 208 { 209 // Check if: 210 // 1. Directory matches directory we are looking for 211 // 2. Style is not installed yet 212 // 3. Style with same name or directory hasn't been installed already within this function 213 if ($style['style_path'] == $dir && empty($style['_installed']) && !in_array($style['style_path'], $installed_dirs) && !in_array($style['style_name'], $installed_names)) 214 { 215 // Install style 216 $style['style_active'] = 1; 217 $style['style_id'] = $this->install_style($style); 218 $style['_installed'] = true; 219 $found = true; 220 $last_installed = $style['style_id']; 221 $installed_names[] = $style['style_name']; 222 $installed_dirs[] = $style['style_path']; 223 $messages[] = sprintf($this->user->lang['STYLE_INSTALLED'], htmlspecialchars($style['style_name'])); 224 } 225 } 226 if (!$found) 227 { 228 $messages[] = sprintf($this->user->lang['STYLE_NOT_INSTALLED'], htmlspecialchars($dir)); 229 } 230 } 231 232 // Show message 233 if (!count($messages)) 234 { 235 trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); 236 } 237 $message = implode('<br />', $messages); 238 $message .= '<br /><br /><a href="' . $this->u_base_action . '&mode=style' . '">« ' . $this->user->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . '</a>'; 239 $message .= '<br /><br /><a href="' . $this->u_base_action . '&mode=install' . '">» ' . $this->user->lang('STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES') . '</a>'; 240 trigger_error($message, E_USER_NOTICE); 241 } 242 243 /** 244 * Confirm styles removal 245 */ 246 protected function action_uninstall() 247 { 248 // Get list of styles to uninstall 249 $ids = $this->request_vars('id', 0, true); 250 251 // Check if confirmation box was submitted 252 if (confirm_box(true)) 253 { 254 // Uninstall 255 $this->action_uninstall_confirmed($ids, $this->request->variable('confirm_delete_files', false)); 256 return; 257 } 258 259 // Confirm box 260 $s_hidden = build_hidden_fields(array( 261 'action' => 'uninstall', 262 'ids' => $ids 263 )); 264 $this->template->assign_var('S_CONFIRM_DELETE', true); 265 confirm_box(false, $this->user->lang['CONFIRM_UNINSTALL_STYLES'], $s_hidden, 'acp_styles.html'); 266 267 // Canceled - show styles list 268 $this->frontend(); 269 } 270 271 /** 272 * Uninstall styles(s) 273 * 274 * @param array $ids List of style IDs 275 * @param bool $delete_files If true, script will attempt to remove files for selected styles 276 */ 277 protected function action_uninstall_confirmed($ids, $delete_files) 278 { 279 $default = $this->default_style; 280 $uninstalled = array(); 281 $messages = array(); 282 283 // Check styles list 284 foreach ($ids as $id) 285 { 286 if (!$id) 287 { 288 trigger_error($this->user->lang['INVALID_STYLE_ID'] . adm_back_link($this->u_action), E_USER_WARNING); 289 } 290 if ($id == $default) 291 { 292 trigger_error($this->user->lang['UNINSTALL_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); 293 } 294 $uninstalled[$id] = false; 295 } 296 297 // Order by reversed style_id, so parent styles would be removed after child styles 298 // This way parent and child styles can be removed in same function call 299 $sql = 'SELECT * 300 FROM ' . STYLES_TABLE . ' 301 WHERE style_id IN (' . implode(', ', $ids) . ') 302 ORDER BY style_id DESC'; 303 $result = $this->db->sql_query($sql); 304 305 $rows = $this->db->sql_fetchrowset($result); 306 $this->db->sql_freeresult($result); 307 308 // Uinstall each style 309 $uninstalled = array(); 310 foreach ($rows as $style) 311 { 312 $result = $this->uninstall_style($style, $delete_files); 313 314 if (is_string($result)) 315 { 316 $messages[] = $result; 317 continue; 318 } 319 $messages[] = sprintf($this->user->lang['STYLE_UNINSTALLED'], $style['style_name']); 320 $uninstalled[] = $style['style_name']; 321 322 // Attempt to delete files 323 if ($delete_files) 324 { 325 $messages[] = sprintf($this->user->lang[$this->delete_style_files($style['style_path']) ? 'DELETE_STYLE_FILES_SUCCESS' : 'DELETE_STYLE_FILES_FAILED'], $style['style_name']); 326 } 327 } 328 329 if (empty($messages)) 330 { 331 // Nothing to uninstall? 332 trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); 333 } 334 335 // Log action 336 if (count($uninstalled)) 337 { 338 add_log('admin', 'LOG_STYLE_DELETE', implode(', ', $uninstalled)); 339 } 340 341 // Clear cache 342 $this->cache->purge(); 343 344 // Show message 345 trigger_error(implode('<br />', $messages) . adm_back_link($this->u_action), E_USER_NOTICE); 346 } 347 348 /** 349 * Activate styles 350 */ 351 protected function action_activate() 352 { 353 // Get list of styles to activate 354 $ids = $this->request_vars('id', 0, true); 355 356 // Activate styles 357 $sql = 'UPDATE ' . STYLES_TABLE . ' 358 SET style_active = 1 359 WHERE style_id IN (' . implode(', ', $ids) . ')'; 360 $this->db->sql_query($sql); 361 362 // Purge cache 363 $this->cache->destroy('sql', STYLES_TABLE); 364 365 // Show styles list 366 $this->frontend(); 367 } 368 369 /** 370 * Deactivate styles 371 */ 372 protected function action_deactivate() 373 { 374 // Get list of styles to deactivate 375 $ids = $this->request_vars('id', 0, true); 376 377 // Check for default style 378 foreach ($ids as $id) 379 { 380 if ($id == $this->default_style) 381 { 382 trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); 383 } 384 } 385 386 // Reset default style for users who use selected styles 387 $sql = 'UPDATE ' . USERS_TABLE . ' 388 SET user_style = 0 389 WHERE user_style IN (' . implode(', ', $ids) . ')'; 390 $this->db->sql_query($sql); 391 392 // Deactivate styles 393 $sql = 'UPDATE ' . STYLES_TABLE . ' 394 SET style_active = 0 395 WHERE style_id IN (' . implode(', ', $ids) . ')'; 396 $this->db->sql_query($sql); 397 398 // Purge cache 399 $this->cache->destroy('sql', STYLES_TABLE); 400 401 // Show styles list 402 $this->frontend(); 403 } 404 405 /** 406 * Show style details 407 */ 408 protected function action_details() 409 { 410 $id = $this->request->variable('id', 0); 411 if (!$id) 412 { 413 trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); 414 } 415 416 // Get all styles 417 $styles = $this->get_styles(); 418 usort($styles, array($this, 'sort_styles')); 419 420 // Find current style 421 $style = false; 422 foreach ($styles as $row) 423 { 424 if ($row['style_id'] == $id) 425 { 426 $style = $row; 427 break; 428 } 429 } 430 431 if ($style === false) 432 { 433 trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); 434 } 435 436 // Read style configuration file 437 $style_cfg = $this->read_style_cfg($style['style_path']); 438 439 // Find all available parent styles 440 $list = $this->find_possible_parents($styles, $id); 441 442 // Add form key 443 $form_key = 'acp_styles'; 444 add_form_key($form_key); 445 446 // Change data 447 if ($this->request->variable('update', false)) 448 { 449 if (!check_form_key($form_key)) 450 { 451 trigger_error($this->user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); 452 } 453 454 $update = array( 455 'style_name' => trim($this->request->variable('style_name', $style['style_name'])), 456 'style_parent_id' => $this->request->variable('style_parent', (int) $style['style_parent_id']), 457 'style_active' => $this->request->variable('style_active', (int) $style['style_active']), 458 ); 459 $update_action = $this->u_action . '&action=details&id=' . $id; 460 461 // Check style name 462 if ($update['style_name'] != $style['style_name']) 463 { 464 if (!strlen($update['style_name'])) 465 { 466 trigger_error($this->user->lang['STYLE_ERR_STYLE_NAME'] . adm_back_link($update_action), E_USER_WARNING); 467 } 468 foreach ($styles as $row) 469 { 470 if ($row['style_name'] == $update['style_name']) 471 { 472 trigger_error($this->user->lang['STYLE_ERR_NAME_EXIST'] . adm_back_link($update_action), E_USER_WARNING); 473 } 474 } 475 } 476 else 477 { 478 unset($update['style_name']); 479 } 480 481 // Check parent style id 482 if ($update['style_parent_id'] != $style['style_parent_id']) 483 { 484 if ($update['style_parent_id'] != 0) 485 { 486 $found = false; 487 foreach ($list as $row) 488 { 489 if ($row['style_id'] == $update['style_parent_id']) 490 { 491 $found = true; 492 $update['style_parent_tree'] = ($row['style_parent_tree'] != '' ? $row['style_parent_tree'] . '/' : '') . $row['style_path']; 493 break; 494 } 495 } 496 if (!$found) 497 { 498 trigger_error($this->user->lang['STYLE_ERR_INVALID_PARENT'] . adm_back_link($update_action), E_USER_WARNING); 499 } 500 } 501 else 502 { 503 $update['style_parent_tree'] = ''; 504 } 505 } 506 else 507 { 508 unset($update['style_parent_id']); 509 } 510 511 // Check style_active 512 if ($update['style_active'] != $style['style_active']) 513 { 514 if (!$update['style_active'] && $this->default_style == $style['style_id']) 515 { 516 trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($update_action), E_USER_WARNING); 517 } 518 } 519 else 520 { 521 unset($update['style_active']); 522 } 523 524 // Update data 525 if (count($update)) 526 { 527 $sql = 'UPDATE ' . STYLES_TABLE . ' 528 SET ' . $this->db->sql_build_array('UPDATE', $update) . " 529 WHERE style_id = $id"; 530 $this->db->sql_query($sql); 531 532 $style = array_merge($style, $update); 533 534 if (isset($update['style_parent_id'])) 535 { 536 // Update styles tree 537 $styles = $this->get_styles(); 538 if ($this->update_styles_tree($styles, $style)) 539 { 540 // Something was changed in styles tree, purge all cache 541 $this->cache->purge(); 542 } 543 } 544 add_log('admin', 'LOG_STYLE_EDIT_DETAILS', $style['style_name']); 545 } 546 547 // Update default style 548 $default = $this->request->variable('style_default', 0); 549 if ($default) 550 { 551 if (!$style['style_active']) 552 { 553 trigger_error($this->user->lang['STYLE_DEFAULT_CHANGE_INACTIVE'] . adm_back_link($update_action), E_USER_WARNING); 554 } 555 set_config('default_style', $id); 556 $this->cache->purge(); 557 } 558 559 // Show styles list 560 $this->frontend(); 561 return; 562 } 563 564 // Show page title 565 $this->welcome_message('ACP_STYLES', null); 566 567 // Show parent styles 568 foreach ($list as $row) 569 { 570 $this->template->assign_block_vars('parent_styles', array( 571 'STYLE_ID' => $row['style_id'], 572 'STYLE_NAME' => htmlspecialchars($row['style_name']), 573 'LEVEL' => $row['level'], 574 'SPACER' => str_repeat(' ', $row['level']), 575 ) 576 ); 577 } 578 579 // Show style details 580 $this->template->assign_vars(array( 581 'S_STYLE_DETAILS' => true, 582 'STYLE_ID' => $style['style_id'], 583 'STYLE_NAME' => htmlspecialchars($style['style_name']), 584 'STYLE_PATH' => htmlspecialchars($style['style_path']), 585 'STYLE_VERSION' => htmlspecialchars($style_cfg['style_version']), 586 'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']), 587 'STYLE_PARENT' => $style['style_parent_id'], 588 'S_STYLE_ACTIVE' => $style['style_active'], 589 'S_STYLE_DEFAULT' => ($style['style_id'] == $this->default_style) 590 ) 591 ); 592 } 593 594 /** 595 * List installed styles 596 */ 597 protected function show_installed() 598 { 599 // Get all installed styles 600 $styles = $this->get_styles(); 601 602 if (!count($styles)) 603 { 604 trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); 605 } 606 607 usort($styles, array($this, 'sort_styles')); 608 609 // Get users 610 $users = $this->get_users(); 611 612 // Add users counter to rows 613 foreach ($styles as &$style) 614 { 615 $style['_users'] = isset($users[$style['style_id']]) ? $users[$style['style_id']] : 0; 616 } 617 618 // Set up styles list variables 619 // Addons should increase this number and update template variable 620 $this->styles_list_cols = 4; 621 $this->template->assign_var('STYLES_LIST_COLS', $this->styles_list_cols); 622 623 // Show styles list 624 $this->show_styles_list($styles, 0, 0); 625 626 // Show styles with invalid inherits_id 627 foreach ($styles as $style) 628 { 629 if (empty($style['_shown'])) 630 { 631 $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($style['style_parent_tree'])); 632 $this->list_style($style, 0); 633 } 634 } 635 636 // Add buttons 637 $this->template->assign_block_vars('extra_actions', array( 638 'ACTION_NAME' => 'activate', 639 'L_ACTION' => $this->user->lang['STYLE_ACTIVATE'], 640 ) 641 ); 642 643 $this->template->assign_block_vars('extra_actions', array( 644 'ACTION_NAME' => 'deactivate', 645 'L_ACTION' => $this->user->lang['STYLE_DEACTIVATE'], 646 ) 647 ); 648 649 if (isset($this->style_counters) && $this->style_counters['total'] > 1) 650 { 651 $this->template->assign_block_vars('extra_actions', array( 652 'ACTION_NAME' => 'uninstall', 653 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'], 654 ) 655 ); 656 } 657 } 658 659 /** 660 * Show list of styles that can be installed 661 */ 662 protected function show_available() 663 { 664 // Get list of styles 665 $styles = $this->find_available(true); 666 667 // Show styles 668 if (empty($styles)) 669 { 670 trigger_error($this->user->lang['NO_UNINSTALLED_STYLE'] . adm_back_link($this->u_base_action), E_USER_NOTICE); 671 } 672 673 usort($styles, array($this, 'sort_styles')); 674 675 $this->styles_list_cols = 3; 676 $this->template->assign_vars(array( 677 'STYLES_LIST_COLS' => $this->styles_list_cols, 678 'STYLES_LIST_HIDE_COUNT' => true 679 ) 680 ); 681 682 // Show styles 683 foreach ($styles as &$style) 684 { 685 // Check if style has a parent style in styles list 686 $has_parent = false; 687 if ($style['_inherit_name'] != '') 688 { 689 foreach ($styles as $parent_style) 690 { 691 if ($parent_style['style_name'] == $style['_inherit_name'] && empty($parent_style['_shown'])) 692 { 693 // Show parent style first 694 $has_parent = true; 695 } 696 } 697 } 698 if (!$has_parent) 699 { 700 $this->list_style($style, 0); 701 $this->show_available_child_styles($styles, $style['style_name'], 1); 702 } 703 } 704 705 // Show styles that do not have parent style in styles list 706 foreach ($styles as $style) 707 { 708 if (empty($style['_shown'])) 709 { 710 $this->list_style($style, 0); 711 } 712 } 713 714 // Add button 715 if (isset($this->style_counters) && $this->style_counters['caninstall'] > 0) 716 { 717 $this->template->assign_block_vars('extra_actions', array( 718 'ACTION_NAME' => 'install', 719 'L_ACTION' => $this->user->lang['INSTALL_STYLES'], 720 ) 721 ); 722 } 723 } 724 725 /** 726 * Find styles available for installation 727 * 728 * @param bool $all if true, function will return all installable styles. if false, function will return only styles that can be installed 729 * @return array List of styles 730 */ 731 protected function find_available($all) 732 { 733 // Get list of installed styles 734 $installed = $this->get_styles(); 735 736 $installed_dirs = array(); 737 $installed_names = array(); 738 foreach ($installed as $style) 739 { 740 $installed_dirs[] = $style['style_path']; 741 $installed_names[$style['style_name']] = array( 742 'path' => $style['style_path'], 743 'id' => $style['style_id'], 744 'parent' => $style['style_parent_id'], 745 'tree' => (strlen($style['style_parent_tree']) ? $style['style_parent_tree'] . '/' : '') . $style['style_path'], 746 ); 747 } 748 749 // Get list of directories 750 $dirs = $this->find_style_dirs(); 751 752 // Find styles that can be installed 753 $styles = array(); 754 foreach ($dirs as $dir) 755 { 756 if (in_array($dir, $installed_dirs)) 757 { 758 // Style is already installed 759 continue; 760 } 761 $cfg = $this->read_style_cfg($dir); 762 if ($cfg === false) 763 { 764 // Invalid style.cfg 765 continue; 766 } 767 768 // Style should be available for installation 769 $parent = $cfg['parent']; 770 $style = array( 771 'style_id' => 0, 772 'style_name' => $cfg['name'], 773 'style_copyright' => $cfg['copyright'], 774 'style_active' => 0, 775 'style_path' => $dir, 776 'bbcode_bitfield' => $cfg['template_bitfield'], 777 'style_parent_id' => 0, 778 'style_parent_tree' => '', 779 // Extra values for styles list 780 // All extra variable start with _ so they won't be confused with data that can be added to styles table 781 '_inherit_name' => $parent, 782 '_available' => true, 783 '_note' => '', 784 ); 785 786 // Check style inheritance 787 if ($parent != '') 788 { 789 if (isset($installed_names[$parent])) 790 { 791 // Parent style is installed 792 $row = $installed_names[$parent]; 793 $style['style_parent_id'] = $row['id']; 794 $style['style_parent_tree'] = $row['tree']; 795 } 796 else 797 { 798 // Parent style is not installed yet 799 $style['_available'] = false; 800 $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($parent)); 801 } 802 } 803 804 if ($all || $style['_available']) 805 { 806 $styles[] = $style; 807 } 808 } 809 810 return $styles; 811 } 812 813 /** 814 * Show styles list 815 * 816 * @param array $styles styles list 817 * @param int $parent parent style id 818 * @param int $level style inheritance level 819 */ 820 protected function show_styles_list(&$styles, $parent, $level) 821 { 822 foreach ($styles as &$style) 823 { 824 if (empty($style['_shown']) && $style['style_parent_id'] == $parent) 825 { 826 $this->list_style($style, $level); 827 $this->show_styles_list($styles, $style['style_id'], $level + 1); 828 } 829 } 830 } 831 832 /** 833 * Show available styles tree 834 * 835 * @param array $styles Styles list, passed as reference 836 * @param string $name Name of parent style 837 * @param int $level Styles tree level 838 */ 839 protected function show_available_child_styles(&$styles, $name, $level) 840 { 841 foreach ($styles as &$style) 842 { 843 if (empty($style['_shown']) && $style['_inherit_name'] == $name) 844 { 845 $this->list_style($style, $level); 846 $this->show_available_child_styles($styles, $style['style_name'], $level + 1); 847 } 848 } 849 } 850 851 /** 852 * Update styles tree 853 * 854 * @param array $styles Styles list, passed as reference 855 * @param array|false $style Current style, false if root 856 * @return bool True if something was updated, false if not 857 */ 858 protected function update_styles_tree(&$styles, $style = false) 859 { 860 $parent_id = ($style === false) ? 0 : $style['style_id']; 861 $parent_tree = ($style === false) ? '' : ($style['style_parent_tree'] == '' ? '' : $style['style_parent_tree']) . $style['style_path']; 862 $update = false; 863 $updated = false; 864 foreach ($styles as &$row) 865 { 866 if ($row['style_parent_id'] == $parent_id) 867 { 868 if ($row['style_parent_tree'] != $parent_tree) 869 { 870 $row['style_parent_tree'] = $parent_tree; 871 $update = true; 872 } 873 $updated |= $this->update_styles_tree($styles, $row); 874 } 875 } 876 if ($update) 877 { 878 $sql = 'UPDATE ' . STYLES_TABLE . " 879 SET style_parent_tree = '" . $this->db->sql_escape($parent_tree) . "' 880 WHERE style_parent_id = {$parent_id}"; 881 $this->db->sql_query($sql); 882 $updated = true; 883 } 884 return $updated; 885 } 886 887 /** 888 * Find all possible parent styles for style 889 * 890 * @param array $styles list of styles 891 * @param int $id id of style 892 * @param int $parent current parent style id 893 * @param int $level current tree level 894 * @return array Style ids, names and levels 895 */ 896 protected function find_possible_parents($styles, $id = -1, $parent = 0, $level = 0) 897 { 898 $results = array(); 899 foreach ($styles as $style) 900 { 901 if ($style['style_id'] != $id && $style['style_parent_id'] == $parent) 902 { 903 $results[] = array( 904 'style_id' => $style['style_id'], 905 'style_name' => $style['style_name'], 906 'style_path' => $style['style_path'], 907 'style_parent_id' => $style['style_parent_id'], 908 'style_parent_tree' => $style['style_parent_tree'], 909 'level' => $level 910 ); 911 $results = array_merge($results, $this->find_possible_parents($styles, $id, $style['style_id'], $level + 1)); 912 } 913 } 914 return $results; 915 } 916 917 /** 918 * Show item in styles list 919 * 920 * @param array $style style row 921 * @param int $level style inheritance level 922 */ 923 protected function list_style(&$style, $level) 924 { 925 // Mark row as shown 926 if (!empty($style['_shown'])) 927 { 928 return; 929 } 930 931 $style['_shown'] = true; 932 933 // Generate template variables 934 $actions = array(); 935 $row = array( 936 // Style data 937 'STYLE_ID' => $style['style_id'], 938 'STYLE_NAME' => htmlspecialchars($style['style_name']), 939 'STYLE_PATH' => htmlspecialchars($style['style_path']), 940 'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']), 941 'STYLE_ACTIVE' => $style['style_active'], 942 943 // Additional data 944 'DEFAULT' => ($style['style_id'] && $style['style_id'] == $this->default_style), 945 'USERS' => (isset($style['_users'])) ? $style['_users'] : '', 946 'LEVEL' => $level, 947 'PADDING' => (4 + 16 * $level), 948 'SHOW_COPYRIGHT' => ($style['style_id']) ? false : true, 949 'STYLE_PATH_FULL' => htmlspecialchars($this->styles_path_absolute . '/' . $style['style_path']) . '/', 950 951 // Comment to show below style 952 'COMMENT' => (isset($style['_note'])) ? $style['_note'] : '', 953 954 // The following variables should be used by hooks to add custom HTML code 955 'EXTRA' => '', 956 'EXTRA_OPTIONS' => '' 957 ); 958 959 // Status specific data 960 if ($style['style_id']) 961 { 962 // Style is installed 963 964 // Details 965 $actions[] = array( 966 'U_ACTION' => $this->u_action . '&action=details&id=' . $style['style_id'], 967 'L_ACTION' => $this->user->lang['DETAILS'] 968 ); 969 970 // Activate/Deactive 971 $action_name = ($style['style_active'] ? 'de' : '') . 'activate'; 972 973 $actions[] = array( 974 'U_ACTION' => $this->u_action . '&action=' . $action_name . '&hash=' . generate_link_hash($action_name) . '&id=' . $style['style_id'], 975 'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE'] 976 ); 977 978 /* // Export 979 $actions[] = array( 980 'U_ACTION' => $this->u_action . '&action=export&hash=' . generate_link_hash('export') . '&id=' . $style['style_id'], 981 'L_ACTION' => $this->user->lang['EXPORT'] 982 ); */ 983 984 // Uninstall 985 $actions[] = array( 986 'U_ACTION' => $this->u_action . '&action=uninstall&hash=' . generate_link_hash('uninstall') . '&id=' . $style['style_id'], 987 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'] 988 ); 989 990 // Preview 991 $actions[] = array( 992 'U_ACTION' => append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'style=' . $style['style_id']), 993 'L_ACTION' => $this->user->lang['PREVIEW'] 994 ); 995 } 996 else 997 { 998 // Style is not installed 999 if (empty($style['_available'])) 1000 { 1001 $actions[] = array( 1002 'HTML' => $this->user->lang['CANNOT_BE_INSTALLED'] 1003 ); 1004 } 1005 else 1006 { 1007 $actions[] = array( 1008 'U_ACTION' => $this->u_action . '&action=install&hash=' . generate_link_hash('install') . '&dir=' . urlencode($style['style_path']), 1009 'L_ACTION' => $this->user->lang['INSTALL_STYLE'] 1010 ); 1011 } 1012 } 1013 1014 // todo: add hook 1015 1016 // Assign template variables 1017 $this->template->assign_block_vars('styles_list', $row); 1018 foreach ($actions as $action) 1019 { 1020 $this->template->assign_block_vars('styles_list.actions', $action); 1021 } 1022 1023 // Increase counters 1024 $counter = ($style['style_id']) ? ($style['style_active'] ? 'active' : 'inactive') : (empty($style['_available']) ? 'cannotinstall' : 'caninstall'); 1025 if (!isset($this->style_counters)) 1026 { 1027 $this->style_counters = array( 1028 'total' => 0, 1029 'active' => 0, 1030 'inactive' => 0, 1031 'caninstall' => 0, 1032 'cannotinstall' => 0 1033 ); 1034 } 1035 $this->style_counters[$counter]++; 1036 $this->style_counters['total']++; 1037 } 1038 1039 /** 1040 * Show welcome message 1041 * 1042 * @param string $title main title 1043 * @param string $description page description 1044 */ 1045 protected function welcome_message($title, $description) 1046 { 1047 $this->template->assign_vars(array( 1048 'L_TITLE' => $this->user->lang[$title], 1049 'L_EXPLAIN' => (isset($this->user->lang[$description])) ? $this->user->lang[$description] : '' 1050 ) 1051 ); 1052 } 1053 1054 /** 1055 * Find all directories that have styles 1056 * 1057 * @return array Directory names 1058 */ 1059 protected function find_style_dirs() 1060 { 1061 $styles = array(); 1062 1063 $dp = @opendir($this->styles_path); 1064 if ($dp) 1065 { 1066 while (($file = readdir($dp)) !== false) 1067 { 1068 $dir = $this->styles_path . $file; 1069 if ($file[0] == '.' || !is_dir($dir)) 1070 { 1071 continue; 1072 } 1073 1074 if (file_exists("{$dir}/style.cfg")) 1075 { 1076 $styles[] = $file; 1077 } 1078 } 1079 closedir($dp); 1080 } 1081 1082 return $styles; 1083 } 1084 1085 /** 1086 * Sort styles 1087 */ 1088 public function sort_styles($style1, $style2) 1089 { 1090 if ($style1['style_active'] != $style2['style_active']) 1091 { 1092 return ($style1['style_active']) ? -1 : 1; 1093 } 1094 if (isset($style1['_available']) && $style1['_available'] != $style2['_available']) 1095 { 1096 return ($style1['_available']) ? -1 : 1; 1097 } 1098 return strcasecmp(isset($style1['style_name']) ? $style1['style_name'] : $style1['name'], isset($style2['style_name']) ? $style2['style_name'] : $style2['name']); 1099 } 1100 1101 /** 1102 * Read style configuration file 1103 * 1104 * @param string $dir style directory 1105 * @return array|bool Style data, false on error 1106 */ 1107 protected function read_style_cfg($dir) 1108 { 1109 static $required = array('name', 'phpbb_version', 'copyright'); 1110 $cfg = parse_cfg_file($this->styles_path . $dir . '/style.cfg'); 1111 1112 // Check if it is a valid file 1113 foreach ($required as $key) 1114 { 1115 if (!isset($cfg[$key])) 1116 { 1117 return false; 1118 } 1119 } 1120 1121 // Check data 1122 if (!isset($cfg['parent']) || !is_string($cfg['parent']) || $cfg['parent'] == $cfg['name']) 1123 { 1124 $cfg['parent'] = ''; 1125 } 1126 if (!isset($cfg['template_bitfield'])) 1127 { 1128 $cfg['template_bitfield'] = $this->default_bitfield(); 1129 } 1130 1131 return $cfg; 1132 } 1133 1134 /** 1135 * Install style 1136 * 1137 * @param array $style style data 1138 * @return int Style id 1139 */ 1140 protected function install_style($style) 1141 { 1142 // Generate row 1143 $sql_ary = array(); 1144 foreach ($style as $key => $value) 1145 { 1146 if ($key != 'style_id' && substr($key, 0, 1) != '_') 1147 { 1148 $sql_ary[$key] = $value; 1149 } 1150 } 1151 1152 // Add to database 1153 $this->db->sql_transaction('begin'); 1154 1155 $sql = 'INSERT INTO ' . STYLES_TABLE . ' 1156 ' . $this->db->sql_build_array('INSERT', $sql_ary); 1157 $this->db->sql_query($sql); 1158 1159 $id = $this->db->sql_nextid(); 1160 1161 $this->db->sql_transaction('commit'); 1162 1163 add_log('admin', 'LOG_STYLE_ADD', $sql_ary['style_name']); 1164 1165 return $id; 1166 } 1167 1168 /** 1169 * Lists all styles 1170 * 1171 * @return array Rows with styles data 1172 */ 1173 protected function get_styles() 1174 { 1175 $sql = 'SELECT * 1176 FROM ' . STYLES_TABLE; 1177 $result = $this->db->sql_query($sql); 1178 1179 $rows = $this->db->sql_fetchrowset($result); 1180 $this->db->sql_freeresult($result); 1181 1182 return $rows; 1183 } 1184 1185 /** 1186 * Count users for each style 1187 * 1188 * @return array Styles in following format: [style_id] = number of users 1189 */ 1190 protected function get_users() 1191 { 1192 $sql = 'SELECT user_style, COUNT(user_style) AS style_count 1193 FROM ' . USERS_TABLE . ' 1194 GROUP BY user_style'; 1195 $result = $this->db->sql_query($sql); 1196 1197 $style_count = array(); 1198 while ($row = $this->db->sql_fetchrow($result)) 1199 { 1200 $style_count[$row['user_style']] = $row['style_count']; 1201 } 1202 $this->db->sql_freeresult($result); 1203 1204 return $style_count; 1205 } 1206 1207 /** 1208 * Uninstall style 1209 * 1210 * @param array $style Style data 1211 * @return bool|string True on success, error message on error 1212 */ 1213 protected function uninstall_style($style) 1214 { 1215 $id = $style['style_id']; 1216 $path = $style['style_path']; 1217 1218 // Check if style has child styles 1219 $sql = 'SELECT style_id 1220 FROM ' . STYLES_TABLE . ' 1221 WHERE style_parent_id = ' . (int) $id . " OR style_parent_tree = '" . $this->db->sql_escape($path) . "'"; 1222 $result = $this->db->sql_query($sql); 1223 1224 $conflict = $this->db->sql_fetchrow($result); 1225 $this->db->sql_freeresult($result); 1226 1227 if ($conflict !== false) 1228 { 1229 return sprintf($this->user->lang['STYLE_UNINSTALL_DEPENDENT'], $style['style_name']); 1230 } 1231 1232 // Change default style for users 1233 $sql = 'UPDATE ' . USERS_TABLE . ' 1234 SET user_style = 0 1235 WHERE user_style = ' . $id; 1236 $this->db->sql_query($sql); 1237 1238 // Uninstall style 1239 $sql = 'DELETE FROM ' . STYLES_TABLE . ' 1240 WHERE style_id = ' . $id; 1241 $this->db->sql_query($sql); 1242 return true; 1243 } 1244 1245 /** 1246 * Delete all files in style directory 1247 * 1248 * @param string $path Style directory 1249 * @param string $dir Directory to remove inside style's directory 1250 * @return bool True on success, false on error 1251 */ 1252 protected function delete_style_files($path, $dir = '') 1253 { 1254 $dirname = $this->styles_path . $path . $dir; 1255 $result = true; 1256 1257 $dp = @opendir($dirname); 1258 1259 if ($dp) 1260 { 1261 while (($file = readdir($dp)) !== false) 1262 { 1263 if ($file == '.' || $file == '..') 1264 { 1265 continue; 1266 } 1267 $filename = $dirname . '/' . $file; 1268 if (is_dir($filename)) 1269 { 1270 if (!$this->delete_style_files($path, $dir . '/' . $file)) 1271 { 1272 $result = false; 1273 } 1274 } 1275 else 1276 { 1277 if (!@unlink($filename)) 1278 { 1279 $result = false; 1280 } 1281 } 1282 } 1283 closedir($dp); 1284 } 1285 if (!@rmdir($dirname)) 1286 { 1287 return false; 1288 } 1289 1290 return $result; 1291 } 1292 1293 /** 1294 * Get list of items from posted data 1295 * 1296 * @param string $name Variable name 1297 * @param string|int $default Default value for array 1298 * @param bool $error If true, error will be triggered if list is empty 1299 * @return array Items 1300 */ 1301 protected function request_vars($name, $default, $error = false) 1302 { 1303 $item = $this->request->variable($name, $default); 1304 $items = $this->request->variable($name . 's', array($default)); 1305 1306 if (count($items) == 1 && $items[0] == $default) 1307 { 1308 $items = array(); 1309 } 1310 1311 if ($item != $default && !count($items)) 1312 { 1313 $items[] = $item; 1314 } 1315 1316 if ($error && !count($items)) 1317 { 1318 trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); 1319 } 1320 1321 return $items; 1322 } 1323 1324 /** 1325 * Generates default bitfield 1326 * 1327 * This bitfield decides which bbcodes are defined in a template. 1328 * 1329 * @return string Bitfield 1330 */ 1331 protected function default_bitfield() 1332 { 1333 static $value; 1334 if (isset($value)) 1335 { 1336 return $value; 1337 } 1338 1339 // Hardcoded template bitfield to add for new templates 1340 $bitfield = new bitfield(); 1341 $bitfield->set(0); 1342 $bitfield->set(1); 1343 $bitfield->set(2); 1344 $bitfield->set(3); 1345 $bitfield->set(4); 1346 $bitfield->set(8); 1347 $bitfield->set(9); 1348 $bitfield->set(11); 1349 $bitfield->set(12); 1350 $value = $bitfield->get_base64(); 1351 return $value; 1352 } 1353 1354 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |