PDO + MsSQL + freetds = wrong characters in INSERT queries - php

I've noticed a problem during SELECT queries in my internal project, regarding utf8 characters (šđčćž). After I'd fixed problem regarding freetds definition for charset and version in freetds.conf, I've started to receive right characters when I run SELECT queries.
But! Now I'm experiencing problem regarding INSERT/UPDATE queries and with SELECT query when I try to search fields with some of those characters (šđčćž), and that's only with PDO bindValue method.
For example, this is my code:
try {
$pdo = new \PDO(
"dblib:host=$host:$port;dbname=$database",
"$username",
"$password"
);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "There was a problem connecting. " . $e->getMessage();
}
When I try insert values with following code, inserted values in database are right:
$query = "INSERT INTO dbo.TABLE (ID, NAME) VALUES (2, 'Beriša');";
$statement = $pdo->prepare($query);
$statement->execute();
//Result:
//2 Beriša
But, after using bindValue method (which I must use, as I work with Symfony2), problem happens:
$query = "INSERT INTO dbo.TABLE (ID, NAME) VALUES (?, ?);";
$statement = $pdo->prepare($query);
$statement->bindValue(1, 2, \PDO::PARAM_INT);
$statement->bindValue(2, 'Beriša', \PDO::PARAM_STR);
$statement->execute();
//Result:
//2 Beriša
Bellow, you can find my current freetds configuration:
[global]
tds version = 8.0
text size = 20971520
client charset = UTF-8
Database charset coalition is Croatian_CI_AS. Unfortunately, I can't change that, as it's old database, designed to work with old application, and for that application I'm working on web presentation.

I have found a solution after some time. It's not a perfect one, as I need to process each value (it's small fix for code, but still not clean enough). If anyone has another idea to make this one better, post it, pls.
$statement->bindValue(2, iconv('utf-8', 'Windows-1252', 'Beriša'), \PDO::PARAM_STR);

Related

PHP - insert in prepared query doesn't work

I have hard time trying to do a simple insert into my sqlite3 db using php7.0
This code prints result correctly, so SELECT's work
$dbconn = new PDO('sqlite:/home/rooter/Desktop/XSS/db/ex1');
$stmtinit = $dbconn->prepare("select count() from tokens;");
$stmtinit->execute();
$rows = $stmtinit->fetch(PDO::FETCH_BOTH);
$tks = $rows[0];
print "tokens_size:".$tks;
But code below doesn't do anything and doesn't throw any error/warning/notice. Table tokens has unchanged size.
$dbconn = new PDO('sqlite:/home/rooter/Desktop/XSS/db/ex1');
$stmt = $dbconn->prepare("insert into tokens(user, token) values ('plaintxt','plaintxt')");
$stmt->execute();
If i try to do that insert manually in db, it works properly.
Following advice from Fred -ii- i turned error mode on
$dbconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Which resulted in message: "attempt to write a readonly database". That happened because when I was creating database I was root.

PHP PDO & Large Objects (LOB) broken after update

