rooneyl has asked for the wisdom of the Perl Monks concerning the following question:

Hello all, I am connecting to a database on my local server. I have written a routine to connect to it.
sub rm_conn { use DBI; use strict; my $conn = DBI->connect("DBI:Pg:dbname=$_[0];", "$_[1]","$_[2] +", {'RaiseError' => 1}); return $conn; }
0 is the database name,
1 is the username,
2 is the password.
Is there a way that I could get these variables from a file located somewhere else on the server, rather then passing them in when the sub is called.
Thank you in adavance for any help, you are making me a better praticer of perl!

Replies are listed 'Best First'.
Re: Database connection
by tachyon-II (Chaplain) on Mar 27, 2008 at 11:37 UTC

    Self explanatory variables as the arguments to your sub would have avoided the need to explain what they are. Use gets executed at begin time. If you really don't want to load DBI every time the code runs use require. There is really no point in using strict in a 2 line sub. It is lexically scoped. Put it just under the shebang line.

    This uses a closure to make a single persistent connection to the DB so you can get that connection from anywhere just by calling the sub. Call it a lightweight object. By adding a disconnect sub within the closure block you can just call that in an end block and your code will automatically disconnect on exit (including if it crashes). This will automatically prevent you from getting can't connect, too many connection errors (especially during testing).

    { my $dbh; sub rm_conn { my ($db, $user, $pass) = @_; require DBI; return $dbh if $dbh; # already connected $dbh = DBI->connect("DBI:Pg:dbname=$db;",$user,$pass, {'RaiseE +rror' => 1}) or die "Can't connect to $db $DBI::errstr; return $dbh; } sub dis_conn { $dbh->disconnect if $dbh; } } END { dis_conn() }

    As far as storing usernames and passwords on the server a flat file is a simple as it gets. Write a sub that takes a filename, opens the file, reads the db/user/pass data in whatever format works for you and returns them. Then just pass it to your rm_conn sub. The name get_dbh makes more sense for self documentation than rm_conn (at least in english which may not be your language)

    sub get_db_stuff { my ($filename) = @_; open F, $filename or die "Can't read $filename $!\n"; my $data = <F>; close F; # this split allows comma, tab or space separated data # but of course precludes spaces in the names my ($db,$user,$pass) = split /[,\s]+/, $data; die "Invalid $data in $filename!\n" unless $db and $user and $pass +; return ($db,$user,$pass); }

    You could of course integrate that into your connection routine if desired.

    For pre-rolled solutions have a look at DBIx::Password and DBIx::PasswordIniFile

Re: Database connection
by stiller (Friar) on Mar 27, 2008 at 11:32 UTC
    Search cpan for Config

    I use Config::Simple a lot.

    Make sure the config file is not readable by anyone that shouldn't get to the username / password to the database.

Re: Database connection
by ww (Archbishop) on Mar 27, 2008 at 11:35 UTC

    Parts of your problem_space is not quite clear to me, so this is largely a shot in the dark. Answers to the questions below will undoubtedly get you better answers.

    Are you getting dbname, uname and p/w from something hardcoded in some other part of your script? ... from a form on a webpage? from the CLI?

    Any why do want to obtain them within the sub? The reference to using a file sounds as though it might be rooted in a security concern, but that's merely a guess. An appropriate answer will also depend on whether your reference to "the server" is to a web server (Apache, etc) or to a fileserver or something else?

    Despite that, taking a stab in the dark, one way to 'get these variables from a file somewhere else on the server" would be to add a block inside the sub (before line 6) opening (and be sure to test the open) the file, and reading the vars.

    Why are you using use strict; in the sub. Does that mean you're not using strict (and warnings!) in main? If so, make your life easier by adding both in the head of your script.

Re: Database connection
by apl (Monsignor) on Mar 27, 2008 at 11:47 UTC
    If you're on a *nix box, you could use environment variables set in the script that runs your perl.

    Then your statement would become (for example):

    my $conn = DBI->connect("DBI:Pg:dbname=$ENV{FDA_DB};", $ENV{SYB_USER +}, $ENV{SYB_PASS}, {'RaiseError' => 1});
Re: Database connection
by oko1 (Deacon) on Mar 27, 2008 at 14:33 UTC

    I think the underlying question you're asking is "can I keep my database login info in some external resource on the server rather than hard-coding it into the script?" There's a question that goes along with that one, which is "how are you going to keep that resource from being visible to the world?" The answers don't have all that much to do with Perl, but here's a fairly common way of doing it (assuming that you're using Apache or something else that honors .htaccess files):

    1) Ensure that you have a .htaccess file in the appropriate directory, and that it's set up to deny external access to the file that you want to use - e.g., if you wanted to use a file called .htinfo, it would look like this:

    <Files .htinfo> order allow,deny deny from all </Files>

    2) Create .htinfo and enter the necessary information. E.g.:

    %info = ( db => 'my_database_name', user => 'user_name', pass => 'password' );

    3) Read it into your application.

    our %info; do ".htinfo" or die "Problem reading '.htinfo'!\n"; my $dbh = DBI->connect( "DBI:mysql:$info{db}", $info{user}, $info{pass +} );
Re: Database connection
by esobchenko (Beadle) on Mar 27, 2008 at 12:38 UTC
    Use singleton pattern to access your dbh. Take a look at Class::Singleton on CPAN.