PDO_OCI - into a clob field - php

I want to insert some base64 encoded data (up to 500.000 characters per field) in an Oracle DB.
Since i havn't used Oracle with PHP before i started using PDO and set fields to CLOB.
Shortversion of my code (class Db extends \PDO):
<?php
[..snip..]
$dbh = new Db( "oci:dbname=" . DB_TNS, DB_USER, DB_PASS );
$Query = ' INSERT INTO "SENTINEL"."SYSTEM_ERRORS"
( BACKTRACE )
VALUES
( :backtrace )
';
$stmt = $dbh->db_prepare( $Query );
$stmt->bindParam( ':backtrace', $backtrace, \PDO::PARAM_LOB );
$backtrace = $someobject->get_backtrace();
$stmt->execute();
print_r($stmt->errorInfo());
$stmt->closeCursor();
I get:
Array ( [0] => HY000 [1] => 932 [2] => OCIStmtExecute: ORA-00932: Inkonsistente Datentypen: CLOB erwartet, BLOB erhalten (ext\pdo_oci\oci_statement.c:148) )
Anyone know how to solve that with PDO, so i don't have to use the oci driver?

I have found a solution here:
https://bugs.php.net/bug.php?id=57095
[2009-08-11 11:27 UTC] lehresman at gmail dot com
wrote:
A coworker discovered the solution. When dealing with CLOBs in Oracle using PDO,
don't treat it as a LOB. You need to bind it as a PDO::PARAM_STR, and give it the
length of the string (that 4th parameter is the key, it fails with an error message
about LONG type otherwise).
Here is an example of how to successfully insert into a CLOB in Oracle:
<?php
/*
CREATE TABLE clob_test (my_clob CLOB)
*/
$big_string = "";
for ($i=0; $i < 10000; $i++)
$big_string .= rand(100000,999999)."\n";
try {
$pdo = new PDO("oci:dbname=TESTDB", "TESTUSER", "TESTPW");
$stmt = $pdo->prepare("INSERT INTO healthbit.clob_test (my_clob) VALUES (:cl)");
$stmt->bindParam(":cl", $big_string, PDO::PARAM_STR, strlen($big_string));
$pdo->beginTransaction();
if (!$stmt->execute()) {
echo "ERROR: ".print_r($stmt->errorInfo())."\n";
$pdo->rollBack();
exit;
}
$pdo->commit();
$stmt = $pdo->prepare("SELECT my_clob FROM healthbit.clob_test");
$stmt->execute();
$row = $stmt->fetch();
$str = "";
while ($tmp = fread($row[0],1024))
$str .= $tmp;
echo strlen($str); // prints 70000
} catch (Exception $e) {
echo "ERROR: ";
echo $e->getMessage();
$pdo->rollBack();
}
Works perfectly fine for me...

Related

How to get the return value from a stored procedure? PHP | PDO

