1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-06-05 22:14:59 +02:00

Merge pull request #3913 from marc1706/ticket/14168

[ticket/14168] Refactor attachment management functions into classes

* marc1706/ticket/14168: (36 commits)
  [ticket/14168] Correctly state return type of upload and upload_attachment
  [ticket/14168] Use attachment manager instead of separate classes
  [ticket/14168] Fix docblock in manager
  [ticket/14168] Add more test cases for attachment manager
  [ticket/14168] Add new test method and more tests
  [ticket/14168] Fix tabs in manager and add test file
  [ticket/14168] Fix tests after rebase
  [ticket/14168] Add attachment manager service
  [ticket/14168] Use correct docblock
  [ticket/14168] Add services_attachment.yml to services.yml
  [ticket/14168] Minor coding style fixes
  [ticket/14168] Move attachment service definitions to services_attachment
  [ticket/14168] Improve code coverage in upload class
  [ticket/14168] Move image check and don't use trigger_error()
  [ticket/14168] Add tests for init_error() during upload
  [ticket/14168] Add basic test file for attachments upload
  [ticket/14168] Fix CS issue
  [ticket/14168] No longer use deprecated functions in core files
  [ticket/14168] Move phpbb_unlink() into attachment delete class
  [ticket/14168] Reset sequence before tests in delete tests
  ...
This commit is contained in:
Tristan Darricau 2015-10-14 08:40:01 +02:00
commit cac090b659
23 changed files with 2006 additions and 550 deletions

View File

@ -1,4 +1,5 @@
imports:
- { resource: services_attachment.yml }
- { resource: services_auth.yml }
- { resource: services_avatar.yml }
- { resource: services_captcha.yml }

View File

@ -0,0 +1,40 @@
services:
attachment.delete:
class: phpbb\attachment\delete
scope: prototype
arguments:
- @config
- @dbal.conn
- @dispatcher
- @filesystem
- @attachment.resync
- %core.root_path%
attachment.manager:
class: phpbb\attachment\manager
scope: prototype
arguments:
- @attachment.delete
- @attachment.resync
- @attachment.upload
attachment.resync:
class: phpbb\attachment\resync
scope: prototype
arguments:
- @dbal.conn
attachment.upload:
class: phpbb\attachment\upload
scope: prototype
arguments:
- @auth
- @cache
- @config
- @files.upload
- @language
- @mimetype.guesser
- @dispatcher
- @plupload
- @user
- %core.root_path%

View File

