[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |