Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Serious programming problem

Name: Anonymous 2011-09-21 3:13

Why does my code not work when the username does not exist? When the username doesn't exist it just gives me a blank screen. No error messages, no form, no nothing. It works as intended when the username is found but the password is incorrect and when the username/password are both correct.

Also, please don't make fun of my code. I'm sensitive and I'd like to stay that way.


<?php
$num_rows = 0;
if($_SERVER['REQUEST_METHOD'] == 'POST') {
  $uname = $_POST['username'];
  $pword = $_POST['password'];


$db_handle = mysql_connect(localhost, "admin", "1admin");
$db_found = mysql_select_db("users", $db_handle);

$result = mysql_query("SELECT * FROM logininfo WHERE username = '$uname'") or die(mysql_error());
$num_rows = mysql_num_rows($result) or die(mysql_error());;
if($num_rows > 0)
  $row = mysql_fetch_array($result) or die(mysql_error());

if($num_rows == 0) {
  echo "Username not found.";
}
else if(md5($pword) != $row['password']) {
  echo "Incorrect Password.";
}
else {
  session_start();
  echo "Success.";
  $_SESSION['login'] = "1";
  $_SESSION['username'] = $uname;
  echo '<META HTTP-EQUIV="Refresh" Content="3; URL=index.php">';   
  exit; 
}
}
?>


<FORM NAME ="form1" METHOD ="POST" ACTION ="login.php">

Username: <INPUT TYPE = 'TEXT' Name ='username'  value="<?PHP print $uname;?>" maxlength="20">
Password: <INPUT TYPE = 'TEXT' Name ='password'  value="<?PHP print $pword;?>" maxlength="16">

<P>
<INPUT TYPE = "Submit" Name = "Submit1"  VALUE = "Login">


</FORM>

Name: Anonymous 2011-09-21 14:07

Here's what you do, OP. Don't use the mysql_* functions.

What I'm about to suggest sounds like "a lot more work". But this is currently the best and easiest way to interact with databases in PHP, and it addresses a lot of the issues you'll experience when doing things "the old way": insecure queries, spaghetti code, unportability, problems maintaining when you encounter a seemingly unrelated bug when you make a change in the future.

What you want to do is use PDO (http://www.php.net/manual/en/pdo.connections.php) and "prepared statements" (http://www.php.net/manual/en/pdostatement.fetchall.php).

You create a PDO object that represents a connection to your database.

$db = new PDO('mysql:host=example.com;dbname=exampledb', 'exampleuser', 'examplepassword');

With this object, you can run raw queries:

$db->query('DROP TABLE tablename');

...but, more importantly, you can prepare statements:

$sth = $db->prepare('SELECT * FROM clients');

This creates a PDOStatement object that represents a query, which now encapsulates a command you can run on your SQL server. You can execute that command with $sth->execute();. You can get a result with $sth->fetch(), or you can get an array of all the results with $sth->fetchAll().

Why is this helpful? Because you separate your SQL commands from the data you're using in those commands. The query is only parsed once, and it can then be used again and again, like any function that takes arguments. That's right: you can pass arguments with placeholders. Like:

$sth = $db->prepare('SELECT * FROM clients WHERE firstname = ? AND lastname = ?');
$sth->execute(array('John', 'Smith'));
$result = $sth->fetchAll();


Or, to be even more clear:

$sth = $db->prepare('SELECT * FROM clients WHERE email = :email AND website = :website');
$sth->execute(array(':email' => 'example@gmail.com', ':website' => $whatever));
$result = $sth->fetchAll();


You can also specify how you want the value returned:

$associative = $sth->fetch(PDO::FETCH_ASSOC);
$object = $sth->fetch(PDO::FETCH_OBJ);


You can get really specific:

class File {
    private $filename;
    function __construct()
    {
        if (isset($this->filename)) {
            echo "The filename property was automatically set by PDO, based on the name of the column given to the query (even though it's private). It's {$this->filename}.\n";
        }  
        if (isset($this->name)) {
            echo "The name property was also set, even though I didn't explicitly define it as a property of this class. It's {$this->name}, and it was attached to this instance as a public member. \n";
        }
    }
}
$sth = $db->prepare('
SELECT  id,
        filename,
        name
FROM files
WHERE filename LIKE :filetype
ORDER BY sequence ASC
');
$sth->bindValue(':filetype', '%.pdf');
$sth->execute();
// these flags will organize the result array as a lookup table:
// $files[$id] = new File();
$pdfs = $sth->fetchAll( PDO::FETCH_UNIQUE | PDO::FETCH_GROUP | PDO::FETCH_CLASS, 'File' );


Arguably the best side effect to this system is that your queries will be much more secure incidentally, since you are treating your SQL commands as distinct from data. Any arguments you pass to a PDOStatement through bindValue, bindParam, or execute() will be escaped as needed, and won't be parsed as SQL, without you remembering to have to do anything silly like mysql_real_escape_string() (what? real? Okay).

(Which is not to say that you shouldn't still think about security precautions -- people can still pass raw HTML, for example, if you let them, for XSS attacks -- but that's a topic for another day.)

Good luck, and in the future, take your questions to StackOverflow. This board is strictly for discussion about Lisp dialects, and other symptoms of autism.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List