Skip to content

Commit

Permalink
Bugfix: mbstring polyfills must not raise value errors in PHP 7
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus committed Sep 17, 2024
1 parent 731f6e1 commit 847748a
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 61 deletions.
60 changes: 42 additions & 18 deletions src/Mbstring/Mbstring.php
Original file line number Diff line number Diff line change
Expand Up @@ -834,19 +834,32 @@ public static function mb_ord($s, $encoding = null)
return $code;
}

public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
/** @return string|false */
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null)
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
if (\PHP_VERSION_ID < 80000) {
trigger_error('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH', \E_USER_WARNING);

return false;
}

throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
}

if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}

if (self::mb_strlen($pad_string, $encoding) <= 0) {
if (\PHP_VERSION_ID < 80000) {
trigger_error('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string', \E_USER_WARNING);

return false;
}

throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
}

Expand All @@ -869,12 +882,13 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin
}
}

public static function mb_ucfirst(string $string, ?string $encoding = null): string
/** @return string|false */
public static function mb_ucfirst(string $string, ?string $encoding = null)
{
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}

$firstChar = mb_substr($string, 0, 1, $encoding);
Expand All @@ -883,12 +897,13 @@ public static function mb_ucfirst(string $string, ?string $encoding = null): str
return $firstChar.mb_substr($string, 1, null, $encoding);
}

public static function mb_lcfirst(string $string, ?string $encoding = null): string
/** @return string|false */
public static function mb_lcfirst(string $string, ?string $encoding = null)
{
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}

$firstChar = mb_substr($string, 0, 1, $encoding);
Expand Down Expand Up @@ -971,27 +986,31 @@ private static function getEncoding($encoding)
return $encoding;
}

public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
}

public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
}

public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__);
}

private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string
/** @return string|false */
private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function)
{
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
} else {
self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given');
} elseif (!self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given')) {
return false;
}

if ('' === $characters) {
Expand Down Expand Up @@ -1029,17 +1048,22 @@ private static function mb_internal_trim(string $regex, string $string, ?string
return iconv('UTF-8', $encoding.'//IGNORE', $string);
}

private static function assertEncoding(string $encoding, string $errorFormat): void
private static function assertEncoding(string $encoding, string $errorFormat): bool
{
try {
$validEncoding = @self::mb_check_encoding('', $encoding);
} catch (\ValueError $e) {
throw new \ValueError(sprintf($errorFormat, $encoding));
}

// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf($errorFormat, $encoding));
if (\PHP_VERSION_ID >= 80000) {
throw new \ValueError(sprintf($errorFormat, $encoding));
}

trigger_error(sprintf($errorFormat, $encoding), E_USER_WARNING);
}

return $validEncoding;
}
}
12 changes: 6 additions & 6 deletions src/Mbstring/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,27 +133,27 @@ function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstrin
}

if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null) { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}

if (!function_exists('mb_ucfirst')) {
function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
function mb_ucfirst(string $string, ?string $encoding = null) { return p\Mbstring::mb_ucfirst($string, $encoding); }
}

if (!function_exists('mb_lcfirst')) {
function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
function mb_lcfirst(string $string, ?string $encoding = null) { return p\Mbstring::mb_lcfirst($string, $encoding); }
}

if (!function_exists('mb_trim')) {
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Mbstring::mb_trim($string, $characters, $encoding); }
}

if (!function_exists('mb_ltrim')) {
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
}

if (!function_exists('mb_rtrim')) {
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
}


Expand Down
25 changes: 17 additions & 8 deletions src/Php83/Php83.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public static function json_validate(string $json, int $depth = 512, int $flags
return \JSON_ERROR_NONE === json_last_error();
}

public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
/** @return string|false */
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null)
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
Expand All @@ -50,19 +51,27 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin
$encoding = mb_internal_encoding();
}

$errorToTrigger = null;
try {
$validEncoding = @mb_check_encoding('', $encoding);
if (!@mb_check_encoding('', $encoding)) {
$errorToTrigger = sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding);
}
} catch (\ValueError $e) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
$errorToTrigger = sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding);
}

// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
if (mb_strlen($pad_string, $encoding) <= 0) {
$errorToTrigger = 'mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string';
}

if (mb_strlen($pad_string, $encoding) <= 0) {
throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
if (null !== $errorToTrigger) {
if (PHP_VERSION_ID < 80000) {
trigger_error($errorToTrigger, E_USER_WARNING);

return false;
}

throw new \ValueError($errorToTrigger);
}

$paddingRequired = $length - mb_strlen($string, $encoding);
Expand Down
16 changes: 8 additions & 8 deletions src/Php83/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@
function json_validate(string $json, int $depth = 512, int $flags = 0): bool { return p\Php83::json_validate($json, $depth, $flags); }
}

if (extension_loaded('mbstring')) {
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
}

