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

delete.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 13.95 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          $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  }
481