PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,152 @@
<?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\avatar\driver;
/**
* Base class for avatar drivers
*/
abstract class driver implements \phpbb\avatar\driver\driver_interface
{
/**
* Avatar driver name
* @var string
*/
protected $name;
/**
* Current board configuration
* @var \phpbb\config\config
*/
protected $config;
/** @var \FastImageSize\FastImageSize */
protected $imagesize;
/**
* Current $phpbb_root_path
* @var string
*/
protected $phpbb_root_path;
/**
* Current $php_ext
* @var string
*/
protected $php_ext;
/**
* Path Helper
* @var \phpbb\path_helper
*/
protected $path_helper;
/**
* Cache driver
* @var \phpbb\cache\driver\driver_interface
*/
protected $cache;
/**
* Array of allowed avatar image extensions
* Array is used for setting the allowed extensions in the fileupload class
* and as a base for a regex of allowed extensions, which will be formed by
* imploding the array with a "|".
*
* @var array
*/
protected $allowed_extensions = array(
'gif',
'jpg',
'jpeg',
'png',
);
/**
* Construct a driver object
*
* @param \phpbb\config\config $config phpBB configuration
* @param \FastImageSize\FastImageSize $imagesize FastImageSize class
* @param string $phpbb_root_path Path to the phpBB root
* @param string $php_ext PHP file extension
* @param \phpbb\path_helper $path_helper phpBB path helper
* @param \phpbb\cache\driver\driver_interface $cache Cache driver
*/
public function __construct(\phpbb\config\config $config, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null)
{
$this->config = $config;
$this->imagesize = $imagesize;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
$this->path_helper = $path_helper;
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function get_custom_html($user, $row, $alt = '')
{
return '';
}
/**
* {@inheritdoc}
*/
public function prepare_form_acp($user)
{
return array();
}
/**
* {@inheritdoc}
*/
public function delete($row)
{
return true;
}
/**
* {@inheritdoc}
*/
public function get_name()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function get_config_name()
{
return preg_replace('#^phpbb\\\\avatar\\\\driver\\\\#', '', get_class($this));
}
/**
* {@inheritdoc}
*/
public function get_acp_template_name()
{
return 'acp_avatar_options_' . $this->get_config_name() . '.html';
}
/**
* Sets the name of the driver.
*
* @param string $name Driver name
*/
public function set_name($name)
{
$this->name = $name;
}
}

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.
*
*/
namespace phpbb\avatar\driver;
/**
* Interface for avatar drivers
*/
interface driver_interface
{
/**
* Returns the name of the driver.
*
* @return string Name of driver.
*/
public function get_name();
/**
* Returns the config name of the driver. To be used in accessing the CONFIG variables.
*
* @return string Config name of driver.
*/
public function get_config_name();
/**
* Get the avatar url and dimensions
*
* @param array $row User data or group data that has been cleaned with
* \phpbb\avatar\manager::clean_row
* @return array Avatar data, must have keys src, width and height, e.g.
* ['src' => '', 'width' => 0, 'height' => 0]
*/
public function get_data($row);
/**
* Returns custom html if it is needed for displaying this avatar
*
* @param \phpbb\user $user phpBB user object
* @param array $row User data or group data that has been cleaned with
* \phpbb\avatar\manager::clean_row
* @param string $alt Alternate text for avatar image
*
* @return string HTML
*/
public function get_custom_html($user, $row, $alt = '');
/**
* Prepare form for changing the settings of this avatar
*
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user $user User object
* @param array $row User data or group data that has been cleaned with
* \phpbb\avatar\manager::clean_row
* @param array &$error Reference to an error array that is filled by this
* function. Key values can either be a string with a language key or
* an array that will be passed to vsprintf() with the language key in
* the first array key.
*
* @return bool True if form has been successfully prepared
*/
public function prepare_form($request, $template, $user, $row, &$error);
/**
* Prepare form for changing the acp settings of this avatar
*
* @param \phpbb\user $user phpBB user object
*
* @return array Array of configuration options as consumed by acp_board.
* The setting for enabling/disabling the avatar will be handled by
* the avatar manager.
*/
public function prepare_form_acp($user);
/**
* Process form data
*
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user $user User object
* @param array $row User data or group data that has been cleaned with
* \phpbb\avatar\manager::clean_row
* @param array &$error Reference to an error array that is filled by this
* function. Key values can either be a string with a language key or
* an array that will be passed to vsprintf() with the language key in
* the first array key.
*
* @return array Array containing the avatar data as follows:
* ['avatar'], ['avatar_width'], ['avatar_height']
*/
public function process_form($request, $template, $user, $row, &$error);
/**
* Delete avatar
*
* @param array $row User data or group data that has been cleaned with
* \phpbb\avatar\manager::clean_row
*
* @return bool True if avatar has been deleted or there is no need to delete,
* i.e. when the avatar is not hosted locally.
*/
public function delete($row);
/**
* Get the avatar driver's template name
*
* @return string Avatar driver's template name
*/
public function get_template_name();
/**
* Get the avatar driver's template name (ACP)
*
* @return string Avatar driver's template name
*/
public function get_acp_template_name();
}

View File

@ -0,0 +1,198 @@
<?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\avatar\driver;
/**
* Handles avatars hosted at gravatar.com
*/
class gravatar extends \phpbb\avatar\driver\driver
{
/**
* The URL for the gravatar service
*/
const GRAVATAR_URL = '//secure.gravatar.com/avatar/';
/**
* {@inheritdoc}
*/
public function get_data($row)
{
return array(
'src' => $row['avatar'],
'width' => $row['avatar_width'],
'height' => $row['avatar_height'],
);
}
/**
* {@inheritdoc}
*/
public function get_custom_html($user, $row, $alt = '')
{
return '<img src="' . $this->get_gravatar_url($row) . '" ' .
($row['avatar_width'] ? ('width="' . $row['avatar_width'] . '" ') : '') .
($row['avatar_height'] ? ('height="' . $row['avatar_height'] . '" ') : '') .
'alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
}
/**
* {@inheritdoc}
*/
public function prepare_form($request, $template, $user, $row, &$error)
{
$template->assign_vars(array(
'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', ''),
'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', ''),
'AVATAR_GRAVATAR_EMAIL' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar']) ? $row['avatar'] : '',
));
return true;
}
/**
* {@inheritdoc}
*/
public function process_form($request, $template, $user, $row, &$error)
{
$row['avatar'] = $request->variable('avatar_gravatar_email', '');
$row['avatar_width'] = $request->variable('avatar_gravatar_width', 0);
$row['avatar_height'] = $request->variable('avatar_gravatar_height', 0);
if (empty($row['avatar']))
{
return false;
}
if (!function_exists('validate_data'))
{
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
}
$validate_array = validate_data(
array(
'email' => $row['avatar'],
),
array(
'email' => array(
array('string', false, 6, 60),
array('email'),
),
)
);
$error = array_merge($error, $validate_array);
if (!empty($error))
{
return false;
}
// Get image dimensions if they are not set
if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
{
/**
* default to the minimum of the maximum allowed avatar size if the size
* is not or only partially entered
*/
$row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']);
$url = $this->get_gravatar_url($row);
if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false))
{
$error[] = 'UNABLE_GET_IMAGE_SIZE';
return false;
}
if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['width'] <= 0))
{
$error[] = 'AVATAR_NO_SIZE';
return false;
}
$row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data['width'];
$row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data['height'];
}
if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
{
$error[] = 'AVATAR_NO_SIZE';
return false;
}
if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
{
if ($row['avatar_width'] > $this->config['avatar_max_width'] || $row['avatar_height'] > $this->config['avatar_max_height'])
{
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
return false;
}
}
if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
{
if ($row['avatar_width'] < $this->config['avatar_min_width'] || $row['avatar_height'] < $this->config['avatar_min_height'])
{
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
return false;
}
}
return array(
'avatar' => $row['avatar'],
'avatar_width' => $row['avatar_width'],
'avatar_height' => $row['avatar_height'],
);
}
/**
* {@inheritdoc}
*/
public function get_template_name()
{
return 'ucp_avatar_options_gravatar.html';
}
/**
* Build gravatar URL for output on page
*
* @param array $row User data or group data that has been cleaned with
* \phpbb\avatar\manager::clean_row
* @return string Gravatar URL
*/
protected function get_gravatar_url($row)
{
global $phpbb_dispatcher;
$url = self::GRAVATAR_URL;
$url .= md5(strtolower(trim($row['avatar'])));
if ($row['avatar_width'] || $row['avatar_height'])
{
$url .= '?s=' . max($row['avatar_width'], $row['avatar_height']);
}
/**
* Modify gravatar url
*
* @event core.get_gravatar_url_after
* @var string row User data or group data
* @var string url Gravatar URL
* @since 3.1.7-RC1
*/
$vars = array('row', 'url');
extract($phpbb_dispatcher->trigger_event('core.get_gravatar_url_after', compact($vars)));
return $url;
}
}

