Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: is there a safe way to extract($_POST)

Tags:

php

Is there a safe way to auto assign the keys in a posted array? Below are two examples of wrong ways...

foreach( $_POST as $key => $value ) {
     $$key = $value;
}

or

extract($_POST)

Is there a better way, or is it best to code:

$foo = $_POST('foo');
$bar = $_POST('bar');
....

for all 50 inputs on my form?

(the posted info will be inserted into a database).

like image 292
superUntitled Avatar asked Mar 15 '11 01:03

superUntitled


2 Answers

One more cautious way of extracting all input fields at once is:

extract( $_POST, EXTR_OVERWRITE, "form_" );

This way all your input variables will be called $form_foo and $form_bar at least. Avoid doing that in the global scope - not because global is evil, but because nobody ever cleans up there.

However, since mostly you do that in a localized scope, you can as well apply htmlentities if for example you need all fields just for output:

extract(array_map("htmlspecialchars", $_POST), EXTR_OVERWRITE, "form_");
like image 169
mario Avatar answered Oct 05 '22 06:10

mario


The answer to your question depends on the computer, language, and security knowledge of the programmer. The opening sequence of processing $_POST is kind of like the opening move in a game of chess. Many use foreach loops without realizing that foreach will make a copy of the contents of $_POST the way you have it used (Programming PHP: Chapter 5, p.128-129). Wouldn't it be funny if you caused a buffer overflow simply by using foreach!

One commenter implied that everything should just be worked with inside of the $_POST superglobal. There are some merits to this... However, forgetting cache memory for a moment, access to array values is slower than direct access to a variable.

Since you have fifty (50) controls to validate (with potentially large contents), I might not want to take that array access performance hit more than 50 times (the original access hits). Moreover, if you are concerned about writing secure input validation routines, keeping your dirty laundry (non-validated input) separate from your clean (validated input) laundry is a good idea. That said, you may need a clean array anyway (hence the $_POST advocate's response), but at least you are reducing risk in the process by keeping the hopefully good separate from the potentially bad.

Is there a safe way to auto assign the keys in a posted array?

I might start like this:

Function library for this example.


function all_controls_submitted($controls) {
  $postKeys = array_keys($_POST);
  foreach($controls as $key) {
    if(! array_key_exists($key, $postKeys)) {
      return false;
    }
  }
  return true;
}

function all_controls_set($controls) {
  foreach($controls as $key) {
    if(! isset($_POST[$key])) {
      return false;
    }
  }
  return true;
}

if(is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER[REQUEST_URI]) && $_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/contact.php') {
  $newForm = true;
} elseif (is_array($_SERVER) && isset($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/contact.php') {
  $newForm = false;
  $controlNames = array('firstName', 'lastName', 'e-mail', 'company', 'subject', 'message', 'captcha');
  define('NUM_CONTROLS_EXPECTED', count($controlNames)); //Seven (7)
  if(is_array($_POST) && count($_POST) === NUM_CONTROLS_EXPECTED && all_controls_submitted($controlNames) && all_controls_set($controlNames)) {
    //Begin input validation
  }
} else {
  header('location: http://www.nsa.gov');
}

Notice that I prep things with the $controlNames array, therefore I do not have to ask $_POST for the keys. After all, I should know them! :-) The two user-defined functions, all_controls_submitted() and all_controls_set() are two fundamental questions that should be asked before trying to use any values in $_POST (I say, anyway). Admittedly, I do use $_POST in all_controls_submitted(), but only to obtain the names of the controls submitted, not the values.

$postKeys = array_keys($_POST);

However, who is to say that the control names themselves could not be poisonous and in need of input validation?!! Same goes for values in $_SERVER. See, a chess game.

Is there a safe way to auto assign the keys in a posted array? I cannot tell you for certain, but perhaps something like the code above could help? You'd have the keys, at least.

Programming PHP: Chapter 5, p.125

like image 40
Anthony Rutledge Avatar answered Oct 05 '22 07:10

Anthony Rutledge