ADODB and SQL SERVER functions - php

I have a web service, that connects to my MSSQL data base using ADODB for PHP. Then, I created a simple function to return a string, just for tests, but, I'll implement with another logic.
Here is my SQL SERVER FUNCTION:
USE [myDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [myDB].[VerifyUser]
(
#user varchar(50),
#pass varchar(50)
)
RETURNS varchar(32)
AS
BEGIN
DECLARE #token varchar(32);
SET #token = 'Works!';
RETURN #token;
END
And, this is my web service method:
function wseAutenticacao($usuario, $senha) {
require_once('include/adodb5/adodb.inc.php');
$db = &ADONewConnection('mssqlnative');
$db->Connect(<host>, <user>, <pass>, <db_name>);
$stmt = $db->Prepare('VerifyUser');
$db->InParameter($stmt, $usuario, 'user');
$db->InParameter($stmt, $senha, 'pass');
$db->OutParameter($stmt, $token, 'token');
$result = $db->Execute($stmt);
return array('result' => $result);
}
I don't get the string "Works!" returned by my sql function. What is returned is a boolean with a false value, like I'm doing something wrong, but, I followed the ADODB Documentation example and now, I don't know what I have to do. I'm stuck!
If anyone would share your knowledge, I'll be greatful!
Thanks!

The #token local variable is only visible within the function itself. The result of the scalar function needs to be assigned to the output parameter in the executed script. One method you could try is a parameterized SELECT statement to assign the function return value to the output parameter:
$stmt = $db->Prepare('SELECT #token = VerifyUser(#user, #pass);');

I know the thread is old, but I'm looking for a solution for something similar. It seems that the current implementation of 'mssqlnative' does not support parameters at all. That is, the base class ADOConnection implements a mock metod Parameter which should be overridden in subclasses. ADODB_mssqlnative does not have an override of this method, hence, your parameters disappear into the void. Next thing, the current implementaton of _query() expects input parameters as array.
So, you could change your code to this to make it work
$db = &ADONewConnection('mssqlnative');
$db->Connect(<host>, <user>, <pass>, <db_name>);
$stmt = 'VerifyUser';
$params = array($usuario, $senha, $token);
$result = $db->Execute($stmt, $params);
return array('result' => $result);
Also, note that the params array is not associative. The current implementation of sqlsrv_query does not allow named parameters.

Related

PHP PDO Wrapper class implementation

I have been developing a wrapper class inside a small PHP framework and I am experiencing something weird with one of the method in my class.
First here is the class code :
<?php
namespace Framework;
header('Content-Type: text/html; charset=UTF-8');
class cConnexion
{
public $m_log;//This will be instantiate as a cLog object (another class in the namespace)
private $m_DB;//PDO instance
private $m_Host;//Host of the conneciton string
private $m_DBName;//Name of the DB to connecte to
private $m_Driver;//Driver name, mysql for MySQL, sqlsrv for MSSQL
private $m_Login;//Username for authentification
private $m_Password;//Password for authentification
public function __construct($p_Driver = "mysql", $p_host, $p_DBName, $p_login, $p_password)
{
$this->m_Host= $p_host;
$this->m_Driver = $p_Driver;
$this->m_DBName = $p_DBName;
$this->m_Login = $p_login;
$this->m_Password = $p_password;
$this->m_log = new cLog('', '', true, false, false);
}
public function SecureExecute($p_query, $p_param)
{
try
{
$stmt = $this->m_DB->prepare($p_query);
$status = $stmt->execute($p_param);
$this->m_log->setMessageFR("Aucune exception ne s'est levé. ");
$this->m_log->setMessageEN("No exceptions were raised. ");
$this->m_log->setSuccess($status);
return $status;
}
catch(\PDOException $e)
{
$this->m_log->setMessageFR("Une exception de type PDO est levé. ".$e->getMessage());
$this->m_log->setMessageEN("A PDO exception was raised. ".$e->getMessage());
$this->m_log->setSuccess(false);
return false;
}
}
}
?>
Note that I have remove every other method that are not relevant to the question but kept the constructor and all the properties. Also note that there is a method to connect the $m_DB property to the DB, you might want to assume it has already been called.
Here is the problem I need help solving:
Step by Step description of what is going on:
I create an instance of cConnexion and use the connecteToDB method that isn't described in here but it is working properly because I can use another method to do MySQL 'SELECT' statement.
I tried to UPDATE a row which doesn't exist in a MySQL table but the object still tell me that the UPDATE was successful.
Is that normal? I read the PDO::PDOStatement::execute Doc and is says that the return value of PDO::PDOStatement::execute is either true (on success) or false(if fails).
Here is an exemple of code using the method:
$sql = "UPDATE Employes SET CieNo = 3, Nom = :Name, Dept = :Department WHERE EmplCode = :Code";
$params = array
(
'Code'=>$EmplCode,// = 123
'Name'=>($lname." ".$fname),// = Lalonde Sebastien
'Department'=>$dep,// = INFO
);
$cn = new cConnexion(/*Connection string and params here*/);
$cn->connectToDB();
if($cn->SecureExecute($sql, $params))
{
echo "SQL1: true";
}
The following code always output "SQL1: true" even when the UPDATE shouldn't had work...(because the Employes table doesn't contains an EmplCode = 123).
Can someone suggest a way to change my class so that the method SecureExecute() return false when this happen?
The execute method returns true on success, which in your case is true: The mysql query was executed successfully, however no rows were effected.
If you need to check whether the update actually altered anything, you need to use "rowCount":
$stmt = $this->m_DB->prepare('Update ...');
$stmt->execute();
$effected = $stmt->rowCount();
You can then decide if you want to return a true/false value from your method.
http://www.php.net/manual/en/pdostatement.rowcount.php
You'll only receive an error if the SQL command itself is in error. So if Employes is a valid table, and CieNo, Nom, Dept, and EmplCode are all valid columns, then your SQL statement is valid, even though it doesn't always find a row to UPDATE. Technically, it was "successful", just not in the way you're wanting.
Take a look at rowCount()
for info on how to determine whether 0 or more rows were affected by your query.
In fact, this whole class appears to be utterly useless. Exactly the same outcome can be achieved with raw PDO, with very small addition.
$cn = new PDO(/*Connection string and params here*/);
$cn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $cn->prepare($sql);
$stmt->execute($params);