View File

@ -0,0 +1,207 @@
<?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\avatar\driver;
/**
* Handles avatars selected from the board gallery
*/
class local extends \phpbb\avatar\driver\driver
{
/**
* {@inheritdoc}
*/
public function get_data($row)
{
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path();
return array(
'src' => $root_path . $this->config['avatar_gallery_path'] . '/' . $row['avatar'],
'width' => $row['avatar_width'],
'height' => $row['avatar_height'],
);
}
/**
* {@inheritdoc}
*/
public function prepare_form($request, $template, $user, $row, &$error)
{
$avatar_list = $this->get_avatar_list($user);
$category = $request->variable('avatar_local_cat', key($avatar_list));
foreach ($avatar_list as $cat => $null)
{
if (!empty($avatar_list[$cat]))
{
$template->assign_block_vars('avatar_local_cats', array(
'NAME' => $cat,
'SELECTED' => ($cat == $category),
));
}
if ($cat != $category)
{
unset($avatar_list[$cat]);
}
}
if (!empty($avatar_list[$category]))
{
$template->assign_vars(array(
'AVATAR_LOCAL_SHOW' => true,
));
$table_cols = isset($row['avatar_gallery_cols']) ? $row['avatar_gallery_cols'] : 4;
$row_count = $col_count = $avatar_pos = 0;
$avatar_count = count($avatar_list[$category]);
reset($avatar_list[$category]);
while ($avatar_pos < $avatar_count)
{
$img = current($avatar_list[$category]);
next($avatar_list[$category]);
if ($col_count == 0)
{
++$row_count;
$template->assign_block_vars('avatar_local_row', array(
));
}
$template->assign_block_vars('avatar_local_row.avatar_local_col', array(
'AVATAR_IMAGE' => $this->phpbb_root_path . $this->config['avatar_gallery_path'] . '/' . $img['file'],
'AVATAR_NAME' => $img['name'],
'AVATAR_FILE' => $img['filename'],
'CHECKED' => $img['file'] === $row['avatar'],
));
$template->assign_block_vars('avatar_local_row.avatar_local_option', array(
'AVATAR_FILE' => $img['filename'],
'S_OPTIONS_AVATAR' => $img['filename'],
'CHECKED' => $img['file'] === $row['avatar'],
));
$col_count = ($col_count + 1) % $table_cols;
++$avatar_pos;
}
}
return true;
}
/**
* {@inheritdoc}
*/
public function prepare_form_acp($user)
{
return array(
'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
);
}
/**
* {@inheritdoc}
*/
public function process_form($request, $template, $user, $row, &$error)
{
$avatar_list = $this->get_avatar_list($user);
$category = $request->variable('avatar_local_cat', '');
$file = $request->variable('avatar_local_file', '');
if (empty($category) || empty($file))
{
return false;
}
if (!isset($avatar_list[$category][urldecode($file)]))
{
$error[] = 'AVATAR_URL_NOT_FOUND';
return false;
}
return array(
'avatar' => ($category != $user->lang['NO_AVATAR_CATEGORY']) ? $category . '/' . $file : $file,
'avatar_width' => $avatar_list[$category][urldecode($file)]['width'],
'avatar_height' => $avatar_list[$category][urldecode($file)]['height'],
);
}
/**
* {@inheritdoc}
*/
public function get_template_name()
{
return 'ucp_avatar_options_local.html';
}
/**
* Get a list of avatars that are locally available
* Results get cached for 24 hours (86400 seconds)
*
* @param \phpbb\user $user User object
*
* @return array Array containing the locally available avatars
*/
protected function get_avatar_list($user)
{
$avatar_list = ($this->cache == null) ? false : $this->cache->get('_avatar_local_list_' . $user->data['user_lang']);
if ($avatar_list === false)
{
$avatar_list = array();
$path = $this->phpbb_root_path . $this->config['avatar_gallery_path'];
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $file_info)
{
$file_path = $file_info->getPath();
$image = $file_info->getFilename();
// Match all images in the gallery folder
if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image))
{
$dims = $this->imagesize->getImageSize($file_path . '/' . $image);
if ($dims === false)
{
$dims = array(0, 0);
}
else
{
$dims = array($dims['width'], $dims['height']);
}
$cat = ($path == $file_path) ? $user->lang['NO_AVATAR_CATEGORY'] : str_replace("$path/", '', $file_path);
$avatar_list[$cat][$image] = array(
'file' => ($cat != $user->lang['NO_AVATAR_CATEGORY']) ? str_replace('%2F', '/', rawurlencode($cat)) . '/' . rawurlencode($image) : rawurlencode($image),
'filename' => rawurlencode($image),
'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $image))),
'width' => $dims[0],
'height' => $dims[1],
);
}
}
ksort($avatar_list);
if ($this->cache != null)
{
$this->cache->put('_avatar_local_list_' . $user->data['user_lang'], $avatar_list, 86400);
}
}
return $avatar_list;
}
}

