Before saving the input from users in the database, I am using the below function to replace all HTML special chars. All my users will always be using the English Language.

Option 1

function clean($var) {
  $regEx="/[^a-zA-Z0-9 -_]/"; 
  $var = preg_replace($regEx, "", $var);
  return $var;

I want users to be able to only store

  • Letters (a to z) (Case Insensitive)
  • Numbers (0 to 9)
  • Space, Dash, Underscore

Will the above function is good for this job, or should I be using a more efficient/inbuilt function in PHP?

This is how I am using the function.

$userInput = htmlspecialchars(clean($userInput));

Option 2

function h($str_to_encode = ""){
    // Pregmatch will replacte all HTML characters with Empty string
    return preg_replace("/&#?[a-z0-9]{2,8};/i","", htmlspecialchars($str_to_encode));

Regex from : https://stackoverflow.com/a/657670/4050261

  • 3
    \$\begingroup\$ "All my users will always be using the English language." doesn't imply that only the letters from a-z are valid. Take a look at this: English words with diacritics. \$\endgroup\$ Commented Feb 2, 2018 at 10:32
  • 1
    \$\begingroup\$ You haven't told us much about why you're doing this, but I get the sense that this is almost certainly the wrong thing to do. \$\endgroup\$ Commented Feb 2, 2018 at 15:03
  • \$\begingroup\$ @200_success, since it is a small project, want to reduce functionality for better security. \$\endgroup\$
    – Adarsh
    Commented Feb 2, 2018 at 19:42

2 Answers 2


Similar to Toto's answer, I recommend:

function clean($var) {
    return preg_replace("~[^\w -]+~", "", $var);

This will replace all occurrences of one or more consecutive forbidden characters.

Adding the "one or more" (+) quantifier means longer potential matches and fewer total replacements. IOW, imagine a carton of a dozen eggs on yhe ground. If the task was to pick up 12 eggs, you could squat 12 times picking them up one at a time, or just squat once and pickup the carton.

I have eliminated the unnecessary inclusion of "single-use variables" as there is no benefit in retaining them for readability.

Following this custom function call, the call of htmlspecialchars() is useless because there won't be any chars to convert.

On the other hand, if you wanted to call htmlspecialchars_decode() prior to clean() there is reasonable logic to that decision, but it depends on the input that you are expecting.


Your regex [^a-zA-Z0-9 -_] matches everything that is not a to z, A to Z, 0 to 9 and space to _, this last range includes all character between hexa020 and hexa5F (ie for example !, ", #, $, % and many other), in a character class, - must be escaped or place at the beginning or at the end like:

  • [^a-zA-Z0-9 \-_]
  • [^a-zA-Z0-9 _-]
  • [^-a-zA-Z0-9 _]

That said, you can simplify a bit:

[a-zA-Z0-9_] can be coded as \w (depending on locale), so your regex becomes [^\w -].

If you want to be unicode compatible, use:

[^\pL\pN_ -] where \pL stands for any letter in any laguage and \pN for any digit.

  • 1
    \$\begingroup\$ You can also put the hyphen after a range or a shorthand character class: [^a-z-A-Z0-9 _], [^a-zA-Z-0-9 _], [^\pL-\pN_ ]. It's ugly, but possible... \$\endgroup\$ Commented Feb 3, 2018 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.