Add display picture support and error code refactor
This commit is contained in:
parent
85bdff7d3c
commit
738f8a455c
7 changed files with 523 additions and 286 deletions
|
@ -37,7 +37,7 @@
|
||||||
*/
|
*/
|
||||||
public function getUserDisplayImagesPath(): string
|
public function getUserDisplayImagesPath(): string
|
||||||
{
|
{
|
||||||
return $this->userDisplayImagesPath;
|
return $this->path . DIRECTORY_SEPARATOR . $this->userDisplayImagesPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Socialbox\Classes\StandardMethods;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Socialbox\Abstracts\Method;
|
||||||
|
use Socialbox\Classes\Configuration;
|
||||||
|
use Socialbox\Classes\Utilities;
|
||||||
|
use Socialbox\Enums\Flags\SessionFlags;
|
||||||
|
use Socialbox\Enums\StandardError;
|
||||||
|
use Socialbox\Exceptions\StandardException;
|
||||||
|
use Socialbox\Interfaces\SerializableInterface;
|
||||||
|
use Socialbox\Managers\RegisteredPeerManager;
|
||||||
|
use Socialbox\Managers\SessionManager;
|
||||||
|
use Socialbox\Objects\ClientRequest;
|
||||||
|
use Socialbox\Objects\RpcRequest;
|
||||||
|
|
||||||
|
class SettingsSetDisplayPicture extends Method
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function execute(ClientRequest $request, RpcRequest $rpcRequest): ?SerializableInterface
|
||||||
|
{
|
||||||
|
if(!$rpcRequest->containsParameter('image'))
|
||||||
|
{
|
||||||
|
return $rpcRequest->produceError(StandardError::RPC_INVALID_ARGUMENTS, "Missing 'image' parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($rpcRequest->getParameter('image')) > Configuration::getStorageConfiguration()->getUserDisplayImagesMaxSize())
|
||||||
|
{
|
||||||
|
return $rpcRequest->produceError(StandardError::RPC_INVALID_ARGUMENTS, "Image size exceeds the maximum allowed size of " . Configuration::getStorageConfiguration()->getUserDisplayImagesMaxSize() . " bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$decodedImage = base64_decode($rpcRequest->getParameter('image'));
|
||||||
|
|
||||||
|
if($decodedImage === false)
|
||||||
|
{
|
||||||
|
return $rpcRequest->produceError(StandardError::BAD_REQUEST, "Failed to decode JPEG image base64 data");
|
||||||
|
}
|
||||||
|
|
||||||
|
$sanitizedImage = Utilities::resizeImage(Utilities::sanitizeJpeg($decodedImage), 126, 126);
|
||||||
|
}
|
||||||
|
catch(Exception $e)
|
||||||
|
{
|
||||||
|
throw new StandardException('Failed to process JPEG image: ' . $e->getMessage(), StandardError::BAD_REQUEST, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Set the password
|
||||||
|
RegisteredPeerManager::updateDisplayPicture($request->getPeer(), $sanitizedImage);
|
||||||
|
|
||||||
|
// Remove the SET_DISPLAY_PICTURE flag
|
||||||
|
SessionManager::removeFlags($request->getSessionUuid(), [SessionFlags::SET_DISPLAY_PICTURE]);
|
||||||
|
|
||||||
|
// Check & update the session flow
|
||||||
|
SessionManager::updateFlow($request->getSession());
|
||||||
|
}
|
||||||
|
catch(Exception $e)
|
||||||
|
{
|
||||||
|
throw new StandardException('Failed to update display picture: ' . $e->getMessage(), StandardError::INTERNAL_SERVER_ERROR, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rpcRequest->produceResponse(true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,287 +1,367 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Socialbox\Classes;
|
namespace Socialbox\Classes;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use Exception;
|
||||||
use JsonException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use JsonException;
|
||||||
use Socialbox\Enums\StandardHeaders;
|
use RuntimeException;
|
||||||
use Throwable;
|
use Socialbox\Enums\StandardHeaders;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class Utilities
|
class Utilities
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Decodes a JSON string into an associative array, throws an exception if the JSON is invalid
|
|
||||||
*
|
|
||||||
* @param string $json The JSON string to decode
|
|
||||||
* @return array The decoded associative array
|
|
||||||
* @throws InvalidArgumentException If the JSON is invalid
|
|
||||||
*/
|
|
||||||
public static function jsonDecode(string $json): array
|
|
||||||
{
|
{
|
||||||
$decoded = json_decode($json, true);
|
/**
|
||||||
|
* Decodes a JSON string into an associative array, throws an exception if the JSON is invalid
|
||||||
if (json_last_error() !== JSON_ERROR_NONE)
|
*
|
||||||
|
* @param string $json The JSON string to decode
|
||||||
|
* @return array The decoded associative array
|
||||||
|
* @throws InvalidArgumentException If the JSON is invalid
|
||||||
|
*/
|
||||||
|
public static function jsonDecode(string $json): array
|
||||||
{
|
{
|
||||||
throw match (json_last_error())
|
$decoded = json_decode($json, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE)
|
||||||
{
|
{
|
||||||
JSON_ERROR_DEPTH => new InvalidArgumentException("JSON decoding failed: Maximum stack depth exceeded"),
|
throw match (json_last_error())
|
||||||
JSON_ERROR_STATE_MISMATCH => new InvalidArgumentException("JSON decoding failed: Underflow or the modes mismatch"),
|
|
||||||
JSON_ERROR_CTRL_CHAR => new InvalidArgumentException("JSON decoding failed: Unexpected control character found"),
|
|
||||||
JSON_ERROR_SYNTAX => new InvalidArgumentException("JSON decoding failed: Syntax error, malformed JSON"),
|
|
||||||
JSON_ERROR_UTF8 => new InvalidArgumentException("JSON decoding failed: Malformed UTF-8 characters, possibly incorrectly encoded"),
|
|
||||||
default => new InvalidArgumentException("JSON decoding failed: Unknown error"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return $decoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function jsonEncode(mixed $data): string
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
|
|
||||||
}
|
|
||||||
catch(JsonException $e)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException("Failed to encode json input", $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes the given data in Base64.
|
|
||||||
*
|
|
||||||
* @param string $data The data to be encoded.
|
|
||||||
* @return string The Base64 encoded string.
|
|
||||||
* @throws InvalidArgumentException if the encoding fails.
|
|
||||||
*/
|
|
||||||
public static function base64encode(string $data): string
|
|
||||||
{
|
|
||||||
$encoded = base64_encode($data);
|
|
||||||
|
|
||||||
if (!$encoded)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException('Failed to encode data in Base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $encoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes a Base64 encoded string.
|
|
||||||
*
|
|
||||||
* @param string $data The Base64 encoded data to be decoded.
|
|
||||||
* @return string The decoded data.
|
|
||||||
* @throws InvalidArgumentException If decoding fails.
|
|
||||||
*/
|
|
||||||
public static function base64decode(string $data): string
|
|
||||||
{
|
|
||||||
$decoded = base64_decode($data, true);
|
|
||||||
|
|
||||||
if ($decoded === false)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException('Failed to decode data from Base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $decoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request headers as an associative array
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getRequestHeaders(): array
|
|
||||||
{
|
|
||||||
// Check if function getallheaders() exists
|
|
||||||
if (function_exists('getallheaders'))
|
|
||||||
{
|
|
||||||
$headers = getallheaders();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Fallback for servers where getallheaders() is not available
|
|
||||||
$headers = [];
|
|
||||||
foreach ($_SERVER as $key => $value)
|
|
||||||
{
|
|
||||||
if (str_starts_with($key, 'HTTP_'))
|
|
||||||
{
|
{
|
||||||
// Convert header names to the normal HTTP format
|
JSON_ERROR_DEPTH => new InvalidArgumentException("JSON decoding failed: Maximum stack depth exceeded"),
|
||||||
$headers[str_replace('_', '-', strtolower(substr($key, 5)))] = $value;
|
JSON_ERROR_STATE_MISMATCH => new InvalidArgumentException("JSON decoding failed: Underflow or the modes mismatch"),
|
||||||
|
JSON_ERROR_CTRL_CHAR => new InvalidArgumentException("JSON decoding failed: Unexpected control character found"),
|
||||||
|
JSON_ERROR_SYNTAX => new InvalidArgumentException("JSON decoding failed: Syntax error, malformed JSON"),
|
||||||
|
JSON_ERROR_UTF8 => new InvalidArgumentException("JSON decoding failed: Malformed UTF-8 characters, possibly incorrectly encoded"),
|
||||||
|
default => new InvalidArgumentException("JSON decoding failed: Unknown error"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function jsonEncode(mixed $data): string
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
|
||||||
|
}
|
||||||
|
catch(JsonException $e)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException("Failed to encode json input", $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the given data in Base64.
|
||||||
|
*
|
||||||
|
* @param string $data The data to be encoded.
|
||||||
|
* @return string The Base64 encoded string.
|
||||||
|
* @throws InvalidArgumentException if the encoding fails.
|
||||||
|
*/
|
||||||
|
public static function base64encode(string $data): string
|
||||||
|
{
|
||||||
|
$encoded = base64_encode($data);
|
||||||
|
|
||||||
|
if (!$encoded)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('Failed to encode data in Base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a Base64 encoded string.
|
||||||
|
*
|
||||||
|
* @param string $data The Base64 encoded data to be decoded.
|
||||||
|
* @return string The decoded data.
|
||||||
|
* @throws InvalidArgumentException If decoding fails.
|
||||||
|
*/
|
||||||
|
public static function base64decode(string $data): string
|
||||||
|
{
|
||||||
|
$decoded = base64_decode($data, true);
|
||||||
|
|
||||||
|
if ($decoded === false)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('Failed to decode data from Base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the request headers as an associative array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getRequestHeaders(): array
|
||||||
|
{
|
||||||
|
// Check if function getallheaders() exists
|
||||||
|
if (function_exists('getallheaders'))
|
||||||
|
{
|
||||||
|
$headers = getallheaders();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback for servers where getallheaders() is not available
|
||||||
|
$headers = [];
|
||||||
|
foreach ($_SERVER as $key => $value)
|
||||||
|
{
|
||||||
|
if (str_starts_with($key, 'HTTP_'))
|
||||||
|
{
|
||||||
|
// Convert header names to the normal HTTP format
|
||||||
|
$headers[str_replace('_', '-', strtolower(substr($key, 5)))] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($headers === false)
|
||||||
|
{
|
||||||
|
throw new RuntimeException('Failed to get request headers');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Throwable object into a formatted string.
|
||||||
|
*
|
||||||
|
* @param Throwable $e The throwable to be converted into a string.
|
||||||
|
* @return string The formatted string representation of the throwable, including the exception class, message, file, line, and stack trace.
|
||||||
|
*/
|
||||||
|
public static function throwableToString(Throwable $e): string
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
"%s: %s in %s:%d\nStack trace:\n%s",
|
||||||
|
get_class($e),
|
||||||
|
$e->getMessage(),
|
||||||
|
$e->getFile(),
|
||||||
|
$e->getLine(),
|
||||||
|
$e->getTraceAsString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a formatted header string.
|
||||||
|
*
|
||||||
|
* @param StandardHeaders $header The standard header object.
|
||||||
|
* @param string $value The header value to be associated with the standard header.
|
||||||
|
* @return string The formatted header string.
|
||||||
|
*/
|
||||||
|
public static function generateHeader(StandardHeaders $header, string $value): string
|
||||||
|
{
|
||||||
|
return $header->value . ': ' . $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random string of specified length using the provided character set.
|
||||||
|
*
|
||||||
|
* @param int $int The length of the random string to be generated.
|
||||||
|
* @param string $string The character set to use for generating the random string.
|
||||||
|
* @return string The generated random string.
|
||||||
|
*/
|
||||||
|
public static function randomString(int $int, string $string): string
|
||||||
|
{
|
||||||
|
$characters = str_split($string);
|
||||||
|
$randomString = '';
|
||||||
|
|
||||||
|
for ($i = 0; $i < $int; $i++)
|
||||||
|
{
|
||||||
|
$randomString .= $characters[array_rand($characters)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $randomString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random CRC32 hash.
|
||||||
|
*
|
||||||
|
* @return string The generated CRC32 hash as a string.
|
||||||
|
*/
|
||||||
|
public static function randomCrc32(): string
|
||||||
|
{
|
||||||
|
return hash('crc32b', uniqid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizes a file name by removing any characters that are not alphanumeric, hyphen, or underscore.
|
||||||
|
*
|
||||||
|
* @param string $name The file name to be sanitized.
|
||||||
|
* @return string The sanitized file name.
|
||||||
|
*/
|
||||||
|
public static function sanitizeFileName(string $name): string
|
||||||
|
{
|
||||||
|
return preg_replace('/[^a-zA-Z0-9-_]/', '', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizes a Base64-encoded JPEG image by validating its data, decoding it,
|
||||||
|
* and re-encoding it to ensure it conforms to the JPEG format.
|
||||||
|
*
|
||||||
|
* @param string $data The Base64-encoded string potentially containing a JPEG image,
|
||||||
|
* optionally prefixed with "data:image/...;base64,".
|
||||||
|
* @return string A sanitized and re-encoded JPEG image as a binary string.
|
||||||
|
* @throws InvalidArgumentException If the input data is not valid Base64,
|
||||||
|
* does not represent an image, or is not in the JPEG format.
|
||||||
|
*/
|
||||||
|
public static function sanitizeJpeg(string $data): string
|
||||||
|
{
|
||||||
|
// Temporarily load the decoded data as an image
|
||||||
|
$tempResource = imagecreatefromstring($data);
|
||||||
|
|
||||||
|
// Validate that the decoded data is indeed an image
|
||||||
|
if ($tempResource === false)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException("The data does not represent a valid image.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate MIME type using getimagesizefromstring
|
||||||
|
$imageInfo = getimagesizefromstring($data);
|
||||||
|
if ($imageInfo === false || $imageInfo['mime'] !== 'image/jpeg')
|
||||||
|
{
|
||||||
|
imagedestroy($tempResource); // Cleanup resources
|
||||||
|
throw new InvalidArgumentException("The image is not a valid JPEG format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture the re-encoded image in memory and return it as a string
|
||||||
|
ob_start(); // Start output buffering
|
||||||
|
$saveResult = imagejpeg($tempResource, null, 100); // Max quality, save to output buffer
|
||||||
|
imagedestroy($tempResource); // Free up memory resources
|
||||||
|
|
||||||
|
if (!$saveResult)
|
||||||
|
{
|
||||||
|
ob_end_clean(); // Clean the output buffer if encoding failed
|
||||||
|
throw new InvalidArgumentException("Failed to encode the sanitized image.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the sanitized jpeg image as the result
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes an image to a specified width and height while maintaining its aspect ratio.
|
||||||
|
* The resized image is centered on a black background matching the target dimensions.
|
||||||
|
*
|
||||||
|
* @param string $data The binary data of the source image.
|
||||||
|
* @param int $width The desired width of the resized image.
|
||||||
|
* @param int $height The desired height of the resized image.
|
||||||
|
* @return string The binary data of the resized image in PNG format.
|
||||||
|
* @throws InvalidArgumentException If the source image cannot be created from the provided data.
|
||||||
|
* @throws Exception If image processing fails during resizing.
|
||||||
|
*/
|
||||||
|
public static function resizeImage(string $data, int $width, int $height): string
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Create image resource from binary data
|
||||||
|
$sourceImage = imagecreatefromstring($data);
|
||||||
|
if (!$sourceImage)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException("Failed to create image from provided data");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get original dimensions
|
||||||
|
$sourceWidth = imagesx($sourceImage);
|
||||||
|
$sourceHeight = imagesy($sourceImage);
|
||||||
|
|
||||||
|
// Calculate aspect ratios
|
||||||
|
$sourceRatio = $sourceWidth / $sourceHeight;
|
||||||
|
$targetRatio = $width / $height;
|
||||||
|
|
||||||
|
// Initialize dimensions for scaling
|
||||||
|
$scaleWidth = $width;
|
||||||
|
$scaleHeight = $height;
|
||||||
|
|
||||||
|
// Calculate scaling dimensions to maintain aspect ratio
|
||||||
|
if ($sourceRatio > $targetRatio)
|
||||||
|
{
|
||||||
|
// Source image is wider - scale by width
|
||||||
|
$scaleHeight = $width / $sourceRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Source image is taller - scale by height
|
||||||
|
$scaleWidth = $height * $sourceRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create target image with desired dimensions
|
||||||
|
$targetImage = imagecreatetruecolor($width, $height);
|
||||||
|
if (!$targetImage)
|
||||||
|
{
|
||||||
|
throw new Exception("Failed to create target image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill background with black
|
||||||
|
$black = imagecolorallocate($targetImage, 0, 0, 0);
|
||||||
|
imagefill($targetImage, 0, 0, $black);
|
||||||
|
|
||||||
|
// Calculate padding to center the scaled image
|
||||||
|
$paddingX = ($width - $scaleWidth) / 2;
|
||||||
|
$paddingY = ($height - $scaleHeight) / 2;
|
||||||
|
|
||||||
|
// Enable alpha blending
|
||||||
|
imagealphablending($targetImage, true);
|
||||||
|
imagesavealpha($targetImage, true);
|
||||||
|
|
||||||
|
// Resize and copy the image with high-quality resampling
|
||||||
|
if (!imagecopyresampled($targetImage, $sourceImage, (int)$paddingX, (int)$paddingY, 0, 0, (int)$scaleWidth, (int)$scaleHeight, $sourceWidth, $sourceHeight))
|
||||||
|
{
|
||||||
|
throw new Exception("Failed to resize image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start output buffering
|
||||||
|
ob_start();
|
||||||
|
|
||||||
|
// Output image as PNG (you can modify this to support other formats)
|
||||||
|
imagepng($targetImage);
|
||||||
|
|
||||||
|
// Return the image data
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (isset($sourceImage))
|
||||||
|
{
|
||||||
|
imagedestroy($sourceImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($targetImage))
|
||||||
|
{
|
||||||
|
imagedestroy($targetImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($headers === false)
|
/**
|
||||||
|
* Converts an array into a serialized string by joining the elements with a comma.
|
||||||
|
*
|
||||||
|
* @param array $list An array of elements that need to be converted to a comma-separated string.
|
||||||
|
* @return string A string representation of the array elements, joined by commas.
|
||||||
|
*/
|
||||||
|
public static function serializeList(array $list): string
|
||||||
{
|
{
|
||||||
throw new RuntimeException('Failed to get request headers');
|
return implode(',', $list);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $headers;
|
/**
|
||||||
}
|
* Converts a serialized string into an array by splitting the string at each comma.
|
||||||
|
*
|
||||||
/**
|
* @param string $list A comma-separated string that needs to be converted to an array.
|
||||||
* Converts a Throwable object into a formatted string.
|
* @return array An array of string values obtained by splitting the input string.
|
||||||
*
|
*/
|
||||||
* @param Throwable $e The throwable to be converted into a string.
|
public static function unserializeList(string $list): array
|
||||||
* @return string The formatted string representation of the throwable, including the exception class, message, file, line, and stack trace.
|
|
||||||
*/
|
|
||||||
public static function throwableToString(Throwable $e): string
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
"%s: %s in %s:%d\nStack trace:\n%s",
|
|
||||||
get_class($e),
|
|
||||||
$e->getMessage(),
|
|
||||||
$e->getFile(),
|
|
||||||
$e->getLine(),
|
|
||||||
$e->getTraceAsString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a formatted header string.
|
|
||||||
*
|
|
||||||
* @param StandardHeaders $header The standard header object.
|
|
||||||
* @param string $value The header value to be associated with the standard header.
|
|
||||||
* @return string The formatted header string.
|
|
||||||
*/
|
|
||||||
public static function generateHeader(StandardHeaders $header, string $value): string
|
|
||||||
{
|
|
||||||
return $header->value . ': ' . $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random string of specified length using the provided character set.
|
|
||||||
*
|
|
||||||
* @param int $int The length of the random string to be generated.
|
|
||||||
* @param string $string The character set to use for generating the random string.
|
|
||||||
* @return string The generated random string.
|
|
||||||
*/
|
|
||||||
public static function randomString(int $int, string $string): string
|
|
||||||
{
|
|
||||||
$characters = str_split($string);
|
|
||||||
$randomString = '';
|
|
||||||
|
|
||||||
for ($i = 0; $i < $int; $i++)
|
|
||||||
{
|
{
|
||||||
$randomString .= $characters[array_rand($characters)];
|
return explode(',', $list);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $randomString;
|
/**
|
||||||
}
|
* Checks if the given HTTP response code indicates success or failure.
|
||||||
|
*
|
||||||
/**
|
* @param int $responseCode The HTTP response code to check.
|
||||||
* Generates a random CRC32 hash.
|
* @return bool True if the response code indicates success, false otherwise.
|
||||||
*
|
*/
|
||||||
* @return string The generated CRC32 hash as a string.
|
public static function isSuccessCodes(int $responseCode): bool
|
||||||
*/
|
|
||||||
public static function randomCrc32(): string
|
|
||||||
{
|
|
||||||
return hash('crc32b', uniqid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanitizes a file name by removing any characters that are not alphanumeric, hyphen, or underscore.
|
|
||||||
*
|
|
||||||
* @param string $name The file name to be sanitized.
|
|
||||||
* @return string The sanitized file name.
|
|
||||||
*/
|
|
||||||
public static function sanitizeFileName(string $name): string
|
|
||||||
{
|
|
||||||
return preg_replace('/[^a-zA-Z0-9-_]/', '', $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanitizes a Base64-encoded JPEG image by validating its data, decoding it,
|
|
||||||
* and re-encoding it to ensure it conforms to the JPEG format.
|
|
||||||
*
|
|
||||||
* @param string $data The Base64-encoded string potentially containing a JPEG image,
|
|
||||||
* optionally prefixed with "data:image/...;base64,".
|
|
||||||
* @return string A sanitized and re-encoded JPEG image as a binary string.
|
|
||||||
* @throws InvalidArgumentException If the input data is not valid Base64,
|
|
||||||
* does not represent an image, or is not in the JPEG format.
|
|
||||||
*/
|
|
||||||
public static function sanitizeBase64Jpeg(string $data): string
|
|
||||||
{
|
|
||||||
// Detect and strip the potential "data:image/...;base64," prefix, if present
|
|
||||||
if (str_contains($data, ','))
|
|
||||||
{
|
{
|
||||||
[, $data] = explode(',', $data, 2);
|
return $responseCode >= 200 && $responseCode < 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the Base64 string
|
|
||||||
$decodedData = base64_decode($data, true);
|
|
||||||
|
|
||||||
// Check if decoding succeeded
|
|
||||||
if ($decodedData === false)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException("Invalid Base64 data.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporarily load the decoded data as an image
|
|
||||||
$tempResource = imagecreatefromstring($decodedData);
|
|
||||||
|
|
||||||
// Validate that the decoded data is indeed an image
|
|
||||||
if ($tempResource === false)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException("The Base64 data does not represent a valid image.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate MIME type using getimagesizefromstring
|
|
||||||
$imageInfo = getimagesizefromstring($decodedData);
|
|
||||||
if ($imageInfo === false || $imageInfo['mime'] !== 'image/jpeg')
|
|
||||||
{
|
|
||||||
imagedestroy($tempResource); // Cleanup resources
|
|
||||||
throw new InvalidArgumentException("The image is not a valid JPEG format.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capture the re-encoded image in memory and return it as a string
|
|
||||||
ob_start(); // Start output buffering
|
|
||||||
$saveResult = imagejpeg($tempResource, null, 100); // Max quality, save to output buffer
|
|
||||||
imagedestroy($tempResource); // Free up memory resources
|
|
||||||
|
|
||||||
if (!$saveResult)
|
|
||||||
{
|
|
||||||
ob_end_clean(); // Clean the output buffer if encoding failed
|
|
||||||
throw new InvalidArgumentException("Failed to encode the sanitized image.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the sanitized jpeg image as the result
|
|
||||||
return ob_get_clean();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an array into a serialized string by joining the elements with a comma.
|
|
||||||
*
|
|
||||||
* @param array $list An array of elements that need to be converted to a comma-separated string.
|
|
||||||
* @return string A string representation of the array elements, joined by commas.
|
|
||||||
*/
|
|
||||||
public static function serializeList(array $list): string
|
|
||||||
{
|
|
||||||
return implode(',', $list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a serialized string into an array by splitting the string at each comma.
|
|
||||||
*
|
|
||||||
* @param string $list A comma-separated string that needs to be converted to an array.
|
|
||||||
* @return array An array of string values obtained by splitting the input string.
|
|
||||||
*/
|
|
||||||
public static function unserializeList(string $list): array
|
|
||||||
{
|
|
||||||
return explode(',', $list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given HTTP response code indicates success or failure.
|
|
||||||
*
|
|
||||||
* @param int $responseCode The HTTP response code to check.
|
|
||||||
* @return bool True if the response code indicates success, false otherwise.
|
|
||||||
*/
|
|
||||||
public static function isSuccessCodes(int $responseCode): bool
|
|
||||||
{
|
|
||||||
return $responseCode >= 200 && $responseCode < 300;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,28 +15,31 @@ enum StandardError : int
|
||||||
case INTERNAL_SERVER_ERROR = -2000;
|
case INTERNAL_SERVER_ERROR = -2000;
|
||||||
case SERVER_UNAVAILABLE = -2001;
|
case SERVER_UNAVAILABLE = -2001;
|
||||||
|
|
||||||
|
// Client Errors
|
||||||
|
case BAD_REQUEST = -3000;
|
||||||
|
case METHOD_NOT_ALLOWED = -3001;
|
||||||
|
|
||||||
// Authentication/Cryptography Errors
|
// Authentication/Cryptography Errors
|
||||||
case INVALID_PUBLIC_KEY = -3000;
|
case INVALID_PUBLIC_KEY = -4000; // *
|
||||||
|
|
||||||
case SESSION_REQUIRED = -3001;
|
case SESSION_REQUIRED = -5001; // *
|
||||||
case SESSION_NOT_FOUND = -3002;
|
case SESSION_NOT_FOUND = -5002; // *
|
||||||
case SESSION_EXPIRED = -3003;
|
case SESSION_EXPIRED = -5003; // *
|
||||||
case SESSION_DHE_REQUIRED = -3004;
|
case SESSION_DHE_REQUIRED = -5004; // *
|
||||||
|
|
||||||
case ALREADY_AUTHENTICATED = -3005;
|
case ALREADY_AUTHENTICATED = -6005;
|
||||||
case UNSUPPORTED_AUTHENTICATION_TYPE = -3006;
|
case UNSUPPORTED_AUTHENTICATION_TYPE = -6006;
|
||||||
case AUTHENTICATION_REQUIRED = -3007;
|
case AUTHENTICATION_REQUIRED = -6007;
|
||||||
case REGISTRATION_DISABLED = -3008;
|
case REGISTRATION_DISABLED = -6008;
|
||||||
case CAPTCHA_NOT_AVAILABLE = -3009;
|
case CAPTCHA_NOT_AVAILABLE = -6009;
|
||||||
case INCORRECT_CAPTCHA_ANSWER = -3010;
|
case INCORRECT_CAPTCHA_ANSWER = -6010;
|
||||||
case CAPTCHA_EXPIRED = -3011;
|
case CAPTCHA_EXPIRED = -6011;
|
||||||
|
|
||||||
// General Error Messages
|
// General Error Messages
|
||||||
case PEER_NOT_FOUND = -4000;
|
case PEER_NOT_FOUND = -7000;
|
||||||
case INVALID_USERNAME = -4001;
|
case INVALID_USERNAME = -7001;
|
||||||
case USERNAME_ALREADY_EXISTS = -4002;
|
case USERNAME_ALREADY_EXISTS = -7002;
|
||||||
case NOT_REGISTERED = -4003;
|
case NOT_REGISTERED = -7003;
|
||||||
case METHOD_NOT_ALLOWED = -4004;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default generic message for the error
|
* Returns the default generic message for the error
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
use Socialbox\Classes\StandardMethods\GetSessionState;
|
use Socialbox\Classes\StandardMethods\GetSessionState;
|
||||||
use Socialbox\Classes\StandardMethods\GetTermsOfService;
|
use Socialbox\Classes\StandardMethods\GetTermsOfService;
|
||||||
use Socialbox\Classes\StandardMethods\Ping;
|
use Socialbox\Classes\StandardMethods\Ping;
|
||||||
|
use Socialbox\Classes\StandardMethods\SettingsSetDisplayName;
|
||||||
use Socialbox\Classes\StandardMethods\SettingsSetPassword;
|
use Socialbox\Classes\StandardMethods\SettingsSetPassword;
|
||||||
use Socialbox\Classes\StandardMethods\VerificationAnswerImageCaptcha;
|
use Socialbox\Classes\StandardMethods\VerificationAnswerImageCaptcha;
|
||||||
use Socialbox\Classes\StandardMethods\VerificationGetImageCaptcha;
|
use Socialbox\Classes\StandardMethods\VerificationGetImageCaptcha;
|
||||||
|
@ -83,6 +84,7 @@
|
||||||
self::VERIFICATION_ANSWER_IMAGE_CAPTCHA => VerificationAnswerImageCaptcha::execute($request, $rpcRequest),
|
self::VERIFICATION_ANSWER_IMAGE_CAPTCHA => VerificationAnswerImageCaptcha::execute($request, $rpcRequest),
|
||||||
|
|
||||||
self::SETTINGS_SET_PASSWORD => SettingsSetPassword::execute($request, $rpcRequest),
|
self::SETTINGS_SET_PASSWORD => SettingsSetPassword::execute($request, $rpcRequest),
|
||||||
|
self::SETTINGS_SET_DISPLAY_NAME => SettingsSetDisplayName::execute($request, $rpcRequest),
|
||||||
|
|
||||||
default => $rpcRequest->produceError(StandardError::METHOD_NOT_ALLOWED, sprintf("The method %s is not supported by the server", $rpcRequest->getMethod()))
|
default => $rpcRequest->produceError(StandardError::METHOD_NOT_ALLOWED, sprintf("The method %s is not supported by the server", $rpcRequest->getMethod()))
|
||||||
};
|
};
|
||||||
|
|
|
@ -322,7 +322,8 @@
|
||||||
* Updates the display name of a registered peer based on the given unique identifier or RegisteredPeerRecord object.
|
* Updates the display name of a registered peer based on the given unique identifier or RegisteredPeerRecord object.
|
||||||
*
|
*
|
||||||
* @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
|
* @param string|RegisteredPeerRecord $peer The unique identifier of the registered peer, or an instance of RegisteredPeerRecord.
|
||||||
* @param string $name The new
|
* @param string $name The new display name to set to the user
|
||||||
|
* @throws DatabaseOperationException Thrown if there was an error while trying to update the display name
|
||||||
*/
|
*/
|
||||||
public static function updateDisplayName(string|RegisteredPeerRecord $peer, string $name): void
|
public static function updateDisplayName(string|RegisteredPeerRecord $peer, string $name): void
|
||||||
{
|
{
|
||||||
|
@ -362,6 +363,60 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the display picture of a registered peer in the database.
|
||||||
|
*
|
||||||
|
* @param string|RegisteredPeerRecord $peer The unique identifier of the peer or an instance of RegisteredPeerRecord.
|
||||||
|
* @param string $displayPictureData The raw jpeg data of the display picture.
|
||||||
|
* @return void
|
||||||
|
* @throws DatabaseOperationException If there is an error during the database operation.
|
||||||
|
*/
|
||||||
|
public static function updateDisplayPicture(string|RegisteredPeerRecord $peer, string $displayPictureData): void
|
||||||
|
{
|
||||||
|
if(empty($uuid))
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('The display picture UUID cannot be empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
$uuid = Uuid::v4()->toRfc4122();
|
||||||
|
$displayPicturePath = Configuration::getStorageConfiguration()->getUserDisplayImagesPath() . DIRECTORY_SEPARATOR . $uuid . '.jpeg';
|
||||||
|
|
||||||
|
// Delete the file if it already exists
|
||||||
|
if(file_exists($displayPicturePath))
|
||||||
|
{
|
||||||
|
unlink($displayPicturePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the file contents & set the permissions
|
||||||
|
file_put_contents($displayPicturePath, $displayPictureData);
|
||||||
|
chmod($displayPicturePath, 0644);
|
||||||
|
|
||||||
|
if(is_string($peer))
|
||||||
|
{
|
||||||
|
$peer = self::getPeer($peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($peer->isExternal())
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException('Cannot update the display picture of an external peer');
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::getLogger()->verbose(sprintf("Updating display picture of peer %s to %s", $peer->getUuid(), $uuid));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$statement = Database::getConnection()->prepare('UPDATE `registered_peers` SET display_picture=? WHERE uuid=?');
|
||||||
|
$statement->bindParam(1, $uuid);
|
||||||
|
$peerUuid = $peer->getUuid();
|
||||||
|
$statement->bindParam(2, $peerUuid);
|
||||||
|
$statement->execute();
|
||||||
|
}
|
||||||
|
catch(PDOException $e)
|
||||||
|
{
|
||||||
|
throw new DatabaseOperationException('Failed to update the display picture of the peer in the database', $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the password authentication record associated with the given unique peer identifier or a RegisteredPeerRecord object.
|
* Retrieves the password authentication record associated with the given unique peer identifier or a RegisteredPeerRecord object.
|
||||||
*
|
*
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
private string $username;
|
private string $username;
|
||||||
private string $server;
|
private string $server;
|
||||||
private ?string $displayName;
|
private ?string $displayName;
|
||||||
|
private ?string $displayPicture;
|
||||||
/**
|
/**
|
||||||
* @var PeerFlags[]
|
* @var PeerFlags[]
|
||||||
*/
|
*/
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
$this->username = $data['username'];
|
$this->username = $data['username'];
|
||||||
$this->server = $data['server'];
|
$this->server = $data['server'];
|
||||||
$this->displayName = $data['display_name'] ?? null;
|
$this->displayName = $data['display_name'] ?? null;
|
||||||
|
$this->displayPicture = $data['display_picture'] ?? null;
|
||||||
|
|
||||||
if($data['flags'])
|
if($data['flags'])
|
||||||
{
|
{
|
||||||
|
@ -105,16 +107,41 @@
|
||||||
return $this->displayName;
|
return $this->displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the display picture.
|
||||||
|
*
|
||||||
|
* @return string|null The display picture if set, or null otherwise.
|
||||||
|
*/
|
||||||
|
public function getDisplayPicture(): ?string
|
||||||
|
{
|
||||||
|
return $this->displayPicture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the flags.
|
||||||
|
*
|
||||||
|
* @return PeerFlags[] The flags.
|
||||||
|
*/
|
||||||
public function getFlags(): array
|
public function getFlags(): array
|
||||||
{
|
{
|
||||||
return $this->flags;
|
return $this->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a flag to the current instance.
|
||||||
|
*
|
||||||
|
* @param PeerFlags $flag The flag to add.
|
||||||
|
*/
|
||||||
public function flagExists(PeerFlags $flag): bool
|
public function flagExists(PeerFlags $flag): bool
|
||||||
{
|
{
|
||||||
return in_array($flag, $this->flags, true);
|
return in_array($flag, $this->flags, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a flag to the current instance.
|
||||||
|
*
|
||||||
|
* @param PeerFlags $flag The flag to add.
|
||||||
|
*/
|
||||||
public function removeFlag(PeerFlags $flag): void
|
public function removeFlag(PeerFlags $flag): void
|
||||||
{
|
{
|
||||||
$key = array_search($flag, $this->flags, true);
|
$key = array_search($flag, $this->flags, true);
|
||||||
|
@ -182,6 +209,7 @@
|
||||||
'username' => $this->username,
|
'username' => $this->username,
|
||||||
'server' => $this->server,
|
'server' => $this->server,
|
||||||
'display_name' => $this->displayName,
|
'display_name' => $this->displayName,
|
||||||
|
'display_picture' => $this->displayPicture,
|
||||||
'flags' => PeerFlags::toString($this->flags),
|
'flags' => PeerFlags::toString($this->flags),
|
||||||
'enabled' => $this->enabled,
|
'enabled' => $this->enabled,
|
||||||
'created' => $this->created
|
'created' => $this->created
|
||||||
|
|
Loading…
Add table
Reference in a new issue