Creating a container function for a PDO query in PHP

Because I find PDO executions extremely hard to remember and find myself looking back at previous projects or other websites just to remember how to select rows from a database, I decided that I would try and create my own functions that contain the PDO executions and just plug in the data I need. It seemed a lot simpler than it actually is though...
So far I have already created a connect function successfully, but now when it comes to create a select function I'm stumped for multiple reasons.
For starters there could be a variating amount of args that can be passed into the function and secondly I can't figure out what I should pass to the function and in which order.
So far the function looks like this. To keep me sane, I've added the "id" part to it so I can see what exactly I need to accomplish in the final outcome, and will be replaced by variables accordingly when I work out how to do it.
function sql_select($conn, **what to put here**) {
try {
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
$result = $stmt->fetchAll();
if ( count($result) ) {
foreach($result as $row) {
print_r($row);
}
} else {
return "No rows returned.";
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
}
So far what I've established that the function will need to do is
Connect to the database (using another function to generate the $conn variable, already done)
Select the table
Specify the column
Supply the input to match
Allow for possible args such as ORDER by 'id' DESC
Lastly from this I would need to create a function to insert, update and delete rows from the database.
Or, is there a better way to do this rather than functions?
If anyone could help me accomplish my ambitions to simply simplify PDO executions it would be greatly appreciated. Thanks in advance!
First of all, I have no idea where did you get 10 lines
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = ?');
$stmt->execute(array($id));
$result = $stmt->fetchAll();
is ALL the code you need, and it's actually three lines, which results with a regular PHP array that you can use wherever you wish. Without the need of any PDO code. Without the need of old mysql code.
Lastly from this I would need to create a function to insert, update and delete rows from the database.
DON'T ever do it.
Please read my explanations here and here based on perfect examples of what you'll end up if continue this way.
accomplish my ambitions to simply simplify PDO executions
That's indeed a great ambition. However, only few succeeded in a real real simplification, but most resulted with actually more complex code. For starter you can try code from the first linked answer. Having a class consists of several such functions will indeed improve your experience with PDO.
. . . and find myself looking back at previous projects or other
websites just to remember how to select rows from a database . . .
FYI, we all do that.
You had a problem with the PDO API and now you have two problems. My best and strongest suggestion is this: If you want a simpler/different database API, do not roll your own. Search http://packagist.org for an ORM or a DBAL that looks good and use it instead of PDO.
Other people have already done this work for you. Use their work and focus instead on whatever awesome thing is unique to your app. Work smart, not hard and all that.
Writting a wrapper, should start form connecting the DB, and all the possible method could be wrapped. Passing connection to the query method, doesn't look good.
A very rough example would be the code bellow, I strongly do not suggest this mixture, but it will give you the direction.
You connection should be made either from the constructor, or from another method called in the constructor, You can use something like this:
public function __construct($driver = NULL, $dbname = NULL, $host = NULL, $user = NULL, $pass = NULL, $port = NULL) {
$driver = $driver ?: $this->_driver;
$dbname = $dbname ?: $this->_dbname;
$host = $host ?: $this->_host;
$user = $user ?: $this->_user;
$pass = $pass ?: $this->_password;
$port = $port ?: $this->_port;
try {
$this->_dbh = new PDO("$driver:host=$host;port=$port;dbname=$dbname", $user, $pass);
$this->_dbh->exec("set names utf8");
} catch(PDOException $e) {
echo $e->getMessage();
}
}
So you can either pass connection credentials when you instantiate your wrapper or use default ones.
Now, you can make a method that just recieves the query. It's more OK to write the whole query, than just pass tables and columns. It will not make a whole ORM, but will just make the code harder to read.
In my first times dealing with PDO, I wanted everything to be dynamically, so what I achieved, later I realized is immature style of coding, but let's show it
public function query($sql, $unset = null) {
$sth = $this->_dbh->prepare($sql);
if($unset != null) {
if(is_array($unset)) {
foreach ($unset as $val) {
unset($_REQUEST[$val]);
}
}
unset($_REQUEST[$unset]);
}
foreach ($_REQUEST as $key => $value) {
if(is_int($value)) {
$param = PDO::PARAM_INT;
} elseif(is_bool($value)) {
$param = PDO::PARAM_BOOL;
} elseif(is_null($value)) {
$param = PDO::PARAM_NULL;
} elseif(is_string($value)) {
$param = PDO::PARAM_STR;
} else {
$param = FALSE;
}
$sth->bindValue(":$key", $value, $param);
}
$sth->execute();
$result = $sth->fetchAll();
return $result;
}
So what all of these spaghetti does?
First I though I would want all of my post values to be send as params, so if I have
input name='user'
input name='password'
I can do $res = $db->query("SELECT id FROM users WHERE username = :user AND password = :password");
And tada! I have fetched result of this query, $res is now an array containing the result.
Later I found, that if I have
input name='user'
input name='password'
input name='age'
In the same form, but the query remains with :user and :password and I submit the form, the called query will give mismatch in bound params, because the foreach against the $_REQUEST array will bind 3 params, but in the query I use 2.
So, I set the code in the beginning of the method, where I can provide what to exclude. Calling the method like $res = $db->query("SELECT id FROM users WHERE username = :user AND password = :password", 'age'); gave me the possibility to do it.
It works, but still is no good.
Better have a query() method that recieves 2 things:
The SQL string with the param names
The params as array.
So you can use the foreach() logic with bindValue, but not on the superglobal array, but on the passed on.
Then, you can wrap the fetch methods
public function fetch($res, $mode = null)
You should not directly return the fetch from the query, as it might be UPDATE, INSERT or DELETE.
Just pass the $res variable to the fetch() method, and a mode like PDO::FETCH_ASSOC. You can use default value where it would be fetch assoc, and if you pass something else, to use it.
Don't try to be so abstract, as I started to be. It will make you fill cracks lately.
Hum... IMHO I don't think you should try to wrap PDO in functions, because they're already "wrapped" in methods. In fact, going from OOP to procedural seems a step back (or at least a step in the wrong direction). PDO is a good library and has a lot of methods and features that you will surely lose if you wrap them in simple reusable functions.
One of those features is the BeginTransaction/Rollback (see more here)
Regardless, In a OOP point of view you can decorate the PDO object itself, adding some simple methods.
Here's an example based on your function
Note: THIS CODE IS UNTESTED!!!!
class MyPdo
{
public function __construct($conn)
{
$this->conn = $conn;
}
public function pdo()
{
return $this->conn;
}
public function selectAllById($table, $id = null)
{
$query = 'SELECT * FROM :table';
$params = array('table'=>$table);
if (!is_null($id)) {
$query .= ' WHERE id = :id';
$params['id'] = $id;
}
$r = $this->conn->prepare($query)
->execute($params)
->fetchAll();
//More stuff here to manipulate $r (results)
return $r;
}
public function __call($name, $params)
{
call_user_func_array(array($this->conn, $name), $params);
}
}
Note: THIS CODE IS UNTESTED!!!!
ORM
Another option is using an ORM, which would let you interact with your models/entities directly without bothering with creating/destroying connections, inserting/deleting, etc... Doctrine2 or Propel are good bets for PHP.
Howeveran ORM is a lot more complex than using PDO directly.

PHP, PDO & MYSQL : lastInsertId() returns NULL

I am rather new at PDO-based MySQL and I'm running into a problem.
This is the method I'm executing :
public function insert( $table, $data )
{
// utility functions to auto-format the statements
$keys = $this->getKeys($data);
$placeholders = $this->getPlaceholders($data);
$q = "INSERT INTO $table ($keys) VALUES ($placeholders)";
// this simply returns a new PDO object
$dbh = $this->createSession();
$stmt = $dbh->prepare($q);
$stmt->execute( array_values($data) );
return $dbh->lastInsertId();
}
After that, I run my method and store the returned value in a variable :
$new_user_id = $U->insert( $data );
var_dump($new_user_id);
And I get
NULL
Note the query is actually executed, and my data is correctly inserted into my table; no problem on that side. It seems it just can't grab the last insert ID as I ask for it.
Thanks for your time.
Not sure about any PDO-specific issues, but by default MySQL only returns an insert id if there's an auto_increment integer field in the database (generally but not necessarily the primary key). If your table doesn't include this nothing is returned by $dbh->lastInsertId()
I've reviewed the code again and I found that my value wasn't returned because of an intermediate method that wasn't passing the value correctly to the top-layer method.
Checking the value at the source shows no problem.
Thanks for the replies anyway.

Accessing MySQL stored procedure output in Zend Framework 2

I have a simple MySQL stored procedure that takes two parameters and inserts a row into a table. I can execute it just fine from Zend Framework 2 like this:
$result = $this->dbAdapter->query('CALL sp_register_user(?, ?)', array('username', 'password'));
I can also access any result sets returned from my stored procedure.
What I want now is to have an output value from my stored procedure as a third parameter, so something like this:
DELIMITER //
CREATE PROCEDURE sp_register_user(IN username VARCHAR(50), IN password VARCHAR(128), OUT code INTEGER)
NOT DETERMINISTIC
COMMENT 'Registers a user'
BEGIN
INSERT INTO user VALUES (username, password);
SET code = 123;
END //
The question is how I can access this output variable from PHP (ZF2). I have only been able to find examples of how to do it directly through PDO, which I am using. Example 4 on this page shows how to do it through PDO directly. My concern is that if I use the PDO object directly, I am losing some abstractions and I am thereby assuming that I will always be using PDO.
Still, I tried to make it work with PDO directly, like this:
$username = 'my_username';
$password = 'my_password';
$code = 0;
$stmt = $this->dbAdapter->createStatement();
$stmt->prepare('CALL sp_register_user(?, ?, ?)');
$stmt->getResource()->bindParam(1, $username);
$stmt->getResource()->bindParam(2, $password);
$stmt->getResource()->bindParam(3, $code, \PDO::PARAM_INT, 3);
$stmt->execute();
However, I get an error saying that the statement could not be executed.
The ideal solution would be one where I could make use of ZF2's abstraction layer, but any ideas on how to access the output parameter are welcome and appreciated.
this must work, because i m using it :
$str = "DECLARE #Msgvar varchar(100);DECLARE #last_id int;
exec CallEntry_Ins $CallLoginId,".$this->usrId .",#Msg = #Msgvar OUTPUT,#LAST_ID = #last_id OUTPUT;
SELECT #Msgvar AS N'#Msg',#last_id AS '#LAST_ID'; ";
$stmt = $db->prepare($str);
$stmt->execute();
$rtStatus = $stmt->fetchAll();
$rtStatus[0]["#LAST_ID"] //accessing Op para

PDO: can I avoid bindParam?

I modified this code from somewhere but I am not sure if I am doing it correctly,
I use method to insert data into database,
# insert or update data
public function query($query, $params=array())
{
try
{
$stmt = $this->connection->prepare($query);
$params = is_array($params) ? $params : array($params);
$stmt->execute($params);
return true;
}
catch (PDOException $e)
{
# call the get_error function
$this->get_error($e);
}
}
Then I just need to call it like this,
$sql = "
INSERT root_countries_cities_towns (
tcc_names,
cny_numberic,
tcc_created
)VALUES(
?,
?,
NOW()
)";
$pdo->query($sql,array('UK','000'));
It works fine perfectly! but I don't understand what this line does - can someone explain please?
$params = is_array($params) ? $params : array($params);
I thought I have to use bindParam to bind the parameters first, but it seems that I don;t have to anymore with is method - is it safe and secure then??
Does it meant that I don't have to prepare the query in this way anymore?
$sql = "
INSERT root_countries_cities_towns (
tcc_names,
cny_numberic,
tcc_created
)VALUES(
:name,
:numberic,
NOW()
)";
and forget about this binding?
$stmt = bindParam(':name','UK', PDO::PARAM_STR);
$stmt = bindParam(':numberic','000', PDO::PARAM_STR);
Thanks.
I guess that's pretty much PHP syntax question rather than PDO one.
$params = is_array($params) ? $params : array($params);
is a shortland (called ternary operator)) for
if (is_array($params)) {
$params = $params;
} else {
$params = array($params);
}
which I'd rather wrote as
if (!is_array($params)) $params = array($params);
which is pretty self-explanatory and can be read almost in plain English:
if $params is not an array, let's make it array with one value of former $params
That's why I hate ternary operator (and lambdas) and always avoid it's use. It makes pretty readable code into a mess. Just out of programmer's laziness.
To answer your other questions,
Does it meant that I don't have to prepare the query in this way anymore?
Who said that? You're preparing it all right in your code, check it again.
and forget about this binding?
that's true. execute($params) is just another way to bind variables.
the line
$params = is_array($params) ? $params : array($params);
is simply checking if the $params variable is an array, and if so, it creates an array with the original $params value as its only element, and assigns the array to $params.
This would allow you to provide a single variable to the query method, or an array of variables if the query has multiple placeholders.
The reason it doesn't use bindParam is because the values are being passed to the execute() method. With PDO you have multiple methods available for binding data to placeholders:
bindParam
bindValue
execute($values)
The big advantage for the bindParam method is if you are looping over an array of data, you can call bindParam once, to bind the placeholder to a specific variable name (even if that variable isn't defined yet) and it will get the current value of the specified variable each time the statement is executed.
The first example transforms the contents of your $params into an array, if it wasn't already an array (for example if only one parameter was passed and it was passed as an individual item instead of as an array of length 1).
The two examples work just as well, except that for the first one, parameters introduced with the array $params are injected where ? are found in the SQL query, whereas in the second one, the formatting of the parameters is actually done by name (you bind a parameter name as found in the sql to an actual parameter).
You should use the first one, it's easier to write.
Passing an array to PDOStatement::execute() passes each entry in the array through PDOStatement::bindParam() (or maybe bindValues()) using defaults (bind type, etc).
Basically, it's as safe as pre-binding.
The advantage to using bindParam is that it binds to the variable reference. This means you can change the value of the variable without re-binding and execute the statement with new values. This is especially useful in a loop, eg
$vals = array('foo', 'bar', 'baz');
$stmt->bindParam(1, $val);
foreach ($vals as $val) {
$stmt->execute(); // Executes once for each value in $vals
}
I don't understand what this line does - can someone explain please?
That line converts a non-array into an array.
For example
$params = 'foo';
$params = is_array($params) ? $params : array($params);
$params == array('foo');
I imagine it's to facilitate situations where you have only one placeholder and one value to bind as PDOStatement::execute() can only be passed an array.
Try this class. I use PDO a lot and this is what I use all the time for my projects.PHP PDO Class on GitHub

Categories