function fetch() on a non-object in PHP - php

I have this url,
http://webworks.net/ww.incs/forgotten-password-verification.php?verification_code=974bf747124c69f12ae3b36afcaccc68&email=myemail#gmail.com&redirect=/ww.admin/index.php
And this gives the following error.
Fatal error: Call to a member function fetch() on a non-object in
/var/www/webworks/ww.incs/basics.php on line 23
Call Stack: 0.0005 338372 1. {main}()
/var/www/webworks/ww.incs/forgotten-password-verification.php:
0 0.0020 363796 2. dbRow()
/var/www/webworks/ww.incs/forgotten-password-verification.php:18
The forgotten-password-verification.php
require 'login-libs.php';
login_check_is_email_provided();
// check that a verification code was provided
if(
!isset($_REQUEST['verification_code']) || $_REQUEST['verification_code']==''
){
login_redirect($url,'novalidation');
}
// check that the email/verification code combination matches a row in the user table
// $password=md5($_REQUEST['email'].'|'.$_REQUEST['password']);
$r=dbRow('select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
verification_code="'.$_REQUEST['verification_code'].'" and active'
);
if($r==false){
login_redirect($url,'validationfailed');
}
// success! set the session variable, then redirect
$_SESSION['userdata']=$r;
$groups=json_decode($r['groups']);
$_SESSION['userdata']['groups']=array();
foreach($groups as $g)$_SESSION['userdata']['groups'][$g]=true;
if($r['extras']=='')$r['extras']='[]';
$_SESSION['userdata']['extras']=json_decode($r['extras']);
login_redirect($url);
And login-libs,
require 'basics.php';
$url='/';
$err=0;
function login_redirect($url,$msg='success'){
if($msg)$url.='?login_msg='.$msg;
header('Location: '.$url);
echo 'redirect';
exit;
}
// set up the redirect
if(isset($_REQUEST['redirect'])){
$url=preg_replace('/[\?\&].*/','',$_REQUEST['redirect']);
if($url=='')$url='/';
}
// check that the email address is provided and valid
function login_check_is_email_provided(){
if(
!isset($_REQUEST['email']) || $_REQUEST['email']==''
|| !filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL)
){
login_redirect($GLOBALS['url'],'noemail');
}
}
// check that the captcha is provided
function login_check_is_captcha_provided(){
if(
!isset($_REQUEST["recaptcha_challenge_field"]) || $_REQUEST["recaptcha_challenge_field"]==''
|| !isset($_REQUEST["recaptcha_response_field"]) || $_REQUEST["recaptcha_response_field"]==''
){
login_redirect($GLOBALS['url'],'nocaptcha');
}
}
// check that the captcha is valid
function login_check_is_captcha_valid(){
require 'recaptcha.php';
$resp=recaptcha_check_answer(
RECAPTCHA_PRIVATE,
$_SERVER["REMOTE_ADDR"],
$_REQUEST["recaptcha_challenge_field"],
$_REQUEST["recaptcha_response_field"]
);
if(!$resp->is_valid){
login_redirect($GLOBALS['url'],'invalidcaptcha');
}
}
basics.php is,
session_start();
function __autoload($name) {
require $name . '.php';
}
function dbInit(){
if(isset($GLOBALS['db']))return $GLOBALS['db'];
global $DBVARS;
$db=new PDO('mysql:host='.$DBVARS['hostname'].';dbname='.$DBVARS['db_name'],$DBVARS['username'],$DBVARS['password']);
$db->query('SET NAMES utf8');
$db->num_queries=0;
$GLOBALS['db']=$db;
return $db;
}
function dbQuery($query){
$db=dbInit();
$q=$db->query($query);
$db->num_queries++;
return $q;
}
function dbRow($query) {
$q = dbQuery($query);
return $q->fetch(PDO::FETCH_ASSOC);
}
define('SCRIPTBASE', $_SERVER['DOCUMENT_ROOT'] . '/');
require SCRIPTBASE . '.private/config.php';
if(!defined('CONFIG_FILE'))define('CONFIG_FILE',SCRIPTBASE.'.private/config.php');
set_include_path(SCRIPTBASE.'ww.php_classes'.PATH_SEPARATOR.get_include_path());
I am not sure how to solve the problem.
My db:
CREATE TABLE IF NOT EXISTS `user_accounts` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` text,
`password` char(32) DEFAULT NULL,
`active` tinyint(4) DEFAULT '0',
`groups` text,
`activation_key` varchar(32) DEFAULT NULL,
`extras` text,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;
INSERT INTO `user_accounts` (`id`, `email`, `password`, `active`, `groups`, `activation_key`, `extras`) VALUES
(2, 'bla#blabla.com', '6d24dde9d56b9eab99a303a713df2891', 1, '["_superadministrators"]', '5d50e39420127d0bab44a56612f2d89b', NULL),
(3, 'user#blabla.com', 'e83052ab33df32b94da18f6ff2353e94', 1, '[]', NULL, NULL),
(9, 'myemail#gmail.com', '9ca3eee3c43384a575eb746eeae0f279', 1, '["_superadministrators"]', '974bf747124c69f12ae3b36afcaccc68', NULL);

The answer is, I believe, in this:
the table user_accounts:
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` text,
`password` char(32) DEFAULT NULL,
`active` tinyint(4) DEFAULT '0',
`groups` text,
`activation_key` varchar(32) DEFAULT NULL,
`extras` text,
PRIMARY KEY (`id`)
and
the 'forgotten-password-verification.php':
// check that the email/verification code combination matches a row in the user table
// $password=md5($_REQUEST['email'].'|'.$_REQUEST['password']);
$r=dbRow('select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
verification_code="'.$_REQUEST['verification_code'].'" and active'
);
where verification_code is not a valid part of user_accounts.
Change it and it should work ;)

