INSERT statement does not work with PDO - php

EDIT: PDO appears to have an issue with the French character in the column name Unité. Is there a solution to this, or do I need to rename the column in the database?
SELECT statements work with PDO, but the INSERT statement does not.
Connection string:
$dbCon = new PDO("mysql:host=".$host.";dbname=".$dbName.";charset=utf8", $username, $password);
Working SELECT statement:
$sql = 'SELECT * FROM availability WHERE event_id=:postID';
$stmt = $dbCon->prepare($sql);
$stmt->execute(array(':postID'=>$postID));
$result = $stmt->fetchAll();
Non-functioning INSERT statement:
$sql = 'INSERT INTO `availability` (`event_id`,`Nom`,`Address`,`Address2`,`Tel1`,`Tel2`,`Tel3`,`Classement`,`Soleil`,`Unité`,`Dispo`,`Ville`,`Type`,`URL`,`Jour1`,`Jour2`,`Jour3`,`Jour4`,`Jour5`,`Jour6`,`Jour7`,`Jour8`,`Jour9`,`Jour10`,`Jour11`,`Jour12`,`Jour13`,`Jour14`,`Jour15`,`visible`) (SELECT :postID,`Nom`,`Address`,`Address2`,`Tel1`,`Tel2`,`Tel3`,`Classement`,`Soleil`,`Unité`,`Dispo`,`Ville`,`Type`,`URL`,`Jour1`,`Jour2`,`Jour3`,`Jour4`,`Jour5`,`Jour6`,`Jour7`,`Jour8`,`Jour9`,`Jour10`,`Jour11`,`Jour12`,`Jour13`,`Jour14`,`Jour15`,`visible` FROM `default_hotels`)';
$stmt = $dbCon->prepare($sql);
$stmt->execute(array(':postID'=>$postID));
$result = $stmt->fetchAll();
Another working SELECT statement:
$sql = 'SELECT post_title FROM wp_posts WHERE id=:postID';
$stmt = $dbCon->prepare($sql);
$stmt->execute(array(':postID'=>$postID));
$records = $stmt->fetchAll();
All of the statements appear in this order in my script. The variables are re-used and not cleared.
The SQL INSERT statement that I provided works when submitted through phpmyadmin but not PDO.

The PDO charset parameter in the connection string started being supported in PHP 5.3.6. Before that it did nothing. So the problem is that the connection to your database is not actually run in utf8, but likely latin1. Hence the encoding of the column name in PHP and in MySQL doesn't match, hence MySQL misunderstands the column name, hence can't find the column you ask for.
See https://stackoverflow.com/a/279279/476 for alternative ways to specify the connection encoding, upgrade your version of PHP, or use ASCII-only for column names (that's a good idea anyway, specifically because it makes compatibility issues like this much less of a problem).

Related

Understanding PDO Prepared Statements and Binding Parameters

