1449 lines
44 KiB
PHP
1449 lines
44 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Various Static Utility methods for working with the installer
|
|
*
|
|
* Standard: PSR-2
|
|
*
|
|
* @link http://www.php-fig.org/psr/psr-2 Full Documentation
|
|
*
|
|
* @package SC\DUPX\U
|
|
*/
|
|
|
|
defined('ABSPATH') || defined('DUPXABSPATH') || exit;
|
|
|
|
use Duplicator\Installer\Core\Bootstrap;
|
|
use Duplicator\Installer\Utils\Log\Log;
|
|
use Duplicator\Installer\Core\Params\PrmMng;
|
|
use Duplicator\Libs\Snap\SnapIO;
|
|
use Duplicator\Libs\Snap\SnapJson;
|
|
|
|
class DUPX_U
|
|
{
|
|
const MAINTENANCE_INDEX_MARKER = '<!-- DUPLICATOR INSTALLER MAINTENANCE -->';
|
|
|
|
/**
|
|
* Adds a slash to the end of a file or directory path
|
|
*
|
|
* @param string $path A path
|
|
*
|
|
* @return string The original $path with a with '/' added to the end.
|
|
*/
|
|
public static function addSlash($path)
|
|
{
|
|
$last_char = substr($path, strlen($path) - 1, 1);
|
|
if ($last_char != '/') {
|
|
$path .= '/';
|
|
}
|
|
return $path;
|
|
}
|
|
|
|
/**
|
|
* Does one string contain other
|
|
*
|
|
* @param string $haystack The full string to search
|
|
* @param string $needle The substring to search on
|
|
*
|
|
* @return bool Returns true if the $needle was found in the $haystack
|
|
*/
|
|
public static function contains($haystack, $needle)
|
|
{
|
|
$pos = strpos($haystack, $needle);
|
|
return ($pos !== false);
|
|
}
|
|
|
|
/**
|
|
* move all folder content up to parent
|
|
*
|
|
* @param string $subFolderName full path
|
|
* @param boolean $deleteSubFolder if true delete subFolder after moved all
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public static function moveUpfromSubFolder($subFolderName, $deleteSubFolder = false)
|
|
{
|
|
if (!is_dir($subFolderName)) {
|
|
return false;
|
|
}
|
|
|
|
$parentFolder = dirname($subFolderName);
|
|
if (!is_writable($parentFolder)) {
|
|
return false;
|
|
}
|
|
|
|
$success = true;
|
|
if (($subList = glob(rtrim($subFolderName, '/') . '/*', GLOB_NOSORT)) === false) {
|
|
Log::info("Problem glob folder " . $subFolderName);
|
|
return false;
|
|
} else {
|
|
foreach ($subList as $cName) {
|
|
$destination = $parentFolder . '/' . basename($cName);
|
|
if (file_exists($destination)) {
|
|
$success = SnapIO::rrmdir($destination);
|
|
}
|
|
|
|
if ($success) {
|
|
$success = rename($cName, $destination);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($success && $deleteSubFolder) {
|
|
$success = SnapIO::rrmdir($subFolderName);
|
|
}
|
|
}
|
|
|
|
if (!$success) {
|
|
Log::info("Problem om moveUpfromSubFolder subFolder:" . $subFolderName);
|
|
}
|
|
|
|
return $success;
|
|
}
|
|
|
|
/**
|
|
* @param string $archive_filepath full path of zip archive
|
|
* @param string $password archive password
|
|
*
|
|
* @return boolean|string path of dup-installer folder of false if not found
|
|
*/
|
|
public static function findDupInstallerFolder($archive_filepath, $password)
|
|
{
|
|
if (!DUPX_Conf_Utils::isPhpZipAvailable()) {
|
|
return '';
|
|
}
|
|
$zipArchive = new ZipArchive();
|
|
$result = false;
|
|
$dupArchiveTxt = Bootstrap::ARCHIVE_PREFIX . Bootstrap::getPackageHash() . Bootstrap::ARCHIVE_EXTENSION;
|
|
|
|
if ($zipArchive->open($archive_filepath) === true) {
|
|
if (strlen($password)) {
|
|
$zipArchive->setPassword($password);
|
|
}
|
|
for ($i = 0; $i < $zipArchive->numFiles; $i++) {
|
|
$stat = $zipArchive->statIndex($i);
|
|
$safePath = rtrim(self::setSafePath($stat['name']), '/');
|
|
if (substr_count($safePath, '/') > 2) {
|
|
continue;
|
|
}
|
|
$exploded = explode('/', $safePath);
|
|
if (
|
|
($dup_index = array_search($dupArchiveTxt, $exploded)) !== false &&
|
|
$exploded[$dup_index - 1] === 'dup-installer'
|
|
) {
|
|
$result = implode('/', array_slice($exploded, 0, $dup_index - 1));
|
|
break;
|
|
}
|
|
}
|
|
if ($zipArchive->close() !== true) {
|
|
Log::info("Can't close ziparchive:" . $archive_filepath);
|
|
return false;
|
|
}
|
|
} else {
|
|
Log::info("Can't open zip archive:" . $archive_filepath);
|
|
return false;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Dumps a variable for debugging
|
|
*
|
|
* @param mixed $var The variable to view
|
|
* @param bool $pretty Pretty print the var
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function dump($var, $pretty = false)
|
|
{
|
|
if ($pretty) {
|
|
echo '<pre>';
|
|
print_r($var);
|
|
echo '</pre>';
|
|
} else {
|
|
print_r($var);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return a string with the elapsed time
|
|
*
|
|
* @see getMicrotime()
|
|
*
|
|
* @param int|float $end The final time in the sequence to measure
|
|
* @param int|float $start The start time in the sequence to measure
|
|
*
|
|
* @return string The time elapsed from $start to $end
|
|
*/
|
|
public static function elapsedTime($end, $start)
|
|
{
|
|
return sprintf("%.4f sec.", abs($end - $start));
|
|
}
|
|
|
|
/**
|
|
* Echo 256 spaces
|
|
*
|
|
* PHP_SAPI for fcgi requires a data flush of at least 256
|
|
* bytes every 40 seconds or else it forces a script halt
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function fcgiFlush()
|
|
{
|
|
echo(str_repeat(' ', 256));
|
|
flush();
|
|
}
|
|
|
|
/**
|
|
* Get current microtime as a float. Method is used for simple profiling
|
|
*
|
|
* @see elapsedTime
|
|
*
|
|
* @return float A float in the form "msec sec", where sec is the number of seconds since the Unix epoch
|
|
*/
|
|
public static function getMicrotime()
|
|
{
|
|
return microtime(true);
|
|
}
|
|
|
|
/**
|
|
* Gets the size of a variable in memory
|
|
*
|
|
* @param mixed $var A valid PHP variable
|
|
*
|
|
* @return int The amount of memory the variable has consumed
|
|
*/
|
|
public static function getVarSize($var)
|
|
{
|
|
$start_memory = memory_get_usage();
|
|
$var = unserialize(serialize($var));
|
|
return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
|
|
}
|
|
|
|
/**
|
|
* Is the string JSON
|
|
*
|
|
* @param string $string Any string blob
|
|
*
|
|
* @return bool Returns true if the string is JSON encoded
|
|
*/
|
|
public static function isJSON($string)
|
|
{
|
|
|
|
return is_string($string) && is_array(json_decode($string, true)) ? true : false;
|
|
}
|
|
|
|
/**
|
|
* Display human readable byte sizes
|
|
*
|
|
* @param int $size The size in bytes
|
|
*
|
|
* @return string Human readable bytes such as 50MB, 1GB
|
|
*/
|
|
public static function readableByteSize($size)
|
|
{
|
|
try {
|
|
$units = array(
|
|
'B',
|
|
'KB',
|
|
'MB',
|
|
'GB',
|
|
'TB',
|
|
);
|
|
for ($i = 0; $size >= 1024 && $i < 4; $i++) {
|
|
$size /= 1024;
|
|
}
|
|
return round($size, 2) . $units[$i];
|
|
} catch (Exception $e) {
|
|
return "n/a";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes path safe for any OS for PHP
|
|
*
|
|
* Paths should ALWAYS READ be "/"
|
|
* uni: /home/path/file.txt
|
|
* win: D:/home/path/file.txt
|
|
*
|
|
* @param string $path The path to make safe
|
|
*
|
|
* @return string The original $path with a with all slashes facing '/'.
|
|
*/
|
|
public static function setSafePath($path)
|
|
{
|
|
return str_replace("\\", "/", $path);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check PHP version
|
|
*
|
|
* @param string $version PHP version we looking for
|
|
*
|
|
* @return boolean Returns true if version is same or above.
|
|
*/
|
|
public static function isVersion($version)
|
|
{
|
|
return (version_compare(PHP_VERSION, $version) >= 0);
|
|
}
|
|
|
|
/**
|
|
* The domain part of the given URL
|
|
* www.myurl.co.uk => myurl.co.uk
|
|
* www.google.com => google.com
|
|
* my.test.myurl.co.uk => myurl.co.uk
|
|
* www.myurl.localweb => myurl.localweb
|
|
*
|
|
* @param string $url string The URL whichs domain you want to get
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getDomain($url)
|
|
{
|
|
$pieces = parse_url($url);
|
|
$domain = isset($pieces['host']) ? $pieces['host'] : '';
|
|
if (strpos($domain, ".") !== false) {
|
|
if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
|
|
return $regs['domain'];
|
|
} else {
|
|
$exDomain = explode('.', $domain);
|
|
return implode('.', array_slice($exDomain, -2, 2));
|
|
}
|
|
} else {
|
|
return $domain;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string $oldSubUrl The old sub url
|
|
* @param string $oldMainUrl The old main url
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getDefaultURL($oldSubUrl, $oldMainUrl)
|
|
{
|
|
$paramsManager = PrmMng::getInstance();
|
|
$newMainUrl = $paramsManager->getValue(PrmMng::PARAM_URL_NEW);
|
|
$parsedNewMainUrl = parse_url($newMainUrl);
|
|
$parsedOldMainUrl = parse_url($oldMainUrl);
|
|
$parsedOldSubUrl = parse_url($oldSubUrl);
|
|
$oldMainDomain = $parsedOldMainUrl['host'];
|
|
$oldSubDomain = $parsedOldSubUrl['host'];
|
|
$newMainDomain = $parsedNewMainUrl['host'];
|
|
// PARSE SCHEME
|
|
$resultScheme = isset($parsedNewMainUrl['scheme']) ? $parsedNewMainUrl['scheme'] : 'http';
|
|
// PARSE HOST
|
|
if ($oldMainDomain === $oldSubDomain) {
|
|
$resultDomain = $newMainDomain;
|
|
} else {
|
|
$oldNoWwwMainDomain = (strpos($oldMainDomain, 'www.') === 0) ? substr($oldMainDomain, 4) : $oldMainDomain;
|
|
$newNoWwwMainDomain = (strpos($newMainDomain, 'www.') === 0) ? substr($newMainDomain, 4) : $newMainDomain;
|
|
if (($pos = strrpos($oldSubDomain, $oldNoWwwMainDomain)) === strlen($oldSubDomain) - strlen($oldNoWwwMainDomain)) {
|
|
$subDif = substr($oldSubDomain, 0, $pos);
|
|
$resultDomain = $subDif . $newNoWwwMainDomain;
|
|
} else {
|
|
// If I can't find a match it is a non-manageable url so I take the value of the old url.
|
|
$resultDomain = $oldSubDomain;
|
|
}
|
|
}
|
|
|
|
// PARSE PATH
|
|
$oldMainPath = isset($parsedOldMainUrl['path']) ? $parsedOldMainUrl['path'] : '';
|
|
$oldSubPath = isset($parsedOldSubUrl['path']) ? $parsedOldSubUrl['path'] : '';
|
|
$newMainPath = isset($parsedNewMainUrl['path']) ? $parsedNewMainUrl['path'] : '';
|
|
if ($oldMainPath === $oldSubPath) {
|
|
$resultPath = $newMainPath;
|
|
} else {
|
|
if (strpos($oldSubPath, $oldMainPath) === 0) {
|
|
$subDif = substr($oldSubPath, strlen($oldMainPath));
|
|
$resultPath = $newMainPath . '/' . trim($subDif, '/');
|
|
} else {
|
|
// If I can't find a match it is a non-manageable path so I take the value of the old path.
|
|
$resultPath = $oldSubPath;
|
|
}
|
|
}
|
|
|
|
if (empty($resultPath) || $resultPath === '/') {
|
|
$resultPath = '';
|
|
}
|
|
|
|
return $resultScheme . '://' . $resultDomain . '/' . trim($resultPath, '/');
|
|
}
|
|
|
|
/**
|
|
* Get default chunk size in byte
|
|
*
|
|
* @param int $min_chunk_size Min minimum chunk size in bytes
|
|
*
|
|
* @return int An integer chunk size byte value.
|
|
*/
|
|
public static function get_default_chunk_size_in_byte($min_chunk_size = 0)
|
|
{
|
|
|
|
if ($min_chunk_size == 0) {
|
|
$min_chunk_size = 2 * MB_IN_BYTES;
|
|
}
|
|
$post_max_size_in_bytes = self::get_bytes_from_shorthand(ini_get('post_max_size'));
|
|
$considered_post_max_size_in_bytes = $post_max_size_in_bytes - KB_IN_BYTES;
|
|
$upload_max_filesize_in_bytes = self::get_bytes_from_shorthand(ini_get('upload_max_filesize'));
|
|
$considered_upload_max_filesize_in_bytes = $upload_max_filesize_in_bytes - KB_IN_BYTES;
|
|
$memory_limit_in_bytes = self::get_bytes_from_shorthand(ini_get('memory_limit'));
|
|
$considered_memory_limit_in_bytes = $memory_limit_in_bytes - KB_IN_BYTES;
|
|
$chunk_size_in_byte = min(
|
|
$considered_post_max_size_in_bytes,
|
|
$considered_upload_max_filesize_in_bytes,
|
|
$considered_memory_limit_in_bytes, // In extraction process, 2 MB is improving speed, so we are using 5MB instead of 10 MB
|
|
$min_chunk_size
|
|
);
|
|
return $chunk_size_in_byte;
|
|
}
|
|
|
|
/**
|
|
* Converts a shorthand byte value to an integer byte value.
|
|
*
|
|
* @param string $value A (PHP ini) byte value, either shorthand or ordinary.
|
|
*
|
|
* @return int An integer byte value.
|
|
*/
|
|
private static function get_bytes_from_shorthand($value)
|
|
{
|
|
$value = strtolower(trim($value));
|
|
$bytes = (int) $value;
|
|
if (false !== strpos($value, 'g')) {
|
|
$bytes *= GB_IN_BYTES;
|
|
} elseif (false !== strpos($value, 'm')) {
|
|
$bytes *= MB_IN_BYTES;
|
|
} elseif (false !== strpos($value, 'k')) {
|
|
$bytes *= KB_IN_BYTES;
|
|
}
|
|
|
|
// For windows 32 bit int max limit
|
|
if ($bytes < 0) {
|
|
return PHP_INT_MAX;
|
|
}
|
|
|
|
return min($bytes, PHP_INT_MAX);
|
|
// Deal with large (float) values which run into the maximum integer size.
|
|
}
|
|
|
|
/**
|
|
* Escaping for HTML blocks.
|
|
*
|
|
* @param string $text The text to be escaped.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function esc_html($text)
|
|
{
|
|
$safe_text = SnapJson::checkInvalidUTF8($text);
|
|
$safe_text = self::_wp_specialchars($safe_text, ENT_QUOTES);
|
|
/**
|
|
* Filters a string cleaned and escaped for output in HTML.
|
|
*
|
|
* Text passed to esc_html() is stripped of invalid or special characters
|
|
* before output.
|
|
*
|
|
* @param string $safe_text The text after it has been escaped.
|
|
* @param string $text The text prior to being escaped.
|
|
*/
|
|
return $safe_text;
|
|
}
|
|
|
|
/**
|
|
* Escape single quotes, htmlspecialchar " < > &, and fix line endings.
|
|
*
|
|
* Escapes text strings for echoing in JS. It is intended to be used for inline JS
|
|
* (in a tag attribute, for example onclick="..."). Note that the strings have to
|
|
* be in single quotes. The {@see 'js_escape'} filter is also applied here.
|
|
*
|
|
* @param string $text The text to be escaped.
|
|
*
|
|
* @return string Escaped text.
|
|
*/
|
|
public static function esc_js($text)
|
|
{
|
|
$safe_text = SnapJson::checkInvalidUTF8($text);
|
|
$safe_text = self::_wp_specialchars($safe_text, ENT_COMPAT);
|
|
$safe_text = preg_replace('/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes($safe_text));
|
|
$safe_text = str_replace("\r", '', $safe_text);
|
|
$safe_text = str_replace("\n", '\\n', addslashes($safe_text));
|
|
/**
|
|
* Filters a string cleaned and escaped for output in JavaScript.
|
|
*
|
|
* Text passed to esc_js() is stripped of invalid or special characters,
|
|
* and properly slashed for output.
|
|
*
|
|
* @param string $safe_text The text after it has been escaped.
|
|
* @param string $text The text prior to being escaped.
|
|
*/
|
|
return $safe_text;
|
|
}
|
|
|
|
/**
|
|
* Escaping for HTML attributes.
|
|
*
|
|
* @param string $text The text to be escaped.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function esc_attr($text)
|
|
{
|
|
$safe_text = SnapJson::checkInvalidUTF8($text);
|
|
$safe_text = self::_wp_specialchars($safe_text, ENT_QUOTES);
|
|
/**
|
|
* Filters a string cleaned and escaped for output in an HTML attribute.
|
|
*
|
|
* Text passed to esc_attr() is stripped of invalid or special characters
|
|
* before output.
|
|
*
|
|
* @param string $safe_text The text after it has been escaped.
|
|
* @param string $text The text prior to being escaped.
|
|
*/
|
|
return $safe_text;
|
|
}
|
|
|
|
/**
|
|
* Escaping for textarea values.
|
|
*
|
|
* @param string $text The text to be escaped.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function esc_textarea($text)
|
|
{
|
|
$safe_text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
|
|
/**
|
|
* Filters a string cleaned and escaped for output in a textarea element.
|
|
*
|
|
* @param string $safe_text The text after it has been escaped.
|
|
* @param string $text The text prior to being escaped.
|
|
*/
|
|
return $safe_text;
|
|
}
|
|
|
|
/**
|
|
* Escape an HTML tag name.
|
|
*
|
|
* @param string $tag_name The tag name to be escaped.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function tag_escape($tag_name)
|
|
{
|
|
$safe_tag = strtolower(preg_replace('/[^a-zA-Z0-9_:]/', '', $tag_name));
|
|
/**
|
|
* Filters a string cleaned and escaped for output as an HTML tag.
|
|
*
|
|
* @param string $safe_tag The tag name after it has been escaped.
|
|
* @param string $tag_name The text before it was escaped.
|
|
*/
|
|
return $safe_tag;
|
|
}
|
|
|
|
/**
|
|
* Converts a number of special characters into their HTML entities.
|
|
*
|
|
* Specifically deals with: &, <, >, ", and '.
|
|
*
|
|
* $quote_style can be set to ENT_COMPAT to encode " to
|
|
* ", or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
|
|
*
|
|
* @param string $string The text which is to be encoded.
|
|
* @param int|string $quote_style Optional. Converts double quotes if set to ENT_COMPAT,
|
|
* both single and double if set to ENT_QUOTES or none if
|
|
* set to ENT_NOQUOTES. Also compatible with old values;
|
|
* converting single quotes if set to 'single', double if
|
|
* set to 'double' or both if otherwise set. Default is
|
|
* ENT_NOQUOTES.
|
|
* @param bool|string $charset Optional. The character encoding of the string. Default is false.
|
|
* @param bool $double_encode Optional. Whether to encode existing html entities. Default is false.
|
|
*
|
|
* @return string The encoded text with HTML entities.
|
|
*/
|
|
public static function _wp_specialchars($string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false) // phpcs:ignore
|
|
{
|
|
$string = (string) $string;
|
|
if (0 === strlen($string)) {
|
|
return '';
|
|
}
|
|
|
|
// Don't bother if there are no specialchars - saves some processing
|
|
if (!preg_match('/[&<>"\']/', $string)) {
|
|
return $string;
|
|
}
|
|
|
|
// Account for the previous behaviour of the function when the $quote_style is not an accepted value
|
|
if (empty($quote_style)) {
|
|
$quote_style = ENT_NOQUOTES;
|
|
} elseif (!in_array($quote_style, array(0, 2, 3, 'single', 'double'), true)) {
|
|
$quote_style = ENT_QUOTES;
|
|
}
|
|
|
|
// Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
|
|
if (!$charset) {
|
|
static $_charset = null;
|
|
if (!isset($_charset)) {
|
|
$_charset = '';
|
|
}
|
|
$charset = $_charset;
|
|
}
|
|
|
|
if (in_array($charset, array('utf8', 'utf-8', 'UTF8'))) {
|
|
$charset = 'UTF-8';
|
|
}
|
|
|
|
$_quote_style = $quote_style;
|
|
if ($quote_style === 'double') {
|
|
$quote_style = ENT_COMPAT;
|
|
$_quote_style = ENT_COMPAT;
|
|
} elseif ($quote_style === 'single') {
|
|
$quote_style = ENT_NOQUOTES;
|
|
}
|
|
|
|
if (!$double_encode) {
|
|
// Guarantee every &entity; is valid, convert &garbage; into &garbage;
|
|
// This is required for PHP < 5.4.0 because ENT_HTML401 flag is unavailable.
|
|
$string = self::wp_kses_normalize_entities($string);
|
|
}
|
|
|
|
$string = @htmlspecialchars($string, $quote_style, $charset, $double_encode);
|
|
// Back-compat.
|
|
if ('single' === $_quote_style) {
|
|
$string = str_replace("'", ''', $string);
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Perform a deep string replace operation to ensure the values in $search are no longer present
|
|
*
|
|
* Repeats the replacement operation until it no longer replaces anything so as to remove "nested" values
|
|
* e.g. $subject = '%0%0%0DDD', $search ='%0D', $result ='' rather than the '%0%0DD' that
|
|
* str_replace would return
|
|
*
|
|
* @access private
|
|
*
|
|
* @param string|string[] $search The value being searched for, otherwise known as the needle.
|
|
* An array may be used to designate multiple needles.
|
|
* @param string $subject The string being searched and replaced on, otherwise known as the haystack.
|
|
*
|
|
* @return string The string with the replaced svalues.
|
|
*/
|
|
private static function _deep_replace($search, $subject) // phpcs:ignore
|
|
{
|
|
$subject = (string) $subject;
|
|
$count = 1;
|
|
while ($count) {
|
|
$subject = str_replace($search, '', $subject, $count);
|
|
}
|
|
|
|
return $subject;
|
|
}
|
|
|
|
/**
|
|
* Converts and fixes HTML entities.
|
|
*
|
|
* This function normalizes HTML entities. It will convert `AT&T` to the correct
|
|
* `AT&T`, `:` to `:`, `&#XYZZY;` to `&#XYZZY;` and so on.
|
|
*
|
|
* @param string $string Content to normalize entities
|
|
*
|
|
* @return string Content with normalized entities
|
|
*/
|
|
public static function wp_kses_normalize_entities($string)
|
|
{
|
|
// Disarm all entities by converting & to &
|
|
$string = str_replace('&', '&', $string);
|
|
// Change back the allowed entities in our entity whitelist
|
|
$string = preg_replace_callback('/&([A-Za-z]{2,8}[0-9]{0,2});/', array(__CLASS__, 'wp_kses_named_entities'), $string);
|
|
$string = preg_replace_callback('/&#(0*[0-9]{1,7});/', array(__CLASS__, 'wp_kses_normalize_entities2'), $string);
|
|
$string = preg_replace_callback('/&#[Xx](0*[0-9A-Fa-f]{1,6});/', array(__CLASS__, 'wp_kses_normalize_entities3'), $string);
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Callback for wp_kses_normalize_entities() regular expression.
|
|
*
|
|
* This function only accepts valid named entity references, which are finite,
|
|
* case-sensitive, and highly scrutinized by HTML and XML validators.
|
|
*
|
|
* @param string[] $matches preg_replace_callback() matches array
|
|
*
|
|
* @return string Correctly encoded entity
|
|
*/
|
|
public static function wp_kses_named_entities($matches)
|
|
{
|
|
if (empty($matches[1])) {
|
|
return '';
|
|
}
|
|
|
|
$allowedentitynames = array(
|
|
'nbsp',
|
|
'iexcl',
|
|
'cent',
|
|
'pound',
|
|
'curren',
|
|
'yen',
|
|
'brvbar',
|
|
'sect',
|
|
'uml',
|
|
'copy',
|
|
'ordf',
|
|
'laquo',
|
|
'not',
|
|
'shy',
|
|
'reg',
|
|
'macr',
|
|
'deg',
|
|
'plusmn',
|
|
'acute',
|
|
'micro',
|
|
'para',
|
|
'middot',
|
|
'cedil',
|
|
'ordm',
|
|
'raquo',
|
|
'iquest',
|
|
'Agrave',
|
|
'Aacute',
|
|
'Acirc',
|
|
'Atilde',
|
|
'Auml',
|
|
'Aring',
|
|
'AElig',
|
|
'Ccedil',
|
|
'Egrave',
|
|
'Eacute',
|
|
'Ecirc',
|
|
'Euml',
|
|
'Igrave',
|
|
'Iacute',
|
|
'Icirc',
|
|
'Iuml',
|
|
'ETH',
|
|
'Ntilde',
|
|
'Ograve',
|
|
'Oacute',
|
|
'Ocirc',
|
|
'Otilde',
|
|
'Ouml',
|
|
'times',
|
|
'Oslash',
|
|
'Ugrave',
|
|
'Uacute',
|
|
'Ucirc',
|
|
'Uuml',
|
|
'Yacute',
|
|
'THORN',
|
|
'szlig',
|
|
'agrave',
|
|
'aacute',
|
|
'acirc',
|
|
'atilde',
|
|
'auml',
|
|
'aring',
|
|
'aelig',
|
|
'ccedil',
|
|
'egrave',
|
|
'eacute',
|
|
'ecirc',
|
|
'euml',
|
|
'igrave',
|
|
'iacute',
|
|
'icirc',
|
|
'iuml',
|
|
'eth',
|
|
'ntilde',
|
|
'ograve',
|
|
'oacute',
|
|
'ocirc',
|
|
'otilde',
|
|
'ouml',
|
|
'divide',
|
|
'oslash',
|
|
'ugrave',
|
|
'uacute',
|
|
'ucirc',
|
|
'uuml',
|
|
'yacute',
|
|
'thorn',
|
|
'yuml',
|
|
'quot',
|
|
'amp',
|
|
'lt',
|
|
'gt',
|
|
'apos',
|
|
'OElig',
|
|
'oelig',
|
|
'Scaron',
|
|
'scaron',
|
|
'Yuml',
|
|
'circ',
|
|
'tilde',
|
|
'ensp',
|
|
'emsp',
|
|
'thinsp',
|
|
'zwnj',
|
|
'zwj',
|
|
'lrm',
|
|
'rlm',
|
|
'ndash',
|
|
'mdash',
|
|
'lsquo',
|
|
'rsquo',
|
|
'sbquo',
|
|
'ldquo',
|
|
'rdquo',
|
|
'bdquo',
|
|
'dagger',
|
|
'Dagger',
|
|
'permil',
|
|
'lsaquo',
|
|
'rsaquo',
|
|
'euro',
|
|
'fnof',
|
|
'Alpha',
|
|
'Beta',
|
|
'Gamma',
|
|
'Delta',
|
|
'Epsilon',
|
|
'Zeta',
|
|
'Eta',
|
|
'Theta',
|
|
'Iota',
|
|
'Kappa',
|
|
'Lambda',
|
|
'Mu',
|
|
'Nu',
|
|
'Xi',
|
|
'Omicron',
|
|
'Pi',
|
|
'Rho',
|
|
'Sigma',
|
|
'Tau',
|
|
'Upsilon',
|
|
'Phi',
|
|
'Chi',
|
|
'Psi',
|
|
'Omega',
|
|
'alpha',
|
|
'beta',
|
|
'gamma',
|
|
'delta',
|
|
'epsilon',
|
|
'zeta',
|
|
'eta',
|
|
'theta',
|
|
'iota',
|
|
'kappa',
|
|
'lambda',
|
|
'mu',
|
|
'nu',
|
|
'xi',
|
|
'omicron',
|
|
'pi',
|
|
'rho',
|
|
'sigmaf',
|
|
'sigma',
|
|
'tau',
|
|
'upsilon',
|
|
'phi',
|
|
'chi',
|
|
'psi',
|
|
'omega',
|
|
'thetasym',
|
|
'upsih',
|
|
'piv',
|
|
'bull',
|
|
'hellip',
|
|
'prime',
|
|
'Prime',
|
|
'oline',
|
|
'frasl',
|
|
'weierp',
|
|
'image',
|
|
'real',
|
|
'trade',
|
|
'alefsym',
|
|
'larr',
|
|
'uarr',
|
|
'rarr',
|
|
'darr',
|
|
'harr',
|
|
'crarr',
|
|
'lArr',
|
|
'uArr',
|
|
'rArr',
|
|
'dArr',
|
|
'hArr',
|
|
'forall',
|
|
'part',
|
|
'exist',
|
|
'empty',
|
|
'nabla',
|
|
'isin',
|
|
'notin',
|
|
'ni',
|
|
'prod',
|
|
'sum',
|
|
'minus',
|
|
'lowast',
|
|
'radic',
|
|
'prop',
|
|
'infin',
|
|
'ang',
|
|
'and',
|
|
'or',
|
|
'cap',
|
|
'cup',
|
|
'int',
|
|
'sim',
|
|
'cong',
|
|
'asymp',
|
|
'ne',
|
|
'equiv',
|
|
'le',
|
|
'ge',
|
|
'sub',
|
|
'sup',
|
|
'nsub',
|
|
'sube',
|
|
'supe',
|
|
'oplus',
|
|
'otimes',
|
|
'perp',
|
|
'sdot',
|
|
'lceil',
|
|
'rceil',
|
|
'lfloor',
|
|
'rfloor',
|
|
'lang',
|
|
'rang',
|
|
'loz',
|
|
'spades',
|
|
'clubs',
|
|
'hearts',
|
|
'diams',
|
|
'sup1',
|
|
'sup2',
|
|
'sup3',
|
|
'frac14',
|
|
'frac12',
|
|
'frac34',
|
|
'there4',
|
|
);
|
|
$i = $matches[1];
|
|
return (!in_array($i, $allowedentitynames) ) ? "&$i;" : "&$i;";
|
|
}
|
|
|
|
/**
|
|
* Helper function to determine if a Unicode value is valid.
|
|
*
|
|
* @param int $i Unicode value
|
|
*
|
|
* @return bool True if the value was a valid Unicode number
|
|
*/
|
|
public static function wp_valid_unicode($i)
|
|
{
|
|
return ( $i == 0x9 || $i == 0xa || $i == 0xd ||
|
|
($i >= 0x20 && $i <= 0xd7ff) ||
|
|
($i >= 0xe000 && $i <= 0xfffd) ||
|
|
($i >= 0x10000 && $i <= 0x10ffff) );
|
|
}
|
|
|
|
/**
|
|
* Callback for wp_kses_normalize_entities() regular expression.
|
|
*
|
|
* This function helps wp_kses_normalize_entities() to only accept 16-bit
|
|
* values and nothing more for `&#number;` entities.
|
|
*
|
|
* @access private
|
|
*
|
|
* @param string[] $matches preg_replace_callback() matches array
|
|
*
|
|
* @return string Correctly encoded entity
|
|
*/
|
|
public static function wp_kses_normalize_entities2($matches)
|
|
{
|
|
if (empty($matches[1])) {
|
|
return '';
|
|
}
|
|
|
|
$i = $matches[1];
|
|
if (self::wp_valid_unicode($i)) { // @phpstan-ignore-line
|
|
$i = str_pad(ltrim($i, '0'), 3, '0', STR_PAD_LEFT);
|
|
$i = "&#$i;";
|
|
} else {
|
|
$i = "&#$i;";
|
|
}
|
|
|
|
return $i;
|
|
}
|
|
|
|
/**
|
|
* Callback for wp_kses_normalize_entities() for regular expression.
|
|
*
|
|
* This function helps wp_kses_normalize_entities() to only accept valid Unicode
|
|
* numeric entities in hex form.
|
|
*
|
|
* @access private
|
|
*
|
|
* @param string[] $matches preg_replace_callback() matches array
|
|
*
|
|
* @return string Correctly encoded entity
|
|
*/
|
|
public static function wp_kses_normalize_entities3($matches)
|
|
{
|
|
if (empty($matches[1])) {
|
|
return '';
|
|
}
|
|
|
|
$hexchars = $matches[1];
|
|
return (!self::wp_valid_unicode(hexdec($hexchars)) ) ? "&#x$hexchars;" : '&#x' . ltrim($hexchars, '0') . ';';
|
|
}
|
|
|
|
/**
|
|
* Retrieve a list of protocols to allow in HTML attributes.
|
|
*
|
|
* @since 3.3.0
|
|
* @since 4.3.0 Added 'webcal' to the protocols array.
|
|
* @since 4.7.0 Added 'urn' to the protocols array.
|
|
*
|
|
* @see wp_kses()
|
|
* @see esc_url()
|
|
*
|
|
* @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
|
|
* 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
|
|
* 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
|
|
*/
|
|
public static function wp_allowed_protocols()
|
|
{
|
|
static $protocols = array();
|
|
if (empty($protocols)) {
|
|
$protocols = array(
|
|
'http',
|
|
'https',
|
|
'ftp',
|
|
'ftps',
|
|
'mailto',
|
|
'news',
|
|
'irc',
|
|
'gopher',
|
|
'nntp',
|
|
'feed',
|
|
'telnet',
|
|
'mms',
|
|
'rtsp',
|
|
'svn',
|
|
'tel',
|
|
'fax',
|
|
'xmpp',
|
|
'webcal',
|
|
'urn',
|
|
);
|
|
}
|
|
|
|
return $protocols;
|
|
}
|
|
|
|
/**
|
|
* Checks and cleans a URL.
|
|
*
|
|
* A number of characters are removed from the URL. If the URL is for displaying
|
|
* (the default behaviour) ampersands are also replaced. The {@see 'clean_url'} filter
|
|
* is applied to the returned cleaned URL.
|
|
*
|
|
* @since 2.8.0
|
|
*
|
|
* @param string $url The URL to be cleaned.
|
|
* @param string[] $protocols Optional. An array of acceptable protocols.
|
|
* Defaults to return value of
|
|
* wp_allowed_protocols()
|
|
* @param string $_context Private. Use esc_url_raw() for database usage.
|
|
*
|
|
* @return string The cleaned $url after the {@see 'clean_url'} filter is applied.
|
|
*/
|
|
public static function esc_url($url, $protocols = null, $_context = 'display')
|
|
{
|
|
$original_url = $url;
|
|
if ('' == $url) {
|
|
return $url;
|
|
}
|
|
|
|
$url = str_replace(' ', '%20', $url);
|
|
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url);
|
|
if ('' === $url) {
|
|
return $url;
|
|
}
|
|
|
|
if (0 !== stripos($url, 'mailto:')) {
|
|
$strip = array(
|
|
'%0d',
|
|
'%0a',
|
|
'%0D',
|
|
'%0A',
|
|
);
|
|
$url = self::_deep_replace($strip, $url);
|
|
}
|
|
|
|
$url = str_replace(';//', '://', $url);
|
|
/* If the URL doesn't appear to contain a scheme, we
|
|
* presume it needs http:// prepended (unless a relative
|
|
* link starting with /, # or ? or a php file).
|
|
*/
|
|
if (
|
|
strpos($url, ':') === false && !in_array($url[0], array('/', '#', '?')) &&
|
|
!preg_match('/^[a-z0-9-]+?\.php/i', $url)
|
|
) {
|
|
$url = 'http://' . $url;
|
|
}
|
|
// Replace ampersands and single quotes only when displaying.
|
|
if ('display' == $_context) {
|
|
$url = self::wp_kses_normalize_entities($url);
|
|
$url = str_replace('&', '&', $url);
|
|
$url = str_replace("'", ''', $url);
|
|
}
|
|
|
|
if (( false !== strpos($url, '[') ) || ( false !== strpos($url, ']') )) {
|
|
$parsed = wp_parse_url($url);
|
|
$front = '';
|
|
if (isset($parsed['scheme'])) {
|
|
$front .= $parsed['scheme'] . '://';
|
|
} elseif ('/' === $url[0]) {
|
|
$front .= '//';
|
|
}
|
|
|
|
if (isset($parsed['user'])) {
|
|
$front .= $parsed['user'];
|
|
}
|
|
|
|
if (isset($parsed['pass'])) {
|
|
$front .= ':' . $parsed['pass'];
|
|
}
|
|
|
|
if (isset($parsed['user']) || isset($parsed['pass'])) {
|
|
$front .= '@';
|
|
}
|
|
|
|
if (isset($parsed['host'])) {
|
|
$front .= $parsed['host'];
|
|
}
|
|
|
|
if (isset($parsed['port'])) {
|
|
$front .= ':' . $parsed['port'];
|
|
}
|
|
|
|
$end_dirty = str_replace($front, '', $url);
|
|
$end_clean = str_replace(array('[', ']'), array('%5B', '%5D'), $end_dirty);
|
|
$url = str_replace($end_dirty, $end_clean, $url);
|
|
}
|
|
|
|
if ('/' === $url[0]) {
|
|
$good_protocol_url = $url;
|
|
} else {
|
|
if (!is_array($protocols)) {
|
|
$protocols = self::wp_allowed_protocols();
|
|
}
|
|
$good_protocol_url = self::wp_kses_bad_protocol($url, $protocols);
|
|
if (strtolower($good_protocol_url) != strtolower($url)) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filters a string cleaned and escaped for output as a URL.
|
|
*
|
|
* @since 2.3.0
|
|
*
|
|
* @param string $good_protocol_url The cleaned URL to be returned.
|
|
* @param string $original_url The URL prior to cleaning.
|
|
* @param string $_context If 'display', replace ampersands and single quotes only.
|
|
*/
|
|
return $good_protocol_url;
|
|
}
|
|
|
|
/**
|
|
* Removes any invalid control characters in $string.
|
|
*
|
|
* Also removes any instance of the '\0' string.
|
|
*
|
|
* @param string $string The text which is to be purified.
|
|
* @param array<string,mixed> $options Set 'slash_zero' => 'keep' when '\0' is allowed. Default is 'remove'.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function wp_kses_no_null($string, $options = null)
|
|
{
|
|
if (!isset($options['slash_zero'])) {
|
|
$options = array('slash_zero' => 'remove');
|
|
}
|
|
|
|
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $string);
|
|
if ('remove' == $options['slash_zero']) {
|
|
$string = preg_replace('/\\\\+0+/', '', $string);
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Sanitize string from bad protocols.
|
|
*
|
|
* This function removes all non-allowed protocols from the beginning of
|
|
* $string. It ignores whitespace and the case of the letters, and it does
|
|
* understand HTML entities. It does its work in a while loop, so it won't be
|
|
* fooled by a string like "javascript:javascript:alert(57)".
|
|
*
|
|
* @param string $string Content to filter bad protocols from
|
|
* @param string[] $allowed_protocols Allowed protocols to keep
|
|
*
|
|
* @return string Filtered content
|
|
*/
|
|
public static function wp_kses_bad_protocol($string, $allowed_protocols)
|
|
{
|
|
$string = self::wp_kses_no_null($string);
|
|
$iterations = 0;
|
|
do {
|
|
$original_string = $string;
|
|
$string = self::wp_kses_bad_protocol_once($string, $allowed_protocols);
|
|
} while ($original_string != $string && ++$iterations < 6);
|
|
if ($original_string != $string) {
|
|
return '';
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Sanitizes content from bad protocols and other characters.
|
|
*
|
|
* This function searches for URL protocols at the beginning of $string, while
|
|
* handling whitespace and HTML entities.
|
|
*
|
|
* @param string $string Content to check for bad protocols
|
|
* @param string[] $allowed_protocols Allowed protocols
|
|
* @param int $count Optional. Number of times the function
|
|
*
|
|
* @return string Sanitized content
|
|
*/
|
|
public static function wp_kses_bad_protocol_once($string, $allowed_protocols, $count = 1)
|
|
{
|
|
$string2 = preg_split('/:|�*58;|�*3a;/i', $string, 2);
|
|
if (isset($string2[1]) && !preg_match('%/\?%', $string2[0])) {
|
|
$string = trim($string2[1]);
|
|
$protocol = self::wp_kses_bad_protocol_once2($string2[0], $allowed_protocols);
|
|
if ('feed:' == $protocol) {
|
|
if ($count > 2) {
|
|
return '';
|
|
}
|
|
$string = wp_kses_bad_protocol_once($string, $allowed_protocols, ++$count);
|
|
if (empty($string)) {
|
|
return $string;
|
|
}
|
|
}
|
|
$string = $protocol . $string;
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Convert all entities to their character counterparts.
|
|
*
|
|
* This function decodes numeric HTML entities (`A` and `A`).
|
|
* It doesn't do anything with other entities like ä, but we don't
|
|
* need them in the URL protocol whitelisting system anyway.
|
|
*
|
|
* @param string $string Content to change entities
|
|
*
|
|
* @return string Content after decoded entities
|
|
*/
|
|
public static function wp_kses_decode_entities($string)
|
|
{
|
|
$string = preg_replace_callback('/&#([0-9]+);/', array(__CLASS__, '_wp_kses_decode_entities_chr'), $string);
|
|
$string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', array(__CLASS__, '_wp_kses_decode_entities_chr_hexdec'), $string);
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Regex callback for wp_kses_decode_entities()
|
|
*
|
|
* @param string[] $match preg match
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function _wp_kses_decode_entities_chr($match) // phpcs:ignore
|
|
{
|
|
return chr($match[1]); // @phpstan-ignore-line
|
|
}
|
|
|
|
/**
|
|
* Regex callback for wp_kses_decode_entities()
|
|
*
|
|
* @param string[] $match preg match
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function _wp_kses_decode_entities_chr_hexdec($match) // phpcs:ignore
|
|
{
|
|
return chr(hexdec($match[1]));
|
|
}
|
|
|
|
/**
|
|
* Callback for wp_kses_bad_protocol_once() regular expression.
|
|
*
|
|
* This function processes URL protocols, checks to see if they're in the
|
|
* white-list or not, and returns different data depending on the answer.
|
|
*
|
|
* @access private
|
|
*
|
|
* @param string $string URI scheme to check against the whitelist
|
|
* @param string[] $allowed_protocols Allowed protocols
|
|
*
|
|
* @return string Sanitized content
|
|
*/
|
|
public static function wp_kses_bad_protocol_once2($string, $allowed_protocols)
|
|
{
|
|
$string2 = self::wp_kses_decode_entities($string);
|
|
$string2 = preg_replace('/\s/', '', $string2);
|
|
$string2 = self::wp_kses_no_null($string2);
|
|
$string2 = strtolower($string2);
|
|
$allowed = false;
|
|
foreach ((array) $allowed_protocols as $one_protocol) {
|
|
if (strtolower($one_protocol) == $string2) {
|
|
$allowed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($allowed) {
|
|
return "$string2:";
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle maintenance mode for the site.
|
|
*
|
|
* Creates/deletes the maintenance file to enable/disable maintenance mode.
|
|
*
|
|
* @param bool $enable True to enable maintenance mode, false to disable.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function maintenanceMode($enable = false)
|
|
{
|
|
$homePath = SnapIO::trailingslashit(PrmMng::getInstance()->getValue(PrmMng::PARAM_PATH_WP_CORE_NEW));
|
|
if (!is_writable($homePath)) {
|
|
Log::info('CAN\'T ' . ($enable ? 'SET' : 'REMOVE') . ' MAINTENANCE MODE, ROOT FOLDER NOT WRITABLE');
|
|
return;
|
|
}
|
|
|
|
$maintenanceFile = $homePath . '.maintenance';
|
|
$indexFile = $homePath . 'index.html';
|
|
|
|
if (file_exists($indexFile)) {
|
|
$indexContent = file_get_contents($indexFile);
|
|
$manageIndex = (strpos($indexContent, self::MAINTENANCE_INDEX_MARKER) !== false);
|
|
} else {
|
|
$manageIndex = true;
|
|
}
|
|
|
|
if ($enable) {
|
|
Log::info('MAINTENANCE MODE ENABLE');
|
|
if (file_put_contents($maintenanceFile, '<?php $upgrading = ' . time() . '; ?>') == false) {
|
|
Log::info('CAN\'T SET MAINTENANCE MODE FILE \"' . $maintenanceFile . "\"");
|
|
}
|
|
if ($manageIndex && SnapIo::copy(DUPX_INIT . '/assets/maintenance.html', $indexFile) == false) {
|
|
Log::info('CAN\'T SET MAINTENANCE INDEX FILE \"' . $indexFile . "\"");
|
|
}
|
|
} else {
|
|
Log::info('MAINTENANCE MODE DISABLE');
|
|
if (file_exists($maintenanceFile) && unlink($maintenanceFile) == false) {
|
|
Log::info('CAN\'T REMOVE MAINTENANCE MODE FILE \"' . $maintenanceFile . "\"");
|
|
}
|
|
if ($manageIndex && file_exists($indexFile) && unlink($indexFile) == false) {
|
|
Log::info('CAN\'T REMOVE MAINTENANCE INDEX FILE \"' . $indexFile . "\"");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if string is base64 encoded
|
|
*
|
|
* @param string $str input string
|
|
*
|
|
* @return false|string return false if isn't base64 string or decoded string
|
|
*/
|
|
public static function is_base64($str)
|
|
{
|
|
// Check if there are valid base64 characters
|
|
if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $str)) {
|
|
return false;
|
|
}
|
|
|
|
// Decode the string in strict mode and check the results
|
|
$decoded = base64_decode($str, true);
|
|
if (false === $decoded) {
|
|
return false;
|
|
}
|
|
|
|
// Encode the string again
|
|
if (base64_encode($decoded) != $str) {
|
|
return false;
|
|
}
|
|
|
|
return $decoded;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string[] $matches regex match
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function encodeUtf8CharFromRegexMatch($matches)
|
|
{
|
|
if (empty($matches) || !is_array($matches)) {
|
|
return '';
|
|
} else {
|
|
return json_decode('"' . $matches[0] . '"');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* this function escape generic string to prevent security issue.
|
|
* Used to replace string in wp transformer
|
|
*
|
|
* for example
|
|
* abc'" become "abc'\""
|
|
*
|
|
* @param string $str input string
|
|
* @param bool $addQuote if true add " before and after string
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getEscapedGenericString($str, $addQuote = true)
|
|
{
|
|
$result = SnapJson::jsonEncode(trim($str));
|
|
$result = str_replace(array('\/', '$'), array('/', '\\$'), $result);
|
|
$result = preg_replace_callback(
|
|
'/\\\\u[a-fA-F0-9]{4}/m',
|
|
array(
|
|
__CLASS__,
|
|
'encodeUtf8CharFromRegexMatch',
|
|
),
|
|
$result
|
|
);
|
|
if (!$addQuote) {
|
|
$result = substr($result, 1, strlen($result) - 2);
|
|
}
|
|
return $result;
|
|
}
|
|
}
|