Why does my Perl script fail to connect to the database? - mysql

I have a Perl script which retrieves data from MySQL Database. this is the code:
sub startSession{
my $self = shift;
my $dsn = "dbi:".$self{platform}.":".$self{database}.":".$self{host}.":".$self{port};
print "$dsn\n" ;
$self{dbHandle} = DBI->connect($dsn,$user,$password);
}
I have provided every information from an external file. I get the error message
DBI connect('dbname:**.**.**.**:3306','',...) failed: Access denied for user 'root'#'dbserver' (using password: NO) at line 89
Can't call method "prepare" on an undefined value at at line 97
I am very sure the root can connect from any host and the password is also correct.

First, your immediate problem, is as #Sinan Ünür says, that you need to change $self{platform} to $self->{platform}, etc.
Your second immediate problem is that it appears you're getting $user and $password from nowhere (they are not passed to the function, so they are undefined unless they are global variables), which would explain the using password: NO part of the error. Maybe those should be $self->{user} and $self->{password}?
You should considering put this at the top of your module, at least during development, to automatically catch errors like these:
use warnings qw(all);
use strict;
But I'd also comment, that from a design perspective, you really ought to treat DSNs as opaque strings. Each database has its own DSN format. So if you ever want to target a different database, you'll need a different DSN format. Or, possibly, someday MySQL will use a different format (it already has two). Either way, it'll be much easier to change it one place, in a configuration file, than to track down each place you concatenate the various pieces together.

The key part of the warning that I see is "using password: NO". Check that the password is being set properly.

Presumably, $self is a hashref, not a plain hash, and you don't have warnings on. So, turn them on, and use $self->{platform} etc.

Related

Connecting to a MySQL database using DBI

