JEMBOT MAWOT Bypass Shell
<?php
namespace Props;
use Psr\Container\ContainerInterface;
/**
* Container holding values which can be resolved upon reading and optionally stored and shared
* across reads.
*
* Values are read/set as properties.
*
* @note see scripts/example.php
*/
class Container implements ContainerInterface
{
/**
* @var callable[]
*/
private $factories = array();
/**
* @var array
*/
private $cache = array();
/**
* Fetch a value.
*
* @param string $name
* @return mixed
* @throws FactoryUncallableException|ValueUnresolvableException|NotFoundException
*/
public function __get($name)
{
if (array_key_exists($name, $this->cache)) {
return $this->cache[$name];
}
$value = $this->build($name);
$this->cache[$name] = $value;
return $value;
}
/**
* {@inheritdoc}
*/
public function get($name)
{
return $this->__get($name);
}
/**
* Set a value.
*
* @param string $name
* @param mixed $value
* @throws \InvalidArgumentException
*/
public function __set($name, $value)
{
if ($value instanceof \Closure) {
$this->setFactory($name, $value);
return;
}
$this->cache[$name] = $value;
unset($this->factories[$name]);
}
/**
* Set a value to be later returned as is. You only need to use this if you wish to store
* a Closure.
*
* @param string $name
* @param mixed $value
* @throws \InvalidArgumentException
*/
public function setValue($name, $value)
{
unset($this->factories[$name]);
$this->cache[$name] = $value;
}
/**
* @param string $name
*/
public function __unset($name)
{
unset($this->cache[$name]);
unset($this->factories[$name]);
}
/**
* @param string $name
* @return bool
*/
public function __isset($name)
{
return array_key_exists($name, $this->factories) || array_key_exists($name, $this->cache);
}
/**
* {@inheritdoc}
*/
public function has($name)
{
return $this->__isset($name);
}
/**
* Fetch a freshly-resolved value.
*
* @param string $method method name must start with "new_"
* @param array $args
* @return mixed
* @throws BadMethodCallException
*/
public function __call($method, $args)
{
if (0 !== strpos($method, 'new_')) {
throw new BadMethodCallException("Method name must begin with 'new_'");
}
return $this->build(substr($method, 4));
}
/**
* Can we fetch a new value via new_$name()?
*
* @param string $name
* @return bool
*/
public function hasFactory($name)
{
return array_key_exists($name, $this->factories);
}
/**
* Set a factory to generate a value when the container is read.
*
* @param string $name The name of the value
* @param callable $factory Factory for the value
* @throws FactoryUncallableException
*/
public function setFactory($name, $factory)
{
if (!is_callable($factory, true)) {
throw new FactoryUncallableException('$factory must appear callable');
}
unset($this->cache[$name]);
$this->factories[$name] = $factory;
}
/**
* Get an already-set factory callable (Closure, invokable, or callback)
*
* @param string $name The name of the value
* @return callable
* @throws NotFoundException
*/
public function getFactory($name)
{
if (!array_key_exists($name, $this->factories)) {
throw new NotFoundException("No factory available for: $name");
}
return $this->factories[$name];
}
/**
* Add a function that gets applied to the return value of an existing factory
*
* @note A cached value (from a previous property read) will thrown away. The next property read
* (and all new_NAME() calls) will call the original factory.
*
* @param string $name The name of the value
* @param callable $extender Function that is applied to extend the returned value
* @return \Closure
* @throws FactoryUncallableException|NotFoundException
*/
public function extend($name, $extender)
{
if (!is_callable($extender, true)) {
throw new FactoryUncallableException('$extender must appear callable');
}
if (!array_key_exists($name, $this->factories)) {
throw new NotFoundException("No factory available for: $name");
}
$factory = $this->factories[$name];
$newFactory = function (Container $c) use ($extender, $factory) {
return call_user_func($extender, call_user_func($factory, $c), $c);
};
$this->setFactory($name, $newFactory);
return $newFactory;
}
/**
* Get all keys available
*
* @return string[]
*/
public function getKeys()
{
$keys = array_keys($this->cache) + array_keys($this->factories);
return array_unique($keys);
}
/**
* Build a value
*
* @param string $name
* @return mixed
* @throws FactoryUncallableException|ValueUnresolvableException|NotFoundException
*/
private function build($name)
{
if (!array_key_exists($name, $this->factories)) {
throw new NotFoundException("Missing value: $name");
}
$factory = $this->factories[$name];
if (is_callable($factory)) {
try {
return call_user_func($factory, $this);
} catch (\Exception $e) {
throw new ValueUnresolvableException("Factory for '$name' threw an exception.", 0, $e);
}
}
$msg = "Factory for '$name' was uncallable";
if (is_string($factory)) {
$msg .= ": '$factory'";
} elseif (is_array($factory)) {
if (is_string($factory[0])) {
$msg .= ": '{$factory[0]}::{$factory[1]}'";
} else {
$msg .= ": " . get_class($factory[0]) . "->{$factory[1]}";
}
}
throw new FactoryUncallableException($msg);
}
}
xxxxx1.0, XXX xxxx