View File

@ -0,0 +1,216 @@
<?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\avatar\driver;
/**
* Handles avatars hosted remotely
*/
class remote extends \phpbb\avatar\driver\driver
{
/**
* {@inheritdoc}
*/
public function get_data($row)
{
return array(
'src' => $row['avatar'],
'width' => $row['avatar_width'],
'height' => $row['avatar_height'],
);
}
/**
* {@inheritdoc}
*/
public function prepare_form($request, $template, $user, $row, &$error)
{
$template->assign_vars(array(
'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', ''),
'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', ''),
'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '',
));
return true;
}
/**
* {@inheritdoc}
*/
public function process_form($request, $template, $user, $row, &$error)
{
$url = $request->variable('avatar_remote_url', '');
$width = $request->variable('avatar_remote_width', 0);
$height = $request->variable('avatar_remote_height', 0);
if (empty($url))
{
return false;
}
if (!preg_match('#^(http|https|ftp)://#i', $url))
{
$url = 'http://' . $url;
}
if (!function_exists('validate_data'))
{
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
}
$validate_array = validate_data(
array(
'url' => $url,
),
array(
'url' => array('string', true, 5, 255),
)
);
$error = array_merge($error, $validate_array);
if (!empty($error))
{
return false;
}
// Check if this url looks alright
// Do not allow specifying the port (see RFC 3986) or IP addresses
if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url) ||
preg_match('@^(http|https|ftp)://[^/:?#]+:[0-9]+[/:?#]@i', $url) ||
preg_match('#^(http|https|ftp)://(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])#i', $url) ||
preg_match('#^(http|https|ftp)://(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){0,5}(?:[\dA-F]{1,4}(?::[\dA-F]{1,4})?|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:)|(?:::))#i', $url))
{
$error[] = 'AVATAR_URL_INVALID';
return false;
}
// Get image dimensions
if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false))
{
$error[] = 'UNABLE_GET_IMAGE_SIZE';
return false;
}
if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['height'] <= 0))
{
$error[] = 'AVATAR_NO_SIZE';
return false;
}
$width = ($width && $height) ? $width : $image_data['width'];
$height = ($width && $height) ? $height : $image_data['height'];
if ($width <= 0 || $height <= 0)
{
$error[] = 'AVATAR_NO_SIZE';
return false;
}
$types = \phpbb\files\upload::image_types();
$extension = strtolower(\phpbb\files\filespec::get_extension($url));
// Check if this is actually an image
if ($file_stream = @fopen($url, 'r'))
{
// Timeout after 1 second
stream_set_timeout($file_stream, 1);
// read some data to ensure headers are present
fread($file_stream, 1024);
$meta = stream_get_meta_data($file_stream);
if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers']))
{
$headers = $meta['wrapper_data']['headers'];
}
else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data']))
{
$headers = $meta['wrapper_data'];
}
else
{
$headers = array();
}
foreach ($headers as $header)
{
$header = preg_split('/ /', $header, 2);
if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type')
{
if (strpos($header[1], 'image/') !== 0)
{
$error[] = 'AVATAR_URL_INVALID';
fclose($file_stream);
return false;
}
else
{
fclose($file_stream);
break;
}
}
}
}
else
{
$error[] = 'AVATAR_URL_INVALID';
return false;
}
if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']])))
{
if (!isset($types[$image_data['type']]))
{
$error[] = 'UNABLE_GET_IMAGE_SIZE';
}
else
{
$error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension);
}
return false;
}
if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
{
if ($width > $this->config['avatar_max_width'] || $height > $this->config['avatar_max_height'])
{
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
return false;
}
}
if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
{
if ($width < $this->config['avatar_min_width'] || $height < $this->config['avatar_min_height'])
{
$error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
return false;
}
}
return array(
'avatar' => $url,
'avatar_width' => $width,
'avatar_height' => $height,
);
}
/**
* {@inheritdoc}
*/
public function get_template_name()
{
return 'ucp_avatar_options_remote.html';
}
}

