$q_expdata .= "protein.expdata NOT LIKE '%nmr%' AND "; $q_expdata .= "protein.expdata NOT LIKE '%theor%') OR "; $q_expdata .= "protein.expdata = NULL)"; } else { $q_expdata = mkLikeOpt("protein.expdata", $expdata); } } else { $q_expdata = ""; } This is where things can get hairy. To create a correctly formed query statement, we need to check the existence of the previous clauses generated from each variable. To make the code more compact, I chose to use the ternary conditional operator: condition ? option1 : option2, which we saw in Chapter 6. /* construct and submit the search */ $query = "SELECT DISTINCT site.source_id, site.site_id, site.metal, site.num_ligands, protein.description"; $query .= " FROM protein,site WHERE "; /* check the existence of each part of the query * before sending */ $qtemp = ($q_metal!="") ? $q_metal : ""; $qtemp .= ($qtemp!="" && $q_num_lig!="") ? " AND " . $q_num_lig : $q_num_lig; $qtemp .= ($qtemp!="" && $q_expdata!="") ? " AND " . $q_expdata : $q_expdata; $qtemp .= ($qtemp!="" && $q_r_val!="") ? " AND " . $q_r_val : $q_r_val; $qtemp .= ($qtemp!="" && $q_res!="") ? " AND " . $q_res : $q_res; $qtemp .= ($qtemp!="" && $q_author!="") ? " AND " . $q_author : $q_author; $query .= $qtemp ; $query .= " AND protein.source_id=site.source_id ORDER BY site.site_id "; $query = strtolower(stripslashes($query)); If we are debugging the script (i.e., if $debug is set to true), let's save some data that can later be readily parsed: /* save to a file for debugging */ if ($debug) { $datestamp = date("Y-m-d#H:m:s#", time()); $dbgfp = fopen ($querylog, "a"); $ip = getenv("REMOTE_ADDR"); $agent = getenv("HTTP_USER_AGENT"); fwrite($dbgfp, "$datestamp"); fwrite($dbgfp, "$ip#$agent#"); fwrite($dbgfp, "$query"); } TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The code for performing the query and processing the results is similar to that for the pdbsearch.php script above: /* Get the results and process */ $php_errormsg=""; @$result = SQL_query($query,$link); $msqlerrormsg = SQL_error(); if ($php_errormsg!="") { echo ("<HTML><BODY BGCOLOR=\"white\"><B>"); echo("PHP Error: "); echo($php_errormsg . "<P>"); if ($msqlerrormsg != "") { echo("mSQL Error: " . $msqlerrormsg ); } echo ("</B></BODY></HTML>"); fwrite ($dbgfp, "#ERROR IN QUERY: PHP=" . $php_errormsg . " mSQL=" . $msqlerrormsg . "\n"); fclose ($dbgfp); exit; } @$nrows = SQL_num_rows($result); Next we generate a listing of the variables defined by the user. This is usually a good way of providing feedback and also making sure that the input was correctly parsed: /* Output the query variables */ $hitstr = ( $nrows > 1 ) ? " hits" : " hit"; $outvar = "<DIV ALIGN=\"CENTER\"><B>Your query was:</B><BR>"; $outvar .= "[Metal(s)=" . $metal . "] AND [Number of Ligands= " . $num_lig; $outvar .= "] AND [Resolution<=" . $res . "] AND [R-value<=" . $r_val; $outvar .= "] AND [Expdata=" . $expdata . "] AND [Author(s)=" . $author; $outvar .= "] AND [you asked to show (at the most) " . $showhits; $outvar .= " hits per page. <B>This search found: " . $nrows . $hitstr . "</B></DIV>\n"; echo ($outvar); Finally, we create the table containing the query results, taking into account the maximum number of hits per page that the user specified in the search form. We use the makeForm() function to display the next set of results (if any), using a form that hands the subsequent processing to the prev_next.php script (discussed a bit later in this chapter): /* create hits table only if we got some results */ if ($nrows > 0) { if ($showhits=="all") { $max = $nrows; } else { $max = min((int)$showhits,(int)$nrows); } $rightlower = $max + 1; TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com $rightupper = min(2*$max,$nrows); $showing = "<P><DIV ALIGN=\"CENTER\"><B><U> Showing results: 1 "; $showing .= " to " . (int) $max . "</U></B></DIV>"; echo ($showing); if ($rightlower <= $nrows) { echo ("<DIV ALIGN=\"CENTER\">\n <TABLE WIDTH=\"90%\">\n<TR>\n"); echo ("<TD ALIGN=\"RIGHT\">\n"); makeForm(urlencode($outvar), urlencode($query), $nrows, $max, $rightlower, $rightupper); echo ("</TD>\n"); echo ("</TR>\n</TABLE>\n</DIV>"); } makeTable($result,$max); if ($rightlower <= $nrows) { echo ("<DIV ALIGN=\"CENTER\">\n <TABLE WIDTH=\"90%\">\n<TR>\n"); echo ("<TD ALIGN=\"RIGHT\">\n"); makeForm(urlencode($outvar), urlencode($query), $nrows, $max, $rightlower, $rightupper); echo ("</TD>\n"); echo("</TR>\n</TABLE>\n</DIV>"); } } else { echo ("<DIV ALIGN=\"CENTER\" STYLE=\"background: yellow;\"> <BIG>No sites were found that matched your query </BIG></DIV>"); } If debugging is turned on, we write the number of hits found and close the log file. Finally, we clear the result handle and send the closing HTML tags: if ($debug) { fwrite($dbgfp,sprintf("#%d\n",$nrows)); fclose($dbgfp); } if ($result) SQL_free_result($result); ?> </TD> </TR> <TR> <TD ALIGN="CENTER" BGCOLOR="#E0FFFF"> <HR WIDTH="50%"> <?php virtual ("/include/nav_mdb_text.inc") ?> <HR WIDTH="50%"> </TD> </TR> <TR> TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com <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: <? echo (date("D, F d, Y - h:i a",time())) ?> </SMALL> </ADDRESS> </BODY> </HTML> The general script for displaying the previous/next set of hits matching the query parameters is named prev_next.php and is shown below. This is a simple script and does not need to regenerate SQL statements from variables; instead, the SQL statement is URL-encoded and passed into the script in a hidden HTML element. First we send the HTML header/layout to give the page the same look as all the other pages in the MDB site: <!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> <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> <?php virtual (" /include/navhead.inc") ?> </TD> </TR> TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com <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</H2> Next, we process the passed-in hidden variables, and require the appropriate files for our SQL function wrappers and for formatting and displaying the results: <?php /* Script: prev_next.php * simple script to implement the "Previous results", * "Next results" buttons * * Written by: Jesus M. Castagnetto * Created on: Feb 01, 1999 */ /* included scripts are in the /php_inc/ dir */ require ("sql.inc"); require ("tables.inc"); /* (hidden) variables passed to the script: * form_str = a string w/ the form entry * sql_str = a string w/ the SQL query * max = maximum number of hits per page * lower,upper = bounds for the results range */ $db = "metallodb"; $query = urldecode($sql_str); $form = urldecode ($form_str); $link = SQL_pconnect(); $result = SQL($db,$query . " LIMIT " . $upper ,$link); echo (urldecode($form_str)); if ($result) { /* we got some hits */ $leftlower = max(1, $lower - $max); $leftupper = $lower - 1; $rightlower = $upper + 1; $rightupper = min((int)$nrows,(int)($upper + $max)); $showing = "<P><DIV ALIGN=\"CENTER\"><B><U> Showing results: " . (int) $lower; $showing .= " to " . (int) $upper . "</U></B></DIV>"; echo ($showing); echo ("<DIV ALIGN=\"CENTER\">\n <TABLE WIDTH=\"90%\">\n<TR>\n"); if ($leftupper > 0) { echo ("<TD ALIGN=\"LEFT\">\n"); makeForm(urlencode($form), urlencode($query), $nrows, TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com $max, $leftlower, $leftupper); echo ("</TD>\n"); } if ($rightlower <= $nrows) { echo ("<TD ALIGN=\"RIGHT\">\n"); makeForm(urlencode($form), urlencode($query), $nrows, $max, $rightlower, $rightupper); echo ("</TD>\n"); } echo("</TR>\n</TABLE>\n</DIV>"); makeTable($result, $max, $lower, $upper); echo ("<DIV ALIGN=\"CENTER\">\n <TABLE WIDTH=\"90%\">\n<TR>\n"); if ($leftupper > 0) { echo ("<TD ALIGN=\"LEFT\">\n"); makeForm(urlencode($form), urlencode($query), $nrows, $max, $leftlower, $leftupper); echo ("</TD>\n"); } if ($rightlower <= $nrows) { echo ("<TD ALIGN=\"RIGHT\">\n"); makeForm(urlencode($form), urlencode($query), $nrows, $max, $rightlower, $rightupper); echo ("</TD>\n"); } echo("</TR>\n</TABLE>\n</DIV>"); } else { echo ("<BR>No sites with those characteristics were found, try again<BR>\n"); } if ($result) SQL_free_result($result); ?> And finally the closing HTML tags: </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. TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 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> If, for example, we performed a search for metal sites containing zinc or copper ions (zn, cu), with 4, 5, or 6 ligands, and with a resolution less than or equal to 2.0 Angstroms, from experimental data obtained by X-ray crystallography, the output will display as below: Here you can see the effect of using makeTable() for displaying the hits, and makeForm() for generating the results navigation button. Summary In this chapter, we looked at a real example of using PHP to connect to a database via the Web. We analyzed the characteristics of a web application, and shown examples on how to implement search TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com interfaces and processing scripts. But I've just scratched the surfaced of what you can do in terms of variable processing. You could, for example, write completely generic SQL generation functions by using a particular format for the variable names, for example naming all the variables with their type appended. Let us supposed that we have implemented an interface for entering data; the name of the variables passed to the script can be of the form: var1:num, var3:str, var4:date. We can now write a simple piece of code to generate the INSERT statement. Firstly, we would need to get the variables from the global array list $HTTP_POST_VARS, and process only those variables that have a type. These will be added to two parallel arrays, one containing the variable name and the other containing the appropriately quoted value: /* get all the variables */ $i=0; while(list($k,$v) = each($HTTP_GET_VARS)) { if (!strpos($k, ":")) { continue; } else { list($var[$i],$type[$i]) = explode(":",$k); if ($type[$i] == "str" || $type[$i] == "date") { $value[$i] = strtolower("\'" . addslashes($v) . "\'"); } else { $value[$i] = $v; } $i++; } } We can use these two arrays with the implode function in PHP, to generate a correct INSERT statement in a few lines: $query = "insert into " . $table . " (" . implode($var, ",") . ") values ("; $query .= stripslashes(implode($value, ",")) . ")"; When designing a web application with a database backend, the main steps that our scripts have to accomplish will be: ❑ Processing the form variables ❑ Generating the SQL query ❑ Displaying the results Generally the middle step is the one that can be problematic, and we have shown here some functions that allow us to deal with the creation of valid SQL statements. Bear in mind that these are not the only (or maybe the best) solutions, but the ones that were best suited to the MDB site requirements. I am sure that you will come up with much better scripts, and hope that the examples and information here can serve as a starting point in your experimentation with database-backed web applications. TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com A PHP Functions Apache Functions Function Returns Description apache_lookup_ uri(filename) Class Returns as a class information about the URI specified in filename apache_note(no te_name, [note_value]) String Retrieves or (if the second parameter is included) sets values from the notes tables getallheaders( ) Array Returns an array of the HTTP request headers virtual(filena me) Intege r Performs an Apache sub-request such as including a CGI script Array Functions Function Returns Description array( ) Array Creates and returns an array from the supplied parameters array_key s(array) Array Returns an array containing all the keys of the supplied array. Added in PHP 4.0. array_mer ge(arrays ) Array Merges and returns the supplied arrays. Added in PHP 4.0. array_pop (array) Mixed Pops and returns the last element from the end of the array. Added in PHP 4.0. array_pus h(array, variables ) Integer Pushes the supplied variables onto the end of the array; returns the number of elements in the array. Added in PHP 4.0. array_shi ft(array) Mixed Removes and returns the first element from the beginning of the array. Added in PHP 4.0. array_sli ce(array, Array Returns a sub-array from the specified array starting at the offset from the beginning (if positive) or end (if negative) TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com offset, [length]) of the array. If length is positive, it specifies the number of elements the returned array will contain; if negative, it specifies the offset from the end of the original array where the returned array will end. If length is omitted, all elements from offset to the end of the array will be returned. Added in PHP 4.0. array_spl ice(input , offset, [length], [replacem ent]) Array Removes a sub-array from the input array and replaces it with the elements of the replacement array. The offset and length arguments are the same as for array_slice(). Returns an array containing the removed elements. Added in PHP 4.0. array_uns hift(arra y, variables ) Integer Adds the supplied variables to the beginning of the array. Added in PHP 4.0. array_val ues(array ) Array Returns an array containing all the values of the supplied array. Added in PHP 4.0. array_wal k(array, function, [paramete r]) Integer Iterates through the supplied array, applying the named function to every element, passing the element's value as the first parameter and the key as the second; if a third parameter is required, it may be supplied by the parameter argument. arsort(ar ray) Void Sorts the supplied array in descending order, retaining the correlation between keys and values asort(arr ay) Void Sorts the supplied array in ascending order, retaining the correlation between keys and values compact(v arnames) Array Merges the variables and/or arrays named in the varnames argument into a single array. Added in PHP 4.0. count(arr ay) Integer Returns the number of elements in the supplied array current(a rray) Mixed Returns the current element in the supplied array each(arra y) Array Returns a four-element sub-array containing the key and value of the current element from the specified array. The key is contained in elements 0 and "key", the value in elements 1 and "value". end(array ) Void Sets the last element of the supplied array as the current element extract(a rray, [extract_ type], [prefix]) Void Import variables into the symbol table from the supplied array. The extract_type parameter specifies the action to take in case of a collision, and prefix specifies a string to be prefixed to the variable names. in_array( value, array) Boolea n Returns true if the specified value exists in the supplied array. Added in PHP 4.0. key(array ) Mixed Returns the key for the current element in the array ksort(arr ay) Integer Sorts the array by the keys of its elements, retaining the correlation between keys and values list(vari ables) Void Assigns the supplied variables as if they were an array next(arra y) Mixed Moves the array pointer one element forward and returns the next element, or false if the end of the array is reached pos(array ) Mixed Returns the current element from the supplied array TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... current script getmypid() Integer Returns the current process ID for PHP getmyuid() Integer Returns the UID for the PHP script's owner getrusage([who ]) Array Returns the current resource usage phpinfo() Integer Output information about the current state and configuration of PHP phpversion() String Returns the current version of PHP putenv(value) Void Sets the value of an environment variable set_magic_quot... PHP Options and Information Function Returns Description error_log(mess age, message_type, [destination], [extra_headers ]) Integer Sends an error message to the specified destination error_reportin g([level]) Integer Sets or returns the error reporting level extension_load ed(name) Boolean Indicates whether the named extension is loaded get_cfg_var(va r) String Returns the value of the specified PHP. .. r_handle) Resets the directory stream with the specified handle to the beginning of the directory Dynamic Loading Functions Function dl(extensi on) Returns Description Integer Used to load the specified PHP extension at runtime Program Execution Functions Function Returns Description escapeshell cmd(command ) String Escapes shell metacharacters in the specified command exec(comman d, [array], [return_var... String Creates a unique temporary filename in the specified directory touch(filena me, time) Integer Sets the modification time of the specified file to the specified time umask([mask] ) Integer Sets PHP' s umask and returns the old umask unlink(filen ame) Integer Deletes the specified file TEAM FLY PRESENTS Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com HTTP Functions Function... specifies the number of postscript points in a unit in the coordinate system cpdf_place_inline_ima ge(pdfdoc, image, x, y, angle, width, height, x-scale, yscale, [mode]) Void Places on the page the specified PHP- created image, which is placed at the specified x, y coordinates, rotated at angle degrees, with the specified height and width and x- and yscaling The units are the page default if mode is 0 or unsupplied;... Indicates whether the named extension is loaded get_cfg_var(va r) String Returns the value of the specified PHP configuration option get_current_us er() String Returns the name of the owner of the current PHP script get_magic_quot es_gpc() Long Returns the current setting for magic_quotes_gpc get_magic_quot es_runtime() Long Returns the current setting for magic_quotes_runtime TEAM FLY PRESENTS Simpo PDF... String Formats a local time/date according to the current locale; if no timestamp is supplied, the current time is used time() Integer Returns current UNIX timestamp (number of seconds since midnight 1/1/ 197 0 GMT) Database (dbm-style) Abstraction Layer Functions Function Returns Description dba_close(han dle) Void Closes the database with the specified handle dba_delete(ke y, handle) Boolean Deletes the... the value of an environment variable set_magic_quot es_runtime(set ting) Long Enables or disables magic_quotes_runtime set_time_limit (seconds) Void Sets the limit for the maximum length of time that a PHP script can take to execute Informix Functions Function Returns Description ifx_affected_r ows(result_id) Integer Returns the number of rows affected by the query ifx_blobinfile _mode(mode) Void Sets . buttons * * Written by: Jesus M. Castagnetto * Created on: Feb 01, 199 9 */ /* included scripts are in the /php_ inc/ dir */ require ("sql.inc"); require ("tables.inc");. the pdbsearch .php script above: /* Get the results and process */ $php_ errormsg=""; @$result = SQL_query($query,$link); $msqlerrormsg = SQL_error(); if ( $php_ errormsg!=""). ("</B></BODY></HTML>"); fwrite ($dbgfp, "#ERROR IN QUERY: PHP= " . $php_ errormsg . " mSQL=" . $msqlerrormsg . " "); fclose ($dbgfp);