I am new in PDO. I heard that it is more friendly to the programmer to use multiple databases in a project and it is much more secure, so I want to learn PDO. I want to insert data into MySQL using PDO but I can't, and no error message comes. I used the following code:
<?php
class ManageUsers02 {
private $db_con;
public $db_host = "localhost"; // I run this code on my localhost
public $db_name = "todo"; // database name
public $db_user = "root"; // username
public $db_pass = ""; // password
function __construct() {
try {
// connect to database using PDO
$this->db_con = new PDO("mysql:host=$this->db_host;db_name=$this->db_name", $this->db_user, $this->db_pass);
} catch (PDOException $exc) { // PDO exception handling
echo $exc->getMessage();
}
}
public function reg_user($username, $password, $ip_address, $reg_date, $reg_time ) {
try {
// preparing sql query
$query = $this->db_con->prepare("INSERT INTO user_reg (username, password, ip_address, reg_date, reg_time) VALUES ( ?, ?, ?, ?, ? )");
}
catch( PDOException $exc ) { // PDO exception handling
echo $exc->getMessage();
}
try {
// execute sql query
$query->execute(array($username, $password, $ip_address, $reg_date, $reg_time));
}
catch( PDOException $exc ) {
echo $exc->getMessage();
}
$counts = $query->rowCount(); // return value of affected row
// here it should be return 1
echo "<br /> count :: <b> " . $counts . "</b> <br />"; // shows result 0
// no value inserted
}
}
$user_reg = new ManageUsers02();
$user_reg->reg_user('pdo_name', 'pdo_password', '127.0.0.1', '2013-2-6', '4:20 am');
?>
This fails because of insert a string to a mysql Time field.
$sql = "INSERT INTO user_reg ( ... , reg_time) VALUES (..., '4:20 am');
If you want to use '4:20 am' you should use.
TIME( STR_TO_DATE( ? , '%h:%i %p' ))
like
$sql = "INSERT INTO user_reg ( ... , reg_time) VALUES
( ?, ?, ?, ?, TIME( STR_TO_DATE( ? , '%h:%i %p' )))";
and give the class a ok and a counts .
<?php
class ManageUsers02 {
...
public $counts = 0;
public $ok = false;
function __construct() {
try {
$this->db_con = new PDO("mysql:dbname=$this->db_name;host=$this->db_host", $this->db_user, $this->db_pass);
} catch (PDOException $exc) { // PDO exception handling
echo $exc->getMessage();
return;
}
if (!$this->db_con) {
return;
}
$this->ok = true;
}
public function reg_user($username, $password, $ip_address, $reg_date, $reg_time ) {
$this->counts = 0;
$this->ok = false;
$sql = "INSERT INTO user_reg (username, password, ip_address,
reg_date, reg_time) VALUES
( ?, ?, ?, ?, TIME( STR_TO_DATE( ? , '%h:%i %p' )))";
try {
$query = $this->db_con->prepare($sql);
}
catch( PDOException $exc ) { // PDO exception handling
echo $exc->getMessage();
return;
}
if (!$query) {
return;
}
try {
$this->ok = $query->execute(array($username, $password, $ip_address, $reg_date, $reg_time));
}
catch( PDOException $exc ) {
echo $exc->getMessage();
$this->ok = false;
return;
}
if ($this->ok) {
$this->counts = $query->rowCount(); // return value of affected row
}
}
}
$user_reg = new ManageUsers02();
if ($user_reg->ok) {
$user_reg->reg_user('pdo_name4', 'pdo_password4',
'127.0.0.1', '2013-2-6', '04:20 am' );
if ($user_reg->ok) {
echo "<br /> count :: <b> " . $user_reg->counts . "</b> <br />";
} else { echo "Error : Insert failed";}
} else { echo "Error : Connection failed: ";}
?>
+1 to the answer from #moskito-x for spotting the incorrect time format. But there are a couple of other functional problems with your code.
$this->db_con = new PDO("mysql:host=$this->db_host;db_name=$this->db_name", ...
You need to use dbname in the DSN, not db_name. See http://www.php.net/manual/en/ref.pdo-mysql.connection.php
$this->db_con = new PDO("mysql:host=$this->db_host;dbname=$this->db_name", ...
Also you need to enable the error mode like this:
$this->db_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
If you don't, PDO doesn't throw exceptions on prepare() or execute(), but those functions just return false if there's an error.
I don't know what's particular problem with your insert, but your implementation is just terrible. By design.
First of all you have to get rid of PDO connection code in the class. You have to create a PDO instance separately, and then only pass it in constructor.
Secondly, you have to get rid of all these try..catch which makes your code bloated with not a slightest benefit.
Also, No class method should ever output a single byte, but return only.
So, it have to be something like
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$pdo = new PDO($dsn, $user, $pass, $opt);
class ManageUsers02
{
private $db_con;
function __construct($db_con)
{
$this->db_con = $db_con;
}
public function reg_user($username, $password, $ip_address, $reg_date, $reg_time )
{
$sql "INSERT INTO user_reg (username, password, ip_address, reg_date, reg_time)
VALUES ( ?, ?, ?, ?, ? )";
$query = $this->db_con->prepare($sql);
$query->execute(array($username, $password, $ip_address, $reg_date, $reg_time));
return $counts = $query->rowCount(); // return value of affected ro
}
}
$user_reg = new ManageUsers02($pdo);
$count = $user_reg->reg_user('pdo_name', 'pdo_password', '127.0.0.1', '2013-2-6', '4:20 am');
var_dump($count);
This setup at least will tell you if something goes wrong.
Related
I need to know how to get the result of a select statement that is executed after an insert statement as one execute in PDO.
My PDO connection parameters are as follows:
$opt = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => true];
$conn = new PDO($dsn, $user, $pass, $opt);
I have the following helper function that i use for my PDO statement Execution:
function databaseExecute($SQL, $BIND_P, &$BIND_R) {
global $conn;
$stmt = $conn->prepare($SQL);
if ($stmt->execute($BIND_P)) {
if ($BIND_R !== false) {
//Type testing is important here
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
if (!$tmp || count($tmp) == 0) {
return false;
}
$BIND_R = $tmp;
} else {
$stmt->closeCursor();
}
return true;
}
$stmt->closeCursor();
return false;
}
My function itself is:
/**
* Adds the current purchase object to the database table
* #return true if success
*/
public function pushToDB() {
global $tbl_purchases;
//We don't push purchaseID since that field is auto handled by the database
$sql = "INSERT INTO " . $tbl_purchases . " (ProductID, UID, TID, GenDate, KeyIDs, Total, Assigned) VALUES (?, ?, ?, ?, ?, ?, ?); SELECT LAST_INSERT_ID();";
$result = array();
if (databaseExecute($sql, array(
$this->getProductID(),
$this->getUID(),
$this->getTID(),
$this->getGenDate(),
$this->getKeyIDsJSON(),
$this->getTotal(),
$this->getAssigned(),
), $r)) {
var_dump($result);
$this->_setPurchaseID($result[0]);
return true;
}
trigger_error("Purchase::pushToDB - Could not push purchase to database", E_USER_ERROR);
return false;
}
But this throws a general error
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error when i attempt to fetchAll
In this situation, how do i get the result of the SQL execution?
PS: Using Two executes is not acceptable here.
Using Two executes is not acceptable here.
This is but a delusion.
Use either second query or - better - a dedicated function PDO::LastInsertId(). But with your rather poorly designed function it could be a problem. So be it 2 queries.
So change your functions to
function databaseExecute($SQL, $BIND_P = array();) {
global $conn;
if (!$BIND_P)
{
return $conn->query($SQL);
}
$stmt = $conn->prepare($SQL);
$stmt->execute($BIND_P);
return $stmt;
}
and
public function pushToDB() {
global $tbl_purchases;
//We don't push purchaseID since that field is auto handled by the database
$sql = "INSERT INTO $tbl_purchases
(ProductID, UID, TID, GenDate, KeyIDs, Total, Assigned)
VALUES (?, ?, ?, ?, ?, ?, ?)";
databaseExecute($sql, array(
$this->getProductID(),
$this->getUID(),
$this->getTID(),
$this->getGenDate(),
$this->getKeyIDsJSON(),
$this->getTotal(),
$this->getAssigned(),
));
$id = databaseExecute("SELECT LAST_INSERT_ID()")->fetchColumn();
$this->_setPurchaseID($db);
return true;
}
}
You can alter your databaseExectute function to take an extra parameter of 'SecondResult' (for example), then change it to something like...
function databaseExecute($SQL, $BIND_P, &$BIND_R,$SecondResult) {
global $conn;
$stmt = $conn->prepare($SQL);
if ($stmt->execute($BIND_P)) {
if ($BIND_R !== false) {
//Type testing is important here
if ($SecondResult) $stmt->nextRowSet(); // this will ensure that the fetchAll will return the data from the 2nd query
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
if (!$tmp || count($tmp) == 0) {
return false;
}
$BIND_R = $tmp;
} else {
$stmt->closeCursor();
}
return true;
}
$stmt->closeCursor();
return false;
}
I just typed this in to here directly, I haven't tested it, but it should work.
Also, I'm not saying that the other comments are wrong, and there might be a better way of doing this, but you CAN run two queries within the same 'statement'.
I am new to PDO and I am having a problem with the following insert operation. It ends up always in the else case (returning 0).
function insertInclusao($usuarioId, $tipoFaturaId, $parametrosValidadores, $identificadorExtra, $optin) {
$pdoConnection = new PDO("mysql:host=host;dbname=dbname", "user", "pass");
try {
$stmte = $pdoConnection->prepare("INSERT INTO SF_INCLUSAO (UsuarioId, TipoFaturaId, ParametrosValidadores, DataInclusao, IdentificadorExtra, Optin) VALUES (?, ?, ?, NOW(), ?, ?)");
$stmte->bindParam(1, $usuarioId , PDO::PARAM_INT);
$stmte->bindParam(2, $tipoFaturaId , PDO::PARAM_INT);
$stmte->bindParam(3, $parametrosValidadores , PDO::PARAM_STR);
$stmte->bindParam(4, $identificadorExtra , PDO::PARAM_STR);
$stmte->bindParam(5, $optin , PDO::PARAM_INT);
$executarInclusao = $stmte->execute();
if($executarInclusao) {
return $pdoConnection->lastInsertId();
} else {
return 0;
}
} catch (PDOException $e) {
return -1;
}
}
It used to work when I was using mysql_query like this:
function insertInclusao($usuarioId, $tipoFaturaId, $parametrosValidadores, $identificadorExtra, $optin) {
$db_connection = mysql_connect( "host", "user", "pass" ) or die( mysql_error() );
mysql_select_db( "database" ) or die( mysql_error() );
$insert_query = "INSERT INTO SF_INCLUSAO (UsuarioId, TipoFaturaId, ParametrosValidadores, DataInclusao, IdentificadorExtra, Optin) VALUES ('".$usuarioId."', '".$tipoFaturaId."', '".$parametrosValidadores."', NOW(), '".$identificadorExtra."', '".$optin."');";
$query_return = mysql_query($insert_query);
$new_id = mysql_insert_id();
if($query_return) {
return $new_id; // OK
}
else {
return 0;
}
}
Right now I am failing to see what could be wrong. Any suggestions?
You need to set this
$pdoConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdoConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
You will now get the error because you have set the PDO error mode to exception.
function insertInclusao($usuarioId, $tipoFaturaId, $parametrosValidadores, $identificadorExtra, $optin) {
$pdoConnection = new PDO("mysql:host=host;dbname=dbname", "user", "pass");
$pdoConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdoConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
try {
$stmte = $pdoConnection->prepare("INSERT INTO SF_INCLUSAO (UsuarioId, TipoFaturaId, ParametrosValidadores, DataInclusao, IdentificadorExtra, Optin) VALUES (?, ?, ?, NOW(), ?, ?)");
$stmte->bindParam(1, $usuarioId , PDO::PARAM_INT);
$stmte->bindParam(2, $tipoFaturaId , PDO::PARAM_INT);
$stmte->bindParam(3, $parametrosValidadores , PDO::PARAM_STR);
$stmte->bindParam(4, $identificadorExtra , PDO::PARAM_STR);
$stmte->bindParam(5, $optin , PDO::PARAM_INT);
$executarInclusao = $stmte->execute();
if($executarInclusao) {
return $pdoConnection->lastInsertId();
} else {
return 0;
}
} catch (PDOException $e) {
return $e->getMessage();
}
}
Use this
$pdoConnection = new PDO("mysql:host=host;dbname=dbname", "user", "pass",array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
and then you can change this:
if($executarInclusao) {
return $pdoConnection->lastInsertId();
} else {
return 0;
}
for this:
return $pdoConnection->lastInsertId();
Because if something go wrong with query, $stmte->execute() throw PDOException
Scenario:
I have a SQL Query INSERT INTO dbo.Grades (Name, Capacity, SpringPressure) VALUES ('{PHP}',{PHP}, {PHP})
The data types are correct.
I need to now get the latest IDENTIY which is GradeID.
I have tried the following after consulting MSDN and StackOverflow:
SELECT SCOPE_IDENTITY() which works in SQL Management Studio but does not in my php code. (Which is at the bottom), I have also tried to add GO in between the two 'parts' - if I can call them that - but still to no avail.
The next thing I tried, SELECT ##IDENTITY Still to no avail.
Lastly, I tried PDO::lastInsertId() which did not seem to work.
What I need it for is mapping a temporary ID I assign to the object to a new permanent ID I get back from the database to refer to when I insert an object that is depended on that newly inserted object.
Expected Results:
Just to return the newly inserted row's IDENTITY.
Current Results:
It returns it but is NULL.
[Object]
0: Object
ID: null
This piece pasted above is the result from print json_encode($newID); as shown below.
Notes,
This piece of code is running in a file called save_grades.php which is called from a ajax call. The call is working, it is just not working as expected.
As always, I am always willing to learn, please feel free to give advice and or criticize my thinking. Thanks
Code:
for ($i=0; $i < sizeof($grades); $i++) {
$grade = $grades[$i];
$oldID = $grade->GradeID;
$query = "INSERT INTO dbo.Grades (Name, Capacity, SpringPressure) VALUES ('" . $grade->Name . "',". $grade->Capacity .", ".$grade->SpringPressure .")";
try {
$sqlObject->executeNonQuery($query);
$query = "SELECT SCOPE_IDENTITY() AS ID";
$newID = $sqlObject->executeQuery($query);
print json_encode($newID);
} catch(Exception $e) {
print json_encode($e);
}
$gradesDictionary[] = $oldID => $newID;
}
EDIT #1
Here is the code for my custom wrapper. (Working with getting the lastInsertId())
class MSSQLConnection
{
private $connection;
private $statement;
public function __construct(){
$connection = null;
$statement =null;
}
public function createConnection() {
$serverName = "localhost\MSSQL2014";
$database = "{Fill In}";
$userName = "{Fill In}";
$passWord = "{Fill In}";
try {
$this->connection = new PDO( "sqlsrv:server=$serverName;Database=$database", $userName, $passWord);
$this->connection->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch( PDOException $e ) {
die("Connection Failed, please contact system administrator.");
}
if ($this->connection == null) {
die("Connection Failed, please contact system administrator.");
}
}
public function executeQuery($queryString) {
$results = array();
$this->statement = $this->connection->query( $queryString );
while ( $row = $this->statement->fetch( PDO::FETCH_ASSOC ) ){
array_push($results, $row);
}
return $results;
}
public function executeNonQuery($queryString) {
$numRows = $this->connection->exec($queryString);
}
public function getLastInsertedID() {
return $this->connection->lastInsertId();
}
public function closeConnection() {
$this->connection = null;
$this->statement = null;
}
}
This is PDO right ? better drop these custom function wrapper...
$json = array();
for ($i=0; $i < sizeof($grades); $i++) {
//Query DB
$grade = $grades[$i];
$query = "INSERT INTO dbo.Grades (Name, Capacity, SpringPressure)
VALUES (?, ?, ?)";
$stmt = $conn->prepare($query);
$success = $stmt->execute(array($grade->Name,
$grade->Capacity,
$grade->SpringPressure));
//Get Ids
$newId = $conn->lastInsertId();
$oldId = $grade->GradeID;
//build JSON
if($success){
$json[] = array('success'=> True,
'oldId'=>$oldId, 'newId'=>$newId);
}else{
$json[] = array('success'=> False,
'oldId'=>$oldId);
}
}
print json_encode($json);
Try the query in this form
"Select max(GradeID) from dbo.Grades"
I have this function that inserts data from a checkbox into my sql database and it works just find, but Im pretty new to this so I would like to know if there is a better/safer (from sql injections) way to do this. I know I should be using PDO with prepared statements, but that is something I am tackling later.
Here is the form that produces the html checkboxes:
<form action="" method="post">
<?php
if(empty($clients) === true){
echo '<p>You do not have any clients yet.</p>';
}
else
{
foreach($clients as $client){
echo'
<input type="checkbox" name="client_data[]" value="'.$_SESSION['user_id'].'|'.$class_id.'|'.$client['first_name'].'|'.$client['nickname'].'|'.$client['last_name'].'">
'.$client['first_name'].' ('.$client['nickname'].') '.$client['last_name'].'
<br />';
} // foreach($client
} // if empty
?>
Here is the php that calls the function:
if (isset($_POST['exist_to_class'])){
if (empty($_POST['client_data']) === true){
$errors [] = 'You much select a client to be added to the class.';
} else {
if (isset($_POST['client_data']) && !empty($_POST['client_data']));
foreach ($_POST['client_data'] as $cd){
exist_client_to_class($cd);
header('Location: view_class.php?class_id='.$class_id.' ');
} // foreach $cd
} // else
} //isset
And here is my function that inserts the data into the db:
// add existing client to class ----------------------------------------------------
function exist_client_to_class($cd){
list($user_id, $class_id, $first_name, $last_name, $nickname) = explode('|', $cd);
mysql_query("INSERT INTO `clients` (user_id, class_id, first_name, last_name, nickname, date)
VALUES('$user_id', '$class_id', '$first_name', '$last_name', '$nickname', CURDATE())");
}
First stab at a PDO prepared statement:UPDATE
function exist_client_to_class($cd){
try{
$stmt = $conn->prepare('INSERT INTO clients
(user_id, class_id, first_name, last_name, nickname, date)
VALUES (:user_id, :class_id, :first_name, :last_name, :nickname, CURDATE())
');
list($user_id, $class_id, $first_name, $last_name, $nickname) = explode('|', $cd);
$stmt->execute(array(
':user_id' => $user_id,
':class_id' => $class_id,
':first_name' => $first_name,
':last_name' => $last_name,
':nickname' => $nickname
)
);
}
catch(PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
}
Here is the db connect file:
//PDO database connect
try {
$conn = new PDO('mysql:host=localhost;dbname=customn7_cm', '**********', '**********');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->exec("SET CHARACTER SET utf8");
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
To put simply, Yes.
You aren't sanitizing or escaping your user data in anyway. you are using the old mysql_* community deprecated functions. You're best bet is to start using PDO or Mysqli
Read this article: PHP Database Access: Are You Doing It Correctly?
This works for most sql injections: (from php.net)
decleration:
string mysql_real_escape_string ( string $unescaped_string [, resource $link_identifier = NULL ] )
// Connect
$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password') OR die(mysql_error());
// Query
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
i need return id of last inseted row in my database :
i have a class named DatabaseHandler to use pdo
<?php class DatabaseHandler
{
private static $_mHandler;
private function __construct()
{}
private static function GetHandler()
{
if (!isset(self::$_mHandler))
{
try
{
self::$_mHandler =
new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD,
array(PDO::ATTR_PERSISTENT => DB_PERSISTENCY));
self::$_mHandler->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
self::$_mHandler->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
}
catch (PDOException $e)
{
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
}
return self::$_mHandler;
}
public static function Close()
{
self::$_mHandler = null;
}
public static function Execute($sqlQuery, $params = null)
{
try
{
$database_handler = self::GetHandler();
$statement_handler = $database_handler->prepare('set names utf8; ' . $sqlQuery);
$statement_handler->execute($params);
$result=$database_handler->lastInsertId();
}catch(PDOException $e){
self::Close();
trigger_error($e->getMessage(), E_USER_ERROR);
}
return $result;
}?>
and STORED PROCEDURE in mysql db :
CREATE PROCEDURE `sp_users_Insert`(IN _username VARCHAR(50), IN _email VARCHAR(50), IN _password CHAR(32), IN _ip VARCHAR(15), IN _reg_date INT, IN _ref_id MEDIUMINT)
BEGIN
INSERT INTO n_users
(username , email , password , ip , reg_date , ref_id )
VALUES(_username , _email , _password , _ip , _reg_date , _ref_id );
END$$
and when i call that like this , the database record is created but lastInsertId() return 0:
$username =me;
$email=me#me.com;
$password =msadss;
$ip =12.0.0.1;
$reg_date =1347284764;
$ref_id =12;
$sql = 'CALL `sp_users_Insert`(:username,:email,:password,:ip,:reg_date,:ref_id)';
$params = array (':username' => $username, ':email' => $email, ':password' => $password, ':ip' => $ip, ':reg_date' => $reg_date, ':ref_id' => $ref_id);
DatabaseHandler::Close();
return DatabaseHandler::Execute($sql, $params);
What i am doing wrong?
Try as last command in your procedure:
SELECT LAST_INSERT_ID();