Skip to content

Commit

Permalink
Merge branch 'fix-issue-549-v3' of github.com:AnrDaemon/smarty into A…
Browse files Browse the repository at this point in the history
…nrDaemon-fix-issue-549-v3 (#771)
  • Loading branch information
wisskid committed Jul 19, 2022
1 parent 27910bf commit 20a8026
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- Fixed problems with smarty_mb_str_replace [#549](https://github.com/smarty-php/smarty/issues/549)

### Changed
- Updated HTML of the debug template [#599](https://github.com/smarty-php/smarty/pull/599)

Expand Down
34 changes: 34 additions & 0 deletions libs/plugins/shared.mb_str_replace.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,43 @@ function smarty_mb_str_replace($search, $replace, $subject, &$count = 0)
}
}
} else {
$mb_reg_charset = mb_regex_encoding();
// Check if mbstring regex is using UTF-8
$reg_is_unicode = !strcasecmp($mb_reg_charset, "UTF-8");
if(!$reg_is_unicode) {
// ...and set to UTF-8 if not
mb_regex_encoding("UTF-8");
}

// See if charset used by Smarty is matching one used by regex...
$current_charset = mb_regex_encoding();
$convert_result = (bool)strcasecmp(Smarty::$_CHARSET, $current_charset);
if($convert_result) {
// ...convert to it if not.
$subject = mb_convert_encoding($subject, $current_charset, Smarty::$_CHARSET);
$search = mb_convert_encoding($search, $current_charset, Smarty::$_CHARSET);
$replace = mb_convert_encoding($replace, $current_charset, Smarty::$_CHARSET);
}

$parts = mb_split(preg_quote($search), $subject) ?: array();
// If original regex encoding was not unicode...
if(!$reg_is_unicode) {
// ...restore original regex encoding to avoid breaking the system.
mb_regex_encoding($mb_reg_charset);
}
if($parts === false) {
// This exception is thrown if call to mb_split failed.
// Usually it happens, when $search or $replace are not valid for given mb_regex_encoding().
// There may be other cases for it to fail, please file an issue if you find a reproducible one.
throw new SmartyException("Source string is not a valid $current_charset sequence (probably)");
}

$count = count($parts) - 1;
$subject = implode($replace, $parts);
// Convert results back to charset used by Smarty, if needed.
if($convert_result) {
$subject = mb_convert_encoding($subject, Smarty::$_CHARSET, $current_charset);
}
}
return $subject;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class PluginFunctionHtmlSelectDateTest extends PHPUnit_Smarty
public function setUp(): void
{
$this->setUpSmarty(dirname(__FILE__));
$this->smarty->setErrorReporting(E_ALL & ~E_DEPRECATED);

$year = date('Y');
$this->now = mktime(15, 0, 0, 2, 20, $year);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* Smarty PHPunit tests - issue #549 regression tests
*
* @package PHPunit
* @author Andrey Repin <anrdaemon@yandex.ru>
*/

/**
* class for compiler tests
*
* @runTestsInSeparateProcess
* @preserveGlobalState disabled
* @backupStaticAttributes enabled
*
* mb_split breaks if Smarty encoding is not the same as mbstring regex encoding.
*/
class MbSplitEncodingIssue549Test extends PHPUnit_Smarty
{
/** @var string Saved Smarty charset */
private $charset;

/** @var array Source data for tests, hexed to protect from accidental reencoding */
private $data = array(
"subject" => '4772c3bc6e6577616c64', // "Grünewald"
"pattern" => '77616c64', // "wald"
"replacement" => '7374c3bc726d', // "stürm"
"result" => '4772c3bc6e657374c3bc726d', // "Grünestürm"
);

public function setUp(): void
{
if(!\Smarty::$_MBSTRING)
{
$this->markTestSkipped("mbstring extension is not in use by Smarty");
}

$this->charset = \Smarty::$_CHARSET;
$this->setUpSmarty(dirname(__FILE__));
}

protected function tearDown(): void
{
\Smarty::$_CHARSET = $this->charset ?: \Smarty::$_CHARSET;
$this->cleanDirs();
}

/** Provider for testReplaceModifier
*/
public function encodingPairsProvider()
{
return array(
"with non-UNICODE src/non-UNICODE regex (PHP < 5.6 default)" => array("Windows-1252", "EUC-JP"),
"with UTF-8 src/non-UNICODE regex (PHP < 5.6 default)" => array("UTF-8", "EUC-JP"),
"with UTF-8 src/UTF-8 regex (PHP >= 5.6)" => array("UTF-8", "UTF-8"),
"with non-UNICODE src/UTF-8 regex" => array("Windows-1252", "UTF-8"),
);
}

/** Test behavior of `replace` modifier with different source and regex encodings
*
* @dataProvider encodingPairsProvider
*/
public function testReplaceModifier($mb_int_encoding, $mb_regex_encoding)
{
$data = $this->data;
\array_walk($data, function(&$value, $key) use($mb_int_encoding) {
$value = \mb_convert_encoding(pack("H*", $value), $mb_int_encoding, "UTF-8");
});
\extract($data, \EXTR_SKIP);

\mb_regex_encoding($mb_regex_encoding);
\Smarty::$_CHARSET = $mb_int_encoding;
$this->assertEquals($result, $this->smarty->fetch("string:{\"$subject\"|replace:\"$pattern\":\"$replacement\"}"));
}

}
2 changes: 2 additions & 0 deletions tests/UnitTests/TemplateSource/_Issues/549/cache/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ignore anything in here, but keep this directory
*
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ignore anything in here, but keep this directory
*

0 comments on commit 20a8026

Please sign in to comment.