Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:01 - Dateigröße: 31.43 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      /**
136      * Check topic/post visibility for a given forum ID
137      *
138      * Note: Read permissions are not checked.
139      *
140      * @param $mode        string    Either "topic" or "post"
141      * @param $forum_id    int        The forum id is used for permission checks
142      * @param $data        array    Array with item information to check visibility
143      * @return bool        True if the item is visible, false if not
144      */
145      public function is_visible($mode, $forum_id, $data)
146      {
147          $visibility = $data[$mode . '_visibility'];
148          $poster_key = ($mode === 'topic') ? 'topic_poster' : 'poster_id';
149          $is_visible = ($visibility == ITEM_APPROVED) ||
150              ($this->config['display_unapproved_posts'] &&
151                  ($this->user->data['user_id'] != ANONYMOUS) &&
152                  ($visibility == ITEM_UNAPPROVED || $visibility == ITEM_REAPPROVE) &&
153                  ($this->user->data['user_id'] == $data[$poster_key])) ||
154               $this->auth->acl_get('m_approve', $forum_id);
155   
156          /**
157          * Allow changing the result of calling is_visible
158          *
159          * @event core.phpbb_content_visibility_is_visible
160          * @var    bool        is_visible            Default visibility condition, to be modified by extensions if needed.
161          * @var    string        mode                Either "topic" or "post"
162          * @var    int            forum_id            Forum id of the current item
163          * @var    array        data                Array of item information
164          * @since 3.2.2-RC1
165          */
166          $vars = array(
167              'is_visible',
168              'mode',
169              'forum_id',
170              'data',
171          );
172          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_is_visible', compact($vars)));
173   
174          return $is_visible;
175      }
176   
177      /**
178      * Create topic/post visibility SQL for a given forum ID
179      *
180      * Note: Read permissions are not checked.
181      *
182      * @param $mode            string    Either "topic" or "post"
183      * @param $forum_id        int        The forum id is used for permission checks
184      * @param $table_alias    string    Table alias to prefix in SQL queries
185      * @return string    The appropriate combination SQL logic for topic/post_visibility
186      */
187      public function get_visibility_sql($mode, $forum_id, $table_alias = '')
188      {
189          $where_sql = '';
190   
191          $get_visibility_sql_overwrite = false;
192   
193          /**
194          * Allow changing the result of calling get_visibility_sql
195          *
196          * @event core.phpbb_content_visibility_get_visibility_sql_before
197          * @var    string        where_sql                        Extra visibility conditions. It must end with either an SQL "AND" or an "OR"
198          * @var    string        mode                            Either "topic" or "post" depending on the query this is being used in
199          * @var    array        forum_id                        The forum id in which the search is made.
200          * @var    string        table_alias                        Table alias to prefix in SQL queries
201          * @var    mixed        get_visibility_sql_overwrite    If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
202          *                                                     If false, get_visibility_sql continues normally
203          *                                                     It must be either boolean or string
204          * @since 3.1.4-RC1
205          */
206          $vars = array(
207              'where_sql',
208              'mode',
209              'forum_id',
210              'table_alias',
211              'get_visibility_sql_overwrite',
212          );
213          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_visibility_sql_before', compact($vars)));
214   
215          if ($get_visibility_sql_overwrite !== false)
216          {
217              return $get_visibility_sql_overwrite;
218          }
219   
220          if ($this->auth->acl_get('m_approve', $forum_id))
221          {
222              $where_sql .= '1 = 1';
223          }
224          else
225          {
226              $visibility_query = $table_alias . $mode . '_visibility = ';
227   
228              $where_sql .= '(' . $visibility_query . ITEM_APPROVED . ')';
229              if ($this->config['display_unapproved_posts'] && ($this->user->data['user_id'] != ANONYMOUS))
230              {
231                  $poster_key = ($mode === 'topic') ? 'topic_poster' : 'poster_id';
232                  $where_sql .= ' OR ((' . $visibility_query . ITEM_UNAPPROVED . ' OR ' . $visibility_query . ITEM_REAPPROVE .')';
233                  $where_sql .= ' AND ' . $table_alias . $poster_key . ' = ' . ((int) $this->user->data['user_id']) . ')';
234              }
235          }
236          return '(' . $where_sql . ')';
237      }
238   
239      /**
240      * Create topic/post visibility SQL for a set of forums
241      *
242      * Note: Read permissions are not checked. Forums without read permissions
243      *        should not be in $forum_ids
244      *
245      * @param $mode            string    Either "topic" or "post"
246      * @param $forum_ids        array    Array of forum ids which the posts/topics are limited to
247      * @param $table_alias    string    Table alias to prefix in SQL queries
248      * @return string    The appropriate combination SQL logic for topic/post_visibility
249      */
250      public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '')
251      {
252          $where_sql = '';
253   
254          $approve_forums = array_keys($this->auth->acl_getf('m_approve', true));
255          if (!empty($forum_ids) && !empty($approve_forums))
256          {
257              $approve_forums = array_intersect($forum_ids, $approve_forums);
258              $forum_ids = array_diff($forum_ids, $approve_forums);
259          }
260   
261          $get_forums_visibility_sql_overwrite = false;
262          /**
263          * Allow changing the result of calling get_forums_visibility_sql
264          *
265          * @event core.phpbb_content_visibility_get_forums_visibility_before
266          * @var    string        where_sql                            Extra visibility conditions. It must end with either an SQL "AND" or an "OR"
267          * @var    string        mode                                Either "topic" or "post" depending on the query this is being used in
268          * @var    array        forum_ids                            Array of forum ids which the posts/topics are limited to
269          * @var    string        table_alias                            Table alias to prefix in SQL queries
270          * @var    array        approve_forums                        Array of forums where the user has m_approve permissions
271          * @var    mixed        get_forums_visibility_sql_overwrite    If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event
272          *                                                         If false, get_forums_visibility_sql continues normally
273          *                                                         It must be either boolean or string
274          * @since 3.1.3-RC1
275          */
276          $vars = array(
277              'where_sql',
278              'mode',
279              'forum_ids',
280              'table_alias',
281              'approve_forums',
282              'get_forums_visibility_sql_overwrite',
283          );
284          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_forums_visibility_before', compact($vars)));
285   
286          if ($get_forums_visibility_sql_overwrite !== false)
287          {
288              return $get_forums_visibility_sql_overwrite;
289          }
290   
291          // Moderator can view all posts/topics in the moderated forums
292          $where_sql .= '(' . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums, false, true) . ' OR ';
293          // Normal user can view approved items only
294          $where_sql .= '(' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . '
295              AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . '))';
296   
297          return '(' . $where_sql . ')';
298      }
299   
300      /**
301      * Create topic/post visibility SQL for all forums on the board
302      *
303      * Note: Read permissions are not checked. Forums without read permissions
304      *        should be in $exclude_forum_ids
305      *
306      * @param $mode                string    Either "topic" or "post"
307      * @param $exclude_forum_ids    array    Array of forum ids which are excluded
308      * @param $table_alias        string    Table alias to prefix in SQL queries
309      * @return string    The appropriate combination SQL logic for topic/post_visibility
310      */
311      public function get_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '')
312      {
313          $where_sqls = array();
314   
315          $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids);
316   
317          $visibility_sql_overwrite = null;
318   
319          /**
320          * Allow changing the result of calling get_global_visibility_sql
321          *
322          * @event core.phpbb_content_visibility_get_global_visibility_before
323          * @var    array        where_sqls                            Array of extra visibility conditions. Will be joined by imploding with "OR".
324          * @var    string        mode                                Either "topic" or "post" depending on the query this is being used in
325          * @var    array        exclude_forum_ids                    Array of forum ids the current user doesn't have access to
326          * @var    string        table_alias                            Table alias to prefix in SQL queries
327          * @var    array        approve_forums                        Array of forums where the user has m_approve permissions
328          * @var    string        visibility_sql_overwrite            If not empty, forces the function to return visibility_sql_overwrite after executing the event
329          * @since 3.1.3-RC1
330          */
331          $vars = array(
332              'where_sqls',
333              'mode',
334              'exclude_forum_ids',
335              'table_alias',
336              'approve_forums',
337              'visibility_sql_overwrite',
338          );
339          extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_get_global_visibility_before', compact($vars)));
340   
341          if ($visibility_sql_overwrite)
342          {
343              return $visibility_sql_overwrite;
344          }
345   
346          // Include approved items in all forums but the excluded
347          $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true, true) . '
348              AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
349   
350          // If user has moderator permissions, add everything in the moderated forums
351          if (count($approve_forums))
352          {
353              $where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums);
354          }
355   
356          return '(' . implode(' OR ', $where_sqls) . ')';
357      }
358   
359      /**
360      * Change visibility status of one post or all posts of a topic
361      *
362      * @param $visibility    int        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
363      * @param $post_id        mixed    Post ID or array of post IDs to act on,
364      *                                if it is empty, all posts of topic_id will be modified
365      * @param $topic_id        int        Topic where $post_id is found
366      * @param $forum_id        int        Forum where $topic_id is found
367      * @param $user_id        int        User performing the action
368      * @param $time            int        Timestamp when the action is performed
369      * @param $reason        string    Reason why the visibility was changed.
370      * @param $is_starter    bool    Is this the first post of the topic changed?
371      * @param $is_latest        bool    Is this the last post of the topic changed?
372      * @param $limit_visibility    mixed    Limit updating per topic_id to a certain visibility
373      * @param $limit_delete_time    mixed    Limit updating per topic_id to a certain deletion time
374      * @return array        Changed post data, empty array if an error occurred.
375      */
376      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)
377      {
378          if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE)))
379          {
380              return array();
381          }
382   
383          if ($post_id)
384          {
385              if (is_array($post_id))
386              {
387                  $where_sql = $this->db->sql_in_set('post_id', array_map('intval', $post_id));
388              }
389              else
390              {
391                  $where_sql = 'post_id = ' . (int) $post_id;
392              }
393              $where_sql .= ' AND topic_id = ' . (int) $topic_id;
394          }
395          else
396          {
397              $where_sql = 'topic_id = ' . (int) $topic_id;
398   
399              // Limit the posts to a certain visibility and deletion time
400              // This allows us to only restore posts, that were approved
401              // when the topic got soft deleted. So previous soft deleted
402              // and unapproved posts are still soft deleted/unapproved
403              if ($limit_visibility !== false)
404              {
405                  $where_sql .= ' AND post_visibility = ' . (int) $limit_visibility;
406              }
407   
408              if ($limit_delete_time !== false)
409              {
410                  $where_sql .= ' AND post_delete_time = ' . (int) $limit_delete_time;
411              }
412          }
413   
414          $sql = 'SELECT poster_id, post_id, post_postcount, post_visibility
415              FROM ' . $this->posts_table . '
416              WHERE ' . $where_sql;
417          $result = $this->db->sql_query($sql);
418   
419          $post_ids = $poster_postcounts = $postcounts = $postcount_visibility = array();
420          while ($row = $this->db->sql_fetchrow($result))
421          {
422              $post_ids[] = (int) $row['post_id'];
423   
424              if ($row['post_visibility'] != $visibility)
425              {
426                  if ($row['post_postcount'] && !isset($poster_postcounts[(int) $row['poster_id']]))
427                  {
428                      $poster_postcounts[(int) $row['poster_id']] = 1;
429                  }
430                  else if ($row['post_postcount'])
431                  {
432                      $poster_postcounts[(int) $row['poster_id']]++;
433                  }
434   
435                  if (!isset($postcount_visibility[$row['post_visibility']]))
436                  {
437                      $postcount_visibility[$row['post_visibility']] = 1;
438                  }
439                  else
440                  {
441                      $postcount_visibility[$row['post_visibility']]++;
442                  }
443              }
444          }
445          $this->db->sql_freeresult($result);
446   
447          if (empty($post_ids))
448          {
449              return array();
450          }
451   
452          if (!function_exists('truncate_string'))
453          {
454              include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
455          }
456   
457          $data = array(
458              'post_visibility'        => (int) $visibility,
459              'post_delete_user'        => (int) $user_id,
460              'post_delete_time'        => ((int) $time) ?: time(),
461              'post_delete_reason'    => truncate_string($reason, 255, 255, false),
462          );
463          /**
464           * Perform actions right before the query to change post visibility
465           *
466           * @event core.set_post_visibility_before_sql
467           * @var            int            visibility        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
468           * @var            array        post_id            Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
469           * @var            int            topic_id        Topic of the post IDs to be modified.
470           * @var            int            forum_id        Forum ID that the topic_id resides in.
471           * @var            int            user_id            User ID doing this action.
472           * @var            int            time            Timestamp of this action.
473           * @var            string        reason            Reason specified by the user for this change.
474           * @var            bool        is_starter        Are we changing the topic's starter?
475           * @var            bool        is_latest        Are we changing the topic's latest post?
476           * @var            array        data            The data array for this action.
477           * @since 3.1.10-RC1
478           * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
479           */
480          $vars = array(
481              'visibility',
482              'post_id',
483              'topic_id',
484              'forum_id',
485              'user_id',
486              'time',
487              'reason',
488              'is_starter',
489              'is_latest',
490              'data',
491          );
492          extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_before_sql', compact($vars)));
493          $sql = 'UPDATE ' . $this->posts_table . '
494              SET ' . $this->db->sql_build_array('UPDATE', $data) . '
495              WHERE ' . $this->db->sql_in_set('post_id', $post_ids);
496          $this->db->sql_query($sql);
497   
498          // Group the authors by post count, to reduce the number of queries
499          foreach ($poster_postcounts as $poster_id => $num_posts)
500          {
501              $postcounts[$num_posts][] = $poster_id;
502          }
503   
504          $postcount_change = 0;
505   
506          // Update users postcounts
507          foreach ($postcounts as $num_posts => $poster_ids)
508          {
509              if (in_array($visibility, array(ITEM_REAPPROVE, ITEM_DELETED)))
510              {
511                  $postcount_change -= $num_posts;
512   
513                  $sql = 'UPDATE ' . $this->users_table . '
514                      SET user_posts = 0
515                      WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . '
516                          AND user_posts < ' . $num_posts;
517                  $this->db->sql_query($sql);
518   
519                  $sql = 'UPDATE ' . $this->users_table . '
520                      SET user_posts = user_posts - ' . $num_posts . '
521                      WHERE ' . $this->db->sql_in_set('user_id', $poster_ids) . '
522                          AND user_posts >= ' . $num_posts;
523                  $this->db->sql_query($sql);
524              }
525              else
526              {
527                  $postcount_change += $num_posts;
528   
529                  $sql = 'UPDATE ' . $this->users_table . '
530                      SET user_posts = user_posts + ' . $num_posts . '
531                      WHERE ' . $this->db->sql_in_set('user_id', $poster_ids);
532                  $this->db->sql_query($sql);
533              }
534          }
535   
536          if ($postcount_change != 0)
537          {
538              $this->config->increment('num_posts', $postcount_change, false);
539          }
540   
541          $update_topic_postcount = true;
542   
543          // Sync the first/last topic information if needed
544          if (!$is_starter && $is_latest)
545          {
546              if (!function_exists('update_post_information'))
547              {
548                  include($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext);
549              }
550   
551              // update_post_information can only update the last post info ...
552              if ($topic_id)
553              {
554                  update_post_information('topic', $topic_id, false);
555              }
556              if ($forum_id)
557              {
558                  update_post_information('forum', $forum_id, false);
559              }
560          }
561          else if ($is_starter && $topic_id)
562          {
563              if (!function_exists('sync'))
564              {
565                  include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
566              }
567   
568              // ... so we need to use sync, if the first post is changed.
569              // The forum is resynced recursive by sync() itself.
570              sync('topic', 'topic_id', $topic_id, true);
571   
572              // sync recalculates the topic replies and forum posts by itself, so we don't do that.
573              $update_topic_postcount = false;
574          }
575   
576          $topic_update_array = array();
577          // Update the topic's reply count and the forum's post count
578          if ($update_topic_postcount)
579          {
580              $field_alias = array(
581                  ITEM_APPROVED    => 'posts_approved',
582                  ITEM_UNAPPROVED    => 'posts_unapproved',
583                  ITEM_DELETED    => 'posts_softdeleted',
584                  ITEM_REAPPROVE    => 'posts_unapproved',
585              );
586              $cur_posts = array_fill_keys($field_alias, 0);
587   
588              foreach ($postcount_visibility as $post_visibility => $visibility_posts)
589              {
590                  $cur_posts[$field_alias[(int) $post_visibility]] += $visibility_posts;
591              }
592   
593              $sql_ary = array();
594              $recipient_field = $field_alias[$visibility];
595   
596              foreach ($cur_posts as $field => $count)
597              {
598                  // Decrease the count for the old statuses.
599                  if ($count && $field != $recipient_field)
600                  {
601                      $sql_ary[$field] = " - $count";
602                  }
603              }
604              // Add up the count from all statuses excluding the recipient status.
605              $count_increase = array_sum(array_diff($cur_posts, array($recipient_field)));
606   
607              if ($count_increase)
608              {
609                  $sql_ary[$recipient_field] = " + $count_increase";
610              }
611   
612              if (count($sql_ary))
613              {
614                  $forum_sql = array();
615   
616                  foreach ($sql_ary as $field => $value_change)
617                  {
618                      $topic_update_array[] = 'topic_' . $field . ' = topic_' . $field . $value_change;
619                      $forum_sql[] = 'forum_' . $field . ' = forum_' . $field . $value_change;
620                  }
621   
622                  $sql = 'UPDATE ' . $this->forums_table . '
623                      SET ' . implode(', ', $forum_sql) . '
624                      WHERE forum_id = ' . (int) $forum_id;
625                  $this->db->sql_query($sql);
626              }
627          }
628   
629          if ($post_id)
630          {
631              $sql = 'SELECT 1 AS has_attachments
632                  FROM ' . POSTS_TABLE . '
633                  WHERE topic_id = ' . (int) $topic_id . '
634                      AND post_attachment = 1
635                      AND post_visibility = ' . ITEM_APPROVED . '
636                      AND ' . $this->db->sql_in_set('post_id', $post_id, true);
637              $result = $this->db->sql_query_limit($sql, 1);
638   
639              $has_attachment = (bool) $this->db->sql_fetchfield('has_attachments');
640              $this->db->sql_freeresult($result);
641   
642              if ($has_attachment && $visibility == ITEM_APPROVED)
643              {
644                  $topic_update_array[] = 'topic_attachment = 1';
645              }
646              else if (!$has_attachment && $visibility != ITEM_APPROVED)
647              {
648                  $topic_update_array[] = 'topic_attachment = 0';
649              }
650          }
651   
652          if (!empty($topic_update_array))
653          {
654              // Update the number for replies and posts, and update the attachments flag
655              $sql = 'UPDATE ' . $this->topics_table . '
656                  SET ' . implode(', ', $topic_update_array) . '
657                  WHERE topic_id = ' . (int) $topic_id;
658              $this->db->sql_query($sql);
659          }
660          /**
661           * Perform actions after all steps to changing post visibility
662           *
663           * @event core.set_post_visibility_after
664           * @var            int            visibility        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
665           * @var            array        post_id            Array containing all post IDs to be modified. If blank, all posts within the topic are modified.
666           * @var            int            topic_id        Topic of the post IDs to be modified.
667           * @var            int            forum_id        Forum ID that the topic_id resides in.
668           * @var            int            user_id            User ID doing this action.
669           * @var            int            time            Timestamp of this action.
670           * @var            string        reason            Reason specified by the user for this change.
671           * @var            bool        is_starter        Are we changing the topic's starter?
672           * @var            bool        is_latest        Are we changing the topic's latest post?
673           * @var            array        data            The data array for this action.
674           * @since 3.1.10-RC1
675           * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
676           */
677          $vars = array(
678              'visibility',
679              'post_id',
680              'topic_id',
681              'forum_id',
682              'user_id',
683              'time',
684              'reason',
685              'is_starter',
686              'is_latest',
687              'data',
688          );
689          extract($this->phpbb_dispatcher->trigger_event('core.set_post_visibility_after', compact($vars)));
690          return $data;
691      }
692   
693      /**
694      * Set topic visibility
695      *
696      * Allows approving (which is akin to undeleting/restore) or soft deleting an entire topic.
697      * Calls set_post_visibility as needed.
698      *
699      * Note: By default, when a soft deleted topic is restored. Only posts that
700      *        were approved at the time of soft deleting, are being restored.
701      *        Same applies to soft deleting. Only approved posts will be marked
702      *        as soft deleted.
703      *        If you want to update all posts, use the force option.
704      *
705      * @param $visibility    int        Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
706      * @param $topic_id        mixed    Topic ID to act on
707      * @param $forum_id        int        Forum where $topic_id is found
708      * @param $user_id        int        User performing the action
709      * @param $time            int        Timestamp when the action is performed
710      * @param $reason        string    Reason why the visibilty was changed.
711      * @param $force_update_all    bool    Force to update all posts within the topic
712      * @return array        Changed topic data, empty array if an error occurred.
713      */
714      public function set_topic_visibility($visibility, $topic_id, $forum_id, $user_id, $time, $reason, $force_update_all = false)
715      {
716          if (!in_array($visibility, array(ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE)))
717          {
718              return array();
719          }
720   
721          if (!$force_update_all)
722          {
723              $sql = 'SELECT topic_visibility, topic_delete_time
724                  FROM ' . $this->topics_table . '
725                  WHERE topic_id = ' . (int) $topic_id;
726              $result = $this->db->sql_query($sql);
727              $original_topic_data = $this->db->sql_fetchrow($result);
728              $this->db->sql_freeresult($result);
729   
730              if (!$original_topic_data)
731              {
732                  // The topic does not exist...
733                  return array();
734              }
735          }
736   
737          if (!function_exists('truncate_string'))
738          {
739              include($this->phpbb_root_path . 'includes/functions_content.' . $this->php_ext);
740          }
741   
742          // Note, we do not set a reason for the posts, just for the topic
743          $data = array(
744              'topic_visibility'        => (int) $visibility,
745              'topic_delete_user'        => (int) $user_id,
746              'topic_delete_time'        => ((int) $time) ?: time(),
747              'topic_delete_reason'    => truncate_string($reason, 255, 255, false),
748          );
749          /**
750           * Perform actions right before the query to change topic visibility
751           *
752           * @event core.set_topic_visibility_before_sql
753           * @var            int            visibility            Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
754           * @var            int            topic_id            Topic of the post IDs to be modified.
755           * @var            int            forum_id            Forum ID that the topic_id resides in.
756           * @var            int            user_id                User ID doing this action.
757           * @var            int            time                Timestamp of this action.
758           * @var            string        reason                Reason specified by the user for this change.
759           * @var            bool        force_update_all    Force an update on all posts within the topic, regardless of their current approval state.
760           * @var            array        data                The data array for this action.
761           * @since 3.1.10-RC1
762           * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
763           */
764          $vars = array(
765              'visibility',
766              'topic_id',
767              'forum_id',
768              'user_id',
769              'time',
770              'reason',
771              'force_update_all',
772              'data',
773          );
774          extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_before_sql', compact($vars)));
775          $sql = 'UPDATE ' . $this->topics_table . '
776              SET ' . $this->db->sql_build_array('UPDATE', $data) . '
777              WHERE topic_id = ' . (int) $topic_id;
778          $this->db->sql_query($sql);
779   
780          if (!$this->db->sql_affectedrows())
781          {
782              return array();
783          }
784   
785          if (!$force_update_all && $original_topic_data['topic_delete_time'] && $original_topic_data['topic_visibility'] == ITEM_DELETED && $visibility == ITEM_APPROVED)
786          {
787              // If we're restoring a topic we only restore posts, that were soft deleted through the topic soft deletion.
788              $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']);
789          }
790          else if (!$force_update_all && $original_topic_data['topic_visibility'] == ITEM_APPROVED && $visibility == ITEM_DELETED)
791          {
792              // If we're soft deleting a topic we only mark approved posts as soft deleted.
793              $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true, $original_topic_data['topic_visibility']);
794          }
795          else
796          {
797              $this->set_post_visibility($visibility, false, $topic_id, $forum_id, $user_id, $time, '', true, true);
798          }
799          /**
800           * Perform actions after all steps to changing topic visibility
801           *
802           * @event core.set_topic_visibility_after
803           * @var            int            visibility            Element of {ITEM_APPROVED, ITEM_DELETED, ITEM_REAPPROVE}
804           * @var            int            topic_id            Topic of the post IDs to be modified.
805           * @var            int            forum_id            Forum ID that the topic_id resides in.
806           * @var            int            user_id                User ID doing this action.
807           * @var            int            time                Timestamp of this action.
808           * @var            string        reason                Reason specified by the user for this change.
809           * @var            bool        force_update_all    Force an update on all posts within the topic, regardless of their current approval state.
810           * @var            array        data                The data array for this action.
811           * @since 3.1.10-RC1
812           * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
813           */
814          $vars = array(
815              'visibility',
816              'topic_id',
817              'forum_id',
818              'user_id',
819              'time',
820              'reason',
821              'force_update_all',
822              'data',
823          );
824          extract($this->phpbb_dispatcher->trigger_event('core.set_topic_visibility_after', compact($vars)));
825          return $data;
826      }
827   
828      /**
829      * Add post to topic and forum statistics
830      *
831      * @param $data            array    Contains information from the topics table about given topic
832      * @param $sql_data        array    Populated with the SQL changes, may be empty at call time (by reference)
833      * @return null
834      */
835      public function add_post_to_statistic($data, &$sql_data)
836      {
837          $sql_data[$this->topics_table] = (($sql_data[$this->topics_table]) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved + 1';
838   
839          $sql_data[$this->forums_table] = (($sql_data[$this->forums_table]) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved + 1';
840   
841          if ($data['post_postcount'])
842          {
843              $sql_data[$this->users_table] = (($sql_data[$this->users_table]) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts + 1';
844          }
845   
846          $this->config->increment('num_posts', 1, false);
847      }
848   
849      /**
850      * Remove post from topic and forum statistics
851      *
852      * @param $data            array    Contains information from the topics table about given topic
853      * @param $sql_data        array    Populated with the SQL changes, may be empty at call time (by reference)
854      * @return null
855      */
856      public function remove_post_from_statistic($data, &$sql_data)
857      {
858          if ($data['post_visibility'] == ITEM_APPROVED)
859          {
860              $sql_data[$this->topics_table] = ((!empty($sql_data[$this->topics_table])) ? $sql_data[$this->topics_table] . ', ' : '') . 'topic_posts_approved = topic_posts_approved - 1';
861              $sql_data[$this->forums_table] = ((!empty($sql_data[$this->forums_table])) ? $sql_data[$this->forums_table] . ', ' : '') . 'forum_posts_approved = forum_posts_approved - 1';
862   
863              if ($data['post_postcount'])
864              {
865                  $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1';
866              }
867   
868              $this->config->increment('num_posts', -1, false);
869          }
870          else if ($data['post_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE)
871          {
872              $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_unapproved = forum_posts_unapproved - 1';
873              $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_unapproved = topic_posts_unapproved - 1';
874          }
875          else if ($data['post_visibility'] == ITEM_DELETED)
876          {
877              $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_softdeleted = forum_posts_softdeleted - 1';
878              $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_softdeleted = topic_posts_softdeleted - 1';
879          }
880      }
881   
882      /**
883      * Remove topic from forum statistics
884      *
885      * @param $data            array    Post and topic data
886      * @param $sql_data        array    Populated with the SQL changes, may be empty at call time (by reference)
887      * @return null
888      */
889      public function remove_topic_from_statistic($data, &$sql_data)
890      {
891          if ($data['topic_visibility'] == ITEM_APPROVED)
892          {
893              $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1';
894   
895              if ($data['post_postcount'])
896              {
897                  $sql_data[$this->users_table] = ((!empty($sql_data[$this->users_table])) ? $sql_data[$this->users_table] . ', ' : '') . 'user_posts = user_posts - 1';
898              }
899          }
900          else if ($data['topic_visibility'] == ITEM_UNAPPROVED || $data['post_visibility'] == ITEM_REAPPROVE)
901          {
902              $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1';
903          }
904          else if ($data['topic_visibility'] == ITEM_DELETED)
905          {
906              $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1';
907          }
908   
909      }
910  }
911