PHP/mySQL INSERT NULL if variable is empty - php

i want to check if a variable from $_POST is empty and INSERT a NULL to my Database.
But when I do it my way i always get a String called NULL and not a real NULL in my data set.
This is how I tried it:
if(isset($_POST['folge'])){
$comment = !empty($_POST['comment']) ? "'".$_POST['comment']."'" : null;
$sqlstring = "INSERT INTO eventstest (comment) VALUES (".$comment.")";
echo $sqlstring;
if ($mysqli->query($sqlstring) === TRUE) {
printf("Table myCity successfully created.\n");
}else{
printf("Errorcode: %d\n", $mysqli->errno);
printf("Error: %d\n", $mysqli->error);
}
if I send the form without making inputs to "comment" page output is:
INSERT INTO eventstest (comment) VALUES ()Errorcode: 1136 Error: 0
Whats wrong? Or whats the better way to check for empty inputs and add NULL to DB?
PS: The database cell has STANDARD: NULL

If you want to insert a NULL value into MySQL, you have to pass a null-value in the SQL query, not the string of null. It will still be a string from a PHP perspective, but not from the MySQL perspective.
if (!empty($_POST['comment'])) {
$comment = "'".$mysqli->real_escape_string($_POST['comment'])."'";
} else {
$comment = "NULL";
}
You can also shorten that into a one-liner, using a ternary operator
$comment = !empty($_POST['comment']) ? "'".$mysqli->real_escape_string($_POST['comment'])."'" : "NULL";
Then, because you assign the quotes around the comment-string itself, as you should do, since you alternatively want to pass a null-value, you need to remove the single quotes surrounding the variable from the query. This would otherwise break it too, as you'd get ''comment''.
$sql = "INSERT INTO table (comment) VALUES (".$comment.")";
Of course this assumes that the column comment allows for null-values. Otherwise it will fail, in which case you should either insert empty strings or change the column to accept null values.
It should also be noted that this query is exposed to SQL injection attacks, and you should use an API that supports prepared statements - such as PDO or MySQLi, and utilize those to secure your database against these kinds of attacks. Using a prepared statement with MySQLi would look something like this. See how we supply a PHP null to the value in bind_param() if $_POST['comment'] is empty.
// Set MySQLi to throw exceptions on errors, thereby removing the need to individually check every query
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
if (isset($_POST['folge'])) {
// $comment = !empty($_POST['comment']) ? $_POST['comment'] : null; // Ternary operator
$comment = $_POST['comment'] ?? null; // Null coalescing operator, since PHP 7
$sql = "INSERT INTO eventstest (comment) VALUES (?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("s", $comment);
$stmt->execute();
$stmt->close();
}
PHP Ternary Operator
How can I prevent SQL injection in PHP?

Several things wrong here. First is that you are using string concatenation instead of prepared statements. This leaves you open to SQL injection. I suggest you stop this project right now and return after learning to use PDO and prepared statements.
Secondly, 'NULL' != null you need to specify it as null
Last but not least, generally there isn't a need to explicitly check for null in postvars and then pass a null again. If the column type allows null and you do not pass in a non null value. null will be stored in it anyway

Related

mysqli_real_escape_string doesn't insert into db

I propose the following question ... I have to make sure that the following query also accept values ​​with the quotes inside ..
I tried using mysqli_real_escape_string but it did not work .. I am attaching my attempts ..
1° Put the function during the post
$idCantiere = $_POST["idCantiere"];
$nomeCantiere = mysqli_real_escape_string($_POST["nomeCantiere"]);
$sql = "INSERT INTO Cantiere(
idCantiere,
nomeCantiere)
VALUES(
'$idCantiere',
'$nomeCantiere')";
if (mysqli_query($mysqli, $sql))
{
echo "<script type='text/javascript'>alert('Cantiere Inserto');
</script>";
} else
{
echo "Error: " . $sql . "" . mysqli_error($mysqli);
}
2° Put the function during the query
$idCantiere = $_POST["idCantiere"];
$nomeCantiere = $_POST["nomeCantiere"];
$sql = "INSERT INTO Cantiere(
idCantiere,
nomeCantiere)
VALUES(
'$idCantiere',
mysqli_real_escape_string('$nomeCantiere'))";
if (mysqli_query($mysqli, $sql))
{
echo "<script type='text/javascript'>alert('Cantiere Inserto');
</script>";
} else
{
echo "Error: " . $sql . "" . mysqli_error($mysqli);
}
How can I solve the problem?
Drop the mysqli_real_escape_string() and just use prepared statements which is simple and prevents sql injections.
<?php
$idCantiere = isset($_POST['idCantiere']) ? $_POST['idCantiere'] : null;
$nomeCantiere = isset($_POST['nomeCantiere']) ? $_POST['nomeCantiere'] : null;
$sql = $mysqli->prepare("INSERT INTO Cantiere (idCantiere,nomeCantiere) VALUES(?.?)");
$sql->bind_param("is",$idCantiere,$nomeCantiere);
if($sql->execute()){
//success message
}else{
//return error
}
?>
A prepared statement is a feature used to execute the same (or similar) SQL statements repeatedly with high efficiency.
Prepared statements basically work like this:
Prepare: An SQL statement template is created and sent to the database. Certain values are left unspecified, called parameters (labeled "?"). Example: INSERT INTO MyGuests VALUES(?, ?, ?)
The database parses, compiles, and performs query optimization on the SQL statement template, and stores the result without executing it
Execute: At a later time, the application binds the values to the parameters, and the database executes the statement. The application may execute the statement as many times as it wants with different values
Compared to executing SQL statements directly, prepared statements have three main advantages:
Prepared statements reduce parsing time as the preparation on the query is done only once (although the statement is executed multiple times)
Bound parameters minimize bandwidth to the server as you need send only the parameters each time, and not the whole query
Prepared statements are very useful against SQL injections, because parameter values, which are transmitted later using a different protocol, need not be correctly escaped. If the original statement template is not derived from external input, SQL injection cannot occur.
You are wrong to pass parameters to the mysqli_real_escape_string () function
before inserting the post you must put the connection string with which you access the DB
$connection=mysqli_connect("localhost","USER","PASSWORD","DB");
$nomeCantiere= mysqli_real_escape_string($connection, $_POST['nomeCantiere']);
your second attempt is wrong reuses my line of code in the first .. during the post
You have to pass the connection variable as first parameter
Eg:
$con=mysqli_connect("localhost","my_user","my_password","my_db");
$age = mysqli_real_escape_string($con, $_POST['age']);
Checkout documentation for more detail.
http://php.net/manual/en/mysqli.real-escape-string.php
You can try to replace quote with php
$nomeCantiere = $_POST["nomeCantiere"];
str_replace("'", "''", $nomeCantiere );
if you insert 2 quotes ( '' ) instead of one mysql will put that value in the table with only 1 quote
You are missing one parameter in function
mysqli_real_escape_string($con,$sql);

