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

delete.php

Zuletzt modifiziert: 09.10.2024, 12:52 - Dateigröße: 12.50 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\attachment;
015   
016  use \phpbb\config\config;
017  use \phpbb\db\driver\driver_interface;
018  use \phpbb\event\dispatcher;
019  use \phpbb\filesystem\filesystem;
020   
021  /**
022   * Attachment delete class
023   */
024  class delete
025  {
026      /** @var config */
027      protected $config;
028   
029      /** @var driver_interface */
030      protected $db;
031   
032      /** @var dispatcher */
033      protected $dispatcher;
034   
035      /** @var filesystem  */
036      protected $filesystem;
037   
038      /** @var resync */
039      protected $resync;
040   
041      /** @var string phpBB root path */
042      protected $phpbb_root_path;
043   
044      /** @var array Attachement IDs */
045      protected $ids;
046   
047      /** @var string SQL ID string */
048      private $sql_id;
049   
050      /** @var string SQL where string */
051      private $sql_where = '';
052   
053      /** @var int Number of deleted items */
054      private $num_deleted;
055   
056      /** @var array Post IDs */
057      private $post_ids = array();
058   
059      /** @var array Message IDs */
060      private $message_ids = array();
061   
062      /** @var array Topic IDs */
063      private $topic_ids = array();
064   
065      /** @var array Info of physical file */
066      private $physical = array();
067   
068      /**
069       * Attachment delete class constructor
070       *
071       * @param config $config
072       * @param driver_interface $db
073       * @param dispatcher $dispatcher
074       * @param filesystem $filesystem
075       * @param resync $resync
076       * @param string $phpbb_root_path
077       */
078      public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, filesystem $filesystem, resync $resync, $phpbb_root_path)
079      {
080          $this->config = $config;
081          $this->db = $db;
082          $this->dispatcher = $dispatcher;
083          $this->filesystem = $filesystem;
084          $this->resync = $resync;
085          $this->phpbb_root_path = $phpbb_root_path;
086      }
087   
088      /**
089       * Delete Attachments
090       *
091       * @param string $mode can be: post|message|topic|attach|user
092       * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
093       * @param bool $resync set this to false if you are deleting posts or topics
094       *
095       * @return int|bool Number of deleted attachments or false if something
096       *            went wrong during attachment deletion
097       */
098      public function delete($mode, $ids, $resync = true)
099      {
100          if (!$this->set_attachment_ids($ids))
101          {
102              return false;
103          }
104   
105          $this->set_sql_constraints($mode);
106   
107          /**
108           * Perform additional actions before collecting data for attachment(s) deletion
109           *
110           * @event core.delete_attachments_collect_data_before
111           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
112           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
113           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
114           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
115           * @since 3.1.7-RC1
116           */
117          $vars = array(
118              'mode',
119              'ids',
120              'resync',
121              'sql_id',
122          );
123          extract($this->dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
124   
125          // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
126          $this->collect_attachment_info($resync);
127   
128          // Delete attachments from database
129          $this->delete_attachments_from_db();
130   
131          /**
132           * Perform additional actions after attachment(s) deletion from the database
133           *
134           * @event core.delete_attachments_from_database_after
135           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
136           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
137           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
138           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
139           * @var    array    post_ids        Array with post ids for deleted attachment(s)
140           * @var    array    topic_ids        Array with topic ids for deleted attachment(s)
141           * @var    array    message_ids        Array with private message ids for deleted attachment(s)
142           * @var    array    physical        Array with deleted attachment(s) physical file(s) data
143           * @var    int        num_deleted        The number of deleted attachment(s) from the database
144           * @since 3.1.7-RC1
145           */
146          $vars = array(
147              'mode',
148              'ids',
149              'resync',
150              'sql_id',
151              'post_ids',
152              'topic_ids',
153              'message_ids',
154              'physical',
155              'num_deleted',
156          );
157          extract($this->dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
158   
159          if (!$this->num_deleted)
160          {
161              return 0;
162          }
163   
164          // Delete attachments from filesystem
165          $this->remove_from_filesystem();
166   
167          // If we do not resync, we do not need to adjust any message, post, topic or user entries
168          if (!$resync)
169          {
170              return $this->num_deleted;
171          }
172   
173          // No more use for the original ids
174          unset($ids);
175   
176          // Update post indicators for posts now no longer having attachments
177          $this->resync->resync('post', $this->post_ids);
178   
179          // Update message table if messages are affected
180          $this->resync->resync('message', $this->message_ids);
181   
182          // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
183          $this->resync->resync('topic', $this->topic_ids);
184   
185          return $this->num_deleted;
186      }
187   
188      /**
189       * Set attachment IDs
190       *
191       * @param mixed $ids ID or array of IDs
192       *
193       * @return bool True if attachment IDs were set, false if not
194       */
195      protected function set_attachment_ids($ids)
196      {
197          // 0 is as bad as an empty array
198          if (empty($ids))
199          {
200              return false;
201          }
202   
203          if (is_array($ids))
204          {
205              $ids = array_unique($ids);
206              $this->ids = array_map('intval', $ids);
207          }
208          else
209          {
210              $this->ids = array((int) $ids);
211          }
212   
213          return true;
214      }
215   
216      /**
217       * Set SQL constraints based on mode
218       *
219       * @param string $mode Delete mode; can be: post|message|topic|attach|user
220       */
221      private function set_sql_constraints($mode)
222      {
223          switch ($mode)
224          {
225              case 'post':
226              case 'message':
227                  $this->sql_id = 'post_msg_id';
228                  $this->sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
229              break;
230   
231              case 'topic':
232                  $this->sql_id = 'topic_id';
233              break;
234   
235              case 'user':
236                  $this->sql_id = 'poster_id';
237              break;
238   
239              case 'attach':
240              default:
241                  $this->sql_id = 'attach_id';
242              break;
243          }
244      }
245   
246      /**
247       * Collect info about attachment IDs
248       *
249       * @param bool $resync Whether topics/posts should be resynced after delete
250       */
251      protected function collect_attachment_info($resync)
252      {
253          // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
254          $sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
255              FROM ' . ATTACHMENTS_TABLE . '
256              WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
257   
258          $sql .= $this->sql_where;
259   
260          $result = $this->db->sql_query($sql);
261   
262          while ($row = $this->db->sql_fetchrow($result))
263          {
264              // We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
265              if ($resync && !$row['is_orphan'])
266              {
267                  if (!$row['in_message'])
268                  {
269                      $this->post_ids[] = $row['post_msg_id'];
270                      $this->topic_ids[] = $row['topic_id'];
271                  }
272                  else
273                  {
274                      $this->message_ids[] = $row['post_msg_id'];
275                  }
276              }
277   
278              $this->physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
279          }
280          $this->db->sql_freeresult($result);
281   
282          // IDs should be unique
283          $this->post_ids = array_unique($this->post_ids);
284          $this->message_ids = array_unique($this->message_ids);
285          $this->topic_ids = array_unique($this->topic_ids);
286      }
287   
288      /**
289       * Delete attachments from database table
290       */
291      protected function delete_attachments_from_db()
292      {
293          /**
294           * Perform additional actions before attachment(s) deletion
295           *
296           * @event core.delete_attachments_before
297           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
298           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
299           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
300           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
301           * @var    array    post_ids        Array with post ids for deleted attachment(s)
302           * @var    array    topic_ids        Array with topic ids for deleted attachment(s)
303           * @var    array    message_ids        Array with private message ids for deleted attachment(s)
304           * @var    array    physical        Array with deleted attachment(s) physical file(s) data
305           * @since 3.1.7-RC1
306           */
307          $vars = array(
308              'mode',
309              'ids',
310              'resync',
311              'sql_id',
312              'post_ids',
313              'topic_ids',
314              'message_ids',
315              'physical',
316          );
317          extract($this->dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
318   
319          // Delete attachments
320          $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
321              WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
322   
323          $sql .= $this->sql_where;
324   
325          $this->db->sql_query($sql);
326          $this->num_deleted = $this->db->sql_affectedrows();
327      }
328   
329      /**
330       * Delete attachments from filesystem
331       */
332      protected function remove_from_filesystem()
333      {
334          $space_removed = $files_removed = 0;
335   
336          foreach ($this->physical as $file_ary)
337          {
338              if ($this->unlink_attachment($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
339              {
340                  // Only non-orphaned files count to the file size
341                  $space_removed += $file_ary['filesize'];
342                  $files_removed++;
343              }
344   
345              if ($file_ary['thumbnail'])
346              {
347                  $this->unlink_attachment($file_ary['filename'], 'thumbnail', true);
348              }
349          }
350   
351          /**
352           * Perform additional actions after attachment(s) deletion from the filesystem
353           *
354           * @event core.delete_attachments_from_filesystem_after
355           * @var    string    mode            Variable containing attachments deletion mode, can be: post|message|topic|attach|user
356           * @var    mixed    ids                Array or comma separated list of ids corresponding to the mode
357           * @var    bool    resync            Flag indicating if posts/messages/topics should be synchronized
358           * @var    string    sql_id            The field name to collect/delete data for depending on the mode
359           * @var    array    post_ids        Array with post ids for deleted attachment(s)
360           * @var    array    topic_ids        Array with topic ids for deleted attachment(s)
361           * @var    array    message_ids        Array with private message ids for deleted attachment(s)
362           * @var    array    physical        Array with deleted attachment(s) physical file(s) data
363           * @var    int        num_deleted        The number of deleted attachment(s) from the database
364           * @var    int        space_removed    The size of deleted files(s) from the filesystem
365           * @var    int        files_removed    The number of deleted file(s) from the filesystem
366           * @since 3.1.7-RC1
367           */
368          $vars = array(
369              'mode',
370              'ids',
371              'resync',
372              'sql_id',
373              'post_ids',
374              'topic_ids',
375              'message_ids',
376              'physical',
377              'num_deleted',
378              'space_removed',
379              'files_removed',
380          );
381          extract($this->dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
382   
383          if ($space_removed || $files_removed)
384          {
385              $this->config->increment('upload_dir_size', $space_removed * (-1), false);
386              $this->config->increment('num_files', $files_removed * (-1), false);
387          }
388      }
389   
390      /**
391       * Delete attachment from filesystem
392       *
393       * @param string $filename Filename of attachment
394       * @param string $mode Delete mode
395       * @param bool $entry_removed Whether entry was removed. Defaults to false
396       * @return bool True if file was removed, false if not
397       */
398      public function unlink_attachment($filename, $mode = 'file', $entry_removed = false)
399      {
400          // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
401          $sql = 'SELECT COUNT(attach_id) AS num_entries
402          FROM ' . ATTACHMENTS_TABLE . "
403          WHERE physical_filename = '" . $this->db->sql_escape(utf8_basename($filename)) . "'";
404          $result = $this->db->sql_query($sql);
405          $num_entries = (int) $this->db->sql_fetchfield('num_entries');
406          $this->db->sql_freeresult($result);
407   
408          // Do not remove file if at least one additional entry with the same name exist.
409          if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
410          {
411              return false;
412          }
413   
414          $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
415          $filepath = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename;
416   
417          try
418          {
419              if ($this->filesystem->exists($filepath))
420              {
421                  $this->filesystem->remove($this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename);
422                  return true;
423              }
424          }
425          catch (\phpbb\filesystem\exception\filesystem_exception $exception)
426          {
427              // Fail is covered by return statement below
428          }
429   
430          return false;
431      }
432  }
433