Perl, SQL, DBI: Why doesn't my UPDATE function work? Code and things I've tried inside - mysql

UPDATE 2: I never found the solution to this. Since the instructor's code is readily available for us to use and hack together with our own, and I'd already wasted weeks trying to debug, I just created a new table and started from his code, made changes and tested as I went, until I ended up with that I wanted in functionality. If anyone every comes across a reason for the odd behavior, I'd sincerely appreciate knowing what caused this.
Almost everyone who suggested anything offered up ideas I had already tried, and listed as already tried, in my original post. Thank you to everyone offering their insight, but please do read posts completely before making suggestions.
UPDATE: to present my main question more clearly. The original post is below that with all code, as well as what I've tried.
I designed my updateData() function to update a record. Instead, it returns its error code.
sub updateData {
# and this returns "Update Failed!" for me. I can't figure out why.
$sql = "UPDATE friendface SET first_name = '$first_name',
last_name = '$last_name',
email_address = '$email_address',
password = '$password'
WHERE user_id = $user_id;";
$rc = $dbh->do($sql);
if ($rc != 1) {
print "Update Failed!";
}
}
Ninja editing as I reread through this mess 3:
Code at the bottom. Sorry if the formatting is awful or I'm not descriptive enough. I really tried. Ask if I can provide anything else that is helpful.
Hi everyone,
School assignment here, print a table with records you can edit and delete.
I've got an HTML page with forms for inserting data, then a perl script that displays the table with buttons to update and delete. Delete works fine. The whole script works fine (EXCEPT the link from the block of text you get when you access the .pl directly, but I don't care about that at the moment) without the contents of my UPDATE function. The code for the UPDATE function works fine line by line in MySQL. But I can't get the updateData function with the UPDATE query to work in my .pl file.
We're allowed full access to the instructor's example code. I COULD start with his page, then modify it into my own page. I'd rather be able to write my own page without relying on that crutch. I am, however, comparing my code to his and I don't see where I'm going wrong. Syntax looks good, as far as I know / can find docs for.
I played with varying syntax anyway just in case. Put a comma after the final record before my WHERE clause because it looked wrong without, but apparently without is the way to go. Everything I read says the current syntax is correct.
I thought maybe it was trying to edit a user_id that didn't exist, but printing the user_id showed it was using the correct one.
I think my DBI->connect is working because it doesn't return Connection Failed.
The correct function, updateData(), is running because the final output is the Update Failed return code, unique to that function.
I can trace the code through Edit button > Edit form > Confirm Edit function > updateData function > $dbh authenticates successfully, do($sql), which is my UPDATE query, which looks syntactically correct. But for some reason, $dbh->do($sql); doesn't come out true.
In the updateData function, I thought I'd make sure the problem wasn't that I was only updating 4 of the 6 fields. Well, 5, since the key isn't ever going to be updated. Anyway, I thought that might be tripping it up somehow, but adding a line to update username didn't help, so I took it out again.
I've really been trying to figure this out on my own and I'm pulling my hair out. It's always some dumb little thing. Is it spacing? It usually doesn't matter, but I know ENDFORM had to be the first, and only, thing on the line in order to work for me. But I don't know of any spacing rules for this particular code. Please. Point me in the right direction.
Just to be explicit, printEditButton() and printDeleteButton() are the code for the edit and delete buttons...
DESC table, code for the html page, and the pl script follows:
*********************
*********************
***DESC friendface***
*********************
*********************
Field Type Null Key Default Extra
user_id int(11) NO PRI NULL auto_increment
username char(50) YES NULL
first_name char(20) YES NULL
last_name char(20) YES NULL
email_address char(50) YES NULL
password char(50) YES NULL
*********************
*********************
*friendFaceForm.html*
*********************
*********************
<table bgcolor='antiquewhite' align=center cellpadding=2>
<form action='friendFaceForm.pl' method=GET>
<tr>
<td align=right>Username</td>
<td><input type=text name=username></td>
</tr>
<tr>
<td align=right>First Name</td>
<td><input type=text name=first_name></td>
</tr>
<tr>
<td align=right>Last Name</td>
<td><input type=text name=last_name></td>
</tr>
<tr>
<td align=right>Email Address</td>
<td><input type=text name=email_address></td>
</tr>
<tr>
<td align=right>Password</td>
<td><input type=text name=password></td>
</tr>
<tr>
<td align=center colspan=2> <input type=submit name=action value='Insert Data'></td>
</tr>
</form>
</table>
*********************
*********************
**friendFaceForm.pl**
*********************
*********************
#!/usr/bin/perl
use CGI qw(:standard);
use DBI;
use warnings;
print "Content-type: text/html\n\n";
$dbh = DBI->connect("DBI:mysql:jwiard1:localhost", "jwiard1", "jwiard1")
or endProgram("Connection Failed!");
$action = param('action');
$user_id = param('user_id');
$username = param('username');
$first_name = param('first_name');
$last_name = param('last_name');
$email_address = param('email_address');
$password = param('password');
if ($action eq 'Insert Data') {
#$action holds this value coming from the html page
#this happens first
insertData();
printTable();
}
elsif ($action eq 'Edit') {
#prints the edit form
printEditForm();
}
elsif ($action eq 'Confirm Edit') {
#then updateData() runs
updateData();
printTable();
}
elsif ($action eq 'Delete') {
deleteData();
printTable();
}
elsif ($action eq 'Print Table') {
printTable();
}
else {
print "Either you are accessing this file directly or \$action has an unaccounted for value.<br><br>
If it's the former, get out of here!<br><br>
If it's the latter... you're getting sleepy. You're getting verrrry sleepy. When you reach the end of this sentence, you'll wake up with no memory of this page and a strong feeling that Joe Wiard's code is perfect.<br><br>
...or did you just want to see the table?";
print "<input type=submit name=action value='Print Table'>";
}
####
#Functions! Yay!
####
sub endProgram {
my ($msg) = #_;
print $msg;
die();
}
sub insertData {
#after inserting data, the user is left to click Edit or Delete
#making $action hold the value of 'Edit' or 'Delete' Go to elsif($action eq 'Edit'
print "Your data has been saved.";
$sql = "INSERT INTO friendface SET user_id='$user_id',
username='$username',
first_name='$first_name',
last_name='$last_name',
email_address='$email_address',
password='$password' ;";
$rc = $dbh->do($sql);
if ($rc != 1) {
print "Insert failed!";
}
}
sub printEditButton {
print "<form>";
print "<input type=hidden name=user_id value='$href->{user_id}'>";
print "<input type=submit name=action value='Edit'>";
print "</form>";
}
sub printDeleteButton {
print "<form>";
print "<input type=hidden name=user_id value='$href->{user_id}'>";
print "<input type=submit name=action value='Delete'>";
print "</form>";
}
sub confirmEdit {
}
sub lookUpRow {
$sql = "SELECT * FROM friendface WHERE user_id=$user_id;";
$sth = $dbh->prepare($sql);
$rc = $sth->execute();
$href = $sth->fetchrow_hashref();
}
sub printEditForm {
#prints fields for 4 of the values in a record. I don't want the user to be able to
#change their username. They can only edit first and last names, email and password.
#after this, $action either holds 'Confirm Edit' or 'Cancel'. Go to elsif
#($action'Confirm Edit')
lookUpRow();
print <<ENDOFFORM;
<form>
First Name: <input type=text name=first_name value='$href->{first_name}'> <br>
Last Name: <input type=text name=last_name value='$href->{last_name}'> <br>
Email Address: <input type=text name=email_address value='$href->{email_address}'> <br>
Password: <input type=text name=password value='$href->{password}'> <br>
<input type=hidden name=user_id value=$href->{user_id}'> <br>
<input type=submit value="Confirm Edit" name=action>
<input type=submit value="Cancel" name=action>
</form>
ENDOFFORM
#It seems that ENDOFFORM *MUST* be at the beginning of the line. No TABS or SPACES
#preceeding, and NOTHING after. Half an hour of debugging lead me to discovery this
#tidbit that I should have just remembered from class. Or Googled. :P
}
sub updateData {
#and this returns "Update Failed!" for me. I can't figure out why.
$sql = "UPDATE friendface SET first_name = '$first_name',
last_name = '$last_name',
email_address = '$email_address',
password = '$password'
WHERE user_id = $user_id ;";
$rc = $dbh->do($sql);
if ($rc != 1) {
print "Update Failed!";
}
}
sub deleteData {
$sql = "DELETE FROM friendface WHERE user_id = $user_id;";
$rc = $dbh->do($sql);
}
sub printTable {
$sql = "SELECT * FROM friendface;";
$sth = $dbh->prepare($sql);
$rc = $sth->execute();
$count = 0;
print "<table>";
#print header
while ($href = $sth->fetchrow_hashref() ) {
$count ++;
if ($count % 2 == 0) {
print "<tr bgcolor=lightblue>";
}
else {
print "<tr bgcolor=lightgray>";
}
print "<td>";
print $href->{'user_id'};
print "</td>";
print "<td>";
print $href->{'username'};
print "</td>";
print "<td>";
print $href->{'first_name'};
print "</td>";
print "<td>";
print $href->{'last_name'};
print "</td>";
print "<td>";
print $href->{'email_address'};
print "</td>";
print "<td>";
print $href->{'password'};
print "</td>";
print "<td>";
printEditButton();
print "</td>";
print "<td>";
printDeleteButton();
print "</td>";
print "</tr>";
}
print "</table>";

From the DBI documentation, it seems that the "do" method does some magic with the return value:
do
If you're doing an UPDATE, INSERT, or DELETE there is no data that
comes back from the database, so there is a short cut. You can say
$dbh->do('DELETE FROM people WHERE age > 65'); for example, and DBI
will prepare the statement, execute it, and finish it. do returns a
true value if it succeeded, and a false value if it failed. Actually,
if it succeeds it returns the number of affected rows. In the example
it would return the number of rows that were actually deleted. (DBI
plays a magic trick so that the value it turns is true even when it is
0. This is bizarre, because 0 is usually false in Perl. But it's convenient because you can use it either as a number or as a
true-or-false success code, and it works both ways.)
Are you sure the update didn't work? Perform a select afterward to double-check. It could just be that you're misinterpreting the return code.

Related

Perl/HTML Basic Login

So I have a University assignment where I must have authenticated users login to edit a text file. I'm trying to contain this all within the one CGI file to keep it easy.
I've written a html form as shown below:
Admin Login:
<form name="login" method="post" action="pbr.cgi"><input type="text" name="user" value="Username" onfocus="(this.value == 'Username') && (this.value = '')"onblur="(this.value == '') && (this.value = 'Username')"/>
<input type="password" name="password" value="123456" onfocus="(this.value == '123456') && (this.value = '')"onblur="(this.value == '') && (this.value = '123456')"/>
<input class="login" name="Login" type="submit" value="Login"></form>
I also have a login sub in the cgi as below:
sub Login {
$luser = $cgi->param('user');
$lpass = $cgi->param('password');
open (PASSWD, "<passwords.txt");
my #passwds = <PASSWD>;
close (PASSWD);
foreach (#passwds){
($user, $pass, $passsalt) = split ":";
if ($user = $luser){
$testpass = $salt . $lpass;
$testpass = sha256_hex($testpass);
if ($pass = $testpass){
$validuser = 1;
} else {
$validuser = 0;
}
} else {
print "Failure!"
}
}
}
Can someone explain to me how I get the CGI to recognise the login button has been pressed and subsequently execute the Login sub while reloading the page? Obviously I'll have to set a cookie as well once I get this working but I just want to get it working first.
The CGI module you're (obviously) using also supports fetching the parameter list as a hash. You should try to dump this out to the see complete request:
print Dumper($cgi->Vars);
You'll notice that the Login button is a <input ...> tag like the others and behaves exactly the same way: By setting a parameter defined by the name= and value= properties.
Three additional remarks on your script:
if ($user = $luser){ says: Try to copy the value of $luser into the variable $user. If this succeeds and the new value of $user is true (not undef, empty or 0), run the following lines until end of the if block. = is an assignment in Perl, while == and eq are comparisons. See http://perldoc.perl.org/perlop.html#Equality-Operators for more information.
The better way of reading a file is using while (<FILEHANDLE>) { ... }. Your solution read the full file into memory even if the first line matches the user trying to login. while reads line-by-line until you exit the loop.
Consider running PerlCritic on your sourcecode. It doesn't check for errors, but shows best practice hints where the Perl community prefers some other way. Don't try to "fix" every critic report, but check them to improve your code.

Check if entry is available in database

I have generated a 10 digit number, added it to a database after purchase.
Now I want to make a php page to give users an input box, ask them to enter the 10 digit number, and click submit. After you click submit it should return if the pin is used or has not been used it. (Used if its not available - Not used if its in the table)
I got the following code:
<?php
require_once 'db.php';
function validated_pin($pin)
{
$pin = mysql_real_escape_string($pin); // SECURITY!
$result = mysql_query("SELECT pins FROM pins WHERE pin='$pin' LIMIT 1");
if (mysql_fetch_row($result)) {
return 'This pin has already been used';
} else {
return 'This pin is available for use';
}
}
echo '<html><center>
<form action="' . $_SERVER['SCRIPT_NAME'] . '" method="post">
<table style="border:0px solid black;">
<tr>
<td>PIN*:</td><td><input type="text" name="pin" value="" class="bginput"/></td>
</tr>
<tr>
<td></td><td><input type="submit" id ="submit" name="submit1" value="Check Pin>>" class="button"></td>
</tr>
</table>';
echo validated_pin($pin);
echo '</center></html>';
?>
And PHPmyAdmin looks like this:
http://gyazo.com/67c3df7171c83c677cb221c04d644ed7.png
It's located in _donation and in table name pins
I don't know whats going on tried looking everywhere
The current code will return this error
Warning: mysql_fetch_row() expects parameter 1 to be resource, boolean given in /home/website/public_html/directory/example.php on line 8
Your query is failing to fetch data, resulting in false returned.
Firstly - you should catch this false value and not assume $result has data.
Secondly - var_dump() the query you are running, run that in PhpMyAdmin
Your query is-
$result = mysql_query("SELECT pins FROM pins WHERE pin='$pin' LIMIT 1");
shouldn't it be
$result = mysql_query("SELECT pin FROM pins WHERE pin='$pin' LIMIT 1");
pin is the column name right? not pins
if (mysql_fetch_row($result)) {
if(mysql_num_rows($result)>0)
return 'This pin has already been used';
else
return 'This pin is available for use';
}
This seemed to have solved it:
$pin = $_POST["pin"];
function validated_pin($pin)
{
$pin = mysql_real_escape_string($pin); // SECURITY!
$result = mysql_query("SELECT pin FROM pins WHERE pin='$pin' LIMIT 1");
if(mysql_num_rows($result) == 0) {
return 'This pin has already been used';
} else {
return 'This pin is available for use';
}
}
Still facing the issue of it saying "Already been used" before I execute any code.

PHP login issues

I am creating a login which links to a database, when entering information the login then runs a blank page and does nothing, below is my code:
include "conn.php";
session_start();
$email_address = $_POST['email_address'];
$password = $_POST['password'];
if ($email_address && $password)
{
$connect = mysql_connect("computing","i7906890","password") or die ("couldn't connect!");
mysql_select_db("i7906890") or die ("couldn't find database");
$guery = mysql_query("SELECT * FROM UserAccount WHERE email_address = '$email_address'");
if ($numrows!=0) {
//code to login
while ($row = mysql_fetch_assoc($query)) //Password Check
{
$dbemail_address = $row['email_address']
$dbpassword = $row['password']
}
//Check if they match
if ($email_address==$dbemail_address&&$password==$dbpassword)
{
echo "You're in! <a href='user_page.php'>click</a> here to enter the members page";
$_SESSION['user']==$dbemail_address;
}
else
echo "Incorrect Password!";
}
else
die("That user doesn't exist!");
}
else
die("Please enter an email address and password!");
?>
Also here is my form
<form action = "login2.php" method ="POST">
<p><img src="images/space.gif" width="70px" height="1px"/><strong>Log in</strong> or <strong>Register</strong><br>
Email:<img src="images/space.gif" width="34px" height="1px"/><input type="text" name="user" size="33"> <br>
Password:<img src="images/space.gif" width="10px" height="1px"/><input type="password" name="password" size="33"> <br>
<div align="center">
<input type="submit" value="Log in" class="button">
</div>
</p>
</form>
Please help! SOS
You're missing a few ; in your code which is causing the script to crap out and not display anything. (Specifically in the while loop but check elsewhere as well.)
Edit: You may also want to consider losing that while loop all together and putting the password criteria in the SQL statement for better performance. And like the other poster said, watch out for SQL injection.
Please help! SOS Yep, you're in deep sh... But not for what you'd expect...
Even if your code was operating well, you are the 5th or 6th who asks roughly the same question, riddled with SQL injection in a PHP login form using the deprecated mysql_ functions...
And also, $guery is not the same as $query... Check for the q and g letters...
This line:
$guery = mysql_query("SELECT * FROM UserAccount WHERE email_address = '$email_address'");
Should be at least
$query = mysql_query("SELECT * FROM UserAccount WHERE email_address = '".mysql_real_escape($email_address)."'");
to both be correct, and avoid injection...
But you should really be using prepared statements through PDO, like this:
try {
//open connection, this is different than in the old functions
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
//***running query
//**step1: create statement
$stmt = $dbh->prepare('SELECT * FROM UserAccount WHERE email_address = :email'); //notice parameter prefixed with ':'
//**step2: bind values (be sure to also check out the bindParameter() function too!)
$stmt->bindValue(':email', $email_address);
//**step3: exexcute statement
$stmt->execute();
//**step4: process results
$result = $stmt->fetch(PDO::FETCH_OBJ);
if($result->PASSWORD==$password) {
//logged in, do whatever reuqired
}
$dbh = null; //don't let it slip out of our hands
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
Also, another word of caution: don't store plaintext passwords. Even storing MD5 hashes is out of scope these days, and SHA1 is also declared to be weak...

mysql_fetch_array fails sometimes

I'm trying to implement the connection to a online payment framework.
One of the files is giving me some trouble, because sometimes the code works, sometimes it doesn't... And I can't understand why...
Here's where the code is failing...
$sql = "select transidmerchant,totalamount from nsiapay where transidmerchant='".$order_number."'and trxstatus='Verified'";
$result = mysql_query($sql);
**$checkout = mysql_fetch_array($result);**
echo "sql : ".$sql;
$hasil=$checkout['transidmerchant'];
echo "hasil: ".$hasil;
$amount=$checkout['totalamount'];
echo "amount: ".$amount;
// Custom Field
if (!$hasil) {
echo 'Stop1';
} else {
if ($status=="Success") {}
}
It's just part of the code but I think it's enough for you to try to see the problem... It fails on the bold line, $checkout = mysql_fetch_array($result);
The weird thing is that the "echo sql" works, and it shows the right values, but then when I put them on the array, sometimes the variables are passed, sometimes they're not... And so, when getting to if (!$hasil) it fails because the value is empty... but sometimes it works...
Any ideas on what might be happen?
Thans
Luis
The only way this fail is when query doesn't return anything.
The correct way would be to check if there is something returned:
$sql = "select transidmerchant,totalamount from nsiapay where transidmerchant='".$order_number."'and trxstatus='Verified'";
$result = mysql_query($sql);
if($checkout = mysql_fetch_array($result)){
$hasil = $checkout['transidmerchant'];
echo "hasil: ".$hasil;
$amount=$checkout['totalamount'];
echo "amount: ".$amount;
// Custom Field
if (!$hasil) {
echo 'Stop1';
} else {
if ($status=="Success") {}
}
}else{
echo "Empty query result";
}

Update Database Not Working

Can anyone tell me why this isn't working? Everything comes up fine but when I hit submit it doesn't update the database.
$row = mysql_fetch_array($sql);
$title = $row['title'];
$content = $row['content'];
$author = $row['author'];
$author_email = $row['author_email'];
$cat = $row['category'];
$date = $row['date'];
$id = $row['id'];
$form = "<tr><td>$id
<form action='edit.php' method='post'>
<input type='text' value='$title' name='title'><br>
<textarea name='content'>$content</textarea><br>
<input type='submit' name='submit'>
</td></tr>";
$ptitle = htmlentities($_POST['title']);
$pcontent = htmlentities($_POST['content']);
if($_POST['submit']){
if ($ptitle && $pcontent){
mysql_query("UPDATE blogdata SET id='$id', title='$ptitle', author='$author', author_email='$author_email', date='$date', category='$category', content='$pcontent' WHERE id='$id'");
}
else
echo "A forms empty.";
}
else
echo "$form";
Note first that you should not be using the values that have been submitted directly from the form without first validating them. I will not address that here, but I will address your query:
You cannot set the value of the row identifier that you plan to use in your WHERE clause; this causes a concurrency problem. Your row identifier should be immutable.
Thus, your query should look like this (reminder: I have not fixed the security related issues):
UPDATE blogdata SET title='$ptitle', author='$author',
author_email='$author_email', date='$date', category='$category',
content='$pcontent' WHERE id='$id'
Because its badly written code with bugs in it?
You should use htmlentities to escape content you are writing to the browser. You should use mysql_real_escape_string to escape content you are writing to the database. Your code should have comments in it explaining what it does. You should check the return value for mysql_query and poll mysql_error when appropriate. You shouldn't quote numeric values in your SQL.