0

My code below (must be something to do with sql statement (the UPDATE query statement), basically when I go in browser and visit script with a key that i know exists in the database I get the following error:

[15/04/2012 18:33:57] - exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '' for key 'user_activation_key'' in C:\wamp\www\user-verify.php:53
Stack trace:
#0 C:\wamp\www\user-verify.php(53): PDOStatement->execute(Array)
#1 {main}

Here is my code:, not sure what it saying about duplicate entry, as the user_activation_key column is unique and yes i am using InnoDB and foreign keys for data interigty.

// check if key is set and alphanumeric and equals 40 chars long
// we use sha1 so it will always be 40 chars long.
if(isset($_GET['key']) && ctype_alnum($_GET['key']) && strlen($_GET['key']) == 40){
    $key = trim($_GET['key']);
}

// if key isset
if(isset($key)){

try {
        // connect to database
        $dbh = sql_con();

        // if key is of valid length and type we need to update the `user_activation_key` in the `users_status` table to NULL
        // and update the `user_status`in the `users` table to 1 (tinyint)(active) based on the condition that the 
        // activation key can be found in the users_status.user_activation_key column and user_uid match in both users_status and users table
        $stmt = $dbh->prepare("
                            UPDATE
                                users
                            JOIN
                                users_status
                            ON
                                users_status.user_activation_key = ?
                            SET
                                users.user_status = 1,
                                users_status.user_activation_key = NULL
                            WHERE
                                users_status.user_uid = users.user_uid");

        // execute query
        $stmt->execute(array($key));

        if ( $stmt->rowCount() > 0 ) {

            echo 'account now activated';
            exit;

        } else {
            echo 'could not activate account at this time';
            exit;
        }

    // close database connection
    $dbh = null;

} // if any errors found log them and display friendly message
catch (PDOException $e) {
    ExceptionErrorHandler($e);
    require_once($footer_inc);
    exit;
}

} else {

// else key not valid or set
echo '<h1>Invalid Activation Link</h1>';

$SiteErrorMessages =
"Oops! Your account could not be activated. Please recheck the link in your email.
The activation link appears to be invalid.<br /><br />
If the problem persists please request a new one <a href='/member/resend-activation-email'>here</a>.";

SiteErrorMessages();

include($footer_inc);
exit;

}

Not sure why I am getting that error, any know what it means exactly ?

It won't perform the update even though the key exists in the users_status table. If I enter an invalid key it says could not activate account at this time which is what it should do but when the key is valid it should update but it's outputting the error above.

UPDATE:

Here is the the database design for those two tables.

CREATE TABLE `users` (
  `user_uid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'users unique id',
  `user_status` tinyint(1) unsigned NOT NULL COMMENT '0 = verify | 1 = active |  2 =  suspended | 3 = delete | 4 = spam |',
  `user_login` varchar(15) NOT NULL COMMENT 'users login username',
  `user_pass` char(152) NOT NULL,
  `user_email` varchar(255) NOT NULL COMMENT 'users email',
  `user_registered` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'user registration date',
  `user_display_name` varchar(60) NOT NULL COMMENT 'users display name (first & last name)',
  `user_failed_logins` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'failed login attempts',
  PRIMARY KEY (`user_uid`),
  UNIQUE KEY `user_login` (`user_login`),
  UNIQUE KEY `user_email` (`user_email`),
  KEY `user_pass` (`user_pass`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT=Users Table';

CREATE TABLE `users_status` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto generated id',
  `user_uid` int(10) unsigned NOT NULL,
  `user_activation_key` char(40) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_uid` (`user_uid`),
  UNIQUE KEY `user_activation_key` (`user_activation_key`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='user status table, when a user registers they must first activate there account';


ALTER TABLE `users_status`
  ADD CONSTRAINT `FK_user_status` FOREIGN KEY (`user_uid`) REFERENCES `users` (`user_uid`) ON DELETE CASCADE ON UPDATE CASCADE;
halfer
  • 19,824
  • 17
  • 99
  • 186
PHPLOVER
  • 7,047
  • 18
  • 37
  • 54
  • Can you provide the table definitions please. – GavinCattell Apr 15 '12 at 17:56
  • @GavinCattell - Updated main post, thanks phplover – PHPLOVER Apr 15 '12 at 18:07
  • 1
    You can't update two tables at a go, however, you can batch it. http://stackoverflow.com/questions/2044467/how-to-update-two-tables-in-one-statement-in-sql-server-2005 – keni Apr 15 '12 at 18:31
  • @Keni, i don't understand, if i run the below sql statement in Navicat it does exactly what i want it to: (basically the activation key below is an activation key that exists in database, basically when i run it in Navicat it updates the two rows, the `user_status.users_activation_key` to null and the `user.user_status` to 1 (active), don't understand :/ `UPDATE users JOIN users_status ON users_status.user_activation_key = '959e1a8dc42fd836a84160a7ec45ad12221fef3c' SET users.user_status = 1, users_status.user_activation_key = NULL WHERE users_status.user_uid = users.user_uid` – PHPLOVER Apr 15 '12 at 18:53
  • @keni, could you explain a bit more please ? i had a look at the link and understand what your saying but how is it when i run the query in my comment above in Navicat it does what i want it to which is update the two rows based on the conditions set in the sql statement ? thanks phplover – PHPLOVER Apr 15 '12 at 19:37
  • I upvoted but realised that link is for SQL Server 2005 and im using MySQL, still not solved my problem, it works in Navicat but the SQL statement won't work in the php script, thanks phplover – PHPLOVER Apr 16 '12 at 10:48

3 Answers3

4

On your query you are setting users_status.user_activation_key as NULL, and I am pretty sure, it has a UNIQUE index and value NULL must be already available in the table.

That's why you are receiving that error.

Starx
  • 77,474
  • 47
  • 185
  • 261
  • what your saying makes sense, it's a unique column, maybe i should make it not unique and do the check in php to ensure when a activation gets generated that it already does not exist in `users_status` table ? .. if i understand correctly because it's a unique column it cannot have a null value ? i updated main post with db design, thanks phplover – PHPLOVER Apr 15 '12 at 18:09
  • @PHPLOVER, Adding unique index is fine. Just do not allow `NULL`s – Starx Apr 15 '12 at 18:14
  • ok so how do i set the user_activation_key row for that particular user to nothing ? i mean it's a unique column but also when activation takes place i want the activation key to be updated to nothing on successful update ? thanks phplover – PHPLOVER Apr 15 '12 at 18:26
  • @PHPLOVER, Activation records are generally maintained on separate table, with only modifying the state and never removing it. BUt this depends, script to script. – Starx Apr 15 '12 at 18:29
  • they are on a serperate table, the `user_status` table holds the `user_uid` and `activation key`, on registration it inserts into `users` table there username, email, password etc and then the last insert id is then used to put there activation key and user_uid in the `users_status` table, when a user activates there account via email as long as the activation key is valid and a match is found in `users_status` table and `user_uid` match on both tables i want it to set `user_activation_key` to nothing and update `user.users_status` to 1 (which means active) thanks phplover – PHPLOVER Apr 15 '12 at 18:44
  • @PHPLOVER My bad, I didn't realize it was mysql earlier, tried hard to remove the comment then, but here we are. – keni Apr 16 '12 at 06:39
0

You are passing a NULL value for user_status.user_activiation_key and it seems that this field is a primary key and it cant be NULL or a Duplicate key ( exist key) so this will violate the Integrity constraint violation

confucius
  • 13,127
  • 10
  • 47
  • 66
  • the `user_status.user_activation_key` is not a primary key but is unique and has an index on it. I updated main post with database design, thanks phplover – PHPLOVER Apr 15 '12 at 19:08
0

After banging my head several times I have solved it, the problem was even thou the user_activation_key was unique and had an index I did not set the column to allow NULL values hence the error.

I changed it so it's still unique and has an index but allow NULL values and it works.

halfer
  • 19,824
  • 17
  • 99
  • 186
PHPLOVER
  • 7,047
  • 18
  • 37
  • 54