+ Reply to Thread
Results 1 to 6 of 6

Thread: Building a Big Project, Part 6

  1. #1
    Join Date
    Jul 2006
    Posts
    16,491
    Blog Entries
    75
    Rep Power
    143

    Building a Big Project, Part 6

    Note: this is part of a series.
    The first part is here: Building a Big Project, Part 1
    The second part is here: Building a Big Project, Part 2
    The third part is here: Building a Big Project, Part 3
    The fourth part is here: Building a Big Project, Part 4
    The fifth part is here: Building a Big Project, Part 5

    In the last tutorial, I cheated. I showed the finished init.php without showing you the flawed version I had originally.
    finished init.php:
    Code:
    <?php
    session_start();
    
    //define root URLs
    $root = "http://localhost/MyFiction/";
    $sroot = "http://localhost/MyFiction/";
    
    //open database.
    //This is going to store everything, so we might as well have our connection now!
    if (!($sourcedb = mysql_connect('localhost:3306','root','')))
    {
    die('Database error: could not connect!');
    }
    if (!mysql_select_db('MYFICTION',$sourcedb))
    {
    die('Cannot use database!');
    }
    
    //set flags for ValString()
    $vsNone=0;
    $vsStrict=1;
    $vsHTML=2;
    $vsSQL=4;
    $vsEmail=8;
    //Validation function
    //$vsStrict forces a test failure to return "", otherwise the functions will attempt to make it valid.
    //
    function ValString($instr, $flags, $len=-1)
    {
    //reintroduce flags to function scope
    $vsNone=0;
    $vsStrict=1;
    $vsHTML=2;
    $vsSQL=4;
    $vsEmail=8;
    //test length
    if (strlen($instr)>$len && $len!=-1)
    {
    if ($flags & $vsStrict)
    $instr="";
    else
    $instr=substr($instr,1,$len);
    }
    //test valid single email address
    if ($flags & $vsEmail)
    {
    if(!preg_match('/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/', $instr) && ($flags & $vsStrict))
    $instr="";
    }
    //test for invalid SQL characters
    if ($flags & $vsSQL)
    {
    if(($flags & $vsStrict) && (pos($instr,"'") || pos($instr,"`") || pos($instr,'"')))
    $instr="";
    else
    {
    $instr=str_replace("'","''",$instr);
    $instr=str_replace("`","``",$instr);
    $instr=str_replace('"','""',$instr);
    }
    }
    return $instr;
    }
    ?>
    broken init.php:
    Code:
    <?php
    session_start();
    
    //define root URLs
    $root = "http://localhost/MyFiction/";
    $sroot = "http://localhost/MyFiction/";
    
    //open database.
    //This is going to store everything, so we might as well have our connection now!
    if (!($sourcedb = mysql_connect('localhost:3306','root','')))
    {
    die('Database error: could not connect!');
    }
    if (!mysql_select_db('MYFICTION',$sourcedb))
    {
    die('Cannot use database!');
    }
    
    //set flags for ValString()
    $vsNone=0;
    $vsStrict=1;
    $vsHTML=2;
    $vsSQL=4;
    $vsEmail=8;
    //Validation function
    //$vsStrict forces a test failure to return "", otherwise the functions will attempt to make it valid.
    //
    function ValString($instr, $flags, $len=-1)
    {
    //test length
    if (strlen($instr)>$len && $len!=-1)
    {
    if ($flags & $vsStrict)
    $instr="";
    else
    $instr=substr($instr,1,$len);
    }
    //test valid single email address
    if ($flags & $vsEmail)
    {
    if(!preg_match('/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/', $instr) && ($flags & $vsStrict))
    $instr="";
    }
    //test for invalid SQL characters
    if ($flags & $vsSQL)
    {
    if(($flags & $vsStrict) && (pos($instr,"'") || pos($instr,"`") || pos($instr,'"')))
    $instr="";
    else
    {
    $instr=str_replace("'","''",$instr);
    $instr=str_replace("`","``",$instr);
    $instr=str_replace('"','""',$instr);
    }
    }
    return $instr;
    }
    ?>
    It took me a while to figure out that global variables don't get brought into function scope. It was a little bit irritating, to say the least. What was even more annoying were the gyrations I went through to figure out what was happening. I ended up polluting join.php with debugging messages as I worked through the problem. There has to be a better way to deal with this.

    Welcome to testing! Maybe it's because I just finished reading The Pragmatic Programmer, or because I just had to fix a bug that I thought I had fixed a couple months ago at work, or because I know where this function is going, but testing is really on my mind right now.

    This type of function just SCREAMS for unit testing. I'm going to create a folder inside my main folder called Tests. That is where I'll create mini-program files for doing unit testing. I don't anticipate having a lot of them, but it should be enough to get me by. Our basic test method looks like this:
    tests\valstring.php:
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
    <title>Test ValString Function</title>
    </head>
    <body>
    <?php
    include("../init.php");
    include("../close.php");
    ?>
    </body>
    </html>
    We'll beef this basic file up with a little data, and have fun!
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
    <title>Test ValString Function</title>
    </head>
    <body>
    <?php
    include("../init.php");
    $rawtext = array("boring","<h>HTML</h>","don't use in SQL","email@nowhere.com","<not>e'mail<safe>@garbage.junk")
    %>
    <table>
    <thead>
    <tr>
    <td>raw text</td><td>length</td><td>flags</td><td>result</td>
    </tr>
    </thead>
    <tbody>
    </tbody>
    </table>
    <%
    include("../close.php");
    ?>
    </body>
    </html>
    OK, that wasn't very fun. But it should give you an idea of where this is going. We'll just add a little logic to finish off our simple table and...
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
    <title>Test ValString Function</title>
    <link rel="stylesheet" type="text/css" href="Myfiction.css" />
    </head>
    <body>
    <?php
    include("../init.php");
    $rawtext = array("boring","<h>HTML</h>","don't use in SQL","email@nowhere.com","<not>e'mail<safe>@garbage.junk")
    ?>
    <table>
    <thead>
    <tr>
    <td>raw text</td><td>length</td><td>flags</td><td>result</td>
    </tr>
    </thead>
    <tbody>
    <?php
    foreach($rawtext as $string) {
    for($flags=0;$flags<16;$flags++){
    for($length=-1;$length<40;$length+=5){
    $output="<tr><td>" . htmlspecialchars($string) . "</td><td>" . $length . "</td><td>";
    if ($flags==0){
    $output .= " vsNone ";
    }
    if ($flags&$vsStrict){
    $output .= " vsStrict ";
    }
    if ($flags&$vsHTML){
    $output .= " vsHTML ";
    }
    if ($flags&$vsSQL){
    $output .= " vsSQL ";
    }
    if ($flags&$vsEmail){
    $output .= " vsEmail ";
    }
    $output .= "</td><td>" . htmlspecialchars(ValString($string,$flags,$length)) . "</td>";
    echo "$output";
    }
    }
    }
    ?>
    </tbody>
    </table>
    <?php
    include("../close.php");
    ?>
    </body>
    </html>
    If you're one of those people who just reads these things and goes "ooh, ahh!", stop! Run the above code with our init.php. You'll need close.php again:
    Code:
    <?php
    //close database if still open
    if ($sourcedb)
    {
    mysql_close($sourcedb);
    }
    ?>
    What we get is a TON of the following:
    Code:
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    
    Warning: Wrong parameter count for pos() in C:\wamp\www\MyFiction\init.php on line 53
    !

    It's the darnedest thing! I never saw that before! It seems I was using the pos() function instead of the strpos() function! How about that? Making a quick substitution and rerunning it now gives me:
    Code:
    raw text    length    flags    result
    boring    -1    vsNone     boring
    boring    4    vsNone     orin
    boring    9    vsNone     boring
    boring    14    vsNone     boring
    boring    19    vsNone     boring
    as the first few lines. Notice that "orin"? That's not right! It seems that substr() in PHP is 0-based instead of 1-based (the first language I've seen that happen in)!

    Finally, if you scroll down on the results a ways, you'll see a seciont like this:
    Code:
    <h>HTML</h>    -1     vsHTML     <h>HTML</h>
    <h>HTML</h>    4    vsHTML     <h>H
    <h>HTML</h>    9    vsHTML     <h>HTML</
    <h>HTML</h>    14    vsHTML     <h>HTML</h>
    <h>HTML</h>    19    vsHTML     <h>HTML</h>
    <h>HTML</h>    24    vsHTML     <h>HTML</h>
    If you'll recall, we didn't do anything to deal with HTML handling. We can add that now. Our final init.php ends up being:
    Code:
    <?php
    session_start();
    
    //define root URLs
    $root = "http://localhost/MyFiction/";
    $sroot = "http://localhost/MyFiction/";
    
    //open database.
    //This is going to store everything, so we might as well have our connection now!
    if (!($sourcedb = mysql_connect('localhost:3306','root','')))
    {
    die('Database error: could not connect!');
    }
    if (!mysql_select_db('MYFICTION',$sourcedb))
    {
    die('Cannot use database!');
    }
    
    //set flags for ValString()
    $vsNone=0;
    $vsStrict=1;
    $vsHTML=2;
    $vsSQL=4;
    $vsEmail=8;
    //Validation function
    //$vsStrict forces a test failure to return "", otherwise the functions will attempt to make it valid.
    //
    function ValString($instr, $flags, $len=-1)
    {
    //reintroduce flags to function scope
    $vsNone=0;
    $vsStrict=1;
    $vsHTML=2;
    $vsSQL=4;
    $vsEmail=8;
    //test length
    if (strlen($instr)>$len && $len!=-1)
    {
    if ($flags & $vsStrict)
    $instr="";
    else
    $instr=substr($instr,0,$len);
    }
    //test valid single email address
    if ($flags & $vsEmail)
    {
    if(!preg_match('/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/', $instr) && ($flags & $vsStrict))
    $instr="";
    }
    //test for invalid SQL characters
    if ($flags & $vsSQL)
    {
    if(($flags & $vsStrict) && (strpos ($instr,"'") || strpos ($instr,"`") || strpos ($instr,'"')))
    $instr="";
    else
    {
    $instr=str_replace("'","''",$instr);
    $instr=str_replace("`","``",$instr);
    $instr=str_replace('"','""',$instr);
    }
    }
    if ($flags & $vsHTML)
    {
    if(($flags & $vsStrict) && $instr !=htmlspecialchars($instr))
    $instr="";
    else
    {
    $instr=htmlspecialchars($instr);
    }
    }
    return $instr;
    }
    ?>
    This was a pretty simple test, with visual inspection instead of automatic inspection. On the good side, we were able to catch two bugs and on piece of unimplemented functionality! If we're going to use something like ValString() as a core piece of our product moving forward, it is very important to ensure it is working correctly.

    In addition to unit testing, you should also perform functional testing. I was able to find one tool that looks very promising: a FireFox pluging called Molybdenum. I haven't had a chance to try it out yet, but it should give us the ability to create rigorous tests that will help validate functionality works, and continues to work.
    Last edited by WingedPanther; 02-23-2011 at 05:24 PM.
    Programming is a branch of mathematics.
    My CodeCall Blog | My Personal Blog

  2. CODECALL Circuit advertisement
    Join Date
    Always
    Posts
    Many

     
  3. #2
    Join Date
    Aug 2009
    Location
    ~/
    Posts
    918
    Rep Power
    19

    Re: Building a Big Project, Part 6

    Thanks for breaking it down in detail.

    You're the man... +rep
    Awesome job!!

  4. #3
    Jordan Guest

    Re: Building a Big Project, Part 6

    Nice read! You can use the global keyword to bring global functions into scope.

    Code:
    function ValString($instr$flags$len=-1)
    {
      
    //reintroduce flags to function scope
      
    global $vsNone$vsStrict$vsHTML,  $vsSQL$vsEmail
    +rep!

  5. #4
    Join Date
    Jul 2006
    Posts
    16,491
    Blog Entries
    75
    Rep Power
    143

    Re: Building a Big Project, Part 6

    Thanks for the info, Jordan! That's exactly what I needed. I should probably rework things so that there's a single array of flags. That way I can update it in the global and have it work correctly in ValString without changes.
    Programming is a branch of mathematics.
    My CodeCall Blog | My Personal Blog

  6. #5
    Join Date
    Jul 2006
    Location
    Amherst, New York, United States
    Posts
    6,277
    Blog Entries
    26
    Rep Power
    20

    Re: Building a Big Project, Part 6

    The idea of polluting the global namespace makes me want to slit my wrists.

  7. #6
    Join Date
    Jul 2006
    Posts
    16,491
    Blog Entries
    75
    Rep Power
    143

    Re: Building a Big Project, Part 6

    That's one of the things that irritates me about Delphi, actually. Technically, every form is its own class, but you feel like you're dealing with a global space. I suppose I could create a validation class, and store the flags and functions in it. To be honest, I'm feeling too lazy to mess with learning PHP OOP right now. This project feels like procedural will do the job just fine.
    Programming is a branch of mathematics.
    My CodeCall Blog | My Personal Blog

+ Reply to Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Advanced Building a Big Project, Part 7
    By WingedPanther in forum PHP Tutorials
    Replies: 4
    Last Post: 10-04-2009, 04:56 PM
  2. Advanced Building a Big Project, Part 4
    By WingedPanther in forum PHP Tutorials
    Replies: 4
    Last Post: 09-13-2009, 03:51 PM
  3. Advanced Building a Big Project, Part 1
    By WingedPanther in forum PHP Tutorials
    Replies: 15
    Last Post: 09-13-2009, 03:49 PM
  4. Advanced Building a Big Project, Part 3
    By WingedPanther in forum PHP Tutorials
    Replies: 5
    Last Post: 09-13-2009, 03:49 PM
  5. Advanced Building a Big Project, Part 2
    By WingedPanther in forum PHP Tutorials
    Replies: 6
    Last Post: 09-13-2009, 02:36 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts