Web

Fix Oxwall PHP 8.3 Validation Fails on Paste Error

Resolve Oxwall form validation failing on PHP 8.3 when pasting text. 'Please fill the form properly' error due to invisible Unicode characters. Robust server-side fixes, code examples for RequiredValidator, trim/mb_strlen issues, and client-side paste handlers.

1 answer 1 view

Oxwall validation fails on PHP 8.3 when pasting text — “Please fill the form properly” error

I’m running an Oxwall-based site and after upgrading to PHP 8.3 many forms (forum posts, user profile fields) fail validation when users copy/paste text. The fields appear non-empty after pasting, but submission returns the JavaScript error “Please fill the form properly” unless the user types at least one key. Typing directly works; sometimes refreshing the page fixes the issue temporarily.

I suspect the problem is in RequiredValidator (ow_core/validator.php). It may be due to PHP 8.3 handling of trim(), mb_strlen(), or invisible Unicode characters introduced during copy/paste, or a mismatch between how the client-side JS sends the value and how PHP validates it.

Current isValid implementation:

php
public function isValid( $value )
{
 if ( is_array($value) )
 {
 if ( sizeof($value) === 0 )
 {
 return false;
 }
 }
 else if ( $value === null || mb_strlen(trim($value)) === 0 )
 {
 return false;
 }

 return true;
}

Questions:

  1. Why would pasted-only input be considered empty by this server-side validation after upgrading to PHP 8.3?
  2. Is this a known PHP 8.3 change in string handling or Unicode trimming that could cause mb_strlen(trim($value)) to return 0 for pasted text (e.g., due to zero-width or control characters)?
  3. What is the best way to fix this in Oxwall:
  • Normalize or strip invisible Unicode characters on the server (examples welcomed)?
  • Change isValid to use a different check (e.g., normalize, remove Unicode category C characters, use grapheme_strlen, or check for non-whitespace characters with a regex)?
  • Or implement a client-side workaround to ensure paste triggers proper input/change events and sends the actual text?
  1. Please provide a robust server-side code example to replace or enhance isValid to reliably detect non-empty pasted input on PHP 8.3 without introducing security issues or performance regressions.

Any explanations or code examples that handle Unicode invisible characters and PHP 8.3 specifics would be appreciated.

This Oxwall PHP 8.3 validation problem most often comes from invisible Unicode/control characters or from the browser not firing a proper input event on paste — the existing RequiredValidator (mb_strlen(trim($value)) === 0) can return “empty” for pasted-only content or when the client-side value isn’t updated. The safest fixes are: (1) make the server-side validation Unicode-aware (detect any printable grapheme like letters, numbers, punctuation, or symbols and ignore only control/format/separator characters for emptiness checks) and (2) add a tiny client-side paste handler so paste reliably triggers validation. Example server code and a client-side snippet are below.


Contents


Why pasted input can be considered “empty” on Oxwall PHP 8.3 validation

There are two common reasons you’ll see “Please fill the form properly” after paste while typing works:

  • Invisible or format Unicode characters: copy/paste can insert characters like ZERO WIDTH SPACE (U+200B), ZERO WIDTH JOINER (U+200D), BOM (U+FEFF), directional marks (U+200E/U+200F) or other control/format characters. If your emptiness test strips or ignores those, the server may see “no printable characters” and treat the field as empty.
  • Client-side race/event issue: some validators only react to key events; a paste sometimes doesn’t trigger the same event listeners (or the validator checks the value before the paste is applied), so JavaScript reports empty and cancels submission. Typing one key fixes it because that produces an input/change event.

You reported the Oxwall RequiredValidator check:

php
else if ( $value === null || mb_strlen(trim($value)) === 0 )
{
 return false;
}

That check relies on trim() and mb_strlen(). trim() only strips a small ASCII set of whitespace by default and will not remove many Unicode-format characters; mb_strlen() counts characters correctly for multibyte strings when encoding is right. So the server-side check can fail in two ways: either the value actually contains only characters your pipeline treats as “empty” (control/format/separator), or the client never sent the pasted text (client-side bug). Both are plausible — and both should be handled.


