Please help me to correct this code.
error at line
$stmt->execute($params = [], $query);
and when i open the file with dreamweaver every "$params=[]" is error.
-Databasse.php-
<?php
include_once('connection.php'); //my connection is here
class Database extends connection{
public function __construct(){
parent::__construct();
}
public function getRow($params = [], $query){
try {
$stmt = $this->datab->prepare($query);
$stmt->execute($params);
return $stmt->fetch();
} catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
public function getRows($query, $params = []){
try {
$stmt = $this->datab->prepare($query);
$stmt->execute($params);
return $stmt->fetchAll();
} catch (PDOException $e) {
throw new Exception($e->getMessage());
}
}
this is half of the source code database.php
Need to see more of the code - what is your query string, what array w/ what values are you trying to feed into it?
Typically your query will have question marks ? or might have keywords with colons :mykeyword as place holders for values, and then your array holds the values that are "prepared" and executed.
$query="select name from users where name=? and passwordHash=?";
$res=$connection->prepare($query);
$res->execute(array(
"myuser",
"dd02c7c2232759874e1c205587017bed"),
);
// OR
$query="select name from users where name=:name and passwordHash=:passwordHash";
$res=$connection->prepare($query);
$res->execute(array(
":name" => "myuser",
":passwordHash" => "dd02c7c2232759874e1c205587017bed"),
);
This does the query preparation, escaping, etc. and the "myuser" value replaces the first question mark and the hash string replaces the second.
Related
My PHP-coded JOIN fails My SQL JOIN is fine as it works from the SQL command line - but while my PHP code will return one or more records from a single table, it fails when I JOIN with:
Uncaught Error: Call to a member function get_result() on array
My environment:
Windows 8.1.6
10.4.24-MariaDB
Apache/2.4.53 (Win64)
libmysql - mysqlnd 8.1.6
OpenSSL/1.1.1n PHP/8.1.6
The following query works from the sql command line. It is the one I would like PHP to resolve for me:
SELECT productoptionsr.contentnamekey,content.contentname LEFT JOIN content ON productoptionsr.contentnamekey=content.contentnamekey FROM productoptionsr WHERE businessnamekey='8c9007ab5e9942a80b19887057511d7b1f3c5bbea8672dc03f4fd8291f6c18ab' AND ponamekey='c91bafa8aebfb760547c761110441790f263d3c23721a5034b4d26e97b231668' ORDER BY seq;
My PHP code (a library that I put together in part using code from php.net help text)
function DBExecute($DB, $sql)
{ // A wrapper to prepare, execute a query and return $stmt
//////////////////////////////////////////////////////////////////////////////
global $sql_request;
$sql_request=$sql;
//////////////////////////////////////////////////////////////////////////////
try { $stmt = $DB->prepare($sql); }
catch (Exception $e)
{ // Handle the error, something went wrong
error_log($e->getMessage());
return DBState($DB, [ "errno"=>$e->getCode(), "error"=>$e->getMessage() ]);
}
try { $stmt->execute(); }
catch (Exception $e)
{ // Handle the error, something went wrong
error_log($e->getMessage());
return DBState($DB, [ "errno"=>$e->getCode(), "error"=>$e->getMessage() ]);
}
return $stmt;
}
function DBSelect($DB, $table, $selection, $conditions, $limit=0)
{ // A simple wrapper to prepare, select and return records
global $receipt, $sql_request;
if($limit>0)
{ $conditions="$conditions LIMIT $limit"; }
$sql="SELECT $selection FROM $table WHERE $conditions";
$sql_request=$sql;
//////////////////////////////////////////////////////////////////////////////
$result=[];
try
{ $stmt=DBExecute($DB, $sql);
if (!($res = $stmt->get_result()))
{ Abort("DBSelectData get_result() failed: (" . $stmt->errno . ") " . $stmt->error ." $sql"); }
//////////////////////////////////////////////////////////////////////////////
for ($row_no = ($res->num_rows - 1); $row_no >= 0; $row_no--) {
$res->data_seek($row_no);
$result[]=$res->fetch_assoc();
}
//////////////////////////////////////////////////////////////////////////////
// Reverse our reverse array to put it into correct order
if(isset($result))
{$result=array_reverse($result);}
$stmt->close();
return $result;
} catch (Exception $e)
{
// Handle the error, something went wrong
error_log($e->getMessage());
return DBState($DB, [ "errno"=>$e->getCode(), "error"=>$e->getMessage() ]);
}
return true;
}
function DBState($DB=false, $stmt=false)
{ // Return state of play, give precedence to prepare/execute errno
//////////////////////////////////////////////////////////////////////////////
global $sql_request;
//////////////////////////////////////////////////////////////////////////////
if($stmt&&$stmt["errno"]>0)
{ return [ "affected_rows"=>0, "insert_id"=>0, "errno"=>$stmt["errno"], "error"=>$stmt["error"], "query"=>"$sql_request", "A"=>mt_rand(2,32767) ]; }
return [ "affected_rows"=>mysqli_affected_rows($DB), "insert_id"=>mysqli_insert_id($DB), "errno"=>$DB->errno, "error"=>$DB->error, "query"=>"$sql_request", "B"=>mt_rand(2,32767) ];
}
function DBConnect($DBHOST, $DBUSER, $DBPASS, $DBINSTANCE)
{ // Connect to the db and return a pointer
// Enable DB exceptions
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// Connect
$DB=new mysqli("$DBHOST", "$DBUSER", "$DBPASS", "$DBINSTANCE");
if($DB->connect_errno)
{
$report["DBHOST"]="$DBHOST";
$report["DBUSER"]="$DBUSER";
if(mb_strlen("$DBPASS")>4&&"$DBPASS"!=="false")
{ $report["DBUSER"]="true"; } else { $report["DBUSER"]="false"; }
$report["DBINSTANCE"]="$DBHOST";
$report["errno"]=$DB->connect_errno;
$report["error"]="Connect error: ".$DB->connect_error;
Abort( json_encode( $report, JSON_PRETTY_PRINT) );
}
// Set char set
mysqli_set_charset($DB, 'utf8mb4');
return $DB;
}
function DBClose($DB)
{ // Disconnect from db
$result=DBState($DB, [ "errno"=>0, "error"=>"" ]);
$DB->close();
return $result;
}
DBSelect($DB, "$TABLE[PRODUCTOPTIONSR]",
"PRODUCTOPTIONSR.contentnamekey, CONTENT.contentname INNER JOIN CONTENT ON PRODUCTOPTIONSR.contentnamekey=CONTENT.contentnamekey",
"businessnamekey='8c9007ab5e9942a80b19887057511d7b1f3c5bbea8672dc03f4fd8291f6c18ab' AND ponamekey='c91bafa8aebfb760547c761110441790f263d3c23721a5034b4d26e97b231668' ORDER BY seq");
Your code is very messy due to all the superfluous error checking, which has led you to your current problem. You are catching the error and then returning an array from DBState which then bubbles up to DBExecute. Thus, somewhere there you have a suppressed error which causes your code to execute get_result on an array. Fix your return types and remove all this error checking.
Here's your code after a slight tyding up:
<?php
/**
* A wrapper to prepare, execute a query and return $stmt
*/
function DBExecute($DB, $sql): mysqli_stmt
{
$stmt = $DB->prepare($sql);
$stmt->execute();
return $stmt;
}
/**
* A simple wrapper to prepare, select and return records
*/
function DBSelect($DB, $table, $selection, $conditions, $limit = 0): array
{
if ($limit > 0) {
$conditions = "$conditions LIMIT $limit";
}
$sql = "SELECT $selection FROM $table WHERE $conditions";
$stmt = DBExecute($DB, $sql);
return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
}
/**
* Connect to the db and return a pointer
*/
function DBConnect($DBHOST, $DBUSER, $DBPASS, $DBINSTANCE): mysqli
{
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$DB = new mysqli("$DBHOST", "$DBUSER", "$DBPASS", "$DBINSTANCE");
$DB->set_charset('utf8mb4');
return $DB;
}
It's far from perfect, but at least now the actual error will show up in your error logs. It's still missing parameter type specifications.
Lesson learned: be very careful with try-catch. Use it only if you are sure that you actually need it.
I'm a new in web programming and would ask the advice for code below.
I have the code in class Database. There is it. As you see there's a connect to database with mysqli. And this code work.
function __construct() {
$this->conn = $this->connectDB();
}
function connectDB() {
$conn = mysqli_connect($this->host,$this->user,$this->password,$this->database);
return $conn;
}
function runBaseQuery($query) {
$result = mysqli_query($this->conn,$query);
while($row=mysqli_fetch_assoc($result)) {
$resultset[] = $row;
}
if(!empty($resultset))
return $resultset;
}
function runQuery($query, $param_type, $param_value_array) {
$sql = $this->conn->prepare($query);
$this->bindQueryParams($sql, $param_type, $param_value_array);
$sql->execute();
$result = $sql->get_result();
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$resultset[] = $row;
}
}
if(!empty($resultset)) {
return $resultset;
}
}
function bindQueryParams($sql, $param_type, $param_value_array) {
$param_value_reference[] = & $param_type;
for($i=0; $i<count($param_value_array); $i++) {
$param_value_reference[] = & $param_value_array[$i];
}
call_user_func_array(array(
$sql,
'bind_param'
), $param_value_reference);
}
function insert($query, $param_type, $param_value_array) {
$sql = $this->conn->prepare($query);
$this->bindQueryParams($sql, $param_type, $param_value_array);
$sql->execute();
}
function update($query, $param_type, $param_value_array) {
$sql = $this->conn->prepare($query);
$this->bindQueryParams($sql, $param_type, $param_value_array);
$sql->execute();
}
I have to write this class in PDO. I've done it, but something is wrong. I try to connect my Database and get the error
Fatal error: Uncaught TypeError: PDO::__construct() expects parameter 4
class DB {
private $host = "";
private $user = "";
private $password = "";
private $database = "";
private $pdo;
function __construct() {
$this->pdo = $this->connectDB();
}
function connectDB() {
try
{
$pdo = new PDO($this->host,$this->user,$this->password,$this->database);
}
catch (PDOException $e) {
print "Error!: " . $e->getMessage();
}
die();
}
function runBaseQuery($query)
{
$result = $pdo->query($query);
while ($row = $pdo->fetch(PDO::FETCH_ASSOC)) {
$resultset[] = $row;
}
if (!empty($resultset))
return $resultset;
}
function runQuery($query, $param_type, $param_value_array) {
$sql = $pdo->prepare($query);
$pdo->execute($sql, $param_type, $param_value_array);
$result = $pdo->fetchAll(PDO::FETCH_ASSOC);
if ($result->num_rows > 0) {
while ($row = $pdo->fetchAll(PDO::FETCH_ASSOC)) {
$resultset[] = $row;
}
}
if(!empty($resultset)) {
return $resultset;
}
}
function bindQueryParams($sql, $param_type, $param_value_array) {
$param_value_reference[] = & $param_type;
for($i=0; $i<count($param_value_array); $i++) {
$param_value_reference[] = & $param_value_array[$i];
}
call_user_func_array(array(
$sql,
'bind_param'
), $param_value_reference);
}
function insert($query, $param_type, $param_value_array) {
$sql = $pdo->prepare($query);
$pdo->execute($sql, $param_type, $param_value_array);
}
function update($query, $param_type, $param_value_array) {
$sql = $pdo->prepare($query);
$pdo->execute($sql, $param_type, $param_value_array);
}
}
But my the new code don't work. Where is the problem?
Your new class has multiple problems. The one you are asking about can be solved by understanding how to connect properly with PDO and what DSN is. For this I have to refer you to this awesome article https://phpdelusions.net/pdo#dsn
Take this DSN for example:
mysql:host=localhost;dbname=test;port=3306;charset=utf8mb4
driver^ ^ colon ^param=value pair ^semicolon
You start by specifying which DB driver you would like to use: mysql:. After this comes a list of key-value pairs separated by a semicolon. The order should be host, DB name, and charset. You should specify all of these values.
Your DSN is your first argument to PDO::__construct(), the second and third is username and password respectively. The third one is an array of options.
Your options array should contain at least two values. You need to enable error reporting and switch off emulated prepared statements. These are the recommended settings.
Your connection should look at least similar to this:
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$this->pdo = new PDO('mysql:host='.$this->host.';dbname='.$this->database.';charset=utf8mb4', $this->user, $this->password, $options);
However, please take note, that the constructor will be called once, and you do not need to put these values in private properties. They can simply be constants or hardcoded in the constructor. You will never need to reuse this values after opening connection.
Your second main mistake is that you are referring in a lot of places to $pdo, but you should be using $this->pdo.
Other notes:
die(); is going to end your whole script. Do not use it.
Do not catch exceptions, just to print out the error message. It defeats the whole purpose of the exceptions.
The method bindQueryParams() seems completely unnecessary. I would recommend you remove it.
runQuery is riddled with mistakes. $pdo->execute() takes in only one argument, which should be the array of values to be bound. There is no need for param type like in mysqli. The while loop is redundant and incorrect.
num_rows does not exist in PDO, and is not needed at all.
None of these method provide any benefit over just plain PDO.
Conclusion:
The class you have written is completely unnecessary and only makes your code more difficult to understand and maintain. While it might have made more sense with mysqli, PDO is simpler to use and does not need to be wrapped in such class. Please read the article linked at the beginning carefully, it will help you a lot.
The PDO connection does not take a 4th parameter for the database name. The DB name is passed in with the host name. So change:
$pdo = new PDO($this->host,$this->user,$this->password,$this->database);
to:
$pdo = new PDO($this->host . ';dbname=' . $this->database, $this->user, $this->password);
For more information see https://www.php.net/manual/en/pdo.connections.php
Additionally, it is unclear what $this->host contains but for PDO if that is just a host path you need to pass in the driver you are using as well, so you might even need to add
mysql:host=
to the start of this. With mysqli this is not required because the only RDBMS mysqli supports is mysql.
So potentially complete answer:
$pdo = new PDO('mysql:host=' . $this->host . ';dbname=' . $this->database, $this->user, $this->password);
An example of one of my queries...
public function db_query_select($query, $params, $param_types){
$dbc = $this->dbConnect();
if($stmt = $dbc->prepare($query)){
//prepared.
//move the types to the front of the param array
array_unshift($params, $param_types);
//call the bind param function with the parameters passed in by reference
//bind_param only allows by reference.
call_user_func_array(array($stmt, "bind_param"), $this->paramsToRefs($params));
//binded.
//attempt to execute the sql statement.
if ($stmt->execute()){
$result = $stmt->get_result();
$stmt->close();
$dbc->close();
return $result;
}
}
//must have failed...
return NULL;
}
how can I change stmt get_result(); to something that is accepted by shared servers/hosts without the native driver... mysqlnd.
Anyone know? without changing all of my functions that use this database function.
Thanks.
UPDATED:::: Thanks to #your common sense, See Answer.
I believe this is what I was after. Hope it helps anyone that was having the same problem as myself. PDO vs MySQLi, seems simpler... no user call func or anything like that.
DB HANDLER:
private function dbConnect(){
$config = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/NTConfig.ini');
try {
$dbc = new PDO('mysql:host='.$config['DB_HOST'].';dbname='.$config['DB_DATABASE'].'', $config['DB_USER'], $config['DB_PASSWORD']);
$dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}
return $dbc;
}
public function db_query_select($query, $params){
$dbc = $this->dbConnect();
if($stmt = $dbc->prepare($query)){
//prepared.
//attempt to execute the sql statement.
if ($stmt->execute($params)){
$result = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($result);
//$stmt->close();
//$dbc->close();
return $result;
}
}
//must have failed...
return NULL;
}
Outside the DBHANDLER
$query = "SELECT error_desc FROM nt_errors WHERE error_code = :ERROR_CODE LIMIT 1";
//array: holds parameters for the query.
$params = array(
':ERROR_CODE' => $code
);
$result = $db->db_query_select($query, $params);
if ($result == NULL){
$errorText = 'ERROR: Failed to retrieve error';
}
else{
//var_dump($result);
$errorText = $result['error_desc'];
PDO is not only much more user friendly than mysqli but also doesn't have any of such a nasty drawbacks. So I strongly suggest to use PDO instead of mysqli.
With DO, the function you're after should be as simple as this
function run($sql, $args = NULL)
{
$pdo = ...;//your means of getting the connection variable
$stmt = $pdo->prepare($sql);
$stmt->execute($args);
return $stmt;
}
After gettin the function's result, you can chain a fetch method to its call, fetchColumn() in your case.
Given your code is mostly procedural, let me suggest you a very simple PDO wrapper I wrote. So the full code would be:
$sql = "SELECT error_desc FROM nt_errors WHERE error_code = ?";
$errorText = DB::run($sql,[$code])->fetchColumn();
if (!$errorText){
$errorText = 'ERROR: Failed to retrieve error';
}
Here DB class is a better replacement of your dbConnect() function, and run() method is a replacement for db_query_select() that actually can be used for any query type, including insert, update or anything.
This code section is used on another page where results are to be displayed.
<?php
require 'core/init.php'; //all classes are contained in here.
$general->logged_out_protect();
$search = $_POST['search'];
if ($users->user_exists($_POST['search']) == false) {
$errors[] = "Sorry that username doesn't exists";
} else
if ($users->user_exists($_POST['search']) == true) {
// i would like to display username which is in the user_exists if the above condition is met.
}
}
?>
//This is function user_exists in which i determine if username is in database then after i display the username.
public function user_exists($username) {
$query = $this->db->prepare("SELECT COUNT(`id`) FROM `users` WHERE `username`= ?");
$query->bindValue(1, $username);
try{
$query->execute();
$rows = $query->fetchColumn();
if($rows == 1){
return true;
}else{
return false;
}
} catch (PDOException $e){
die($e->getMessage());
}
}
You either use PDO and execute: http://php.net/manual/en/pdo.prepare.php
$sth->execute(array(':calories' => 150, ':colour' => 'red'));
or mysqli and bind param and then execute: http://php.net/manual/en/mysqli.prepare.php
if ($stmt = $mysqli->prepare("SELECT District FROM City WHERE Name=?")) {
/* bind parameters for markers */
$stmt->bind_param("s", $city);
/* execute query */
$stmt->execute();
note if you use prepare:
you don't need to escape your input string
you need to use ? as placeholder or :placeholder : http://php.net/manual/en/mysqli-stmt.bind-param.php
Query debugging:
to get mysqli errors use: or die(mysqli_error($db) after your execute or query call.
solution
change the order of your execute() and bind_param() (first bind_param() then execute())
your sql query should be: "SELECT * FROM users WHERE username like '%$?%'"
Several programming suggestions.
PHP is dynamic typed, so a variable or function result value, may return different variable types, stick to single type.
In some circumstances null could be used, instead of the predefined type, for example,
returning null when a search is not found, instead of an integer value.
For PHP, use comments to determine which data type a function receives or returns.
Before.
public function user_exists($username) {
After.
public /* bool */ function user_exists(/* string */ $username) {
It doesn't change your code logic, but, helps any programmer, either you or another person, to understand the logic of the function.
When using a "try" sentence in a function that returns a value (non void function), only use a single "try" sentence.
When using a "try" sentence in a function that returns a value (non void function), declare the local variables with empty values before the "try", and make all assignaments inside the "try":
Before.
public function user_exists($username) {
$query = $this->db->prepare("SELECT COUNT(`id`) FROM `users` WHERE `username`= ?");
$query->bindValue(1, $username);
try{
$query->execute();
$rows = $query->fetchColumn();
if($rows == 1){
return true;
}else{
return false;
}
} catch (PDOException $e){
die($e->getMessage());
}
}
After.
public function user_exists($username) {
$query = null;
try{
$query = $this->db->prepare("SELECT COUNT(`id`) FROM `users` WHERE `username`= ?");
$query->bindValue(1, $username);
$query->execute();
$rows = $query->fetchColumn();
if($rows == 1){
return true;
}else{
return false;
}
} catch (PDOException $e){
die($e->getMessage());
}
}
This allows you to read their values in the catch section when an exception is generated,
or to clean them either in the catch sections or finally sections.
Even that the PHP enviroment is garbaged collected as: Java, ".Net", and other programming enviroments, some good "House Cleaning" is welcome, and helps you have more control of your programming logic.
When using a "try" sentence in a function that returns a value (non void function), assign the exception result to a local variable, and transfer the die to a "finally" section.
Example:
public function user_exists($username) {
$query = null;
$ExceptionMsg = "";
$AnyException = false;
try{
$query = $this->db->prepare("SELECT COUNT(`id`) FROM `users` WHERE `username`= ?");
$query->bindValue(1, $username);
$query->execute();
$rows = $query->fetchColumn();
if($rows == 1){
return true;
}else{
return false;
}
} catch (PDOException $e){
$ExceptionMsg = $e->getMessage();
$AnyException = true;
} finally{
if ($AnyException)
die($ExceptionMsg);
}
}
Cheers.
I have created class having the following two methods:
Connection method is as following:
private function connect(){
try{
$this->con = new PDO("mysql:host={$this->host};dbname={$this->db_name};charset=utf8", $this->db_user, $this->db_pass);
$this->con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->con->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE);
}catch(PDOException $ex){
return $ex->getMessage();
}
}
While here is the method for insert,update,delete and search record in table:
public function dbQuery($sql,$bindVars=array()){
try{
$this->connect();
$statement = $this->con->prepare($sql);
$statement->execute($bindVars);
if($statement->rowCount() > 0){
return true;
}
else{
return false;
}
}catch(PDOException $exc){
return $exc->getMessage();
}
$this->con = null;
Now i am using this way to (for example) insert record to my table:
1- fill array that could be bind to dbQuery method;
$bindInputInsert = array(
':empSno'=>$empSno,
':fromCourt'=>$fromCourt,
':toCourt'=>$toCourt,
':transferDate'=>$transferDate,
':transferFromDate'=>$transferFromDate,
':causeOfTransfer'=>$causeOfTransfer,
':departmentDetails'=>$departmentDetails,
':orderNo'=>$orderNo
);
2- Now prepare an insert query like this:
$sqlInsert = "INSERT INTO empoffices (
empSno,
fromCourt,
toCourt,
transferDate,
transferFromDate,
causeOfTransfer,
departmentDetails,
orderNo
)
VALUES(
:empSno,
:fromCourt,
:toCourt,
:transferDate,
:transferFromDate,
:causeOfTransfer,
:departmentDetails,
:orderNo
)";
3- Send the query to dbQuery method and test record inserted or not?
if($db->dbQuery($sqlInsert,$bindInputInsert)){
echo($method->sucMsg("Info: - "," Record saved successfully"));
}
else {
echo($method->errorMsg("Error: - ","Record not saved"));
}//end else insert()
Problem i am facing with this:
The above method is working fine for me but when if i misspelled a column name in the query it does not inserted record to table (Which is correct), but still it returns true??? while it should return false?
What i am doing wrong i am not understanding, please help me out in this. Thanks in Advance.
Your method dbQuery only returns false if a valid query results in a rowCount() <= 0. When you send an invalid query, such as one with a misspelled column name, it is returning an exception, specifically $exc->getMessage(); which is not false.
Try something like this instead:
if ($db->dbQuery($sqlInsert,$bindInputInsert) === true) {
// success
} ...
This will evaluate as true if and only if dbQuery returns exactly true - not false or $exc->getMessage();.