163 lines
4.7 KiB
PHP
163 lines
4.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file classes/submission/Sanitizer.php
|
|
*
|
|
* Copyright (c) 2014-2020 Simon Fraser University
|
|
* Copyright (c) 2000-2020 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class Sanitizer
|
|
*
|
|
* @brief A sanitization class to sanitize submission data before saving
|
|
*/
|
|
|
|
namespace PKP\submission;
|
|
|
|
use Exception;
|
|
use Illuminate\Support\Arr;
|
|
use PKP\core\PKPString;
|
|
|
|
class Sanitizer
|
|
{
|
|
/**
|
|
* Defined sanitization rule/method mapping to attributes
|
|
* It's possible to have multiple sanitization rule for a single attributes
|
|
*
|
|
* $sanitizeMap = [
|
|
* 'attribute_1' => 'class_method_1',
|
|
* 'attribute_2' => ['class_method_21', 'class_method_22'],
|
|
* ...
|
|
* ]
|
|
*/
|
|
protected array $sanitizeMap = [];
|
|
|
|
/**
|
|
* Passed params to sanitize
|
|
*/
|
|
protected array $sanitizeParams;
|
|
|
|
/**
|
|
* Define if allow empty sanitization for attributes
|
|
*/
|
|
protected bool $allowEmptySanization = false;
|
|
|
|
/**
|
|
* The entity code to number conversion to update
|
|
* As TinyMCE do a force entity conversion even when defined the 'entity_encoding' as 'raw'
|
|
*
|
|
* @see 5.0+ : https://www.tiny.cloud/docs/configure/content-filtering/#entity_encoding
|
|
* @see 6.0+ : https://www.tiny.cloud/docs/tinymce/6/content-filtering/#entity_encoding
|
|
*/
|
|
protected static array $entityCodeToCharMapping = [
|
|
'&' => '&',
|
|
'>' => '>',
|
|
'<' => '<',
|
|
'"' => '"',
|
|
"'" => ''',
|
|
];
|
|
|
|
/**
|
|
* Convert the TinyMCE/HTMLPurify based converted entity codes to actual character
|
|
*/
|
|
public static function replaceSpecialCharEntityValueWithCharacter(string $string): string
|
|
{
|
|
return str_replace(
|
|
array_values(static::$entityCodeToCharMapping),
|
|
array_keys(static::$entityCodeToCharMapping),
|
|
$string
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Apply the sanitization process for given attribute
|
|
*/
|
|
protected function runSanitizationProcess(string $method, mixed $paramKey, mixed $beforeSanitizevalue): void
|
|
{
|
|
$this->sanitizeParams = array_merge($this->sanitizeParams, [
|
|
$paramKey => $this->{$method}($beforeSanitizevalue),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Sanitize the submission localized/unlocalized title[title] attribute
|
|
*/
|
|
public function title(string|array $param): string|array
|
|
{
|
|
if (is_array($param)) {
|
|
foreach ($param as $localeKey => $localizedSubmissionTitle) {
|
|
// TinyMCE sometimes converts special chars to entity code and some times not
|
|
// A very weird quirk by tinyMCE
|
|
// e.g '&' turned into '&'
|
|
$param[$localeKey] = self::replaceSpecialCharEntityValueWithCharacter(
|
|
PKPString::stripUnsafeHtml($localizedSubmissionTitle, 'allowed_title_html')
|
|
);
|
|
}
|
|
|
|
return $param;
|
|
}
|
|
|
|
return self::replaceSpecialCharEntityValueWithCharacter(
|
|
PKPString::stripUnsafeHtml($param, 'allowed_title_html')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Sanitize the submission localized/unlocalized sub title[subtitle] attribute
|
|
*/
|
|
public function subtitle(string|array $param): string|array
|
|
{
|
|
return $this->title($param);
|
|
}
|
|
|
|
/**
|
|
* Define should allow attributes with empty sanitization rules
|
|
*/
|
|
public function allowEmptySanitization(): self
|
|
{
|
|
$this->allowEmptySanization = true;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Run sanitization
|
|
*/
|
|
public function sanitize(array $params, array $sanitizingKeys = []): array
|
|
{
|
|
$this->sanitizeParams = $params;
|
|
|
|
$sanitizableParams = empty($sanitizingKeys)
|
|
? $params
|
|
: array_intersect_key($params, array_flip($sanitizingKeys));
|
|
|
|
foreach ($sanitizableParams as $paramKey => $paramValue) {
|
|
if (in_array($paramKey, $this->sanitizeMap)) {
|
|
collect(Arr::wrap($this->sanitizeMap[$paramKey]))
|
|
->each(
|
|
fn ($method) => $this->runSanitizationProcess(
|
|
$method,
|
|
$paramKey,
|
|
$paramValue
|
|
)
|
|
);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (method_exists($this, $paramKey)) {
|
|
$this->runSanitizationProcess($paramKey, $paramKey, $paramValue);
|
|
continue;
|
|
}
|
|
|
|
if (!$this->allowEmptySanization) {
|
|
throw new Exception(
|
|
sprintf("Running empty sanitization for attribute '%s' is now allowed", $paramKey)
|
|
);
|
|
}
|
|
}
|
|
|
|
return $this->sanitizeParams;
|
|
}
|
|
}
|