I have created a "Feedback" section on a website. In this section, I've included a text field for comments and star rating system. The rating input is not required (people are not forced to leave rates) and is used to create a $_POST['rating'] integer variable (1-5) which is binded into an insert PDO query:
$dbms->bindparam(':rating', $_POST['rating'], PDO::PARAM_INT);
This works well when $_POST['rating'] variable is set, but when it's not I get the following error:
SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for column 'rating' at row 1
Is there any way (i.e. a flag) to tell PDO to bind a parameter only if it's not empty and use MySQL default value instead?
if(empty($_POST['rating'])) $_POST['rating'] = 0;
Somewhere before your bind. This will thus always give PDO an int value regardless of user action. If rating isn't set, the rating becomes 0.
Related
The error is:-
Field 'attn' doesn't have a default value41
If I set all the value of column query run perfectly like :
$stuattend = "INSERT INTO tblattendance(roll, attandence, att_time) VALUES('$roll', 'present', '5:30')";
I guess my problem is when I execute one value (roll) through query.
What would be the solution?
Hi the error clearly states that you have a column named as attn which is not nullable field by default. Either provide the default value or make it nullable or pass it some value so that it stops throwing the error.
You can change the above query to assign the default value as follows :
NOTE : Here you may assign the any value to it. Thinking that it may be integer I am doing as follows
INSERT INTO tblattendance(roll, attandence, att_time, attn) VALUES('$roll', 'present', '5:30', 10)
I have optional input provided as the 'type' value. I'm trying to prevent the statement from updating the type if it is null data and continue to update the equipment value.
Im tempted to create seperate prepare statements dependant on PHP check of null, but then found the SQL ISNULL(). I havnt used it before and am unsure how to use it within a prepare, unless there is a better way of achieving this?
PHP:
$update = $db -> prepare("UPDATE room
SET type = ISNULL(#:type,:type), equipment = :equipment
WHERE room_id = :room_id");
$update -> bindParam(":room_id", $room_id);
$update -> bindParam(":type", $data['type']);
$update -> bindParam(":equipment", $equipmentList);
$update -> execute();
I get a 'SQLSTATE[42000]: Syntax error or access violation: 1582' when attempting the above.
UPDATE:
UPDATE room
SET type = IFNULL(:type, type), equipment = :equipment
WHERE room_id = :room_id
Ok this correct syntax fixes errors, thanks to eggyal! The problem now is that null :type values are updated and the database valuetype(which is a enum) is not used instead of the null. I double checked in php before SQL that the :type values is null.
Why is IFNULL still returning a null?
Use bindValue instead of bindParam, you are not altering the value of parameter, therefore you don't need to pass it by reference.
if the data type in MySQL can contain null then you can tell it that you are sending a NULL value. Code:
$update -> bindValue(":type", $data['type'], is_null($data['type'] ? PDO::PARAM_NULL : PDO::PARAM_STR);
If your target column cannot contain null then you do not need to execute the query at all.
MySQL's ISNULL() function takes only a single argument and returns either 1 or 0 indicating whether that argument was null or not, respectively. It is equivalent to the IS NULL comparison operator.
MySQL does have a 2-argument IFNULL() function, which may have been what you intended to use (though the arguments you've applied are nonsense)?
UPDATE room
SET type = IFNULL(:type, type),
equipment = :equipment
WHERE room_id = :room_id
If :type is not NULL, its value will be used; else the incumbent value of the type column will be used instead (yielding no change).
You can use the COALESCE() function. It takes as many arguments as you give it and returns the first not-null argument it encounters if any. Otherwise it returns NULL.
UPDATE room
SET type = COALESCE(:type, type), equipment = :equipment
WHERE room_id = :room_id
It assumed a more complex query with multiple bindings so please don't guide me to use the things like implode(',',$ids), (?,?,?) or PDO possibilities for this example.
The question is to clarify a possibility of the SQL-injection of this specific method.
There is parameter 1,2,3 in the url http://localhost/executeSql/1,2,3.
The parameter is passed by binding into = ANY operator as the string representation of the array '{1,2,3}' of PostgreSQL 9.3.
The php-code on Laravel 5.1:
public function executeSql($ids)
{
$ids='{'.$ids.'}';
$condition = 'WHERE id = ANY(:ids)';
$sql="SELECT id FROM (VALUES (1),(2),(3)) AS t(id) $condition";
DB::select($sql,[':ids'=>$ids]);
}
The result is the query:
SELECT id FROM (VALUES (1),(2),(3)) AS t(id) WHERE id = ANY('{1,2,3}')
That's works well untill the parameter contains integers only.
If the parameter is 1,2,3+ the QueryException occurs:
Invalid text representation: 7 ERROR: invalid input syntax for integer: "3+"
Can it be considered a proper protection to avoid SQL-injection?
As far as I understand from the documentation here and here , ANY convert the string you pass into an array and then use the operator (=) to compare each value in the array for one that would match.
In this case, I think pgsql do a little more: it has seen the lvalue (id) is of type integer, so it expect an array of integers. Since 3+ is not an integer, you have this one.
You should probably inspect the content of ids array (using filter_var and like) to ensure you have only integer values.
Since you definitively want the query to run with unintended result, this fails as a proper SQL injection because ANY checks its input and the query fails before running.
If however pgsql comes with a facility to build an array of integer from range, like {1:999999999999}, then you probably have a problem because the query will match a lot whole more rows.
I have a field 'year' in table 1 which is defined as a VARCHAR(255) and I need to update 'num_years' in table 2 with the value of 'year'. 'num_years' is defined as an INT.
When I try to update 'num_years' with 'year' if 'year' is defined as 3 it works fine, but if I define 'year' as 'foo' it will update 'num_years' with 0.
When I used to use mysql_query functions it would generate an error about invalid column 'foo' or similar, but with PDO it doesn't throw an exception when I was expecting it to.
In this manner we want to ensure that 'num_years' is not updated with 0 if 'years' is numeric. Does PDO have anything built in that throws exception if this is the case?
I'm using PDO transactions and prepared statements.
Validate if its a string or not before you put it into your sql statement that way if your year from table1 consists of something like "1 year" you can explode or otherwise strip off the characters and the space and return just the 1 for insert into your int column in table 2.
Also doing it this way you can special handle events like text only in input field and set it as either a 0 or a -1 or something in your int field which you can later trap and validate on display to say "not specified" or something equivilent.
Hope that makes sense
Instead of inserting a string variable to PDO you can insert something like $delta = $year + 0. If it is "foo" you get $delta = 0 and adding this to num_years will not change them.
The other way is of course typecasting, so use (int)$year.
This should be done in PHP, not PDO.
I have a MYSQL table with an ENUM field named "offset" and some other columns. The field is defined as:
ENUM(0,1), can be NULL, predefined value NULL
Now I have two server. A production server and a development server and the same PHP script used to create and to update the database.
First step: the application create the record witout passing the "offset" in the CREATE query.
Second step: the application ask to the user some data (not the "offset" value), read the row inserted in step one and make an array, update some field (not the "offset" field), create a query in an automated fashion and save the row again with the updated values.
The automated query builder simple read all the field passed in an array and create the UPDATE string.
In both systems I obtain this array:
$values = array(... 'offset' => null);
and convert it in this same query passing the values in the mysql_real_escape_string:
UPDATE MyTable SET values..., `offset` = '' WHERE id = '10';
Now there is the problem. When i launch the query in the production system, the row is saved, in the development system I got an error and the db says that the offset data is wrong without saving the row.
From phpmyadmin when I create the row with the first step, it shows NULL in the offset field. After saving the field in the system which give no errors, it show me an empty string.
Both system are using MySQL 5 but the production uses 5.0.51 on Linux and development use 5.0.37 on Windows.
The questions:
Why one system give me an error an the other one save the field ? Is a configuration difference ?
Why when I save the field which is an enum "0" or "1" it saves "" and not NULL ?
Why one system give me an error an the other one save the field ? Is a configuration difference ?
Probably. See below.
Why when I save the field which is an enum "0" or "1" it saves "" and not NULL ?
According to the MySQL ENUM documentation:
The value may also be the empty string ('') or NULL under certain circumstances:
If you insert an invalid value into an ENUM (that is, a string not present in the list of permitted values), the empty string is inserted instead as a special error value. This string can be distinguished from a "normal" empty string by the fact that this string has the numeric value 0. ...
If strict SQL mode is enabled, attempts to insert invalid ENUM values result in an error.
(Emphasis added.)
strager's answer seems like a good explanation on why your code behaves differently on the 2 environments.
The problem lies elsewhere though. If you want to set a value to NULL in the query you shound use exactly NULL, but you are using mysql_real_escape_string() which result is always a string:
$ php -r 'var_dump(mysql_real_escape_string(null));'
string(0) ""
You should handle this differently. E.g:
$value = null
$escaped_value = is_null($value) ? "NULL" : mysql_real_escape_string($value);
var_dump($escaped_value);
// NULL
Some DB layers, like PDO, handle this just fine for you.
If you want it to be NULL, why don't you do this in the first place:
UPDATE MyTable SET values..., `offset` = NULL WHERE id = 10;