Try a regular expression to limit sequential newlines before passing things into nl2br:
$clean = preg_replace('/\n{4,}/', '\n', preg_replace('/\r/', '', $dirty));
For the uninitiated:
- \r is a Carriage Return, which we can safely strip before calling nl2br
- \n is a Newline
- {4,} means "repeat the last character four or more times
So, any sequence of four or more newlines in a row will be reduced to one.
Unfortunately this is easily defeated. A user can simply come by and hit enter + space + enter + space + enter + space...
It's a start, though. Let's make it a bit more idiot-proof.
$dirty = preg_replace('/\r/', '', $dirty);
$clean = preg_replace('/\n{4,}/', '\n', preg_replace('/^\s+$/m', '', $dirty));
Now we're also:
- Setting the "m" modifier so...
- The ^ means "the beginning of a line" (without "m" it means the beginning of the entire string)
- The $ means "the end of a line" (without "m" it means the end of the entire string)
- \s+ means "any space character, repeating"
So, now it removes \r, then changes lines that are nothing but spaces to being empty, then it limits empty lines.
Beware, this may break formatting, depending on what markup you're using. Certain markup engines can operate on lines that are pure-whitespace and do smart things with them, such as the markup engine used here at SO.
Have you considered banning jerks? It's sometimes effective. :)