A few months ago, my Ubuntu package auto-updated PHP from 7.0.8 to 7.0.13, at which point my script for updating photos stored on a SQL database started failing. I got around this by reinstalling 7.0.8. Last month, I was again auto-updated to 7.0.15 and my script failed again.
My script writes a jpg image to a MS-SQL database, using PDO & FreeTDS, plus Large Objects (LOB) to handle the photo. I emphasise that it worked up to PHP version 7.0.8. The following is a test script isolating my problem.
<?php
$dsn = 'dblib:dbname=photos;host=gary';
$id = 693925;
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$photo = file_get_contents("coco.jpg");
$query = "UPDATE photo_table SET photo = :photo WHERE id = :id";
$stmt = $dbh->prepare($query);
$stmt->bindValue(":photo", $photo, PDO::PARAM_LOB);
$stmt->bindValue(":id", $id, PDO::PARAM_INT);
$stmt->execute();
}
}
catch (PDOException $e) {
echo $e->getMessage();
}
The result is an "Incorrect syntax" error!?
SQLSTATE[HY000]: General error:
102 Incorrect syntax near '����'.[102] (severity 15) [(null)]
Using the latest available PHP version 7.0.15, reading from the database works, including reading the photo as a Large Object. There is no problem writing every other field to the database, it only fails on my image.
Despite searching over the last few weeks, I still have to find someone else reporting the same problem.
I am after any advice, either a change to the code, or some configuration settings to allow LOBs to work again.
I suggest you use bindParam instead of bindValue always because in bindParam
Unlike PDOStatement::bindValue(), the variable is bound as a
reference and will only be evaluated at the time that
PDOStatement::execute() is called.
$photo = file_get_contents("coco.jpg");//change this to below
$photo = fopen($_FILES['file']['tmp_name'], 'rb');
$query = "UPDATE photo_table SET photo = :photo WHERE id = :id";
$stmt = $dbh->prepare($query);
$stmt->bindValue(":photo", $photo, PDO::PARAM_LOB);//change to this below
$stmt->bindParam(":photo", $photo, PDO::PARAM_LOB);
$stmt->bindValue(":id", $id, PDO::PARAM_INT);//change this to below
$stmt->bindParam(":id", $id, PDO::PARAM_INT);
This is just only suggestions check here...... http://php.net/manual/en/pdo.lobs.php & http://www.php.net/manual/en/pdostatement.bindparam.php#refsect1-pdostatement.bindparam-description
My solution/workaround was to convert the binary from the image into hexadecimal representation before sending the data to SQL.
$photo = bin2hex(file_get_contents("coco.jpg"));
converting it back again during the SQL statement.
$query =
"UPDATE photo_table SET photo=CONVERT(varbinary(max), :photo, 2) WHERE id = :id";

Bulk insert using PDO and PHP variable containing all database values