I want to show the return value of SP of SQL Server. I tried to use this way, but I wasn't successful.
I am using the PHP PDO for the database connection and I am executing an SQL Server stored procedure.
$feesObj = new FeesConfig('config/fees.ini');
$feesConfig = $feesObj->getFeesConfig();
$studentId = $user->getSyStudentId();
$statement = $conn->prepare('exec ?= usp_GetStudentDegreeLevel ?');
$statement->bindParam(1, $retval, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT);
$statement->bindParam(2, $studentId, PDO::PARAM_INT);
$statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
var_dump("return value". $retval);exit;
Output of this SP Execution
NULL
Expected Result
1
Where I am wrong with this code. I am calling the SQL Server SP.
Original answer (with my usual approach for getting the return value(s) of possible output parameters and the return value of the stored procedure):
You may consider the following:
The return value from a stored procedure is an integer, so you need to use an appropriate binding.
In case of an OUTPUT parameter you need to set the maxLength parameter in the PDOStatement::bindParam call. As is explained in the documentation, to ...indicate that a parameter is an OUT parameter from a stored procedure, you must explicitly set the length.
You need to fetch all possible result sets (using PDOStatement::nextRowset) to get the value of an output parameter. Or, as an option, in case of an INSERT or UPDATE statement, put SET NOCOUNT ON as first line in your stored procedure. As is explained in the documentation, this statement ... stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set.
Below is a simplified example using SQL Server 2017, PHP 7.4.8 and PHP Driver for SQL Server 5.8:
Stored procedure:
CREATE PROCEDURE usp_GetStudentDegreeLevel
#StudentId INT
AS
BEGIN
SELECT 'Information about the student' AS StudentInfo;
RETURN 1;
END
PHP code:
<?php
$server = 'server\instance,port';
$database = 'database';
$username = 'username';
$password = 'password';
try {
$conn = new PDO("sqlsrv:server=$server;Database=$database", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);
} catch( PDOException $e ) {
die( "Error connecting to SQL Server".$e->getMessage());
}
try {
//
$sql = "EXEC ? = usp_GetStudentDegreeLevel ?";
$statement = $conn->prepare($sql);
if ($statement === false) {
echo print_r($conn->errorInfo(), true);
exit;
}
// Execution
$retval = 0;
$studentId = 1;
$statement->bindParam(1, $retval, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$statement->bindParam(2, $studentId, PDO::PARAM_INT);
if ($statement->execute() === false) {
echo print_r($conn->errorInfo(), true);
exit;
}
// Fetch data.
do {
if ($statement->columnCount() > 0) {
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
echo print_r($row, true);
};
};
} while ($statement->nextRowset());
//
var_dump("Return value: " . $retval);
$statement = null;
} catch (PDOException $e) {
echo $e->getMessage();
exit;
}
$conn = null;
?>
Result:
Array ( [StudentInfo] => Information about the student ) string(15) "Return value: 1"
Update (an example, which reproduces the unexpected return value):
The only way I can reproduce this error is the combination of:
Using PDO::ERRMODE_SILENT as default error handling mode.
An error in the stored procedure and/or an error in the SQL statement.
No checks whether the result from the PDO::prepare and/or PDOStatement::execute calls is successful or not.
PHP code:
// PDO object with default error handling (PDO::ERRMODE_SILENT, but for PHP version before 8.0.0)
$conn = new PDO("sqlsrv:server=$server;Database=$database", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);
// SQL statement with error
$sql = "EXEC ? = usp_GetStudentDegreeLevel ,?";
$statement = $conn->prepare($sql);
$statement->bindParam(1, $retval, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 1);
$statement->bindParam(2, $studentId, PDO::PARAM_INT);
$statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
//
var_dump($retval);
Result:
NULL

How to properly select from MSSQL using PHP PDO with query, containing cyrillic symbols?

