I'm making an iOS app that sends a username string to this PHP file and then the PHP file checks to see if their username exists in a database, in a table called "members". I got this code online and modified it a little to fit my needs. This is the code:
// Main method to redeem a code
function redeem() {
// Check for required parameters
if (isset($_POST["username"])) {
// Put parameters into local variables
$code = $_POST["username"];
echo $code;
// Look up code in database
$user_id = 0;
echo "userid";
$stmt = $this->db->prepare('SELECT username FROM members WHERE username=', $code);
echo "dbprepare";
$stmt->bind_param("is", $code);
echo "bindparam";
$stmt->execute();
echo "execute";
$stmt->bind_result($id, $code);
echo "bindresult";
while ($stmt->fetch()) {
break;
}
$stmt->close();
The code is tripping up on bind_param, it only gets to echo "dbprepare". Am I doing something incorrectly? How do I check for the username?
try this code
$stmt = $this->db->prepare('SELECT username FROM members WHERE username=?');
echo "dbprepare";
$stmt->bind_param("s", $code);
I would guess you do miss an actual placeholder here:
$stmt = $this->db->prepare('SELECT username FROM members WHERE username=?', $code);
See the added ?. The prepare call does not just append the value.
You do need to tell it where it belongs. (If your class implements prepare/bind as in mysqli or PDO, and as commonly understood.)
You forgot to add a ? in your SQL.
$stmt = $this->db->prepare('SELECT username FROM members WHERE username=?', $code);
echo "dbprepare";
$stmt->bind_param("is", $code);
Related
I have numerous statements on my website and I was wondering when and how you use $stmt->close(); correctly. Would it open vulnerabilities by leaving it open?
In this example, would the correct place to close the statement be line 23?
// First, check if the email and code exists
if (isset($_GET['email'], $_GET['code'])) {
if ($stmt = $con->prepare('SELECT * FROM accounts WHERE email = ? AND activation_code = ?')) {
$stmt->bind_param('ss', $_GET['email'], $_GET['code']);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
// Account exists with the requested email and code
if ($stmt = $con->prepare('UPDATE accounts SET activation_code = ? WHERE email = ? AND activation_code = ?')) {
// Set the new activation code to 'activated', this is how we can check if the user has activated their account
$newcode = 'activated';
$stmt->bind_param('sss', $newcode, $_GET['email'], $_GET['code']);
$stmt->execute();
header('Location: messages.php?message=activated');
exit;
}
} else {
header('Location: messages.php?message=activated-error');
exit;
}
}
}
There are two statements here, would I close both? Or do I just close them both at the bottom? Also, as I am using header('Location:') does the $stmt->close(); actually get executed?
You do not need to use $stmt->close(); at all. You almost never need to close anything manually in PHP. PHP will close it for you once it is no longer needed. If you structure your code properly, PHP will close everything for you when it is most optimal.
Using header('Location:') doesn't affect mysqli objects. When you exit the code, the whole script stops and that is when PHP will close everything if it hasn't been closed yet.
You really should use some encapsulation. Don't use mysqli methods directly. Create some function or class which will abstract from this interface and it will be easier for you to use it. If you do it properly, then you do not need to worry at all about closing the objects.
I'm developing a login/register form for my client. Right now I am working on the registration part of the form however I seem to have encountered an issue.
I am trying to append the user's input to a database if it does not currently exist. I'm developing this functionality using PHP version 7. However, the code does not seem to append the data to the database even when telling me it has done so successfully.
Here is code:
<?php
if($_SERVER["REQUEST_METHOD"] == "POST") {
//define variables and set values to null
$email = $code = "";
//set variable values to HTML input
$email = $_POST['email'];
$code = $_POST['code'];
//check if email exists
$stmt = $conn->prepare("SELECT userEmail FROM userDetails WHERE userEmail=?");
$stmt->bind_param("s", $prepemail);
//set parameters and execute
$prepemail = $email;
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo "email exists";
return false;
} else {
//$stmt->close(); removed as per #Akintunde-Rotimi's suggestion
//insert email into database
$stmt = $conn->prepare("INSERT INTO userDetails (userEmail) VALUES (?)");
$stmt->bind_param("s", $newemail);
//set parameters and execute
$newemail = $email;
$stmt->execute();
echo "New records created successfully";
}
}
?>
The code successfully connects to the database and even tells me if the user already exists. It just doesn't add the user's email to the database and I can't seem to figure out why.
I have researched methods on how to insert the data into the database using prepared statements as I have done here. I've used W3Schools as a reference but still no luck.
The code doesn't seem to have any obvious spelling errors, so have you tried to catch errors? Replace
$stmt->execute();
with
if(!$stmt->execute()) {
trigger_error("there was an error....".$conn->error, E_USER_WARNING);
}
You can also check how many rows are affected, -1 meaning there was an error.
printf("%d Zeile eingefügt.\n", $stmt->affected_rows);
Also, enabling more errors to be shown (at least for development)
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// ...
I've done a login and registration for my site and it works fine.
Now I just want to make a simple profile page where the user can see all their details.
I'm only able to get back the username, so I'm unsure how to get the rest of their details.
Here is the code for registering and logging in:
function selectUser($conn, $username, $password)
{
$query = "SELECT password FROM login WHERE username = :username";
$stmt = $conn->prepare($query);
$stmt->bindValue(':username', $username);
$stmt->execute();
if ($row = $stmt->fetch(PDO::FETCH_OBJ))
{
if (md5($password) == $row->password)
{
$_SESSION['username'] = $username;
//$_SESSION['password'] = $password; DO NOT DO THIS
echo "Welcome, you are now logged in as " . $username;
return true;
}
return false;
} else {
//echo "Your details were not found";
return false;
}
}
function selectNew($conn, $name, $username, $password, $contact, $occupation, $role, $picture)
{
$query = "INSERT INTO login VALUES (NULL, :name, :username, :password, :contactNumber, :occupation, :role, :pic)";
$stmt = $conn->prepare($query);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':username', $username);
$stmt->bindValue(':password', $password);
$stmt->bindValue(':contactNumber', $contact);
$stmt->bindValue(':occupation', $occupation);
$stmt->bindValue(':role', $role);
$stmt->bindValue(':pic', $picture);
$affected_rows = $stmt->execute();
if ($affected_rows == 1)
{
return true;
} else {
return false;
}
}
Don't worry, the password has been hashed.
heres what I've tried:
function selectUser($conn, $username, $password)
{
$query = "SELECT * FROM login WHERE username = :username";
$stmt = $conn->prepare($query);
$stmt->bindValue(':username', $username);
$stmt->execute();
$row = $stmt->fetch();
echo $row['occupation'];
echo $row['role'];
}
2nd attempt:
if(isset($_SESSION["username"]))
{
echo "Welcome, you are now logged in as <b>".$_SESSION['username']."</b> <img class='clientView' src='images/loginIcon.png' alt='client'>"; }
else {
echo "You are currently not logged in";
}
$user = $_SESSION["username"];
$query = "SELECT * FROM login WHERE username = :username";
$term = $conn->prepare($query);
$term->bindValue(':username', $user);
$term->execute();
if ($username = $term->fetch(PDO::FETCH_OBJ))
{
echo "<li><h3>" . $user->username ." ". $user->user_ID . "</h3></li>";
}
The simple answer is to replace your query in selectUser(...) with SELECT * FROM login WHERE username = :username. Note the * after the SELECT command, which functions as a wild card and thus asks for every single column of each row it finds (instead of just the password column as you are currently asking for.
You could then, as you iterate over the returned rows, access other columns of the user via your $row variable. Just like you access the user's hashed password with $row->password, you could access $row->contactNumber.
A note about good practice:
Depending on the case, I would not recommend doing a wildcard (*) SELECT command at login. In fact, I would recommend simply hashing the password prior to the query and attempting to then qualify your query with WHERE username = :username AND password = :password (obviously, bind the hashed password to :password). Instead of asking for the password column, or wildcard columns, you could SELECT the row's unique ID.
This way, you don't even need to iterate over the returned rows at all...you only have to make sure any row returned (see num_rows) to see if the user can be successfully "logged in". You can then cache the returned row's unique ID into your session, and then do subsequent queries as necessary for other pieces of information...such as the user's role or contact number. This effectively brings the complexity of all of your query processing down from linear time to constant time...a minor, but still non-trivial, improvement for an application.
Also, as a word of warning, this login system is very simple and easily spoofed. PHP sessions provide some security, but they are not full-proof. A sniffer snagging the session cookie will allow them to log in as the user whom they sniffed it from. I would recommend looking into adding in your own session layer as well once you have the rest of your login system implemented. And absolutely use SSL.
A note about optimization:
Using a wildcard (*) in a SELECT command is actually a prime place for a speed bottleneck to occur. If you know exactly what columns you want from the database, it is best to ask for them explicitly. For example, instead of *, you could do password,occupation,role.
$_SESSION['username'] = $username;
You have user name in session right.
Just pass this value in where condition of mysql .and get the entire record from login table .just show where ever you want to show.
You can change your SELECT statement to return the other values you want to store in your $_SESSION variables and then access them each with $row->{variable}
Just make sure you populate the $_SESSION after you do your password check
Not dissimilar to your existing code - use the session variable you set when the user logs in
$username=!empty( $_SESSION['username'] ) ? $_SESSION['username'] : false;
$sql='select * from `login` where `username`=:username;';
$stmt=$conn->prepare( $sql );
if( $stmt && $username ){
$stmt->bindValue(':username',$username);
$result=$stmt->execute();
if( $result ){
$rs=$stmt->fetchAll( PDO::FETCH_OBJ );
/* display results from $rs */
/*
There should most likely only be one record!!
*/
$row=$rs[0];
foreach( $row as $column => $value )echo $column.' '.$value;
}
}
I'm trying to recall data from database to post later on
When someone logs in using this code:
function login($email, $password, $mysqli)
{
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, salt, phnumber, realname, age, sex FROM members WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $username, $db_password, $salt, $phnumber, $realname, $age, $sex);
$stmt->fetch();
}
}
Then I set variables for email and name using this code:
$realname = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $realname);
$_SESSION['realname'] = $realname;
$email = preg_replace("/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/", "", $email);
$_SESSION['email'] = $email;
Then when I recall all the variables using print_r($_SESSION); The email is posted without # or . for example: johnsmithyahoocom and also the name is posted without space like JohnSmith Which is undesirable. How can I make it post the right email form and space between names?
Why are you using preg_replace?
And I would recommend, if you are already using a database, to store only the users ID in the SESSION and fetch the other data from the database, when you need the users Information.
Sorry for wasting your time on this
Everything was going fine I just had to relogin to apply changes I made
/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/ is working fine and recalls the right email form from database I just had to restart the SESSION to see changed I made.
I'm new to PHP and made a simple php site that allows me to submit a form and delete data stored in a database. I was told it was better to use prepared statements to avoid SQL Injection.
I updated my delete and it still works, not sure if it's totally right:
<?php
include("dbconnect.php");
$getid = $_GET["id"];
$delete = mysqli_prepare($database,"DELETE FROM contacts WHERE id IN ($getid)");
mysqli_stmt_execute($delete);
header("Location:http://localhost/address-book");
exit;
?>
But I can't seem to get the add to database feature to work. I tried a variety of different ways to write it, but I'm sure that I'm missing something simple. Here's the unsafe code that I originally wrote:
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
include("inc/dbconnect.php");
// assigns form data to table columns
$assign = "INSERT INTO contacts(firstName,lastName,email,phone,birthday) VALUES ('$_POST[firstName]','$_POST[lastName]','$_POST[email]','$_POST[phone]','$_POST[birthday]')";
//execute query
if (mysqli_query($database,$assign)) {
header("Location:http://localhost/address-book/");
exit;
} else {
exit;
}
?>
If someone could guide me in the right direction I'd be thankful. I'm new to all of this.
UPDATED: I've updated my original code and came up with this instead for delete:
<?php
include("dbconnect.php");
$getid = $_GET["id"];
$delete = mysqli_prepare($database,"DELETE FROM contacts WHERE id IN (?)");
mysqli_stmt_bind_param($delete, 's', $getid);
mysqli_stmt_execute($delete);
header("Location:http://localhost/address-book");
exit;
?>
and the add feature:
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
include("inc/dbconnect.php");
$firstName = "$_POST[firstName]";
$lastName = "$_POST[lastName]";
$email = "$_POST[email]";
$phone = "$_POST[phone]";
// assigns form data to table columns
$assign = mysqli_prepare($database,"INSERT INTO contacts(firstName,lastName,email,phone) VALUES (?,?,?,?)");
mysqli_stmt_bind_param($assign, 'ssss', $firstName, $lastName, $email, $phone);
mysqli_stmt_execute($assign);
exit;
}
?>
A simple Prepare statement is something along the lines of
$query = $this->db->prepare("Query here WHERE something = ?") - note this example is taken from my site so you'll likely have something else instead of $this->->prepare.
The key thing is that the "= something " is denoted as a question mark.
You then bind the value of that question mark to the query
$query->bindValue(1, passed in parameter)
As a fully working example:
//function to add 1 to downloads each time a file is downloaded
public function addToDownload($filename){
$query = $this->db->prepare('UPDATE trainingMaterial SET downloads = downloads + 1 WHERE filename = ?');
$query->bindValue(1, $filename);
try{
$query->execute();
}catch(PDOException $e){
die($e->getMessage());
}
}
Your query `$assign = "INSERT INTO contacts(firstName,lastName,email,phone,birthday) VALUES ('$_POST[firstName]','$_POST[lastName]','$_POST[email]','$_POST[phone]','$_POST[birthday]')";
would be
$assign = "INSERT INTO contacts(firstName,lastName,email,phone,birthday) VALUES ?,?,?,?,?)";
$assign->bindValue(1, '$_POST[firstName]')
$assign->bindValue(2, '$_POST[lastName]')
etc etc