@ -39,6 +39,9 @@ class acp_attachments
/** @var \phpbb\filesystem\filesystem_interface */
protected $filesystem;
/** @var \phpbb\attachment\manager */
protected $attachment_manager;
public $id;
public $u_action;
protected $new_config;
@ -55,6 +58,7 @@ class acp_attachments
$this->user = $user;
$this->phpbb_container = $phpbb_container;
$this->filesystem = $phpbb_filesystem;
$this->attachment_manager = $phpbb_container->get('attachment.manager');
$user->add_lang(array('posting', 'viewtopic', 'acp/attachments'));
@ -922,11 +926,11 @@ class acp_attachments
$delete_files = array();
while ($row = $db->sql_fetchrow($result))
{
phpbb_unlink($row['physical_filename'], 'file');
$this->attachment_manager->unlink($row['physical_filename'], 'file');
if ($row['thumbnail'])
{
phpbb_unlink($row['physical_filename'], 'thumbnail');
$this->attachment_manager->unlink($row['physical_filename'], 'thumbnail');
}
$delete_files[$row['attach_id']] = $row['real_filename'];
@ -1091,7 +1095,7 @@ class acp_attachments
}
$db->sql_freeresult($result);
if ($num_deleted = delete_attachments('attach', $delete_files))
if ($num_deleted = $this->attachment_manager->delete('attach', $delete_files))
{
if (sizeof($delete_files) != $num_deleted)
{

View File

@ -1788,7 +1788,7 @@ class acp_forums
*/
function delete_forum_content($forum_id)
{
global $db, $config, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@ -1809,7 +1809,10 @@ class acp_forums
}
$db->sql_freeresult($result);
delete_attachments('topic', $topic_ids, false);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('topic', $topic_ids, false);
unset($attachment_manager);
// Delete shadow topics pointing to topics in this forum
delete_topic_shadows($forum_id);

View File

@ -543,7 +543,10 @@ class acp_users
if (confirm_box(true))
{
delete_attachments('user', $user_id);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('user', $user_id);
unset($attachment_manager);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_ATTACH', false, array($user_row['username']));
trigger_error($user->lang['USER_ATTACHMENTS_REMOVED'] . adm_back_link($this->u_action . '&u=' . $user_id));
@ -2139,7 +2142,10 @@ class acp_users
}
$db->sql_freeresult($result);
delete_attachments('attach', $marked);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('attach', $marked);
unset($attachment_manager);
$message = (sizeof($log_attachments) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED'];

View File

@ -1024,7 +1024,10 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$search->index_remove($post_ids, $poster_ids, $forum_ids);
delete_attachments('post', $post_ids, false);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('post', $post_ids, false);
unset($attachment_manager);
/**
* Perform additional actions during post(s) deletion
@ -1111,329 +1114,21 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
/**
* Delete Attachments
*
* @deprecated 3.2.0-a1 (To be removed: 3.4.0)
*
* @param string $mode can be: post|message|topic|attach|user
* @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
* @param bool $resync set this to false if you are deleting posts or topics
*/
function delete_attachments($mode, $ids, $resync = true)
{
global $db, $config, $phpbb_dispatcher;
global $phpbb_container;
// 0 is as bad as an empty array
if (empty($ids))
{
return false;
}
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$num_deleted = $attachment_manager->delete($mode, $ids, $resync);
if (is_array($ids))
{
$ids = array_unique($ids);
$ids = array_map('intval', $ids);
}
else
{
$ids = array((int) $ids);
}
$sql_where = '';
switch ($mode)
{
case 'post':
case 'message':
$sql_id = 'post_msg_id';
$sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
break;
case 'topic':
$sql_id = 'topic_id';
break;
case 'user':
$sql_id = 'poster_id';
break;
case 'attach':
default:
$sql_id = 'attach_id';
$mode = 'attach';
break;
}
$post_ids = $message_ids = $topic_ids = $physical = array();
/**
* Perform additional actions before collecting data for attachment(s) deletion
*
* @event core.delete_attachments_collect_data_before
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
);
extract($phpbb_dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
// Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
$sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $db->sql_in_set($sql_id, $ids);
$sql .= $sql_where;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
// We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
if ($resync && !$row['is_orphan'])
{
if (!$row['in_message'])
{
$post_ids[] = $row['post_msg_id'];
$topic_ids[] = $row['topic_id'];
}
else
{
$message_ids[] = $row['post_msg_id'];
}
}
$physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
}
$db->sql_freeresult($result);
/**
* Perform additional actions before attachment(s) deletion
*
* @event core.delete_attachments_before
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @var array post_ids Array with post ids for deleted attachment(s)
* @var array topic_ids Array with topic ids for deleted attachment(s)
* @var array message_ids Array with private message ids for deleted attachment(s)
* @var array physical Array with deleted attachment(s) physical file(s) data
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
'post_ids',
'topic_ids',
'message_ids',
'physical',
);
extract($phpbb_dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
// Delete attachments
$sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $db->sql_in_set($sql_id, $ids);
$sql .= $sql_where;
$db->sql_query($sql);
$num_deleted = $db->sql_affectedrows();
/**
* Perform additional actions after attachment(s) deletion from the database
*
* @event core.delete_attachments_from_database_after
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @var array post_ids Array with post ids for deleted attachment(s)
* @var array topic_ids Array with topic ids for deleted attachment(s)
* @var array message_ids Array with private message ids for deleted attachment(s)
* @var array physical Array with deleted attachment(s) physical file(s) data
* @var int num_deleted The number of deleted attachment(s) from the database
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
'post_ids',
'topic_ids',
'message_ids',
'physical',
'num_deleted',
);
extract($phpbb_dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
if (!$num_deleted)
{
return 0;
}
// Delete attachments from filesystem
$space_removed = $files_removed = 0;
foreach ($physical as $file_ary)
{
if (phpbb_unlink($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
{
// Only non-orphaned files count to the file size
$space_removed += $file_ary['filesize'];
$files_removed++;
}
if ($file_ary['thumbnail'])
{
phpbb_unlink($file_ary['filename'], 'thumbnail', true);
}
}
/**
* Perform additional actions after attachment(s) deletion from the filesystem
*
* @event core.delete_attachments_from_filesystem_after
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @var array post_ids Array with post ids for deleted attachment(s)
* @var array topic_ids Array with topic ids for deleted attachment(s)
* @var array message_ids Array with private message ids for deleted attachment(s)
* @var array physical Array with deleted attachment(s) physical file(s) data
* @var int num_deleted The number of deleted attachment(s) from the database
* @var int space_removed The size of deleted files(s) from the filesystem
* @var int files_removed The number of deleted file(s) from the filesystem
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
'post_ids',
'topic_ids',
'message_ids',
'physical',
'num_deleted',
'space_removed',
'files_removed',
);
extract($phpbb_dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
if ($space_removed || $files_removed)
{
$config->increment('upload_dir_size', $space_removed * (-1), false);
$config->increment('num_files', $files_removed * (-1), false);
}
// If we do not resync, we do not need to adjust any message, post, topic or user entries
if (!$resync)
{
return $num_deleted;
}
// No more use for the original ids
unset($ids);
// Now, we need to resync posts, messages, topics. We go through every one of them
$post_ids = array_unique($post_ids);
$message_ids = array_unique($message_ids);
$topic_ids = array_unique($topic_ids);
// Update post indicators for posts now no longer having attachments
if (sizeof($post_ids))
{
// Just check which posts are still having an assigned attachment not orphaned by querying the attachments table
$sql = 'SELECT post_msg_id
FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
AND in_message = 0
AND is_orphan = 0';
$result = $db->sql_query($sql);
$remaining_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$remaining_ids[] = $row['post_msg_id'];
}
$db->sql_freeresult($result);
// Now only unset those ids remaining
$post_ids = array_diff($post_ids, $remaining_ids);
if (sizeof($post_ids))
{
$sql = 'UPDATE ' . POSTS_TABLE . '
SET post_attachment = 0
WHERE ' . $db->sql_in_set('post_id', $post_ids);
$db->sql_query($sql);
}
}
// Update message table if messages are affected
if (sizeof($message_ids))
{
// Just check which messages are still having an assigned attachment not orphaned by querying the attachments table
$sql = 'SELECT post_msg_id
FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $db->sql_in_set('post_msg_id', $message_ids) . '
AND in_message = 1
AND is_orphan = 0';
$result = $db->sql_query($sql);
$remaining_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$remaining_ids[] = $row['post_msg_id'];
}
$db->sql_freeresult($result);
// Now only unset those ids remaining
$message_ids = array_diff($message_ids, $remaining_ids);
if (sizeof($message_ids))
{
$sql = 'UPDATE ' . PRIVMSGS_TABLE . '
SET message_attachment = 0
WHERE ' . $db->sql_in_set('msg_id', $message_ids);
$db->sql_query($sql);
}
}
// Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
if (sizeof($topic_ids))
{
// Just check which topics are still having an assigned attachment not orphaned by querying the attachments table (much less entries expected)
$sql = 'SELECT topic_id
FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
AND is_orphan = 0';
$result = $db->sql_query($sql);
$remaining_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$remaining_ids[] = $row['topic_id'];
}
$db->sql_freeresult($result);
// Now only unset those ids remaining
$topic_ids = array_diff($topic_ids, $remaining_ids);
if (sizeof($topic_ids))
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET topic_attachment = 0
WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
$db->sql_query($sql);
}
}
unset($attachment_manager);
return $num_deleted;
}
@ -1551,27 +1246,19 @@ function update_posted_info(&$topic_ids)
/**
* Delete attached file
*
* @deprecated 3.2.0-a1 (To be removed: 3.4.0)
*/
function phpbb_unlink($filename, $mode = 'file', $entry_removed = false)
{
global $db, $phpbb_root_path, $config;
global $phpbb_container;
// Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
$sql = 'SELECT COUNT(attach_id) AS num_entries
FROM ' . ATTACHMENTS_TABLE . "
WHERE physical_filename = '" . $db->sql_escape(utf8_basename($filename)) . "'";
$result = $db->sql_query($sql);
$num_entries = (int) $db->sql_fetchfield('num_entries');
$db->sql_freeresult($result);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$unlink = $attachment_manager->unlink($filename, $mode, $entry_removed);
unset($attachment_manager);
// Do not remove file if at least one additional entry with the same name exist.
if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
{
return false;
}
$filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename);
return $unlink;
}
/**

View File

@ -391,183 +391,27 @@ function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
* Upload Attachment - filedata is generated here
* Uses upload class
*
* @deprecated 3.2.0-a1 (To be removed: 3.4.0)
*
* @param string $form_name The form name of the file upload input
* @param int $forum_id The id of the forum
* @param bool $local Whether the file is local or not
* @param string $local_storage The path to the local file
* @param bool $is_message Whether it is a PM or not
* @param \filespec $local_filedata A filespec object created for the local file
* @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype guesser object if used
* @param \phpbb\plupload\plupload $plupload The plupload object if one is being used
* @param array $local_filedata A filespec object created for the local file
*
* @return object filespec
* @return array File data array
*/
function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false)
{
global $auth, $user, $config, $db, $cache;
global $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container;
global $phpbb_container;
$filedata = array(
'error' => array()
);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$file = $attachment_manager->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata);
unset($attachment_manager);
$upload = $phpbb_container->get('files.upload');
if ($config['check_attachment_content'] && isset($config['mime_triggers']))
{
$upload->set_disallowed_content(explode('|', $config['mime_triggers']));
}
else if (!$config['check_attachment_content'])
{
$upload->set_disallowed_content(array());
}
$filedata['post_attach'] = $local || $upload->is_valid($form_name);
if (!$filedata['post_attach'])
{
$filedata['error'][] = $user->lang['NO_UPLOAD_FORM_FOUND'];
return $filedata;
}
$extensions = $cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
$upload->set_allowed_extensions(array_keys($extensions['_allowed_']));
/** @var \phpbb\files\filespec $file */
$file = ($local) ? $upload->handle_upload('files.types.local', $local_storage, $local_filedata) : $upload->handle_upload('files.types.form', $form_name);
if ($file->init_error())
{
$filedata['post_attach'] = false;
return $filedata;
}
// Whether the uploaded file is in the image category
$is_image = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id))
{
// Check Image Size, if it is an image
if ($is_image)
{
$file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']);
}
// Admins and mods are allowed to exceed the allowed filesize
if (!empty($extensions[$file->get('extension')]['max_filesize']))
{
$allowed_filesize = $extensions[$file->get('extension')]['max_filesize'];
}
else
{
$allowed_filesize = ($is_message) ? $config['max_filesize_pm'] : $config['max_filesize'];
}
$file->upload->set_max_filesize($allowed_filesize);
}
$file->clean_filename('unique', $user->data['user_id'] . '_');
// Are we uploading an image *and* this image being within the image category?
// Only then perform additional image checks.
$file->move_file($config['upload_path'], false, !$is_image);
// Do we have to create a thumbnail?
$filedata['thumbnail'] = ($is_image && $config['img_create_thumbnail']) ? 1 : 0;
if (sizeof($file->error))
{
$file->remove();
$filedata['error'] = array_merge($filedata['error'], $file->error);
$filedata['post_attach'] = false;
return $filedata;
}
// Make sure the image category only holds valid images...
if ($is_image && !$file->is_image())
{
$file->remove();
if ($plupload && $plupload->is_active())
{
$plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
}
// If this error occurs a user tried to exploit an IE Bug by renaming extensions
// Since the image category is displaying content inline we need to catch this.
trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']);
}
$filedata['filesize'] = $file->get('filesize');
$filedata['mimetype'] = $file->get('mimetype');
$filedata['extension'] = $file->get('extension');
$filedata['physical_filename'] = $file->get('realname');
$filedata['real_filename'] = $file->get('uploadname');
$filedata['filetime'] = time();
/**
* Event to modify uploaded file before submit to the post
*
* @event core.modify_uploaded_file
* @var array filedata Array containing uploaded file data
* @var bool is_image Flag indicating if the file is an image
* @since 3.1.0-RC3
*/
$vars = array(
'filedata',
'is_image',
);
extract($phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
// Check our complete quota
if ($config['attachment_quota'])
{
if ($config['upload_dir_size'] + $file->get('filesize') > $config['attachment_quota'])
{
$filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
$filedata['post_attach'] = false;
$file->remove();
return $filedata;
}
}
// Check free disk space
if ($free_space = @disk_free_space($phpbb_root_path . $config['upload_path']))
{
if ($free_space <= $file->get('filesize'))
{
if ($auth->acl_get('a_'))
{
$filedata['error'][] = $user->lang['ATTACH_DISK_FULL'];
}
else
{
$filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
}
$filedata['post_attach'] = false;
$file->remove();
return $filedata;
}
}
// Create Thumbnail
if ($filedata['thumbnail'])
{
$source = $file->get('destination_file');
$destination = $file->get('destination_path') . '/thumb_' . $file->get('realname');
if (!create_thumbnail($source, $destination, $file->get('mimetype')))
{
$filedata['thumbnail'] = 0;
}
}
return $filedata;
return $file;
}
/**

View File

@ -1153,12 +1153,10 @@ function delete_pm($user_id, $msg_ids, $folder_id)
if (sizeof($delete_ids))
{
// Check if there are any attachments we need to remove
if (!function_exists('delete_attachments'))
{
include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}
delete_attachments('message', $delete_ids, false);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('message', $delete_ids, false);
unset($attachment_manager);
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
@ -1363,12 +1361,10 @@ function phpbb_delete_users_pms($user_ids)
if (!empty($delete_ids))
{
// Check if there are any attachments we need to remove
if (!function_exists('delete_attachments'))
{
include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}
delete_attachments('message', $delete_ids, false);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('message', $delete_ids, false);
unset($attachment_manager);
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $delete_ids);

View File

@ -1140,12 +1140,6 @@ class parse_message extends bbcode_firstpass
*/
protected $plupload;
/**
* The mimetype guesser object used for attachment mimetypes
* @var \phpbb\mimetype\guesser
*/
protected $mimetype_guesser;
/**
* Init - give message here or manually
*/
@ -1541,6 +1535,7 @@ class parse_message extends bbcode_firstpass
function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false)
{
global $config, $auth, $user, $phpbb_root_path, $phpEx, $db, $request;
global $phpbb_container;
$error = array();
@ -1576,7 +1571,9 @@ class parse_message extends bbcode_firstpass
{
if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id))
{
$filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$filedata = $attachment_manager->upload($form_name, $forum_id, false, '', $is_message);
$error = $filedata['error'];
if ($filedata['post_attach'] && !sizeof($error))
@ -1646,6 +1643,9 @@ class parse_message extends bbcode_firstpass
if ($index !== false && !empty($this->attachment_data[$index]))
{
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
// delete selected attachment
if ($this->attachment_data[$index]['is_orphan'])
{
@ -1660,11 +1660,11 @@ class parse_message extends bbcode_firstpass
if ($row)
{
phpbb_unlink($row['physical_filename'], 'file');
$attachment_manager->unlink($row['physical_filename'], 'file');
if ($row['thumbnail'])
{
phpbb_unlink($row['physical_filename'], 'thumbnail');
$attachment_manager->unlink($row['physical_filename'], 'thumbnail');
}
$db->sql_query('DELETE FROM ' . ATTACHMENTS_TABLE . ' WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id']);
@ -1672,7 +1672,7 @@ class parse_message extends bbcode_firstpass
}
else
{
delete_attachments('attach', array(intval($this->attachment_data[$index]['attach_id'])));
$attachment_manager->delete('attach', $this->attachment_data[$index]['attach_id']);
}
unset($this->attachment_data[$index]);
@ -1692,7 +1692,9 @@ class parse_message extends bbcode_firstpass
{
if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id))
{
$filedata = upload_attachment($form_name, $forum_id, false, '', $is_message, false, $this->mimetype_guesser, $this->plupload);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$filedata = $attachment_manager->upload($form_name, $forum_id, false, '', $is_message);
$error = array_merge($error, $filedata['error']);
if (!sizeof($error))
@ -1980,18 +1982,6 @@ class parse_message extends bbcode_firstpass
$this->plupload = $plupload;
}
/**
* Setter function for passing the mimetype_guesser object
*
* @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype_guesser object
*
* @return null
*/
public function set_mimetype_guesser(\phpbb\mimetype\guesser $mimetype_guesser)
{
$this->mimetype_guesser = $mimetype_guesser;
}
/**
* Function to perform custom bbcode validation by extensions
* can be used in bbcode_init() to assign regexp replacement

View File

@ -70,12 +70,10 @@ class ucp_attachments
if (confirm_box(true))
{
if (!function_exists('delete_attachments'))
{
include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}
delete_attachments('attach', $delete_ids);
/** @var \phpbb\attachment\manager $attachment_manager */
$attachment_manager = $phpbb_container->get('attachment.manager');
$attachment_manager->delete('attach', $delete_ids);
unset($attachment_manager);
meta_refresh(3, $this->u_action);
$message = ((sizeof($delete_ids) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']) . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');

View File

@ -0,0 +1,432 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\attachment;
use \phpbb\config\config;
use \phpbb\db\driver\driver_interface;
use \phpbb\event\dispatcher;
use \phpbb\filesystem\filesystem;
/**
* Attachment delete class
*/
class delete
{
/** @var config */
protected $config;
/** @var driver_interface */
protected $db;
/** @var \phpbb\event\dispatcher */
protected $dispatcher;
/** @var filesystem */
protected $filesystem;
/** @var resync */
protected $resync;
/** @var string phpBB root path */
protected $phpbb_root_path;
/** @var array Attachement IDs */
protected $ids;
/** @var string SQL ID string */
private $sql_id;
/** @var string SQL where string */
private $sql_where = '';
/** @var int Number of deleted items */
private $num_deleted;
/** @var array Post IDs */
private $post_ids = array();
/** @var array Message IDs */
private $message_ids = array();
/** @var array Topic IDs */
private $topic_ids = array();
/** @var array Info of physical file */
private $physical = array();
/**
* Attachment delete class constructor
*
* @param config $config
* @param driver_interface $db
* @param dispatcher $dispatcher
* @param filesystem $filesystem
* @param resync $resync
* @param string $phpbb_root_path
*/
public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, filesystem $filesystem, resync $resync, $phpbb_root_path)
{
$this->config = $config;
$this->db = $db;
$this->dispatcher = $dispatcher;
$this->filesystem = $filesystem;
$this->resync = $resync;
$this->phpbb_root_path = $phpbb_root_path;
}
/**
* Delete Attachments
*
* @param string $mode can be: post|message|topic|attach|user
* @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
* @param bool $resync set this to false if you are deleting posts or topics
*
* @return int|bool Number of deleted attachments or false if something
* went wrong during attachment deletion
*/
public function delete($mode, $ids, $resync = true)
{
if (!$this->set_attachment_ids($ids))
{
return false;
}
$this->set_sql_constraints($mode);
/**
* Perform additional actions before collecting data for attachment(s) deletion
*
* @event core.delete_attachments_collect_data_before
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
);
extract($this->dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
// Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
$this->collect_attachment_info($resync);
// Delete attachments from database
$this->delete_attachments_from_db();
/**
* Perform additional actions after attachment(s) deletion from the database
*
* @event core.delete_attachments_from_database_after
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @var array post_ids Array with post ids for deleted attachment(s)
* @var array topic_ids Array with topic ids for deleted attachment(s)
* @var array message_ids Array with private message ids for deleted attachment(s)
* @var array physical Array with deleted attachment(s) physical file(s) data
* @var int num_deleted The number of deleted attachment(s) from the database
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
'post_ids',
'topic_ids',
'message_ids',
'physical',
'num_deleted',
);
extract($this->dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
if (!$this->num_deleted)
{
return 0;
}
// Delete attachments from filesystem
$this->remove_from_filesystem();
// If we do not resync, we do not need to adjust any message, post, topic or user entries
if (!$resync)
{
return $this->num_deleted;
}
// No more use for the original ids
unset($ids);
// Update post indicators for posts now no longer having attachments
$this->resync->resync('post', $this->post_ids);
// Update message table if messages are affected
$this->resync->resync('message', $this->message_ids);
// Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
$this->resync->resync('topic', $this->topic_ids);
return $this->num_deleted;
}
/**
* Set attachment IDs
*
* @param mixed $ids ID or array of IDs
*
* @return bool True if attachment IDs were set, false if not
*/
protected function set_attachment_ids($ids)
{
// 0 is as bad as an empty array
if (empty($ids))
{
return false;
}
if (is_array($ids))
{
$ids = array_unique($ids);
$this->ids = array_map('intval', $ids);
}
else
{
$this->ids = array((int) $ids);
}
return true;
}
/**
* Set SQL constraints based on mode
*
* @param string $mode Delete mode; can be: post|message|topic|attach|user
*/
private function set_sql_constraints($mode)
{
switch ($mode)
{
case 'post':
case 'message':
$this->sql_id = 'post_msg_id';
$this->sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
break;
case 'topic':
$this->sql_id = 'topic_id';
break;
case 'user':
$this->sql_id = 'poster_id';
break;
case 'attach':
default:
$this->sql_id = 'attach_id';
break;
}
}
/**
* Collect info about attachment IDs
*
* @param bool $resync Whether topics/posts should be resynced after delete
*/
protected function collect_attachment_info($resync)
{
// Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
$sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
$sql .= $this->sql_where;
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
// We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
if ($resync && !$row['is_orphan'])
{
if (!$row['in_message'])
{
$this->post_ids[] = $row['post_msg_id'];
$this->topic_ids[] = $row['topic_id'];
}
else
{
$this->message_ids[] = $row['post_msg_id'];
}
}
$this->physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
}
$this->db->sql_freeresult($result);
// IDs should be unique
$this->post_ids = array_unique($this->post_ids);
$this->message_ids = array_unique($this->message_ids);
$this->topic_ids = array_unique($this->topic_ids);
}
/**
* Delete attachments from database table
*/
protected function delete_attachments_from_db()
{
/**
* Perform additional actions before attachment(s) deletion
*
* @event core.delete_attachments_before
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @var array post_ids Array with post ids for deleted attachment(s)
* @var array topic_ids Array with topic ids for deleted attachment(s)
* @var array message_ids Array with private message ids for deleted attachment(s)
* @var array physical Array with deleted attachment(s) physical file(s) data
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
'post_ids',
'topic_ids',
'message_ids',
'physical',
);
extract($this->dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
// Delete attachments
$sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
$sql .= $this->sql_where;
$this->db->sql_query($sql);
$this->num_deleted = $this->db->sql_affectedrows();
}
/**
* Delete attachments from filesystem
*/
protected function remove_from_filesystem()
{
$space_removed = $files_removed = 0;
foreach ($this->physical as $file_ary)
{
if ($this->unlink_attachment($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
{
// Only non-orphaned files count to the file size
$space_removed += $file_ary['filesize'];
$files_removed++;
}
if ($file_ary['thumbnail'])
{
$this->unlink_attachment($file_ary['filename'], 'thumbnail', true);
}
}
/**
* Perform additional actions after attachment(s) deletion from the filesystem
*
* @event core.delete_attachments_from_filesystem_after
* @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
* @var mixed ids Array or comma separated list of ids corresponding to the mode
* @var bool resync Flag indicating if posts/messages/topics should be synchronized
* @var string sql_id The field name to collect/delete data for depending on the mode
* @var array post_ids Array with post ids for deleted attachment(s)
* @var array topic_ids Array with topic ids for deleted attachment(s)
* @var array message_ids Array with private message ids for deleted attachment(s)
* @var array physical Array with deleted attachment(s) physical file(s) data
* @var int num_deleted The number of deleted attachment(s) from the database
* @var int space_removed The size of deleted files(s) from the filesystem
* @var int files_removed The number of deleted file(s) from the filesystem
* @since 3.1.7-RC1
*/
$vars = array(
'mode',
'ids',
'resync',
'sql_id',
'post_ids',
'topic_ids',
'message_ids',
'physical',
'num_deleted',
'space_removed',
'files_removed',
);
extract($this->dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
if ($space_removed || $files_removed)
{
$this->config->increment('upload_dir_size', $space_removed * (-1), false);
$this->config->increment('num_files', $files_removed * (-1), false);
}
}
/**
* Delete attachment from filesystem
*
* @param string $filename Filename of attachment
* @param string $mode Delete mode
* @param bool $entry_removed Whether entry was removed. Defaults to false
* @return bool True if file was removed, false if not
*/
public function unlink_attachment($filename, $mode = 'file', $entry_removed = false)
{
// Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
$sql = 'SELECT COUNT(attach_id) AS num_entries
FROM ' . ATTACHMENTS_TABLE . "
WHERE physical_filename = '" . $this->db->sql_escape(utf8_basename($filename)) . "'";
$result = $this->db->sql_query($sql);
$num_entries = (int) $this->db->sql_fetchfield('num_entries');
$this->db->sql_freeresult($result);
// Do not remove file if at least one additional entry with the same name exist.
if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
{
return false;
}
$filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
$filepath = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename;
try
{
if ($this->filesystem->exists($filepath))
{
$this->filesystem->remove($this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename);
return true;
}
}
catch (\phpbb\filesystem\exception\filesystem_exception $exception)
{
// Fail is covered by return statement below
}
return false;
}
}

View File

@ -0,0 +1,99 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\attachment;
/**
* Attachment manager
*/
class manager
{
/** @var delete Attachment delete class */
protected $delete;
/** @var resync Attachment resync class */
protected $resync;
/** @var upload Attachment upload class */
protected $upload;
/**
* Constructor for attachment manager
*
* @param delete $delete Attachment delete class
* @param resync $resync Attachment resync class
* @param upload $upload Attachment upload class
*/
public function __construct(delete $delete, resync $resync, upload $upload)
{
$this->delete = $delete;
$this->resync = $resync;
$this->upload = $upload;
}
/**
* Wrapper method for deleting attachments
*
* @param string $mode can be: post|message|topic|attach|user
* @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
* @param bool $resync set this to false if you are deleting posts or topics
*
* @return int|bool Number of deleted attachments or false if something
* went wrong during attachment deletion
*/
public function delete($mode, $ids, $resync = true)
{
return $this->delete->delete($mode, $ids, $resync);
}
/**
* Wrapper method for deleting attachments from filesystem
*
* @param string $filename Filename of attachment
* @param string $mode Delete mode
* @param bool $entry_removed Whether entry was removed. Defaults to false
* @return bool True if file was removed, false if not
*/
public function unlink($filename, $mode = 'file', $entry_removed = false)
{
return $this->delete->unlink_attachment($filename, $mode, $entry_removed);
}
/**
* Wrapper method for resyncing specified type
*
* @param string $type Type of resync
* @param array $ids IDs to resync
*/
public function resync($type, $ids)
{
$this->resync->resync($type, $ids);
}
/**
* Wrapper method for uploading attachment
*
* @param string $form_name The form name of the file upload input
* @param int $forum_id The id of the forum
* @param bool $local Whether the file is local or not
* @param string $local_storage The path to the local file
* @param bool $is_message Whether it is a PM or not
* @param array $local_filedata An file data object created for the local file
*
* @return array File data array
*/
public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = [])
{
return $this->upload->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata);
}
}

View File

@ -0,0 +1,124 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\attachment;
use \phpbb\db\driver\driver_interface;
/**
* Attachment resync class
*/
class resync
{
/** @var driver_interface */
protected $db;
/** @var string Attachment table SQL ID */
private $attach_sql_id;
/** @var string Resync table SQL ID */
private $resync_sql_id;
/** @var string Resync SQL table */
private $resync_table;
/** @var string SQL where statement */
private $sql_where;
/**
* Constructor for attachment resync class
*
* @param driver_interface $db Database driver
*/
public function __construct(driver_interface $db)
{
$this->db = $db;
}
/**
* Set type constraints for attachment resync
*
* @param string $type Type of resync; can be: message|post|topic
*/
protected function set_type_constraints($type)
{
switch ($type)
{
case 'message':
$this->attach_sql_id = 'post_msg_id';
$this->sql_where = ' AND in_message = 1
AND is_orphan = 0';
$this->resync_table = PRIVMSGS_TABLE;
$this->resync_sql_id = 'msg_id';
break;
case 'post':
$this->attach_sql_id = 'post_msg_id';
$this->sql_where = ' AND in_message = 0
AND is_orphan = 0';
$this->resync_table = POSTS_TABLE;
$this->resync_sql_id = 'post_id';
break;
case 'topic':
$this->attach_sql_id = 'topic_id';
$this->sql_where = ' AND is_orphan = 0';
$this->resync_table = TOPICS_TABLE;
$this->resync_sql_id = 'topic_id';
break;
}
}
/**
* Resync specified type
*
* @param string $type Type of resync
* @param array $ids IDs to resync
*/
public function resync($type, $ids)
{
if (empty($type) || !is_array($ids) || !sizeof($ids) || !in_array($type, array('post', 'topic', 'message')))
{
return;
}
$this->set_type_constraints($type);
// Just check which elements are still having an assigned attachment
// not orphaned by querying the attachments table
$sql = 'SELECT ' . $this->attach_sql_id . '
FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $this->db->sql_in_set($this->attach_sql_id, $ids)
. $this->sql_where;
$result = $this->db->sql_query($sql);
$remaining_ids = array();
while ($row = $this->db->sql_fetchrow($result))
{
$remaining_ids[] = $row[$this->attach_sql_id];
}
$this->db->sql_freeresult($result);
// Now only unset those ids remaining
$ids = array_diff($ids, $remaining_ids);
if (sizeof($ids))
{
$sql = 'UPDATE ' . $this->resync_table . '
SET ' . $type . '_attachment = 0
WHERE ' . $this->db->sql_in_set($this->resync_sql_id, $ids);
$this->db->sql_query($sql);
}
}
}

View File

@ -0,0 +1,334 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\attachment;
use phpbb\auth\auth;
use \phpbb\cache\service;
use \phpbb\config\config;
use \phpbb\event\dispatcher;
use \phpbb\language\language;
use \phpbb\mimetype\guesser;
use \phpbb\plupload\plupload;
use \phpbb\user;
/**
* Attachment upload class
*/
class upload
{
/** @var auth */
protected $auth;
/** @var service */
protected $cache;
/** @var config */
protected $config;
/** @var \phpbb\files\upload Upload class */
protected $files_upload;
/** @var \phpbb\language\language */
protected $language;
/** @var guesser Mimetype guesser */
protected $mimetype_guesser;
/** @var dispatcher */
protected $phpbb_dispatcher;
/** @var plupload Plupload */
protected $plupload;
/** @var user */
protected $user;
/** @var \phpbb\files\filespec Current filespec instance */
private $file;
/** @var array File data */
private $file_data = array(
'error' => array()
);
/** @var array Extensions array */
private $extensions;
/**
* Constructor for attachments upload class
*
* @param auth $auth
* @param service $cache
* @param config $config
* @param \phpbb\files\upload $files_upload
* @param language $language
* @param guesser $mimetype_guesser
* @param dispatcher $phpbb_dispatcher
* @param plupload $plupload
* @param user $user
* @param $phpbb_root_path
*/
public function __construct(auth $auth, service $cache, config $config, \phpbb\files\upload $files_upload, language $language, guesser $mimetype_guesser, dispatcher $phpbb_dispatcher, plupload $plupload, user $user, $phpbb_root_path)
{
$this->auth = $auth;
$this->cache = $cache;
$this->config = $config;
$this->files_upload = $files_upload;
$this->language = $language;
$this->mimetype_guesser = $mimetype_guesser;
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->plupload = $plupload;
$this->user = $user;
$this->phpbb_root_path = $phpbb_root_path;
}
/**
* Upload Attachment - filedata is generated here
* Uses upload class
*
* @param string $form_name The form name of the file upload input
* @param int $forum_id The id of the forum
* @param bool $local Whether the file is local or not
* @param string $local_storage The path to the local file
* @param bool $is_message Whether it is a PM or not
* @param array $local_filedata An file data object created for the local file
*
* @return array File data array
*/
public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = array())
{
$this->init_files_upload($forum_id, $is_message);
$this->file_data['post_attach'] = $local || $this->files_upload->is_valid($form_name);
if (!$this->file_data['post_attach'])
{
$this->file_data['error'][] = $this->language->lang('NO_UPLOAD_FORM_FOUND');
return $this->file_data;
}
$this->file = ($local) ? $this->files_upload->handle_upload('files.types.local', $local_storage, $local_filedata) : $this->files_upload->handle_upload('files.types.form', $form_name);
if ($this->file->init_error())
{
$this->file_data['post_attach'] = false;
return $this->file_data;
}
// Whether the uploaded file is in the image category
$is_image = (isset($this->extensions[$this->file->get('extension')]['display_cat'])) ? $this->extensions[$this->file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
if (!$this->auth->acl_get('a_') && !$this->auth->acl_get('m_', $forum_id))
{
// Check Image Size, if it is an image
if ($is_image)
{
$this->file->upload->set_allowed_dimensions(0, 0, $this->config['img_max_width'], $this->config['img_max_height']);
}
// Admins and mods are allowed to exceed the allowed filesize
if (!empty($this->extensions[$this->file->get('extension')]['max_filesize']))
{
$allowed_filesize = $this->extensions[$this->file->get('extension')]['max_filesize'];
}
else
{
$allowed_filesize = ($is_message) ? $this->config['max_filesize_pm'] : $this->config['max_filesize'];
}
$this->file->upload->set_max_filesize($allowed_filesize);
}
$this->file->clean_filename('unique', $this->user->data['user_id'] . '_');
// Are we uploading an image *and* this image being within the image category?
// Only then perform additional image checks.
$this->file->move_file($this->config['upload_path'], false, !$is_image);
// Do we have to create a thumbnail?
$this->file_data['thumbnail'] = ($is_image && $this->config['img_create_thumbnail']) ? 1 : 0;
// Make sure the image category only holds valid images...
$this->check_image($is_image);
if (sizeof($this->file->error))
{
$this->file->remove();
$this->file_data['error'] = array_merge($this->file_data['error'], $this->file->error);
$this->file_data['post_attach'] = false;
return $this->file_data;
}
$this->fill_file_data();
$filedata = $this->file_data;
/**
* Event to modify uploaded file before submit to the post
*
* @event core.modify_uploaded_file
* @var array filedata Array containing uploaded file data
* @var bool is_image Flag indicating if the file is an image
* @since 3.1.0-RC3
*/
$vars = array(
'filedata',
'is_image',
);
extract($this->phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
$this->file_data = $filedata;
unset($filedata);
// Check for attachment quota and free space
if (!$this->check_attach_quota() || !$this->check_disk_space())
{
return $this->file_data;
}
// Create Thumbnail
$this->create_thumbnail();
return $this->file_data;
}
/**
* Create thumbnail for file if necessary
*
* @return array Updated $filedata
*/
protected function create_thumbnail()
{
if ($this->file_data['thumbnail'])
{
$source = $this->file->get('destination_file');
$destination = $this->file->get('destination_path') . '/thumb_' . $this->file->get('realname');
if (!create_thumbnail($source, $destination, $this->file->get('mimetype')))
{
$this->file_data['thumbnail'] = 0;
}
}
}
/**
* Init files upload class
*
* @param int $forum_id Forum ID
* @param bool $is_message Whether attachment is inside PM or not
*/
protected function init_files_upload($forum_id, $is_message)
{
if ($this->config['check_attachment_content'] && isset($this->config['mime_triggers']))
{
$this->files_upload->set_disallowed_content(explode('|', $this->config['mime_triggers']));
}
else if (!$this->config['check_attachment_content'])
{
$this->files_upload->set_disallowed_content(array());
}
$this->extensions = $this->cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
$this->files_upload->set_allowed_extensions(array_keys($this->extensions['_allowed_']));
}
/**
* Check if uploaded file is really an image
*
* @param bool $is_image Whether file is image
*/
protected function check_image($is_image)
{
// Make sure the image category only holds valid images...
if ($is_image && !$this->file->is_image())
{
$this->file->remove();
if ($this->plupload && $this->plupload->is_active())
{
$this->plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
}
// If this error occurs a user tried to exploit an IE Bug by renaming extensions
// Since the image category is displaying content inline we need to catch this.
$this->file->set_error($this->language->lang('ATTACHED_IMAGE_NOT_IMAGE'));
}
}
/**
* Check if attachment quota was reached
*
* @return bool False if attachment quota was reached, true if not
*/
protected function check_attach_quota()
{
if ($this->config['attachment_quota'])
{
if (intval($this->config['upload_dir_size']) + $this->file->get('filesize') > $this->config['attachment_quota'])
{
$this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
$this->file_data['post_attach'] = false;
$this->file->remove();
return false;
}
}
return true;
}
/**
* Check if there is enough free space available on disk
*
* @return bool True if disk space is available, false if not
*/
protected function check_disk_space()
{
if ($free_space = @disk_free_space($this->phpbb_root_path . $this->config['upload_path']))
{
if ($free_space <= $this->file->get('filesize'))
{
if ($this->auth->acl_get('a_'))
{
$this->file_data['error'][] = $this->language->lang('ATTACH_DISK_FULL');
}
else
{
$this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
}
$this->file_data['post_attach'] = false;
$this->file->remove();
return false;
}
}
return true;
}
/**
* Fills file data with file information and current time as filetime
*/
protected function fill_file_data()
{
$this->file_data['filesize'] = $this->file->get('filesize');
$this->file_data['mimetype'] = $this->file->get('mimetype');
$this->file_data['extension'] = $this->file->get('extension');
$this->file_data['physical_filename'] = $this->file->get('realname');
$this->file_data['real_filename'] = $this->file->get('uploadname');
$this->file_data['filetime'] = time();
}
}

View File

@ -571,7 +571,6 @@ $plupload = $phpbb_container->get('plupload');
/* @var $mimetype_guesser \phpbb\mimetype\guesser */
$mimetype_guesser = $phpbb_container->get('mimetype.guesser');
$message_parser->set_plupload($plupload);
$message_parser->set_mimetype_guesser($mimetype_guesser);
if (isset($post_data['post_text']))
{

View File

@ -0,0 +1,127 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
require_once(dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php');
class phpbb_attachment_delete_test extends \phpbb_database_test_case
{
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\filesystem\filesystem */
protected $filesystem;
/** @var \phpbb\attachment\resync */
protected $resync;
/** @var \phpbb\attachment\delete */
protected $attachment_delete;
protected $phpbb_root_path;
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml');
}
public function setUp()
{
global $db, $phpbb_root_path;
parent::setUp();
$this->config = new \phpbb\config\config(array());
$this->db = $this->new_dbal();
$db = $this->db;
$this->resync = new \phpbb\attachment\resync($this->db);
$this->filesystem = $this->getMock('\phpbb\filesystem\filesystem', array('remove', 'exists'));
$this->filesystem->expects($this->any())
->method('remove')
->willReturn(false);
$this->filesystem->expects($this->any())
->method('exists')
->willReturn(true);
$this->phpbb_root_path = $phpbb_root_path;
$this->dispatcher = new \phpbb_mock_event_dispatcher();
$this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $phpbb_root_path);
}
public function data_attachment_delete()
{
return array(
array('attach', '', false, false),
array('meh', 5, false, 0),
array('attach', array(5), false, 0),
array('attach', array(1,2), false, 2),
array('attach', array(1,2), true, 2),
array('post', 5, false, 0),
array('topic', 5, false, 0),
array('topic', 1, true, 3),
array('user', 1, false, 0),
);
}
/**
* @dataProvider data_attachment_delete
*/
public function test_attachment_delete($mode, $ids, $resync, $expected)
{
// We need to reset the attachment ID sequence to properly test this
if ($this->db->get_sql_layer() === 'postgres')
{
$sql = 'ALTER SEQUENCE phpbb_attachments_seq RESTART WITH 1';
$this->db->sql_query($sql);
}
$this->assertSame($expected, $this->attachment_delete->delete($mode, $ids, $resync));
}
public function data_attachment_unlink()
{
return array(
array(true, true, true),
array(true, false, false),
array(true, true, false, true),
);
}
/**
* @dataProvider data_attachment_unlink
*/
public function test_attachment_delete_success($remove_success, $exists_success, $expected, $throw_exception = false)
{
$this->filesystem = $this->getMock('\phpbb\filesystem\filesystem', array('remove', 'exists'));
if ($throw_exception)
{
$this->filesystem->expects($this->any())
->method('remove')
->willThrowException(new \phpbb\filesystem\exception\filesystem_exception);;
}
else
{
$this->filesystem->expects($this->any())
->method('remove')
->willReturn($remove_success);
}
$this->filesystem->expects($this->any())
->method('exists')
->willReturn($exists_success);
$this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $this->phpbb_root_path);
$this->assertSame($expected, $this->attachment_delete->unlink_attachment('foobar'));
}
}

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_attachments">
<column>post_msg_id</column>
<column>topic_id</column>
<column>in_message</column>
<column>is_orphan</column>
<column>attach_comment</column>
<column>physical_filename</column>
<column>thumbnail</column>
<row>
<value>1</value>
<value>1</value>
<value>0</value>
<value>0</value>
<value>foo</value>
<value>foo</value>
<value>0</value>
</row>
<row>
<value>1</value>
<value>1</value>
<value>1</value>
<value>0</value>
<value>foo2</value>
<value>foo2</value>
<value>0</value>
</row>
<row>
<value>1</value>
<value>1</value>
<value>1</value>
<value>0</value>
<value>foo2</value>
<value>foo2</value>
<value>1</value>
</row>
</table>
<table name="phpbb_extensions">
<column>extension</column>
<column>group_id</column>
<row>
<value>jpg</value>
<value>1</value>
</row>
<row>
<value>png</value>
<value>1</value>
</row>
</table>
<table name="phpbb_extension_groups">
<column>cat_id</column>
<column>group_id</column>
<column>download_mode</column>
<column>upload_icon</column>
<column>max_filesize</column>
<column>allow_group</column>
<column>allow_in_pm</column>
<column>allowed_forums</column>
<column>group_name</column>
<row>
<value>1</value>
<value>1</value>
<value>1</value>
<value> </value>
<value>1000</value>
<value>1</value>
<value>1</value>
<value>a:1:{i:0;i:1;}</value>
<value>Images</value>
</row>
</table>
<table name="phpbb_posts">
<column>post_id</column>
<column>post_text</column>
<column>poster_id</column>
<column>post_attachment</column>
<row>
<value>1</value>
<value>foo</value>
<value>1</value>
<value>1</value>
</row>
<row>
<value>2</value>
<value>foo</value>
<value>1</value>
<value>1</value>
</row>
</table>
<table name="phpbb_privmsgs">
<column>msg_id</column>
<column>message_text</column>
<column>message_attachment</column>
<column>to_address</column>
<column>bcc_address</column>
<row>
<value>1</value>
<value>foo</value>
<value>1</value>
<value>2</value>
<value>2</value>
</row>
<row>
<value>2</value>
<value>foo</value>
<value>1</value>
<value>2</value>
<value>2</value>
</row>
</table>
<table name="phpbb_topics">
<column>topic_id</column>
<column>forum_id</column>
<column>topic_title</column>
<column>topic_attachment</column>
<row>
<value>1</value>
<value>1</value>
<value>foo</value>
<value>1</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>bar</value>
<value>1</value>
</row>
</table>
</dataset>

View File

@ -0,0 +1,131 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
class phpbb_attachment_manager_test extends \phpbb_test_case
{
protected $delete;
protected $resync;
protected $upload;
public function setUp()
{
$this->delete = $this->getMockBuilder('\phpbb\attachment\delete')
->disableOriginalConstructor()
->setMethods(['delete', 'unlink_attachment'])
->getMock();
$this->resync = $this->getMockBuilder('\phpbb\attachment\resync')
->disableOriginalConstructor()
->setMethods(['resync'])
->getMock();
$this->upload = $this->getMockBuilder('\phpbb\attachment\upload')
->disableOriginalConstructor()
->setMethods(['upload'])
->getMock();
}
protected function get_manager()
{
return new \phpbb\attachment\manager($this->delete, $this->resync, $this->upload);
}
public function data_manager()
{
return array(
array(
'delete',
'unlink_attachment',
'unlink',
['foo'],
['foo', 'file', false],
true,
true,
),
array(
'delete',
'unlink_attachment',
'unlink',
['foo', 'bar'],
['foo', 'bar', false],
true,
true,
),
array(
'delete',
'unlink_attachment',
'unlink',
['foo', 'bar', true],
['foo', 'bar', true],
true,
true,
),
array(
'delete',
'delete',
'delete',
['foo', [1, 2, 3]],
['foo', [1, 2, 3], true],
5,
5,
),
array(
'delete',
'delete',
'delete',
['foo', [1, 2, 3], false],
['foo', [1, 2, 3], false],
2,
2,
),
array(
'resync',
'resync',
'resync',
['foo', [1, 2, 3]],
['foo', [1, 2, 3]],
true,
null,
),
array(
'upload',
'upload',
'upload',
['foo', 1],
['foo', 1, false, '', false, []],
true,
true,
),
array(
'upload',
'upload',
'upload',
['foo', 1, true, 'bar', true, ['filename' => 'foobar']],
['foo', 1, true, 'bar', true, ['filename' => 'foobar']],
true,
true,
),
);
}
/**
* @dataProvider data_manager
*/
public function test_manager($class, $method_class, $method_manager, $input_manager, $input_method, $return, $output)
{
$mock = call_user_func_array([$this->{$class}, 'expects'], [$this->atLeastOnce()]);
$mock = $mock->method($method_class);
$mock = call_user_func_array([$mock, 'with'], $input_method);
$mock->willReturn($return);
$manager = $this->get_manager();
$this->assertSame($output, call_user_func_array([$manager, $method_manager], $input_manager));
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
class phpbb_attachment_resync_test extends \phpbb_database_test_case
{
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\attachment\resync */
protected $resync;
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml');
}
public function setUp()
{
parent::setUp();
$this->db = $this->new_dbal();
$this->resync = new \phpbb\attachment\resync($this->db);
}
public function data_resync()
{
return array(
array('', array(1), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '1')),
array('post', array(1), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '1')),
array('post', array(2), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '0')),
array('topic', array(1), 'topic_id', TOPICS_TABLE, array('topic_attachment' => '1'), array('topic_attachment' => '1')),
array('topic', array(2), 'topic_id', TOPICS_TABLE, array('topic_attachment' => '1'), array('topic_attachment' => '0')),
array('message', array(1), 'msg_id', PRIVMSGS_TABLE, array('message_attachment' => '1'), array('message_attachment' => '1')),
array('message', array(2), 'msg_id', PRIVMSGS_TABLE, array('message_attachment' => '1'), array('message_attachment' => '0')),
);
}
/**
* @dataProvider data_resync
*/
public function test_resync($type, $ids, $sql_id, $exist_table, $exist_data, $resync_data)
{
$sql_prefix = ($type) ?: 'post';
$sql = 'SELECT ' . $sql_prefix . '_attachment
FROM ' . $exist_table . '
WHERE ' . $sql_id . ' = ' . $ids[0];
$result = $this->db->sql_query($sql);
$data = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
$this->assertEquals($exist_data, $data);
$this->resync->resync($type, $ids);
$sql = 'SELECT ' . $sql_prefix . '_attachment
FROM ' . $exist_table . '
WHERE ' . $sql_id . ' = ' . $ids[0];
$result = $this->db->sql_query($sql);
$data = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
$this->assertEquals($resync_data, $data);
}
}

View File

@ -0,0 +1,430 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
require_once(dirname(__FILE__) . '/../../phpBB/includes/functions.php');
require_once(dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php');
class phpbb_attachment_upload_test extends \phpbb_database_test_case
{
/** @var \phpbb\auth\auth */
protected $auth;
/** @var \phpbb\cache\service */
protected $cache;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbb\files\upload */
protected $files_upload;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbb\mimetype\guesser */
protected $mimetype_guesser;
/** @var \phpbb\event\dispatcher */
protected $phpbb_dispatcher;
/** @var \phpbb\plupload\plupload */
protected $plupload;
/** @var \phpbb\user */
protected $user;
/** @var string phpBB root path */
protected $phpbb_root_path;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\attachment\upload */
protected $upload;
private $filesystem;
/** @var \Symfony\Component\DependencyInjection\ContainerInterface */
protected $container;
/** @var \phpbb\files\factory */
protected $factory;
/** @var \bantu\IniGetWrapper\IniGetWrapper */
protected $php_ini;
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml');
}
public function setUp()
{
global $config, $phpbb_root_path, $phpEx;
parent::setUp();
$this->auth = new \phpbb\auth\auth();
$this->config = new \phpbb\config\config(array(
'upload_path' => '',
'img_create_thumbnail' => true,
));
$config = $this->config;
$this->db = $this->new_dbal();
$this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), $this->config, $this->db, $phpbb_root_path, $phpEx);
$this->request = $this->getMock('\phpbb\request\request');
$this->filesystem = new \phpbb\filesystem\filesystem();
$this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
$guessers = array(
new \Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser(),
new \Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser(),
new \phpbb\mimetype\content_guesser(),
new \phpbb\mimetype\extension_guesser(),
);
$guessers[2]->set_priority(-2);
$guessers[3]->set_priority(-2);
$this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers);
$this->plupload = new \phpbb\plupload\plupload($phpbb_root_path, $this->config, $this->request, new \phpbb\user($this->language, '\phpbb\datetime'), $this->php_ini, $this->mimetype_guesser);
$factory_mock = $this->getMockBuilder('\phpbb\files\factory')
->disableOriginalConstructor()
->getMock();
$factory_mock->expects($this->any())
->method('get')
->willReturn(new \phpbb\files\filespec(
$this->filesystem,
$this->language,
$this->php_ini,
new \FastImageSize\FastImageSize(),
$this->phpbb_root_path,
$this->mimetype_guesser
));
$this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
$this->container->set('files.filespec', new \phpbb\files\filespec(
$this->filesystem,
$this->language,
$this->php_ini,
new \FastImageSize\FastImageSize(),
$phpbb_root_path,
new \phpbb\mimetype\guesser(array(
'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
))));
$this->container->set('files.types.form', new \phpbb\files\types\form(
$factory_mock,
$this->language,
$this->php_ini,
$this->plupload,
$this->request
));
$this->container->set('files.types.local', new \phpbb\files\types\local(
$factory_mock,
$this->language,
$this->php_ini,
$this->request
));
$this->factory = new \phpbb\files\factory($this->container);
$this->files_upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
$this->phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$this->user = new \phpbb\user($this->language, '\phpbb\datetime');
$this->upload = new \phpbb\attachment\upload(
$this->auth,
$this->cache,
$this->config,
$this->files_upload,
$this->language,
$this->mimetype_guesser,
$this->phpbb_dispatcher,
$this->plupload,
$this->user,
$this->phpbb_root_path
);
}
public function data_upload()
{
return array(
array('foobar', 1, false,
array(),
array(
'error' => array(
'Upload initiated but no valid file upload form found.',
),
'post_attach' => false,
)
),
array('foobar', 1, true,
array(
'realname' => 'foobar.jpg',
'type' => 'jpg',
'size' => 100,
),
array(
'error' => array(
'NOT_UPLOADED',
'The image file you tried to attach is invalid.',
),
'post_attach' => false,
'thumbnail' => 1,
)
),
array('foobar', 1, true,
array(),
array(
'error' => array(
'NOT_UPLOADED',
),
'post_attach' => false,
'thumbnail' => 0,
)
),
);
}
/**
* @dataProvider data_upload
*/
public function test_upload($form_name, $forum_id, $local, $filedata, $expected)
{
$filedata = $this->upload->upload($form_name, $forum_id, $local, '', false, $filedata);
$this->assertSame($expected, $filedata);
}
public function test_init_error()
{
$filespec = $this->getMockBuilder('\phpbb\files\filespec')
->disableOriginalConstructor()
->getMock();
$filespec->expects($this->any())
->method('init_error')
->willReturn(true);
$filespec->expects($this->any())
->method('set_upload_namespace')
->willReturnSelf();
$filespec->expects($this->any())
->method('set_upload_ary')
->willReturnSelf();
$this->container->set('files.filespec', $filespec);
$factory_mock = $this->getMockBuilder('\phpbb\files\factory')
->disableOriginalConstructor()
->getMock();
$factory_mock->expects($this->any())
->method('get')
->willReturn($filespec);
$this->container->set('files.types.local', new \phpbb\files\types\local(
$factory_mock,
$this->language,
$this->php_ini,
$this->request
));
$this->upload = new \phpbb\attachment\upload(
$this->auth,
$this->cache,
$this->config,
$this->files_upload,
$this->language,
$this->mimetype_guesser,
$this->phpbb_dispatcher,
$this->plupload,
$this->user,
$this->phpbb_root_path
);
$filedata = $this->upload->upload('foobar', 1, true);
$this->assertSame(array(
'error' => array(),
'post_attach' => false,
), $filedata);
}
public function data_image_upload()
{
return array(
array(false, false, array(),
array(
'error' => array('The image file you tried to attach is invalid.'),
'post_attach' => false,
'thumbnail' => 1,
)
),
array(false, true, array(),
array(
'error' => array('The image file you tried to attach is invalid.'),
'post_attach' => false,
'thumbnail' => 1,
)
),
array(true, false, array(),
array(
'error' => array(),
'post_attach' => true,
// thumbnail gets reset to 0 as creation was not possible
'thumbnail' => 0,
'filesize' => 100,
'mimetype' => 'jpg',
'extension' => 'jpg',
'real_filename' => 'foobar.jpg',
)
),
array(true, false,
array(
'check_attachment_content' => true,
'mime_triggers' => '',
),
array(
'error' => array(),
'post_attach' => true,
// thumbnail gets reset to 0 as creation was not possible
'thumbnail' => 0,
'filesize' => 100,
'mimetype' => 'jpg',
'extension' => 'jpg',
'real_filename' => 'foobar.jpg',
)
),
array(true, false,
array(
'attachment_quota' => 150,
),
array(
'error' => array(),
'post_attach' => true,
// thumbnail gets reset to 0 as creation was not possible
'thumbnail' => 0,
'filesize' => 100,
'mimetype' => 'jpg',
'extension' => 'jpg',
'real_filename' => 'foobar.jpg',
)
),
array(true, false,
array(
'attachment_quota' => 50,
),
array(
'error' => array(
'ATTACH_QUOTA_REACHED',
),
'post_attach' => false,
'thumbnail' => 1,
'filesize' => 100,
'mimetype' => 'jpg',
'extension' => 'jpg',
'real_filename' => 'foobar.jpg',
)
),
);
}
/**
* @dataProvider data_image_upload
*/
public function test_image_upload($is_image, $plupload_active, $config_data, $expected)
{
$filespec = $this->getMock('\phpbb\files\filespec',
array(
'init_error',
'is_image',
'move_file',
'is_uploaded',
),
array(
$this->filesystem,
$this->language,
$this->php_ini,
new \FastImageSize\FastImageSize(),
$this->phpbb_root_path,
$this->mimetype_guesser,
$this->plupload
));
foreach ($config_data as $key => $value)
{
$this->config[$key] = $value;
}
$filespec->set_upload_namespace($this->files_upload);
$filespec->expects($this->any())
->method('init_error')
->willReturn(false);
$filespec->expects($this->any())
->method('is_image')
->willReturn($is_image);
$filespec->expects($this->any())
->method('is_uploaded')
->willReturn(true);
$filespec->expects($this->any())
->method('move_file')
->willReturn(false);
$this->container->set('files.filespec', $filespec);
$factory_mock = $this->getMockBuilder('\phpbb\files\factory')
->disableOriginalConstructor()
->getMock();
$factory_mock->expects($this->any())
->method('get')
->willReturn($filespec);
$this->container->set('files.types.local', new \phpbb\files\types\local(
$factory_mock,
$this->language,
$this->php_ini,
$this->request
));
$plupload = $this->getMockBuilder('\phpbb\plupload\plupload')
->disableOriginalConstructor()
->getMock();
$plupload->expects($this->any())
->method('is_active')
->willReturn($plupload_active);
if ($plupload_active)
{
$plupload->expects($this->once())
->method('emit_error')
->with(104, 'ATTACHED_IMAGE_NOT_IMAGE')
->willReturn(false);
}
$this->upload = new \phpbb\attachment\upload(
$this->auth,
$this->cache,
$this->config,
$this->files_upload,
$this->language,
$this->mimetype_guesser,
$this->phpbb_dispatcher,
$plupload,
$this->user,
$this->phpbb_root_path
);
$filedata = $this->upload->upload('foobar', 1, true, '', false, array(
'realname' => 'foobar.jpg',
'type' => 'jpg',
'size' => 100,
));
foreach ($expected as $key => $entry)
{
$this->assertEquals($entry, $filedata[$key]);
}
// Reset config data
foreach ($config_data as $key => $value)
{
$this->config->delete($key);
}
}
}

