5

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"
Community
  • 1
  • 1
Wesley Murch
  • 101,186
  • 37
  • 194
  • 228

4 Answers4

6

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

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

Dave Kok
  • 892
  • 9
  • 19
  • That doesn't prevent the user from overwriting `$_POST` in its entirety again, but interesting approach. +1 – deceze Oct 18 '12 at 12:43
  • Yeah this is actually quite clever! I will give this a go this afternoon. – Wesley Murch Oct 18 '12 at 12:44
  • Indeed, he could even [overload the \[\] operator](http://stackoverflow.com/questions/787692/operator-overloading-in-php) in that new class, if he's using PHP5. – Maxime Morin Oct 18 '12 at 12:45
  • @MaximeMorin: That's some pretty wild stuff, thanks so much for the link, I would have never dreamed that was possible. – Wesley Murch Oct 18 '12 at 12:47
  • I do still wonder about the overwriting aspect, as `$_POST = array()` would disable my previous assignment. [This comment](http://programmers.stackexchange.com/questions/76406/directly-modifying-superglobals#comment135530_76406) indicated that it was a possibility. – Wesley Murch Oct 18 '12 at 12:54
  • Yes but who will be overriding $_POST variable in regular code? Don't spend to time on securing your environment. In the end it is a waste of time. – Dave Kok Oct 18 '12 at 13:14
  • @DaveKok: Thank you for the comment but I've seen it done, even by people I respect. I don't consider this a waste of time as it has been very educational. – Wesley Murch Oct 18 '12 at 13:16
6

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;
    }
}
Baba
  • 94,024
  • 28
  • 166
  • 217
  • This is brilliant, but new territory for me. Everything works great except `$_POST = "Hello World";` (assigning specific keys does trigger the error) - any idea? – Wesley Murch Oct 18 '12 at 13:08
  • @Wesley Thanks .. this can work for all your super globals since they are all arrays – Baba Oct 18 '12 at 13:10
  • I tried adding a `__set` function just for the hell of it but that did not work either, it was still possible to reassign `$_POST/SUPER` in its entirety. How could that be done? – Wesley Murch Oct 18 '12 at 13:13
  • I'd love to know how to accomplish that, it would be the last piece of the puzzle. – Wesley Murch Oct 18 '12 at 13:14
  • Use the `setRequest` method ..... :) you would be able to reassign `$_POST/SUPER` – Baba Oct 18 '12 at 13:16
  • I want `$_POST = "Hello World";` to trigger an error, it seems to not be working even with your edit, but I'm still hacking away at it and flipping through the manual. Everything else seems to be working great! – Wesley Murch Oct 18 '12 at 13:17
  • Same issue, $_POST can still be overwritten, and I have no intent on using a `$SUPER` variable instead (no one will have a clue to use it). I will accept defeat if it is not a possibility. Thank you very much for your help, I will accept your answer this afternoon, but if you find an answer to that piece, please share. – Wesley Murch Oct 18 '12 at 13:31
  • `$_POST` is a variable name and by default it can be overwritten .... they only thing you can do is always check its Integrity with the original once ... In fact you can not even prevent some type conversion – Baba Oct 18 '12 at 13:35
  • If it is not possible, I would remove the part of your answer that suggests it is, where you say "`$_POST['hello'] = "Hello World"; // This would trigger error ;`" – Wesley Murch Oct 18 '12 at 13:36
  • Oh you're right, my mistake - I copied a part of your answer that was edited. Thanks so much. – Wesley Murch Oct 18 '12 at 14:12
2

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.

Paolo Stefan
  • 10,112
  • 5
  • 45
  • 64
1

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.

mario
  • 144,265
  • 20
  • 237
  • 291
  • Thanks a lot, will look at the code in detail later on, but this is very cool - I never imagined it was possible. I was thinking of just using a class with static methods for reading, might as well as long as we're using "superglobals" and goofy syntax, right? Thanks a lot for sharing this. I was thinking of printing notices in dev/debug mode and maybe even as harsh as fatal errors in production mode... silent errors seem dangerous even if they are logged. No chance of preventing `$_POST = 'something';` though, right? – Wesley Murch Oct 18 '12 at 21:50
  • You might be able to utilize `__destruct()` for the latter. But with PHPs garbage collector this will only show up way after the fact; for logging at best. Personally I do like the weird syntax as it visualizes instant sanitization and right where stuff gets accessed. For one project I also use a more rigid setting with fatal errors and exceptions for unfiltered access. So such wrappers do add some flexibility still. – mario Oct 18 '12 at 23:03