From experience and also having been told constantly the benefits of using prepared statements and binding my parameters, I have constantly used those two techniques in my code, however I would like to understand exactly the purpose of each of those two techiques:
From my understanding of prepared statements:
$sql = "SELECT * FROM myTable WHERE id = ".$id;
$stmt = $conn->prepare($sql);
$stmt->execute();
The previous code should create a sort of a buffer in the database with the query I proposed. Now FROM MY UNDERSTANDING (and I could be very wrong), the previous code is insecure, because the string $sql could be anything depending on what $id actually is, and if $id = 1; DROP TABLE myTable;--, I would be inserting a malicious query even though I have a prepared statement.
FROM MY UNDERSTANDING this is where binding my parameters com in. If I do the following instead:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
The database should know exactly all the parts of the sql statement before hand:
SELECT these columns: * FROM myTable and WHERE id = "a variable that was input by the user", and if "a variable that was input by the user" != a variable, the query fails.
I have been told by some my understanding is correct, and by others that it is false, could someone please let me know if I am wrong, correct, or missing something? And elaborate as much as you want, all feedback is greatly appreciated!
You're correct that the first case is insecure. It's important to understand though, that preparing a statement only has value if you are using variable data, and/or executing the same query repeatedly. If you are executing plain statements with no variables, you could simply do this:
$sql = "SELECT * from myTable WHERE this_column IS NOT NULL";
$result = $conn->query($sql);
And end up with a PDOStatement object to work with, just like when you use PDO::exec().
For your second case, again, you're largely correct. What's happening is the variable passed to the database is escaped and quoted (unless you specify otherwise with the third argument to PDOStatement::bindParam(), it's sent as a string which is fine for most cases.) So, the query won't "fail" if bad data is sent. It behaves exactly as if you had passed a valid number that didn't exist as an ID in the database. There are, of course, some edge cases where you are still vulnerable even with a correctly prepared statement.
Also, to make life easier, you can use prepared statements like this, to do implicit binding:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([":id"=>$id]);
Or even like this, with un-named parameters:
$sql = "SELECT * FROM myTable WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);
Naturally, most of this has been explained in the comments while I was typing up the answer!

Mysqli LIKE not working with apostrophe?

When I use my mysqli function to search the database for a certain string with a ' (apostrophe) it never finds a result, although it is exactly the same in the databse.
For example: I search for: dawn's, this gets escaped through real_escape to: dawn\'s and this is the same as in the database (it's put in escaped as well in the database). But still it does not give me a result.
This is the code I use:
$mysqli = goConnect();
$query = $mysqli->real_escape_string($query);
if(!($stmt = $mysqli->prepare("SELECT * FROM movies WHERE title LIKE '%$query%'"))){
http_response_code(400);
echo "<p class='results'>Cannot prepare the statement, please try again later.</p>";
}
echo $query;
if($stmt->execute()){
Why doesn't this work properly?
Mysqli doesn't have a LIKE operator and Mysql LIKE works with any characters, including apostrophe.
and this is the same as in the database (it's put in escaped as well in the database).
This is what you are doing wrong. It shouldn't be the same in the database. It should be stored as is.
Besides, you should always, always ALWAYS use placeholders to substitute variables in the query. Were you using them, you'd never encounter a problem like this.
So, first change this code to
$mysqli = goConnect();
$stmt = $mysqli->prepare("SELECT * FROM movies WHERE title LIKE ?");
$query = "%$query%";
$stmt->bind_param("s", $query);
$stmt->execute();
And then change your insert code accordingly, to make it add not a single extra character to the data.

MySQL DB query compare to PHP variable

I am very new to PHP and only have a class from a year ago where I touched MySQL.
I am trying to add a check in some existing code to query a db table for a value, and if that value is = to 1, change a variable in the code. Seems simple enough but it's not working out. I am getting 0 results from my query, even though the query works as expected in Sequel Pro.
I am modeling my syntax after the existing query even though I don't fully understand the prepare and execute functions, because I don't want to create a new db connection to make it easier on myself. I'll give the snippets that matter, I think.
My question: Why is this not returning results, when it works fine in the database directly? The query should return 2 results, in the form of Integers, which I want to compare to another integer, $friend_uid.
$dbObj = new sdb("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USERNAME, DB_PASSWORD);
$dbObj->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$newStatus = 'REQUEST_PENDING';
$botquery = "SELECT `KAP_USER_MAIN.UID` FROM `KAP_USER_MAIN` WHERE `KAP_USER_MAIN.IS_BOT` = 1";
$botstatement = $dbObj->prepare($botquery, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$botstatement->execute();
$posts[]= "sql error " . mysql_error();
if(!$botstatement){
$posts[] = "failed bot query: " . mysql_error();
}
$num_rows = mysql_num_rows($botstatement);
if ($num_rows == false) {
$num_rows = 0;
}
$posts[] = "$num_rows rows";
while($row = mysql_fetch_array($botstatement)) {
if($row[0]['UID'] == $friend_uid){
$newStatus = 'FRIENDS';
}
}
$statement->execute(array(':uid'=>$uid,':friend_uid'=>$friend_uid,':status'=>$newStatus));
Here is an example of a query from the existing code that works just fine, which I am modeling after:
$query = "SELECT kits.TOTAL_UNIT,kum.ENERGY,kum.NAME,kum.LEVEL FROM KAP_USER_MAIN kum,KNP_INVENTORY_TRANSACTION_SUMMARY kits WHERE kits.UID = :uid AND kits.INV_ID = '10004' and kum.UID = :uid";
$statement = $dbObj->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$statement->execute(array(':uid'=>$uid));
$res = $statement->fetchAll(PDO::FETCH_ASSOC);
$sender_name = $res[0]['NAME'];
DON'T MIX PDO AND MYSQL FUNCTIONS
Looking more closely at the code, it looks like you are mixing PDO and mysql functions.
That's not valid. Don't mix calls to the two separate interface libraries.
The mysql_fetch_array function cannot be used to fetch from a PDO statement. Use the appropriate PDO fetch functions/methods.
There are three separate and distinct MySQL interface libraries in PHP.
There's the older (and now deprecated) mysql interface, all the functions from that interface start with mysql_.
There's the improved mysqli interface. The procedural style functions all begin with mysqli_.
And thirdly, there's the more database independent PDO interface.
Do not mix calls of these three separate interface libraries, because mixing calls won't work.
It looks like you're getting a connection with PDO, preparing a statement with PDO... but you are calling the msyql_error, mysql_num_rows and mysql_fetch_array functions. Replace those calls to the mysql_ functions with the appropriate PDO functions.
DOT CHARACTER IN COLUMN NAME?
It's very strange to include a dot character in a column name. (It's not invalid to do that, but something like that wouldn't fly in our shop.)
SELECT `KAP_USER_MAIN.UID` FROM `KAP_USER_MAIN` WHERE `KAP_USER_MAIN.IS_BOT` = 1
^ ^
But I'm suspicious that the column names are actually UID and IS_BOT, and that what you intended was:
SELECT `KAP_USER_MAIN`.`UID` FROM `KAP_USER_MAIN` WHERE `KAP_USER_MAIN`.`IS_BOT` = 1
^ ^ ^ ^
Each identifier (the column name and the table name) can be escaped separately. The dot character between the table name and the column name should not be escaped, because that's part of the SQL text, not part of the identifier.
We typically use a short table alias in our queries, so a typical query would look like this:
SELECT m.UID FROM `KAP_USER_MAIN` m WHERE m.IS_BOT` = 1
Or, for a query equivalent to the original query (with the dot character as part of the column name), like this:
SELECT m.`KAP_USER_MAIN.UID` FROM `KAP_USER_MAIN` m WHERE m.`KAP_USER_MAIN.IS_BOT` = 1
(That's not invalid, to include a dot character in a column name, but it is an unusual pattern, one that we don't see very often. I think that's because that pattern leads to more potential problems than whatever problem it was intended to solve.)
If the query works the way it is in your code, then that dot character must be part of the column name.

PDO: select fetch last columns as NULL

when i select data from ODBC with PDO (in PHP) some columns are fetched as NULL, but in database data exists. Where i execute same query with odbc_* functions it works fine.
Here is code i using
$sql = "SELECT * FROM table WHERE rowid = 123456";
$connection = odbc_connect("Velocis RDS", $usr, $pwd);
$result = odbc_exec($connection, $sql);
while ($data = odbc_fetch_array($result)) {
print_r($data);
}
With this all columns are fetched correctly :
$connection = new PDO("odbc:Velocis RDS", $usr, $pwd);
$stmt = $dbConn->prepare("SELECT * FROM table WHERE rowid = 123456");
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$stmt->execute();
print_r($stmt->fetchAll());
with this code last 9 columns are fetched as NULL. There is nothing special with this columns. It contains text or numbers.
Any help would be appreciated. Thanks in advance.
I actually had the exact same issue with a different type of database where the id field worked but the others returned null via pdo_odbc and worked 100% with odbc. After a lot of research I came across a PHP Bug report with similar issue (Bug#61573) but paved the way to for me to figure out a fix.
Try type casting the fields to VARCHAR. This worked for me. The issue is that pdo_odbc does not work with several types that odbc can.
For reference or if still needed please include the PHP version and table schema as these are important to figure out fixes. :)

How do you connect/retrieve data from a MYSQL database using objects in PHP?

Generally I connect and retrieve data using the standard way (error checking removed for simplicity):
$db = mysql_select_db("dbname", mysql_connect("host","username","passord"));
$items = mysql_query("SELECT * FROM $db");
while($item = mysql_fetch_array($items)) {
my_function($item[rowname]);
}
Where my_function does some useful things witht that particular row.
What is the equivalent code using objects?
Since version 5.1, PHP is shipped with the PDO driver, which gives a class for prepared statements.
$dbh = new PDO("mysql:host=$hostname;dbname=$db", $username, $password); //connect to the database
//each :keyword represents a parameter or value to be bound later
$query= $dbh->prepare('SELECT * FROM users WHERE id = :id AND password = :pass');
# Variables are set here.
$query->bindParam(':id', $id); // this is a pass by reference
$query->bindValue(':pass', $pass); // this is a pass by value
$query->execute(); // query is run
// to get all the data at once
$res = $query->fetchall();
print_r($res);
see PDO driver at php.net
Note that this way (with prepared statements) will automatically escape all that needs to be and is one of the safest ways to execute mysql queries, as long as you use binbParam or bindValue.
There is also the mysqli extension to do a similar task, but I personally find PDO to be cleaner.
What going this whole way around and using all these steps gives you is possibly a better solution than anything else when it comes to PHP.
You can then use $query->fetchobject to retrieve your data as an object.
You can use the mysql_fetch_object()
http://is2.php.net/manual/en/function.mysql-fetch-object.php

Categories