Skip to content

Commit

Permalink
Cleaned up Sanitizer, including adding defaults
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesread committed Aug 27, 2023
1 parent 631ae2d commit 5093d4a
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 84 deletions.
111 changes: 77 additions & 34 deletions src/main/php/libAllure/Sanitizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,46 @@

namespace libAllure;

/**
* Sanitizes and filters input.
*
* This class has an unusual history, and the first thing you will probably ask
* is why on earth this class exists when PHP has filter_ functions.
*
* It looks like PHP's filter_ function were added in PHP 5.2 (~2006), yet
* this class was probably written around2005-2008 - and PHP 5.2 either probably
* was not available on my server, or I just didn't know about the filter_
* functions.
*
* However, the filter_ functions interface is incredibly goofy (array of
* $options, etc), so this class has now been re-written as a wrapper around
* the filter_ functions.
*/
class Sanitizer
{
public $filterAllowUndefined = true;
public $onUndefinedDoVariableHunt = false;

private const INPUT_GET = 1;
private const INPUT_POST = 2;
private const INPUT_REQUEST = 3;
private const INPUT_SERVER = 4;
private const INPUT_LITERAL = 5;
public const INPUT_GET = 1;
public const INPUT_POST = 2;
public const INPUT_REQUEST = 3; // Not available in PHP's filter functions.
public const INPUT_SERVER = 4;
public const INPUT_COOKIE = 5;

public const FORMAT_FOR_DB = 1;
public const FORMAT_FOR_HTML = 2;
public const FORMAT_FOR_ALL = 64;

private $inputSource = self::INPUT_REQUEST;
private $variableNamePrefixes = array ('form');

private static $instance;

/**
* The constructor is still public as it's quite likely that users will want
* to create instances of this class with different options. This singleton
* method is useful for getting an instance with sane defaults.
*/
public static function getInstance()
{
if (self::$instance == null) {
Expand All @@ -57,32 +79,41 @@ public function setInputSource($inputSource)
$this->inputSource = $inputSource;
}

private function getInput($name)
private function getInputSourceArray(): array
{
switch ($this->inputSource) {
case self::INPUT_GET:
$source = $_GET;
break;
case self::INPUT_POST:
$source = $_POST;
break;
case self::INPUT_REQUEST:
$source = $_REQUEST;
break;
case self::INPUT_SERVER:
$source = $_SERVER;
break;
case self::INPUT_LITERAL:
return $name;
case self::INPUT_GET: return $_GET;
case self::INPUT_POST: return $_POST;
case self::INPUT_REQUEST: return $_REQUEST;
case self::INPUT_SERVER: return $_SERVER;
case self::INPUT_COOKIE: return $_COOKIE;
default:
throw new \Exception('Invalid input source');
}
}

public function hasInput($name): bool
{
return $this->getInput($name) !== null;
}

private function getInput($name)
{
$source = $this->getInputSourceArray();

if (isset($source[$name])) {
return $source[$name];
} else {
return $this->variableHunt($source, $name);
}

if ($this->onUndefinedDoVariableHunt) {
$val = $this->variableHunt($source, $name);
}

if (!$this->filterAllowUndefined) {
throw new \Exception('Input variable not found: ' . $name);
}

return null;
}

private function variableHunt(array $source, $name)
Expand All @@ -93,11 +124,7 @@ private function variableHunt(array $source, $name)
}
}

if ($this->filterAllowUndefined) {
return false;
} else {
throw new \Exception('Input variable not found: ' . $name);
}
return false;
}

public function filterId()
Expand Down Expand Up @@ -167,13 +194,20 @@ public function filterNumeric($content)
return $content;
}

public function filterString($name)
public function filterString($name, $default = null): mixed
{
return (string) $this->getInput($name);
return $this->filterInputString($name, $default);
}

public function filterFilepath()
public function filterInputString($name, $default = null): mixed
{
$v = $this->getInput($name);

if (is_string($v)) {
return filter_var($v, FILTER_UNSAFE_RAW);
} else {
return $default;
}
}

public function escapeStringForClean($content)
Expand All @@ -187,7 +221,9 @@ public function escapeStringForClean($content)

public function escapeStringForDatabase($content)
{
return $this->escapeStringForClean($content);
trigger_error('Method ' . __METHOD__ . ' is deprecated', E_USER_DEPRECATED);

return null;
}

public function escapeStringForHtml($content)
Expand All @@ -203,7 +239,6 @@ public function escapeStringForConsole($content)
return $content;
}


public function formatStringForDatabase($content)
{
return $this->escapeStringForDatabase($content);
Expand Down Expand Up @@ -241,10 +276,18 @@ public function formatBool($content)
}
}

public function filterEnum($name, $accepted, $default = null)
public function filterEnum($name, array $accepted, $default = null)
{
$value = $this->filterString($name);
return $this->filterInputEnum($name, $accepted, $default);
}