PHP 8.3 string handling and Unicode trimming (what changed)

Short answer: PHP 8.3 did not introduce a new unicode-trimming function; the long-awaited Unicode-aware trimming helpers (mb_trim, mb_ltrim, mb_rtrim) landed in PHP 8.4 work (see notes on mb_trim) and are not available in 8.3. The built-in trim() still only strips the traditional ASCII set described in the manual, so it won’t remove many Unicode separators or format characters — which means relying on trim() + mb_strlen() is not a robust Unicode-aware “not-empty” test on 8.3. See the docs for trim() and the note about Unicode whitespace, and the php.watch summary for mb_trim in 8.4: the PHP trim manual and php.watch: mb_trim.

That means: the bug is unlikely to be a mysterious PHP 8.3 regression that suddenly makes mb_strlen() return zero for ordinary pasted characters — but it does mean Oxwall’s check is brittle for Unicode and invisible characters and should be hardened.


You have three sensible approaches; ideally you apply the server-side fix plus a small client-side patch.

Server-side: robust Unicode-aware required check (preferred)

Goal: treat a field as non-empty if it contains at least one printable grapheme (letters, digits, punctuation or symbols) while treating pure whitespace, control and format characters as empty. This approach:

  • avoids false negatives from invisible Unicode control/format characters,
  • doesn’t mutate the original text (validation only),
  • is fast for typical form fields.

A reliable test is to check for at least one character in Unicode classes Letter/Number/Punctuation/Symbol: preg_match(‘/[\p{L}\p{N}\p{P}\p{S}]/u’, $s). As a fallback, normalize before testing and strip common invisible chars (U+200B, U+FEFF, etc.). See the code example below.

Why this is safe: it accepts emojis and symbols (they are \p{S}), accepts punctuation and letters across scripts (\p{L}), and rejects strings made solely of control/format/separator characters.

Server-side: normalize or strip invisible Unicode characters on save (optional)

If you want to remove zero-width or BOM characters from stored content, do it explicitly and consciously (separate from validation). Example small sanitizer:

  • Remove format/control characters: preg_replace(‘/[\p{C}]+/u’, ‘’, $str) — but be cautious: \p{C} includes private-use and surrogate classes; removing those may be OK but be mindful if you store special private-use characters.
  • Or remove just the most common invisible ones: preg_replace(‘/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{2060}]+/u’, ‘’, $str)

Only strip on save if you intend to alter user input; otherwise use the cleaning only for the validation check.

References and patterns for invisible characters are available in community answers for removing non-printable characters (see the Stack Overflow discussion on removing non-printable characters).

Client-side: ensure paste triggers input/change events (workaround)

Because the UI shows text but submission fails until typing, a quick and low-risk fix is to ensure paste triggers the same event handlers as typing. Add a tiny script that listens for paste and dispatches input/change after the paste finishes:

Plain JS:

js
document.addEventListener('paste', function (e) {
 const el = e.target;
 if (!el || (el.tagName !== 'INPUT' && el.tagName !== 'TEXTAREA')) return;
 // Delay so the browser inserts the pasted content first
 setTimeout(function () {
 el.dispatchEvent(new Event('input', { bubbles: true }));
 el.dispatchEvent(new Event('change', { bubbles: true }));
 }, 0);
});

jQuery:

js
$(document).on('paste', 'input, textarea', function () {
 const el = this;
 setTimeout(function () { $(el).trigger('input').trigger('change'); }, 0);
});

This usually fixes race/event issues and is a small, reversible patch while you roll out a server-side fix.


Robust server-side code example to replace/enhance isValid

Below is a recommended replacement for RequiredValidator::isValid. This focuses on detecting the presence of any printable Unicode character and keeps behavior fast and safe for PHP 8.3.

