I've tried searching forums for a solution, however most of the answers were either too difficult to understand. SO I'm in the process of making a website for a small community, and currently we have our database and html design layout, but I'm getting snagged on how to push my Perl CGI form into another Perl program to then alter my database.
Here is the Perl controller that alters the database tables (and it works):
#!/usr/bin/perl -w
#!/usr/bin/perl -wT
# DBI is the standard database interface for Perl
# DBD is the Perl module that we use to connect to the <a href=http://mysql.com/>MySQL</a> database
use DBI;
use DBD::mysql;
use warnings;
#----------------------------------------------------------------------
# open the accessDB file to retrieve the database name, host name, user name and password
open(ACCESS_INFO, "accessDB.txt") || die "Can't access login credentials";
# assign the values in the accessDB file to the variables
my $database = <ACCESS_INFO>;
my $host = <ACCESS_INFO>;
my $userid = <ACCESS_INFO>;
my $passwd = <ACCESS_INFO>;
my $tablename = "Article";
# the chomp() function will remove any newline character from the end of a string
chomp ($database, $host, $userid, $passwd);
# close the accessDB file
close(ACCESS_INFO);
#----------------------------------------------------------------------
# invoke the ConnectToMySQL sub-routine to make the database connection
$connection = ConnectToMySql($database);
if ($tablename == "Article"){
$connection = InsertArticle($database);
}
elsif ($tablename == "Category"){
$connection = InsertCategory($database);
}
elsif ($tablename == "Comment"){
$connection = InsertComment($database);
}
elsif ($tablename == "User"){
$connection = InsertUser($database);
}
else {
print "No such table found. Contact website administrator.\n"
}
sub InsertArticle{
$query = "insert into $tablename (Id, CategoryId, UserId, Title, Content) values(?, ?, ?, ?, ?)";
$statement = $connection->prepare($query);
$statement->execute('undef', '1', '1029', 'Dota2>League', 'textfromarticle');
}
sub InsertCategory{
$query = "insert into $tablename (Id, CategoryId, UserId, Title, Content) values(?, ?, ?, ?, ?)";
$statement = $connection->prepare($query);
$statement->execute('undef', '1', '1029', 'Dota2>League', 'textfromarticle');
}
sub InsertComment{
$query = "insert into $tablename (Id, CategoryId, UserId, Title, Content) values(?, ?, ?, ?, ?)";
$statement = $connection->prepare($query);
$statement->execute('undef', '1', '1029', 'Dota2>League', 'textfromarticle');
}
sub InsertUser{
$query = "insert into $tablename (Id, CategoryId, UserId, Title, Content) values(?, ?, ?, ?, ?)";
$statement = $connection->prepare($query);
$statement->execute('undef', '1', '1029', 'Dota2>League', 'textfromarticle');
}
exit;
#--- start sub-routine ------------------------------------------------
sub ConnectToMySql {
#----------------------------------------------------------------------
my ($db) = #_;
# assign the values to your connection variable
my $connectionInfo="dbi:mysql:$db;$host";
# make connection to database
my $l_connection = DBI->connect($connectionInfo,$userid,$passwd);
# the value of this connection is returned by the sub-routine
return $l_connection;
}
#--- end sub-routine --------------------------------------------------
In the future, I'll define the other tables in my database through global variables that depend on what button the user presses on the correct webpage. As in, if they're viewing a list of articles, an option at the top would be "submit an article". And from there, the form CGI would be sent to them that they can fill out.
And here is the CGI that makes the form that would be submitted to the above controller script to alter the table:
#!/usr/bin/perl
#!/usr/bin/perl -wT
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser); #remove this in production
my $q = new CGI;
print $q->header; #Content-Type: text/html; charset=ISO-8859-1
print $q->start_html(
-title => 'submit an Article', #page name
-style => {'src' => '/dmrwebsite/dmrwebsite/userinterface'}, #link to style sheet
);
print $q->start_form(
-name => 'submitting an Article',
-method => 'POST',
enctype => &CGI::URL_ENCODED,
-onsubmit => 'return true',
-action => '/dmrwebsite/dmrwebsite/controller.addtotable.pl',
);
print $q-.textfield(
-name => 'title',
-value => 'default value',
-required,
-size => 20,
-maxlength =>50,
);
print $q->textarea(
-name => 'content',
-value => 'default value',
-required,
-maxlength => 1000,
-cols => 60,
);
print $q->textarea(
-name => 'url',
-value => 'default value',
maxlength => 100,
cols =>60,
);
print $q-checkbox(
-name => 'humancheck',
-checked => 1,
-value => 'two',
-label => 'The number two',
);
print $q-submit(
-name => 'submit_Article',
-value => 'submit Article',
-onsumbit => 'javascript: validate_form()',
);
if ($q->param()) {
submit_form($q);
} else {
print "Please check your form for inaccuracies.";
}
sub submit_form($){
my ($q) = #_;
}
print $q->end_form; #ends the form html
print $q->end_html; #end the html document
So basically what I'm stuck at is understand how to send the form data to the perl script in which I can then define the table data in my $tablename = "Article"; and $statement->execute('undef', '1', '1029', 'Dota2>League', 'textfromarticle');.
Also, I don't have a javascript program to send to the parameter -onsubmit => javaapplication(),. Is that needed? Can I substitute my own Perl program to check the user inputted fields? And how would I call this function? IN the same file or can it just be in the parent directory like /website/perlchecker.pl?
Any help would be greatly appreciated as I'm only a couple days into using Perl let alone CGI and html. Got a couple people helping me on the front end of the website though.
Thanks,
-Ori
So many suggestions...
Firstly, your DB insertion program seems to just insert fixed data, so I'm not sure how you think that it works. Also, the if ($tablename == "Article") (and similar) line doesn't do what you want it to. You need to use eq instead of ==.
To answer the question that you asked - you need to change your database program so that it accepts input (probably command line arguments) containing the data that you want inserted into the database. You would then add to your CGI program a line that calls this program (probably using system()) passing it the data from the CGI parameters on the command line.
The code would look something like this:
my $title = $q->param('title');
my $content = $q->param('title');
# ... other params ...
system('db_script.pl', 'Article', $title, $content, ...)';
But please don't do that. That's a terrible idea.
Instead, I highly recommend that you re-write your database manipulation program as a module. That way, you can load the module into any program that needs to talk to the database and access the database by calling functions rather than by calling an external program. If it was down to me, then I'd definitely use DBIx::Class to produce this library - but I realise that might well be seen as rather advanced.
Then there's the elephant in the room. You're still using CGI to write your web interface. The CGI module has been removed from the latest version of Perl as it is no longer considered best practice for writing web applications. I recommend looking at CGI::Alternatives to find out about other, more modern, tools.
But if you're determined to carry on writing your program as a CGI program, then at the very least, please don't use the HTML generation functions. We've known that including your HTML in your program source code is a terrible idea for at least fifteen years. There's no reason to still be doing it in 2015. You should really be using some kind of templating engine to separate your HTML from your Perl code. I recommend the Template Toolkit.
I'm not sure where you are learning these techniques from, but your source seems to be a good ten years behind accepted best practice.
I am trying to fetch data from table. Table contains the data and query is true. Even why following query says $u and $t are not define. While condition becoming false.
I manually checked in database, it was showing results.
$url = "http://paulgraham.com/";
$user_id = "123";
$con = mysqli_connect('127.0.0.1', 'root', '', 'mysql');
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
return;
}
$result = mysqli_query($con,"SELECT * FROM post_data WHERE userid =".$url." and url=".$user_id."");
while ($row = #mysqli_fetch_array($result))
{
echo "hi";
$t = $row['title'];
$u = $row['url'];
}
echo "title is : $t";
echo "url is : $u";
Giving your SQL query :
"SELECT * FROM post_data WHERE userid =".$url." and url=".$user_id.""
You can see you are mixing url and userid... Change to :
"SELECT * FROM post_data WHERE userid =".$user_id." and url=".$url.""
Also define your $t and $u variables before your loop in case you have no record.
Next time, try to var_dump your generated query to test it.
If you were able to see the errors the DBMS is reporting back to PHP then you'd probably be able to work out what's wrong with the code.
Before the 'while' loop try...
print mysql_error();
(the obvious reason it's failing is that strings mut be quoted in SQL, and you've got the parameters the wrong way around)
use CGI;
use strict;
use DBI();
use CGI::Carp qw(fatalsToBrowser);
print "content-type: text/html; charset=iso-8859-1\n\n";
my $q = new CGI;
my $name = $q->param('name');
my $email = $q->param('email');
print $q->header;
#connect to database.
my $dbh = DBI->connect("DBI:mysql:database=test;host=localhost","root",
"mukesh", {'RaiseError' => 1});
eval { $dbh->do("CREATE TABLE IF NOT EXISTS emp (name VARCHAR(20), email VARCHAR(50) UNIQUE NOT NULL)") };
print "creating table emp failed: $#" if $#;
print "<br>";
$dbh->do("INSERT INTO emp(name,email) values('$name','$email')");
my $sql = qq/select * from emp order by name/;
my $sth = $dbh->prepare($sql) or die "Can't prepare $sql:$dbh->errstrn";
my $rv = $sth->execute() or die "can't execute the query: $sth->errstrn";
while (my #row = $sth->fetchrow_array) {
print join(", ",#row),"<br>";
}
$sth->finish();
$dbh->disconnect();
print "<br>Total no of records : $rv";
if ($rv>=1){
print "<br>Record has been successfully updated !!!<br>";
} else {
print "<br>Error!!while inserting record<br>";
exit;
}
When I submit the html form for the same value of email address i am redirected to another
page with the following error:
Content-Type: text/html; charset=ISO-8859-1
Software error:
DBD::mysql::db do failed: Duplicate entry 'rajesh#gmail.com' for key 'email' at C:/Apache2/cgi-bin/connectivity.cgi line 27.
1) I dont want this error to be displayed,instead i want to display my own message if email address already exists.something like "email id already exists please enter a new id"
2) after the above problem is solved, i want it to be displayed on the same page where
i am submitting the form.
this line seems to be failing for duplicate entry
$dbh->do("INSERT INTO emp(name,email) values('$name','$email')");
As others have said you can test to see if the email already exists but what happens if someone submits your form and it gets to the insert after another copy of your code has already tested the email does not exist. It would be better to simply catch this condition by wrapping your insert in an eval (as you already have RaiseError enabled) and testing err and state afterwards to see if the error was a duplicate entry.
eval {
$dbh->do("INSERT INTO emp(name,email) values(?,?)", undef, $name, $email);
};
if ($#) {
# you might want to use state instead of err but you did not show us the state
if ($dbh->err =~ /Duplicate entry/) {
# already registered
} else {
# report what is in $# - it is a different error
}
}
BTW, as you have RaiseError enabled you do not need to keep checking the returns (your "or die") from various DBI methods - they will die automatically if they fail and as PrintError defaults to 1, as you have found they will print the error.
One last thing, the fat comma (=>) automatically stringifies the thing to the left so "{'RaiseError' => 1}" can be written "{RaiseError => 1}".
To handle this you could check if the email address already exists.
my $sth = $dbh->prepare("SELECT COUNT(*) FROM emp WHERE email = ?");
$sth->execute($email);
my $rows = $sth->fetchrow_arrayref();
$sth->finish();
if ($rows->[0] == 0) {
# Insert your email address
} else {
# Show an error message
}
And as amon pointed out you should always use Placeholders for your statements.
I am writing a code that will check 2 different tables to determine the privileges the user will have. The code looks like this:
$query1 = ("SELECT 1 FROM `customers` WHERE `Email` = '$email' AND `Password` = '$password'");
$query2 = ("SELECT 1 FROM `admins` WHERE `Email` = '$email' AND `Password` = '$password'");
$result1 = mysql_query($query1) or die(mysql_error());
$result2 = mysql_query($query2) or die(mysql_error());
if (mysql_num_rows($result1) == 1) {
// Log user in as a Customer
exit;
} else if (mysql_num_rows($result2) == 1) {
// Log user in as an Admin.
exit;
} else {
// Direct user to registration page.
}
Can anyone look at this and tell me if there would be any security risk by doing it this way? Thank you in advance for your help!
Firstly you have a change that your code is only known by you.
Secondly you have to check the input data. email and password area is not safety. You should prevent SQL injection. Otherwise your code is not secure.
By the way i'm offering you IP restricted login for admins. I'm using this. And it is more secure.
One big problem here is that the code is vulnerable for sql injections.
Which basicly means that the user could put code in the email or password form to bypass the check you have here.
A start would be to perform the following to your input BEFORE you use them in your query:
$email = mysql_real_escape_string($email);
$password = mysql_real_escape_string($password);
Though, the mysql library is not recommended by php, rather read about prepared statements in pdo here: http://www.php.net/manual/en/ref.pdo-mysql.php
But you can try the mysql_real_escape_string to have a first security measure against sql injections.
This is insecure if for example my password was
OR 1=1
I get access. Use mysql prepared statements
<?php
$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
/* Prepared statement, stage 1: prepare */
if (!($stmt = $mysqli->prepare("SELECT 1 FROM customers WHERE Email = (?) AND Password = (?)"))) {
echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
if (!$stmt->bind_param("ss", $email, $password)) {
echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}
if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}
?>
Something is wrong with this code.
#!/use/bin/perl
use strict;
use warnings;
use Frontier::Daemon;
use DBI;
sub credentials {
my ($username, $password) = #_;
my $tablename = "users";
my $user = "db_user";
my $pw = "db_pass";
$dbh = DBI->connect('DBI:mysql:database;host=localhost', $user, $pw, {RaiseError => 1});
$sql = "SELECT username, password FROM $tablename";
$sth = $dbh->prepare($sql);
$sth->execute or die "SQL Error: $DBI::errstr\n";
if ($sth->rows > 0) {
$login_response = "Login Successful";
} else {
$login_response = "Invalid Credentials";
return {'login' => $login_response};
die();
}
}
$methods = {'login.credentials' => \&credentials,};
Frontier::Daemon->new(LocalPort => 8080, methods => $methods)
or die "Couldn't start HTTP server: $!";
This is another problem with your code - you're not doing anything with the supplied username and password. You need to add a where clause to your SQL statement, so:
my $sql = 'SELECT * FROM users WHERE username = ? AND password = ? ';
my $sth = $dbh->prepare($sql);
$sth->execute($username, $password);
However, given that your example is selecting all records from the 'users' table, I'd have thought that credentials() would at least be returning some rows. However, I'm afraid that I've not used Frontier::Daemon in the past, so I'm not able to help on that front.
I also can't see how this code would work given that you are using strictures. $dbh, $sql, $sth and $login_response haven't been declared. So make sure that you're using 'my' in the right places - as per my example above.
To fix the problems you mentioned with returning the correct string - the logic in your if statement isn't quite right. You are returning the string 'Login Successful' when there's a successful login and the hashref { login => $login_response } when no user could be found.
I think the confusion arose from the layout of the braces. I must stress that you try and indent you code properly, which will make it much more readable to yourself and other developers when debugging and maintaining the code in the future.
The following logic should do the job.
if($sth->rows > 0){
return "Login Successful";
}
return "Invalid Credentials";