1

I am creating a very simple registration form in php, currently when the user tries to register there will popup a javascript alert with a succes or fail message.

Now I want to catch the sql exception to show if the username or email already excists in the database instead of a standard fail message.

This is the code I have so far:

if(isset($_POST['btn-signup']))
{
  $uname = mysql_real_escape_string($_POST['uname']);
  $email = mysql_real_escape_string($_POST['email']);
  $upass = md5(mysql_real_escape_string($_POST['pass']));

  if(mysql_query("INSERT INTO user(username,password,email) VALUES('$uname','$upass','$email')"))
{
?>
    <script>alert('successfully registered ');</script>
<?php
}
else{
?>
    <script>alert('error while registering you...');</script>
<?php
 }
}
?>

How can I check if the email or username already excists in the database? Both variable's are already unique in the database.

Lesley Peters
  • 243
  • 4
  • 18
  • 5
    Please don't use `md5()` for passwords, especially if they're unsalted. – ʰᵈˑ Jul 04 '16 at 15:43
  • 3
    **WARNING:** The `mysql_*` API is deprecated and dropped as of PHP7.0.0. Consider using [`mysqli`](http://php.net/mysqli) or [`pdo`](http://php.net/pdo) and binding your parameters. – ʰᵈˑ Jul 04 '16 at 15:44
  • Thanks for the information, didn't know about that. – Lesley Peters Jul 04 '16 at 15:51
  • Out of pure curiosity, because there are a **LOT** of SO questions regarding Deprecated varients of MySQL, how did you hear / start learning about MySQL @LesleyPeters? I'm just curious how you didn't hear about it's end-of-life status... – Martin Jul 04 '16 at 15:53
  • Before you `INSERT` it, simply perform a `SELECT` query and check the number of rows returned. `SELECT * FROM user WHERE username='$uname' OR email='$email'` – Qirel Jul 04 '16 at 15:54
  • @Martin I copied the code from this tutorial: http://www.codingcage.com/2015/01/user-registration-and-login-script-using-php-mysql.html I should've checked the date of creation. – Lesley Peters Jul 04 '16 at 15:55
  • @Qirel I don't want 2 queries while the database can return an exception for me. If there are about 10 million records in that table, I don't want to check them all before inserting a new one. – Lesley Peters Jul 04 '16 at 15:56
  • @LesleyPeters hmmm, the issue is more the code writers fault than your own, the code has been deprecated for something like 3 years so the guy writing the tutorial blog in january 2015 (the website date) really should have known better..... – Martin Jul 04 '16 at 15:56
  • @Martin well, atleast you tell it now because It's an easy fix for now. Thanks for the info. – Lesley Peters Jul 04 '16 at 15:57
  • 2
    Please dont __roll your own__ password hashing. PHP provides [`password_hash()`](http://php.net/manual/en/function.password-hash.php) and [`password_verify()`](http://php.net/manual/en/function.password-verify.php) please use them, I might want to use your site one day And here are some [good ideas about passwords](https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet) If you are using a PHP version prior to 5.5 [there is a compatibility pack available here](https://github.com/ircmaxell/password_compat) – RiggsFolly Jul 04 '16 at 16:01
  • Please dont use [the `mysql_` database extension](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php), it is deprecated (gone for ever in PHP7) Specially if you are just learning PHP, spend your energies learning the `PDO` database extensions. [Start here](http://php.net/manual/en/book.pdo.php) its really pretty easy – RiggsFolly Jul 04 '16 at 16:01
  • @RiggsFolly Thanks for the alternative's for the password hashing! I also found an alternative for mysql_ I am using the first example from this website now (MySQLi Object-oriented): http://www.w3schools.com/php/php_mysql_insert.asp is this safe to use? – Lesley Peters Jul 04 '16 at 16:18
  • 1
    @LesleyPeters it's not inherently secure. Ensure you [bind your parameters](http://php.net/manual/en/mysqli-stmt.bind-param.php) at the very least. – ʰᵈˑ Jul 04 '16 at 16:19
  • @LesleyPeters MySQLi is perfectly *ok* as long as used in Prepared Statements, but the "popular" one is PDO. Only the Hipster poops like me use MySQLi (hahaha) – Martin Jul 04 '16 at 16:19
  • 1
    In addition to being weak `md5(mysql_real_escape_string(input))` is pretty weird - escape and then md5? Suggests a misunderstanding, or copy pasta. – AD7six Jul 04 '16 at 16:32

2 Answers2

2

From Comments:

I don't want 2 queries while the database can return an exception for me. If there are about 10 million records in that table, I don't want to check them all before inserting a new one.

Ok, so you have one query to insert and check is unique? So you have to INSERT on a UNIQUE_INDEX MySQL column, you can catch these sort of exceptions with the following style of answer shameless stolen from this answer to this question:

In the case of this answer we'll assume you're using PDO, because you should. Please read up about it.

// Pre-setup the database connection somewhere, usually an include (or a class)
$link = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbusername,$dbpassword);
// PDO needs to be set in Exception mode:
$link->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

//Input Processing functions.
// (entirely optional)
$uname = MyCleanerFunction($_POST['uname']);
$email = MyCleanerFunction($_POST['email']);
//please see note below re:MD5
//$upass = md5($_POST['pass']); 
$options['cost'] = 12;
$upass = password_hash($_POST['pass'],PASSWORD_BCRYPT,$options);

//now reach the code part:
    try {
        //PDO query execution goes here:

         $statement = $link->prepare("INSERT INTO user(username,password,email) VALUES(:uname, :email, :pass)"));
         $statement->bindValue(":uname", $uname);
         $statement->bindValue(":email", $email);
         $statement->bindValue(":pass", $upass);
         $statement->execute();
         //reaching here everything is ok! 
    }
    catch (\PDOException $e) {
        if ($e->errorInfo[1] == 1062) {
            // The INSERT query failed due to a key constraint violation.
            // THIS means that it failed because the Primary Key 
            // (the email) appears already in the database table.
        }
        if($e->errorInfo[1] == 9999){
          // possible other IF clauses for other errors in INSERT.
        }
    }

You would also do well to read up about catching and outputting PDO errors. As well as all about MySQL Unique Key Constraints.

  • Also very useful alternative viewpoint that you Should not catch PDO exceptions.

  • Also please note that MD5 is an extremely weak hash for storing passwords and that PHP password_hash function is the much preferred way of doing it.

  • PLEASE use Prepared Statements for your MySQL interactions, the layout above is a rough guide to how they look and is very similar for MySQLi and PDO. Prepared Statements go a long way towards securing your data from malicious user input.

Community
  • 1
  • 1
Martin
  • 19,815
  • 6
  • 53
  • 104
  • Can you make a note about using `md5()` on the password in your answer, please. – ʰᵈˑ Jul 04 '16 at 16:16
  • `MyCleanerFunction` doesn't need to exist if using bound parameters. – AD7six Jul 04 '16 at 16:31
  • Technically, no, but I personally always want to do some sort of edge-case cleaning on data as soon as I've got it. I also hope that having placeholder functions there help the OP to realise that filtering and cleaning can take place quite comfortably before writing to the `PDO` statement. – Martin Jul 04 '16 at 16:35
  • Given the code in the question, it reads like a suggestion to keep using `mysql_real_escape_string` - Be wary of sticking unmentioned code in an answer hoping the OP/reader will read into it the meaning you want. – AD7six Jul 04 '16 at 16:37
  • @AD7six I don't think it does read like that, but I have updated the answer . It's not "unintentional" code, the code is from the OPs original code and so at worst can be a reference for them to view a new layout / structure. – Martin Jul 04 '16 at 16:48
  • Thanks a lot! I've learned a lot from this piece of code, and ofcourse your explanation. The user registration and login was the only databse connection I had now, so it shouldn't be to hard to replace this all. Thanks again :) – Lesley Peters Jul 04 '16 at 16:50
  • @LesleyPeters ahh no worries, pleased I could help you. Once you're used to the syntax then Prepared Statements make the whole thing so much easier to code. – Martin Jul 04 '16 at 16:56
  • @Martin Can you give me a link, or tell me some information about the MyCleanerFunction? When I use it I'm getting an error that the function doesn't excists. When I search it on google I get less then 1 page and nothing has to do something with php or coding. – Lesley Peters Jul 04 '16 at 18:43
  • @LesleyPeters `MyCleanerFunction` is a function you make yourself in order to clean (remove unwanted characters) from the input. It's an example placeholder, that's all. If you want it, you can make it `:-)` – Martin Jul 04 '16 at 19:42
  • Ahh okay thanks, I've almost rewritten the script now into the PDO format. It was a hard and boring job to find the syntax for every query, but now I got everything, I love it! – Lesley Peters Jul 04 '16 at 20:14