Line 23 of basics.php is probably:
return $q->fetch(PDO::FETCH_ASSOC);
This means that $q is not the object you expected it to be (seems like a PDOStatement). Apparently, it is returned from the dbQuery function, which returns the result of PDO::query. PDO::query will return a PDOStatement on success, or FALSE on error.
It means that you query is erroneous. Most likely this one:
$r=dbRow('select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
verification_code="'.$_REQUEST['verification_code'].'" and active'
);
The problem is probably the end of your query, which does not look like valid SQL:
and active
Also, since you are using PDO, you should take advantage of prepared statements, since your code is actually open to SQL injection. addslashes is not a proper mechanism for escaping database parameters, and you should not use $_REQUEST unless you know what you are doing. You should use $_GET, $_POST or $_COOKIE directly.
For your securing your queries, use prepared statements, and check the return values:
function dbQuery($query, array $params = array()){
$db=dbInit();
$q=$db->prepare($query); // use prepare() instead of query()
$q->execute($params); // automatically bind the parameters with execute()
$db->num_queries++;
return $q;
}
function dbRow($query, array $params = array()) {
$q = dbQuery($query, $params);
if (!$q) {
// check for errors
throw new Exception('A database error has occured!');
}
return $q->fetch(PDO::FETCH_ASSOC);
}
Then just do:
$r=dbRow('select * from user_accounts where email=? and verification_code=?',
array($_GET['email'], $_GET['verification_code'])
);

There is a problem in password_reminder.php.
In stead of verificatio_code, it was using activation_code.

Related

Why my MySQL function to check if inserted data exists not working?

I'm writing a registry form and wanna check if inserted data exists.
I wrote my own function to do that. This Function should check tables and if rows exist, return FALSE and if not exist then return TRUE and will insert the data to the tables.
I have 2 tables: 'users' and 'passwords'.
USERS(
user_id INT AUTO_INCREMENT,
user_login VARCHAR(30) NOT NULL,
user_email VARCHAR(255) NOT NULL,
join_date TIMESTAMP NOT NULL,
PRIMARY KEY - user_id
)
PASSWORDS(
password_id INT AUTO_INCREMENT,
user_id INT NOT NULL,
hash_password VARCHAR(255) NOT NULL,
PRIMARY KEY - password_id,
FOREIGN KEY - user_id REFERENCES USERS(user_id)
)
My SQL CODE:
CREATE FUNCTION `create_user`(`login` VARCHAR(30), `password` VARCHAR(255), `email` VARCHAR(255)) RETURNS BOOLEAN DETERMINISTIC NO SQL SQL SECURITY DEFINER BEGIN
IF (SELECT EXISTS(SELECT user_login,user_email FROM users WHERE user_login = login OR user_email = email LIMIT 1) OR (SELECT EXISTS(SELECT hash_password FROM passwords WHERE hash_password = password LIMIT 1)))
THEN
RETURN FALSE;
ELSE
INSERT INTO users(user_login,user_email)
VALUES(
login,
email
);
INSERT INTO passwords(user_id, hash_password)
VALUES(
(SELECT MAX(user_id) FROM users),
password
);
RETURN TRUE;
END IF;
END
MY PHP CODE:
public static function createUser($user,$password,$email,$DbDependency)
{
self::setDependency($DbDependency);
$query = "CALL create_user('$user','$password','$email')";
try
{
if(self::getDependency() -> query($query))
{
new UserManager($user,$password,$email);
header("Location: ../../Views/congratulations");
}
else
{
echo "bad";
}
}
catch(PDOException $error)
{
echo $error -> getMessage();
}
}
MySQL function 'create_user' should return FALSE if data exists OR TRUE if not exists,insert data to tables and PHP. IF function works then it should create a new userManager object and go to next page.
Instead of this page, it shows me "bad" and tables are still empty.