View File

@ -0,0 +1,330 @@
<?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\avatar\driver;
/**
* Handles avatars uploaded to the board
*/
class upload extends \phpbb\avatar\driver\driver
{
/**
* @var \phpbb\filesystem\filesystem_interface
*/
protected $filesystem;
/**
* @var \phpbb\event\dispatcher_interface
*/
protected $dispatcher;
/**
* @var \phpbb\files\factory
*/
protected $files_factory;
/**
* Construct a driver object
*
* @param \phpbb\config\config $config phpBB configuration
* @param string $phpbb_root_path Path to the phpBB root
* @param string $php_ext PHP file extension
* @param \phpbb\filesystem\filesystem_interface $filesystem phpBB filesystem helper
* @param \phpbb\path_helper $path_helper phpBB path helper
* @param \phpbb\event\dispatcher_interface $dispatcher phpBB Event dispatcher object
* @param \phpbb\files\factory $files_factory File classes factory
* @param \phpbb\cache\driver\driver_interface $cache Cache driver
*/
public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\path_helper $path_helper, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\files\factory $files_factory, \phpbb\cache\driver\driver_interface $cache = null)
{
$this->config = $config;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
$this->filesystem = $filesystem;
$this->path_helper = $path_helper;
$this->dispatcher = $dispatcher;
$this->files_factory = $files_factory;
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function get_data($row)
{
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path();
return array(
'src' => $root_path . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'],
'width' => $row['avatar_width'],
'height' => $row['avatar_height'],
);
}
/**
* {@inheritdoc}
*/
public function prepare_form($request, $template, $user, $row, &$error)
{
if (!$this->can_upload())
{
return false;
}
$template->assign_vars(array(
'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false,
'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
));
return true;
}
/**
* {@inheritdoc}
*/
public function process_form($request, $template, $user, $row, &$error)
{
if (!$this->can_upload())
{
return false;
}
/** @var \phpbb\files\upload $upload */
$upload = $this->files_factory->get('upload')
->set_error_prefix('AVATAR_')
->set_allowed_extensions($this->allowed_extensions)
->set_max_filesize($this->config['avatar_filesize'])
->set_allowed_dimensions(
$this->config['avatar_min_width'],
$this->config['avatar_min_height'],
$this->config['avatar_max_width'],
$this->config['avatar_max_height'])
->set_disallowed_content((isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
$url = $request->variable('avatar_upload_url', '');
$upload_file = $request->file('avatar_upload_file');
if (!empty($upload_file['name']))
{
$file = $upload->handle_upload('files.types.form', 'avatar_upload_file');
}
else if (!empty($this->config['allow_avatar_remote_upload']) && !empty($url))
{
if (!preg_match('#^(http|https|ftp)://#i', $url))
{
$url = 'http://' . $url;
}
if (!function_exists('validate_data'))
{
require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
}
$validate_array = validate_data(
array(
'url' => $url,
),
array(
'url' => array('string', true, 5, 255),
)
);
$error = array_merge($error, $validate_array);
if (!empty($error))
{
return false;
}
// Do not allow specifying the port (see RFC 3986) or IP addresses
// remote_upload() will do its own check for allowed filetypes
if (preg_match('@^(http|https|ftp)://[^/:?#]+:[0-9]+[/:?#]@i', $url) ||
preg_match('#^(http|https|ftp)://(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])#i', $url) ||
preg_match('#^(http|https|ftp)://(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){0,5}(?:[\dA-F]{1,4}(?::[\dA-F]{1,4})?|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:)|(?:::))#i', $url))
{
$error[] = 'AVATAR_URL_INVALID';
return false;
}
$file = $upload->handle_upload('files.types.remote', $url);
}
else
{
return false;
}
$prefix = $this->config['avatar_salt'] . '_';
$file->clean_filename('avatar', $prefix, $row['id']);
// If there was an error during upload, then abort operation
if (count($file->error))
{
$file->remove();
$error = $file->error;
return false;
}
// Calculate new destination
$destination = $this->config['avatar_path'];
// Adjust destination path (no trailing slash)
if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
{
$destination = substr($destination, 0, -1);
}
$destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
{
$destination = '';
}
$filedata = array(
'filename' => $file->get('filename'),
'filesize' => $file->get('filesize'),
'mimetype' => $file->get('mimetype'),
'extension' => $file->get('extension'),
'physical_filename' => $file->get('realname'),
'real_filename' => $file->get('uploadname'),
);
/**
* Before moving new file in place (and eventually overwriting the existing avatar with the newly uploaded avatar)
*
* @event core.avatar_driver_upload_move_file_before
* @var array filedata Array containing uploaded file data
* @var \phpbb\files\filespec file Instance of filespec class
* @var string destination Destination directory where the file is going to be moved
* @var string prefix Prefix for the avatar filename
* @var array row Array with avatar row data
* @var array error Array of errors, if filled in by this event file will not be moved
* @since 3.1.6-RC1
* @changed 3.1.9-RC1 Added filedata
* @changed 3.2.3-RC1 Added file
*/
$vars = array(
'filedata',
'file',
'destination',
'prefix',
'row',
'error',
);
extract($this->dispatcher->trigger_event('core.avatar_driver_upload_move_file_before', compact($vars)));
unset($filedata);
if (!count($error))
{
// Move file and overwrite any existing image
$file->move_file($destination, true);
}
// If there was an error during move, then clean up leftovers
$error = array_merge($error, $file->error);
if (count($error))
{
$file->remove();
return false;
}
// Delete current avatar if not overwritten
$ext = substr(strrchr($row['avatar'], '.'), 1);
if ($ext && $ext !== $file->get('extension'))
{
$this->delete($row);
}
return array(
'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'),
'avatar_width' => $file->get('width'),
'avatar_height' => $file->get('height'),
);
}
/**
* {@inheritdoc}
*/
public function prepare_form_acp($user)
{
return array(
'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
);
}
/**
* {@inheritdoc}
*/
public function delete($row)
{
$error = array();
$destination = $this->config['avatar_path'];
$prefix = $this->config['avatar_salt'] . '_';
$ext = substr(strrchr($row['avatar'], '.'), 1);
$filename = $this->phpbb_root_path . $destination . '/' . $prefix . $row['id'] . '.' . $ext;
/**
* Before deleting an existing avatar
*
* @event core.avatar_driver_upload_delete_before
* @var string destination Destination directory where the file is going to be deleted
* @var string prefix Prefix for the avatar filename
* @var array row Array with avatar row data
* @var array error Array of errors, if filled in by this event file will not be deleted
* @since 3.1.6-RC1
*/
$vars = array(
'destination',
'prefix',
'row',
'error',
);
extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars)));
if (!count($error) && $this->filesystem->exists($filename))
{
try
{
$this->filesystem->remove($filename);
return true;
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
// Fail is covered by return statement below
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function get_template_name()
{
return 'ucp_avatar_options_upload.html';
}
/**
* Check if user is able to upload an avatar
*
* @return bool True if user can upload, false if not
*/
protected function can_upload()
{
return ($this->filesystem->exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
}
}

View File

@ -0,0 +1,375 @@
<?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\avatar;
class manager
{
/**
* phpBB configuration
* @var \phpbb\config\config
*/
protected $config;
/**
* phpBB event dispatcher
* @var \phpbb\event\dispatcher_interface
*/
protected $phpbb_dispatcher;
/**
* Array that contains a list of enabled drivers
* @var array
*/
static protected $enabled_drivers = false;
/**
* Array that contains all available avatar drivers which are passed via the
* service container
* @var array
*/
protected $avatar_drivers;
/**
* Default avatar data row
* @var array
*/
static protected $default_row = array(
'avatar' => '',
'avatar_type' => '',
'avatar_width' => 0,
'avatar_height' => 0,
);
/**
* Construct an avatar manager object
*
* @param \phpbb\config\config $config phpBB configuration
* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher phpBB event dispatcher
* @param array $avatar_drivers Avatar drivers passed via the service container
*/
public function __construct(\phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, $avatar_drivers)
{
$this->config = $config;
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->register_avatar_drivers($avatar_drivers);
}
/**
* Register avatar drivers
*
* @param array $avatar_drivers Service collection of avatar drivers
*/
protected function register_avatar_drivers($avatar_drivers)
{
if (!empty($avatar_drivers))
{
foreach ($avatar_drivers as $driver)
{
$this->avatar_drivers[$driver->get_name()] = $driver;
}
}
}
/**
* Get the driver object specified by the avatar type
*
* @param string $avatar_type Avatar type; by default an avatar's service container name
* @param bool $load_enabled Load only enabled avatars
*
* @return object Avatar driver object
*/
public function get_driver($avatar_type, $load_enabled = true)
{
if (self::$enabled_drivers === false)
{
$this->load_enabled_drivers();
}
$avatar_drivers = ($load_enabled) ? self::$enabled_drivers : $this->get_all_drivers();
// Legacy stuff...
switch ($avatar_type)
{
case AVATAR_GALLERY:
$avatar_type = 'avatar.driver.local';
break;
case AVATAR_UPLOAD:
$avatar_type = 'avatar.driver.upload';
break;
case AVATAR_REMOTE:
$avatar_type = 'avatar.driver.remote';
break;
}
if (!isset($avatar_drivers[$avatar_type]))
{
return null;
}
/*
* There is no need to handle invalid avatar types as the following code
* will cause a ServiceNotFoundException if the type does not exist
*/
$driver = $this->avatar_drivers[$avatar_type];
return $driver;
}
/**
* Load the list of enabled drivers
* This is executed once and fills self::$enabled_drivers
*/
protected function load_enabled_drivers()
{
if (!empty($this->avatar_drivers))
{
self::$enabled_drivers = array();
foreach ($this->avatar_drivers as $driver)
{
if ($this->is_enabled($driver))
{
self::$enabled_drivers[$driver->get_name()] = $driver->get_name();
}
}
asort(self::$enabled_drivers);
}
}
/**
* Get a list of all avatar drivers
*
* As this function will only be called in the ACP avatar settings page, it
* doesn't make much sense to cache the list of all avatar drivers like the
* list of the enabled drivers.
*
* @return array Array containing a list of all avatar drivers
*/
public function get_all_drivers()
{
$drivers = array();
if (!empty($this->avatar_drivers))
{
foreach ($this->avatar_drivers as $driver)
{
$drivers[$driver->get_name()] = $driver->get_name();
}
asort($drivers);
}
return $drivers;
}
/**
* Get a list of enabled avatar drivers
*
* @return array Array containing a list of the enabled avatar drivers
*/
public function get_enabled_drivers()
{
if (self::$enabled_drivers === false)
{
$this->load_enabled_drivers();
}
return self::$enabled_drivers;
}
/**
* Strip out user_, group_, or other prefixes from array keys
*
* @param array $row User data or group data
* @param string $prefix Prefix of data keys (e.g. user), should not include the trailing underscore
*
* @return array User or group data with keys that have been
* stripped from the preceding "user_" or "group_"
* Also the group id is prefixed with g, when the prefix group is removed.
*/
static public function clean_row($row, $prefix = '')
{
// Upon creation of a user/group $row might be empty
if (empty($row))
{
return self::$default_row;
}
$output = array();
foreach ($row as $key => $value)
{
$key = preg_replace("#^(?:{$prefix}_)#", '', $key);
$output[$key] = $value;
}
if ($prefix === 'group' && isset($output['id']))
{
$output['id'] = 'g' . $output['id'];
}
return $output;
}
/**
* Clean driver names that are returned from template files
* Underscores are replaced with dots
*
* @param string $name Driver name
*
* @return string Cleaned driver name
*/
static public function clean_driver_name($name)
{
return str_replace(array('\\', '_'), '.', $name);
}
/**
* Prepare driver names for use in template files
* Dots are replaced with underscores
*
* @param string $name Clean driver name
*
* @return string Prepared driver name
*/
static public function prepare_driver_name($name)
{
return str_replace('.', '_', $name);
}
/**
* Check if avatar is enabled
*
* @param object $driver Avatar driver object
*
* @return bool True if avatar is enabled, false if it's disabled
*/
public function is_enabled($driver)
{
$config_name = $driver->get_config_name();
return $this->config["allow_avatar_{$config_name}"];
}
/**
* Get the settings array for enabling/disabling an avatar driver
*
* @param object $driver Avatar driver object
*
* @return array Array of configuration options as consumed by acp_board
*/
public function get_avatar_settings($driver)
{
$config_name = $driver->get_config_name();
return array(
'allow_avatar_' . $config_name => array('lang' => 'ALLOW_' . strtoupper(str_replace('\\', '_', $config_name)), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
);
}
/**
* Replace "error" strings with their real, localized form
*
* @param \phpbb\user phpBB User object
* @param array $error Array containing error strings
* Key values can either be a string with a language key or an array
* that will be passed to vsprintf() with the language key in the
* first array key.
*
* @return array Array containing the localized error strings
*/
public function localize_errors(\phpbb\user $user, $error)
{
foreach ($error as $key => $lang)
{
if (is_array($lang))
{
$lang_key = array_shift($lang);
$error[$key] = vsprintf($user->lang($lang_key), $lang);
}
else
{
$error[$key] = $user->lang("$lang");
}
}
return $error;
}
/**
* Handle deleting avatars
*
* @param \phpbb\db\driver\driver_interface $db phpBB dbal
* @param \phpbb\user $user phpBB user object
* @param array $avatar_data Cleaned user data containing the user's
* avatar data
* @param string $table Database table from which the avatar should be deleted
* @param string $prefix Prefix of user data columns in database
* @return null
*/
public function handle_avatar_delete(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $avatar_data, $table, $prefix)
{
if ($driver = $this->get_driver($avatar_data['avatar_type']))
{
$driver->delete($avatar_data);
}
$result = $this->prefix_avatar_columns($prefix, self::$default_row);
$sql = 'UPDATE ' . $table . '
SET ' . $db->sql_build_array('UPDATE', $result) . '
WHERE ' . $prefix . 'id = ' . (int) $avatar_data['id'];
$db->sql_query($sql);
// Make sure we also delete this avatar from the users
if ($prefix === 'group_')
{
$result = $this->prefix_avatar_columns('user_', self::$default_row);
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $result) . "
WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'";
$db->sql_query($sql);
}
/**
* Event is triggered after user avatar has been deleted
*
* @event core.avatar_manager_avatar_delete_after
* @var \phpbb\user user phpBB user object
* @var array avatar_data Normalised avatar-related user data
* @var string table Table to delete avatar from
* @var string prefix Column prefix to delete avatar from
* @since 3.2.4-RC1
*/
$vars = array('user', 'avatar_data', 'table', 'prefix');
extract($this->phpbb_dispatcher->trigger_event('core.avatar_manager_avatar_delete_after', compact($vars)));
}
/**
* Prefix avatar columns
*
* @param string $prefix Column prefix
* @param array $data Column data
*
* @return array Column data with prefixed column names
*/
public function prefix_avatar_columns($prefix, $data)
{
foreach ($data as $key => $value)
{
$data[$prefix . $key] = $value;
unset($data[$key]);
}
return $data;
}
}