PHP database class does not commit - php

I'm creating a php class what is able to handle my query's and db connections.
I've played around with it for a while and did some research, now I've created m When I use the class for something to handle it does not commit, but I'm not able to see why it doesn't
I don't get any error's and my mysqli error handling is correct.
does anyone have a idea what's wrong with my script?
sql class:
class sql{
function convertArrayReferences($arr){
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
function database($database, $query, $parameters){
$result;
$mysqli = new mysqli("****", "****", "****", $database);
if(mysqli_connect_errno()){
return "Connect failed: %s\n " . mysqli_connect_error();
}
if(!$stmt = $mysqli->prepare($query)){
return $mysqli->error;
}
if(!$stmt->bind_param($this->convertArrayReferences($parameters))){
return $mysqli->error;
}
if(!$stmt->bind_result($result)){
return $mysqli->error;
}
if(!$stmt->execute()){
return $mysqli->error;
}
$stmt->close();
return $mysqli->error;
}
}
the bit of code where the function is called:
$execute = $sql->database("survivalTmpReg",
"INSERT INTO USERS (name, surname, email, username, password) VALUES (?, ?, ?, ?, ?)",
array("sssss", $name, $surname, $email, $username, $password));
if($execute){
$message = REGISTER_MESSAGE;
}else{
$message = $execute;
}

Statements are not automatically committed unless autocommit is turned on. On the first statement a transaction is created. Unless the transaction is not explicitly committed its changes will not be visible and eventually the transaction will be aborted by the system. MySQLi supports committing transactions using mysqli::commit.

Related

Number of bound variables does not match number of tokens when using a custom PDO function

I tried the questions with similar titles, but they are all regular queries that are not in functions.
I am trying to create an update function in a Database class so I don't have to write out the entire process over and over. However, I am getting the error:
Invalid parameter number: number of bound variables does not match number of tokens
Here is my function.
public function updateRow($query, $params) {
try {
$stmt = $this->master_db_data->prepare($query);
foreach($params as $key => $val) {
$stmt->bindValue($key+1, $val);
$stmt->execute();
return true;
}
} catch(PDOException $e) {
die("Error: " . $e->getMessage());
}
}
And its usage:
$query = "UPDATE records SET content=?, ttl=?, prio=?, change_date=? WHERE id=?";
$params = array($SOA_content, $fields['SOA_TTL'], '1', $DATE_TIME, $id);
if($db->updateRow($query, $params)) {
echo "Success";
}
else {
echo "Fail";
}
Doing it without a function works:
$pdo = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
$query = "UPDATE records SET content=:content, ttl=:ttl, prio=:prio, change_date=:change_date WHERE id=:id";
$stmt = $pdo->prepare($query);
$stmt->bindValue(":content", $SOA_content);
$stmt->bindValue(":ttl", $fields['SOA_TTL']);
$stmt->bindValue(":prio", 1);
$stmt->bindValue(":change_date", $DATE_TIME);
$stmt->bindValue(":id", $id);
$stmt->execute();
Am I wrong with my bindValue in the function? If so, how?
Always make sure your execute calls happen after all binding has been performed. In this situation, move the execute out of the binding loop.

PDO: FetchAll after SQL INSERT and SELECT multiple statement in one execute

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'.

data insertion using PDO

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.

Is this bad practice for inserting data into db?

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));

Properly closing database connections in PHP

I'm facing some doubts in PHP database connections. Since I can't just put a large try/catch/finally block on my method (Java style), what's the best approach to properly closing all connections and prepared statements when size/logic tends to increase? Considering the next method, is everything done right?
public function createRegister($register) {
$this->openConnection();
$query = "INSERT INTO register (username, password, email, confirmationToken) VALUES (?, ?, ?, ?)";
$result = $this->mysqli->query($query);
if ($statement = $this->mysqli->prepare($query)) {
$statement->bind_param("ssss", $register->username, $register->passwordHash, $register->email, $register->confirmationToken);
if (!$statement->execute()) {
$this->closeConnection();
throw new DAOException("Failed to execute statement: " . $statement->error);
}
$statement->close();
} else {
$this->closeConnection();
throw new DAOException("Failed to prepare statement: " . $this->mysqli->error);
}
$this->closeConnection();
}
You can still use try/catch in PHP:
public function createRegister($register) {
$this->openConnection();
$query = "INSERT INTO register (username, password, email, confirmationToken) VALUES (?, ?, ?, ?)";
try {
// This line is not needed
// $result = $this->mysqli->query($query);
if ($statement = $this->mysqli->prepare($query)) {
$statement->bind_param("ssss", $register->username, $register->passwordHash, $register->email, $register->confirmationToken);
if (!$statement->execute()) {
throw new DAOException("Failed to execute statement: " . $statement->error);
}
$statement->close();
} else {
throw new DAOException("Failed to prepare statement: " . $this->mysqli->error);
}
} catch (Exception $e) {
if ((isset($statement)) && (is_callable(array($statement, 'close')))) {
$statment->close();
}
$this->closeConnection();
throw $e;
}
$this->closeConnection();
}
This works well for establishing a connection for one specific task, but what if you want to share the same connection for multiple tasks that also need access to the same schema? You may want to consider a more advanced solution using a singleton/factory pattern for creating and access database connections. I posted such an example as a solution to another question. It is a bit more advanced but once you get your head around it, it is more performant.

Categories