my code looks like this (just a example, at a few parts of my projekt there are a lot of variables more then in this example):
$pdo = new PDO('mysql:host=localhost;dbname=nameofdb;charset=utf8','dbuser','dbpass');
$surname = htmlspecialchars($_POST["surname"]);
$lastname = htmlspecialchars($_POST["lastname"]);
$street = htmlspecialchars($_POST["street"]);
$username = htmlspecialchars($_POST["username"]);
$sql = $pdo->prepare("UPDATE customer SET surname = ?,lastname = ?,street = ? WHERE username = ?");
$sql->execute(array($surname, $lastname, $street,$username));
$pdo->close();
$sql->close();
All POST variables come from forms that users can(must) fill out, so it is important that it is as safe as possible.
Sorry for this (maybe) beginner question(s), but i'm new in the PDO game, still read a lot but want to see what you people say to that code.
Please tell me what i can optimize, and above all WHY, so i can learn!
Related
I tried to fetch results from database with mysqli prepared statements and I wanted to store it in session, but I failed. I want to store id, username, password and mail to session. Can anyone review my code?
$kveri = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$kveri->bind_param('ss', $username, $password);
$kveri->execute();
$kveri->store_result();
$numrows = $kveri->num_rows;
if ( $numrows == 1 )
{
$kveri->bind_result($user_id, $user_username, $user_password, $user_mail);
while ( $kveri->fetch() )
{
$_SESSION['ulogovan'] = true;
$_SESSION['username'] = $user_username;
}
$kveri->close();
echo $_SESSION['username'];
}
Make sure you have turned on error reporting as follows:
mysqli_report(MYSQLI_REPORT_ALL);
You are likely to get the answer there. I ran your code flawlessly and it should work.
Note, I added the following code to the beginning to test (with constants defined but not shown here):
$mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASS,DB_NAME);
As you can see, mysqli is quite inconvenient, if used as is. Thousand tricks, nuances and pitfalls.
To make database interactions feasible, one have to use some sort of higher level abstraction, which will undertake all the repeated dirty job.
Out of such abstractions PDO seems most conventional one:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
$user = $stmt->fetch();
if ($user) {
$_SESSION['username'] = $user['username'];
}
see - when used wisely, a code not necessarily have to be of the size of "War and Peace"
This register form was made by me, but it doesn't do what I want it to do.
I want it to connect to a mysql database and store the information that was given by the form. I want it to hash the $password in md5 and store it in the "gebruikers" table. Please don't reply with "Damn, you have no idea what you are doing" or something like that. I am learning PHP by looking to examples and following tutorials. Please keep in mind that the mysql insert code is not filled in right, because I got stuck a few lines above.
So, my question is: I want to check if the mysql table already contains $email. If it IS already in the mysql table, I want to display an error message that I can place somewhere else in my PHP page. If the email adress given is unique, than the $password should hash into md5 and store into the mysql database, just like the other form entries.
How do I do that?
<?php
// Fetching all the form details
$email = $_POST["email"];
$password = $_POST["password"];
$voornaam = $_POST["voornaam"];
$tussenvoegsel = $_POST["tussenvoegsel"];
$achternaam = $_POST["achternaam"];
$dag = $_POST["dag"];
$maand = $_POST["maand"];
$jaar = $_POST["voornaam"];
$straat = $_POST["straat"];
$postcode = $_POST["postcode"];
$woonplaats = $_POST["woonplaats"];
$cniveau = $_POST["cniveau"];
$oniveau = $_POST["oniveau"];
$voornaam = $_POST["voornaam"];
$aboutme = $_POST["aboutme"];
//Here's where I don't know how to continue
$check = mysql_query("SELECT * FROM `gebruikers` WHERE `email` = '$email'");
if($check === FALSE) {
//there is a user already registered
echo("$email is al in gebruik. <a href='login.php'>Inloggen</a>?");
} else {
//There isn't a username
//mysql_query("INSERT INTO `user` (`id` ,`username` ,`password`) VALUES (NULL , '{$_POST['email']}', MD5( '{$_POST['password']}' ))");
echo("You have been registered!");
}
P.S.: I'm not a native English speaker, so please ignore my grammar mistakes/typos.
First of all, you made a major mistake: There is a SQL-Injection security hole.
Please read this: http://php.net/manual/en/security.database.sql-injection.php
Second, you should use mysqli instead of mysql, because mysql is deprecated.
Your error is that SQL does only return false if the query is invalid, not if there are no results. So the correct way of checking if there are results is to use http://php.net/manual/en/mysqli-result.num-rows.php
$result = mysql_query("SELECT * FROM `gebruikers` WHERE `email` = '$email' LIMIT 1");
if(mysql_fetch_array($result) !== false)
{
...
} else {
....
}
You should also read up on preventing SQL injection.
Maybe you've forgot to set the mysql_connect statement.
But I strongly recommend you stick from now on, with the mysqli_ functionality, since, as Aragon0 said, mysql is deprecated in PHP's newest versions.
Besides, mysqli statements are simpler than the mysql ones, for example you use one statement (mysqli_connect) to connect to your host and select your database at the same time, instead of using separated statements (both mysql_connect and mysql_select_db).
Oh, and no additional service package is required to use it. :)
I've been looking around and can't find a place that is showing me an effective way to do this. Currently I have a query that runs when the user submits a form:
$query = "UPDATE user SET username='$_POST[username]',
nicename='$_POST[nicename]',
email='$_POST[email]',
password=(SHA1)'$_POST[password]',
position='$_POST[position]',
race='$_POST[race]',
type='$_POST[type]' WHERE username=$_SESSION[admin_login]";
I'm not sure on how to get this to actually work correctly. Sorry if it's been asked before, but I can't find a good solution to this anywhere. Thanks in advance for any help.
First of all entire thing is wrong : Why?
Because first of all you need to sanitize the input, which you are not doing, atleast you should use mysqli_real_escape_string like this :
$nicename = mysqli_real_escape_string($connect, $_POST['nicename']);
Reference
Secondly you should encrypt the password before you use it in your query like assign your encrypted password to a variable and than use it in your query, like this :
$hashed_pass = sha1($_POST['password']);
//Query goes here
and last but not the least instead of using super global $_SESSION variable directly in your query, use concatenate it.. like this
WHERE username='".$_SESSION[admin_login]."'";
Firstly, always remember Little Bobby Tables. Inserting data like that can lead to SQL injection attacks just like in that cartoon. I'd highly suggest you use prepared statements, this is a feature in both PDO and MySQLi which are methods of reading and writing to a database using PHP, some info on: PDO and some info on: MySQLi.
Whichever you choose to go with doesn't really matter, it's more about personal preference. I like PDO, so here's an example of binding the data and then executing your query using PDO:
$dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$password = sha1($_POST[password]);
$stmt = $dbh->prepare("UPDATE user SET username = :username, nicename = :nicename, email = :email, password = :password, position = :position, race = :race, type = :type WHERE = :username");
$stmt->bindParam(':username', $_POST['username']);
$stmt->bindParam(':nicename', $_POST['nicename']);
$stmt->bindParam(':email', $_POST['email']);
$stmt->bindParam(':password', $password);
$stmt->bindParam(':position', $_POST['position']);
$stmt->bindParam(':race', $_POST['race']);
$stmt->bindParam(':type', $_POST['type']);
$stmt->bindParam(':username', $_SESSION['admin_login']);
$stmt->execute();
$_POST and $_GET arrays can contain dangerous data, so you need prepare data from these arrays before inserting them into DB.
First, you need typecast values to right data types. In PHP you can use followed constructions: (string) for string data, (int) and (float) for numeric data, (bool) for boolean data.
Field email necessary checked for valid email, use Regex for it.
Follow code is sample of checking data:
<?php
$link = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
$username = mysqli_real_escape_string($link, (string) $_POST['username']);
$nicename = mysqli_real_escape_string($link, (string) $_POST['nicename']);
$email = mysqli_real_escape_string($link, (string) $_POST['email']);
$email = preg_replace( '/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*#[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$/', $email );
$password = sha1((string) $_POST['password']);
$position = mysqli_real_escape_string($link, (string) $_POST['position']);
$race = mysqli_real_escape_string($link, (string) $_POST['race']);
$type = mysqli_real_escape_string($link, (string) $_POST['type']);
$admin = $_SESSION['admin_login'];
$query = "UPDATE `user`
SET `username`='$username',
`nicename`='$nicename',
`email`='$email',
`password`='$password',
`position`='$position',
`race`='$race',
`type`='$type'
WHERE `username`='$admin'";
mysqli_query($link, $query);
mysqli_close($link);
I can't figure out why the password isn't matching when attempting to login after activation. I've trimmed down the pasted code below for ease of viewing.
Here is the relevant registration code:
$salt = substr(sha1(uniqid(rand(),true)),0,20);
$password_db = hash('sha256', $salt.$password1);
$sqlinfo = mysql_query("INSERT INTO db_1 (email, password, salt)
VALUES('$email1','$password_db','$salt')") or die(mysql_error());
Here is the correlating code for login:
$email = $_POST['email'];
$password = $_POST['password'];
$sqlinfo = mysql_query("SELECT * FROM db_1 WHERE email='$email' AND emailactiv='1'");
if($sqlinfo['password'] == hash('sha256', $sqlinfo['salt'].$password)){
while($row = mysql_fetch_array($sqlinfo)){
... }
else { ...
I've done several iterations thus far to no avail. Any insight would be much appreciated.
you code, currently, is vulnerable with SQL injection. One suggestion is to reformat your code using PDO or MySQLI.
Example of PDO:
<?php
$stmt = $dbh->prepare("SELECT * FROM db_1 WHERE email = ? AND emailactiv=? ");
$stmt->bindParam(1, $email);
$stmt->bindParam(2, 1);
$stmt->execute();
?>
you didn't fetch the row that's why it's not matching anything.
add this line before the IF statement:
$rowHere = mysql_fetch_row($sqlinfo);
and use $rowHere in your IF statement.
$email = $_POST['email'];
$password = $_POST['password'];
$sqlinfo = mysql_query("SELECT * FROM db_1 WHERE email='$email' AND emailactiv='1'");
//You need to first fetch data before using it.
while($result = mysql_fetch_array($sqlinfo)) {
//Now you can use the data
if($result['password'] == hash('sha256', $result['salt'].$password)){
//matched... login correct
} else {
//not matched.. invalid login
}
}
...
Hope it's self-explanatory.
You missed one very important line!
BTW, stop using mysql_* functions as they are deprecated, use PDO or mysqli_*
EDIT: Please try now. I thought it can only hold one value (for login purpose)
You need to use mysqli_fetch_array.
Also, mysql_* functions are deprecated. Use MySQLi or PDO instead.
And you need to 'sanitize your inputs' (a common phrase) to avoid SQL injection, using mysqli_real_escape_string or PDO.
See the Bobby Tables link as per the comments on the question.
This is my code to update a table. My problem is that after submitting a fresh record I'm unable to update the first time (it shows blank), but the second time it works fine.
One more thing: when I remove the include statement then it is working fine on submessage.php there is no any phpcode. [annakata: I have no idea what this means]
$pid = $_GET['id'];
$title = $_POST['title'];
$summary = $_POST['summary'];
$content = $_POST['content'];
$catid = $_POST['cid'];
$author = $_POST['author'];
$keyword = $_POST['keyword'];
$result1= mysql_query("update listing set catid='$catid',title='$title',
summary='$summary',content='$content', author='$author', keyword='$keyword' where pid='$pid'",$db);
include("submessage.php");
The things that are wrong with that piece of code are hard to enumerate. However, at the very least, you should establish a connection to the database before you can query it.
Why not just redirect to submessage.php rather than inlining it? Redirecting also prevents duplicate db operations when user refreshed the page. Just replace include statement with:
header('Location: submessage.php?id=' . $pid);
die();
Also, before you deploy your application: DO NOT EVER PUT USER INPUT DIRECTLY IN SQL QUERY. You should used bound parameters instead. Otherwise, you could just as well publicly advertise your database admin password. Read more on PDO and prepared statements at http://ie.php.net/pdo
Here's how I would do it:
$pdo = new PDO(....); // some configuration parameters needed
$sql = "
UPDATE listing SET
catid=:catid, title=:title, summary=:summary,
content=:content, author=:author, keyword=:keyword
WHERE pid=:pid
";
$stmt = $pdo->prepare($sql);
$stmt->bindValue('catid', $_POST['catid']);
$stmt->bindValue('title', $_POST['title']);
$stmt->bindValue('summary', $_POST['summary']);
$stmt->bindValue('content', $_POST['content']);
$stmt->bindValue('author', $_POST['author']);
$stmt->bindValue('keyword', $_POST['keyword']);
$stmt->bindValue('pid', $pid = $_GET['id']);
$stmt->execute();
header('Location: submessage.php?id=' . $pid);
die();
Or in fact, I would use some ORM solution to make it look more like that:
$listing = Listing::getById($pid = $_GET['id']);
$listing->populate($_POST);
$listing->save();
header('Location: submessage.php?id=' . $pid);
die();
Other than the usual warnings of SQL injection - very likely given your code and where you're obtaining the query parameters from (sans any kind of validation) - then it's quite possible your problem has nothing to do with the queries, particularly if it's working on subsequent attempts. Are you sure $_GET['id'] is set the first time you call the script?
Just to note, there is absolutely no reason to have to perform several update queries for each field you need to update - just combine them into a single query.