We will now see two of the several search interfaces that I created for the MDB site. Initially we will discuss a simple one that accepts a list of one or more values, generates the SQL, performs the query and presents the results. The script that processes this form's input (pdbsearch.php) uses some of the functions in the include files we saw above.
The search form straightforward, and looks like this:
A PDB ID is a unique identification code, which anyone working with proteins and biomolecules will know. They are assigned by the people at Protein Data Bank, when the protein is deposited there. The reason for this search form is to allow people who know which proteins they are interested in, and want to know what metal-binding sites exist in them.
This (and all other scripts in the MDB), generate output that has to look consistent with the layout of the other HTML pages. These are themselves generated with XSSI (eXtended Server-Side Includes, an Apache extension of the Server-Side Includes technology which is used to embed other documents and the output of CGI scripts into an HTML page), with templates that dictate their structure. We therefore add the appropriate HTML <META> elements to describe the content:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Pragma" CONTENT="no cache">
<META NAME="Organization" CONTENT="The Scripps Research Institute">
<META NAME="Copyright" CONTENT="The Scripps Research Institute">
<META NAME="Version" CONTENT="1">
<META NAME="Author" CONTENT="Jesus M. Castagnetto, jesusmc@scripps.edu">
<META NAME="Keywords" CONTENT="metal,protein,metalloprotein,protein design,structure,database,molecular biology,metalloenzyme,metalloantibody, database,query,java">
<META NAME="Description" CONTENT="A structural database of metal-binding sites in metalloproteins, including an interactive search and visualization interface.">
<TITLE>
MDB (Query Results) - Metalloprotein Site Database and Browser </TITLE>
Now we include the JavaScript functions we use in this page from an external library:
<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript"
SRC="/javascript/mainbar.js">
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<TABLE BORDER=0 CELLSPACING=0 WIDTH="100%">
<TR>
<TD COLSPAN=2>
We emulate some of the XSSI that the regular HTML files use, by using the virtual function. This is an Apache-specific function that performs an Apache sub-request; it is the equivalent of using the XSSI command <--#include virtual="/path/to/include_file" -->.
<?php virtual ("/include/navhead.inc") ?>
</TD>
</TR>
<TR VALIGN="top">
<TD BGCOLOR="#06F6FA" ROWSPAN=2>
<?php virtual ("/include/navside.inc") ?>
</TD>
<TD><HR>
<?php virtual ("/include/logo.inc") ?>
<!-- END of MDB Logo -->
<HR>
<H2 ALIGN="CENTER">
Results of querying the MDB using PDB ID(s) </H2>
This is where the fun begins. We will process the input, generating the appropriate query statement:
<?php /*
* Script: pdbsearch.php
* Written by: Jesus M. Castagnetto * For the MDB site
*
* Based on the "remote.php" script.
*
* Created: Fri Jan 29 14:26:14 PST 1999 */
First we call the include files we will need later. We require them, although in this case we could also include them. (As we saw in Chapter 6, the difference is that required files are inserted only once, whereas included ones can be used in (for example) loops, where the inserted file can change at runtime.)
/* included scripts are in the /php inc/ dir */
require ("sql.inc");
/* Include the function to generate tables from results */
require ("tables.inc");
require ("parseinput.inc");
Next, we define our global variables: the database to use and a log file where we will save the queries being made, so we can perform a post-mortem if something goes wrong:
/* Initialization of variables */
$db = "metallodb";
$querylog = "tmp/pdb_id_advqueries.log";
Now we connect to the database server and select the database, performing error checking at each step, to help the user (and us) should anything go wrong:
/*
* Main section of the script *
* This script assumes that the database server is on the same * machine as the web server that invokes it.
*/
/* Get a connection and select the database */
$link = SQL pconnect ();
// $link = SQL connect (); # If you prefer a simple connection
if ( !$link ) {
echo("<TABLE BORDER=5><TR BGCOLOR=\"yellow\"><TD>");
echo("Error connecting to the server\n");
echo(SQL error() . "\n");
echo("</TD></TR></TABLE>");
echo("</CENTER></BODY></HTML>");
exit;
}
if (!SQL select db($db,$link)) {
echo("<TABLE BORDER=5><TR BGCOLOR=\"yellow\"><TD>");
echo("Error selecting database " . $db);
echo(SQL error() . "\n");
echo("</TD></TR></TABLE>");
echo("</CENTER></BODY></HTML>");
exit;
}
The next step is to process the values from the input form; we assume that these will be in the form either of a comma-separated list, or a single value. If no values were entered, we let the user know the cause of the error. If there is input, we use the parseList function discussed above to generate the condition clause of the query string:
/* pdb ids requested */
if ($pdbids) {
$q pdbids = parseList("site.source id = ", strtolower($pdbids));
} else {
echo("<TABLE BORDER=5><TR BGCOLOR=\"yellow\"><TD>");
echo ("<B>Error</B> PDB id(s) needed for the search</B>");
echo("</TD></TR></TABLE>");
echo("</CENTER></BODY></HTML>");
exit;
}
When we generate the SQL statement, there will be parts of it that are kept constant, in particular which fields will be displayed (which correspond to the ones in the makeTable function in table.inc above):
/* construct and submit the search */
$query = "SELECT distinct site.source id, site.site id, site.num ligands, site.metal, protein.description";
$query .= " FROM protein, site WHERE ";
$query .= $q pdbids;
$query .= " AND protein.source id=site.source id ORDER BY site.site id";
$query = strtolower(stripslashes($query));
We now save the query as it stands, but we won't close the log file until we get back the results and they are displayed. In this way, even if the script dies during the query process or while getting the results, we can see the SQL statement and figure out what the problem could have been:
/* save to a file for debugging */
$datestamp = date("Y-m-d#H:m:s#", time());
$dbgfp = fopen ($querylog, "a");
$ip = getenv("REMOTE ADDR");
$agent = getenv("HTTP USER AGENT") . " || " . getenv("HTTP REFERER");
fwrite ($dbgfp, "$datestamp");
fwrite ($dbgfp, "$ip#$agent#");
fwrite ($dbgfp, "$query");
Now we perform the query, get the result handler and use makeTable() to create the HTML output. If no results are found, we must let the user know:
/* Get the results and process */
$result = SQL query($query,$link);
if (!$result) {
echo("<TABLE BORDER=5><TR BGCOLOR=\"yellow\"><TD>");
echo("Error obtaining the query results\n");
echo(SQL error() . "\n");
echo("</TD></TR></TABLE>");
echo("</CENTER></BODY></HTML>");
exit;
}
$nrows = SQL num rows($result);
/* create hits table only if we got some results */
if ($nrows > 0) {
echo("<DIV ALIGN=\"CENTER\"><B>
You searched for PDB ID(s):");
echo("</B>".$pdbids."<BR>And ".$nrows);
echo(" ".($nrows>1?"sites were":"site was")." found");
makeTable($result,100000);
} else {
echo ("<DIV ALIGN=\"CENTER\" STYLE=\"background: yellow;\">
<BIG>No sites were found that matched your query </BIG></DIV>");
}
If we got all the way here, it should mean that the query and result processing were successful, so we can finish adding information to the log file, close it, and clear the result handler:
fwrite ($dbgfp, sprintf("#%d\n", $nrows));
fclose($dbgfp);
if ($result) SQL free result($result);
?>
Now we send the closing tags of the HTML document:
</TD>
</TR>
<TR>
<TD ALIGN="CENTER" BGCOLOR="#E0FFFF">
<HR WIDTH="50%">
<?php virtual ("/include/nav mdb text.inc") ?>
<HR WIDTH="50%">
</TD>
</TR>
<TR>
<TD colspan=2 bgcolor="#06F6FA" ALIGN="CENTER">
<?php virtual ("/include/navfoot.inc") ?>
</TD>
</TR>
</TABLE><HR>
<ADDRESS>
<SMALL>
Page maintained by Jesus M.
Castagnetto (jesusmc@scripps.edu) -
© The Scripps Research Institute. <BR>
Query performed on: <?php echo (date("D, F d, Y - h:i a", time())); ?>
</SMALL>
</ADDRESS>
</BODY>
</HTML>
Performing a search for (for example) the metal sites in one of the Superoxide Dismutase metalloproteins (PDB ID: 2SOD), we will obtain the following: