★ wanayoo — archive 1999 http://phpbuilder.com/columns/jesus19990308-2.php3Nouvelle recherche | Portail wanayoo

    



Search:

Keywords:

  

Here I will show a more complex example, which should make life easier for the user (who says the developer's life should be easy too :).

Example 2: Parsing and querying

In the first part of this article we made a straight, no syntax checking, SQL form interface to the database.

Now, I know that some people do not like to write raw SQL, so we will make a more "user-friendly" HTML form:

query_form.html

<HTML> 
<TITLE>Query form</TITLE> 
<BODY BGCOLOR="white"> 
<FORM ACTION="/old?u=http%3A%2F%2Fphpbuilder.com%2Fcolumns%2Fdo_query.php3&y=1999" METHOD="POST"> 

Find all documents in which:<BR> 

the title contains any of these keywords: (*) 
    <INPUT TYPE="text" NAME="title" SIZE=40>i<BR> 
AND<BR> 
was written by any of the following: (check as many as needed)<BR> 
<INPUT TYPE="checkbox" NAME="author[]" VALUE="Mark Musone"> Mark Musone 
<INPUT TYPE="checkbox" NAME="author[]" VALUE="Mattias Nilsson"> Mattias Nilsson 
<INPUT TYPE="checkbox" NAME="author[]" VALUE="Rasmus Lerdorf"> Rasmus Lerdorf 
<INPUT TYPE="checkbox" NAME="author[]" VALUE="Tim Perdue"> Tim Perdue  
<BR> 
AND<BR> 
was published on or after the year: 
<SELECT NAME="pubyear"> 
<OPTION VALUE="1999" SELECTED>1999</OPTION> 
<OPTION VALUE="2000">2000</OPTION> 
<OPTION VALUE="2001">2001</OPTION> 
</SELECT> 
<BR> 
<INPUT TYPE="submit" NAME="submit" VALUE="Submit query"> 
</FORM> 
(*) <I>Note</I>: You can enter a comma separated list of keywords, e.g.  
"mail,imap,logging" will search for full or partial matches to: 
<TT>mail OR imap OR logging</TT> in the title of the article. 
</BODY> 
</HTML> 

To make things interesting, the form will allow the input of 3 different types of variables:

  • a list of optional keywords for the title (using comma as a separator),
  • a series of checkboxes allowing for multiple selections (treated as an array),
  • and a drop down allowing selection of a single option.

Allowing for the input of a list, makes it easy to search for multiple keywords, e.g. if I want to search for articles with "mail" or "imap" in the title, I will write: "mail,imap".

To handle the form above, we are going to reuse the code from the script "do_sql.php3" (isn't recycling good), adding code to parse the title, author, and publication date:

do_query.php3

<HTML>  
<HEAD>  
    <TITLE>Results from query</TITLE>  
</HEAD>  
<BODY BGCOLOR="white">  
<H1 ALIGN="center">Query Results</H1>  
<? 
    
/* Parsing functions 
     * The list parsing function could be defined in terms of an array 
     * parsing function, but I decided to do different implementations 
     * to show how defaulted parameters can be used as flags 
     * --- Jesus M. Castagnetto 
     */
 

    
/* parseList: 
     * $fieldcond = the SQL condition for the input items 
     * $slist = the string containing the list of input items 
     * $sep = the list separator, defaults to a single comma 
     * $q1 and $q2 are the quote string to be pre/appended to the list item 
     */
 
     function parseList ($fieldcond,$slist,$sep=  ",",$q1=  "'",$q2=  "'" )  { 
        $tarr = explode ($sep,$slist ) ; 
        $out = $fieldcond . $q1 . $tarr[0] . $q2 ; 
         if  (count ($tarr ) > 1 )  { 
             for  ($i=1 ; $i<count ($tarr ) ; $i++ )  { 
                 if  ($tarr[$i] !=   "" )  { 
                    $out .=   " or " . $fieldcond . $q1 . $tarr[$i] . $q2 ; 
                 } 
             } 
         } 
        return   "( " . $out .   " )" ; 
     } 

     
/* parseArray: 
     * $field = the field for the input items 
     * $alist = the array containing the input items 
     * $comp = the comparison to be used for the SQL string 
     * $quoted = whether the items need to be single quoted 
     */
 
     function parseArray ($field,$alist,$comp=  "=",$quoted=1 )  { 
         if  ($quoted )  { 
            $q1 = $q2 =   "'" ; 
            $comp = strtolower ($comp ) ; 
             if  ($comp ==   "like" || $comp ==   "clike" )  { 
                $q1 =   "'%" ; $q2 =   "%'" ; 
             } 
         }  else  { 
            $q1 = $q2 =   "" ; 
         } 
        $out = $field.   " " . $comp .   " " . $q1 . $alist[0] . $q2 ; 
         if  (count ($alist ) > 1 )  { 
             for  ($i=1 ; $i<count ($alist ) ; $i++ )  { 
                 if  ($alist[$i] !=   "" )  { 
                    $out .=   " or " . $field.   " " . $comp .   " " . $q1 . $alist[$i] . $q2 ; 
                 } 
             } 
         } 
        return   "( " . $out .   " )" ; 
     } 

    
/* title is a list */  
     if  ($title )  { 
        $q_title = parseList (  "title clike ",strtolower ($title ) "," "'%" "%'" ) ; 
     } 

     
/* author is an array */  
     if  ($author )  { 
        $q_author = parseArray (  "author",$author ) ; 
     } 

     
/* publication year - lower limit */  
    $q_pubyear =  ($pubyear ?   "published >= ".$pubyear.  "0101" :   "" ) ; 
     
     
/* build the query string */  

    $qstring =   " title,author,published,length FROM article WHERE " ; 
    $qstring .= $title ? $q_title :   "" ; 
    $qstring .=  ($title && $author ) ?   " AND " :   "" ; 
    $qstring .= $author ? $q_author :   "" ; 
    $qstring .=  ( ($title && $pubyear ) ||  ($author && $pubyear ) ) ?   " AND " :   "" ; 
    $qstring .= $pubyear ? $q_pubyear :   "" ; 
    $qstring .=   " ORDER BY author,published" ; 

     
/* build message string */  
    $mstring =   "You searched on articles " ; 
    $mstring .= $title ?   " with the words ".$title.  " in the title; " :   "" ; 
    $mstring .= $author ?   " written by ".implode ($author,  " OR " ) :   "" ; 
    $mstring .= $pubyear ?   " published on or after ".$pubyear.  "." :   "" ; 


     
/* Show query string */  
     echo  (  "Saving your query for debugging purposes<BR>\n" ) ;  
     echo  (  "<B>$mstring</B><BR>\n" ) ;  
     
     
/* Uncomment the following line if you want to show the SQL string */  

     
// echo ("The parsed SQL string was: $qstring<BR>\n" ); 

    $link = msql_pconnect ( ) ;  
    $res = msql (  "documents",   "select ".$qstring, $link ) ;   
     if  ($res )  {  
        $nrows = msql_num_rows ($res ) ;  
        $nfields = msql_num_fields ($res ) ;  
        printf (  "and it found: <B>%d rows</B>\n",$nrows ) ;  
     }  else  { 
         echo  (  "<BR>Your query did not find any matches. Try again<BR>\n" ) ;  
     } 
     
     
/* save info into a file */    
    $datestamp = date (  "Y-m-d H:i:s",time ( ) ) ;  
    $fp = fopen (  "query_form.log",   "a+" ) ;  
    fwrite ($fp,    "DATE: $datestamp\n" ) ;  
    fwrite ($fp,    "QUERY: select $qstring\n" ) ;  
    fwrite ($fp, sprintf (  "RESULT: %d rows\n\n",$nrows ) ) ;  
    fclose ($fp ) ;  
     
?>
  
<TABLE BORDER>  
<?  
     if  ($res )  {  
         echo (  "\n<TR BGCOLOR=\"#E0FFFF\">" ) ;  
         for  ($i=0 ;$i<$nfields ;$i++ )  {  
            $fname = msql_fieldname ($res,$i ) ;  
             echo  (  "<TH>$fname</TH>" ) ;  
         }  
         echo (  "</TR>" ) ;  
        $color =    "#D3D3D3" ;  
         for  ($i=0 ;$i<$nrows ;$i++ )  {  
             if  ( ($i % 2 ) == 0 )  {  
                 echo  (  "\n<TR>" ) ;  
             }  else  {  
                 echo  (  "\n<TR BGCOLOR=$color>" ) ;  
             }  
            $rowarr = msql_fetch_row ($res ) ;  
             for  ($j=0 ;$j<$nfields ;$j++ )  {  
                $val = $rowarr[$j] ;  
                 if  ($val ==    ""  )  {  
                    $val = stripslashes (  "&nbsp\;" ) ;  
                 }  
                 echo  (  "<TD>".chop ($val ) "</TD>" ) ;  
             }  
             echo  (  "</TR>" ) ;  
         }  
     }  
?>
  
</TABLE>  
</BODY>  
</HTML>

In the script above we have two general parsing functions that return a valid SQL comparison statement, these can be extended to cases in which we want to allow the use of operators such as: AND, OR, NOT, etc.

In this script, you saw the use of default values for some of the parsing functions parameters; this allows the invokation of the function with a variable number of said parameters. You will only need to specify the defaulted ones if you need to change them.

We will use the form to search for the keywords "image,reading,creating", in the title of articles written by Matias or Mark or Rasmus, with a publication date of 1999 or later. This will generate the following result:

Query Results

Saving your query for debugging purposes
You searched on articles with the words image,reading,creating in the title; written by Mark Musone OR Mattias Nilsson OR Rasmus Lerdorf published on or after 1999.
and it found: 3 rows
titleauthorpublishedlength
IMAP Mail Reading With PHP3Mark Musone19990207200
Creating your own logfileMattias Nilsson19990302200
Image Creation With PHPRasmus Lerdorf19990124200

The form and the handling script can be modified to allow searching on more variables, or to search for keywords in the title and/or the body of the article, or even to retrieve a keyword matched in the body in a context (for example, get the 2 lines above and below the matching line).

Using a form like this gives control on the information the user can access, and reduces the number of possible SQL queries. If you type straight SQL, you can always make a query that can take (for practical purposes) and infinite amount of time to finish, something you may not want to happen in your site.

Where to go from here

If you went through the examples and experimented a bit, you will start having more and better ideas on how to use this newfound flexiblity in your site design. You should be able to make more sophisticated interfaces, allowing the use of more complex logical expressions, or even create the entire query interface based on reading the structure of the database, on-the-fly. No limit to what you can do, just remember to have fun and don't get discouraged.

Paraphrasing an old saying: "Inspiration is 10% of the work, debugging the remaining 90%" (or something like that).

You should check the examples sources available from the "Sample Code" link in this site. In particular I am impressed by the work done to make the PHP base library, which now includes the OOHForms module (highly recommended).

You can get the (IMHO) best web server available from the Apache Project site, and obtain good SQL databases such as: mSQL, MySQL, and PostgreSQL from their respective sites. And of course, keep the PHP manual handy at all times.

You are now on your own pal!
Good luck.
=== Jesús.



 

Sample Code | Columns | Mail Archive | Support | Get Started! | Links | Contribute!

Contact (non support questions)

By viewing these pages you agree to the Legal Terms of Service.

 

 

 

  Geocrawler.com | GoToCity.com | DirectriCity.com | PHPBuilder.com | The Des Moines City.net