public function filterInputEnum($name, array $accepted, $default)
{
return $this->filterVariableEnum($this->filterInputString($name), $accepted, $default);
}

public function filterVariableEnum($value, array $accepted, $default = null)
{
if (in_array($value, $accepted)) {
return $value;
} else {
Expand Down
120 changes: 70 additions & 50 deletions src/test/php/SanitizerTest.php
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
<?php

require_once 'common.php';

use \libAllure\Sanitizer;
use \PHPUnit\Framework\TestCase;

class SanitizerTest extends TestCase {
private $sanitizer;

protected function setUp(): void {
$this->sanitizer = Sanitizer::getInstance();
}

public function testFormatBool() {
$this->assertTrue($this->sanitizer->formatBool(1));
$this->assertTrue($this->sanitizer->formatBool(true));
$this->assertTrue($this->sanitizer->formatBool('true'));
$this->assertTrue($this->sanitizer->formatBool('false'));
$this->assertFalse($this->sanitizer->formatBool(false));
}

public function testFormatNumericAsHex() {
$this->assertEquals('a', $this->sanitizer->formatNumericAsHex(10));
$this->assertEquals('a', $this->sanitizer->formatNumericAsHex(0xA));
$this->assertEquals('cafe', $this->sanitizer->formatNumericAsHex(0xCAFE));
}

public function testFilterUint() {
$_REQUEST['test'] = '0';
$this->assertEquals(0, $this->sanitizer->filterUint('test'));
}

public function testFilterEnum() {
unset($_REQUEST['test']);
$this->assertEquals('Bananas', $this->sanitizer->filterEnum('test', array('Apples', 'Bananas', 'Chestnuts'), 'Bananas'));

$_REQUEST['test'] = 'Bananas';
$this->assertEquals('Bananas', $this->sanitizer->filterEnum('test', array('Apples', 'Bananas', 'Chestnuts'), 'Bananas'));

$_REQUEST['test'] = 'Waffles';
$this->assertEquals('Bananas', $this->sanitizer->filterEnum('test', array('Apples', 'Bananas', 'Chestnuts'), 'Bananas'));
}

public function testFilterNumeric() {
$this->assertNotNull($this->sanitizer->filterNumeric('0101'));
}
}

?>
<?php

require_once 'common.php';

use \libAllure\Sanitizer;
use \PHPUnit\Framework\TestCase;

class SanitizerTest extends TestCase {
private $sanitizer;

protected function setUp(): void {
$this->sanitizer = Sanitizer::getInstance();
}

public function testFormatBool() {
$this->assertTrue($this->sanitizer->formatBool(1));
$this->assertTrue($this->sanitizer->formatBool(true));
$this->assertTrue($this->sanitizer->formatBool('true'));
$this->assertTrue($this->sanitizer->formatBool('false'));
$this->assertFalse($this->sanitizer->formatBool(false));
}

public function testFormatNumericAsHex() {
$this->assertEquals('a', $this->sanitizer->formatNumericAsHex(10));
$this->assertEquals('a', $this->sanitizer->formatNumericAsHex(0xA));
$this->assertEquals('cafe', $this->sanitizer->formatNumericAsHex(0xCAFE));
}

public function testFilterUint()
{
$_REQUEST['test'] = '0';
$this->assertEquals(0, $this->sanitizer->filterUint('test'));
}

public function testFilterString()
{
$_REQUEST['foo'] = 'bar';

$this->assertEquals('bar', $this->sanitizer->filterInputString('foo'));

$this->assertSame(null, $this->sanitizer->filterInputString('foo2'));

$this->assertSame('Snake', $this->sanitizer->filterString('har', 'Snake'));
}

public function testHasInputs()
{
$this->assertFalse($this->sanitizer->hasInput('blat'));

$_REQUEST['foo'] = 'bar';
$this->assertTrue($this->sanitizer->hasInput('foo'));
}

public function testFilterEnum() {
unset($_REQUEST['test']);
$this->assertEquals('Bananas', $this->sanitizer->filterEnum('test', array('Apples', 'Bananas', 'Chestnuts'), 'Bananas'));

$_REQUEST['test'] = 'Bananas';
$this->assertEquals('Bananas', $this->sanitizer->filterEnum('test', array('Apples', 'Bananas', 'Chestnuts'), 'Bananas'));

$_REQUEST['test'] = 'Waffles';
$this->assertEquals('Bananas', $this->sanitizer->filterEnum('test', array('Apples', 'Bananas', 'Chestnuts'), 'Bananas'));
}

public function testFilterNumeric() {
$this->assertNotNull($this->sanitizer->filterNumeric('0101'));
}
}

?>

0 comments on commit 5093d4a

Please sign in to comment.