This question already has answers here:
Sanitizing user's data in GET by PHP [duplicate]
(5 answers)
What are the best PHP input sanitizing functions? [duplicate]
(14 answers)
Closed 7 months ago.
I have a form with a lot of variables which is then sending an email, rather than sanitizing each $_POST value with filter_var($_POST['var'], FILTER_SANITIZE_STRING); I was after a more simple piece of code. I came up with the below, which seems to work as I believe the default action is FILTER_SANITIZE_STRING, but I was just wondering what peoples opinions are, and if this is not good practice, perhaps you could tell me why? The $_POST values are then individually embedded into new variables, so I would only be using array_map just at the start to sanitize everything...
$_POST = array_map('filter_var', $_POST);
Thank you for your replies, to give you a little more information, basically:
I have 20-30 input fields in a form which are being captured,
the data is then displayed to the user to check their input,
variables are then sanitized,
the user is then sent an email
and then finally the details are entered into a db.
currently I am sanitizing using the above array_map function, as well as FILTER_SANITIZE_EMAIL on the email address before sending an email and then escaping the input using mysql_real_escape_string() before the insert into the db. Without getting into prepared statements etc.. do you think I should be doing anything additionally? thanks again!
Just use filter_input_array() from the filter extension.
/* prevent XSS. */
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
This will sanitize your $_GET and $_POST.
Depends what its being used for.
If you are inserting it into the database then mysql_real_escape_string() for quoted strings and type casting for numbers would be the way to go - well ideally prepared statements, but thats an entirely different matter.
If you plan on outputting the data onto the webpage then I would recommend something like htmlspecialchars()
If you plan on using the user input as a shell argument, then you would use escapeshellarg()
Moving onto your question about sending emails. Well, the following should suffice:
filter_var($_POST['message'], FILTER_SANITIZE_STRING);
All this does is basically strip tags and encode special characters.
You can use strip_tags() with array_map()
<?php
$a = array(
'title' => 'Title',
'data' => array(
'hdr' => 'Header',
'bdy' => 'Body'
),
'foo' => array(1, 23, 65)
);
$b = array_map("strip_tags", $a);
print_r($b);
?>
Update for 2D array:
function array_map_r( $func, $arr )
{
$newArr = array();
foreach( $arr as $key => $value )
{
$newArr[ $key ] = ( is_array( $value ) ? array_map_r( $func, $value ) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value ) ) );
}
return $newArr;
}
Usage:
$a = array(
'title' => 'Title',
'data' => array(
'hdr' => 'Header',
'bdy' => 'Body'
),
'foo' => array(1, 23, 65)
);
$ar =array_map_r('strip_tags', $a);
print_r($ar);
Note I found this just by searching the comments for Dimension
There is no correct way to do blanket sanitation. What sanitation method you need depends on what is done to the data.
Sanitize the data directly before it is used.
function strip($string, $allowed_tags = NULL)
{
if (is_array($string))
{
foreach ($string as $k => $v)
{
$string[$k] = strip($v, $allowed_tags);
}
return $string;
}
return strip_tags($string, $allowed_tags);
}
Just an example of a recursive function, for stripping tags in this case.
$arr = strip($arr);
This is what I use in all my projects:
function util_array_trim(array &$array, $filter = false)
{
array_walk_recursive($array, function (&$value) use ($filter) {
$value = trim($value);
if ($filter) {
$value = filter_var($value, FILTER_SANITIZE_STRING);
}
});
return $array;
}
It allows to trim and sanitize a nested array of posted data
This looks ok, but please comment if it can be improved or has any misgivings:
$_GET =filter_var_array($_GET);
$_POST=filter_var_array($_POST);
To apply specific filters on multiple fields, use a switch statement.
$post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
foreach($post as $k => $v) {
switch ($k) {
case 'int_1':
case 'int_2':
$post[$k] = filter_var($v, FILTER_SANITIZE_NUMBER_INT) * 1;
break;
case 'float_1':
case 'float_2':
$post[$k] = filter_var($v, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) * 1;
break;
default:
break;
}
}
Note: My IDE (NetBeans) warns about using global $_POST anywhere as a security violation, so I've just gotten into the habit of using a local $post variable instead. If you choose not to do the blanket string sanitation first, FILTER_SANITIZE_STRING could be used for the default: case.
Let's say we want to sanitize the $_POST array:
foreach($_POST as $k=>$v) {$_POST[$k] = htmlspecialchars($v);}
This simple. Isn't it?
Related
This question already has an answer here:
Is is bad practice to use array_walk with mysqli_real_escape_string?
(1 answer)
Closed 1 year ago.
My code is like this
public function addQuestions($data){
$ans = array();
$ans[1] = $data['ans1'];
$ans[2] = $data['ans2'];
$ans[3] = $data['ans3'];
$ans[4] = $data['ans4'];
$ans= mysqli_real_escape_string($this->db->link, $data[$ans]);
}
Is this right way to use array in this sql function ??
Since you wish to do something to each element of array $ans, it would be most appropriate to use array_map(), as follows:
public function addQuestions($data){
$ans = array();
$ans[1] = $data['ans1'];
$ans[2] = $data['ans2'];
$ans[3] = $data['ans3'];
$ans[4] = $data['ans4'];
$escaped_ans = array_map(function( $e ) {
return mysqli_real_escape_string( $this->db->link, $e);
}, $ans );
I don't have enough reputation to comment on Milan's post, but beware of array_walk, it won't change your original array. For Milan's code to actually affect your array, the function would have to be
function myescape(&$val) //Note the '&' which calls $val by reference.
{
$val = mysqli_real_escape_string($val);
}
array_walk($ans, 'myescape');
To answer your question though:
public function addQuestions($data){
$ans = array('',$data['ans1'],$data['ans2'],$data['ans3'],$data['ans4']);
//I would recommend using an object/associative array in this case though, just the way $data is already
$ans_escaped = array_map(function($val) {
return mysqli_real_escape_string($this->db->link, $val);
}, $ans);
//do whatever you need to do with escaped array
}
My advice though, would be to really look into prepared statements. It might just seem like extra work that you don't want to bother with - at first - but once you learn it, you will never want to do it any other way.
Since you have an array, and you want mysqli_real_escape_string on each element of an array, you can use array_walk():
function myescape($val)
{
return mysqli_real_escape_string($val);
}
... then
array_walk($ans, 'myescape');
if you use MYSQL PDO you won't need add "mysqli_real_escape_string" because all your variables a safe (from SQL injection) after you bind it
http://php.net/manual/en/pdostatement.bindparam.php
A couple questions here..
What is the following syntax?
What do all the pieces mean?
(( ! is_array($data)) ? $data : '')
How is it used in the function at the end?
function form_input($data = '', $value = '', $extra = '')
{
$defaults = array('type' => 'text', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value);
return "<input "._parse_form_attributes($data, $defaults).$extra." />";
}
Thankyou. Blake
Ok let me try as far as I understand you question.
What is the following syntax?
It is a function definition.
What do all the pieces mean?
This is the ternary operator. It means: If $data is not an array (!is_array($data)), return $data (? $data) otherwise return an empty string (: '')
It is a shorthand for if-else.
How is it used in the function at the end?
Not sure what you mean here. A function _parse_form_attributes($data, $defaults) is called witch seems to return a string.
If it in your question refers to $defaults, then it is just an array that gets build and that contains the following values:
Array (
'type' => 'text',
'name' => $data, // or empty string if $data is an array,
'value' => $value
);
It is used to build an input element, that will look like this:
<input type="text"
name="(value of $data or empty)"
value="(value of $value)"
(value of $extra)
/>
Ok this seems to generate the HTML for a form input with ome useful default values.... To answer your Qs in order:
It's a function that takes optional parameters. You could call eg form_input('SomeData', 'SomeValue');
It creates the HTML for the element and includes whatever information you give it, using defaults if no value is provided
A difficult one to answer... In short you're defining a new function. If you provide parameters, they will be used to create a form element. If you omit them, defaults will be used - eg type will default to text for output like <input type="text" [blah]>
I'm not quite sure what you mean here - Append as key-value pairs eg <input type="text" key="Value" [blah]> ? If this is the case, I would personally lose the $extra variable and have an array of key->value pairs instead. Failing that, you need to et $extra as appropriate eg key1="value1" key2="value2"
It's an inline expression of:
function form_input($data = '', $value = '', $extra = '')
{
if (is_string($data)) { // or better: is_scalar()
// leave as-is
}
else {
$data = '';
}
...
(Slightly variated.)
It basically ensures that the $data parameter is never an array. Maybe it was allowed to be an array in previous versions of the function, and this is safety code to ensure correct operation.
Note that type enforcement is another approach (often overkill, but sometimes advisable):
function xy($data, $value, $z) {
assert( ! is_array($data) );
assert( is_string($value) );
1) It returns an input field;
2) Pardon?
3) Function takes three values. $value is the default value of the input field (the one you find in the textbox); $data will be the name of the form if it isn't an array, otherwise the name will be blank; $extra is a string containing other stuff that will go in the form. Please refer to the function _parse_form_attributes;
4) link
By the way, I sincerely hope that _parse_form_attributes() does something amazing, since that looks like an incredibly verbose function and codeigniter has some handy built-in form generation functions.
This question already has answers here:
Sanitizing user's data in GET by PHP [duplicate]
(5 answers)
What are the best PHP input sanitizing functions? [duplicate]
(14 answers)
Closed 7 months ago.
I have a form with a lot of variables which is then sending an email, rather than sanitizing each $_POST value with filter_var($_POST['var'], FILTER_SANITIZE_STRING); I was after a more simple piece of code. I came up with the below, which seems to work as I believe the default action is FILTER_SANITIZE_STRING, but I was just wondering what peoples opinions are, and if this is not good practice, perhaps you could tell me why? The $_POST values are then individually embedded into new variables, so I would only be using array_map just at the start to sanitize everything...
$_POST = array_map('filter_var', $_POST);
Thank you for your replies, to give you a little more information, basically:
I have 20-30 input fields in a form which are being captured,
the data is then displayed to the user to check their input,
variables are then sanitized,
the user is then sent an email
and then finally the details are entered into a db.
currently I am sanitizing using the above array_map function, as well as FILTER_SANITIZE_EMAIL on the email address before sending an email and then escaping the input using mysql_real_escape_string() before the insert into the db. Without getting into prepared statements etc.. do you think I should be doing anything additionally? thanks again!
Just use filter_input_array() from the filter extension.
/* prevent XSS. */
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
This will sanitize your $_GET and $_POST.
Depends what its being used for.
If you are inserting it into the database then mysql_real_escape_string() for quoted strings and type casting for numbers would be the way to go - well ideally prepared statements, but thats an entirely different matter.
If you plan on outputting the data onto the webpage then I would recommend something like htmlspecialchars()
If you plan on using the user input as a shell argument, then you would use escapeshellarg()
Moving onto your question about sending emails. Well, the following should suffice:
filter_var($_POST['message'], FILTER_SANITIZE_STRING);
All this does is basically strip tags and encode special characters.
You can use strip_tags() with array_map()
<?php
$a = array(
'title' => 'Title',
'data' => array(
'hdr' => 'Header',
'bdy' => 'Body'
),
'foo' => array(1, 23, 65)
);
$b = array_map("strip_tags", $a);
print_r($b);
?>
Update for 2D array:
function array_map_r( $func, $arr )
{
$newArr = array();
foreach( $arr as $key => $value )
{
$newArr[ $key ] = ( is_array( $value ) ? array_map_r( $func, $value ) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value ) ) );
}
return $newArr;
}
Usage:
$a = array(
'title' => 'Title',
'data' => array(
'hdr' => 'Header',
'bdy' => 'Body'
),
'foo' => array(1, 23, 65)
);
$ar =array_map_r('strip_tags', $a);
print_r($ar);
Note I found this just by searching the comments for Dimension
There is no correct way to do blanket sanitation. What sanitation method you need depends on what is done to the data.
Sanitize the data directly before it is used.
function strip($string, $allowed_tags = NULL)
{
if (is_array($string))
{
foreach ($string as $k => $v)
{
$string[$k] = strip($v, $allowed_tags);
}
return $string;
}
return strip_tags($string, $allowed_tags);
}
Just an example of a recursive function, for stripping tags in this case.
$arr = strip($arr);
This is what I use in all my projects:
function util_array_trim(array &$array, $filter = false)
{
array_walk_recursive($array, function (&$value) use ($filter) {
$value = trim($value);
if ($filter) {
$value = filter_var($value, FILTER_SANITIZE_STRING);
}
});
return $array;
}
It allows to trim and sanitize a nested array of posted data
This looks ok, but please comment if it can be improved or has any misgivings:
$_GET =filter_var_array($_GET);
$_POST=filter_var_array($_POST);
To apply specific filters on multiple fields, use a switch statement.
$post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
foreach($post as $k => $v) {
switch ($k) {
case 'int_1':
case 'int_2':
$post[$k] = filter_var($v, FILTER_SANITIZE_NUMBER_INT) * 1;
break;
case 'float_1':
case 'float_2':
$post[$k] = filter_var($v, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) * 1;
break;
default:
break;
}
}
Note: My IDE (NetBeans) warns about using global $_POST anywhere as a security violation, so I've just gotten into the habit of using a local $post variable instead. If you choose not to do the blanket string sanitation first, FILTER_SANITIZE_STRING could be used for the default: case.
Let's say we want to sanitize the $_POST array:
foreach($_POST as $k=>$v) {$_POST[$k] = htmlspecialchars($v);}
This simple. Isn't it?
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
If have a problem on my site that users can post empty messages if they use space.
Code:
if (isset($_POST['submit'])) {
// check for empty fields
if (empty($_POST['headline']) || empty($_POST['text']) ||
empty($_POST['forum_id'])) {
header("Refresh: 2; url=/add-thread");
die('You must fill out every field.');
}
// No errors? Save.
else {
$headline = mysql_real_escape_string($_POST['headline']);
$text = mysql_real_escape_string($_POST['text']);
mysql_query("INSERT INTO threads (headline, text, date, forum_id, user_id)
VALUES ('$headline', '$text', NOW(), '$_POST[forum_id]', '$user[id]')");
header("Location: /thread/".mysql_insert_id()."");
}
}
How can I fix this?
trim() the text inputs. You can do that easily like this:
// get input vars and trim space
$callback = array('filter' => FILTER_CALLBACK, 'options' => 'trim');
$fields = filter_input_array(INPUT_POST, array(
'headline' => $callback,
'text' => $callback,
'forum_id' => $callback,
));
// check for empty fields by counting how many are set
if ( count($fields) != count(array_filter($fields)) ) {
// something was unset
}
The empty function checks for variables that meet a set criteria, from the manual
Returns FALSE if var has a non-empty and non-zero value.
The following things are considered to be empty:
"" (an empty string)
0 (0 as an integer)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
var $var; (a variable declared, but without a value in a class)
Your $_POST fields actually contain something like this
" ";
This isn't and empty string, but a string that's filled with whitespace characters.
Before using empty(), trim() the white-space from your POSTed values
$trimmed_post = array();
foreach($_POST as $key=>$value){
$trimmed_post[$key] = $value;
}
if(!empty($trimmed_post['headline'])){
//...
}
You don't need to put the new values into a new array, but I'm not a big fan of changing what's in the auto-generated superglobals.
One final note, you can't do something like this
if(!empty(trim($_POST['headline']))){
//...
}
because the empty function expects to be passed an actual variable. You could do something like this instead
if('' != trim($_POST['headline'])){
//...
}
This is probably the best approach to take. You reduce the number of functions that you need to call, users can post entries with a value of 0, and the code is more explicit about what it does. Another form you'll see is
if(trim($_POST['headline'])){
}
This works because PHP evaluates an empty string ('') as false, and a non empty string as true. I tend to avoid this form because I've found a lot of PHP bugs crop up around misunderstandings on how the equality operators get boolean values out of certain types. Being explicit helps reduce occurrences of these types of bugs.
Just a quick note: You're injecting the value of $_POST['forum_id'] into the SQL; that's not a good idea, since a user could manipulate that value as desired, even if it is coming from a hidden field. It would be wise to escape the value, or at least pass it through intval() and ensure it's an integer (assuming integral post identifiers).
I agree that trimming is the way to go. Here's a much easier way to go about it:
$_POST = array_map('trim', $_POST);
Try
if (!empty($_POST['headline']) && !empty($_POST['text']) &&
!empty($_POST['forum_id']))
For the logic.
You'd have to switch it around though.
UPDATE to clarify:
if (isset($_POST['submit']) && !empty($_POST['headline']) &&
!empty($_POST['text']) && !empty($_POST['forum_id'])) {
$headline = mysql_real_escape_string($_POST['headline']);
$text = mysql_real_escape_string($_POST['text']);
mysql_query("INSERT INTO threads (headline, text, date, forum_id, user_id)
VALUES ('$headline', '$text', NOW(), '$_POST[forum_id]', '$user[id]')");
header("Location: /thread/".mysql_insert_id()."");
}
else
{
header("Refresh: 2; url=/add-thread");
die('You must fill out every field.');
}
}
I trim every $_GET & $_POST variable as soon as the app starts. try something like this:
function trimArray(&$array) {
if (empty($array)) {
return;
}
foreach ($array as $k => $v) {
if (! is_array($v)) {
$array[$k] = trim($v);
} else {
trimArray($v);
}
}
}
if (! empty($_GET)) {
trimArray($_GET);
}
if (! empty($_POST)) {
trimArray($_POST);
}
Right after checking for a submission:
foreach ( $_POST as $key => &$value ) $value = trim($value);
edit in response to asker's comment:
Odd that it didn't work as above. Here was my exercise to confirm it would.
tbramble#wayfarer:~$ php -a
Interactive shell
php > $arr = array('one',' two', ' three ');
php > print_r($arr);
Array
(
[0] => one
[1] => two
[2] => three
)
php > foreach ( $arr as $key => &$value ) $value = trim($value);
php > print_r($arr);
Array
(
[0] => one
[1] => two
[2] => three
)
Must have something to do with working on a superglobal instead of a normal array.