PHP -将数据从MariaDB转换为JSON -错误编码

wqnecbli  于 4个月前  发布在  PHP
关注(0)|答案(2)|浏览(49)

我似乎有一些编码问题,但我不能精确地指出它。
PHPMyAdmin说:

Server type: MariaDB
Server version: 10.3.39-MariaDB-log - MariaDB Server
Server charset: ISO 8859-2 Central European (latin2)
Server connection collation: utf8mb4_unicode_ci

字符串
我不能以任何方式更改SQL服务器,这是由我的网站托管提供商提供的。
我所有的数据库,表和列都使用utf8mb4_unicode_ci。所有的文件都编码为UTF-8。这些值在PHPMyAdmin和MySQLAdmin中都能正常显示。我网站上的其他脚本工作正常,显示英语,俄语,中文等。只是这一个由于某种原因不符合。我尝试通过PHPMA,MySQL甚至从同一个脚本插入数据。
我使用PDO连接,指定字符集,通过一个包含的文件:

<?php
if (!isset($pdo))
{
    $DBHOST = 'localhost';
    $DBNAME = '***';
    $DBUSER = '***';
    $DBPASS = '***';
    $DBCHRS = 'utf8mb4';

    $dsn = 'mysql:host='.$DBHOST.';dbname='.$DBNAME.';charset='.$DBCHRS;
    $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false];
    try
    {
        $pdo = new PDO($dsn, $DBUSER, $DBPASS, $options);
    }
    catch (\PDOException $e)
    {
        echo 'Could not connect to the database!<br>Message: ', $e->getMessage(), '<br>Code: ', $e->getCode();
        exit();
    }
}
?>


然后

$json = [];
$json['people'] = [];
$json['relations'] = [];

$stmt = $pdo->prepare('SELECT * FROM `tree_people`;');
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
    $json['people'][] = $row;

$stmt = $pdo->prepare('SELECT * FROM `tree_relations`;');
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
    $json['relations'][] = $row;

/*/
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=utf-8');
/*/
header('Content-Type: text/html; charset=utf-8');
//*/

//*/
echo '<pre>';
print_r($json);
echo '</pre>';
//*/

echo '<pre>';
echo json_encode($json, JSON_UNESCAPED_UNICODE);
echo '</pre>';


JSON无法生成(空字符串?),并且使用print_r显示的内容中所有特殊字符都显示为。
我要疯了,到底怎么回事?
编辑:我可以正确地从其他表中读取数据。然而,只有当我通过自己的编辑器将数据写入DB时才有可能,而不是通过PMA。请参阅https://herhor.net/news/?id=1,当我第一次通过PMA插入它时,它充满了未知字符。然而,现在当我在PMA或PMA中读取它时,它充满了乱序字符。
看起来在PMA/MySQL使用的编码和我所有的脚本使用的编码之间有一些不匹配。DB不应该自动处理它吗?
编辑2:根据要求,SHOW VARIABLES LIKE 'char%';用于存储:

character_set_client    utf8mb4
character_set_connection    utf8mb4
character_set_database  utf8mb4
character_set_filesystem    binary
character_set_results   utf8mb4
character_set_server    latin2
character_set_system    utf8
character_sets_dir  /usr/share/mysql/charsets/


对于PMA:

character_set_client    utf8mb4
character_set_connection    utf8mb4
character_set_database  utf8mb4
character_set_filesystem    binary
character_set_results   utf8mb4
character_set_server    latin2
character_set_system    utf8
character_sets_dir  /usr/share/mysql/charsets/


对于PHP PDO:

Array
(
    [0] => stdClass Object
        (
            [Variable_name] => character_set_client
            [Value] => latin2
        )

    [1] => stdClass Object
        (
            [Variable_name] => character_set_connection
            [Value] => latin2
        )

    [2] => stdClass Object
        (
            [Variable_name] => character_set_database
            [Value] => utf8mb4
        )

    [3] => stdClass Object
        (
            [Variable_name] => character_set_filesystem
            [Value] => binary
        )

    [4] => stdClass Object
        (
            [Variable_name] => character_set_results
            [Value] => latin2
        )

    [5] => stdClass Object
        (
            [Variable_name] => character_set_server
            [Value] => latin2
        )

    [6] => stdClass Object
        (
            [Variable_name] => character_set_system
            [Value] => utf8
        )

    [7] => stdClass Object
        (
            [Variable_name] => character_sets_dir
            [Value] => /usr/share/mysql/charsets/
        )

)


下面是两个表的SQL导入/导出文件:https://pastebin.com/33Ap4Vje

0h4hbjxa

0h4hbjxa1#

正如您的编辑所示,问题肯定与PDO连接有关,因为它在各种character_set_*变量中显示latin2
SET NAMES utf8mb4添加到$options阵列是否有助于:

$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'
];

字符串

ilmyapht

ilmyapht2#

如果你提供了你遇到麻烦的确切字符串就好了,但是我猜你正在处理非UTF8数据。我猜PHP中的json_encode()如果得到UTF8范围之外的字符(字节),它将返回空字符串。在将字符串传递给json_encode()之前,请尝试重新编码字符串。
你可以在你的字符串上使用utf8_encode(),或者如果你的字符串是用Windows-1252/ANSI编码的,你可以使用以下方法:

$str = mb_convert_encoding($str, "UTF-8", "Windows-1252");

字符串
看看this answer,它专门讨论了PDO上的这个问题:

while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
  foreach($row as &$value)
  {
    $value = mb_convert_encoding($value, "UTF-8", "Windows-1252");
  }
  unset($value);
  $json['relations'][] = $row;
}

**更新:**根据您的更新,似乎你的数据被打乱摆在首位(当你插入使用PHPMYADMIN),但如果它是正常工作时,使用网站编辑器(这与PDO的权利?),问题可能是由charset collation在您的数据库中设置,一个可能的解决方案是:

  • 将数据库导出为.sql文件
  • 读取文件,直到找到charset collation,并确保它是utf8_general_ci和您的数据是好的(没有混乱的编码),保存文件,并添加它作为一个新的数据库和使用。
  • 确保每次与数据库交互时都使用SET NAMES UTF8查询,就像在PDO中一样,您可以使用This

This good answer也可以帮助你。

相关问题