There's got to be a much more elegant way of doing this.
How do I convert all non-empty post data to session variables, without specifying each one line by line? Basically, I want to perform the function below for all instances of X that exist in the POST array.
if (!empty($_POST['X'])) $_SESSION['X']=$_POST['X'];
I was going to do it one by one, but then I figured there must be a much more elegant solution
I would specify a dictionary of POST names that are acceptable.
$accepted = array('foo', 'bar', 'baz');
foreach ( $_POST as $foo=>$bar ) {
if ( in_array( $foo, $accepted ) && !empty($bar) ) {
$_SESSION[$foo] = $bar;
}
}
Or something to that effect. I would not use empty because it treats 0 as empty.
The syntax error, is just because there is a bracket still open. it should be
$vars = array('name', 'age', 'location');
foreach ($vars as $v) {
if (isset($_POST[$v])) {
$_SESSION[$v] = $_POST[$v];
}
}
It should work like that. If you use
if ($_POST[$v])...
it strips down empty data.
Here you go,
if(isset($_POST) {
foreach ($_POST as $key => $val) {
if($val != "Submit")
$_SESSION["$key"] = $val;
}
}
Well the first thing I would suggest is you don't do this. It's a huge potential security hole. Let's say you rely on a session variable of username and/or usertype (very common). Someone can just post over those details. You should be taking a white list approach by only copying approved values from $_POST to $_SESSION ie:
$vars = array('name', 'age', 'location');
foreach ($vars as $v) {
if (isset($_POST[$v]) {
$_SESSION[$v] = $_POST[$v];
}
}
How you define "empty" determines what kind of check you do. The above code uses isset(). You could also do if ($_POST[$v]) ... if you don't want to write empty strings or the number 0.
This lead me to this bit, which is a simplified version of #meder's answer:
<?php
$accepted = array('foo', 'bar', 'baz');
foreach ( $accepted as $name ) {
if ( isset( $_POST[$name] ) ) {
$_SESSION[$name] = $_POST[$name];
}
}
You might also substitute !empty() for isset() above, though be aware of how much farther-reaching empty() is, as #meder pointed out.
$_SESSION["data"] = $POST;
$var = $_SESSION["data"];
Then just use $var as a post variable. For example:
echo $var["email"];
instead of
echo $_POST["email"];
Cheers
Related
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).
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_");
There is not a single reason to do it.
To handle user inputs an array is 100 times better than separate variables
I like an approach where you let dynamic getters and setters in a class do all the work for you. Here's how I would code it.
First, create a bass class to hold data:
class FormParameterHandler {
protected $parameters;
public function __construct($associative_array) {
$this->parameters = array();
foreach($associative_array as $key => $value) {
$this->{$key} = $value;
}
}
public function __get($key) {
$value = null;
if(method_exists($this, "get_$key")) {
$value = $this->{"get_$key"}();
} else {
$value = $this->parameters[$key];
}
return $value;
}
public function __set($key, $value) {
if(method_exists($this, "set_$key")) {
$this->{"set_$key"}($value);
} else {
$this->parameters[$key] = $value;
}
}
}
Next, create a specific class to use for some specific form where there is something special to validate. Use your freedom as a programmer here to implement it any way you want to. And remember, since we're using reflection to look for setter methods, we can write specific setter methods for known problem areas, like e.g. to check for equal passwords in a "register user" form:
class RegisterFormParameterHandler extends FormParameterHandler {
private $passwords_are_equal = null;
public function __construct($register_form_parameters) {
parent::__construct($register_form_parameters);
}
public function has_equal_passwords() {
return $this->passwords_are_equal;
}
public function set_password($password) {
$this->parameters['password'] = $password;
$this->compare_passwords();
}
public function set_password_repeat($password_repeat) {
$this->parameters['password_repeat'] = $password_repeat;
$this->compare_passwords();
}
private function compare_passwords() {
if(isset($this->parameters['password']) && isset($this->parameters['password_repeat'])) {
$this->passwords_are_equal = ($this->parameters['password'] === $this->parameters['password_repeat']);
}
}
}
Finally, use the derived class in a "register user" flow, to easily find out if the two entered passwords match:
$registerFormParameterHandler = new RegisterFormParameterHandler($_POST);
if($registerFormParameterHandler->has_equal_passwords()) {
print "are equal";
//register user
} else {
print "are not equal";
}
You can test this by creating an HTML form that has one input field with the name "password", and another input field with the name "password_repeat".
To access any of the form data, use your form data object variable name, followed by the access operator "dash larger than" -> , followed by the name of the parameter. In the example above, if there was an input field named "user_name", it would be accessed through a call to
$registerFormParameterHandler->user_name
Rr, if you have defined the name of the field you want to get in some other variable, use reflection:
$registerFormParameterHandler->{$settings['form_data_user_name']}
Have fun! :)
A safe way to extract variables into the local scope is not to. You're injecting variables into your local scope, which is a problem however you do it. Even if you limit the variables to only a few select ones that won't clash with other variable names in the scope now, if you start adding elements to your form you may be in trouble later.
Arrays are specifically for holding an unlimited amount of named values without crowding the variable namespace. Use them! You may have to type a little more, but that's par for the course.
While it is best to refer to them with $_POST['variablename'], it is possible to expand only the variables you are expecting.
$expected = array('name', 'telephone', /* etc */);
foreach ($_POST as $key => $value) {
if (!in_array($key, $expected)) {
continue;
}
${$key} = $value;
}
Or, I prefer this:
foreach ($_POST as $key => $value) {
switch ($key) {
case 'name':
case 'telephone':
/* etc. */
${$key} = $value;
break;
default:
break;
}
}
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
Try this inbuilt method/function filter_input
Reference URL: php.net function filter input
Is it possible to take $_GET parameter from the url and put it in php variable without using foreach?
If I do:
var_dump($_GET);
I will get the result:
array(1) { ["block_simple_clock"]=> string(0) "" }
I need to put that value block_simple_clock in a string variable, and I can do that with a foreach:
foreach($_GET as $key => $value) {
var_dump($key);
}
But I would really like to take that value without a foreach if it is possible. I hate using foreach for such a trivial problem :)
Sorry for confusion, that block_simple_clock is a variable, and it can be a different value, I am sending this value with this code:
foreach ($pluginlist->plugins as $key => $plugin) {
if (empty($plugin->component)) {
continue;
}
if (in_array($plugin->component, $arr)) {
if (!in_array($plugin->component, $contribs)) {
$target_url = new moodle_url('redirect.php');
$mform->addElement('advcheckbox', $plugin->component, "<a href={$target_url}?$plugin->component target='_blank'>" . $plugin->name . "</a>", '', array(0, 1));
}
}
$requestedPluginIdCounter++;
}
As you can see the $plugin->component is the value that I am sending via $_GET.
$variable = $_GET['block_simple_clock'];
OR
$variable = $_REQUEST['block_simple_clock'];
If you know exactly which ones you need, you can use
$var = $_GET['name-in-get'];
You mays want to use the function
extract( $_GET );
Which creates global variables with the name of the key :
//suppose GET = $_GET['name']
extract( $_GET );
echo $name; //will echo $_GET['name']
Remember to ALWAYS filter gets and posts values, since they are user input (obviously it depends what you do with them, but especially if they're used for database purposes, it is extremely important)
For more information, see filter_input function
You can do this :
$t = array_keys($_GET);
echo $t[0];
Thank you guys, I have added a name=$plugin->component, and was able to extract the variable with that $_GET["name"] :)
I've been given the task to remove undefined variable and undefined index errors, which i know how to
$value = isset($_POST['value']) ? $_POST['value'] : '';
The problem is this is way too time consuming, I predict over 2000 variables, $_GET, $_POST hasn't been set. So is there a regular expression i can use to set these variables quickly?
How do i do regex to change this $category = $_GET['c'] to this
$category = isset($_GET['c']) ? $_GET['c'] : ''?
And how do i do regex to change if($page or $category or $profile) to this
if(isset($page) or isset($category) or isset($profile))?
This is the best method i can think of by using regex find & replace in Notepad++. I assume over 2000 PHP variable/index undefined errors. How do i solve this without turning off errors?
you should not use regex because it's kind of heavy :)
if i'm understanding your question right, you can do this like this,
with this approach, it does not matter how many parameters contains POST or GET, you simply filter them through foreach loop and getting clean arrays with parameters, also you can make it a function that returning array.and then you just need to check if_array_key_exests() and do your things.
$_POST = ["user"=>"1", "num"=>2];
$_GET = ["user" => '', "num"=>1];
//function method
function filter($array)
{
$arr = array();
foreach ($array as $key => $val) {
if (!empty($val)) {
$arr[$key] = $val;
}
}
return $arr;
}
without function
$post = array();
foreach ($_POST as $key => $val) {
if (!empty($val)) {
$post[$key] = $val;
}
}
$get = array();
foreach ($_GET as $key => $val) {
if (!empty($val)) {
$get[$key] = $val;
}
}
For your first problem, replacing something like
(\$\w+)\s*=\s*\$_GET\[['"]?(\w+)['"]?\]\s*;
by
$1 = isset($_GET['$2']) ? $_GET['$2'] : '';
should work.
Regarding the second, I don't know if this is possible with a variable number of variables. This one works for 3 variables, replace
if\s*\(\s*\s*(\$\w+)\s+or\s+(\$\w+)\s+or\s+(\$\w+)\s*\)
by
if (isset($1) or isset($2) or isset($3))
You can add another \s+or\s+(\$\w+) before the last \s* in the search, and add another or isset($4) in the replacement for 4 variables etc.
I recommend you to replace them one by one instead of replacing all at once ;-)
Also note that if ($a) is not the same as if (isset($a)). Consider something like this:
// query string is a=0
$a = $_GET['a'];
if ($a) // will be false
if (isset($a)) // will be true
if (!empty($a)) // will be false
So, perhaps you want to use !empty() instead of isset(). This should work without notices, too.
resove first issue:
define a function like:
function global_get($key){
return isset($_GET[$key])?$_GET[$key]:'';
}
then use sed(linux tool) to replace all parts like this(it will modify all the $_GET[.*] of php extension files in your project,so be careful to use this):
find /yourproject -name "*.php" -exec sed -i "s/\$_GET\[\([^]]*\)\]/global_get(\1)/" \;
you may modify this command to apply your own demand.
The second issue could be harmful if you use the regex expression because it is hard to make a role rule.so I recommend you to replace manually.
Given knowledge of the following problematic PHP code, where variables are generated based on the request data (e.g. submitted HTML form fields), what exploits are possible?
I'm aware that the request could be constructed to contain data specifically crafted to overwrite existing variables (although we're blind to what variables exist), and thereby break the application, I'm just struggling to think of ways it could break the application for gain.
<?php
function foo( $data ) {
// Some unknown code may exist here
foreach( $data as $key => $value) {
$$key = $value;
}
// Some other unknown code may exist here
}
if ( ! empty($_POST) ) {
foo( $_POST );
}
<?php
$userid = $_SESSION['uid'];
function foo( $data ) {
// Some unknown code may exist here
//$_POST contains userid field;
foreach( $data as $key => $value) {
$$key = $value;
}
// Some other unknown code may exist here
}
if ( ! empty($_POST) ) {
foo( $_POST );
}
$credit_card_no = $cardDetails->getById($userid);
echo 'your current card on file is: ' . $credit_card_no;
Variables are placeholders in your algorithm, they represent values which get filled in at runtime. In your algorithm you do certain things with these values, and you depend on those values to be in a certain known state to some degree or another. Usually the variables, the placeholders, in your algorithms are fixed and are operated on in a certain order; that is the definition of your algorithm.
we take A
and assign to it B
and then we assign A to C
and then we pass C to the function X
...
Variable variables now are basically allowing you to modify those operations based on other values:
we take A
and assign to it B
AND THEN WE ASSIGN B TO ??? <---
and then we assign A to C
and then we pass C to the function X
...
Well, what variable was B assigned to? How is the rest of your algorithm going to behave from now on? Can you trust your knowledge about the state of any particular variable anymore now?
Those are the problems that variable variables based on user input create. It's not impossible to code carefully enough to avoid this being a problem, but you do have to be extremely careful.
Never trust user generated data. It's very dangerous code because you can easily overwrite the superglobals for example.
Read more about the risks:
http://www.php.net/manual/en/security.globals.php
http://php.net/manual/en/function.extract.php
Better use a whitelist with the keys that you expect:
// no whitelist
$_POST = array('foo' => 'bar', '_GET' => array('foo' => 'bar'), '_SESSION' => array('foo' => 'bar'));
foreach ($_POST as $key => $value) {
$$key = $value;
}
echo $foo;
print_r($_GET);
print_r($_SESSION);
// whitelist
$whitelist = array('foo');
$_POST = array('foo' => 'bar', '_GET' => array('foo' => 'bar'), '_SESSION' => array('foo' => 'bar'));
foreach ($_POST as $key => $value) {
if (in_array($key, $whitelist)) {
$$key = $value;
}
}
echo $foo;
print_r($_GET);
print_r($_SESSION);
I want to look through my PHP $_POST variables and change anything that is "undefined" (because of how jQuery is sending it) to "" or at least " " so that when the email form is submitted it doesn't say "undefined" wherever the value wasn't filled out (optional fields).
Thanks!
I recommend you consider altering your javascript to handle the undefines better, BUT..
Here is a no loops approach to do it:
$_POST = unserialize(str_replace('s:9:"undefined";', 's:0:"";', serialize($_POST)));
There is also the more typical approach of using a single loop like so:
foreach($_POST as &$p) if($p=='undefined') $p = '';
Note: The serialize + unserialize approach is cool in that is does not use a loop, but the loop approach is probably slightly faster, especially when $_POST is large.
In PHP if you use an & symbol in an foreach loop it will use it as a reference instead of a value. Changing a reference will set the original value.
<?php
$_POST['text1'] = 'undefined';
$_POST['text2'] = 'undefined';
foreach($_POST as &$var)
{
if($var == 'undefined')
$var = '';
}
print_r($_POST);
?>
<!-- Will output -->
array(
text1=>
text2=>
)
if (isset($_POST['var'])) {
// it is set
} else {
// it isnt set
}
foreach ($_POST as &$var) {
if ($var === 'undefined') {
$var = '';
}
}