i am new to PHP, and am testing a simple PHP to call a Stored Procedure. I can connect to the Oracle database, but when i try to call oci_execute($stmt),
it will always failed. There is no issue with the stored procedure as it is being used by my other java program. Please advise what is the problem.
Thank.
$db="(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=DEVORA)(PORT=1590)))(CONNECT_DATA=(SID=xxxORxxx)))";
$conn = oci_connect("xxxx","xxxx",$db);
if (!$conn) {
$m = oci_error();
echo $m['message'], "\n";
exit;
}
else {
print "Connected to Oracle!\n";
}
$sql = 'BEGIN tcwzusr.getuserapp(:output_cur, :userid, :effdate); END;';
$stmt = oci_parse($conn,$sql);
$userid='myid01';
$effdate='01-12-2017';
oci_bind_by_name($stmt,':userid' ,$userid);
oci_bind_by_name($stmt,':effdate' ,$effdate);
$output_cur = oci_new_cursor($conn);
oci_bind_by_name($stmt,':output_cur', $output_cur,-1, OCI_B_CURSOR);
oci_execute($stmt);
if ( !$status ) {
// Rollback the procedure
print "rollback\n";
oci_rollback($conn);
die ("$status_msg\n");
}
Related
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
I have pleasure to work with legacy PHP application using SQL Server via PDO.
How in PHP can I retrieve return value of stored procedure which is using RETURN statement as output channel?
Example procedure
CREATE PROCEDURE [dbo].[mleko_test]
#param INT
AS
BEGIN
RETURN #param * 3;
END
GO
If possible, I would prefer to not modify procedure.
I am aware that there are similar questions, but they don't cover this case
Get RETURN value from stored procedure in SQL
Get Return Value from SQL Stored Procedure using PHP
Execute stored procedure like this: "exec ?=mleko_test(?)".
Working example:
<?php
#------------------------------
# Connection info
#------------------------------
$server = 'server\instance,port';
$database = 'database';
$uid = 'user';
$pwd = 'password';
#------------------------------
# With PDO
#------------------------------
try {
$conn = new PDO("sqlsrv:server=$server;Database=$database", $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch ( PDOException $e ) {
die ( "Error connecting to SQL Server" );
}
try {
$sql = "exec ? = mleko_test (?)";
$param = 3;
$spresult = 0;
$stmt = $conn->prepare($sql);
$stmt->bindParam(1, $spresult, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->bindParam(2, $param);
$stmt->execute();
} catch ( PDOException $e ) {
die ( "Error connecting to SQL Server" );
}
$stmt = null;
$conn = null;
echo 'Stored procedure return value (with PDO): '.$spresult."</br>";
#------------------------------
# Without PDO
#------------------------------
$cinfo = array (
"Database" => $database,
"UID" => $uid,
"PWD" => $pwd
);
$conn = sqlsrv_connect($server, $cinfo);
if ( $conn === false )
{
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
$sql = "exec ? = mleko_test (?)";
$param = 3;
$spresult = 0;
$params = array(
array(&$spresult, SQLSRV_PARAM_OUT),
array($param, SQLSRV_PARAM_IN),
);
$stmt = sqlsrv_query($conn, $sql, $params);
if ( $stmt === false ) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
}
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
echo 'Stored procedure return value (without PDO): '.$spresult."</br>";
?>
Notes:
Tested with PHP 7.1.12 and PHP Driver for SQL Server (pdo_sqlsrv version 4.3.0+9904).
I came to a solution using multi-query but #Zhorov answer is cleaner
<?php
$connection = new PDO($connectionString, $DB_USERNAME, $DB_PASSWORD);
$stmt = $connection->prepare(<<<SQL
DECLARE #a INT;
EXEC #a = mleko_test :in
SELECT #a AS result;
SQL
);
$stmt->execute([":in" => 123]);
echo $stmt->fetch()["result"] . "\n";
I had to change
$sql = "exec ?=mleko_test(?)";
for
$sql = "{?=call mleko_test(?)}";
I have this script that deletes a certain picture from the website. It's written with mysql functions so i wanted to update it to mysqli but doing so makes the script stop working. No die message from the script are shown no php errors and adding error_reporting(E_ALL); doesn't show any errors either.
Original script:
if(isset($_POST['F3Verwijderen']))
try
{
//delete the file
$sql = "SELECT PandFoto3 FROM tblpand WHERE `PK_Pand` = '".$pandid."'";
$con = mysql_connect('WEBSITE.mysql', 'WEBSITE', 'PASS');
if (!$con) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("WEBSITE");
$result = mysql_query($sql, $con);
while ($row = mysql_fetch_array($result)) {
if(file_exists($_SERVER['DOCUMENT_ROOT'].'/'.$row['PandFoto3'])) {
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$row['PandFoto3']);
} else {
echo $row['PandFoto3'];
}
}
//delete the path url from the database field
mysql_query("UPDATE tblpand SET PandFoto3 = NULL WHERE `PK_Pand` = '".$pandid."'");
mysql_close($con);
header('Location: ../admin/pand-aanpassen.php?id='.$pandid);
}
Updated to mysqli:
try
{
//delete the file
$sql = "SELECT PandFoto3 FROM tblpand WHERE `PK_Pand` = '".$pandid."'";
$con = mysqli_connect('WEBSITE.mysql', 'WEBSITE', 'PASS');
if (!$con) {
die('Could not connect: ' . mysqli_error());
}
mysqli_select_db("WEBSITE");
$result = mysqli_query($sql, $con);
while ($row = mysqli_fetch_array($result)) {
if(file_exists($_SERVER['DOCUMENT_ROOT'].'/'.$row['PandFoto3'])) {
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$row['PandFoto3']);
} else {
echo $row['PandFoto3'];
}
}
//delete the path url from the database field
mysqli_query("UPDATE tblpand SET PandFoto3 = NULL WHERE `PK_Pand` = '".$pandid."'");
mysqli_close($con);
header('Location: ../admin/pand-aanpassen.php?id='.$pandid);
}
Edit:
"no php errors and adding error_reporting(E_ALL); doesn't show any errors either."
That's because it isn't a PHP issue, it's a MySQL issue.
Those are two different animals altogether.
As I said in commments, you need to switch these variables ($sql, $con) around ($con, $sql).
Then this:
$con = mysqli_connect('WEBSITE.mysql', 'WEBSITE', 'PASS');
Just use the 4th parameter instead of mysqli_select_db("WEBSITE"); where you didn't pass the connection variable to.
$con = mysqli_connect('WEBSITE.mysql', 'WEBSITE', 'PASS', 'WEBSITE');
The syntax is:
host
username
password (if any)
database
You also could have done mysqli_select_db($con, "WEBSITE");
Sidenote: In mysql_ (see footnotes), the connection comes last, unlike in mysqli_ which comes first.
Do the same for your UPDATE and pass the connection parameter first.
mysqli_query($con, "UPDATE...
Sidenote: To verify that the update truly was successful, use affected_rows()
http://php.net/manual/en/mysqli.affected-rows.php.
Another thing, mysqli_error() requires a connection to it mysqli_error($con) and check for errors for your queries.
I.e.:
$result = mysqli_query($con, $sql) or die(mysqli_error($con));
References:
http://php.net/manual/en/mysqli.query.php
http://php.net/manual/en/mysqli.error.php
http://php.net/manual/en/mysqli.select-db.php
Sidenote:
You're using try() but no catch(). Either remove it, or consult the manual:
http://php.net/manual/en/language.exceptions.php
Example #4 pulled from the manual:
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}
try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}
try {
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "Second finally.\n";
}
// Continue execution
echo "Hello World\n";
?>
Final notes:
Your present code is open to SQL injection. Use prepared statements, or PDO with prepared statements, they're much safer.
Footnotes: (MySQL and MySQLi comparison)
In regards to mysql_query():
mixed mysql_query ( string $query [, resource $link_identifier = NULL ]
http://php.net/manual/en/function.mysql-query.php
For mysqli_query():
mixed mysqli_query ( mysqli $link , string $query [, int $resultmode = MYSQLI_STORE_RESULT ] )
http://php.net/manual/en/mysqli.query.php
My server is nginx and I use adodb5 to manage the connexion to the Oracle DB.
This db query returns rows in a SQL software like SQLDevelopper but I don't know how to make it work in my case.
$sql = "SELECT geom_object FROM geom_table";
Whereas this other request works :
$sql = "SELECT id FROM geom_table";
My connecting code is correct because all my queries return some data, except those involving SDO_GEOMETRY.
include ("adodb5/adodb-exceptions.inc.php");
include ("adodb5/adodb-errorhandler.inc.php");
include ("adodb5/adodb.inc.php");
try {
$db = NewADOConnection("oci8");
$db->Connect($sid, $user, $password);
$db->SetFetchMode(ADODB_FETCH_ASSOC);
} catch (exception $e) {
var_dump($e);
adodb_backtrace($e->gettrace());
exit;
}
try
{
$ret = $db->GetArray($sql);
print count($ret);
}
catch (exception $e)
{
print $e->msg;
exit;
}
The MDSYS.SDO_GEOMTRY field can not be hanlded as it is in PHP.
First I needed to modify my SQL request to return a Well Known Text :
$sql = "SELECT sdo_util.to_wktgeometry(geom_object) FROM geom_table";
Reading the Oracle Documentation on SDO_UTIL we can see that the TO_WKTGEOMETRY return a CLOB.
PHP can still not read the value of the data. There's one more important step, reading the CLOB.
The Php documentation about OCI-Lob informs us that there are two functions able to read a CLOB and return a string : load and read.
$conn = oci_connect($user_prospect, $password_prospect, $sid_prospect);
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$stid = oci_parse($conn, $sql);
oci_execute($stid);
while (($row = oci_fetch_array($stid)) != false) {
echo $row[column_of_geometry_object]->load();
}
oci_free_statement($stid);
oci_close($conn);
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 )
?>