1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-08-13 12:14:06 +02:00

[ticket/15769] Crop avatars on upload

PHPBB3-15769
This commit is contained in:
mrgoldy
2020-05-10 00:30:30 +02:00
committed by Marc Alexander
parent eb1edd12a1
commit 4d860bf967
17 changed files with 4693 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ use phpbb\config\config;
use phpbb\controller\helper;
use phpbb\event\dispatcher_interface;
use phpbb\files\factory;
use phpbb\image\image_cropper;
use phpbb\path_helper;
use phpbb\storage\exception\exception as storage_exception;
use phpbb\storage\storage;
@@ -100,10 +101,15 @@ class upload extends \phpbb\avatar\driver\driver
return false;
}
$template->assign_vars(array(
'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
$use_board = defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH;
$web_path = $use_board ? generate_board_url() . '/' : $this->path_helper->get_web_root_path();
$template->assign_vars([
'AVATAR_ALLOWED_EXTENSIONS' => implode(',', preg_replace('/^/', '.', $this->allowed_extensions)),
));
'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
'S_CROPPING_AVAILABLE' => image_cropper::is_available(),
'T_ASSETS_PATH' => $web_path . '/assets',
]);
return true;
}
@@ -137,6 +143,7 @@ class upload extends \phpbb\avatar\driver\driver
return false;
}
/** @var \phpbb\files\filespec_storage $file */
$file = $upload->handle_upload('files.types.form_storage', 'avatar_upload_file');
$prefix = $this->config['avatar_salt'] . '_';
@@ -150,6 +157,14 @@ class upload extends \phpbb\avatar\driver\driver
return false;
}
// Lets try to crop the avatar
$data = $request->variable('avatar_cropper_data', '', true);
if (!empty($upload_file['name']) && $data && image_cropper::is_file_supported($file))
{
image_cropper::crop_file_by_data($file, json_decode(htmlspecialchars_decode($data, ENT_COMPAT), true));
}
$filedata = array(
'filename' => $file->get('filename'),
'filesize' => $file->get('filesize'),

View File

@@ -0,0 +1,261 @@
<?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\image;
use phpbb\files\filespec_storage;
/**
* Image cropper for locally uploaded files.
*
* Static class.
* Requires the "ext-gd" PHP extension.
*/
class image_cropper
{
/**
* Check if any image cropping can be done.
*
* @return bool Whether image cropping is available
* @static
*/
public static function is_available(): bool
{
return extension_loaded('gd');
}
/**
* Check if the file extension is supported.
*
* This checks whether the create and save functions for a file extension exists.
* For example the 'imagecreatefrompng' and 'imagepng' functions for a PNG extension.
* Please note that the JPG extension should be in the JPEG form.
* Use @see image_cropper::get_file_extension() to ensure the correct form.
*
* @param string $extension The file extension
* @return bool Whether the file extension is supported or not
* @static
*/
public static function is_extension_supported(string $extension): bool
{
return function_exists(self::get_create_function($extension))
&& function_exists(self::get_save_function($extension));
}
/**
* Check if the file is supported.
*
* Retrieves the file extension from the file,
* and checks if the file extension is supported.
*
* @param filespec_storage $file The locally uploaded file
* @return bool Whether the file is supported or not
* @static
*/
public static function is_file_supported(filespec_storage $file): bool
{
return self::is_extension_supported(self::get_file_extension($file));
}
/**
* Get the file extension.
*
* This ensures that the JPG extension is in the JPEG form.
* Because this form is needed for the create and save functions.
*
* @param filespec_storage $file The locally uploaded file
* @return string The file extension
* @static
*/
public static function get_file_extension(filespec_storage $file): string
{
if ('jpg' === ($extension = strtolower($file->get('extension'))))
{
return 'jpeg';
}
return $extension;
}
/**
* Get the image create function.
*
* @param string $extension The file extension
* @return callable The callable create function
* @static
*/
public static function get_create_function(string $extension): callable
{
return 'imagecreatefrom' . strtolower($extension);
}
/**
* Get the image save function.
*
* @param string $extension The file extension
* @return callable The callable save function
* @static
*/
public static function get_save_function(string $extension): callable
{
return 'image' . strtolower($extension);
}
/**
* Crop the file by specified (cropper) data.
*
* $data = [
* 'x' => (int) Image X offset Required
* 'y' => (int) Image Y offset Required
* 'width' => (int) New image width Required
* 'height' => (int) New image height Required
* 'rotate' => (float) -360.00 to 360.00 Optional
* 'scaleX' => (int) -1 Optional
* 'scaleY' => (int) -1 Optional
* ];
*
* @param filespec_storage $file The locally uploaded file
* @param array $data The (cropper) data
* @return bool Whether the image was successfully saved or not
* @static
*/
public static function crop_file_by_data(filespec_storage $file, array $data): bool
{
$image = self::create_image($file->get('filename'), self::get_file_extension($file));
$rotate = isset($data['rotate']) && (float) $data['rotate'] !== 0;
$flip_x = isset($data['scaleX']) && (int) $data['scaleX'] === -1;
$flip_y = isset($data['scaleY']) && (int) $data['scaleY'] === -1;
if ($rotate)
{
$image = self::rotate_image($image, (float) $data['rotate']);
}
if ($flip_x || $flip_y)
{
$image = self::flip_image($image, $flip_x, $flip_y);
}
$image = self::crop_image_by_array($image, $data);
return self::save_image($file->get('filename'), self::get_file_extension($file), $image);
}
/**
* Create an image.
*
* @param string $file The file path
* @param string $extension The file extension
* @return resource The image resource
* @static
*/
public static function create_image(string $file, string $extension)
{
return self::get_create_function($extension)($file);
}
/**
* Save an image.
*
* @param string $file The file path
* @param string $extension The file extension
* @param resource $image The image resource
* @return bool Whether the image was successfully saved or not
* @static
*/
public static function save_image(string $file, string $extension, $image): bool
{
return self::get_save_function($extension)($image, $file);
}
/**
* Rotate an image.
*
* @param resource $image The image resource
* @param float $degrees The amount of degrees to rotate (-360.00 to 360.00)
* @param int $bg_color The background colour for any part that is left empty
* @return resource The new image resource
* @static
*/
public static function rotate_image($image, float $degrees, int $bg_color = 0)
{
if (false !== ($new_image = imagerotate($image, $degrees, $bg_color)))
{
return $new_image;
}
return $image;
}
/**
* Flip an image.
*
* @param resource $image The image resource
* @param bool $flip_horizontally Whether the image should be flipped horizontally or not
* @param bool $flip_vertically Whether the image should be flipped vertically or not
* @return resource The new image resource
* @static
*/
public static function flip_image($image, bool $flip_horizontally, bool $flip_vertically = false)
{
$flip_mode = 0;
$flip_mode |= $flip_horizontally ? IMG_FLIP_HORIZONTAL : 0;
$flip_mode |= $flip_vertically ? IMG_FLIP_VERTICAL : 0;
if ($flip_mode !== 0)
{
imageflip($image, $flip_mode);
}
return $image;
}
/**
* Crop an image by a data array.
*
* This ensures the correct types (integer) are set.
*
* @param resource $image The image resource
* @param array $data The data array
* @return resource The new image resource
* @static
*/
public static function crop_image_by_array($image, array $data)
{
return self::crop_image($image, (int) $data['x'], (int) $data['y'], (int) $data['width'], (int) $data['height']);
}
/**
* Crop an image.
*
* @param resource $image The image resource
* @param int $x The new image's X offset
* @param int $y The new image's Y offset
* @param int $width The new image's width
* @param int $height The new image's height
* @return resource The new image resource
* @static
*/
public static function crop_image($image, int $x, int $y, int $width, int $height)
{
$new_image = imagecrop($image, [
'x' => $x,
'y' => $y,
'width' => $width,
'height' => $height,
]);
return false !== $new_image ? $new_image : $image;
}
}