Commit 52079b2458b for woocommerce
commit 52079b2458b57039a99760e94681ac602618aad5
Author: Miroslav Mitev <m1r0@users.noreply.github.com>
Date: Fri Jul 24 16:38:22 2026 +0300
Fix product CSV importer crash when mbstring is unavailable (#66732)
diff --git a/plugins/woocommerce/changelog/38541-fix-csv-importer-mbstring-fallback b/plugins/woocommerce/changelog/38541-fix-csv-importer-mbstring-fallback
new file mode 100644
index 00000000000..5262c379372
--- /dev/null
+++ b/plugins/woocommerce/changelog/38541-fix-csv-importer-mbstring-fallback
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix product CSV importer form crashing when the mbstring extension is unavailable.
diff --git a/plugins/woocommerce/includes/admin/importers/views/html-product-csv-import-form.php b/plugins/woocommerce/includes/admin/importers/views/html-product-csv-import-form.php
index a3af9e8e45f..e4eba75cc9b 100644
--- a/plugins/woocommerce/includes/admin/importers/views/html-product-csv-import-form.php
+++ b/plugins/woocommerce/includes/admin/importers/views/html-product-csv-import-form.php
@@ -79,17 +79,30 @@ if ( ! defined( 'ABSPATH' ) ) {
<td><input type="checkbox" id="woocommerce-importer-map-preferences" name="map_preferences" value="1" /></td>
</tr>
<tr class="woocommerce-importer-advanced hidden">
- <th><label><?php esc_html_e( 'Character encoding of the file', 'woocommerce' ); ?></label><br/></th>
- <td><select id="woocommerce-importer-character-encoding" name="character_encoding">
- <option value="" selected><?php esc_html_e( 'Autodetect', 'woocommerce' ); ?></option>
+ <th><label for="woocommerce-importer-character-encoding"><?php esc_html_e( 'Character encoding of the file', 'woocommerce' ); ?></label><br/></th>
+ <td>
+ <?php
+ if ( function_exists( 'mb_list_encodings' ) ) {
+ ?>
+ <select id="woocommerce-importer-character-encoding" name="character_encoding">
+ <option value="" selected><?php esc_html_e( 'Autodetect', 'woocommerce' ); ?></option>
+ <?php
+ $encodings = mb_list_encodings();
+ sort( $encodings, SORT_NATURAL );
+ foreach ( $encodings as $encoding ) {
+ echo '<option>' . esc_html( $encoding ) . '</option>';
+ }
+ ?>
+ </select>
<?php
- $encodings = mb_list_encodings();
- sort( $encodings, SORT_NATURAL );
- foreach ( $encodings as $encoding ) {
- echo '<option>' . esc_html( $encoding ) . '</option>';
- }
+ } else {
?>
- </select>
+ <div class="notice notice-warning inline">
+ <p><?php esc_html_e( 'Your server does not support the mbstring PHP extension, so the file will be treated as UTF-8. Characters in other encodings may be removed.', 'woocommerce' ); ?></p>
+ </div>
+ <?php
+ }
+ ?>
</td>
</tr>
</tbody>
diff --git a/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php b/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php
index c480bf6fa2b..cd44bfb115d 100644
--- a/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php
+++ b/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php
@@ -90,7 +90,13 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
*/
private function adjust_character_encoding( $value ) {
$encoding = $this->params['character_encoding'];
- return 'UTF-8' === $encoding ? $value : mb_convert_encoding( $value, 'UTF-8', $encoding );
+
+ // Skip conversion when the value is already UTF-8 or when mbstring is unavailable.
+ if ( 'UTF-8' === $encoding || ! function_exists( 'mb_convert_encoding' ) ) {
+ return $value;
+ }
+
+ return mb_convert_encoding( $value, 'UTF-8', $encoding );
}
/**
diff --git a/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php b/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php
index e56e4985db9..8a272072ab9 100644
--- a/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php
+++ b/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php
@@ -470,4 +470,45 @@ class WC_Product_CSV_Importer_Test extends \WC_Unit_Test_Case {
$this->assertSame( '', $importer->parse_float_field( '' ), 'Empty values should be returned unchanged.' );
}
+
+ /**
+ * @testdox adjust_character_encoding should convert values from the configured encoding to UTF-8 (issue #38541).
+ * @dataProvider provider_adjust_character_encoding
+ *
+ * @param string $encoding The configured character encoding.
+ * @param string $value The raw value expressed in that encoding.
+ * @param string $expected The expected UTF-8 value.
+ */
+ public function test_adjust_character_encoding_converts_to_utf8( string $encoding, string $value, string $expected ) {
+ if ( ! function_exists( 'mb_convert_encoding' ) ) {
+ $this->markTestSkipped( 'The mbstring extension is required for this test.' );
+ }
+
+ $importer = new WC_Product_CSV_Importer( __DIR__ . '/sample.csv', array( 'character_encoding' => $encoding ) );
+
+ $method = new ReflectionMethod( WC_Product_CSV_Importer::class, 'adjust_character_encoding' );
+ $method->setAccessible( true );
+
+ $this->assertSame(
+ $expected,
+ $method->invoke( $importer, $value ),
+ "Expected a '{$encoding}' value to be converted to UTF-8."
+ );
+ }
+
+ /**
+ * Data provider for test_adjust_character_encoding_converts_to_utf8.
+ *
+ * The é character is the single byte 0xE9 in both ISO-8859-1 and Windows-1252, and the
+ * two-byte sequence 0xC3 0xA9 in UTF-8.
+ *
+ * @return array
+ */
+ public function provider_adjust_character_encoding(): array {
+ return array(
+ 'UTF-8 is returned unchanged' => array( 'UTF-8', 'Café', 'Café' ),
+ 'ISO-8859-1 is converted' => array( 'ISO-8859-1', "Caf\xE9", 'Café' ),
+ 'Windows-1252 is converted' => array( 'Windows-1252', "Caf\xE9", 'Café' ),
+ );
+ }
}