[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/phpbb/attachment/ -> delete.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  namespace phpbb\attachment;
  15  
  16  use phpbb\config\config;
  17  use phpbb\db\driver\driver_interface;
  18  use phpbb\event\dispatcher;
  19  use phpbb\filesystem\filesystem;
  20  
  21  /**
  22   * Attachment delete class
  23   */
  24  class delete
  25  {
  26      /** @var config */
  27      protected $config;
  28  
  29      /** @var driver_interface */
  30      protected $db;
  31  
  32      /** @var dispatcher */
  33      protected $dispatcher;
  34  
  35      /** @var filesystem  */
  36      protected $filesystem;
  37  
  38      /** @var resync */
  39      protected $resync;
  40  
  41      /** @var string phpBB root path */
  42      protected $phpbb_root_path;
  43  
  44      /** @var array Attachement IDs */
  45      protected $ids;
  46  
  47      /** @var string SQL ID string */
  48      private $sql_id;
  49  
  50      /** @var string SQL where string */
  51      private $sql_where = '';
  52  
  53      /** @var int Number of deleted items */
  54      private $num_deleted;
  55  
  56      /** @var array Post IDs */
  57      private $post_ids = array();
  58  
  59      /** @var array Message IDs */
  60      private $message_ids = array();
  61  
  62      /** @var array Topic IDs */
  63      private $topic_ids = array();
  64  
  65      /** @var array Info of physical file */
  66      private $physical = array();
  67  
  68      /**
  69       * Attachment delete class constructor
  70       *
  71       * @param config $config
  72       * @param driver_interface $db
  73       * @param dispatcher $dispatcher
  74       * @param filesystem $filesystem
  75       * @param resync $resync
  76       * @param string $phpbb_root_path
  77       */
  78  	public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, filesystem $filesystem, resync $resync, $phpbb_root_path)
  79      {
  80          $this->config = $config;
  81          $this->db = $db;
  82          $this->dispatcher = $dispatcher;
  83          $this->filesystem = $filesystem;
  84          $this->resync = $resync;
  85          $this->phpbb_root_path = $phpbb_root_path;
  86      }
  87  
  88      /**
  89       * Delete Attachments
  90       *
  91       * @param string $mode can be: post|message|topic|attach|user
  92       * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
  93       * @param bool $resync set this to false if you are deleting posts or topics
  94       *
  95       * @return int|bool Number of deleted attachments or false if something
  96       *            went wrong during attachment deletion
  97       */
  98  	public function delete($mode, $ids, $resync = true)
  99      {
 100          if (!$this->set_attachment_ids($ids))
 101          {
 102              return false;
 103          }
 104  
 105          $this->set_sql_constraints($mode);
 106  
 107          $sql_id = $this->sql_id;
 108  
 109          /**
 110           * Perform additional actions before collecting data for attachment(s) deletion
 111           *
 112           * @event core.delete_attachments_collect_data_before
 113           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
 114           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
 115           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
 116           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
 117           * @since 3.1.7-RC1
 118           */
 119          $vars = array(
 120              'mode',
 121              'ids',
 122              'resync',
 123              'sql_id',
 124          );
 125          extract($this->dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
 126  
 127          $this->sql_id = $sql_id;
 128          unset($sql_id);
 129  
 130          // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
 131          $this->collect_attachment_info($resync);
 132  
 133          // Delete attachments from database
 134          $this->delete_attachments_from_db($mode, $ids, $resync);
 135  
 136          $sql_id = $this->sql_id;
 137          $post_ids = $this->post_ids;
 138          $topic_ids = $this->topic_ids;
 139          $message_ids = $this->message_ids;
 140          $physical = $this->physical;
 141          $num_deleted = $this->num_deleted;
 142  
 143          /**
 144           * Perform additional actions after attachment(s) deletion from the database
 145           *
 146           * @event core.delete_attachments_from_database_after
 147           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
 148           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
 149           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
 150           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
 151           * @var    array    post_ids        Array with post ids for deleted attachment(s)
 152           * @var    array    topic_ids        Array with topic ids for deleted attachment(s)
 153           * @var    array    message_ids        Array with private message ids for deleted attachment(s)
 154           * @var    array    physical        Array with deleted attachment(s) physical file(s) data
 155           * @var    int        num_deleted        The number of deleted attachment(s) from the database
 156           * @since 3.1.7-RC1
 157           */
 158          $vars = array(
 159              'mode',
 160              'ids',
 161              'resync',
 162              'sql_id',
 163              'post_ids',
 164              'topic_ids',
 165              'message_ids',
 166              'physical',
 167              'num_deleted',
 168          );
 169          extract($this->dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
 170  
 171          $this->sql_id = $sql_id;
 172          $this->post_ids = $post_ids;
 173          $this->topic_ids = $topic_ids;
 174          $this->message_ids = $message_ids;
 175          $this->physical = $physical;
 176          $this->num_deleted = $num_deleted;
 177          unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical, $num_deleted);
 178  
 179          if (!$this->num_deleted)
 180          {
 181              return 0;
 182          }
 183  
 184          // Delete attachments from filesystem
 185          $this->remove_from_filesystem($mode, $ids, $resync);
 186  
 187          // If we do not resync, we do not need to adjust any message, post, topic or user entries
 188          if (!$resync)
 189          {
 190              return $this->num_deleted;
 191          }
 192  
 193          // No more use for the original ids
 194          unset($ids);
 195  
 196          // Update post indicators for posts now no longer having attachments
 197          $this->resync->resync('post', $this->post_ids);
 198  
 199          // Update message table if messages are affected
 200          $this->resync->resync('message', $this->message_ids);
 201  
 202          // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
 203          $this->resync->resync('topic', $this->topic_ids);
 204  
 205          return $this->num_deleted;
 206      }
 207  
 208      /**
 209       * Set attachment IDs
 210       *
 211       * @param mixed $ids ID or array of IDs
 212       *
 213       * @return bool True if attachment IDs were set, false if not
 214       */
 215  	protected function set_attachment_ids($ids)
 216      {
 217          // 0 is as bad as an empty array
 218          if (empty($ids))
 219          {
 220              return false;
 221          }
 222  
 223          if (is_array($ids))
 224          {
 225              $ids = array_unique($ids);
 226              $this->ids = array_map('intval', $ids);
 227          }
 228          else
 229          {
 230              $this->ids = array((int) $ids);
 231          }
 232  
 233          return true;
 234      }
 235  
 236      /**
 237       * Set SQL constraints based on mode
 238       *
 239       * @param string $mode Delete mode; can be: post|message|topic|attach|user
 240       */
 241  	private function set_sql_constraints($mode)
 242      {
 243          switch ($mode)
 244          {
 245              case 'post':
 246              case 'message':
 247                  $this->sql_id = 'post_msg_id';
 248                  $this->sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
 249              break;
 250  
 251              case 'topic':
 252                  $this->sql_id = 'topic_id';
 253              break;
 254  
 255              case 'user':
 256                  $this->sql_id = 'poster_id';
 257              break;
 258  
 259              case 'attach':
 260              default:
 261                  $this->sql_id = 'attach_id';
 262              break;
 263          }
 264      }
 265  
 266      /**
 267       * Collect info about attachment IDs
 268       *
 269       * @param bool $resync Whether topics/posts should be resynced after delete
 270       */
 271  	protected function collect_attachment_info($resync)
 272      {
 273          // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
 274          $sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
 275              FROM ' . ATTACHMENTS_TABLE . '
 276              WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
 277  
 278          $sql .= $this->sql_where;
 279  
 280          $result = $this->db->sql_query($sql);
 281  
 282          while ($row = $this->db->sql_fetchrow($result))
 283          {
 284              // We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
 285              if ($resync && !$row['is_orphan'])
 286              {
 287                  if (!$row['in_message'])
 288                  {
 289                      $this->post_ids[] = $row['post_msg_id'];
 290                      $this->topic_ids[] = $row['topic_id'];
 291                  }
 292                  else
 293                  {
 294                      $this->message_ids[] = $row['post_msg_id'];
 295                  }
 296              }
 297  
 298              $this->physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
 299          }
 300          $this->db->sql_freeresult($result);
 301  
 302          // IDs should be unique
 303          $this->post_ids = array_unique($this->post_ids);
 304          $this->message_ids = array_unique($this->message_ids);
 305          $this->topic_ids = array_unique($this->topic_ids);
 306      }
 307  
 308      /**
 309       * Delete attachments from database table
 310       */
 311  	protected function delete_attachments_from_db($mode, $ids, $resync)
 312      {
 313          $sql_id = $this->sql_id;
 314          $post_ids = $this->post_ids;
 315          $topic_ids = $this->topic_ids;
 316          $message_ids = $this->message_ids;
 317          $physical = $this->physical;
 318  
 319          /**
 320           * Perform additional actions before attachment(s) deletion
 321           *
 322           * @event core.delete_attachments_before
 323           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
 324           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
 325           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
 326           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
 327           * @var    array    post_ids        Array with post ids for deleted attachment(s)
 328           * @var    array    topic_ids        Array with topic ids for deleted attachment(s)
 329           * @var    array    message_ids        Array with private message ids for deleted attachment(s)
 330           * @var    array    physical        Array with deleted attachment(s) physical file(s) data
 331           * @since 3.1.7-RC1
 332           */
 333          $vars = array(
 334              'mode',
 335              'ids',
 336              'resync',
 337              'sql_id',
 338              'post_ids',
 339              'topic_ids',
 340              'message_ids',
 341              'physical',
 342          );
 343          extract($this->dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
 344  
 345          $this->sql_id = $sql_id;
 346          $this->post_ids = $post_ids;
 347          $this->topic_ids = $topic_ids;
 348          $this->message_ids = $message_ids;
 349          $this->physical = $physical;
 350          unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical);
 351  
 352          // Delete attachments
 353          $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
 354              WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
 355  
 356          $sql .= $this->sql_where;
 357  
 358          $this->db->sql_query($sql);
 359          $this->num_deleted = $this->db->sql_affectedrows();
 360      }
 361  
 362      /**
 363       * Delete attachments from filesystem
 364       */
 365  	protected function remove_from_filesystem($mode, $ids, $resync)
 366      {
 367          $space_removed = $files_removed = 0;
 368  
 369          foreach ($this->physical as $file_ary)
 370          {
 371              if ($this->unlink_attachment($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
 372              {
 373                  // Only non-orphaned files count to the file size
 374                  $space_removed += $file_ary['filesize'];
 375                  $files_removed++;
 376              }
 377  
 378              if ($file_ary['thumbnail'])
 379              {
 380                  $this->unlink_attachment($file_ary['filename'], 'thumbnail', true);
 381              }
 382          }
 383  
 384          $sql_id = $this->sql_id;
 385          $post_ids = $this->post_ids;
 386          $topic_ids = $this->topic_ids;
 387          $message_ids = $this->message_ids;
 388          $physical = $this->physical;
 389          $num_deleted = $this->num_deleted;
 390  
 391          /**
 392           * Perform additional actions after attachment(s) deletion from the filesystem
 393           *
 394           * @event core.delete_attachments_from_filesystem_after
 395           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
 396           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
 397           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
 398           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
 399           * @var    array    post_ids        Array with post ids for deleted attachment(s)
 400           * @var    array    topic_ids        Array with topic ids for deleted attachment(s)
 401           * @var    array    message_ids        Array with private message ids for deleted attachment(s)
 402           * @var    array    physical        Array with deleted attachment(s) physical file(s) data
 403           * @var    int        num_deleted        The number of deleted attachment(s) from the database
 404           * @var    int        space_removed    The size of deleted files(s) from the filesystem
 405           * @var    int        files_removed    The number of deleted file(s) from the filesystem
 406           * @since 3.1.7-RC1
 407           */
 408          $vars = array(
 409              'mode',
 410              'ids',
 411              'resync',
 412              'sql_id',
 413              'post_ids',
 414              'topic_ids',
 415              'message_ids',
 416              'physical',
 417              'num_deleted',
 418              'space_removed',
 419              'files_removed',
 420          );
 421          extract($this->dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
 422  
 423          $this->sql_id = $sql_id;
 424          $this->post_ids = $post_ids;
 425          $this->topic_ids = $topic_ids;
 426          $this->message_ids = $message_ids;
 427          $this->physical = $physical;
 428          $this->num_deleted = $num_deleted;
 429          unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical, $num_deleted);
 430  
 431          if ($space_removed || $files_removed)
 432          {
 433              $this->config->increment('upload_dir_size', $space_removed * (-1), false);
 434              $this->config->increment('num_files', $files_removed * (-1), false);
 435          }
 436      }
 437  
 438      /**
 439       * Delete attachment from filesystem
 440       *
 441       * @param string $filename Filename of attachment
 442       * @param string $mode Delete mode
 443       * @param bool $entry_removed Whether entry was removed. Defaults to false
 444       * @return bool True if file was removed, false if not
 445       */
 446  	public function unlink_attachment($filename, $mode = 'file', $entry_removed = false)
 447      {
 448          // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
 449          $sql = 'SELECT COUNT(attach_id) AS num_entries
 450          FROM ' . ATTACHMENTS_TABLE . "
 451          WHERE physical_filename = '" . $this->db->sql_escape(utf8_basename($filename)) . "'";
 452          $result = $this->db->sql_query($sql);
 453          $num_entries = (int) $this->db->sql_fetchfield('num_entries');
 454          $this->db->sql_freeresult($result);
 455  
 456          // Do not remove file if at least one additional entry with the same name exist.
 457          if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
 458          {
 459              return false;
 460          }
 461  
 462          $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
 463          $filepath = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename;
 464  
 465          try
 466          {
 467              if ($this->filesystem->exists($filepath))
 468              {
 469                  $this->filesystem->remove($this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename);
 470                  return true;
 471              }
 472          }
 473          catch (\phpbb\filesystem\exception\filesystem_exception $exception)
 474          {
 475              // Fail is covered by return statement below
 476          }
 477  
 478          return false;
 479      }
 480  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1