Sei sulla pagina 1di 7

PHPLIB and multiple databases

Expanding PHPLIB
PHPLIB accesses databases through an object created from class DB_Sql.
Db_mysql.inc includes the DB_Sql class as modified for MySQL. We will extend
DB_Sql by adding code to common.php3, after the line that includes db_mysql.inc.
DB_Sql contains many functions to perform queries. The one we want to change is:
<?php
/* public: connection management */
function connect($Database = "", $Host = "", $User = "", $Password = "") {
/* Handle defaults */
if ("" == $Database)
$Database = $this->Database;
if ("" == $Host)
$Host

= $this->Host;

if ("" == $User)
$User

= $this->User;

if ("" == $Password)
$Password = $this->Password;
/* establish connection, select database */
if ( 0 == $this->Link_ID ) {
$this->Link_ID=mysql_pconnect($Host, $User, $Password);
if (!$this->Link_ID) {
$this->halt("pconnect($Host, $User, \$Password) failed.");
return 0;
}
if (!@mysql_select_db($Database,$this->Link_ID)) {
$this->halt("cannot use database ".$this->Database);
return 0;
}
}
return $this->Link_ID;
}
?>
Find the connect() function in your db_mysql.inc (or the .inc for your database), then
copy it in to common.php3 somewhere after the include of db_mysql.inc. You will
have to wrap it in a class definition as described at the end of this article.
I find the code hard to read. Therefore, the first thing to do is make the copied code
readable:
<?php

/* public: connection management */


function connect($Database = "", $Host = "", $User = "", $Password = "") {
/* Handle defaults */
if ("" == $Database) {
$Database = $this->Database;
}
if ("" == $Host) {
$Host

= $this->Host;

}
if ("" == $User) {
$User

= $this->User;

}
if ("" == $Password) {
$Password = $this->Password;
}
/* establish connection, select database */
if ( 0 == $this->Link_ID ) {
$this->Link_ID=mysql_pconnect($Host, $User, $Password);
if (!$this->Link_ID) {
$this->halt("pconnect($Host, $User, \$Password) failed.");
return 0;
}
if (!@mysql_select_db($Database,$this->Link_ID)) {
$this->halt("cannot use database ".$this->Database);
return 0;
}
}
return $this->Link_ID;
}
?>
I indented the code so the levels let me match the brackets, with the enclosed code.
This avoids errors caused by missing brackets. I added brackets to single lines. PHP
lets you get away without brackets around single lines of code after if statements. As
soon as you add extra code, the shortcut fails. I suggest always use the brackets to
avoid errors when you add code later.
Now, for the connect code change. Notice how the connect() code checks the existence of
a connection and creates the connection if the connection does not exist. This connect()
function is run before every database query. Unfortunately, it only selects the database
once when it makes the connection. If your PHP pages use more than one database, the
connect() code will not pick up the change of database.