if (!function_exists('stream_context_set_options')) {
function stream_context_set_options($context, array $options): bool { return stream_context_set_option($context, $options); }
}
Expand All @@ -37,8 +31,14 @@ function str_increment(string $string): string { return p\Php83::str_increment($
function str_decrement(string $string): string { return p\Php83::str_decrement($string); }
}

if (\PHP_VERSION_ID >= 80100) {
return require __DIR__.'/bootstrap81.php';
if (\PHP_VERSION_ID >= 80000) {
return require __DIR__.'/bootstrap80.php';
}

if (extension_loaded('mbstring')) {
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null) { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
}

if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {
Expand Down
19 changes: 19 additions & 0 deletions src/Php83/bootstrap80.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

if (extension_loaded('mbstring')) {
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
}

if (\PHP_VERSION_ID >= 80100) {
return require __DIR__.'/bootstrap81.php';
}

if (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {
function ldap_exop_sync($ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }
}

if (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) {
function ldap_connect_wallet(?string $uri, string $wallet, string $password, int $auth_mode = \GSLC_SSL_NO_AUTH) { return ldap_connect($uri, $wallet, $password, $auth_mode); }
}
41 changes: 31 additions & 10 deletions src/Php84/Php84.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
*/
final class Php84
{
public static function mb_ucfirst(string $string, ?string $encoding = null): string
/** @return string|false */
public static function mb_ucfirst(string $string, ?string $encoding = null)
{
if (null === $encoding) {
$encoding = mb_internal_encoding();
Expand All @@ -31,8 +32,13 @@ public static function mb_ucfirst(string $string, ?string $encoding = null): str
throw new \ValueError(sprintf('mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given', $encoding));
}

// BC for PHP 7.3 and lower
if (!$validEncoding) {
if (PHP_VERSION_ID < 80000) {
trigger_error(sprintf('mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given', $encoding), \E_USER_WARNING);

return false;
}

throw new \ValueError(sprintf('mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given', $encoding));
}

Expand All @@ -42,7 +48,8 @@ public static function mb_ucfirst(string $string, ?string $encoding = null): str
return $firstChar.mb_substr($string, 1, null, $encoding);
}

public static function mb_lcfirst(string $string, ?string $encoding = null): string
/** @return string|false */
public static function mb_lcfirst(string $string, ?string $encoding = null)
{
if (null === $encoding) {
$encoding = mb_internal_encoding();
Expand All @@ -54,8 +61,13 @@ public static function mb_lcfirst(string $string, ?string $encoding = null): str
throw new \ValueError(sprintf('mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given', $encoding));
}

// BC for PHP 7.3 and lower
if (!$validEncoding) {
if (PHP_VERSION_ID < 80000) {
trigger_error(sprintf('mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given', $encoding), \E_USER_WARNING);

return false;
}

throw new \ValueError(sprintf('mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given', $encoding));
}

Expand Down Expand Up @@ -109,22 +121,26 @@ public static function array_all(array $array, callable $callback): bool
return true;
}

public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
}

public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
}

public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
/** @return string|false */
public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null)
{
return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__);
}

private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string
/** @return string|false */
private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function)
{
if (null === $encoding) {
$encoding = mb_internal_encoding();
Expand All @@ -136,8 +152,13 @@ private static function mb_internal_trim(string $regex, string $string, ?string
throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given', $function, $encoding));
}

// BC for PHP 7.3 and lower
if (!$validEncoding) {
if (PHP_VERSION_ID < 80000) {
trigger_error(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given', $function, $encoding), \E_USER_WARNING);

return false;
}

throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given', $function, $encoding));
}

Expand Down
14 changes: 9 additions & 5 deletions src/Php84/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,28 @@ function array_any(array $array, callable $callback): bool { return p\Php84::arr
function array_all(array $array, callable $callback): bool { return p\Php84::array_all($array, $callback); }
}

if (\PHP_VERSION_ID >= 80000) {
return require __DIR__ . '/bootstrap80.php';
}

if (extension_loaded('mbstring')) {
if (!function_exists('mb_ucfirst')) {
function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Php84::mb_ucfirst($string, $encoding); }
function mb_ucfirst(string $string, ?string $encoding = null) { return p\Php84::mb_ucfirst($string, $encoding); }
}

if (!function_exists('mb_lcfirst')) {
function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Php84::mb_lcfirst($string, $encoding); }
function mb_lcfirst(string $string, ?string $encoding = null) { return p\Php84::mb_lcfirst($string, $encoding); }
}

if (!function_exists('mb_trim')) {
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_trim($string, $characters, $encoding); }
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Php84::mb_trim($string, $characters, $encoding); }
}

if (!function_exists('mb_ltrim')) {
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_ltrim($string, $characters, $encoding); }
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Php84::mb_ltrim($string, $characters, $encoding); }
}

if (!function_exists('mb_rtrim')) {
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_rtrim($string, $characters, $encoding); }
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null) { return p\Php84::mb_rtrim($string, $characters, $encoding); }
}
}
Loading

0 comments on commit 847748a

Please sign in to comment.