2012-02-01 59 views
42

我有一個stdClass對象調用$post,當通過print_r()傾倒,返回如下:爲什麼這個PHP調用json_encode會失敗 - 無法處理單引號?

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" 
} 

我假設某些單引號引起json_encode嗆,但我不知道需要什麼格式才能逃脫。有任何想法嗎?

編輯:修正代碼示例中的不匹配。我運行PHP版本5.3.8

EDIT2:編碼對象後直接,我這樣做:

echo json_last_error() == JSON_ERROR_UTF8; 

該印刷1,這意味着發生瞭如下錯誤:「畸形的UTF-8字符,可能錯誤編碼「。 json_last_error()

編輯3:致電utf8_decode()在帖子標題導致以下:「校友?晚餐即將來臨」。這些數據是從MySQL數據庫中提取的 - 特別是帖子標題是UTF-8編碼的文本字段。也許這個單引號是不正確的編碼?問題是,我有一個SQL GUI應用程序,並且它看起來是正確的。

+0

[Works for me](http://codepad.viper-7.com/39Bmy6)...你運行的是哪個PHP版本?我注意到轉儲對象和'json_encode()'結果不匹配(「ID」不同) - 請驗證您的代碼示例是否正確。 – DaveRandom 2012-02-01 15:34:05

+0

它也適用於我。當你設置post_title時,你是用雙引號(「」)來包圍它的嗎? – 2012-02-01 15:45:06

+0

顯示該字符串的十六進制轉儲。 – Incognito 2012-02-01 15:47:35

回答

55

您需要在執行查詢之前設置連接編碼。如果您使用old, deprecated API

  • 呼叫mysql_set_charset("utf8"):如何做到這一點取決於API,您使用的連接。
  • 通話mysqli_set_charset("utf8")如果使用mysqli
  • 添加charset parameter到連接字符串,如果您使用PDO和PHP> = 5.3.6。在早期版本中,您需要執行SET NAMES utf8

當您從MySQL獲取數據時,任何文本都將以「客戶端編碼」編碼,如果不另行配置,則可能爲windows-1252。導致您的問題的字符是「捲髮報價」,在十六進制轉儲中被看作92,這確認了mysql客戶端正在對windows-1252中的文本進行編碼。

你可以考慮的另一件事是通過utf8_encode通過所有文字,但在這種情況下,它不會產生正確的結果。 PHP的utf8_encodeiso-8859-1轉換爲編碼文本。在此編碼中,\ x92是一個不可打印的控制字符,它將在utf-8中轉換爲不可打印的控制字符。您可以使用str_replace("\x92", "'", $input)來解決這個特定字符的問題,但是如果有任何機會,數據庫中會有其他非ASCII字符,您希望客戶端使用UTF-8。

+4

或者等價的mysqli_set_charset($ link,「utf8」)。 – Lucent 2014-06-24 04:11:17

+1

Doctrine DBAL使用'charset' [選項](http://doctrine-dbal.readthedocs.org/en/latest/reference/configuration.html),您可以將其設置爲「utf8」來解決此問題。 – jaywilliams 2014-07-18 22:31:32

+0

mysql_和mysqli_函數已被棄用,我們現在使用PDO – 2015-06-01 13:31:51

25

什麼我已經在過去做json_encode與UTF8字符的文本是

json_encode(utf8_encode($s)); 

,並在某些情況下

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

的函數utf8_encode()來處理特殊字符(注,這取決於你的意思是如何使用JSON字符串的編碼,無法解碼)

的用htmlspecialchars(),你可以離開了這一點

最後,json_encode()獲取您的JSON數據包。因爲你想要一個對象的json_encode,你需要首先在每個文本部分調用utf8_encode(),或者編寫一個簡單的遞歸的utf8_encode()。對於示例情況下,這會做:

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

如果$ s是一個數組? – 2015-06-01 13:31:41

+2

然後,我想人們不得不做一些像'array_walk_recursive($ s,'utf8_encode');' – Umbrella 2015-06-04 15:37:04

+0

@Umbrella只是一個簡單的代碼片段將設置$ s爲true。我相信你在考慮array_map,不幸的是它沒有遞歸模式。 – arleslie 2016-02-19 08:25:53

7

我有而JSON從ODBC查詢結果編碼PHP數組同樣的問題,我的服務器的OBC配置了「en_US.819」,是一個生產服務器所以我甚至無法觸及它!

當我試圖:

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

其中「respose」是對結果的陣列,它可以作爲只要沒有奇異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

我想在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); 
0

您可以嘗試設置數據庫配置中的字符集:

'charset' => 'utf8', 
'driver_options' => array(
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'' 
)