title: php - Clean user input using preg_replace_callback and ord()?
body: <p>I have a forum style text box and I would like to sanitize the user input to stop potential xss and code insertion. I have seen htmlentities used, but then others have said that &amp;,#,%,: characters need to be encoded as well, and it seems the more I look, the more potentially dangerous characters pop up. Whitelisting is problematic as there are many valid text options beyond ^a-zA-z0-9. I have come up with this code. Will it work to stop attacks and be secure? Is there any reason not to use it, or a better way?</p>
  
  <pre><code>function replaceHTML ($match) {
      return "&amp;#" . ord ($match[0]) . ";";
  }
  
  $clean = preg_replace_callback ( "/[^ a-zA-Z0-9]/", "replaceHTML", $userInput );
  </code></pre>
  
  <p>EDIT:<strong><em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>____</strong>
  I could of course be wrong, but it is my understanding that htmlentities only replaces &amp; &lt; > " (and ' if ENT_QUOTES is turned on). This is probably enough to stop most attacks (and frankly probably more than enough for my low traffic site). In my obsessive attention to detail, however, I dug further. A book I have warns to also encode # and % for "shutting down hex attacks". Two websites I found warned against allowing : and --. Its all rather confusing to me, and led me to explore converting all non-alphanumeric characters. If htmlentities does this already then great, but it does not seem to. Here are results from code I ran I copied after clicking view source in firefox.</p>
  
  <p>original (random characters to test):
  <b>5:</b>gjla#''*&amp;$!j-l:4</p>
  
  <p>preg_replace_callback:
  &#60;b&#62;5&#58;&#60;&#47;b&#62;gjla&#60;hi&#62;&#35;&#39;&#39;&#42;&#38;&#36;&#33;j&#45;l&#58;4</p>
  
  <p>htmlentities (w/ ENT_QUOTES):
  &lt;b&gt;5:&lt;/b&gt;gjla&lt;hi&gt;#''*&amp;$!j-l:4</p>
  
  <p>htmlentities appears to not be encoding those other characters like :
  Sorry for the wall of text. Is this just me being paranoid?</p>
  
  <p>EDIT #2: <strong><em>_</em>__<em>_</em>__<em>_</em>__<em>_</em>_</strong></p>