[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/includes/acp/ -> acp_styles.php (source)

   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 . '&amp;mode=style' . '">&laquo; ' . $this->user->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . '</a>';
 239          $message .= '<br /><br /><a href="' . $this->u_base_action . '&amp;mode=install' . '">&raquo; ' . $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 . '&amp;action=details&amp;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('&nbsp; ', $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 . '&amp;action=details&amp;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 . '&amp;action=' . $action_name . '&amp;hash=' . generate_link_hash($action_name) . '&amp;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 . '&amp;action=export&amp;hash=' . generate_link_hash('export') . '&amp;id=' . $style['style_id'],
 981                  'L_ACTION'    => $this->user->lang['EXPORT']
 982              ); */
 983  
 984              // Uninstall
 985              $actions[] = array(
 986                  'U_ACTION'    => $this->u_action . '&amp;action=uninstall&amp;hash=' . generate_link_hash('uninstall') . '&amp;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 . '&amp;action=install&amp;hash=' . generate_link_hash('install') . '&amp;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  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1