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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
delete.php
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