I'am trying to perform simple SELECT query from PHP PDO to MSSQL database. While query contains cyrillic symbols in WHERE condition, result is empty (if not contains, result return successfully). What can I do to correct query?
putenv('ODBCSYSINI=/etc/');
putenv('ODBCINI=/etc/odbc.ini');
$configODBC = config('database.odbc');
try {
$this->pdo = new PDO('odbc:'. $configODBC['default']['source'], $configODBC['default']['username'], $configODBC['default']['password']);
} catch (PDOException $e) {}
...
$statement = $this->pdo->prepare("SELECT * FROM [DB].[dbo].table WHERE policy_num LIKE '%cyrillic_symbols%'");
$result = $statement->execute();
if ($result) {
while ($out = $statement->fetch()) {
var_dump($out[0]);
}
}
PS. MSSQL version 2012. Data in UTF-8 encoding.
I'll post this as an answer, because it's too long for comment. UTF-8 all the way through, suggested by #RiggsFolly has all the answers. In your case, you need to convert values from CP-1251 from/to UTF-8 . I've made this simple test case, see if this will help you:
T-SQL:
CREATE TABLE CyrillicTable (
[CyrillicText] varchar(200) COLLATE Cyrillic_General_CI_AS
)
INSERT INTO CyrillicTable
(CyrillicText)
VALUES
('Понедельник'),
('Вторник')
PHP (file is UTF-8 encoded, using Notepad++):
<?php
# Connection info
$hostname = 'server\instance,port';
$dbname = 'database';
$username = 'uid';
$pw = 'pwd';
# Connection
try {
$dbh = new PDO("odbc:Driver={SQL Server Native Client 11.0};Server=$hostname;Database=$dbname", $username, $pw);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch( PDOException $e ) {
die( "Error connecting to SQL Server. ".$e->getMessage());
}
# Query
try {
echo "Query"."<br>";
$sql = "SELECT * FROM dbo.[CyrillicTable] WHERE CyrillicText LIKE '%".iconv('UTF-8', 'CP1251', 'онед')."%'";
$stmt = $dbh->query($sql);
while ($row = $stmt->fetch( PDO::FETCH_ASSOC )) {
foreach($row as $name => $value) {
echo $name.": ".iconv('CP1251', 'UTF-8', $value)."<br>";
}
}
echo "<br>";
} catch( PDOException $e ) {
die( "Error executing query: ".$e->getMessage());
}
$stmt = null;
# Query
try {
echo "Prepared query"."<br>";
$sql = "SELECT * FROM dbo.[CyrillicTable] WHERE CyrillicText LIKE ?";
$stmt = $dbh->prepare($sql);
$text = 'орни';
$text = "%$text%";
$text = iconv('UTF-8', 'CP1251', $text);
$stmt->bindParam(1, $text, PDO::PARAM_STR);
$stmt->execute();
while ($row = $stmt->fetch( PDO::FETCH_ASSOC )) {
foreach($row as $name => $value) {
echo $name.": ".iconv('CP1251', 'UTF-8', $value)."<br>";
}
}
echo "<br>";
} catch( PDOException $e ) {
die( "Error executing stored procedure: ".$e->getMessage());
}
$stmt = null;
# End
$dbh = null;
?>
Notes:
Consider using parameterized query.

Sql update for clob field in PDO (PHP) doesn't update nor throw update execption

I've searched all over the net for examples on performing a sql update on clob fields; I believe the example I'm using is the simplest one that should work but so far none have worked. I'm trying to insert a base64 encoded image into the clob field in oracle. Below are the function and the array of clob entries. I've checked the table and verified that no update has occurred on the clob field.
// update row with new clob values
private function clobUpdate($clobArray){
try {
foreach ($clobArray as $item) {
$query = "UPDATE ". static::$table ." SET ". $item["clobField"] ." = EMPTY_BLOB() WHERE ID = :ID RETURNING ". $item["clobField"] . " INTO :blob";
$stmt = $this->db->prepare($query);
$stmt->bindParam(':id', $item["id"]);
$stmt->bindParam(':blob', $item["clobValue"], PDO::PARAM_LOB);
$blob = NULL;
$this->db->beginTransaction();
$stmt->execute();
$this->db->commit();
print_r($blob);
die();
}
} catch(Exception $e){
throw new Exception($e);
}
}
Array
(
[0] => Array
(
[clobField] => 0
[clobValue] => data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAMAAABrrFhUAAAAM1BMVEWxvsa7xs7CzNPM1drT2t/a4OTd4+fn6+7g5enW3eLFz9W/ydC0wcnP1924xMvJ0tjk6OzcN6J1AAAED0lEQVR4AezBgQAAAACAoP2pF6kCAAAAAAAAAAC4vbvLgV3FgQBcCYHiLzT7X+28XWkermbOSeLYMd8OqAA2Ust9u20PR0z8R44l1AYX+n5G/ot01oFPG7/I/yGd23dXn/h/yZ/MoBX+gVTxLTXzD+XQ8Rl75l+YAd+wRf6lvMO+fvKCMmDclnjJ3GHaj5cdMOzgDVKHUT3xFnOzu37PCfREek6gJ9JzAj2RrhNIvNkc9uufo2r44wMKzNj4iB+M6JnP2GDDyYckmND4mAALMp8zoF/ggyLU65NPar43ABmdbwCy+d4AZHS9AfR3Q5WPO6BZ4uNmh16DAqrZZ7CDZ3GihO77BJC7/hrgtQ4cFJH1XwFeLwEKadCpUUjQ3wX4vAVPCknQKVIKdJqUskGjTjG7/iLgsQxUijmhUaCY6LsKksl5FSRXABpR0OY9gAZ9uvcAGgWFFYA6K4BAQcV7AHEFoM4KoFBQdv4UIFcAaqwAVgArgBXACmAFsAJokaJigyqB4oLz9atKoPEVDVpkviJDicqXVOhQ+JICFTpf06HBztfsmmqg30pYSN+XQORr4gpgBbACWJfgKoOrEVqt8HoMrefwuyZfMaFF4CuC/rkRbgYJFAVXoL9rsEKPzhd0KHJQ3AFNBsUNqHJS2GlrjK6DEatjUtAcUGckikkDGoVMETlAq01/A2S/J57Q7Od9mtxwfgIkRgl1+D4DBbp1v5PUZOpAhnY7HxWgXvb0CBa/Bg84Hy7e4Hu8fAR8b4EGE4LPDSCwBRqMqAIlwOGTaA6Y0cSbQAdzxRIs6Zl322BKEzgArpqBCHOiwK9B/LRDDQZtk3epMKm6aAEFEjhgVtW/fv0JlA7XCRwwrjpfP3BqfgHo74kbzDu9BxB5RfUeQFgBmDe9B0DnAXReUmBd4yXReRtAwrrMa3bYVknXZ6BnXtVgWeFlucOugzdI3ef67SfQC2+SBgxqmbeZO6zpJ29VOkypkzebFXa0xAfkBhtaFBgmrFeNfFCsUK3XzIfl2qHVOCcFzHNAoz1STNyhzAiZonIY0GMvfEHZnX58XdtgL3xV2Z1+fA3bYC9Uouy+Pr6CbdAK1SkNQvovU6X863jeOCbVmscQ3vvOTkJNNCBVPKNmGpGrs+ULRFAzjcnVyfIFImiJRqWG60ahYWXgot+kafOHK0akeXHo//xKN0E/+BGlax+RqXEE5zb5IXOTXb/9BLZJek5gTComMIIk8YOS2PADrYLiUfG6BtIf/KjD+QYgh8UbQP5PCSY/awpMRdVtt34FCoxl7vy07vsEkLv8CbDWCmR+Wpbvgoz1QpUfV+VHQdpqBiM/Lpq+AwVuQX6efB9oqhds/Ly2AlgBrAD+3XB+Ca4yiMSPS/hv/wEp/tUncVv5oQAAAABJRU5ErkJggg==
[id] => 25
)
)
***** update
Per Fred's error handling link and this 2007 patch I'm now able to update my clob. Updated function below:
// update row with new clob values
private function clobUpdate($clobArray){
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
foreach ($clobArray as $item) {
$query = "UPDATE ". static::$table ." SET ". $item["clobField"] ." = :CLOB WHERE ID = :ID";
$stmt = $this->db->prepare($query);
$stmt->bindParam(':ID', $item["id"]);
$stmt->bindParam(':CLOB', $item["clobValue"], PDO::PARAM_STR, strlen($item["clobValue"]));
$blob = NULL;
$this->db->beginTransaction();
$stmt->execute();
$this->db->commit();
print_r($blob);
die();
}
} catch(PDOException $e){
echo "Exception ". $e->getMessage();
throw new Exception($e);
}
}
NOTA: Posting as a community wiki to mark the question as solved.
You are using :ID and :id. Those are case-sensitive.
WHERE ID = :ID ... bindParam(':id', => bindParam(':ID',
Use PDO's error handling http://php.net/manual/en/pdo.error-handling.php
Yet, from the link you found about a patch, seems to also have contributed to successfully updating your database.
As per your comment:
"Per Fred's error handling link and this 2007 patch I'm now able to update my clob. Updated function below:"
// update row with new clob values
private function clobUpdate($clobArray){
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
foreach ($clobArray as $item) {
$query = "UPDATE ". static::$table ." SET ". $item["clobField"] ." = :CLOB WHERE ID = :ID";
$stmt = $this->db->prepare($query);
$stmt->bindParam(':ID', $item["id"]);
$stmt->bindParam(':CLOB', $item["clobValue"], PDO::PARAM_STR, strlen($item["clobValue"]));
$blob = NULL;
$this->db->beginTransaction();
$stmt->execute();
$this->db->commit();
print_r($blob);
die();
}
} catch(PDOException $e){
echo "Exception ". $e->getMessage();
throw new Exception($e);
}
}

More efficient way of inserting using PDO?

Hi I am inserting image data into a database each time an image is uploaded to my server. The code I am using looks a bit 'chunky' especially the binds. Can it be done differently to reduce the amount of text and execute more quickly or should I not worry about it?
Here is the code I am using:
function($file_name, $cat, $year, $desc, $title, $image_size, $image_width, $image_height){
//test the connection
try {
//connect to the database
$dbh = new PDO("mysql:host=localhost;dbname=mjbox","root", "usbw");
//if there is an error catch it here
} catch( PDOException $e ) {
//display the error
echo $e->getMessage();
}
$stmt = $dbh->prepare("INSERT INTO mjbox_images(img_file_name,img_cat,
img_year,img_desc,img_title,img_size,img_width,img_height)
VALUES(?,?,?,?,?,?,?,?)");
$stmt->bindParam(1,$file_name);
$stmt->bindParam(2,$cat);
$stmt->bindParam(3,$year);
$stmt->bindParam(4,$desc);
$stmt->bindParam(5,$title);
$stmt->bindParam(6,$image_size);
$stmt->bindParam(7,$image_width);
$stmt->bindParam(8,$image_height);
$stmt->execute();
}
Depending on how much code you want to rewrite, you could always swap from using pure PDO to something like RedBean (which is actually quite nice, being a zero-config ORM).
http://www.redbeanphp.com/
Worth a look, even if you won't use it now; it's definitely a great tool.
Inserts would then take just modifying bean properties, reducing the overall amount of code you'd use.
You could do it like this, passing an array of values and use the keys as place holders, that way you can use the same function to insert into different tables:
<?php
$insert = array('img_file_name'=>'',
'img_cat'=>'',
'img_year'=>'',
'img_desc'=>'',
'img_title'=>'',
'img_size'=>'',
'img_width'=>'',
'img_height'=>'');
insert('mjbox_images',$insert);
function insert($table,$values=array()){
//test the connection
try{
//connect to the database
$dbh = new PDO("mysql:host=localhost;dbname=mjbox","root", "usbw");
//if there is an error catch it here
} catch( PDOException $e ) {
//display the error
echo $e->getMessage();
}
$fieldnames = array_keys($values);
$sql = "INSERT INTO $table";
$fields = '( ' . implode(' ,', $fieldnames) . ' )';
$bound = '(:' . implode(', :', $fieldnames) . ' )';
$sql .= $fields.' VALUES '.$bound;
$stmt = $dbh->prepare($sql);
$stmt->execute($values);// whoops
}
//INSERT INTO mjbox_images( img_file_name ,img_cat ,img_year ,img_desc ,img_title ,img_size ,img_width ,img_height ) VALUES (:img_file_name, :img_cat, :img_year, :img_desc, :img_title, :img_size, :img_width, :img_height )
?>

Unable to retrieve data from SQLite using PHP

This is my first try to use SQLite, I am trying to retrieve data from SQLite but am not getting success neither its throwing any exceptions.
my respective code is as follows:
$sql_query = "SELECT * FROM `item` WHERE combo LIKE '" . $value . "' LIMIT 1;";
try {
/*** connect to SQLite database ***/
$dbh = new PDO("sqlite:src/mydb.s3db");
foreach ($dbh->query($sql_query) as $row) {
$name = $row['name'];
echo "name".$name;
$style = $row['style'];
echo $style;
$appr = $row['appr'];
echo $appr;
$style = $row['style'];
echo $style;
}
} catch(PDOException $e) {
//echo $e -> getMessage();
echo "problem with DB";
echo "<br>";
}
Kindly guide me through this.
Thank you.
//phpnifo();
PDO
PDO support enabled |
PDO drivers mysql, sqlite, sqlite2
pdo_sqlite
PDO Driver for SQLite 3.x enabled |
PECL Module version (bundled) 1.0.1 $Id: pdo_sqlite.c 293036 2010-01-03 09:23:27Z sebastian $
SQLite Library 3.3.7
a) Tell PDO that you want it to use exceptions for reporting errors
$dbh = new PDO("sqlite::memory:");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
b) instead of putting the payload paraemters into the sql statement use prepared parametrized statements
try {
$stmt = $dbh->prepare( 'SELECT * FROM `item` WHERE combo LIKE ? LIMIT 1' );
$stmt->execute( array($value) );
foreach( $stmt as $row ) { ...
c) If you still don't get any output try code that unconditionally prints something. E.g. a SELECT Count(*) will always return at least one record (if no error occurs).
$stmt = $dbh->prepare( 'SELECT Count(*) as cnt FROM `item` WHERE combo LIKE ?' );
$stmt->execute( array($value) );
foreach( $stmt as $row ) {
echo 'Count: ', $row['cnt'], "\n";
}
$stmt = null;
edit: self-contained example
<?php
ini_set('display_errors', true);
error_reporting(E_ALL);
echo "start\n";
try {
$dbh = new PDO("sqlite::memory:");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setup($dbh);
$stmt = $dbh->prepare('SELECT * FROM item WHERE combo LIKE ? LIMIT 1');
$stmt->execute( array('comboB') );
foreach( $stmt as $row ) {
echo
$row['name'], " ",
$row['style'], " ",
$row['appr'], "\n"
;
}
}
catch(Exception $ex) {
var_dump($ex);
}
echo "done.\n";
function setup($dbh) {
$dbh->exec('
CREATE TABLE item (
combo TEXT,
name TEXT,
style TEXT,
appr TEXT
)
');
$stmt = $dbh->prepare('INSERT INTO item (combo,name,style,appr) VALUES (?,?,?,?)');
$stmt->execute( array('comboA','nameA','styleA','apprA') );
$stmt->execute( array('comboB','nameB','styleB','apprB') );
$stmt->execute( array('comboC','nameC','styleC','apprC') );
}

Categories