So I am grabbing the amount of rows in a specific table where the username is already in the database like so:
$second_sql = $db->prepare("SELECT * FROM users WHERE username = :username");
$second_sql->bindParam(':username', $username);
$second_sql->execute();
if($second_sql->rowCount() == 1) {
$db = null;
header("Location: ../login/");
} else {
$statement->execute();
$db = null;
}
The problem is it's not working. If you need more of the script just tell me.
Some databases does not report the row count with PDO->rowCount() method.
SQLite, for instance.
So don't use rowCount(); doing so makes your code less portable.
Instead use the COUNT(*) function in your query, and store the result in a variable.
Finally, use that variable to fetch the one and only column (users) using the fetchColumn() method.
So you can play with this:
try {
$second_sql = $db->prepare("SELECT COUNT(*) from users WHERE username = :username");
$second_sql->bindParam(':username', $username, PDO::PARAM_STR);
$second_sql->execute();
$count = $second_sql->fetchColumn();
} catch (PDOException $e) {
// Here you can log your error
// or send an email
// Never echo this exception on production
// Only on development fase
echo "Error: " . $e->getMessage();
}
if ($count) {
$db = null;
header("Location: ../login/");
} else {
$statement->execute();
$db = null;
}
Perhaps you wanna test you condition for a single row:
if ($count == 1)
Hope this helps you.
Cheers!
Related
I'm making a function that i have to check if a userid is in this table already: if not he has to get into another page yet. But for some reason I get "NULL" back instead of the number of the userID.
my class:
public function countHobbies($userID){
try{
$conn = Db::getConnection();
$statement = $conn->prepare("select * from hobby where userID = '".$userID."'");
$userID = $this->getUserID();
$statement->execute();
$aantal = $statement->fetchAll(PDO::FETCH_ASSOC); //
$aantal->execute();
}
catch(throwable $e){
$error = "Something went wrong";
}
}
and this is on my html page:
$userArray = $_SESSION['user_id'];
$userID = implode(" ", $userArray);
$hobby = new Hobby();
$count = $hobby->countHobbies($userID);
if($count == false){
echo "no";
//header('Location: hobby.php');
}
else{
echo "yes";
}
There are at least two things you need to fix:
Always use parameter binding on the SQL statement. It may not be a security problem in this particular instance, but do get into the habit of using prepared statements. Because otherwise you'll find yourself in situations where you should've but didn't. https://www.php.net/manual/en/security.database.sql-injection.php
The $userID variable must be assigned before it is used.
In the end, it could look like this:
$userID = $this->getUserID();
$statement = $conn->prepare("select * from hobby where userID = ?");
$statement->bind_param("s", $userID);
I'm trying to create a system, where my website generates an unique code (current date + 5 random characters) and that code is transferred to a table in my database.
Before function generateNumber() can insert the unique code into the database, it has to check if the code already exist in the database.
If the code doesn't exist, my function works flawlessly. But the problem is when the code can already be found on the database, my website just doesn't do anything (it should just re-run the function).
function generateNumber()
{
global $conn;
$rand = strtoupper(substr(uniqid(sha1(time())),0,5));
$result = date("Ydm") . $rand;
$SQL = $conn->query("SELECT code FROM test WHERE code='$result'");
$c = $SQL->fetch(PDO::FETCH_ASSOC);
if ($c['code'] > 0) { // test if $result is already in the database
generateNumber();
} else {
$sql2 = "INSERT INTO test (code) VALUES (?)";
$stmt2 = $conn->prepare($sql2);
$stmt2->execute([$result]);
return $result;
}
}
try {
$conn = new PDO("sqlite:db"/*, $username, $password*/);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo generateNumber();
}
catch(PDOException $e) {
echo "Error:" . $e->getMessage();
}
$conn = null;
?>
There are no error messages in the console, but I suspect the problem is this part of the code:
if ($c['code'] > 0) { // test if $result is already in the database
generateNumber();
}
Any idea how I can write this function in a better way?
Solution :
if ($c['code'] > 0) { // test if $result is already in the database
// if the code exists in db the function return nothing
// because you are missing a return :
return generateNumber();
}
try {$db=mysqli_connect( etc )
catch {
retry on time out
handle errors
}
try { if (!($errors = $db->prepare("insert into errors (`insert`,`error`) values(?,?);
print "\n*********prepare Error:" . $db->error;
}
}
catch { repeat above}
try {$errors->bind_param("ss",$sqlLoad,$errormsg); }
catch {repeat above)
....
try {$error->execute()} catch {repeat above error handling}
Now repeat all of that 10-40 times for different SQL queries on different fields.
That is a lot of duplicated code. Make my code hard to read, and if someone wants to add more sql queries they are forced to reduplicate large blocks of code.
I was thinking something like this but ran into a stumbling block with bind.
$sql[0]=array("name","select ? from <tablename>","s");
$sql[1]=array("name","select ?,? from <tablename>","ss");
$sql[2]=array("name","select ?,?,? from <tablename>","sss");
$sql[3]=array("name","select ?,?,?,? from <tablename>","ssss");
for(i=0;i<=3,i++){
try (
$preQuery[$sql[i][0]=$db->prepare($sql[i][1]);}
catch {}
try {$preQuery[$sql[i][0]]->bind_param($sql[i][2],????);} //Here is the trouble how do I define unique variables
catch { }
}
Here is some real code
It is a work in progress
foreach ($fieldspath as $field)
{
$filepath=$_SERVER[$field];
$result=$queryfile->execute();
$getres = $queryfile->get_result();
$numRows = -1;
$numRows = $getres->num_rows;
if ($numRows <>0)
{
$qryField = $getres->fetch_assoc();
$_SERVER[$field]=$qryField["id"];
$fileCount=$qryField["count"];
$fileRating=$qryField["rating"];
mysqli_query($db, "update Files set count=count+1 where `id` ='" . $qryField["id"] . "';");
continue;
}
else
{
$output = $insertFile->execute();
$result = $queryip->execute();
$getres = $queryip->get_result();
$qryField = $getres->fetch_assoc();
$_SERVER[$field]=$qryField["id"];
}
}
Notice: How I can re-execute a query just by:
$result=$queryfile->execute();
The query doesn't have to be re-stated, nor do the parameters. Everything is automatic. The actual queries are all listed at the top of the program, and I never have to see them, or restate them ever again. Also I don't need to cram my parameters into array before I can use them.
<?php
$pipeName = '/var/run/mysql/mysql.sock';
$username = 'user';
$password = 'password';
$db = new PDO('mysql:unix_socket='.$pipeName.";dbname=dbase", $username, $password);
$sql["errors"]="insert into errors (`insert`,`error`) values(:insert,:error);";
$sql["events"]="insert into event (`message`) values(?);";
$sql["queryip"]="select id,count,rating FROM ip where address=? limit 1;";
$sql["queryUsrAgent"]="select id,count,rating FROM http_user_agent where agent=? limit 1;";
$sql["insUsrAgent"]="insert into http_user_agent (`agent`) values (?);";
$sql["insertIP"]="insert into ip (`address`) values (?);";
$sql["insertReqURI"]="insert into request (`REQUEST_URI`) values (?);";
$sql["queryReqURI"]="select * FROM request where REQUEST_URI=? LIMIT 1;";
$sql["queryfile"]="select id,count,rating FROM Files where path=? limit 1;";
$sql["insertFile"]="insert into Files (`path`) values (?);";
$sql["cntIp"]="update ip set count=count+1 where `address` = :ip";
$sql["cntFiles"]="update Files set count=count+1 where `id` = :id;";
$sql["cntAgent"]="update http_user_agent set count=count+1 where `agent` = :agent;";
$sql["reqRequest"]="select * FROM request where REQUEST_URI= :requesturi LIMIT 1;";
$sql["cntRequest"]="update request set count=count+1 where `REQUEST_URI` = :requesturi;";
$ready=doPrepare($db,$sql);
$ready["errors"]->execute(array("insert"=>"stuff","error" =>"stuff"));
pdoRun($ready,"errors",array("iniisert"=>"iiiii","error" =>"yyyyyggg"));
function doPrepare($db, $enmass) {
foreach ($enmass as $key => $sql) {
try {
$stmt[$key] = $db->prepare($sql);
} catch (PDOException $e) {
print "\nStuff";
trigger_error($e);
return false;
}
}
return $stmt;
}
function pdoRun($ready,$query,$vals) {
try {
$ready[$query]->execute($vals);
} catch (PDOException $e) {
print "\nExecution fail";
}
}
// $stmt->execute(array_values($column_values));
?>
Making prepared queries like you are doing doesn't work like you seem to think it does. The parameter placeholders can only substitute for literal values. You can't use them for column names or table names or anything else.
You also can't prepare a query like "select ? from" because it names no table. It's not a syntactically complete query.
The better practice is to code a "helper function" that does the prepare and execute for you. You can reduce repetitive code that way.
By the way, I find PDO is much easier than Mysqli when coding a helper function like this, because you don't have to use the bind_param() with variable arguments. In PDO, you just pass an array of arguments to execute().
function doInsert($db, $sql, $params) {
try {
$stmt = $db->prepare($sql);
$stmt->execute($params);
} catch (PDOException $e) {
trigger_error($e);
return false;
}
return true;
}
Now call it this way:
$sql = "insert into errors (`insert`, `error`) values(?, ?)";
$success = doInsert($db, $sql, [$sqlLoad, $errormsg]);
You might even like the function to format your INSERT statement for you:
function doInsert($db, $table, $column_values) {
$placeholders = array_fill(1, count($column_values), '?');
$columns = implode(',', array_keys($column_values));
$sql = "INSERT INTO `$table` ($columns) VALUES ($placeholders)";
try {
$stmt = $db->prepare($sql);
$stmt->execute(array_values($column_values));
} catch (PDOException $e) {
trigger_error($e);
return false;
}
return true;
}
Then call it like this:
$success = doInsert($db, "errors", ["insert"=>$sqlLoad, "error"=>$errormsg]);
You'll have to do something to apply back-ticks to the column names too.
What is the best way to validate if a record was inserted successfully?
I'm using PDO Statements.
This:
/*******************
Update user picture
********************/
function updateuserpicture($userid, $filename) {
include ("./businesslogic/dbconnection/cfg.php");
try {
$db = new PDO('mysql:host='.$server.';dbname='.$db,$db_user,$db_password);
$sql = $db->prepare("Update usersdata set userpicture=:filename where userid=:userid");
$sql->bindParam(':filename',$filename);
$sql->bindParam(':userid',$userid);
$sql->execute();
$sqlresult = $sql->rowCount();
$db = null;
return $sqlresult; //Then validate if result is greater than 0.
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
}
}
or this:
/*******************
Update user picture
********************/
function updateuserpicture($userid, $filename) {
include ("./businesslogic/dbconnection/cfg.php");
try {
$db = new PDO('mysql:host='.$server.';dbname='.$db,$db_user,$db_password);
$sql = $db->prepare("Update usersdata set userpicture=:filename where userid=:userid");
$sql->bindParam(':filename',$filename);
$sql->bindParam(':userid',$userid);
if ($sql->execute()) {
$db = null;
return TRUE;
} else {
$db = null;
return FALSE;
} //Then validate if result is TRUE or FALSE.
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
}
}
Both ways works fine but im not sure what is the best, can you please help me?
PDO won't actually throw exceptions unless you tell it to. So your try..catch is entirely superfluous and will never do anything.
If the statement was executed without error, that means the data was inserted/updated successfully. No need to count rows, unless you are interested in the specific details of how many rows were altered (which is a different topic than "is the data in my database now?").
Given this, I'd recommend to set PDO to throw exceptions in case of errors and not do any further explicit checking:
$db = new PDO("mysql:host=$server;dbname=$db", $db_user, $db_password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = $db->prepare('UPDATE users SET userpicture = :filename WHERE userid = :userid');
$sql->bindParam(':filename', $filename);
$sql->bindParam(':userid', $userid);
$sql->execute();
This may still mean that the statement did nothing if the user id didn't exist. This would point to a deeper bug in your app, it's questionable if the PDO code should care about it specifically.
Problem is that if I update all users at one time the points row updates. But if I updating it by username row wont updating. I don't know why.
foreach($points as $p) {
$p = $p['points'] - $bet;
$username = $_SESSION['username'];
$q = $pdo -> prepare("UPDATE users SET points = '$p', username = '$username' ");
$q->execute();
}
without 'username = $username' all users updates perfectly.
Try:
try {
$q = $pdo->prepare("UPDATE users SET points = ? WHERE username = ?");
$q->execute(array($p, $username));
} catch(Exception $e) {
echo $e->getMessage();
die();
}
Or:
try {
$q = $pdo->prepare("UPDATE users SET points = :p WHERE username = :username");
$q->bindParam(':p', $p);
$q->bindParam(':username', $username);
$q->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
}
I haven't tested it, but I think that should work.
Check out the site.
WHERE username = 'username' or else with that lack of code, all rows are getting updated and that could be either planned or disaster.
As points is an integer, you should NOT use quotes around the variable, as it will be interpreted as a string, thus failing. So the correct syntax would be:
"UPDATE users SET points = {$p}, username = '{$username}'"