aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB')
-rw-r--r--phpBB/config/services.yml9
-rw-r--r--phpBB/includes/functions_posting.php19
-rw-r--r--phpBB/includes/functions_upload.php31
-rw-r--r--phpBB/includes/message_parser.php49
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php10
-rw-r--r--phpBB/install/install_install.php4
-rw-r--r--phpBB/install/schemas/schema_data.sql2
-rw-r--r--phpBB/language/en/plupload.php65
-rw-r--r--phpBB/phpbb/db/migration/data/v310/alpha1.php1
-rw-r--r--phpBB/phpbb/db/migration/data/v310/plupload.php32
-rw-r--r--phpBB/phpbb/plupload/plupload.php374
-rw-r--r--phpBB/posting.php7
-rw-r--r--phpBB/styles/prosilver/template/overall_footer.html1
-rw-r--r--phpBB/styles/prosilver/template/overall_header.html5
-rw-r--r--phpBB/styles/prosilver/template/plupload.html48
-rw-r--r--phpBB/styles/prosilver/theme/plupload.css11
16 files changed, 659 insertions, 9 deletions
diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml
index 51ae5c454d..c6490a21d7 100644
--- a/phpBB/config/services.yml
+++ b/phpBB/config/services.yml
@@ -258,6 +258,15 @@ services:
php_ini:
class: phpbb\php\ini
+ plupload:
+ class: phpbb\plupload\plupload
+ arguments:
+ - %core.root_path%
+ - @config
+ - @request
+ - @user
+ - @php_ini
+
request:
class: phpbb\request\request
diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php
index ce1238d8e0..1bcef7f1f2 100644
--- a/phpBB/includes/functions_posting.php
+++ b/phpBB/includes/functions_posting.php
@@ -385,8 +385,18 @@ function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
/**
* 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 \filespec $local_filedata A filespec object created for the local file
+* @param \phpbb\plupload\plupload $plupload The plupload object if one is being used
+*
+* @return object filespec
*/
-function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false)
+function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false, \phpbb\plupload\plupload $plupload = null)
{
global $auth, $user, $config, $db, $cache;
global $phpbb_root_path, $phpEx;
@@ -414,7 +424,7 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage
$extensions = $cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
$upload->set_allowed_extensions(array_keys($extensions['_allowed_']));
- $file = ($local) ? $upload->local_upload($local_storage, $local_filedata) : $upload->form_upload($form_name);
+ $file = ($local) ? $upload->local_upload($local_storage, $local_filedata) : $upload->form_upload($form_name, $plupload);
if ($file->init_error)
{
@@ -469,6 +479,11 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage
{
$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']);
diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php
index 4181896eca..04d483e14c 100644
--- a/phpBB/includes/functions_upload.php
+++ b/phpBB/includes/functions_upload.php
@@ -44,10 +44,16 @@ class filespec
var $upload = '';
/**
+ * The plupload object
+ * @var \phpbb\plupload\plupload
+ */
+ protected $plupload;
+
+ /**
* File Class
* @access private
*/
- function filespec($upload_ary, $upload_namespace)
+ function filespec($upload_ary, $upload_namespace, \phpbb\plupload\plupload $plupload = null)
{
if (!isset($upload_ary))
{
@@ -80,6 +86,7 @@ class filespec
$this->local = (isset($upload_ary['local_mode'])) ? true : false;
$this->upload = $upload_namespace;
+ $this->plupload = $plupload;
}
/**
@@ -161,12 +168,14 @@ class filespec
*/
function is_uploaded()
{
- if (!$this->local && !is_uploaded_file($this->filename))
+ $is_plupload = $this->plupload && $this->plupload->is_active();
+
+ if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename))
{
return false;
}
- if ($this->local && !file_exists($this->filename))
+ if (($this->local || $is_plupload) && !file_exists($this->filename))
{
return false;
}
@@ -564,16 +573,28 @@ class fileupload
* Upload file from users harddisk
*
* @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified)
+ * @param \phpbb\plupload\plupload $plupload The plupload object
+ *
* @return object $file Object "filespec" is returned, all further operations can be done with this object
* @access public
*/
- function form_upload($form_name)
+ function form_upload($form_name, \phpbb\plupload\plupload $plupload = null)
{
global $user, $request;
$upload = $request->file($form_name);
unset($upload['local_mode']);
- $file = new filespec($upload, $this);
+
+ if ($plupload)
+ {
+ $result = $plupload->handle_upload($form_name);
+ if (is_array($result))
+ {
+ $upload = array_merge($upload, $result);
+ }
+ }
+
+ $file = new filespec($upload, $this, $plupload);
if ($file->init_error)
{
diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php
index 3e348801c7..acd31fd519 100644
--- a/phpBB/includes/message_parser.php
+++ b/phpBB/includes/message_parser.php
@@ -1050,6 +1050,12 @@ class parse_message extends bbcode_firstpass
var $mode;
/**
+ * The plupload object used for dealing with attachments
+ * @var \phpbb\plupload\plupload
+ */
+ protected $plupload;
+
+ /**
* Init - give message here or manually
*/
function parse_message($message = '')
@@ -1440,6 +1446,11 @@ class parse_message extends bbcode_firstpass
if ($preview || $refresh || sizeof($error))
{
+ if (isset($this->plupload) && $this->plupload->is_active())
+ {
+ $json_response = new \phpbb\json_response();
+ }
+
// Perform actions on temporary attachments
if ($delete_file)
{
@@ -1484,13 +1495,17 @@ class parse_message extends bbcode_firstpass
// Reindex Array
$this->attachment_data = array_values($this->attachment_data);
+ if (isset($this->plupload) && $this->plupload->is_active())
+ {
+ $json_response->send($this->attachment_data);
+ }
}
}
else if (($add_file || $preview) && $upload_file)
{
if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id))
{
- $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
+ $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message, false, $this->plupload);
$error = array_merge($error, $filedata['error']);
if (!sizeof($error))
@@ -1521,12 +1536,32 @@ class parse_message extends bbcode_firstpass
$this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
$this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
$this->filename_data['filecomment'] = '';
+
+ if (isset($this->plupload) && $this->plupload->is_active())
+ {
+ // Send the client the attachment data to maintain state
+ $json_response->send($this->attachment_data);
+ }
}
}
else
{
$error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']);
}
+
+ if (!empty($error) && isset($this->plupload) && $this->plupload->is_active())
+ {
+ // If this is a plupload (and thus ajax) request, give the
+ // client the first error we have
+ $json_response->send(array(
+ 'jsonrpc' => '2.0',
+ 'id' => 'id',
+ 'error' => array(
+ 'code' => 105,
+ 'message' => current($error),
+ ),
+ ));
+ }
}
}
@@ -1687,4 +1722,16 @@ class parse_message extends bbcode_firstpass
$poll['poll_max_options'] = ($poll['poll_max_options'] < 1) ? 1 : (($poll['poll_max_options'] > $config['max_poll_options']) ? $config['max_poll_options'] : $poll['poll_max_options']);
}
+
+ /**
+ * Setter function for passing the plupload object
+ *
+ * @param \phpbb\plupload\plupload $plupload The plupload object
+ *
+ * @return null
+ */
+ public function set_plupload(\phpbb\plupload\plupload $plupload)
+ {
+ $this->plupload = $plupload;
+ }
}
diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php
index e0e7a46494..87dfdf902b 100644
--- a/phpBB/includes/ucp/ucp_pm_compose.php
+++ b/phpBB/includes/ucp/ucp_pm_compose.php
@@ -21,9 +21,10 @@ if (!defined('IN_PHPBB'))
*/
function compose_pm($id, $mode, $action, $user_folders = array())
{
- global $template, $db, $auth, $user;
+ global $template, $db, $auth, $user, $cache;
global $phpbb_root_path, $phpEx, $config;
global $request;
+ global $phpbb_container;
// Damn php and globals - i know, this is horrible
// Needed for handle_message_list_actions()
@@ -385,6 +386,8 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
$message_parser = new parse_message();
+ $plupload = $phpbb_container->get('plupload');
+ $message_parser->set_plupload($plupload);
$message_parser->message = ($action == 'reply') ? '' : $message_text;
unset($message_text);
@@ -1099,6 +1102,11 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Show attachment box for adding attachments if true
$allowed = ($auth->acl_get('u_pm_attach') && $config['allow_pm_attach'] && $form_enctype);
+ if ($allowed)
+ {
+ $plupload->configure($cache, $template, $s_action, false);
+ }
+
// Attachment entry
posting_gen_attachment_entry($attachment_data, $filename_data, $allowed);
diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php
index c273660d08..1a7e1d1094 100644
--- a/phpBB/install/install_install.php
+++ b/phpBB/install/install_install.php
@@ -1322,6 +1322,10 @@ class install_install extends module
SET config_value = '" . md5(mt_rand()) . "'
WHERE config_name = 'avatar_salt'",
+ 'UPDATE ' . $data['table_prefix'] . "config
+ SET config_value = '" . md5(mt_rand()) . "'
+ WHERE config_name = 'plupload_salt'",
+
'UPDATE ' . $data['table_prefix'] . "users
SET username = '" . $db->sql_escape($data['admin_name']) . "', user_password='" . $db->sql_escape(md5($data['admin_pass1'])) . "', user_ip = '" . $db->sql_escape($user_ip) . "', user_lang = '" . $db->sql_escape($data['default_lang']) . "', user_email='" . $db->sql_escape($data['board_email']) . "', user_dateformat='" . $db->sql_escape($lang['default_dateformat']) . "', user_email_hash = " . $db->sql_escape(phpbb_email_hash($data['board_email'])) . ", username_clean = '" . $db->sql_escape(utf8_clean_string($data['admin_name'])) . "'
WHERE username = 'Admin'",
diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql
index cd38f86312..094a43c8a0 100644
--- a/phpBB/install/schemas/schema_data.sql
+++ b/phpBB/install/schemas/schema_data.sql
@@ -222,6 +222,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('new_member_post_li
INSERT INTO phpbb_config (config_name, config_value) VALUES ('new_member_group_default', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('override_user_style', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('pass_complex', 'PASS_TYPE_ANY');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('plupload_salt', 'phpbb_plupload');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('pm_edit_time', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('pm_max_boxes', '4');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('pm_max_msgs', '50');
@@ -284,6 +285,7 @@ INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('num_fi
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('num_posts', '1', 1);
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('num_topics', '1', 1);
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('num_users', '1', 1);
+INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('plupload_last_gc', '0', 1);
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('rand_seed', '0', 1);
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('rand_seed_last_update', '0', 1);
INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('record_online_date', '0', 1);
diff --git a/phpBB/language/en/plupload.php b/phpBB/language/en/plupload.php
new file mode 100644
index 0000000000..cfdce9810e
--- /dev/null
+++ b/phpBB/language/en/plupload.php
@@ -0,0 +1,65 @@
+<?php
+/**
+*
+* plupload [English]
+*
+* @package language
+* @copyright (c) 2010-2013 Moxiecode Systems AB
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* DO NOT CHANGE
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+if (empty($lang) || !is_array($lang))
+{
+ $lang = array();
+}
+
+// DEVELOPERS PLEASE NOTE
+//
+// All language files should use UTF-8 as their encoding and the files must not contain a BOM.
+//
+// Placeholders can now contain order information, e.g. instead of
+// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows
+// translators to re-order the output of data while ensuring it remains correct
+//
+// You do not need this where single placeholders are used, e.g. 'Message %d' is fine
+// equally where a string contains only two placeholders which are used to wrap text
+// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
+
+$lang = array_merge($lang, array(
+ 'PLUPLOAD_ADD_FILES' => 'Add files',
+ 'PLUPLOAD_ADD_FILES_TO_QUEUE' => 'Add files to the upload queue and click the start button.',
+ 'PLUPLOAD_DRAG' => 'Drag files here.',
+ 'PLUPLOAD_ERR_INPUT' => 'Failed to open input stream.',
+ 'PLUPLOAD_ERR_MOVE_UPLOADED' => 'Failed to move uploaded file.',
+ 'PLUPLOAD_ERR_OUTPUT' => 'Failed to open output stream.',
+ 'PLUPLOAD_EXTENSION_ERROR' => 'File extension error.',
+ 'PLUPLOAD_FILENAME' => 'Filename',
+ 'PLUPLOAD_FILES_QUEUED' => '%d files queued',
+ 'PLUPLOAD_GENERIC_ERROR' => 'Generic error.',
+ 'PLUPLOAD_HTTP_ERROR' => 'HTTP error.',
+ 'PLUPLOAD_INIT_ERROR' => 'Init error.',
+ 'PLUPLOAD_IO_ERROR' => 'IO error.',
+ 'PLUPLOAD_NOT_APPLICABLE' => 'N/A',
+ 'PLUPLOAD_SECURITY_ERROR' => 'Security error.',
+ 'PLUPLOAD_SELECT_FILES' => 'Select files',
+ 'PLUPLOAD_SIZE' => 'Size',
+ 'PLUPLOAD_SIZE_ERROR' => 'File size error.',
+ 'PLUPLOAD_STATUS' => 'Status',
+ 'PLUPLOAD_START_UPLOAD' => 'Start upload',
+ 'PLUPLOAD_START_CURRENT_UPLOAD' => 'Start uploading queue',
+ 'PLUPLOAD_STOP_UPLOAD' => 'Stop upload',
+ 'PLUPLOAD_STOP_CURRENT_UPLOAD' => 'Stop current upload',
+ // Note: This string is formatted independently by plupload and so does not
+ // use the same formatting rules as normal phpBB translation strings
+ 'PLUPLOAD_UPLOADED' => 'Uploaded %d/%d files',
+));
diff --git a/phpBB/phpbb/db/migration/data/v310/alpha1.php b/phpBB/phpbb/db/migration/data/v310/alpha1.php
index 04f195daeb..368c53125e 100644
--- a/phpBB/phpbb/db/migration/data/v310/alpha1.php
+++ b/phpBB/phpbb/db/migration/data/v310/alpha1.php
@@ -27,6 +27,7 @@ class alpha1 extends \phpbb\db\migration\migration
'\phpbb\db\migration\data\v310\namespaces',
'\phpbb\db\migration\data\v310\notifications_cron',
'\phpbb\db\migration\data\v310\notification_options_reconvert',
+ '\phpbb\db\migration\data\v310\plupload',
'\phpbb\db\migration\data\v310\signature_module_auth',
'\phpbb\db\migration\data\v310\softdelete_mcp_modules',
'\phpbb\db\migration\data\v310\teampage',
diff --git a/phpBB/phpbb/db/migration/data/v310/plupload.php b/phpBB/phpbb/db/migration/data/v310/plupload.php
new file mode 100644
index 0000000000..1787c6dafc
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v310/plupload.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+namespace phpbb\db\migration\data\v310;
+
+class plupload extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return isset($this->config['plupload_last_gc']) &&
+ isset($this->config['plupload_salt']);
+ }
+
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\310\dev');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('plupload_last_gc', 0)),
+ array('config.add', array('plupload_salt', unique_id())),
+ );
+ }
+}
diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php
new file mode 100644
index 0000000000..6eb5adf864
--- /dev/null
+++ b/phpBB/phpbb/plupload/plupload.php
@@ -0,0 +1,374 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+namespace phpbb\plupload;
+
+/**
+ * @ignore
+ */
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* This class handles all server-side plupload functions
+*
+* @package \phpbb\plupload\plupload
+*/
+class plupload
+{
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\request\request_interface
+ */
+ protected $request;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * @var \phpbb\php\ini
+ */
+ protected $php_ini;
+
+ /**
+ * Final destination for uploaded files, i.e. the "files" directory.
+ * @var string
+ */
+ protected $upload_directory;
+
+ /**
+ * Temporary upload directory for plupload uploads.
+ * @var string
+ */
+ protected $temporary_directory;
+
+ /**
+ * Constructor.
+ *
+ * @param string $phpbb_root_path
+ * @param \phpbb\config\config $config
+ * @param \phpbb\request\request_interface $request
+ * @param \phpbb\user $user
+ * @param \phpbb\php\ini $php_ini
+ *
+ * @return null
+ */
+ public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\user $user, \phpbb\php\ini $php_ini)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->config = $config;
+ $this->request = $request;
+ $this->user = $user;
+ $this->php_ini = $php_ini;
+
+ $this->upload_directory = $this->phpbb_root_path . $this->config['upload_path'];
+ $this->temporary_directory = $this->upload_directory . '/plupload';
+ }
+
+ /**
+ * Plupload allows for chunking so we must check for that and assemble
+ * the whole file first before performing any checks on it.
+ *
+ * @param string $form_name The name of the file element in the upload form
+ *
+ * @return array|null null if there are no chunks to piece together
+ * otherwise array containing the path to the
+ * pieced-together file and its size
+ */
+ public function handle_upload($form_name)
+ {
+ $chunks_expected = $this->request->variable('chunks', 0);
+
+ // If chunking is disabled or we are not using plupload, just return
+ // and handle the file as usual
+ if ($chunks_expected < 2)
+ {
+ return;
+ }
+
+ $file_name = $this->request->variable('name', '');
+ $chunk = $this->request->variable('chunk', 0);
+
+ $this->user->add_lang('plupload');
+ $this->prepare_temporary_directory();
+
+ $file_path = $this->temporary_filepath($file_name);
+ $this->integrate_uploaded_file($form_name, $chunk, $file_path);
+
+ // If we are done with all the chunks, strip the .part suffix and then
+ // handle the resulting file as normal, otherwise die and await the
+ // next chunk.
+ if ($chunk == $chunks_expected - 1)
+ {
+ rename("{$file_path}.part", $file_path);
+
+ $file_info = new \Symfony\Component\HttpFoundation\File\File($file_path);
+
+ // Need to modify some of the $_FILES values to reflect the new file
+ return array(
+ 'tmp_name' => $file_path,
+ 'name' => $this->request->variable('real_filename', ''),
+ 'size' => filesize($file_path),
+ 'type' => $file_info->getMimeType($file_path),
+ );
+ }
+ else
+ {
+ $json_response = new \phpbb\json_response();
+ $json_response->send(array(
+ 'jsonrpc' => '2.0',
+ 'id' => 'id',
+ 'result' => null,
+ ));
+ }
+ }
+
+ /**
+ * Fill in the plupload configuration options in the template
+ *
+ * @param \phpbb\cache\service $cache
+ * @param \phpbb\template\template $template
+ * @param string $s_action The URL to submit the POST data to
+ * @param int $forum_id The ID of the forum
+ *
+ * @return null
+ */
+ public function configure(\phpbb\cache\service $cache, \phpbb\template\template $template, $s_action, $forum_id)
+ {
+ $filters = $this->generate_filter_string($cache, $forum_id);
+ $chunk_size = $this->get_chunk_size();
+ $resize = $this->generate_resize_string();
+
+ $template->assign_vars(array(
+ 'S_RESIZE' => $resize,
+ 'S_PLUPLOAD' => true,
+ 'FILTERS' => $filters,
+ 'CHUNK_SIZE' => $chunk_size,
+ 'S_PLUPLOAD_URL' => htmlspecialchars_decode($s_action),
+ ));
+
+ $this->user->add_lang('plupload');
+ }
+
+ /**
+ * Checks whether the page request was sent by plupload or not
+ *
+ * @return bool
+ */
+ public function is_active()
+ {
+ return $this->request->header('X-PHPBB-USING-PLUPLOAD', false);
+ }
+
+ /**
+ * Returns whether the current HTTP request is a multipart request.
+ *
+ * @return bool
+ */
+ public function is_multipart()
+ {
+ $content_type = $this->request->server('CONTENT_TYPE');
+
+ return strpos($content_type, 'multipart') === 0;
+ }
+
+ /**
+ * Sends an error message back to the client via JSON response
+ *
+ * @param int $code The error code
+ * @param string $msg The translation string of the message to be sent
+ *
+ * @return null
+ */
+ public function emit_error($code, $msg)
+ {
+ $json_response = new \phpbb\json_response();
+ $json_response->send(array(
+ 'jsonrpc' => '2.0',
+ 'id' => 'id',
+ 'error' => array(
+ 'code' => $code,
+ 'message' => $this->user->lang($msg),
+ ),
+ ));
+ }
+
+ /**
+ * Looks at the list of allowed extensions and generates a string
+ * appropriate for use in configuring plupload with
+ *
+ * @param \phpbb\cache\service $cache
+ * @param string $forum_id The ID of the forum
+ *
+ * @return string
+ */
+ public function generate_filter_string(\phpbb\cache\service $cache, $forum_id)
+ {
+ $attach_extensions = $cache->obtain_attach_extensions($forum_id);
+ unset($attach_extensions['_allowed_']);
+ $groups = array();
+
+ // Re-arrange the extension array to $groups[$group_name][]
+ foreach ($attach_extensions as $extension => $extension_info)
+ {
+ if (!isset($groups[$extension_info['group_name']]))
+ {
+ $groups[$extension_info['group_name']] = array();
+ }
+
+ $groups[$extension_info['group_name']][] = $extension;
+ }
+
+ $filters = array();
+ foreach ($groups as $group => $extensions)
+ {
+ $filters[] = sprintf(
+ "{title: '%s', extensions: '%s'}",
+ addslashes(ucfirst(strtolower($group))),
+ addslashes(implode(',', $extensions))
+ );
+ }
+
+ return implode(',', $filters);
+ }
+
+ /**
+ * Generates a string that is used to tell plupload to automatically resize
+ * files before uploading them.
+ *
+ * @return string
+ */
+ public function generate_resize_string()
+ {
+ $resize = '';
+ if ($this->config['img_max_height'] > 0 && $this->config['img_max_width'] > 0)
+ {
+ $resize = sprintf(
+ 'resize: {width: %d, height: %d, quality: 100},',
+ (int) $this->config['img_max_height'],
+ (int) $this->config['img_max_width']
+ );
+ }
+
+ return $resize;
+ }
+
+ /**
+ * Checks various php.ini values and the maximum file size to determine
+ * the maximum size chunks a file can be split up into for upload
+ *
+ * @return int
+ */
+ public function get_chunk_size()
+ {
+ $max = min(
+ $this->php_ini->get_bytes('upload_max_filesize'),
+ $this->php_ini->get_bytes('post_max_size'),
+ max(1, $this->php_ini->get_bytes('memory_limit')),
+ $this->config['max_filesize']
+ );
+
+ // Use half of the maximum possible to leave plenty of room for other
+ // POST data.
+ return floor($max / 2);
+ }
+
+ protected function temporary_filepath($file_name)
+ {
+ // Must preserve the extension for plupload to work.
+ return sprintf(
+ '%s/%s_%s%s',
+ $this->temporary_directory,
+ $this->config['plupload_salt'],
+ md5($file_name),
+ \filespec::get_extension($file_name)
+ );
+ }
+
+ /**
+ * Checks whether the chunk we are about to deal with was actually uploaded
+ * by PHP and actually exists, if not, it generates an error
+ *
+ * @param string $form_name The name of the file in the form data
+ *
+ * @return null
+ */
+ protected function integrate_uploaded_file($form_name, $chunk, $file_path)
+ {
+ $is_multipart = $this->is_multipart();
+ $upload = $this->request->file($form_name);
+ if ($is_multipart && (!isset($upload['tmp_name']) || !is_uploaded_file($upload['tmp_name'])))
+ {
+ $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
+ }
+
+ $tmp_file = $this->temporary_filepath($upload['tmp_name']);
+
+ if (!move_uploaded_file($upload['tmp_name'], $tmp_file))
+ {
+ $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
+ }
+
+ $out = fopen("{$file_path}.part", $chunk == 0 ? 'wb' : 'ab');
+ if (!$out)
+ {
+ $this->emit_error(102, 'PLUPLOAD_ERR_OUTPUT');
+ }
+
+ $in = fopen(($is_multipart) ? $tmp_file : 'php://input', 'rb');
+ if (!$in)
+ {
+ $this->emit_error(101, 'PLUPLOAD_ERR_INPUT');
+ }
+
+ while ($buf = fread($in, 4096))
+ {
+ fwrite($out, $buf);
+ }
+
+ fclose($in);
+ fclose($out);
+
+ if ($is_multipart)
+ {
+ unlink($tmp_file);
+ }
+ }
+
+ /**
+ * Creates the temporary directory if it does not already exist.
+ *
+ * @return null
+ */
+ protected function prepare_temporary_directory()
+ {
+ if (!file_exists($this->temporary_directory))
+ {
+ mkdir($this->temporary_directory);
+
+ copy(
+ $this->upload_directory . '/index.htm',
+ $this->temporary_directory . '/index.htm'
+ );
+ }
+ }
+}
diff --git a/phpBB/posting.php b/phpBB/posting.php
index 1609382551..396b320eac 100644
--- a/phpBB/posting.php
+++ b/phpBB/posting.php
@@ -452,6 +452,8 @@ if ($mode == 'edit')
$orig_poll_options_size = sizeof($post_data['poll_options']);
$message_parser = new parse_message();
+$plupload = $phpbb_container->get('plupload');
+$message_parser->set_plupload($plupload);
if (isset($post_data['post_text']))
{
@@ -1551,6 +1553,11 @@ if (($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_
// Show attachment box for adding attachments if true
$allowed = ($auth->acl_get('f_attach', $forum_id) && $auth->acl_get('u_attach') && $config['allow_attachments'] && $form_enctype);
+if ($allowed)
+{
+ $plupload->configure($cache, $template, $s_action, $forum_id);
+}
+
// Attachment entry
posting_gen_attachment_entry($attachment_data, $filename_data, $allowed);
diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html
index e26c94f367..b26a4c1610 100644
--- a/phpBB/styles/prosilver/template/overall_footer.html
+++ b/phpBB/styles/prosilver/template/overall_footer.html
@@ -65,6 +65,7 @@
<!-- EVENT overall_footer_after -->
{$SCRIPTS}
+<!-- IF S_PLUPLOAD --><!-- INCLUDE plupload.html --><!-- ENDIF -->
</body>
</html>
diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html
index 6ca5c86fa4..92baf6ee51 100644
--- a/phpBB/styles/prosilver/template/overall_header.html
+++ b/phpBB/styles/prosilver/template/overall_header.html
@@ -33,6 +33,11 @@
<link href="{T_THEME_PATH}/bidi.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen, projection" />
<!-- ENDIF -->
+<!-- IF S_PLUPLOAD -->
+ <link href="{T_ASSETS_PATH}/plupload/jquery.plupload.queue/css/jquery.plupload.queue.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen, projection" />
+ <link href="{T_THEME_PATH}/plupload.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen, projection" />
+<!-- ENDIF -->
+
<!--[if lte IE 8]>
<link href="{T_THEME_PATH}/tweaks.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen, projection" />
<![endif]-->
diff --git a/phpBB/styles/prosilver/template/plupload.html b/phpBB/styles/prosilver/template/plupload.html
new file mode 100644
index 0000000000..564c1b5c36
--- /dev/null
+++ b/phpBB/styles/prosilver/template/plupload.html
@@ -0,0 +1,48 @@
+<script type="text/javascript" src="{T_ASSETS_PATH}/plupload/plupload.js"></script>
+<script type="text/javascript" src="{T_ASSETS_PATH}/plupload/plupload.html5.js"></script>
+<script type="text/javascript" src="{T_ASSETS_PATH}/plupload/jquery.plupload.queue/jquery.plupload.queue.js"></script>
+<script type="text/javascript">
+//<![CDATA[
+phpbb.plupload = {
+ i18n: {
+ 'Select files': '{LA_PLUPLOAD_SELECT_FILES}',
+ 'Add files to the upload queue and click the start button.': '{LA_PLUPLOAD_ADD_FILES_TO_QUEUE}',
+ 'Filename': '{LA_PLUPLOAD_FILENAME}',
+ 'Status': '{LA_PLUPLOAD_STATUS}',
+ 'Size': '{LA_PLUPLOAD_SIZE}',
+ 'Add files': '{LA_PLUPLOAD_ADD_FILES}',
+ 'Stop current upload': '{LA_PLUPLOAD_STOP_CURRENT_UPLOAD}',
+ 'Start uploading queue': '{LA_PLUPLOAD_START_CURRENT_UPLOAD}',
+ 'Uploaded %d/%d files': '{LA_PLUPLOAD_UPLOADED}',
+ 'N/A': '{LA_PLUPLOAD_NOT_APPLICABLE}',
+ 'Drag files here.': '{LA_PLUPLOAD_DRAG}',
+ 'File extension error.': '{LA_PLUPLOAD_EXTENSION_ERROR}',
+ 'File size error.': '{LA_PLUPLOAD_SIZE_ERROR}',
+ 'Init error.': '{LA_PLUPLOAD_INIT_ERROR}',
+ 'HTTP Error.': '{LA_PLUPLOAD_HTTP_ERROR}',
+ 'Security error.': '{LA_PLUPLOAD_SECURITY_ERROR}',
+ 'Generic error.': '{LA_PLUPLOAD_GENERIC_ERROR}',
+ 'IO error.': '{LA_PLUPLOAD_IO_ERROR}',
+ 'Stop Upload': '{LA_PLUPLOAD_STOP_UPLOAD}',
+ 'Start upload': '{LA_PLUPLOAD_START_UPLOAD}',
+ '%d files queued': '{LA_PLUPLOAD_FILES_QUEUED}'
+ },
+ config: {
+ runtimes: 'html5',
+ url: '{S_PLUPLOAD_URL}',
+ max_file_size: '{FILESIZE}b',
+ chunk_size: '{CHUNK_SIZE}b',
+ unique_names: true,
+ filters: [{FILTERS}],
+ {S_RESIZE}
+ headers: {'X-PHPBB-USING-PLUPLOAD': '1'},
+ file_data_name: 'fileupload',
+ multipart_params: {'add_file': '{LA_ADD_FILE}'},
+ img_path: '{T_ASSETS_PATH}/plupload/jquery.plupload.queue/img',
+ element_hook: '#attach-panel .inner',
+ form_hook: '#postform'
+ }
+};
+//]]>
+</script>
+<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/plupload.js"></script>
diff --git a/phpBB/styles/prosilver/theme/plupload.css b/phpBB/styles/prosilver/theme/plupload.css
new file mode 100644
index 0000000000..16c26822b5
--- /dev/null
+++ b/phpBB/styles/prosilver/theme/plupload.css
@@ -0,0 +1,11 @@
+.plupload_filelist li.can_delete:hover {
+ cursor: pointer;
+}
+
+.plupload_filelist li.can_delete:hover a {
+ background: url('../../../assets/plupload/jquery.plupload.queue/img/delete.gif');
+}
+
+.plupload_filelist li a.working {
+ background: url('../../../assets/plupload/jquery.plupload.queue/img/throbber.gif');
+}