-3
$con=mysqli_connect("localhost","root","","my_db");
$check="SELECT COUNT(*) FROM persons WHERE Email = '$_POST[eMailTxt]'";
if (mysqli_query($con,$check)>=1)
{
    echo "User Already in Exists<br/>";
}
else
{
    $newUser="INSERT INTO persons(Email,FirstName,LastName,PassWord) values('$_POST[eMailTxt]','$_POST[NameTxt]','$_POST[LnameTxt]','$_POST[passWordTxt]')";
    if (mysqli_query($con,$newUser))
    {
        echo "You are now registered<br/>";
    }
    else
    {
        echo "Error adding user in database<br/>";
    }
}
  • 1
    Code-only answers are discouraged. Explain your answer. – ʰᵈˑ Jul 04 '16 at 16:15
  • 2
    Also, congratulations. **Your answer gives the ability to perform a SQL injection**. Using `mysqli` isn't inherently secure. **Bind your parameters**. – ʰᵈˑ Jul 04 '16 at 16:18
  • well as you stated that checking for username for a million users will be a hectic job so instead you can check for the result count. the counting is doing two job simultaneously one for searching and other for mysqli_num_rows one. – Sarthak Pandit Jul 04 '16 at 16:24
  • well my friend it is just for understanding sql injection and other stuff are taken care with the help of built in functions or one that is created by us. – Sarthak Pandit Jul 04 '16 at 16:25
  • @SarthakPandit that isn't true. `values('$_POST[eMailTxt]'` this kind of code is dangerous, and irresponsible. – AD7six Jul 04 '16 at 16:26
  • You don't seem to understand how **1)** StackOverflow works and how to answer a question here. **2)** How insecure your code is. **3)** OPs requirements. – ʰᵈˑ Jul 04 '16 at 16:27
  • it might be true ,but my friend you are using core php and in current time frameworks are used, such as laravel and ci .which takes care about the security and other faults the answer i mentioned was just for giving rough ideas .well thankyou . – Sarthak Pandit Jul 04 '16 at 16:32
  • 1
    @SarthakPandit It is better to teach a man how to do something himself, than to teach him what to depend on. – Martin Jul 04 '16 at 16:57
  • @SarthakPandit your answer doesn't use "a framework that handles security and other faults" so your argument is moot. – ʰᵈˑ Jul 05 '16 at 10:37
  • the code i mentioned was not using any framework,it was just for giving idea about using the condition for checking that username exist or not. – Sarthak Pandit Jul 06 '16 at 04:22