Files
Froxlor/lib/Froxlor/PhpHelper.php
2022-04-20 15:09:19 +02:00

427 lines
11 KiB
PHP

<?php
namespace Froxlor;
class PhpHelper
{
private static $sort_key = 'id';
private static $sort_type = SORT_STRING;
/**
* sort an array by either natural or string sort and a given index where the value for comparison is found
*
* @param array $list
* @param string $key
*
* @return boolean
*/
public static function sortListBy(&$list, $key = 'id')
{
self::$sort_type = Settings::Get('panel.natsorting') == 1 ? SORT_NATURAL : SORT_STRING;
self::$sort_key = $key;
return usort($list, array(
'self',
'sortListByGivenKey'
));
}
private static function sortListByGivenKey($a, $b)
{
if (self::$sort_type == SORT_NATURAL) {
return strnatcasecmp($a[self::$sort_key], $b[self::$sort_key]);
}
return strcasecmp($a[self::$sort_key], $b[self::$sort_key]);
}
/**
* Wrapper around htmlentities to handle arrays, with the advantage that you
* can select which fields should be handled by htmlentities
*
* @param array $subject
* The subject array
* @param string $fields
* The fields which should be checked for, separated by spaces
* @param int $quote_style
* See php documentation about this
* @param string $charset
* See php documentation about this
*
* @return array The array with htmlentitie'd strings
* @author Florian Lippert <flo@syscp.org>
*/
public static function htmlentitiesArray($subject, $fields = '', $quote_style = ENT_QUOTES, $charset = 'UTF-8')
{
if (is_array($subject)) {
if (! is_array($fields)) {
$fields = self::arrayTrim(explode(' ', $fields));
}
foreach ($subject as $field => $value) {
if ((! is_array($fields) || empty($fields)) || (is_array($fields) && ! empty($fields) && in_array($field, $fields))) {
// Just call ourselve to manage multi-dimensional arrays
$subject[$field] = self::htmlentitiesArray($subject[$field], $fields, $quote_style, $charset);
}
}
} elseif (!empty($subject)) {
$subject = htmlentities($subject, $quote_style, $charset);
}
return $subject;
}
/**
* Replaces Strings in an array, with the advantage that you
* can select which fields should be str_replace'd
*
* @param
* mixed String or array of strings to search for
* @param
* mixed String or array to replace with
* @param
* array The subject array
* @param
* string The fields which should be checked for, separated by spaces
* @return array The str_replace'd array
* @author Florian Lippert <flo@syscp.org>
*/
public static function strReplaceArray($search, $replace, $subject, $fields = '')
{
if (is_array($subject)) {
$fields = self::arrayTrim(explode(' ', $fields));
foreach ($subject as $field => $value) {
if ((! is_array($fields) || empty($fields)) || (is_array($fields) && ! empty($fields) && in_array($field, $fields))) {
$subject[$field] = str_replace($search, $replace, $subject[$field]);
}
}
} else {
$subject = str_replace($search, $replace, $subject);
}
return $subject;
}
/**
* froxlor php error handler
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
*
* @return void|boolean
*/
public static function phpErrHandler($errno, $errstr, $errfile, $errline, $errcontext = array())
{
if (! (error_reporting() & $errno)) {
// This error code is not included in error_reporting
return;
}
if (! isset($_SERVER['SHELL']) || (isset($_SERVER['SHELL']) && $_SERVER['SHELL'] == '')) {
global $theme;
// fallback
if (empty($theme)) {
$theme = "Sparkle";
}
// prevent possible file-path-disclosure
$errfile = str_replace(\Froxlor\Froxlor::getInstallDir(), "", $errfile);
// if we're not on the shell, output a nicer error-message
$err_hint = file_get_contents(\Froxlor\Froxlor::getInstallDir() . '/templates/' . $theme . '/misc/phperrornice.tpl');
// replace values
$err_hint = str_replace("<TEXT>", '#' . $errno . ' ' . $errstr, $err_hint);
$err_hint = str_replace("<DEBUG>", $errfile . ':' . $errline, $err_hint);
// show
echo $err_hint;
// return true to ignore php standard error-handler
return true;
}
// of on shell, use the php standard error-handler
return false;
}
public static function loadConfigArrayDir()
{
// Workaround until we use gettext
global $lng, $theme;
// we now use dynamic function parameters
// so we can read from more than one directory
// and still be valid for old calls
$numargs = func_num_args();
if ($numargs <= 0) {
return null;
}
// variable that holds all dirs that will
// be parsed for inclusion
$configdirs = array();
// if one of the parameters is an array
// we assume that this is a list of
// setting-groups to be selected
$selection = null;
for ($x = 0; $x < $numargs; $x ++) {
$arg = func_get_arg($x);
if (is_array($arg) && isset($arg[0])) {
$selection = $arg;
} else {
$configdirs[] = $arg;
}
}
$data = array();
$data_files = array();
$has_data = false;
foreach ($configdirs as $data_dirname) {
if (is_dir($data_dirname)) {
$data_dirhandle = opendir($data_dirname);
while (false !== ($data_filename = readdir($data_dirhandle))) {
if ($data_filename != '.' && $data_filename != '..' && $data_filename != '' && substr($data_filename, - 4) == '.php') {
$data_files[] = $data_dirname . $data_filename;
}
}
$has_data = true;
}
}
if ($has_data) {
sort($data_files);
foreach ($data_files as $data_filename) {
$data = array_merge_recursive($data, include $data_filename);
}
}
// if we have specific setting-groups
// to select, we'll handle this here
// (this is for multiserver-client settings)
$_data = array();
if ($selection != null && is_array($selection) && isset($selection[0])) {
$_data['groups'] = array();
foreach ($data['groups'] as $group => $data) {
if (in_array($group, $selection)) {
$_data['groups'][$group] = $data;
}
}
$data = $_data;
}
return $data;
}
/**
* ipv6 aware gethostbynamel function
*
* @param string $host
* @param boolean $try_a
* default true
* @return boolean|array
*/
public static function gethostbynamel6($host, $try_a = true)
{
$dns6 = @dns_get_record($host, DNS_AAAA);
if (!is_array($dns6)) {
// no record or failed to check
$dns6 = [];
}
if ($try_a == true) {
$dns4 = @dns_get_record($host, DNS_A);
if (!is_array($dns4)) {
// no record or failed to check
$dns4 = [];
}
$dns = array_merge($dns4, $dns6);
} else {
$dns = $dns6;
}
$ips = array();
foreach ($dns as $record) {
if ($record["type"] == "A") {
// always use compressed ipv6 format
$ip = inet_ntop(inet_pton($record["ip"]));
$ips[] = $ip;
}
if ($record["type"] == "AAAA") {
// always use compressed ipv6 format
$ip = inet_ntop(inet_pton($record["ipv6"]));
$ips[] = $ip;
}
}
if (count($ips) < 1) {
return false;
} else {
return $ips;
}
}
/**
* Function randomStr
*
* generate a pseudo-random string of bytes
*
* @param int $length
*
* @return string
*/
public static function randomStr($length)
{
if (version_compare(PHP_VERSION, '7.0.0') >= 0) {
return random_bytes($length);
} elseif (function_exists('openssl_random_pseudo_bytes')) {
return openssl_random_pseudo_bytes($length);
} else {
$pr_bits = '';
$fp = @fopen('/dev/urandom', 'rb');
if ($fp !== false) {
$pr_bits .= @fread($fp, $length);
@fclose($fp);
} else {
$pr_bits = substr(rand(time(), getrandmax()) . rand(time(), getrandmax()), 0, $length);
}
return $pr_bits;
}
}
/**
* Return human readable sizes
*
* @param int $size
* size in bytes
* @param string $max
* maximum unit
* @param string $system
* 'si' for SI, 'bi' for binary prefixes
*
* @param
* string
*/
public static function sizeReadable($size, $max = null, $system = 'si', $retstring = '%01.2f %s')
{
// Pick units
$systems = array(
'si' => array(
'prefix' => array(
'B',
'KB',
'MB',
'GB',
'TB',
'PB'
),
'size' => 1000
),
'bi' => array(
'prefix' => array(
'B',
'KiB',
'MiB',
'GiB',
'TiB',
'PiB'
),
'size' => 1024
)
);
$sys = isset($systems[$system]) ? $systems[$system] : $systems['si'];
// Max unit to display
$depth = count($sys['prefix']) - 1;
if ($max && false !== $d = array_search($max, $sys['prefix'])) {
$depth = $d;
}
// Loop
$i = 0;
while ($size >= $sys['size'] && $i < $depth) {
$size /= $sys['size'];
$i ++;
}
return sprintf($retstring, $size, $sys['prefix'][$i]);
}
/**
* Replaces all occurrences of variables defined in the second argument
* in the first argument with their values.
*
* @param string $text
* The string that should be searched for variables
* @param array $vars
* The array containing the variables with their values
*
* @return string The submitted string with the variables replaced.
*/
public static function replaceVariables($text, $vars)
{
$pattern = "/\{([a-zA-Z0-9\-_]+)\}/";
$matches = array();
if (count($vars) > 0 && preg_match_all($pattern, $text, $matches)) {
for ($i = 0; $i < count($matches[1]); $i ++) {
$current = $matches[1][$i];
if (isset($vars[$current])) {
$var = $vars[$current];
$text = str_replace("{" . $current . "}", $var, $text);
}
}
}
$text = str_replace('\n', "\n", $text);
return $text;
}
/**
* Returns array with all empty-values removed
*
* @param array $source
* The array to trim
* @return array The trim'med array
*/
public static function arrayTrim($source)
{
$returnval = array();
if (is_array($source)) {
$source = array_map('trim', $source);
$returnval = array_filter($source, function ($value) {
return $value !== '';
});
} else {
$returnval = $source;
}
return $returnval;
}
/**
* function to check a super-global passed by reference
* so it gets automatically updated
*
* @param array $global
* @param \voku\helper\AntiXSS $antiXss
*/
public static function cleanGlobal(&$global, &$antiXss)
{
$ignored_fields = [
'system_default_vhostconf',
'system_default_sslvhostconf',
'system_apache_globaldiropt',
'specialsettings',
'ssl_specialsettings',
'default_vhostconf_domain',
'ssl_default_vhostconf_domain',
'filecontent'
];
if (isset($global) && ! empty($global)) {
$tmp = $global;
foreach ($tmp as $index => $value) {
if (!in_array($index, $ignored_fields)) {
$global[$index] = $antiXss->xss_clean($value);
}
}
}
}
}