View File

@ -312,12 +312,15 @@ class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case
$lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
$lang = new \phpbb\language\language($lang_loader);
$user = new \phpbb\user($lang, '\phpbb\datetime');
$attachment_delete = new \phpbb\attachment\delete($config, $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path);
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
$phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE));
// Works as a workaround for tests
$phpbb_container->set('attachment.manager', $attachment_delete);
delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $reason);

View File

@ -25,7 +25,7 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
{
parent::setUp();
global $cache, $config, $db, $phpbb_dispatcher, $phpbb_container;
global $cache, $config, $db, $phpbb_dispatcher, $phpbb_container, $phpbb_root_path;
$db = $this->db = $this->new_dbal();
$config = new \phpbb\config\config(array(
@ -36,6 +36,8 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
// Works as a workaround for tests
$phpbb_container->set('attachment.manager', new \phpbb\attachment\delete($config, $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path));
$phpbb_container->set(
'auth.provider.db',
new phpbb_mock_auth_provider()

View File

@ -85,12 +85,14 @@ class phpbb_privmsgs_delete_user_pms_test extends phpbb_database_test_case
*/
public function test_delete_user_pms($delete_user, $remaining_privmsgs, $remaining_privmsgs_to)
{
global $db, $phpbb_container;
global $db, $phpbb_container, $phpbb_root_path;
$db = $this->new_dbal();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
// Works as a workaround for tests
$phpbb_container->set('attachment.manager', new \phpbb\attachment\delete(new \phpbb\config\config(array()), $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path));
phpbb_delete_user_pms($delete_user);