php
public function isValid($value)
{
 // keep original array behavior
 if (is_array($value)) {
 return count($value) > 0;
 }

 if ($value === null) {
 return false;
 }

 // ensure string
 $s = (string) $value;

 // Quick path: if ASCII printable chars exist, accept immediately
 if (preg_match('/[A-Za-z0-9\p{P}\p{S}]/u', $s)) {
 return true;
 }

 // Normalize if intl is available (helps composed/decomposed forms)
 if (function_exists('normalizer_normalize')) {
 $norm = normalizer_normalize($s, Normalizer::FORM_C);
 if ($norm !== false) {
 $s = $norm;
 }
 }

 // Remove a few known invisible chars for the emptiness test (but do not persist)
 $s_clean = preg_replace('/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{2060}]+/u', '', $s);

 // Primary Unicode-aware test:
 // If there's at least one Letter, Number, Punctuation or Symbol, treat as non-empty.
 if (preg_match('/[\p{L}\p{N}\p{P}\p{S}]/u', $s_clean)) {
 return true;
 }

 // Fallback: if the string contains ANY character not in Control/Separator categories,
 // treat it as non-empty. This handles edge cases where marks or other classes appear.
 if (preg_match('/[^\p{C}\p{Z}]/u', $s_clean)) {
 return true;
 }

 // nothing printable found
 return false;
}

Why this works:

  • preg_match(‘/[\p{L}\p{N}\p{P}\p{S}]/u’) finds letters, numbers, punctuation or symbols (includes emoji).
  • We normalize (optional) to avoid false empties due to decomposed sequences.
  • We explicitly remove the most common invisible/format characters before testing (safe for validation only).
  • The fallback ![\p{C}\p{Z}] test ensures we don’t accidentally mark strings with marks or other classes as empty.

Notes:

  • This code only changes validation — it does not mutate or strip content that will be stored. If you want to strip invisible chars for storage, do it as a deliberate transform at save time.
  • All regex’s use the Unicode (/u) flag and are O(n) on the field length. For normal form fields this is trivial; for very large posts you might skip normalization or do length checks first.

Testing, deployment and performance notes

  • Reproduce: paste strings containing visible characters plus zero-width ones. Example string with U+200B: “hello\u{200B}world”. Submit and see validator behavior.
  • Logging: temporarily log the hexadecimal codepoints of $value to confirm invisible chars. In PHP, use:
  • bin2hex($value) or
  • join(’ ‘, array_map(function($c){ return sprintf(‘U+%04X’, $c); }, preg_split(’//u’, $value, -1, PREG_SPLIT_NO_EMPTY)))
  • Performance: the regex checks above are linear and trivial for field-length inputs. For very large bodies (multi-megabyte posts) you can:
  • check mb_strlen($value) and skip heavy ops when length is very short,
  • apply the strict check only to required fields that are usually short.
  • Compatibility: test on several browsers and on PHP 8.3 deployed environment. If you control multiple servers, deploy the client-side paste fix first (very low risk) then deploy server-side change in a minor release.
  • Future-proofing: when you can upgrade to PHP 8.4+ you may be able to use mb_trim for some tasks, but custom checks above still give fine-grained control. See the php.watch note on mb_trim for upcoming features.

Sources

  1. The original report and discussion: Oxwall validation fails on PHP 8.3: “Please fill …” error
  2. Oxwall RequiredValidator source: ow_core/validator.php on GitHub
  3. PHP trim() manual (what trim removes): PHP trim — Manual
  4. Removing non-printable characters (examples & regex): How to remove all non printable characters in a string?
  5. Unicode-aware trimming discussion and planned mb_trim in PHP 8.4: php.watch — mb_trim, mb_ltrim, mb_rtrim
  6. Client-side paste and validation issues (examples): HTML input validation that works when using paste and onchange event not detecting copy/paste
  7. Advanced regex for unicode whitespace/control characters: Trimming unicode whitespace/control characters with regex

Conclusion

This Oxwall PHP 8.3 validation issue is best solved by hardening the server-side RequiredValidator to use a Unicode-aware “has printable characters” test (for example, preg_match(‘/[\p{L}\p{N}\p{P}\p{S}]/u’) with normalization/fallbacks) and by deploying a tiny client-side paste handler so paste reliably triggers input/change events. The code sample above is a safe, performant drop-in replacement for isValid on PHP 8.3 that avoids false empties caused by invisible Unicode/control characters while not mutating user content by default.

Authors
Verified by moderation
Moderation
Fix Oxwall PHP 8.3 Validation Fails on Paste Error