I am writing my PHP blog engine. I am using PDO for it. And now, when I am writing class Member - I have an error.
Fatal error: Call to a member function fetch() on a non-object in
/home/tucnak/Server/scripts/php/classes/Member.php on line 42
And source code of my Class:
public function authMember($user, $password)
{
$password = hashIt($password);
$count = 100500;
$count = $this->db->query("SELECT count(*) FROM users-general WHERE nick = $user AND password = $password;")->fetch();
echo($count);
// if ($count == 1){ return 1; } else { throw new Exception("",491); }
}
I have an error using this function.
Your query probably fails because you don't have quotes wrapped around your query.
When that happens, query() will return false instead of an object, breaking the chain.
Don't do it this way; run the query first, save its result, then check whether it's false.
By the way, you should really use prepared statements - your current statement is vulnerable to SQL injection.
"SELECT count(*) FROM `users-general` WHERE nick = '$user' AND password = '$password'"
note the single quotes of 2 different types
Thought, your misunderstanding has nothing to do with PDO. it's basic SQL syntax you have to learn
Related
I am not familiar with the COM class at all and I have not used PHP that much in a few years, so I am really struggling with this. At this point, I am only trying reconfigure the code to prevent SQL injection. There is a deadline to have this done shortly, so now I need to reach out for help.
Here is the original connection statement.
$conn = new COM ("ADODB.Connection") or die("Cannot start ADO");
$conn->open ("PROVIDER=MSOLEDBSQL;SERVER=".$servername.";UID=".$user.";PWD=".$pwd.";DATABASE=".$db);
I assumed I could use prepared statements or binding, however when I do, I get a “cannot pass parameter 2 by reference” error.
$sql = "SELECT * FROM Account WHERE User=?";
$rs= $conn->Execute($sql,array($user));
Uncaught Error: Cannot pass parameter 2 by reference in...
I also tried something similar to what is documented on the adodb.org page, with similar results.
$bindVars = array('$user');
$sql = "SELECT * FROM Account WHERE User=?";
$rs = $conn->execute($sql,$bindVars);
Uncaught com_exception: Microsoft OLE DB Driver for SQL Server
No value given for one or more required parameters.
The errors I am getting makes it look like one of (or possibly both) is possible, but I cannot seem to find the right combination of parameters that will make this work. Can one of these be configured to work? If so, how?
If it is not possible, then I will try to reconfigure this for mysqli (they also have a MySQL database) and probably have to rewrite the entire site. Here are a couple of snippets of the current code. Does anyone have a good example of translating something like this to code that would work if I have to switch to using the MySQLi driver instead?
if ( (isset($_SESSION['userid'])) && (is_numeric($_SESSION['userid'])) ) {
$item = isValidItem($_GET['item']);
$enddate = strtotime($item->Fields['EndDate']->value);
if (is_numeric($_POST['amount'])) { $_SESSION['amount'] = $_POST['amount']; }
if ((is_null($item) == false) && (isset($_SESSION['amount'])) && (isValidBid($item,$_SESSION['amount']))) {
$highestbidder = $item->Fields['UserID']->value;
...
function isValidBid($item,$amount) {
$currentbid = $item->Fields['CurrentBid']->value;
$startdate = strtotime($item->Fields['StartDate']->value);
global $enddate;
if (time() > ($enddate - 300)) {
if (($amount-$currentbid) < 50) {
alert("Invalid bid amount");
session_destroy();
return false;
}
...
Im new to database and i have written a LOT of PHP code that accesses a database using MySQL.
I didnt take into account SQL injection attacks so i have to re-write all that PHP code to use mysql prepared statements.
After looking at videos on how to used prepared SQL statements, to perform just ONE SQL command requires a whole lot of "prepared" statements. My existing code has lots of different SQL statements all over the place, it would be a nightmare to change all that code to pack and unpack all the required preparation for each "prepared" statement command.
Is there some kind of wrapper i can use to prevent turning one line of regular SQL into 6 or 7 lines of prepared statements?
For example use to do this line line of SQL
SELECT * from users where userid=10
needs many more lines of prepared SQL statements, especially if there are lots of other SQL statements too it now becomes very complex.
Is there was some sort of one line wrapper that i can call that accepts the template SQL string, plus the parameters, which also executes the command and returns the result in just one line of wrapper for different types of MYSQL statements it would be great and the code would be much less confusing looking and error prone.
For example
$users=WrapAndExecute($db,"SELECT * from users where userid=?","s",$userid);
$data=WrapAndExecute($db,"UPDATE table SET username=?,city=?","ss",$name,$city);
$result=WrapAndExecute($db,"DELETE from table where id=?","s",$userid);
$result=WrapAndExecute($db,"INSERT into ? (name,address) VALUES(?,?)","ss","users",$name,$address);
Each of those lines above would create a prepared statement template, do the bind, execute it and return the result that a regular MYSQL statement would. This would create minimal impact on existing code.
Anybody knows how to do this or if some easy php library or class already exists to do this, that i can just import and start using it?
Thanks
You don't need to change a query to a prepared statement if it has no PHP variables in it. If it has just constant expressions, it's safe from SQL injection.
$sql = "SELECT * from users where userid=10"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
You don't need to change a query that contains PHP variables, as long as the value of that variable is a constant specified in your code. If it doesn't take its value from any external source, it's safe.
$uid = 10;
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
You don't need to change a query that contains PHP variables, as long as you can filter the value to guarantee that it won't risk an SQL injection. A quick and easy way to do this is to cast it to an integer (if it's supposed to be an integer).
$uid = (int) $_GET['uid'];
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
That leaves cases where you are using "untrusted" values, which may have originated from user input, or reading a file, or even reading from the database. In those cases, parameters are the most reliable way to protect yourself. It's pretty easy:
$sql = "SELECT * from users where userid=?"; // Safe!
// two lines instead of the one line query()
$stmt = $pdo->prepare($sql);
$stmt->execute([$_GET['uid']]);
$data = $stmt->fetchAll();
In a subset of cases, you need one additional line of code than you would normally use.
So quit your whining! ;-)
Re your comment about doing prepared statements in mysqli.
The way they bind variables is harder to use than PDO. I don't like the examples given in http://php.net/manual/en/mysqli.prepare.php
Here's an easier way with mysqli:
$sql = "SELECT * from users where userid=?"; // Safe!
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $_GET['uid']);
$stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_all();
I don't like the stuff they do in their examples with bind_result(), that's confusing and unnecessary. Just use get_result(). So with mysqli, you need two more lines of code than you would with PDO.
I've written query wrappers for mysqli that emulate the convenience of PDO's execute() function. It's a PITA to get an array mapped to the variable-arguments style of bind_param().
See the solution in my answers to https://stackoverflow.com/a/15933696/20860 or https://stackoverflow.com/a/7383439/20860
I were in the same boat, and I wrote such a wrapper that works exactly the way you want, save for it's being a class, not a function.
$user = $sdb->getRow("SELECT * from users where userid=?s", $userid);
$sdb->query("UPDATE table SET username=?s, city=?s", $name, $city);
$sdb->query("DELETE from table where id=?s", $userid);
$sdb->query("INSERT into ?n (name,address) VALUES(?s,?s)","users", $name, $address);
The above is a working code, as long as you have somewhere in your bootstrap file
$db = mysqli_connect(...);
...
require 'safemysql.class.php';
$sdb = new SafeMySQL('mysqli' => $db);
Note that none of the other suggestions could do anything like that.
Also note that if I were writing it today, I would have used PDO, as this class is duplicating a lot of functionality already exists in PDO.
Take a look at the PDO extension in PHP - http://php.net/manual/en/intro.pdo.php: it it secure against injections thanks to prepared statements; also, it allows you to connect to many different databases (e.g. MySQL, MSSQL, etc.).
You can then build your own wrapper as you wish to keep it clean; for example your own wrapper could be as follows:
(following example will return user rows as objects)
// connect to DB
$GLOBALS['default_db'] = new DB('localhost','db_name','username','password') ;
// Get users and output results
$query = new DBQuery('SELECT * FROM users WHERE userid = ?',array(10)) ;
var_dump($query -> results()) ;
var_dump($query -> num_rows()) ;
// DB connection
class DB {
public $connection;
public function __construct($host , $dbname , $username , $password) {
$this->connection = new \PDO('mysql:host=' . $host . ';dbname=' . $dbname , $username , $password);
}
}
// Wrapper
class DBQuery {
private $num_rows = 0;
private $results = array();
public function __construct($query , $params = null , $class_name = null , DB $db = null) {
if ( is_null($db) ) {
$db = $GLOBALS['default_db'];
}
$statement = $db->connection->prepare($query);
$statement->execute($params);
$errors = $statement->errorInfo();
if ( $errors[2] ) {
throw new \Exception($errors[2]);
}
$fetch_style = ($class_name ? \PDO::FETCH_CLASS : \PDO::FETCH_OBJ);
$this->results = $class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style);
$this->num_rows += $statement->rowCount();
while ( $statement->nextrowset() ) {
$this->results = array_merge($this->results,$class_name ? $statement->fetchAll($fetch_style , $class_name) : $statement->fetchAll($fetch_style));
$this->num_rows += $statement->rowCount();
}
}
public function num_rows() {
return $this->num_rows;
}
public function results() {
return $this->results;
}
}
Since a key requirement seems to be that you can implement this with minimal impact on your current codebase, it would have been helpful if you had told us what interface you currently use for running your queries.
While you could use PDO:
that means an awful lot of work if you are not already using PDO
PDO exceptions are horrible
Assuming you are using procedural mysqli (and have a good reason not to use mysqli_prepare()) its not that hard to write something (not tested!):
function wrapAndExecute()
{
$args=func_get_args();
$db=array_shift($args);
$stmt=array_shift($args);
$stmt_parts=explode('?', $stmt);
if (count($args)+1!=count($stmt_parts)) {
trigger_error("Argument count does not match placeholder count");
return false;
}
$real_statement=array_shift($stmt_parts);
foreach ($args as $k=>$val) {
if (isnull($val)) {
$val='NULL';
} else if (!is_numeric($val)) {
$val="'" . mysqli_real_escape_string($db, $val) . "'";
}
$real_statement.=$val . array_shift($stmt_parts);
}
return mysqli_query($db, $real_statement);
}
Note that this does not handle IS [NOT] NULL nicely nor a literal '?' in the statement nor booleans (but these are trivial to fix).
As a part of a login system I need to check if the username exists in the database so I created a query that checks if the username the user entered already exists.
With mysql_result I check if the id is larger as null. If yes: user exists and if not the user doesn't exist. But here it goes wrong and wampserver gives me this error:
Warning: mysql_result() expects parameter 1 to be resource, object given in users.php on line 6
function user_exists($username){
global $user_db;
$username = sanitize($username);
$query = mysqli_query($user_db , "SELECT COUNT(`id`) FROM `users` WHERE `username` = '$username'");
$result = mysql_result($query, 0); //line 6
if(!$result){
return false;
}else{
return true;
}
}
and this is the code that calls that function:
if(user_exists('name') === true){
echo 'exists';
}
$user_db = mysqli_connect("localhost","root","","databaseName");
What did I try:
if I do this: mysqli_result($result,0,"id"); I get this error: Call to undefined function mysqli_result().
got this suggestion from this question
All the answers on questions like mine say that you should not use mysql
and mysqli both but only one of them but when I only use mysli I get the error like I told one paragraph above this one.
So can somebody tell me how to fix this.
You are mixing mysql and mysqli a bit. There is no function mysqli_result() in mysqli driver. However I found a solution to your problem. From comment in PHP documentation:
Converting an old project from using the mysql extension to the mysqli
extension, I found the most annoying change to be the lack of a
corresponding mysql_result function in mysqli. While mysql_result is a
generally terrible function, it was useful for fetching a single
result field value from a result set (for example, if looking up a
user's ID).
The behavior of mysql_result is approximated here, though you may want
to name it something other than mysqli_result so as to avoid thinking
it's an actual, built-in function.
The code:
<?php function mysqli_result($res, $row, $field=0) {
$res->data_seek($row);
$datarow = $res->fetch_array();
return $datarow[$field]; }
?>
Source: http://php.net/manual/en/class.mysqli-result.php
I have been trying to convert a old mysql too pdo as I am trying to learn how pdo works, I have been working on this one file for hours now busting my head and can not figure out what is wrong, and I'm sure its a lot.
try{
$check_user_data = $dbh->query("SELECT * FROM members WHERE username = '$username'");
$stmt = $dbh->prepare($check_user_data);
$stmt->execute();
$result->bind_result($username);
$data_exists = ($check_user_data->fetchColumn() > 0) ? true : false;
if($data_exists = false){
$final_report.="This username does not exist..";
}else{
$get_user_data = $stmt->fetch(PDO::FETCH_ASSOC);
if($get_user_data['password'] == $password){
$start_idsess = $_SESSION['username'] = "".$get_user_data['username']."";
$start_passsess = $_SESSION['password'] = "".$get_user_data['password']."";
$final_report.="You are about to be logged in, please wait a few moments.. <meta http-equiv='Refresh' content='2; URL=members.php'/>";
}
}
foreach ($dbh->query($sql) as $row){
}
$dbh = null;
}
catch(PDOException $e){
echo $e->getMessage();
}
Also getting a fatal
Fatal error: Call to a member function execute() on a non-object
Not sure if the fatal is related to the warning or not.
First, change these two lines:
$check_user_data = $dbh->query("SELECT * FROM members WHERE username = '$username'");
$stmt = $dbh->prepare($check_user_data);
to:
$stmt = $dbh->prepare("SELECT * FROM members WHERE username = :username");
$stmt->bindParam(':username', $username);
This makes use of the parameter feature of prepared statements, which prevents SQL injection.
Next, PDO doesn't have a bind_result method, that's part of MySQLI. To get the results, you should do:
$get_user_data = $stmt->fetch(PDO::FETCH_ASSOC);
$data_exists = ($get_user_data !== false);
You should then remove the call to $stmt->fetch in the else block, because it will try to get the next row of results.
The fatal is definitely related to the warning; you are passing the results of $dbh->query() (which is a PDOStatementObject) into $dbh->prepare, causing $dbh->prepare to return something which is not an object.
Just move the SQL into the $dbh->prepare call and get rid of the $dbh->query() entirely.
For people who might come over here my problem was a bit different i was trying to enable a filter on doctrine/symfony project and accidentally made a mistake on the following line :
$filter->setParameter($name, $someObject);
and when i called the function getParameter($name) in addFilterConstraint function i got the same error
Warning: PDO::prepare() expects parameter 1 to be string, object given
And later on i found the mistake. the fix would be to replace the setParameter second input from $someObject to $someString something like this:
$filter->setParameter($name, 'some string which is the real value you want to get later');
I'm beginning with PHP and i need your help.
I create a try to list all members who has the same interest that the current_member( i mean the connected member ).
I write this :
$current_members = params('current_member');
$members_all = option('db')->query('SELECT * FROM members WHERE interest = $current_members["interest"] ORDER BY lastname, firstname')->fetchAll();
set('members_all', $members_all);
When I go on my page I have the error :
Fatal error: Call to a member function fetchAll() on a non-object
And in my view I just write this :
<h2 id="member-<?= $member['id'] ?>">
<?= avatar_tag($member,'30x30') ?>
<?=$member['firstname']?><small> <?= $member['lastname'] ?></small>
</h2>
I dont understand this error, anyone can help me ?
Thank's for your help.
Do not chain calls to query() and fetchAll() like you are doing. That's bad practice. Never assume your query worked, always check to see if it did.
$db = option('db');
$query = $db->query('SELECT ...');
if($query === FALSE){
print_r($db->errorInfo());
die;
}
$members_all = $query->fetchAll();
(Since you are calling fetchAll(), I assume you are using PDO (and not MySQLi))
Also, do not try to concatenate variables into your SQL query. (P.S. You're not even doing that, you are using single quotes, so $current_members["interest"] is not being read as a variable) That's just asking for an SQL injection attack. What you want to do is use prepared statements.
$db = option('db');
$query = $db->prepare('SELECT * FROM members WHERE interest = ? ORDER BY lastname, firstname');
$exec = $query->execute(array($current_members['interest']));
if($exec === FALSE){
print_r($query->errorInfo());
die;
}
$members_all = $query->fetchAll();
The "call to a member function on a non-object" error, means that you are trying to call a method on a variable that does not represent an object.
You have the following methods called one after the other on the $members_all denifition:
option('db')->query("...")->fetchAll();
You call the method "query" of whatever returns option('db') with some SQL query, and then you call fetchAll() method to whatever returns that "query" method.
I do not know if I explained myself well, the main point is that when you execute the query method it is returning something that has not the "fetchAll" method, in your case your SQL is wrong and probably query() is returning NULL or FALSE instead of a result set.
Change your single quotes with double quotes or concatenate the $current_member['interest'] variable.
IN your sql query
'SELECT * FROM members WHERE interest = $current_members["interest"] ORDER BY lastname, firstname'
you are using single quotes, so $current_members["interest"] actually does not resolve to a PHP variable, it is a string. You can switch single and double quotes:
Made an edit here, passing array offset was not fortunate:
$interest = $current_members['interest'];
"SELECT * FROM members WHERE interest = $interest ORDER BY lastname, firstname"
Unfortunately you did not share any of the underlying database code, but assuming option('db') is a pdo object, this should work fine.
If option('db') really is a pdo, before executing any statement add:
option('db') -> setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
this will tell you the exact error