214 lines
5.3 KiB
PHP
Executable File
214 lines
5.3 KiB
PHP
Executable File
<?php
|
|
namespace AIOWPS\Firewall;
|
|
|
|
/**
|
|
* A class for accessing constants (including from wp-config) from the firewall
|
|
* Only supports parsing 'defines' that have scalar types: int, float, boolean, string and null
|
|
*/
|
|
class Constants implements \ArrayAccess, \IteratorAggregate {
|
|
|
|
/**
|
|
* The list of constants parsed
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $constants;
|
|
|
|
/**
|
|
* The token part of the token identifier
|
|
*
|
|
* @see https://www.php.net/manual/en/function.token-get-all#refsect1-function.token-get-all-returnvalues
|
|
*/
|
|
const TOKEN = 0;
|
|
|
|
/**
|
|
* The string content of the token identifier
|
|
*
|
|
* @see https://www.php.net/manual/en/function.token-get-all#refsect1-function.token-get-all-returnvalues
|
|
*/
|
|
const CONTENT = 1;
|
|
|
|
/**
|
|
* The line number of the token identifier
|
|
*
|
|
* @see https://www.php.net/manual/en/function.token-get-all#refsect1-function.token-get-all-returnvalues
|
|
*/
|
|
const LINE = 2;
|
|
|
|
/**
|
|
* Offset for define's name [ define(NAME, VALUE); ]
|
|
*/
|
|
const DEFINE_NAME_OFFSET = 2;
|
|
|
|
/**
|
|
* Offset for define's value [ define(NAME, VALUE); ]
|
|
*/
|
|
const DEFINE_VALUE_OFFSET = 4;
|
|
|
|
/**
|
|
* Constructs our object
|
|
*/
|
|
public function __construct() {
|
|
$this->constants = array();
|
|
$this->populate_constants();
|
|
}
|
|
|
|
/**
|
|
* Populates our internal constant array with the defines from wp-config
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function populate_constants() {
|
|
|
|
$wpconfig = Utility::get_wpconfig_path();
|
|
|
|
clearstatcache();
|
|
if (!file_exists($wpconfig)) return;
|
|
|
|
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- WP isn't loaded. WP_Filesystem cannot be used.
|
|
$source = file_get_contents($wpconfig);
|
|
|
|
if (false === $source) return;
|
|
|
|
$tokens = token_get_all($source);
|
|
|
|
//Filter out any unwanted tokens
|
|
$tokens = array_values(array_filter($tokens, function($token) {
|
|
|
|
//All tokens that are not arrays are allowed
|
|
if (!is_array($token)) return true;
|
|
|
|
$unwanted_tokens = array(
|
|
'T_COMMENT',
|
|
'T_WHITESPACE',
|
|
'T_DOC_COMMENT',
|
|
);
|
|
|
|
return (!in_array(token_name($token[self::TOKEN]), $unwanted_tokens));
|
|
}));
|
|
|
|
$token_count = count($tokens);
|
|
for ($i = 0; $i < $token_count; $i++) {
|
|
|
|
$current = $tokens[$i];
|
|
|
|
if (!is_array($current)) continue;
|
|
|
|
if ('T_STRING' === token_name($current[self::TOKEN]) && 'define' === strtolower($current[self::CONTENT])) {
|
|
|
|
// Name of the define without the surrounding quotes
|
|
$name = substr($tokens[$i + self::DEFINE_NAME_OFFSET][self::CONTENT], 1, -1);
|
|
|
|
// Grabs the value of the define
|
|
$value = $tokens[$i + self::DEFINE_VALUE_OFFSET];
|
|
|
|
if (!is_array($value)) continue;
|
|
|
|
// We need to interpret the data type of the define's value
|
|
switch (token_name($value[self::TOKEN])) {
|
|
case 'T_CONSTANT_ENCAPSED_STRING':
|
|
$this->constants[$name] = substr($value[self::CONTENT], 1, -1);
|
|
break;
|
|
case 'T_LNUMBER':
|
|
$this->constants[$name] = intval($value[self::CONTENT]);
|
|
break;
|
|
case 'T_DNUMBER':
|
|
$this->constants[$name] = floatval($value[self::CONTENT]);
|
|
break;
|
|
case 'T_STRING':
|
|
$this->constants[$name] = filter_var($value[self::CONTENT], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
break;
|
|
default:
|
|
continue 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Access the constants as properties
|
|
*
|
|
* @param string $name
|
|
* @return mixed
|
|
*/
|
|
public function __get($name) {
|
|
return $this[$name];
|
|
}
|
|
|
|
/**
|
|
* Iterate over the constants
|
|
*
|
|
* @return iterable
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public function getIterator() {
|
|
foreach ($this->constants as $name => $value) yield $name => $value;
|
|
foreach (get_defined_constants() as $name => $value) yield $name => $value;
|
|
}
|
|
|
|
/**
|
|
* Gives us array access to the constants
|
|
*
|
|
* @param mixed $offset
|
|
* @return mixed
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public function offsetGet($offset) {
|
|
if (defined($offset)) {
|
|
return constant($offset);
|
|
} elseif (isset($this->constants[$offset])) {
|
|
return $this->constants[$offset];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the constant exists
|
|
*
|
|
* @param mixed $offset
|
|
* @return boolean
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public function offsetExists($offset) {
|
|
return defined($offset) || isset($this->constants[$offset]);
|
|
}
|
|
|
|
/**
|
|
* Check if constant exists
|
|
*
|
|
* @param string $name
|
|
* @return boolean
|
|
*/
|
|
public function __isset($name) {
|
|
return $this->offsetExists($name);
|
|
}
|
|
|
|
/**
|
|
* Sets the constant. This is disabled as we want it read-only
|
|
*
|
|
* @param mixed $offset
|
|
* @param mixed $value
|
|
* @return void
|
|
* @throws \Exception - Throws an exception if called to ensure it's read-only.
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public function offsetSet($offset, $value) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Needed for ArrayAccess interface but not used by us as we require read-only
|
|
throw new \Exception('Constants are read-only.');
|
|
}
|
|
|
|
/**
|
|
* Unsets the constant. This is disabled as we want it read-only
|
|
*
|
|
* @param mixed $offset
|
|
* @return void
|
|
* @throws \Exception - Throws an exception if called to ensure it's read-only.
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public function offsetUnset($offset) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Needed for ArrayAccess interface but not used by us as we require read-only
|
|
throw new \Exception('Constants are read-only.');
|
|
}
|
|
|
|
}
|