为什么这个PHP调用json_encode会无声地失败 - 无法处理单引号?

时间:2012-02-01 15:29:07

标签: php json

我有一个名为stdClass的{​​{1}}对象,当通过$post转储时,会返回以下内容:

print_r()

回应此对象上调用stdClass Object ( [ID] => 12981 [post_title] => Alumnus' Dinner Coming Soon [post_parent] => 0 [post_date] => 2012-01-31 12:00:51 ) 的结果会产生以下结果:

json_encode()

我假设单引号的内容导致{ "ID": "12981", "post_title": null, "post_parent": "0", "post_date": "2012-01-31 12:00:51" } 窒息,但我不知道需要什么格式来逃避它。有什么想法吗?

编辑:修复了代码示例中的不匹配问题。我正在运行PHP版本5.3.8

EDIT2:在对对象进行编码后,我做到了这一点:

json_encode

此打印的echo json_last_error() == JSON_ERROR_UTF8; ,表示发生了以下错误:“格式错误的UTF-8字符,可能编码错误”。 json_last_error()

EDIT3:在帖子标题上调用1导致以下内容:“校友?晚餐即将来临”。这些数据是从MySQL数据库中提取的 - 特别是帖子标题是一个UTF-8编码的文本字段。也许这个单引号编码不正确?问题是,我有一个SQL GUI应用程序,它正确显示在那里。

5 个答案:

答案 0 :(得分:56)

您需要在执行查询之前设置连接编码。如何完成取决于您用于连接的API:

    如果您使用old, deprecated API。,请致电mysql_set_charset("utf8")
  • 如果您使用mysqli
  • ,请致电mysqli_set_charset("utf8") 如果您使用PDO和PHP> = 5.3.6,则
  • charset parameter添加到连接字符串。在早期版本中,您需要执行SET NAMES utf8

当您从MySQL获取数据时,任何文本都将以“客户端编码”进行编码,如果您不进行其他配置,则可能为windows-1252。导致问题的字符是“卷曲引用”,在十六进制转储中被视为92,它确认mysql客户端在windows-1252中编码文本。

您可能会考虑的另一件事是通过utf8_encode传递所有文本,但在这种情况下,它不会产生正确的结果。 PHP的utf8_encode转换 iso-8859-1 - 编码文本。在此编码中,\ x92是一个不可打印的控制字符,它将在utf-8中转换为不可打印的控制字符。您可以使用str_replace("\x92", "'", $input)来解决此特定字符的问题,但如果数据库中有任何其他非ascii字符,您将希望客户端使用UTF-8。

答案 1 :(得分:25)

过去我用utf8字符对json_encode进行json_encode的操作是

json_encode( utf8_encode( $s ) );

在某些情况下

json_encode( htmlspecialchars( utf8_encode( $s ) ) );

utf8_encode()来处理特殊字符(注意,这是编码,而不是解码)

htmlspecialchars()取决于您使用JSON字符串的意思,您可以将其删除

最后,json_encode()获取您的JSON数据包。

由于你想对一个对象进行json_encode,你需要先在每个文本部分调用utf8_encode(),或者编写一个简单的递归utf8_encode()。对于您的示例,这样做:

function myEncode($o) {
    $o->title = utf8_encode($o->title);
    return json_encode($o);
}

答案 2 :(得分:7)

我遇到了同样的问题,而JSON从ODBC查询结果编码php数组,我的服务器的OBC配置了' en_US.819',是生产服务器所以没有我甚至可以触摸那个!!。

当我尝试时:

echo json_encode($GLOBALS['response'], true);

在哪里'休息'是一个包含结果的数组,它按预期工作,不存在奇怪的char,如果是这样,json_encode将无法返回空。

解决方案?....在从查询中获取行时UTF编码结果:

$result = odbc_exec($conn, $sql_query);
$response = array();
while( $row = odbc_fetch_array($result) ) { 
     $json['pers_identificador'] = $row['pers_identificador'];
     $json['nombre_persona'] = utf8_encode( $row['nombre_persona'] );
     $json['nombre_1'] = utf8_encode($row['nombre_1'] );
     $json['nombre_2'] = utf8_encode($row['nombre_2'] );
     array_push($response, $json); 
  }

现在json_encode工作!!!,结果字符串是这样的:

{"page_id":300,"max_rows":"100","cant_rows":"12897","datos":
  [{"pers_identificador":"301","cedula":"15250068","interno_1":"178202","interno_2":"","nombre_persona":"JOSE JUAN PANDOLFO ZAGORODKO","nombre_1":"JOSE","nombre_2":"JUAN",....

这解决了我的问题。

答案 3 :(得分:5)

我想就此问题向您推荐, 在link 我建议你使用像这样的json_encode包装器:

function safe_json_encode($value){
    if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
        $encoded = json_encode($value, JSON_PRETTY_PRINT);
    } else {
        $encoded = json_encode($value);
    }
    switch (json_last_error()) {
        case JSON_ERROR_NONE:
            return $encoded;
        case JSON_ERROR_DEPTH:
            return 'Maximum stack depth exceeded'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_STATE_MISMATCH:
            return 'Underflow or the modes mismatch'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_CTRL_CHAR:
            return 'Unexpected control character found';
        case JSON_ERROR_SYNTAX:
            return 'Syntax error, malformed JSON'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_UTF8:
            $clean = utf8ize($value);
            return safe_json_encode($clean);
        default:
            return 'Unknown error'; // or trigger_error() or throw new Exception()
    }
}


function utf8ize($mixed) {
    if (is_array($mixed)) {
        foreach ($mixed as $key => $value) {
            $mixed[$key] = utf8ize($value);
        }
    } else if (is_string ($mixed)) {
        return utf8_encode($mixed);
    }
    return $mixed;
}

定义这些功能后,您可以直接使用它,

echo safe_json_encode($response);

答案 4 :(得分:0)

您可以尝试在数据库配置中设置charset:

    public function get_supported_url_patterns()
{
    return array('/https?:\\/\\/(www\\.)?example\\.com\\/movies\\/[0-9]+\\/[^\\.]+\\.html.*/i');
}