Hello!

While it's certainly good practice to sanitize input before its queried in a database, is it good practice to sanitize input that's merely repopulated within the form's controls, ala sticky forms?

Here's what I mean:

Imagine this sticky text box repopulating input without any filtering on your program's part:

<input type="text" name="name" value="<?php if($_POST['name']) echo $_POST['name']; ?>" />

Versus this sticky text box repopulating filtered input:

<input type="text" name="name" value="<?php if($_POST['name']) echo filter_user_input($_POST['name']); ?>" />

Example of filter_user_input() function:

<?php
function filter_user_input($data) {
  $data = trim($data);
  $data = strip_tags($data);
  $data = htmlentities($data);
  $data = mysql_real_escape_string($data);
  $data = trim($data);
  return $data;
}
?>

Is it good practice to sanitize data even if it's merely repopulated in a text box? Or is it merely personal preference when it comes to sticky forms?

    Well, sanitizing data for output to the client and for input to a database are two different things.

    You are displaying some text within a textbox. Suppose the text contains double quotes, now your output will be incorrect, since it will cut off the value portion (and you will get malformed HTML). As such, you should write:

    <input type="text" name="name" value="<?php if (isset($_POST['name'])) echo htmlentities($_POST['name']); ?>" />

    You can use trim() too (only once is needed), as in your filter_user_input() function, but mysql_real_escape_string() and strip_tags() would be unnecessary.

    Nonetheless, if you are inserting $_POST['name'] into a MySQL database using the API, you should still use mysql_real_escape_string().

      Generally, there are three different processes here to consider.

      1: Any inputs from the user should be validated to be within an allowable range, size, etc.; as well as not including any "illegal" data (restricted characters, HTML tags, whatever you do not want to allow). If anything causes an input to be invalid, you should return an error and have the user fix it, not just transparently remove it without the user realizing their inputs have been modified.

      1. Outputting the data to your database requires filtering for characters that have special meaning in SQL. Thus the use of mysql_real_escape_string() or similar methods to escape such characters. It does not remove them, it just removes their special meaning within SQL.

      2. Outputting the data to the browser. This is where htmlentities() comes into play, assuming that you do not want any characters with special meaning as far as HTML is concerned to be output.

      Items 2 and 3 are separate issues. If you combine them as you do in your filter_user_input() function, you are trying to do two separate things in that one function. Besides reducing the modularity of your code, it also may not be desired from a data standpoint. Any text the user enters will now be stored in your database with HTML character entities for any special characters which it converts. Now what happens if you decide you have a use for that data other than simple output to a web page? (At best, you'll have to un-htmlentities() it via html_entity_decode().)

        Thank you for putting things in perspective, laserlight and NogDog.

        Based on your feedback, I decided to split my function in two:

        This function, sanitize_input(), will be used for formatting data before it's outputted to my database:

        <?php
        function sanitize_input($data, $maxlength = 255) {
          $data = strip_tags($data);
          $data = mysql_real_escape_string($data);
          $data = trim($data);
          $data = substr($data, 0, $maxlength);
          return $data;
        }
        ?>

        And this function, format_output(), will be used for formatting data before it's outputted to the client's browser:

        <?php
        function format_output($data) {
          $data = htmlentities($data);
          $data = trim($data);
          return $data;
        }
        ?>

        Thanks again!

          If you do the substr() thing last on your input data, you may be stripping out legitimate data since mysql_real_escape_string() may be adding back-slashes to escape certain characters, but those back-slashes are not actually part of the text that will get stored in the DB.

          <?php
          function sanitize_input($data, $maxlength = 255) {
            $data = trim($data);
            if(get_magic_quotes_gpc())
            {
              $data = stripslashes($data);
            }
            $data = substr($data, 0, $maxlength);
            $data = mysql_real_escape_string($data);
            return $data;
          }
          ?>
          

            That's a good point. I didn't even consider that.

            I will make your recommended changes to my sanitize_input() function.

              2 months later
              NogDog wrote:

              ... mysql_real_escape_string() may be adding back-slashes to escape certain characters, but those back-slashes are not actually part of the text that will get stored in the DB.

              To NogDog. About mysql_real_escape_string (mres). Hope you can elaborate further. If the back slashes are not stored in the DB, does it mean that mysql knows that its stored somewhere else. My impression was that mres's job was just to simply add a back slash and send it peacefully to the DB so that in future it does not harm anybody. Guess I have much more to understand about mres.

              Thanks.

                If the back slashes are not stored in the DB, does it mean that mysql knows that its stored somewhere else.

                No, the backslashes are merely to denote "escape the next character". Consider the same effect in a PHP string:

                echo "This is a \"string\"";

                You would expect the output:

                This is a "string"

                Not:

                This is a \"string\"

                  LL's example is a good analogy. The back-slashes inserted by mrse are, essentially, information-only characters for the MySQL SQL parser, not for the data itself; just as those in a PHP command within a double-quoted string literal are instructions to the PHP parser, not part of the actual string data.

                    To LL and NogDog. Thanks for your patience. Your answers helped answered some questions which are not covered in my SAMPs 24 hours book or are hidden somewhere in google. I hope you take this with a bit of humor and as a sign of progress against the dark forces.

                    Thanks

                      4 days later

                      Hi LL and NogDog again,

                      I believe this query is too basic for a new thread, lol. May we please continue here. Could you please explain the detailed working of strtr() in the code below. This particular code is from the Owasp sanitize.inc.php script. I have shortened it a bit for covenience here. Just can't figure out the numerous question marks.

                      strtr($string,
                      "???????¥µÀÁÂÃÄÅÆ",
                      "SOZsozYYuAAAAAAA");

                      Thanks again.

                        a month later

                        Hi
                        I'm grateful for your queries and responses.

                        I'm new to php/mysql and am trying to test that form fields have been filled out and then sanitize it for storage to db and for email. I'm confused about the logic flow and which should happen first, output to user or prepping for db...I'm also not sure how I should handle errors with the approach outlined in your posts...

                        What I have so far is included just below (some js validation and then some php - ideally the data should be fully validated but not sure where to put the others in😕 and the approach I think recommended here is just below mine. I would really appreciate any insights/ recommendations you can offer!

                                    <title>Contact Form</title>
                        <style type="text/css">
                        
                        
                        .errmsg {
                        	font-family: "Courier New", Courier, mono;
                        	font-size: 12px;
                        	font-weight: bolder;
                        	color: #CC0000;
                        }
                        
                        </style>
                        <script language="JavaScript">
                        function checkForm()
                        {
                        	var cname, cemail, csubject, cmessage;
                        	with(window.document.msgform)
                        	{
                        		cfname    = fname;
                        		clname    = lname;
                        		cemail   = email;
                        		csubject = subject;
                        		cmessage = message;
                        	}
                        
                        if(trim(cfname.value) == '')
                        {
                        	alert('Please enter your first name');
                        	cname.focus();
                        	return false;
                        }
                        	else if(trim(clname.value) == '')
                        {
                        	alert('Please enter last name');
                        	cemail.focus();
                        	return false;
                        }
                        else if(trim(cemail.value) == '')
                        {
                        	alert('Please enter your email');
                        	cemail.focus();
                        	return false;
                        }
                        
                        else if(!isEmail(trim(cemail.value)))
                        {
                        	alert('Email address is not valid');
                        	cemail.focus();
                        	return false;
                        }
                        	else if(trim(csubject.value) == '')
                        {
                        	alert('Please enter a subject');
                        	cemail.focus();
                        	return false;
                        }
                        
                        else if(trim(cmessage.value) == '')
                        {
                        	alert('Please enter your message');
                        	cmessage.focus();
                        	return false;
                        }
                        else
                        {
                        	cfname.value    = trim(cfname.value);
                        	clname.value    = trim(clname.value);
                        	cemail.value   = trim(cemail.value);
                        	cemail.value   = trim(csubject.value);
                        	cmessage.value = trim(cmessage.value);
                        	return true;
                        }
                        }
                        
                        /*
                        Strip whitespace from the beginning and end of a string
                        Input : a string
                        */
                        function trim(str)
                        {
                        	return str.replace(/^\s+|\s+$/g,'');
                        }
                        
                        /*
                        Check if a string is in valid email format. 
                        Returns true if valid, false otherwise.
                        */
                        function isEmail(str)
                        {
                        	var regex = /^[-_.a-z0-9]+@(([-_a-z0-9]+\.)+(ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|in|info|int|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$/i;
                        	return regex.test(str);
                        }
                        </script>
                        
                        <?
                        include(//database cxn file here);
                        
                        $cxn = @ConnectToDb($dbServer, $dbUser, $dbPass, $dbName);
                        
                        $errmsg  = ''; // error message
                        $fname   = ''; // sender's first name
                        $lname   = ''; // sender's last name
                        $email   = ''; // sender's email addres
                        $subject = ''; // message subject
                        $comment = ''; // the message itself
                        
                        if(isset($_POST['send']))
                        {
                        	$fname   = $_POST['fname'];
                        	$lname   = $_POST['lname'];
                        	$email   = $_POST['email'];
                        	$subject = $_POST['subject'];
                        	$comment = $_POST['comment'];
                        
                        
                        
                        if(trim($fname) == '')
                        {
                        	$errmsg = 'Please enter your first name';
                        } 
                        	else if(trim($lname) == '')
                        {
                        	$errmsg = 'Please enter your last name';
                        }
                        else if(trim($email) == '')
                        {
                        	$errmsg = 'Please enter your email address';
                        }
                        else if(!isEmail($email))
                        {
                        	$errmsg = 'Your email address is not valid';
                        }
                        else if(trim($subject) == '')
                        {
                        	$errmsg = 'Please enter message subject';
                        }	
                        else if(trim($comment) == '')
                        {
                        	$errmsg = 'Please enter your message';
                        }
                        
                        if($errmsg == '')
                        
                        {
                        	$myQuery = "insert into users (fname, lname, email, subject, comment) values ('{$fname}','{$lname}', '{$email}', '{$subject}','{$comment}') ";
                        		$result = mysql_query($myQuery);
                        			echo "Thanks! Your message has been sent.";
                        
                        		//close db connection
                        $cxn = @DisconnectFromDb($dbServer, $dbUser, $dbPass, $dbName);
                        
                        }
                        }
                        
                        
                        if(!isset($_POST['send']) || $errmsg != '')
                        {
                        ?>
                        <div align="left" class="errmsg"><?=$errmsg;?></div>
                        <form  method="post" name="msgform" id="msgform">
                          <table width="" border="0" align="left" cellpadding="2" cellspacing="1" >
                            <tr> 
                              <td ><div align="right">First Name:</div></td>
                              <td ><input name="fname" type="text"  id="fname" size="30" value="<?=$fname;?>"></td>
                            </tr>
                        	<tr> 
                              <td ><div align="right">Last Name:</div></td>
                              <td ><input name="lname" type="text"  id="lname" size="30" value="<?=$lname;?>"></td>
                            </tr>
                            <tr> 
                              <td><div align="right"> Email:</div></td>
                              <td><input name="email" type="text"  id="email" size="30" value="<?=$email;?>"></td>
                            </tr>
                        	<tr> 
                              <td><div align="right"> Subject:</div></td>
                              <td><input name="subject" type="text"  id="subject" size="30" value="<?=$subject;?>"></td>
                            </tr>
                        
                        <tr> 
                          <td valign="top"><div align="right">Message</div></td>
                          <td><textarea name="comment" cols="40" rows="5" value="<?=comment;?>"></textarea></td>
                        </tr>
                        <tr align="center"> 
                          <td colspan="2"><div align="left">
                            <input name="send" type="submit" class="" id="send" value="Send Message" onClick="return checkForm();">
                          </div></td>
                        </tr>
                        <tr align="left"> 
                          <td colspan="2"><div align="left"></div></td>
                        </tr>
                        <tr align="left"> 
                          <td colspan="2"><div align="left"></div></td>
                        </tr>		
                        
                          </table>
                        </form>

                        ---------------------------------BEGIN WHAT I THINK THE APPROACH HERE IS----------

                        <?php 
                        
                        //initialize variables...
                        $errmsg = '';
                        $fname = '';
                        $lname = '';
                        $email = '';
                        $subject = '';
                        $comment = '';
                        
                        //declare functions
                        <?php
                        function format_output($data) {
                          $data = htmlentities($data);
                          $data = trim($data);
                          return $data;
                        }
                        
                        function sanitize_input($data, $maxlength = 255) { 
                          $data = trim($data); 
                          if(get_magic_quotes_gpc()) 
                          { 
                            $data = stripslashes($data); 
                          } 
                          $data = substr($data, 0, $maxlength); 
                          $data = mysql_real_escape_string($data); 
                          return $data; 
                        } 
                        
                        
                        ?>
                        
                        
                        
                        //present form with input validation for output back to user...
                        
                        <input type="text" name="fname" value="<?php if($_POST['fname']) {echo format_output($_POST['fname']) else echo 'Please enter your name'; ?>" />
                        etc.
                        
                        <?
                        //
                        redefine variables applying sanitization function
                        $fname = sanitize_input($fname);
                        $lname = sanitize_input($fname);
                        $email = sanitize_input($fname);
                        $subject = sanitize_input($fname);
                        $comment = sanitize_input($fname);
                        
                        //get db cxn
                        //store qry
                        //run qry
                        //close db cxn
                          Write a Reply...