After some hours I have to post this question even if the answer maybe obvious to someone else.
The problem is that I want to test for the tokens, but even when I hardcode this, I still get INVALID. And I know it has to be right, because I tested it in PHPADMIN directly. What's odd is that it always passes the first time (without being hardcoded), but after that it is useless?
The tokens are retrieved from a cookie.
public function findTriplet($credential, $token, $persistentToken) {
$token = "459078a3b05ce938ed58f9678ac78f1agcgfsewe4";
$persistentToken = "24d317b742da89ddf5b8ed50993d0f3cgcgfsewe4";
$credential ="34";
$q = "SELECT IF(SHA1(?) = {$this->tokenColumn}, 1, -1) AS token_match " .
"FROM {$this->tableName} WHERE {$this->credentialColumn} = ? " .
"AND {$this->persistentTokenColumn} = SHA1(?) LIMIT 1 ";
$query = $this->db->prepare($q);
$query->execute(array($token, $credential, $persistentToken));
$result = $query->fetchColumn();
if (!$result) {
return self::TRIPLET_NOT_FOUND;
} else if ($result == 1) {
return self::TRIPLET_FOUND;
} else {
return self::TRIPLET_INVALID; }
}
EDIT
The limit clause always catches the first row it finds, therefore I
always get a mismatch Now I have to fix this.
The solution was simple. Delete the entry that was just validated before inserting a new row with the newly generated token. The new row should contain the SAME persistenceToken you just validated against. REMEMBER, this will still be UNSECURE, so set a FLAG on the serverside that this was a cookielogin, and require a REAL LOGIN for handling important data.
I think your if checks are in the wrong order:
if(!$result) { return self::TRIPLET_NOT_FOUND;}
elseif ($result == 1) { return self::TRIPLET_FOUND;}
else { return self::TRIPLET_INVALID;}
In the SQL, 1 means found, -1 means not found, and anything else would be invalid. But in the PHP, a -1 would fall into the else clause, and return self::TRIPLET_INVALID, whereas an invalid result would fall into if(!$result) and return self::TRIPLET_NOT_FOUND.
Related
I'm working on some web code which uses codeigniter and the built in querybuilder to access a database.
I attempt to load data from the database for the current user
$userModel = $this->loadModel('ModelUser');
$name = $this->session->userdata('user');
$user = $userModel->getUser($name);
This is the code forgetUser:
function getUser($username)
{
$this->db->where('username',$username);
$query = $this->db->get('tblusers',1);
$res = $query->result();
if ($query->num_rows() > 0)
{
log_message('debug','Got user. ID = '.$res[0]->id);
foreach($res[0] as $key => $val)
{
$this->$key = $val;
}
return $this;
}
else {
log_message('info','failed to find user '.$username);
return NULL;
}
}
This works fine except when I let the session expire, in which case I get the details of another user.
These are the results of testing getUser:
$userModel->getUser("Admin"); //Got user. ID = Admin_ID
$userModel->getUser("john"); //Got user. ID = John_ID
$userModel->getUser(""); //Failed to find user
$userModel->getUser(null); //Failed to find user
When I log in as Admin then let the session timeout, the top snippet logs the message:
Got user. ID = John_ID
I would expect either Got user. ID = Admin_ID or Failed to find user
When $this->session->userdata('field') does not find an entry, it returns 0 instead of the "" or null that I was testing against.
Logging $this->db->last_query() showed this since the resulting query was:
SELECT * FROM tblusers WHERE username = 0 LIMIT 1;
MySQL will automatically convert strings to integers where the string starts with an integer. A string without an integer will be cast to 0 as explained in this answer. The query was returning the first entry it came across instead of finding no rows as any string that didn't start with 1-9 would match the WHERE clause.
I added a clause to getUser to return NULL if $username == ''. I did try === 0 but that yielded the same error so there's some type coercion going on that I'm not 100% certain of, but this covers the issue nicer than handling the case each time getUser is called.
I have our users click an activation link via email when they sign up for our site. The link looks like http://www.site.com/?u=123&a=xyz.
When the user hits the link, my code parses the $_GET["u"] and $_GET["a"] params. The code makes sure there is nothing malicious and what not. This code also checks to see if $_GET["u"] is set and defined. If it's empty, it's spits out an error message.
if(isset($_GET["u"]) && ($_GET["u"] !== "") && is_numeric($_GET["u"]) {
// proceed to function
$u = clean_it($_GET["u"]);
} else {
// show error screen
}
If these params ARE NOT empty, they are then sent to a function to check the values against the db.
My check, within this function, is:
if($u === NULL) {
return FALSE;
} else {
// check $u against the db
$sql = "SELECT * FROM users WHERE user_id=$u LIMIT 1;";
}
So when requests comes in, it's going immediately to the function and hitting the sql call. My queries, from these requests, are looking like:
SELECT * FROM users WHERE user_id=NULL LIMIT 1;
Why is this happening? Any ideas? $_GET["u"] is definitely being set (I can see it in the referer). This problem does not always occur; it's pretty random. Maybe 2-3 out of ~140 new accounts per day.
If it happens just sometimes, personally, I would replace those $u === NULL by empty($u). I think you are simply trying to check that you have a value in there.
if(!empty($_GET['u']) && is_numeric($_GET["u"]) {
// proceed to function
$u = clean_it($_GET["u"]);
} else {
// show error screen
}
if(empty($u)) {
return FALSE;
} else {
// check $u against the db
$sql = "SELECT * FROM users WHERE user_id=$u LIMIT 1;";
}
Of course since you only gave fragments of code it could be that your variable gets erased somewhere else we don't see.
On a side note - building your query like this is a bad idea. Research PHP's PDO.
Should I be using mysql_num_rows (rowCount in PDO) in update or insert query?
Currently, my code looks likes this,
public function update_username(){
$q = "UPDATE usertable SET username = '$user_name' WHERE id = '$user_id' LIMIT 1";
$r = $db->query($q);
if($r){
$message = "Updated successfully";
return $message;
}else{
return false;
}
}
Should I change it to like this?
public function update_username(){
$q = "UPDATE usertable SET username = '$user_name' WHERE id = '$user_id' LIMIT 1";
$r = $db->query($q);
if($r){
$num = $r->rowCount();
if($num == 1){
$message = "Updated successfully";
return $message;
}else{
$message = "An error occurred";
return $message;
}
}else{
return false;
}
}
Normally, query goes through without any error, so I shouldn't worry about it too much, but which one would be a better coding practice? Or do you suggest something else?
Thanks so much in advance!
Actually the two codes do something different.
The first one will print "Update success" if the query was successfully executed. But a query can be successfully executed also without affecting any row, i.e. you have a WHERE statamenet that does not match. The second code will not print "Update success" if no rows were affected.
Of course, if you're sure that your WHERE statement has to match, you can use both codes without any difference and using the second one could help you to spot any potential bug, i.e. it doesn't match and so something went wrong (probably the id was different from the one you expected).
Generally, to answer your question, mysql_num_rows is needed only if you want to know how many lines were affected. It's not mandatory at all to use it.
So, it depends on what you want. Both are good, but they are different.
If you are 100% sure the variables are created by you and not someone else you can do it like that, but you can minimize the code more:
public function update_username(){
$q = "UPDATE usertable SET username = '$user_name' WHERE id = '$user_id'";
if($db->query($q)){
return "Updated successfully";
}
return false;
}
First, because a query is executed successfully, doesn't necessarily mean that anything has been updated. So if you need to distinct the difference between a queries validity or the update change, then yes, rowCount would be a good practice.
Second, a prepared statement would be more wise to use when assigning variables (SQL injection, etc).
public function update_username(){
$q = "UPDATE usertable SET username = :user_name WHERE id = :user_id LIMIT 1";
$r = $db->prepare($q);
$r->bindValue(':user_name', $user_name);
$r->bindValue(':user_id', $user_id);
if($r->execute()){
$message = "Updated successfully: updated ".$r->rowCount();
return $message;
}else{
return false;
}
}
To avoid code duplication, maybe you should consider avoiding writing the same execution code for a query, and move that to a method/function which does that all for you, e.g
public function validateStmt($r) {
// validate query
if($r->execute()) {
// check result set
if($r->rowCount() > 0) {
return $r;
}
else {
// if a result set IS expected, then you might consider to handle this as
// a warning or an error
}
}
else {
// query invalid
}
}
Depending on the situation, you will have to choose which part you should use. mysql_num_rows() is used to check how many rows have been affected from your query you have executed. So, it's up to you to decide whether it is really necessary to add the mysql_num_rows() function in to your code or not.
I am working with a simple function that returns true when checking if a user has an appropriate account type.
function userHasType($type)
{
include $_SERVER['DOCUMENT_ROOT'] . '/pathTo/db.connection.php';
$accNum = mysqli_real_escape_string($link, $_SESSION['accountNum']);
$type = mysqli_real_escape_string($link, $type);
$sql = "SELECT COUNT(*) FROM users
INNER JOIN user_types ON users.id = userId
INNER JOIN types ON typeId = types.id
WHERE users.id = '$accNum' AND types.id='$type'";
$result = mysqli_query($link, $sql);
if (!$result)
{
$error = 'Error searching for user types.';
include 'error.html.php';
exit();
}
$row = mysqli_fetch_array($result);
if ($row[0] > 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
The function is named userHasType, i currently use this function like this:
$userHasType = userHasType('thisAccount');
.......
if ($userHasType AND whatever) {
I would like to use a statement where basically, if the user does not have a specific type, then this will happen, else something else will happen.
As in:
if (!$userHasType AND whatever) {
or im guessing this would actually work:
$userNotHasType = !userHasType('thisAccount');
.......
if ($userNotHasType AND whatever) {
Which ever way though, what is the right way to go about this... Because I have tried both and for some reason it is not reacting the way i would expect it to. It would be due to something else, but my conclusion is that both these ways must not work.
So some clarity on the matter would be much appreciated.
EDIT:
Thank You!!
if (!$userHasType) {
$prPrice = ($prPrice2 != 0 && $userIsLoggedIn ) ? $prPrice2 : $prPrice1;
} else {
$prPrice = ($prPrice2 != 0 && $userIsLoggedIn ) ? $prPrice2Incl2PIncl : $prPrice1Incl2PIncl;
}
Yes you CAN use the ! operator in front of a function call and you will get the boolean negative of the function call's return value, and you can do the same to a variable.
Looking at your function code, it seems to me that type.id might be an integer, rather than a string-type value such as a varchar or text. What does the database show as the type for the column id in the types table?
As mentioned by Polynomial, I suggest you avoid using AND. && is usually a better choice when you are dealing with normal precedence situations.
About the use of variables; I think it is good practice to minimize the use of extra variables when reasonable. Of course IMHO this decision is subject to the amount of use the variable has. I suggest sticking with:
if (!$userHasType && whatever) {
or if you do not use $userHasType anywhere else then just go ahead and use the function call in-line:
if (!userHasType('thisAccount') && whatever) {
I want to make my own function which performs in a similar manner to the following actual code.. ie
if(mysql_num_rows($res) == FALSE) {
// DO SOMETHING BECAUSE THERE ARE NO RESULTS
}
In my code, i'm repeating an SQL statement a few times around the place, and if there are results, then I go ahead and do stuff.
What I'd like to do is create my own FALSE return in my own function ie
if(my_special_function($variable) == FALSE) {
// DO STUFF
}
Is this as simple as in my special function having something like...
function my_special_function($variable) {
$sql = 'SELECT field FROM table WHERE something=$variable';
$res = mysql_query($sql);
if(mysql_num_rows($res) == FALSE) {
return FALSE;
} else {
return TRUE;
}
}
?
You can make your special function even simpler:
function my_special_function($variable)
{
$sql = "SELECT field FROM table WHERE something='{$variable}'";
$res = mysql_query($sql);
return mysql_num_rows($res) > 0;
}
Yes, that is all for a function. Why don't you try such things first before asking whether it works or not?
You should add additional error checking for mysql_query and replace $sql = 'SELECT field FROM table WHERE something=$variable'; by:
$sql = 'SELECT field FROM table WHERE something='.$variable;
I'd revise it a bit
function my_special_function($variable) {
$sql = "SELECT field FROM table WHERE something=$variable";
$res = mysql_query($sql);
if(mysql_num_rows($res)) {
return TRUE;
}
return FALSE;
}
Changes
No need for the else { ... } as if the if evaluation is true, it won't go any further, if it isn't, then FALSE is returned.
Changed the if statement to if(mysql_num_rows($res)) as mysql_num_rows() will return FALSE on failure, and a number on everything else. So, if there's 0 affected rows, or an error you won't get the return TRUE.
Inside your $sql variable you had single quotes, the literal $variable would be passed rather than what was passed to the function
I can see a few problems.
Variable interpolation does not happen in single quotes, also its advisable to not to substitute variable directly into queries.
$sql = 'SELECT field FROM table WHERE something=$variable';
should be
$sql = 'SELECT field FROM table WHERE something='.mysql_real_escape_string($variable);
mysql_num_rows returns false when there is a problem, say when its parameter is not a valid resource. If you really want to check the case of "no rows returned" you need to check its value for 0