I am trying to connect to a MySQL database.
I found this script and I am trying to use it on my PC and web host, but it doesn't show any output.
Please have a look at this code. I am running perl at xampp.
#!C:\xampp\perl\bin\perl.exe
print "Content-type: text/html\n\n";
use DBI;
use strict;
my $driver = "localhost";
my $database = "data";
my $dsn = "DBI:$driver:database = $database";
my $userid = "root";
my $password = "";
my $dbh = DBI->connect($dsn, $userid, $password ) or die $DBI::errstr;
I am using the same database with PHP.
but it doesn't show any output.
Judging by the CGI header you're displaying, I assume that you're running this as a CGI program. In which case, it's no surprised that you're not seeing any output - you're not sending any output.
If you ran it as a command line program (and it's often a good idea to get stuff working on the command line before leaping into CGI programming), then you would see the "Content-Type" header. Alternatively, you could add some output to your program and see if that appears in your browser. Something simple like:
print 'It works!';
I'd also like to add, that CGI looks rather outdated these days and there are far better (by which I mean easier and more powerful) ways to write web applications with Perl. You might like to read CGI::Alternatives to get an idea of what is available.
Update:
I've just seen this question asked on Facebook (please don't cross-post without telling people) and I've noticed that your $driver variable is wrong. If you're connecting to MySQL, then $driver should be "mysql" (so that DBI loads "DBD::mysql").
A DSN for the MySQL driver looks like this
DBI:mysql:database=$database;host=$hostname;port=$port
where the host and port fields are optional. (The database is also optional, but you don't want to leave that out.) There are several more esoteric options too, but they're irrelevant here
But you're supplying
DBI:localhost:database = data
Which doesn't even specify a MySQL connection, so I'm not surprised if it doesn't work! I don't know whether the spaces are legal, but I would leave them out to keep in line with the documentation.
You should change that statement to
my $dsn = "DBI:mysql:database=$database;host=$driver"
You may remove ;host=$driver if you wish (why have you called the host name "driver"?) as localhost is the default. A DSN that specifies just a database name and uses the default for all the other fields may be contracted to just
my $dsn = "DBI:mysql:$database"
It may be easier to just write print statements at first to generate some output. You will want to print a MIME content type header of text/plain instead of text/html. Try print "$DBI::errstr\n" for now instead of die, as the latter writes to stderr which won't appear in your browser
you could add:
if ($dbh) {
print 'connect ok';
} else {
print 'connect failed';
}

Warning: mysql_num_rows() But only on webhost, not localhost

On localhost this works great. But when I upload files to server I get this error:
Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in /storage/content/04/13fd39104/xxxxx.com/public_html/users/list.php on line 54
My code is:
//load users from database
$users = mysql_query("SELECT id,username FROM ".$sql_table_users." WHERE id!='".$_SESSION['user_id']."'");
if(mysql_num_rows($users) > 0){
while($user = mysql_fetch_assoc($users)){
//ALT tag contains user ID and user name
print '• '.$user['username'].'<br />';
}
}
Are you sure to have the same db strutture on server? Probably some column or table name are different from localhost. Check also if your db connection credentials are correct
Perhaps your database on server is not the same as your localhost.
add echo mysql_error(); after mysql_query to see details.
I would echo the query string before performing the query to see if it really is the string you think it should be. Most likely one of the variables is not defined so the query is failing. If that doesn't help you could also output any mysql errors after the query.
And of course, the obligatory suggestion to get off of the deprecated mysql_* functions! If you don't want to do PDO, check out mysqli and how very similar it is to the mysql functions if you use the procedural functions.

How to undo sql USE?

What's the SQL command to undo:
USE db;
The syntax I see everywhere is:
USE [db] ;
implying that I can leave out the db part. Not so - this is a syntax error however (maybe just syntax errors in the SQL syntax syntax?).
edit
The programming problem this is causing is that I can't reset the environment in which subsequent commands run. I could reset my DB connection, but this seems efficient.
cmdX; // Works
vs.
cmdX;
cmdY; // May fail because command X upset some state.
cmdX should clean up after itself and put things back where it found them.
Analogously:
cd ./a
doX()
cd ../
doY() // Y expects to not be in a?
I don't think you can. The documentation doesn't say the parameter is optional. It says:
The database remains the default until the end of the session or another USE statement is issued:
So if you want to drop the default, end your session and start a new one without selecting a DB.
What programming problem is this causing for you?
The database argument is not optional.
mysql> use
ERROR:
USE must be followed by a database name
I'm not sure where you saw this command with square brackets around the argument. That is not shown at the documentation page: http://dev.mysql.com/doc/refman/5.6/en/use.html
Microsoft SQL Server uses square brackets around identifiers (as opposed to a style to indicate an optional argument), but the MS SQL documentation for USE also doesn't show it: http://msdn.microsoft.com/en-us/library/ms188366.aspx
What would it mean to "undo" a USE command? Would it be like cd - in bash, making the previous default database again the default? There is no such command in MySQL for this. It doesn't remember what was your previous default database. If you want to return, you just have to USE that database and name it explicitly.

MySQL credentials/hosts variables best practices

I want to know what is the best practice or what is recommended to do when a variables are created for MySQL credentials/host.
define('HOST', 'localhost');
// etc..
mysql_connect(HOST, // etc...
vs
$host = 'localhost';
// etc..
mysql_connect($host, // etc...
For both you can easily check what are the declared variables or constants and maybe can find what are the value easily. I have code that multiple users can share and use.
What is the best way to protect these variables?
Here's few solutions
1) You give each user a user and password and each user has their permissions in the database (only select, or insert ect..). So in your code you simply include a db.config.php so all the variables are set. It does not really matter if the user echo the variables since they use their own.
2) you can give a common username/pass for the database and then encode the file (either using custom encoding, zend optimizer or ioncube and unset the variables. Here's a sample code:
// file mysql_connect.php
$link = mysql_connect("localhost", "mysql_user", "mysql_password")
or die("cannot connect to database : " . mysql_error());
// then this file is encoded so nobody can view it.
3) At some point, someone, somehow will be able to find this information. I would simply recommend to trust your user (assuming these are developers)
At some point in your code you will have to hardcode this kind of information, the important thing is to keep it in only one place to promote maintanability.
However, as you are worried about security I suggest you to check this: Convert PHP file to binary

How can I get the database name from a Perl MySQL DBI handle?

I've connected to a MySQL database using Perl DBI. I would like to find out which database I'm connected to.
I don't think I can use:
$dbh->{Name}
because I call USE new_database and $dbh->{Name} only reports the database that I initially connected to.
Is there any trick or do I need to keep track of the database name?
Try just executing the query
select DATABASE();
From what I could find, the DBH has access to the DSN that you initially connected with, but not after you made the change. (There's probably a better way to switch databases.)
$dbh->{Name} returns the db name from your db handle.
If you connected to another db after connected with your dbh, using mysql query "USE db_name", and you did not setup a new perl DBI db handle, of course, $dbh->{Name} will return the first you previously connected to... It's not spontaneic generation.
So to get the connected db name once the db handle is set up - for DBI mysql:
sub get_dbname {
my ($dbh) = #_;
my $connected_db = $dbh->{name};
$connected_db =~ s/^dbname=([^;].*);host.*$/$1/;
return $connected_db;
}
You can ask mysql:
($dbname) = (each %{$dbh->selectrow_hashref("show tables")}) =~ /^Tables_in_(.*)/;
Update: obviously select DATABASE() is a better way to do it :)
When you create a connection object it is for a certain database. In DBI's case anyway. I I don't believe doing the SQL USE database_name will affect your connection instance at all. Maybe there is a select_db (My DBI is rusty) function for the connection object or you'll have to create a new connection to the new database for the connection instance to properly report it.
FWIW - probably not much - DBD::Informix keeps track of the current database, which can change if you do operations such as CREATE DATABASE. The $dbh->{Name} attribute is specified by the DBI spec as the name used when the handle is established. Consequently, there is an Informix-specific attribute $dbh->{ix_DatabaseName} that provides the actual current database name. See: perldoc DBD::Informix.
You could consider requesting the maintainer(s) of DBD::MySQL add a similar attribute.