I am new to PHP and am trying to update a deprecated code from mysql to PDO.
Considering that the variable $insert contains all values to bulk insert such as:
('82817cf5-52be-4ee4-953c-d3f4ed1459b0','1','EM3X001P.1a','04.03.10.42.00.02'),
('82817cf5-52be-4ee4-953c-d3f4ed1459b0','2','EM3X001P.2a','04.03.10.33.00.02'),
...etc 13k lines to insert
here is the deprecated code:
mysql_connect('localhost', 'root', '') or die(mysql_error());
mysql_select_db("IPXTools") or die(mysql_error());
if ($insert != '')
{
$insert = "INSERT INTO IPXTools.MSSWireList (ID,Record,VlookupNode,HostWireLocation) VALUES ".$insert;
$insert .= "ON DUPLICATE KEY UPDATE Record=VALUES(Record),VlookupNode=VALUES(VlookupNode),HostWireLocation=VALUES(HostWireLocation)";
mysql_query($insert) or die(mysql_error());
$insert = '';
}
here is the new code:
try
{
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //set the PDO error mode to exception
// prepare sql and bind parameters
$stmt = $conn->prepare("INSERT INTO IPXTools.MSSWireList (ID, Record, VlookupNode, HostWireLocation)
VALUES (:ID, :Record, :VlookupNode, :HostWireLocation)");
$stmt->bindParam(':ID', $ID);
$stmt->bindParam(':Record', $Record);
$stmt->bindParam(':VlookupNode', $VlookupNode);
$stmt->bindParam(':HostWireLocation', $HostWireLocation);
// insert a row
// loop through all values inside the $insert variable??????? how?
$stmt->execute();
}
catch(PDOException $e)
{
echo "Error: " . $e->getMessage();
}
$conn = null;
During my research I found an excellent post:
PDO Prepared Inserts multiple rows in single query
One method says I would have to change my $insert variable to include all the field names.
And other method says I dont have to do that. I am looking at Chris M. suggestion:
The Accepted Answer by Herbert Balagtas works well when the $data array is small. With larger $data arrays the array_merge function becomes prohibitively slow. My test file to create the $data array has 28 cols and is about 80,000 lines. The final script took 41s to complete
but I didnt understand what he is doing and I am trying to adapt my code to his. The PHP sintax is new to me so I am strugling with handling the arrays, etc...
I guess the starting point would be the variable $insert which contains all the database values I need.
Do I need to modify my $insert variable to include the field names?
Or I could just use its content and extract the values (how?) and include the values in a loop statement? (that would probably execute my 13k rows one at at time)
Thank you
If you have 13k records to insert, it is good for performance to do not use prepared SQL statement. Just generate SQL query in format like this:
INSERT INTO IPXTools.MSSWireList
(ID, Record, VlookupNode, HostWireLocation)
VALUES
('id1', 'r1', 'node1', 'location1'),
('id2', 'r2', 'node2', 'location2'),
...
('id13000', 'r13000', 'node13000', 'location13000');
What you may do for it - use maner of your legacy code. Your try block will looks loke this:
try
{
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->exec($insert);
}

print_r an insert statement php pdo

I'm using this method to insert data into my database:
function insertMenue($content, $date) {
$session = $_SESSION['aid'];
global $pdo;
$pdo->exec('SET CHARACTER SET utf8');
$query = $pdo->prepare('INSERT INTO menue(type, content, date, creator) VALUE (?,?,?,?)');
$query->bindValue(1, "menue");
$query->bindValue(2, "<p>" . $content . "</p>");
$query->bindValue(3, $date);
$query->bindValue(4, $session);
$query->execute();
}
I'm calling this method for every object in an array. Now every time when there should be a String which contains an umlaut (ä, ö, ü) the String gets cut off where the umlaut should be.
As for example I'm writing:
<p>Salat<br>Gemüse und Teigwaren</p>
The data in the database happens to be just:
<p>Salat<br>Gem
Now the question is:
How can I print_r() the whole sql statement?
print_r($query->execute());
Would display (1,1,1,1)
and I want something like:
(menue, (p)Salat(br)Gemüse und Teigwaren(/p), 2015-09-06, 2)
I'm not sure whether it doesn't get to the database or whether the database is the problem.
The db itself can handle umlaute and is written in utf-8. I dumped the file and took a closer look at it, it shouldn't be corrupted.
You cant see the full query, because it doesnt exist in the PHP side.
PHP first sends the query and then the parameters when using prepared statements
(Not sure what happens when the emulation mode is on though).
If you want to see the final query, you should enable your database's query log and check there.
This is the closest you can get with just PHP:
http://us2.php.net/manual/en/pdostatement.debugdumpparams.php
Try this...
function insertMenue($content, $date) {
$session = $_SESSION['aid'];
global $pdo;
$pdo->exec('SET CHARACTER SET utf8');
$params = ["menue", "<p>$content</p>", $date, $session];
// Check all your params are set...
// Although you may want to consider checking these before entering this block
print_r($params);
$sql = "INSERT INTO menue( type
, content
, date
, creator
)
VALUES( ?
, ?
, ?
, ?
)";
try {
$sth = $pdo->prepare($sql);
$sth->execute($params);
} catch (PDOException $e) {
throw new pdoDbException($e);
}
}

PHP + MySQL transaction+syntax error

First of all I'm new in web development so sorry if its a dumb question,I have an array, that the keys of the array are the id of the records that need to be updated in the database, i came with the bellow code to create the query and using mysql transaction to run the query (since few records should be updated together). the generated query works fine when i run it using command line, but with php code NO!
The code to generate the query :
$insert="";
if($run==true){
foreach($result as $key=>$x){
$insert = $insert ."update project set type='".$x."' "."where "."id=".$key.";";
}
//echo $insert;
$insert=$insert ."COMMIT;";
$insert= "START TRANSACTION;". $insert;
The result of the code:
START TRANSACTION;update project set type='project1' where id=1;update project set type='project2' where id=2;COMMIT;
The error that it gives me:
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'update project set type='project1' where id=1;update project set type='project2'' at line 1
I did not include the sql connections and... since i believe in high percentage they are fine, but in case its necessary i can include them too.
Thanks in advance
Multiple queries are not supported using MySQL functions. You would need to break down the transaction:
$sql1 = UPDATE `project` SET `type`='project1' WHERE `id`=1;
$sql2 = UPDATE `project` SET `type`='project2' WHERE `id`=2;
You can however use mysqli_mutli_query or as mentioned in another answer PDO
You might want to switch to PDO which has an interface to transactions directly.
$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("update project set type= ? where id= ?");
$db->beginTransaction();
try {
foreach ($result as $key => $x) {
$db->execute(array($x, $key));
}
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
throw $e;
}

Categories