Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

content_visibility.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 29.34 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb;
015   
016  /**
017  * phpbb_visibility
018  * Handle fetching and setting the visibility for topics and posts
019  */
020  class content_visibility
021  {
022      /**
023      * Database object
024      * @var \phpbb\db\driver\driver_interface
025      */
026      protected $db;
027   
028      /**
029      * User object
030      * @var \phpbb\user
031      */
032      protected $user;
033   
034      /**
035      * Auth object
036      * @var \phpbb\auth\auth
037      */
038      protected $auth;
039   
040      /**
041      * config object
042      * @var \phpbb\config\config
043      */
044      protected $config;
045   
046      /**
047      * Event dispatcher object
048      * @var \phpbb\event\dispatcher_interface
049      */
050      protected $phpbb_dispatcher;
051   
052      /**
053      * phpBB root path
054      * @var string
055      */
056      protected $phpbb_root_path;
057   
058      /**
059      * PHP Extension
060      * @var string
061      */
062      protected $php_ext;
063   
064      /**
065      * Constructor
066      *
067      * @param    \phpbb\auth\auth        $auth    Auth object
068      * @param    \phpbb\config\config    $config    Config object
069      * @param    \phpbb\event\dispatcher_interface    $phpbb_dispatcher    Event dispatcher object
070      * @param    \phpbb\db\driver\driver_interface    $db        Database object
071      * @param    \phpbb\user        $user            User object
072      * @param    string        $phpbb_root_path    Root path
073      * @param    string        $php_ext            PHP Extension
074      * @param    string        $forums_table        Forums table name
075      * @param    string        $posts_table        Posts table name
076      * @param    string        $topics_table        Topics table name
077      * @param    string        $users_table        Users table name
078      */
079      public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $php_ext, $forums_table, $posts_table, $topics_table, $users_table)
080      {
081          $this->auth = $auth;
082          $this->config = $config;
083          $this->phpbb_dispatcher = $phpbb_dispatcher;
084          $this->db = $db;
085          $this->user = $user;
086          $this->phpbb_root_path = $phpbb_root_path;
087          $this->php_ext = $php_ext;
088          $this->forums_table = $forums_table;
089          $this->posts_table = $posts_table;
090          $this->topics_table = $topics_table;
091          $this->users_table = $users_table;
092      }
093   
094      /**
095      * Can the current logged-in user soft-delete posts?
096      *
097      * @param $forum_id        int        Forum ID whose permissions to check
098      * @param $poster_id        int        Poster ID of the post in question
099      * @param $post_locked    bool    Is the post locked?
100      * @return bool
101      */
102      public function can_soft_delete($forum_id, $poster_id, $post_locked)
103      {
104          if ($this->auth->acl_get('m_softdelete', $forum_id))
105          {
106              return true;
107          }
108          else if ($this->auth->acl_get('f_softdelete', $forum_id) && $poster_id == $this->user->data['user_id'] && !$post_locked)
109          {
110              return true;
111          }
112   
113          return false;
114      }
115   
116      /**
117      * Get the topics post count or the forums post/topic count based on permissions
118      *
119      * @param $mode            string    One of topic_posts, forum_posts or forum_topics
120      * @param $data            array    Array with the topic/forum data to calculate from
121      * @param $forum_id        int        The forum id is used for permission checks
122      * @return int    Number of posts/topics the user can see in the topic/forum
123      */
124      public function get_count($mode, $data, $forum_id)
125      {
126          if (!$this->auth->acl_get('m_approve', $forum_id))
127          {
128              return (int) $data[$mode . '_approved'];
129          }
130   
131          return (int) $data[$mode . '_approved'] + (int) $data[$mode . '_unapproved'] + (int) $data[$mode . '_softdeleted'];
132      }
133   
134      /**
135      * Create topic/post visibility SQL for a given forum ID
136      *
137      * Note: Read permissions are not checked.
138      *
139      * @param $mode            string    Either "topic" or "post"
140      * @param $forum_id        int        The forum id is used for permission checks
141      * @param $table_alias    string    Table alias to prefix in SQL queries
142      * @return string    The appropriate combination SQL logic for topic/post_visibility
143      */
144      public function get_visibility_sql($mode, $forum_id, $table_alias = '')
145      {
146          $where_sql = '';
147   
148          $get_visibility_sql_overwrite = false;
149   
150          /**
151          * Allow changing the result of calling get_visibility_sql
152          *
153          * @event core.phpbb_content_visibility_get_visibility_sql_before
154          * @var    string        where_sql                        Extra visibility conditions. It must end with either an SQL "AND" or an "OR"
155          * @var    string        mode                            Either "topic" or "post" depending on the query this is being used in
156          * @var    array        forum_id                        The forum id in which the search is made.
157          * @var    string        table_alias                        Table alias to prefix in SQL queries
158          * @var    mixed        get_visibility_sql_overwrite    If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
159          *                                                     If false, get_visibility_sql continues normally
160          *                                                     It must be either boolean or string
161          * @since 3.1.4-RC1
162          */
163          $vars = array(
164              'where_sql',
165              'mode',
166              'forum_id',
167              'table_alias',
168              'get_visibility_sql_overwrite',
169          );
170          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_visibility_sql_before', compact($vars)));
171   
172          if ($get_visibility_sql_overwrite !== false)
173          {
174              return $get_visibility_sql_overwrite;
175          }
176   
177          if ($this->auth->acl_get('m_approve', $forum_id))
178          {
179              return $where_sql . '1 = 1';
180          }
181   
182          return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
183      }
184   
185      /**
186      * Create topic/post visibility SQL for a set of forums
187      *
188      * Note: Read permissions are not checked. Forums without read permissions
189      *        should not be in $forum_ids
190      *
191      * @param $mode            string    Either "topic" or "post"
192      * @param $forum_ids        array    Array of forum ids which the posts/topics are limited to
193      * @param $table_alias    string    Table alias to prefix in SQL queries
194      * @return string    The appropriate combination SQL logic for topic/post_visibility
195      */
196      public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '')
197      {
198          $where_sql = '(';
199   
200          $approve_forums = array_intersect($forum_ids, array_keys($this->auth->acl_getf('m_approve', true)));
201   
202          $get_forums_visibility_sql_overwrite = false;
203          /**
204          * Allow changing the result of calling get_forums_visibility_sql
205          *
206          * @event core.phpbb_content_visibility_get_forums_visibility_before
207          * @var    string        where_sql                            The action the user tried to execute
208          * @var    string        mode                                Either "topic" or "post" depending on the query this is being used in
209          * @var    array        forum_ids                            Array of forum ids which the posts/topics are limited to
210          * @var    string        table_alias                            Table alias to prefix in SQL queries
211          * @var    array        approve_forums                        Array of forums where the user has m_approve permissions
212          * @var    mixed        get_forums_visibility_sql_overwrite    If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
213          *                                                         If false, get_forums_visibility_sql continues normally
214          *                                                         It must be either boolean or string
215          * @since 3.1.3-RC1
216          */
217          $vars = array(
218              'where_sql',
219              'mode',
220              'forum_ids',
221              'table_alias',
222              'approve_forums',
223              'get_forums_visibility_sql_overwrite',
224          );
225          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars)));
226   
227          if ($get_forums_visibility_sql_overwrite !== false)
228          {
229              return $get_forums_visibility_sql_overwrite;
230          }
231   
232          if (sizeof($approve_forums))
233          {
234              // Remove moderator forums from the rest
235              $forum_ids = array_diff($forum_ids, $approve_forums);
236   
237              if (!sizeof($forum_ids))
238              {
239                  // The user can see all posts/topics in all specified forums
240                  return $where_sql . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ')';
241              }
242              else
243              {
244                  // Moderator can view all posts/topics in some forums
245                  $where_sql .= $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ' OR ';
246              }
247          }
248          else
249          {
250              // The user is just a normal user
251              return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . '
252                  AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . ')';
253          }
254   
255          $where_sql .= '(' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . '
256              AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids) . '))';
257   
258          return $where_sql;
259      }
260   
261      /**
262      * Create topic/post visibility SQL for all forums on the board
263      *
264      * Note: Read permissions are not checked. Forums without read permissions
265      *        should be in $exclude_forum_ids
266      *
267      * @param $mode                string    Either "topic" or "post"
268      * @param $exclude_forum_ids    array    Array of forum ids which are excluded
269      * @param $table_alias        string    Table alias to prefix in SQL queries
270      * @return string    The appropriate combination SQL logic for topic/post_visibility
271      */
272      public function get_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '')
273      {
274          $where_sqls = array();
275   
276          $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids);
277   
278          $visibility_sql_overwrite = null;
279   
280          /**
281          * Allow changing the result of calling get_global_visibility_sql
282          *
283          * @event core.phpbb_content_visibility_get_global_visibility_before
284          * @var    array        where_sqls                            The action the user tried to execute
285          * @var    string        mode                                Either "topic" or "post" depending on the query this is being used in
286          * @var    array        exclude_forum_ids                    Array of forum ids the current user doesn't have access to
287          * @var    string        table_alias                            Table alias to prefix in SQL queries
288          * @var    array        approve_forums                        Array of forums where the user has m_approve permissions
289          * @var    string        visibility_sql_overwrite    Forces the function to return an implosion of where_sqls (joined by "OR")
290          * @since 3.1.3-RC1
291          */
292          $vars = array(
293              'where_sqls',
294              'mode',
295              'exclude_forum_ids',
296              'table_alias',
297              'approve_forums',
298              'visibility_sql_overwrite',
299          );
300          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars)));
301   
302          if ($visibility_sql_overwrite)
303          {
304              return $visibility_sql_overwrite;
305          }
306   
307          if (sizeof($exclude_forum_ids))
308          {
309              $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . '
310                  AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
311          }
312          else
313          {
314              $where_sqls[] = $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
315          }
316   
317          if (sizeof($approve_forums))
318          {
319              $where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums);
320              return '(' . implode(' OR ', $where_sqls) . ')';
321          }
322   
323          // There is only one element, so we just return that one
324          return $where_sqls[0];
325      }
326   
327      /**
328      * Change visibility status of one post or all posts of a topic
329      *
330      * @param $visibility    int        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
331      * @param $post_id        mixed    Post ID or array of post IDs to act on,
332      *                                if it is empty, all posts of topic_id will be modified
333      * @param $topic_id        int        Topic where $post_id is found
334      * @param $forum_id        int        Forum where $topic_id is found
335      * @param $user_id        int        User performing the action
336      * @param $time            int        Timestamp when the action is performed
337      * @param $reason        string    Reason why the visibility was changed.
338      * @param $is_starter    bool    Is this the first post of the topic changed?
339      * @param $is_latest        bool    Is this the last post of the topic changed?
340      * @param $limit_visibility    mixed    Limit updating per topic_id to a certain visibility
341      * @param $limit_delete_time    mixed    Limit updating per topic_id to a certain deletion time
342      * @return array        Changed post data, empty array if an error occurred.
343      */
344      public function set_post_visibility($visibility, $post_id, $topic_id, $forum_id, $user_id, $time, $reason, $is_starter, $is_latest, $limit_visibility = false, $limit_delete_time = false)
345      {
346          if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE)))
347          {
348              return array();
349          }
350   
351          if ($post_id)
352          {
353              if (is_array($post_id))
354              {
355                  $where_sql = $this->db->sql_in_set('post_id', array_map('intval', $post_id));
356              }
357              else
358              {
359                  $where_sql = 'post_id = ' . (int) $post_id;
360              }
361              $where_sql .= ' AND topic_id = ' . (int) $topic_id;
362          }
363          else
364          {
365              $where_sql = 'topic_id = ' . (int) $topic_id;
366   
367              // Limit the posts to a certain visibility and deletion time
368              // This allows us to only restore posts, that were approved
369              // when the topic got soft deleted. So previous soft deleted
370              // and unapproved posts are still soft deleted/unapproved
371              if ($limit_visibility !== false)
372              {
373                  $where_sql .= ' AND post_visibility = ' . (int) $limit_visibility;
374              }
375   
376              if ($limit_delete_time !== false)
377              {
378                  $where_sql .= ' AND post_delete_time = ' . (int) $limit_delete_time;
379              }
380          }
381   
382          $sql = 'SELECT poster_id, post_id, post_postcount, post_visibility
383              FROM ' . $this->posts_table . '
384              WHERE ' . $where_sql;
385          $result = $this->db->sql_query($sql);
386   
387          $post_ids = $poster_postcounts = $postcounts = $postcount_visibility = array();
388          while ($row = $this->db->sql_fetchrow($result))
389          {
390              $post_ids[] = (int) $row['post_id'];
391   
392              if ($row['post_visibility'] != $visibility)
393              {
394                  if ($row['post_postcount'] && !isset($poster_postcounts[(int) $row['poster_id']]))
395                  {
396                      $poster_postcounts[(int) $row['poster_id']] = 1;
397                  }
398                  else if ($row['post_postcount'])
399                  {
400                      $poster_postcounts[(int) $row['poster_id']]++;
401                  }
402   
403                  if (!isset($postcount_visibility[$row['post_visibility']]))
404                  {
405                      $postcount_visibility[$row['post_visibility']] = 1;
406                  }
407                  else
408                  {
409                      $postcount_visibility[$row['post_visibility']]++;
410                  }
411              }
412          }
413          $this->db->sql_freeresult($result);
414   
415          if (empty($post_ids))
416          {
417              return array();
418          }
419   
420          if (!function_exists('truncate_string'))
421          {
422              include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
423          }
424   
425          $data = array(
426              'post_visibility'        => (int) $visibility,
427              'post_delete_user'        => (int) $user_id,
428              'post_delete_time'        => ((int) $time) ?: time(),
429              'post_delete_reason'    => truncate_string($reason, 255, 255, false),
430          );
431          /**
432           * Perform actions right before the query to change post visibility
433           *
434           * @event core.set_post_visibility_before_sql
435           * @var            int            visibility        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
436           * @var            array        post_id            Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
437           * @var            int            topic_id        Topic of the post IDs to be modified.
438           * @var            int            forum_id        Forum ID that the topic_id resides in.
439           * @var            int            user_id            User ID doing this action.
440           * @var            int            timestamp        Timestamp of this action.
441           * @var            string        reason            Reason specified by the user for this change.
442           * @var            bool        is_starter        Are we changing the topic's starter?
443           * @var            bool        is_latest        Are we changing the topic's latest post?
444           * @var            array        data            The data array for this action.
445           * @since 3.1.10-RC1
446           */
447          $vars = array(
448              'visibility',
449              'post_id',
450              'topic_id',
451              'forum_id',
452              'user_id',
453              'timestamp',
454              'reason',
455              'is_starter',
456              'is_latest',
457              'data',
458          );
459          extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars)));
460          $sql = 'UPDATE ' . $this->posts_table . '
461              SET ' . $this->db->sql_build_array('UPDATE', $data) . '
462              WHERE ' . $this->db->sql_in_set('post_id', $post_ids);
463          $this->db->sql_query($sql);
464   
465          // Group the authors by post count, to reduce the number of queries
466          foreach ($poster_postcounts as $poster_id => $num_posts)
467          {
468              $postcounts[$num_posts][] = $poster_id;
469          }
470   
471          // Update users postcounts
472          foreach ($postcounts as $num_posts => $poster_ids)
473          {
474              if (in_array($visibility, array(ITEM_REAPPROVE, ITEM_DELETED)))
475              {
476                  $sql = 'UPDATE ' . $this->users_table . '
477                      SET user_posts = 0
478                      WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . '
479                          AND user_posts < ' . $num_posts;
480                  $this->db->sql_query($sql);
481   
482                  $sql = 'UPDATE ' . $this->users_table . '
483                      SET user_posts = user_posts - ' . $num_posts . '
484                      WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . '
485                          AND user_posts >= ' . $num_posts;
486                  $this->db->sql_query($sql);
487              }
488              else
489              {
490                  $sql = 'UPDATE ' . $this->users_table . '
491                      SET user_posts = user_posts + ' . $num_posts . '
492                      WHERE ' . $this->db->sql_in_set('user_id', $poster_ids);
493                  $this->db->sql_query($sql);
494              }
495          }
496   
497          $update_topic_postcount = true;
498   
499          // Sync the first/last topic information if needed
500          if (!$is_starter && $is_latest)
501          {
502              if (!function_exists('update_post_information'))
503              {
504                  include($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext);
505              }
506   
507              // update_post_information can only update the last post info ...
508              if ($topic_id)
509              {
510                  update_post_information('topic', $topic_id, false);
511              }
512              if ($forum_id)
513              {
514                  update_post_information('forum', $forum_id, false);
515              }
516          }
517          else if ($is_starter && $topic_id)
518          {
519              if (!function_exists('sync'))
520              {
521                  include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
522              }
523   
524              // ... so we need to use sync, if the first post is changed.
525              // The forum is resynced recursive by sync() itself.
526              sync('topic', 'topic_id', $topic_id, true);
527   
528              // sync recalculates the topic replies and forum posts by itself, so we don't do that.
529              $update_topic_postcount = false;
530          }
531   
532          $topic_update_array = array();
533          // Update the topic's reply count and the forum's post count
534          if ($update_topic_postcount)
535          {
536              $field_alias = array(
537                  ITEM_APPROVED    => 'posts_approved',
538                  ITEM_UNAPPROVED    => 'posts_unapproved',
539                  ITEM_DELETED    => 'posts_softdeleted',
540                  ITEM_REAPPROVE    => 'posts_unapproved',
541              );
542              $cur_posts = array_fill_keys($field_alias, 0);
543   
544              foreach ($postcount_visibility as $post_visibility => $visibility_posts)
545              {
546                  $cur_posts[$field_alias[(int) $post_visibility]] += $visibility_posts;
547              }
548   
549              $sql_ary = array();
550              $recipient_field = $field_alias[$visibility];
551   
552              foreach ($cur_posts as $field => $count)
553              {
554                  // Decrease the count for the old statuses.
555                  if ($count && $field != $recipient_field)
556                  {
557                      $sql_ary[$field] = " - $count";
558                  }
559              }
560              // Add up the count from all statuses excluding the recipient status.
561              $count_increase = array_sum(array_diff($cur_posts, array($recipient_field)));
562   
563              if ($count_increase)
564              {
565                  $sql_ary[$recipient_field] = " + $count_increase";
566              }
567   
568              if (sizeof($sql_ary))
569              {
570                  $forum_sql = array();
571   
572                  foreach ($sql_ary as $field => $value_change)
573                  {
574                      $topic_update_array[] = 'topic_' . $field . ' = topic_' . $field . $value_change;
575                      $forum_sql[] = 'forum_' . $field . ' = forum_' . $field . $value_change;
576                  }
577   
578                  $sql = 'UPDATE ' . $this->forums_table . '
579                      SET ' . implode(', ', $forum_sql) . '
580                      WHERE forum_id = ' . (int) $forum_id;
581                  $this->db->sql_query($sql);
582              }
583          }
584   
585          if ($post_id)
586          {
587              $sql = 'SELECT 1 AS has_attachments
588                  FROM ' . POSTS_TABLE . '
589                  WHERE topic_id = ' . (int) $topic_id . '
590                      AND post_attachment = 1
591                      AND post_visibility = ' . ITEM_APPROVED . '
592                      AND ' . $this->db->sql_in_set('post_id', $post_id, true);
593              $result = $this->db->sql_query_limit($sql, 1);
594   
595              $has_attachment = (bool) $this->db->sql_fetchfield('has_attachments');
596              $this->db->sql_freeresult($result);
597   
598              if ($has_attachment && $visibility == ITEM_APPROVED)
599              {
600                  $topic_update_array[] = 'topic_attachment = 1';
601              }
602              else if (!$has_attachment && $visibility != ITEM_APPROVED)
603              {
604                  $topic_update_array[] = 'topic_attachment = 0';
605              }
606          }
607   
608          if (!empty($topic_update_array))
609          {
610              // Update the number for replies and posts, and update the attachments flag
611              $sql = 'UPDATE ' . $this->topics_table . '
612                  SET ' . implode(', ', $topic_update_array) . '
613                  WHERE topic_id = ' . (int) $topic_id;
614              $this->db->sql_query($sql);
615          }
616          /**
617           * Perform actions after all steps to changing post visibility
618           *
619           * @event core.set_post_visibility_after
620           * @var            int            visibility        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
621           * @var            array        post_id            Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
622           * @var            int            topic_id        Topic of the post IDs to be modified.
623           * @var            int            forum_id        Forum ID that the topic_id resides in.
624           * @var            int            user_id            User ID doing this action.
625           * @var            int            timestamp        Timestamp of this action.
626           * @var            string        reason            Reason specified by the user for this change.
627           * @var            bool        is_starter        Are we changing the topic's starter?
628           * @var            bool        is_latest        Are we changing the topic's latest post?
629           * @var            array        data            The data array for this action.
630           * @since 3.1.10-RC1
631           */
632          $vars = array(
633              'visibility',
634              'post_id',
635              'topic_id',
636              'forum_id',
637              'user_id',
638              'timestamp',
639              'reason',
640              'is_starter',
641              'is_latest',
642              'data',
643          );
644          extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars)));
645          return $data;
646      }
647   
648      /**
649      * Set topic visibility
650      *
651      * Allows approving (which is akin to undeleting/restore) or soft deleting an entire topic.
652      * Calls set_post_visibility as needed.
653      *
654      * Note: By default, when a soft deleted topic is restored. Only posts that
655      *        were approved at the time of soft deleting, are being restored.
656      *        Same applies to soft deleting. Only approved posts will be marked
657      *        as soft deleted.
658      *        If you want to update all posts, use the force option.
659      *
660      * @param $visibility    int        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
661      * @param $topic_id        mixed    Topic ID to act on
662      * @param $forum_id        int        Forum where $topic_id is found
663      * @param $user_id        int        User performing the action
664      * @param $time            int        Timestamp when the action is performed
665      * @param $reason        string    Reason why the visibilty was changed.
666      * @param $force_update_all    bool    Force to update all posts within the topic
667      * @return array        Changed topic data, empty array if an error occured.
668      */
669      public function set_topic_visibility($visibility, $topic_id, $forum_id, $user_id, $time, $reason, $force_update_all = false)
670      {
671          if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE)))
672          {
673              return array();
674          }
675   
676          if (!$force_update_all)
677          {
678              $sql = 'SELECT topic_visibility, topic_delete_time
679                  FROM ' . $this->topics_table . '
680                  WHERE topic_id = ' . (int) $topic_id;
681              $result = $this->db->sql_query($sql);
682              $original_topic_data = $this->db->sql_fetchrow($result);
683              $this->db->sql_freeresult($result);
684   
685              if (!$original_topic_data)
686              {
687                  // The topic does not exist...
688                  return array();
689              }
690          }
691   
692          if (!function_exists('truncate_string'))
693          {
694              include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
695          }
696   
697          // Note, we do not set a reason for the posts, just for the topic
698          $data = array(
699              'topic_visibility'        => (int) $visibility,
700              'topic_delete_user'        => (int) $user_id,
701              'topic_delete_time'        => ((int) $time) ?: time(),
702              'topic_delete_reason'    => truncate_string($reason, 255, 255, false),
703          );
704          /**
705           * Perform actions right before the query to change topic visibility
706           *
707           * @event core.set_topic_visibility_before_sql
708           * @var            int            visibility            Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
709           * @var            int            topic_id            Topic of the post IDs to be modified.
710           * @var            int            forum_id            Forum ID that the topic_id resides in.
711           * @var            int            user_id                User ID doing this action.
712           * @var            int            timestamp            Timestamp of this action.
713           * @var            string        reason                Reason specified by the user for this change.
714           * @var            bool        force_update_all    Force an update on all posts within the topic, regardless of their current approval state.
715           * @var            array        data                The data array for this action.
716           * @since 3.1.10-RC1
717           */
718          $vars = array(
719              'visibility',
720              'topic_id',
721              'forum_id',
722              'user_id',
723              'timestamp',
724              'reason',
725              'force_update_all',
726              'data',
727          );
728          extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars)));
729          $sql = 'UPDATE ' . $this->topics_table . '
730              SET ' . $this->db->sql_build_array('UPDATE', $data) . '
731              WHERE topic_id = ' . (int) $topic_id;
732          $this->db->sql_query($sql);
733   
734          if (!$this->db->sql_affectedrows())
735          {
736              return array();
737          }
738   
739          if (!$force_update_all && $original_topic_data['topic_delete_time'] && $original_topic_data['topic_visibility'] == ITEM_DELETED && $visibility == ITEM_APPROVED)
740          {
741              // If we're restoring a topic we only restore posts, that were soft deleted through the topic soft deletion.
742              $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility'], $original_topic_data['topic_delete_time']);
743          }
744          else if (!$force_update_all && $original_topic_data['topic_visibility'] == ITEM_APPROVED && $visibility == ITEM_DELETED)
745          {
746              // If we're soft deleting a topic we only mark approved posts as soft deleted.
747              $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility']);
748          }
749          else
750          {
751              $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true);
752          }
753          /**
754           * Perform actions after all steps to changing topic visibility
755           *
756           * @event core.set_topic_visibility_after
757           * @var            int            visibility            Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
758           * @var            int            topic_id            Topic of the post IDs to be modified.
759           * @var            int            forum_id            Forum ID that the topic_id resides in.
760           * @var            int            user_id                User ID doing this action.
761           * @var            int            timestamp            Timestamp of this action.
762           * @var            string        reason                Reason specified by the user for this change.
763           * @var            bool        force_update_all    Force an update on all posts within the topic, regardless of their current approval state.
764           * @var            array        data                The data array for this action.
765           * @since 3.1.10-RC1
766           */
767          $vars = array(
768              'visibility',
769              'topic_id',
770              'forum_id',
771              'user_id',
772              'timestamp',
773              'reason',
774              'force_update_all',
775              'data',
776          );
777          extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars)));
778          return $data;
779      }
780   
781      /**
782      * Add post to topic and forum statistics
783      *
784      * @param $data            array    Contains information from the topics table about given topic
785      * @param &$sql_data        array    Populated with the SQL changes, may be empty at call time
786      * @return null
787      */
788      public function add_post_to_statistic($data, &$sql_data)
789      {
790          $sql_data[$this->topics_table] = (($sql_data[$this->topics_table]) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved + 1';
791   
792          $sql_data[$this->forums_table] = (($sql_data[$this->forums_table]) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved + 1';
793   
794          if ($data['post_postcount'])
795          {
796              $sql_data[$this->users_table] = (($sql_data[$this->users_table]) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts + 1';
797          }
798   
799          $this->config->increment('num_posts', 1, false);
800      }
801   
802      /**
803      * Remove post from topic and forum statistics
804      *
805      * @param $data            array    Contains information from the topics table about given topic
806      * @param &$sql_data        array    Populated with the SQL changes, may be empty at call time
807      * @return null
808      */
809      public function remove_post_from_statistic($data, &$sql_data)
810      {
811          if ($data['post_visibility'] == ITEM_APPROVED)
812          {
813              $sql_data[$this->topics_table] = ((!empty($sql_data[$this->topics_table])) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved - 1';
814              $sql_data[$this->forums_table] = ((!empty($sql_data[$this->forums_table])) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved - 1';
815   
816              if ($data['post_postcount'])
817              {
818                  $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1';
819              }
820   
821              $this->config->increment('num_posts', -1, false);
822          }
823          else if ($data['post_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE)
824          {
825              $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_unapproved = forum_posts_unapproved - 1';
826              $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_unapproved = topic_posts_unapproved - 1';
827          }
828          else if ($data['post_visibility'] == ITEM_DELETED)
829          {
830              $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_softdeleted = forum_posts_softdeleted - 1';
831              $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_softdeleted = topic_posts_softdeleted - 1';
832          }
833      }
834   
835      /**
836      * Remove topic from forum statistics
837      *
838      * @param $data            array    Post and topic data
839      * @param &$sql_data        array    Populated with the SQL changes, may be empty at call time
840      * @return null
841      */
842      public function remove_topic_from_statistic($data, &$sql_data)
843      {
844          if ($data['topic_visibility'] == ITEM_APPROVED)
845          {
846              $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1';
847   
848              if ($data['post_postcount'])
849              {
850                  $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1';
851              }
852          }
853          else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE)
854          {
855              $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1';
856          }
857          else if ($data['topic_visibility'] == ITEM_DELETED)
858          {
859              $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1';
860          }
861   
862      }
863  }
864