How to UPDATE a MySQL table from an HTML form with PHP PDO prepared statements

I’m working on an app and I am getting stuck updating values in a MySQL database table.
When I use the single value version of the name attribute (i.e. name="value1") everything works fine. But, when I use the array syntax (name="value[]") for the name attribute I get an error.
The error occurs right here:
$stmt = $conn->prepare("UPDATE students SET value=value+{$_POST['value']}");
The error is:
Error: Notice: Array to string conversion on line 8
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'value' in 'field list'
This is my PDOStatement::execute statement.
$stmt->execute(array("value", $_POST['value']));
This is my HTML:
<input class="input" id="id1" name="value[]" type="range">
<input class="input" id="id2" name="value[]" type="range">
<input class="input" id="id3" name="value[]" type="range">
The columns in my table are named value1, value2, value3 and so on.
Thanks for your comprehensive reaction. I didn't mentioned that the input must increase the database values. However, this is how I get it to work.
if(isset($_POST['value'])){
if(is_array($_POST['value'])) {
foreach($_POST['value'] as $key => $value) {
$stmt = $conn->prepare("UPDATE students SET value".($key+1)." = ? + value".($key+1)." ");
$stmt->execute(array($value));
}
}
With thanks to the guy who removed his answer but he give me the inspiration!
Warning: Never use anything from $_POST directly! Sanitize and validate all user input. What you see below is for demonstration purposes only. Without a WHERE clause in your query, the entire table will be updated.
When you do this in your HTML <input> elements:
name="value[]"
$_POST will receive an array for the $_POST element value. Thus,
$_POST['value'] //resolves to an array.
That is why you are getting an error (Error: Notice: Array to string conversion) when you do this:
$stmt = $conn->prepare("UPDATE `students` SET `value` = `value` +{$_POST['value']}");
Braces {} are typically used during string interpolations within double quotes. Your code is trying to turn an array in to a string.
You might try this instead:
$stmt = $conn->prepare("UPDATE `students` SET `value1` = `value1` + ?");
Or, this ...
$stmt = $conn->prepare("UPDATE `students` SET `value1` = `value1` + :value1");
Do not put user input directly into a prepared statement. The PHP PDO::prepare manual page states.
Prepares an SQL statement to be executed by the
PDOStatement::execute() method. The SQL statement can contain zero or
more named (:name) or question mark (?) parameter markers for which
real values will be substituted when the statement is executed. You
cannot use both named and question mark parameter markers within the
same SQL statement; pick one or the other parameter style. Use these
parameters to bind any user-input, do not include the user-input
directly in the query.
You need to do some processing of the array $_POST['values'] first. Sanitizing and validating the data is highly advisable and a best practice.
The data for your <input> elements is actually here.
$_POST['values'][0] //Resolves to a string.
$_POST['values'][1] //Resolves to a string.
$_POST['values'][2] //Resolves to a string.
The error Column not found: 1054 Unknown column 'value' in 'field list' suggests that you should use the name of an actual column in your table. By your own words, those field names are value1, value2, and value3.
When you use PDOStatement::execute, you can do this just to see if things are working in the ? way....
$stmt->execute([$_POST['values'][0]]) //PHP 5.4+
Or
$stmt->execute(array([$_POST['values'][0])) //PHP 5.3 and below
If you used named parameters, you can try this.
$stmt->execute(['value1' => $_POST['values'][0]]) //PHP 5.4+
Or
$stmt->execute(array('value1' => [$_POST['values'][0])) //PHP 5.3 and below
.... but I call that living dangerously. Sanitize and validate your inputs first.
If you ever get to the point of using MySQL stored procedures (say, for an e-commerce site) with your PDO prepared statements, look up PDOStatement::bindParam (must use variables with this) and PDOStatement::bindValue (can use general values, like string literals).
$stmt->bindValue(1, $variable);
$stmt->execute();
Or ...
$stmt->bindValue(:name, $variable);
$stmt->execute();
$stmt->bindParam(1, $variable); or $stmt->bindParam(:name, $variable); are mostly useful for using IN/OUT arguments with stored procedures.
Be careful. You will end up updating the entire table because there is no WHERE condition in your query! But, if you want all records to have the same value, that's how you can do it. :-) What would Edgar F. Codd say?
While it is possible to use a loop to solve the problem of using all three supposed $_POST['value'] elements, one still needs to ask why the entire table would need to be updated for each iteration.
I edited your answer to look like this.
if(isset($_POST['value']) && is_array($_POST['value']) && !empty($_POST['value']) && (count($_POST['value']) === 3)){
foreach($_POST['value'] as $key => $value) {
$num = ($key + 1);
$stmt = $conn->prepare("UPDATE `students` SET value{$num} = ? + value{$num}");
$stmt->bindValue(1, $value);
$stmt->execute();
}
}
While not comprehensive, at least better checking is being done. But, something like this could be better.
if(!isset($_POST['value']) || !is_array($_POST['value']) || empty($_POST['value']) || (count($_POST['value']) !== 3)){
throw new UnexpectedValueException("Something is wrong with the input in $_POST.");
}
foreach($_POST['value'] as $key => $value) {
$num = ($key + 1);
$stmt = $conn->prepare("UPDATE `students` SET value{$num} = ? + value{$num}");
$stmt->bindValue(1, $value);
$stmt->execute();
}

Why mysql_real_escape_string() did not prevent hack?

I've a website that hacked today. Server logs returned something like this as hacker's tries:
www.site.com/notifications.php?PID=7&id=999999.9%20union%20all%20select%20%28select%20distinct%20concat%280x7e%2C0x27%2Cunhex%28Hex%28cast%28schema_name%20as%20char%29%29%29%2C0x27%2C0x7e%29%20from%20%60information_schema%60.schemata%20limit%201%2C1%29%2C0x31303235343830303536%2C0x31303235343830303536%2C0x31303235343830303536--
But I've used mysql_real_escape_string() in my code:
if (isset($_GET['id']) && $_GET['id'] != '') {
$id = mysql_real_escape_string($_GET['id']);
} else {
$id = '';
}
if ($id == '') {
$stmt = "SELECT * FROM tbln13 ORDER BY id DESC";
} else {
$stmt = "SELECT * FROM tbln13 WHERE id = $id";
}
$NewsResult = mysql_query($stmt) or die (mysql_error());
Why my website could not prevent this attack?
Because escape_string add slashes and such to quotes. You didn't have any quotes in your query, or the string they submitted.
Your query doesn't have a STRING in it, it appears to expect an int. If you expected an integer, you should have verified it was an int, or forced it to an int, before using it in a query. Escaping a value as a string, then using it as an int, won't work.
Switch to prepared statements in MySQLi or PDO.
The sql injected query looks like this
SELECT * FROM tbln13 WHERE id = 999999.9
union all select
(select distinct concat(0x7e,0x27,unhex(Hex(cast(schema_name as char))),0x27,0x7e)
from `information_schema`.schemata
limit 1,1),
0x31303235343830303536, 0x31303235343830303536, 0x31303235343830303536--
as you see, you were injected because you have just allowed this!
You expected a number but you didn't check for it! So you got the number and something more.
You should have checked the $id variable for what you expected, which is the number. This is what I would use:
if (!preg_match('/^\d+$/', $id))
die("ERROR: invalid id"); // error, don't continue
Use prepared statements, that will, in most cases, prevent SQL injections.
A simple and comprehensible guide to prepared statements can be found in this website:
Bobby Tables
More over you should stop using MYSQL, it's outdated and will be removed in future implementations. Use MySQLi or PDO instead.
Because your escaped variable is not a string therefore it is not inside quotes in your query. If you want a quick fix you can change your query to:
$stmt = "SELECT * FROM tbln13 WHERE id = '$id'";
It is not standard use for numeric comparison but should work.
As mentioned by others, you should ditch deprecated mysql_* functions and instead used prepared statements via mysqli or PDO.
Even then you should also be validating your input, because just using prepared statements will not help you identify whether you have input values that are valid. You would ideally make sure all your input is valid before even attempting a prepared statement. In this case, this validation could be as simple as this:
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (false === $id) {
// you do not have a valid integer value passed. Do something.
} else {
// continue with your prepared statement
}

How do you properly set a blank variable as NULL

I am parsing an XML feed into a MYSQL table using simplexml_load_file(). Some of the variables are blank, I would like them to be actual NULL instead of NULL, or is there even a difference?
$xml = simplexml_load_file('cb.xml') or die ('Bad XML File');
foreach($xml->item as $item) {
$name = $item->name;
//Tried
if ($name == '') {
$name = 'NULL';
}
//And
if ($name == '') {
$name = NULL;
}
mysql_query("INSERT INTO cb (name) VALUES ('$name')");
This is because you're giving MySQL a string:
.... ('ANYTHING WITHIN QUOTES IS A STRING')
And the PHP null value, when "casted" to a string, becomes an empty string. So your first try gave ... ('NULL'), and now it gives ... ('').
You must use the NULL keyword inside the query, without quotes, to insert NULL into a database field.
mysql_query("INSERT INTO cb (name) VALUES (" . ($name == null ? "NULL" : "'$name'") . ")");
Oh, and as usual, take care not to get SQL-injected with your unprotected $name variable.
The second variable initialization is correct; the first is just the string 'NULL' (which is not special from PHP's viewpoint). However, you should be using prepared statements (MySQLi_STMT or PDOStatement. If you want to stick with the regular mysql extension, use mysql_real_escape_string
An example with PDO is:
$stmt = $pdo_con->prepare("INSERT INTO cb (name) VALUES (?);");
$stmt->execute(array($name));
This will handle nulls correctly, unlike your current string interpolation.
if you're using more than one value and shorthand if else does work then do this: (we will insert the null data in column 3) * Notice that the single quotes are omitted.. this is because "NULL" cannot be entered in as a string for sql or else it will be a string NULL not an SQL NULL which is what we want.
//condition
if ($col3_var !== NULL)
$col3_var = "'$col3_var'";
else
$col3_var = "NULL"; //SQL will omit the "" here
$sql = "INSERT INTO tablename
(col1, col2, col3...)
VALUES
('$col1_var', '$col2_var', $col3_var)";
$result = mysql_query($sql) or die("Err: " . mysql_error());

using nulls in a mysqli prepared statement

In a mysqli prepared statement, a NULL gets turned into '' (in the case of a string) or 0 (in the case of an integer). I would like to store it as a true NULL. Is there any way of doing this?
It's possible to bind a true NULL value to the prepared statements (read this).
You can, in fact, use mysqli_bind_parameter to pass a NULL value to the database. simply create a variable and store the NULL value (see the manpage for it) to the variable and bind that. Works great for me anyway.
Thus it'll have to be something like:
<?php
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'world');
// person is some object you have defined earlier
$name = $person->name();
$age = $person->age();
$nickname = ($person->nickname() != '') ? $person->nickname() : NULL;
// prepare the statement
$stmt = $mysqli->prepare("INSERT INTO Name, Age, Nickname VALUES (?, ?, ?)");
$stmt->bind_param('sis', $name, $age, $nickname);
?>
This should insert a NULL value into the database.
For anyone coming looking at this because they are having problems binding NULL in their WHERE statement, the solution is this:
There is a mysql NULL safe operator that must be used:
<=>
Example:
<?php
$price = NULL; // NOTE: no quotes - using php NULL
$stmt = $mysqli->prepare("SELECT id FROM product WHERE price <=> ?"); // Will select products where the price is null
$stmt->bind_param($price);
?>
The comments to the PHP documentation on mysqli_stmt::bind_param indicate that passing in NULL was not easily possible.
Please see #creatio's answer: https://stackoverflow.com/a/6892491/18771
Solutions offered in the comments do some pre-preparation work on the prepared statement, replacing the "?" markers with "NULL" for every param that has the PHP null value. The modified query string is then used.
The following function is from user comment 80119:
function preparse_prepared($sQuery, &$saParams)
{
$nPos = 0;
$sRetval = $sQuery;
foreach ($saParams as $x_Key => $Param)
{
//if we find no more ?'s we're done then
if (($nPos = strpos($sQuery, '?', $nPos + 1)) === false)
{
break;
}
//this test must be done second, because we need to
//increment offsets of $nPos for each ?.
//we have no need to parse anything that isn't NULL.
if (!is_null($Param))
{
continue;
}
//null value, replace this ? with NULL.
$sRetval = substr_replace($sRetval, 'NULL', $nPos, 1);
//unset this element now
unset($saParams[$x_Key]);
}
return $sRetval;
}
(It's not really the coding style I would have done it in, but if it works...)
I store all parameters in an array and pass them in bind_param function using array_shift($myArray). NULL is accepted like that.
<?php
$mysqli=new mysqli('localhost','root','','test');
$mysqli->query("CREATE TABLE test_NULL (id int(11))");
if($query=$mysqli->prepare("insert into test_NULL VALUES(?)")){
$query->bind_param('i',$null); //note that $null is undefined
$query->execute();
}else{
echo __LINE__.' '.$mysqli->error;
}
?>

Categories