Question

I have this framework project kind of on the backburner where I want to enforce the use of an Input class to access all superglobals like $_POST, $_GET and $_SERVER. A recent question here reminded me about it.

The class will do a little cleanup of the keys to make sure there's nothing malicious or unexpected, and provide a way to access items without the hassle of using isset() each time. It may do other things depending on configuration, and will possibly clear the superglobals as well. I also don't like the fact that superglobals are not read-only, I want to enforce integrity in the values. I want this class to be used exclusively, and want to warn developers when it is not used.

My question is this, and I fear the answer is "No":

Is it possible to to trigger an error when one of the superglobals is accessed? For example:

$myvar = $_POST['key'];
// Prints "Error: POST cannot be accessed directly, use the Input class instead"

Or when writing to superglobals?:

$_POST['key'] = 'myvalue';
// Prints "Error: POST data cannot be modified"
Was it helpful?

Solution

You can use ArrayAccess

Example 1 :

$_POST = new SUPER($_POST);
$_POST['hello'] = "Hello World"; // This would trigger error ;

Example 2 : a.php?var=1&var2=2

$_GET = new SUPER($_GET);
echo $_GET['var'] ; // returns 1
echo $_GET['var2'] ; // returns 2

$_GET['var3'] = 2 ; //return error

Class Used

class SUPER implements \ArrayAccess {
    private $request = array();

    public function __construct(array $array) {
        $this->request = $array;
    }

    public function setRequest(array $array) {
        $this->request = $array;
    }

    public function offsetSet($offset, $value) {
        trigger_error("Error: SUPER GLOBAL data cannot be modified");
    }

    public function offsetExists($offset) {
        return isset($this->request[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->request[$offset]);
    }

    public function offsetGet($offset) {
        return isset($this->request[$offset]) ? $this->request[$offset] : null;
    }
}

OTHER TIPS

How about assigning an object to the $_POST variable and using magic methods?

$_POST = new %your-class%();

It does not trigger anything more than a notice, but if you first copy all your superglobals keys/values inside an object and then do:

unset($_GET,$_POST,$_SERVER);

after that, any read access to those superglobals will simply fail. To forbid writing, you can instance an object of your choice over these variables (i.e. with name $_GET, $_POST, $_SERVER). To keep these accessible via the [$key] array operator, they should be instances of objects implementing the ArrayAccess interface.

This is basically what @Baba already showcased, but I've been using a similar input wrapper for a few projects. It's suited for small projects very much, but admittedly I still have to overcome usage reluctance. It simplifies sanitizing and auditing however for sure.

http://sourceforge.net/p/php7framework/svn/66/tree/trunk/php7/input.php?force=True
http://sourceforge.net/p/php7framework/wiki/input/

The ArrayAccess approach is all you need. To prevent input injection at runtime or overwriting offsetSet is enough. Though I'm just printing out notices, but still allow it.

Basically it's for sanitizing however. Any raw access to e.g. $_REQUEST["key"] will go through a default filter for example, but you can also simply invoke various filter chains at runtime:

 print $_POST->html->text["comment"];

Lately I've been allowing a restrained register_globals workaorund, localize multiple variables at once. With PHP 5.4 syntax it looks quite funny:

 extract( $_REQUEST->list->text[[ title, id, email ]] );
 // implicit undef-constant notices here ^^ of course

If you just wrap $_GET, $_POST, $_REQUEST at startup you have already accomplished your goal. The only syntactic drawback is that you can no longer use empty($_POST), all other raw array accesses are still permitted by such wrappers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top