$GLOBAL Setting a table in array Call to member function

Okay, I'm using GLOBALS to set some settings within my whole site
$tmp = $GLOBALS['_ODB']->query("SELECT * FROM `options`");
$GLOBALS['options'] = NameToTop($tmp->fetchAll(PDO::FETCH_ASSOC));
I have this as my query, then I use this function to put the returned data in an array
So I can call it by using $GLOBALS['settings']['setting1']
function NameToTop($arr)
{
$output = array();
foreach ($arr as $val) {
$output[$val['name']] = $val['value'];
}
return $output;
}
Then here is the settings table, I don't see why this is going wrong; I really need some help.
CREATE TABLE IF NOT EXISTS `options` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`name` text NOT NULL,
`value` text NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
--
-- Dumping data for table `options`
--
INSERT INTO `options` (`ID`, `name`, `value`) VALUES
(1, 'setting1', 'Name'),
(2, 'email', 'webmaster#gmail.com'),
(3, 'site_title', 'Title of Site'),
I'm getting
Call to a member function fetchAll() on a non-object
You're expecting $tmp to be a PDOStatement object in order to call fetchAll() on it but it isn't, hence the error message you're seeing.
PDO::query() returns false on failure, so this is most likely what is happening.
This comment from the PDO manual talks about the return value of query():
The handling of errors by this function is controlled by the
attribute PDO::ATTR_ERRMODE.
Use the following to make it throw an exception:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
You need to read up on error handling in PDO. Most people do tend to go down the exceptions route.
That would make your example something like this:
try {
$tmp = $GLOBALS['_ODB']->query("SELECT * FROM `options`");
$GLOBALS['options'] = NameToTop($tmp->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
// handle the error in some way
echo $e->getMessage();
}

mysql_affected_rows Returns False On Successful Query?

I am having a difficult time sorting through this PHP/MySQL issue. Let me show you my database, and explain my situation:
Create table:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(50) NOT NULL AUTO_INCREMENT,
`active` varchar(20) NOT NULL,
`activation` varchar(15) NOT NULL,
`firstName` longtext NOT NULL,
`lastName` longtext NOT NULL,
`passWord` longtext NOT NULL,
`changePassword` text NOT NULL,
`emailAddress1` longtext NOT NULL,
`emailAddress2` longtext NOT NULL,
`emailAddress3` longtext NOT NULL,
`role` longtext NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `name` (`firstName`,`lastName`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
Insert a value:
INSERT INTO `users` (
`id` ,
`active` ,
`activation` ,
`firstName` ,
`lastName` ,
`passWord` ,
`changePassword` ,
`emailAddress1` ,
`emailAddress2` ,
`emailAddress3` ,
`role`
) VALUES (
NULL, '1000000000', 'abcdefghijklmno', 'John', 'Smith', '*24D7FB97963C40FE5C56A6672F9560FC8B681508', 'on', 'john#gmail.com', '', '', 'User'
);
Update a value:
$affected = mysql_query(UPDATE users SET passWord = PASSWORD('a9eb42e1b3be829ef42972ea9abab334'), changePassword = 'on' WHERE emailAddress1 = 'john#gmail.com', $dbID);
if (mysql_affected_rows($affected)) {
//Never runs
}
The above UPDATE query executes just fine in my script, phpMyAdmin, and the MySQL terminal. However, mysql_affected_rows($affected) always gives me this error:
Warning: mysql_affected_rows() expects parameter 1 to be resource, boolean given
I know that this means my query failed, but every time I go into the database, I see that the values have been updated.
Removing the parameter from the function appears to clear things up. However, I rather have the identifier as the function parameter, just to be sure what I am referring to, and for code insurance.
Any idea why this might be doing this?
Thank you for your time.
http://php.net/mysql_query
Return Values
...
For other type of SQL statements, INSERT, UPDATE, DELETE, DROP, etc, mysql_query() returns TRUE on success or FALSE on error.
And:
int mysql_affected_rows ([ resource $link_identifier = NULL ] )
This means mysql_affected_rows wants a mysql connection resource as an argument. Not the result of mysql_query, and most certainly not if that result is only true or false. You use it like this:
$successful = mysql_query('UPDATE ...');
if ($successful) {
echo 'Affected rows: ' . mysql_affected_rows();
} else {
echo 'Fail: ' . mysql_error();
}
change:
$affected = mysql_query(UPDATE users SET passWord = PASSWORD('a9eb42e1b3be829ef42972ea9abab334'), changePassword = 'on' WHERE emailAddress1 LIKE 'john#gmail.com', $dbID);
and execute
In my case, it was that the new value of updating was equal to the old value, so no change is made and the result of the mysql_affected_rows() would be 0 or false

PHP: Getting insert confirmation on prepared statement

I am a newbie to prepared statements and trying to get something simple to work.
This is my DB table:
`unblocker_users` (
`uno` bigint(20) NOT NULL AUTO_INCREMENT,
`user_email` varchar(210) DEFAULT NULL,
`pw_hash` varchar(30) DEFAULT NULL,
`email_confirmed` tinyint(4) DEFAULT NULL,
`total_requests` bigint(20) DEFAULT NULL,
`today_date` date DEFAULT NULL,
`accessed_today` tinyint(4) DEFAULT NULL,)
and this is my function to insert some test data
function add_new_user($e_mail1)
{
require_once "db.php";
$stmt = $mysqli->prepare("INSERT INTO unblocker_users VALUES ('',?, ?,0,0,?,0)");
$stmt->bind_param('sss', $e_mail1, $this->genRandomString(1),$this->today_date());
$stmt->execute();
$stmt->close();
// ####### Below line is giving an error ########
$done = $stmt->affected_rows;
return $done;
}
As you can see above, i have marked the line that is giving me an error.
Warning: unblocker_class::add_new_user() [unblocker-class.add-new-user]: Property access is not allowed yet in...
Where did I go wrong?
How can i get some sort of confirmation that a row has been inserted successfully?
Thanks!
you close the prepared statement BEFORE you want to access its affected rows
$done = $stmt->affected_rows;
$stmt->close();
return $done;

OOP PHP user class (usercake) not adding to database

I recently found this little user class script called usercake (http://usercake.com/), has all the basic functionality and seems to work very well.
My problem: The first user gets added to the database fine, but after that it is not working. Clearly there's just something slightly wrong that I'm not figuring out ( i do not know oop php very well). No errors occure (that i can see), and the email gets sent out.
I've installed it multiple places with the same fate. I'd like to fix it because using this script saves a lot of reinventing the wheel time.
Here is the URL where I have it: http://rawcomposition.com/birding/loggedin/register.php
Here is the function that gets called once everything is validated:
public function userCakeAddUser()
{
global $db,$emailActivation,$websiteUrl,$db_table_prefix;
//Prevent this function being called if there were construction errors
if($this->status)
{
//Construct a secure hash for the plain text password
$secure_pass = generateHash($this->clean_password);
//Construct a unique activation token
$this->activation_token = generateActivationToken();
//Do we need to send out an activation email?
if($emailActivation)
{
//User must activate their account first
$this->user_active = 0;
$mail = new userCakeMail();
//Build the activation message
$activation_message = lang("ACTIVATION_MESSAGE",array($websiteUrl,$this->activation_token));
//Define more if you want to build larger structures
$hooks = array(
"searchStrs" => array("#ACTIVATION-MESSAGE","#ACTIVATION-KEY","#USERNAME#"),
"subjectStrs" => array($activation_message,$this->activation_token,$this->unclean_username)
);
/* Build the template - Optional, you can just use the sendMail function
Instead to pass a message. */
if(!$mail->newTemplateMsg("new-registration.txt",$hooks))
{
$this->mail_failure = true;
}
else
{
//Send the mail. Specify users email here and subject.
//SendMail can have a third parementer for message if you do not wish to build a template.
if(!$mail->sendMail($this->clean_email,"New User"))
{
$this->mail_failure = true;
}
}
}
else
{
//Instant account activation
$this->user_active = 1;
}
if(!$this->mail_failure)
{
//Insert the user into the database providing no errors have been found.
$sql = "INSERT INTO `".$db_table_prefix."Users` (
`Username`,
`Username_Clean`,
`Password`,
`Email`,
`ActivationToken`,
`LastActivationRequest`,
`LostPasswordRequest`,
`Active`,
`Group_ID`,
`SignUpDate`,
`LastSignIn`
)
VALUES (
'".$db->sql_escape($this->unclean_username)."',
'".$db->sql_escape($this->clean_username)."',
'".$secure_pass."',
'".$db->sql_escape($this->clean_email)."',
'".$this->activation_token."',
'".time()."',
'0',
'".$this->user_active."',
'1',
'".time()."',
'0'
)";
return $db->sql_query($sql);
}
}
}
And here is the table structure:
CREATE TABLE IF NOT EXISTS `userCake_Users` (
`User_ID` int(11) NOT NULL AUTO_INCREMENT,
`Username` varchar(150) NOT NULL,
`Name` varchar(100) NOT NULL,
`Username_Clean` varchar(150) NOT NULL,
`Password` varchar(225) NOT NULL,
`Email` varchar(150) NOT NULL,
`ActivationToken` varchar(225) NOT NULL,
`LastActivationRequest` int(11) NOT NULL,
`LostPasswordRequest` int(1) NOT NULL DEFAULT '0',
`Active` int(1) NOT NULL,
`Group_ID` int(11) NOT NULL,
`SignUpDate` int(11) NOT NULL,
`LastSignIn` int(11) NOT NULL,
PRIMARY KEY (`User_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
To me, there are 2 possibilities why it is not adding further users after the first one is added:
First, $this->mail_failure flag is set to TRUE for the following user accounts after the first user is created. But this scenario is not likely because it is the same code that has run successfully for the first user and therefore there is no reason why the flag should be TRUE for others.
Second possibility is that $this->status is FALSE for the second user account. If false, the method userCakeAddUser() does not do anything. The reasons why this flag could be false is either the username or the email address already exists.
Are you using the same username or email address you used for the first account for the second account as well? I'm sure you must not be using the same username but perhaps the same email address. The usercake classes does not allow the same username or same email addresses.
Hope this helps.
I would do 4 things with this uggly code :
1) to enable the error_reporting mode so that you can see something in case sthg occurs :
error_reporting(E_ALL);
2) to test this INSERT sql straight into the dB to make sure it's working properly, and validate this piece of code. If the sql INSERT request is valid, then check the access conditions to these SQL request, like Abhay said above,
3) As we do not have your all config available, a guess game is difficult. So I'd suggest you to add one NULL field for the AI User_ID.
$sql = "INSERT INTO `".$db_table_prefix."Users` (
`User_ID`, // Add this here
`Username`,
`Username_Clean`,
`Password`,
`Email`,
`ActivationToken`,
`LastActivationRequest`,
`LostPasswordRequest`,
`Active`,
`Group_ID`,
`SignUpDate`,
`LastSignIn`
)
VALUES (
NULL, // and that one
'".$db->sql_escape($this->unclean_username)."',
'".$db->sql_escape($this->clean_username)."',
'".$secure_pass."',
'".$db->sql_escape($this->clean_email)."',
'".$this->activation_token."',
'".time()."',
'0', // later, I would also try using an int for an int
'".$this->user_active."',
'1',
'".time()."',
'0'
)";
4) to find another one, better coded, using OOP and PDO.
You given Name as NOT NULL and in Insert statement of your code is not sending Name value, so mysql will throw an exception, saying Name cannot be null, check this once.

Categories