There are several ways to change the code. We are looking for the change that has the
least impact on PHPLIB and lets us display the status of the database activity, if we need
to diagnose a problem. The two things we need outside PHPLIB are the connection id and
the database name. Therefore, make both external to PHPLIB. In common.php3:
<?php
$db_connection = 0; // Common database connection id.
$db_database = ""; // Name of current database.
?>
Next, we change PHPLIB to store the connection id and database name in these fields.
The rest of your code can set and use the same fields. If you need to find which database
is in use when diagnosing a problem, insert this in your page:
<?php
Print("<p>db_database: " . $db_database . "</p>");
?>
(There are shorter ways to write the print line. This way highlights the variable name in
editors that have colour coding. It also works reliable with arrays and other compound
variable names.)
How do we get connect() to use our new variables? We could add an extra line near the
top so you have:
<?php
{
globals $db_connect, $db_database;
/* Handle defaults */
?>
The extra line makes our extra variables available within connect(). Here is a more
sophisticated way. Straight after the definition of $db_database, add:
<?php
function db_connect($db_connect_host="", $db_connect_user="",$db_connect_pass="")
{
globals $db_connect;
if(!empty($db_connect_host)) {
$db_connect = mysql_pconnect($db_connect_host,
$db_connect_user, $db_connect_pass);
}
return($db_connect);

function db_database($db_database_new="") {
globals $db_database;
if(!empty($db_database_new)) {
$db_database = @mysql_select_db($db_database_new, db_connect());
}

return($db_database);
}
?>
By defining these common functions once, you can get the common variables in all sorts
of places, without having to add the globals line all over the place. Here is the common()
function using our db functions:
<?php
function connect($Database = "", $Host = "", $User = "", $Password = "") {
/* Handle defaults */
if ("" == $Database) {
$Database = $this->Database;
}
if ("" == $Host) {
$Host

= $this->Host;

}
if ("" == $User) {
$User

= $this->User;

}
if ("" == $Password) {
$Password = $this->Password;
}
/* establish connection, select database */
if ( 0 == db_connect()) {
$this->Link_ID = db_connect($Host, $User, $Password);
if (!$this->Link_ID) {
$this->halt("pconnect($Host, $User, \$Password) failed.");
return 0;
}
}
if (0 != db_connect()) {
if($Database != db_database()) {
$this->Database = db_database($Database))
if(empty($this->Database)) {
$this->halt("cannot use database " . $this->Database);
return 0;
}
}
}

return $this->Link_ID;
}
?>
The test for the database is taken outside the test for the connect so that connect() can
check for a new database, even when there is a current connection. It means we compare
db_connect() to 0 twice as often. The result is worth the slight extra processing.
We place the database connection and the database selection outside of PHPLIB, so we
can use the same functions for database selection everywhere else in your PHP code.
There is only one disadvantage at this stage: We assume the same host, user and
password for all database accesses. If you have a user logging on, then accessing a
special database with special privileges, you will have to set up a special connection for
that access. How? Define variables:
<?php
$db_host = "";
$db_user = "";
$db_pass = "";
?>
Expand the db_database() function to compare the current user and host to the special
user and host. You could also add:
<?php
$db_type = "";
?>
and store in it the type of database, mysql, Oracle, etc. so you can access multiple
databases.
Changing the code to handle multiple databases is more complex. You have to
change the query functions, as well as the connect and select. You might want to
read up on PHP's ODBC connection, then use the ODBC option in PHPLIB. ODBC
handles many databases in a generic way that may be a little slower. ODBC lets you
use the same code on multiple types of databases. If you do use multiple database
types, you can have problems with dates requiring different formats and generally
weird differences between the databases. ODBC simplifies the connection, but does
not fix the way databases interpret data and SQL.
Now for a quick lesson on redefining object classes. The connect() function is
wrapped in a class definition:
<?php
class DB_Sql {
}
?>
When we copy the function in to common.php3, we need to redefine the DB_Sql
class. We do that by wrapping connect() in:
<?php
class db_DB_Sql extends DB_Sql {
}

?>

Have a look at the PHP documentation on objects and classes to see what "extends"
does. The "25 words or less" summary is: Everything in the extended definition
replaces and overrides everything in the original definition.
Now to use db_DB_Sql. When you set up PHPLIB, you will have a statement that
says:
<?php
$x = new DB_Sql;
?>
Change it to:
<?php
$x = new db_DB_Sql;
?>
That will use the modified class, instead of the original.
You are now an expert on objects, classes, OOP and can demand $10,000 more per
year.
We made an effective change with the minimum impact on the PHPLIB code. Keep
track of the changes, so you can reapply them to a new release of PHPLIB. If you
have errors with database access, you can place print statements in the external
functions to see when connections are made. You can now do a lot more, without
changing the PHPLIB code.
If the SQL seems to fail, you can copy the query() function from DB_Sql in
db_mysql.inc to the db_DB_Sql in common.PHP3, then insert a print statement to see
the SQL in use.
PHPLIB writes cookies. A print statement in the middle of PHPLIB may produce error
messages about problems writing HTTP headers. Ignore the errors or write the
diagnostic messages to a disk file. Start with:
$db_log_file = "t:/diag.txt";
or similar. Point to a text file somewhere on your disk. In Windows, make sure you
use a directory that exists or you will get a weird error.
Now define:
<?php
function db_log($db_log_message) {
globals $db_log_file;
$db_log_f = fopen($db_log_file, "a");
fwrite($db_log_f, date("Y m d H:i:s")." ".$db_log_message."\r\n");
fclose($db_log_f);
}
?>
Anytime you need to see what is happening, add log messages like:
<?php
db_log("current database: " . db_database());

?>
There are some built in logging techniques and system logs you can use. You may
not have access to the right directories and may have to search large files to find a
tiny piece of information. This separate log gives you some control during testing. I
recommend it before and after logs like:
<?php
db_log("current database: " . db_database());
db_database("bookcatalogue");
db_log("current database: " . db_database());
?>
Remember to use the right database in your database accesses so you do not query
the PHPLIB database. You might like to create a wrapper function for the database
query function or change the function you use. If you use mysql_query(), you can use
db_database() first. You can also replace:
<?php
db_database("bookcatalogue");
$result = mysql_query("select * from?", db_connect());
?>
with
<?php
$result = mysql_db_query(db_database("bookcatalogue"), "select * from?",
db_connect());
?>
which suggests the function:
<?php
function db_query($db_query_database, $db_query_sql) {
return(mysql_db_query(db_database($db_query_database),
$db_query_sql,
db_connect());
}
?>
Now you can use PHPLIB (and any similar software) with multiple databases
extend classes/objects insert diagnostic checks write a log of anything to a file

Potrebbero piacerti anche