เหตุใด json_encode จึงส่งคืนสตริงว่าง


108

ฉันมีโครงสร้าง php อย่างง่ายที่มีอาร์เรย์ซ้อนกัน 3 อาร์เรย์

ฉันไม่ได้ใช้ออบเจ็กต์เฉพาะและสร้างอาร์เรย์ด้วยตัวเองโดยมี 2 ลูปซ้อนกัน

นี่คือตัวอย่าง var_dump ของอาร์เรย์ที่ฉันต้องการแปลงเป็น Json

array (size=2)
  'tram B' => 
    array (size=2)
      0 => 
        array (size=3)
          'name' => string 'Ile Verte' (length=9)
          'distance' => int 298
          'stationID' => int 762
      1 => 
        array (size=3)
          'name' => string 'La Tronche Hôpital' (length=18)
          'distance' => int 425
          'stationID' => int 771
  16 => 
    array (size=4)
      0 => 
        array (size=3)
          'name' => string 'Bastille' (length=8)
          'distance' => int 531
          'stationID' => int 397
      1 => 
        array (size=3)
          'name' => string 'Xavier Jouvin' (length=13)
          'distance' => int 589
          'stationID' => int 438

ในสคริปต์อื่นฉันมีโครงสร้างที่คล้ายกันและjson_encodeทำงานได้ดี เลยไม่เข้าใจว่าทำไมjson_encodeจะไม่ทำงานที่นี่

แก้ไข: ดูเหมือนจะมีปัญหากับการเข้ารหัส เมื่อmb_detect_encodingส่งคืน ASCII การjson_encodeทำงาน แต่เมื่อส่งคืน UTF8 จะไม่ทำงานอีกต่อไป

Edit2: json_last_error()ผลตอบแทนJSON_ERROR_UTF8ซึ่งหมายถึง: ในรูปแบบ UTF-8 ตัวอักษรอาจจะไม่ถูกต้องเข้ารหัส


คู่มือ PHP บอกว่าThis function only works with UTF-8 encoded data.ดังนั้นจึงไม่ควรมีปัญหากับการเข้ารหัส
MahanGM

13
พยายามที่จะใช้utf8_encode()บนทุ่งอาร์เรย์ก่อนที่จะมอบสตริงname json_encode()
MahanGM

ขอบคุณ ! ฉันเพิ่งมาหาวิธีแก้ปัญหานี้ซึ่งช่วยแก้ปัญหาของฉันได้
Matthieu Riegler

ใช่เห็นคำตอบ โชคดี.
MahanGM

3
ใช้JSON_PARTIAL_OUTPUT_ON_ERRORตัวเลือกเพื่อดูปัญหา (เช่นฟิลด์ที่มี UTF8 จะเป็นค่าว่าง)
Peter Krauss

คำตอบ:


255

หลังจาก 2 ชั่วโมงของการขุด (แก้ไข cf)

ฉันพบสิ่งต่อไปนี้:

  • ในกรณีของฉันมันเป็นปัญหาในการเข้ารหัส
  • mb_detect_encoding ผลตอบแทนอาจเป็นการตอบสนองที่ผิดพลาดบางสตริงอาจไม่ใช่ UTF-8
  • การใช้utf8_encode()สตริงเหล่านั้นช่วยแก้ปัญหาของฉันได้ แต่ดูหมายเหตุด้านล่าง

นี่คือฟังก์ชันเรียกซ้ำที่สามารถบังคับให้แปลงเป็น UTF-8 สตริงทั้งหมดที่มีอยู่ในอาร์เรย์:

function utf8ize($d) {
    if (is_array($d)) {
        foreach ($d as $k => $v) {
            $d[$k] = utf8ize($v);
        }
    } else if (is_string ($d)) {
        return utf8_encode($d);
    }
    return $d;
}

ใช้มันง่ายๆดังนี้:

echo json_encode(utf8ize($data));

หมายเหตุ: utf8_encode ()เข้ารหัสสตริง ISO-8859-1 เป็น UTF-8 ตามเอกสารดังนั้นหากคุณไม่แน่ใจเกี่ยวกับไอคอนการเข้ารหัสอินพุตv ()หรือmb_convert_encoding ()อาจเป็นตัวเลือกที่ดีกว่าตามที่ระบุไว้ในความคิดเห็นและโซลูชันอื่น ๆ


4
ขอขอบคุณสำหรับการแก้ปัญหา ... แต่ทราบด้านหนึ่งของคุณ: เปลี่ยน} else {ไป} else if (is_string ($d)) {; มิฉะนั้นคุณจะเปลี่ยนทุกอย่างเป็นสตริง (เช่นINTจะกลายเป็น a STRING)
Paul Peelen

3
คุณเพิ่งช่วยชีวิตฉัน ฉันกำลังจะจบทุกอย่างจนกว่าจะเจอฟังก์ชันนี้ !! ขอบคุณ.
silversunhunter

2
WTF! ขอบคุณสำหรับการแบ่งปันวิธีแก้ปัญหาของคุณ ฉันเห็นได้ว่าสิ่งนี้จะต้องใช้เวลามากในการคิดออกและฉันรู้สึกขอบคุณคุณที่ทำเช่นนั้นและแบ่งปัน
kris

1
หลังจากแก้ไขจุดบกพร่องสามวันฉันสามารถจูบคุณได้เลย
AJB

2
หากอ่านจากฐานข้อมูลเพียงแค่ใช้ $ conn-> set_charset ("utf8");
Andrew Briggs

36

Matthieu Riegler นำเสนอทางออกที่ดีมาก แต่ฉันต้องปรับเปลี่ยนเล็กน้อยเพื่อจัดการกับวัตถุด้วย:

function utf8ize($d) {
    if (is_array($d)) 
        foreach ($d as $k => $v) 
            $d[$k] = utf8ize($v);

     else if(is_object($d))
        foreach ($d as $k => $v) 
            $d->$k = utf8ize($v);

     else 
        return utf8_encode($d);

    return $d;
}

หมายเหตุเพิ่มเติมอีกประการหนึ่ง: json_last_error ()อาจเป็นประโยชน์ในการดีบักฟังก์ชัน json_encode () / json_encode ()


มันไม่ควรจะelseifแทนelse if? (คือไม่ว่าง)
Uwe Keim

2
@UweKeim ตามเอกสาร PHP "elseif และอื่น ๆ ถ้าจะถือว่าเหมือนกันทุกประการเมื่อใช้วงเล็บปีกกา" ซึ่งหมายความว่าเทียบเท่าตราบใดที่คุณไม่ใช้สัญกรณ์โคลอนเช่นif(): elseif:
Adam Bubela

1
ทำได้ดีมาก PHP เป็นขยะและพวกชอบเก็บไม่ให้ไปทิ้ง
Lonnie Best

คุณควรใส่else if(is_int($d)||is_bool($d)) return $d;ก่อนอันสุดท้ายเนื่องจาก:{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
David Refoua

เช่นเดียวกับที่ @ paul-peelen แนะนำให้ @ matthieu-riegler: เปลี่ยนค่าสุดท้ายelseสำหรับelse if(is_string ($d)); มิฉะนั้นคุณจะเปลี่ยนทุกอย่างเป็นสตริง (เช่นINTจะกลายเป็น a STRING)
Bruno Serrano

30

สำหรับฉันคำตอบสำหรับปัญหานี้คือการตั้งค่าcharset=utf8ในการเชื่อมต่อ PDO ของฉัน

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);

2
หรือในฟังก์ชัน mysqli: mysqli_set_charset ($ connection, "utf8");
user18099

นี่คือคำแนะนำในการแก้ปัญหาของฉัน สาเหตุที่แตกต่างกันเล็กน้อยของการเชื่อมต่อ msqli เพียงโทร$mysqli->set_charset("utf8");หลังจากจัดการฐานข้อมูลของคุณ
MaggusK

โปรดใช้utf8mb4ใน MySQL เวอร์ชันล่าสุด utf8ล้าสมัย
ธรรมทาน

10

Adam Bubela ยังนำเสนอวิธีแก้ปัญหาที่ดีจริงๆซึ่งช่วยฉันแก้ปัญหาของฉันและนี่คือฟังก์ชันที่เรียบง่าย:

function utf8ize($d)
{ 
    if (is_array($d) || is_object($d))
        foreach ($d as &$v) $v = utf8ize($v);
    else
        return utf8_encode($d);

    return $d;
}

1
ฉันชอบอันนี้เพราะมันรักษาคีย์
dev0

7

ฉันมีปัญหาเดียวกันกับ PHP 5.6 ฉันใช้Open Server + Nginx บน Windows 7 ชุดอักขระทั้งหมดตั้งค่าเป็น UTF-8 ในทางทฤษฎีตามเอกสารอย่างเป็นทางการธง

JSON_UNESCAPED_UNICODE

ควรแก้ปัญหานี้ น่าเสียดายที่นี่ไม่ใช่กรณีของฉัน ฉันไม่รู้ว่าทำไม. ตัวอย่างทั้งหมดข้างต้นไม่สามารถแก้ปัญหาของฉันได้ดังนั้นฉันจึงพบการใช้งานของฉันเอง ฉันเชื่อว่ามันสามารถช่วยใครสักคนได้ อย่างน้อยตัวอักษรรัสเซียก็ผ่านการทดสอบ

function utf8ize($d) {
    if (is_array($d) || is_object($d)) {
        foreach ($d as &$v) $v = utf8ize($v);
    } else {
        $enc   = mb_detect_encoding($d);

        $value = iconv($enc, 'UTF-8', $d);
        return $value;
    }

    return $d;
}

4

คำตอบที่ยอมรับนี้ใช้ได้ผล แต่ในกรณีที่คุณรับข้อมูลจาก MySQL (เหมือนเดิม) มีวิธีที่ง่ายกว่า

เมื่อคุณเปิดฐานข้อมูลของคุณก่อนที่คุณจะสอบถามคุณสามารถตั้งค่าชุดอักขระโดยใช้ mysqli ดังนี้:

/* change character set to utf8 | Procedural*/
if (!mysqli_set_charset($link, "utf8")) {
    printf("Error loading character set utf8: %s\n", mysqli_error($link));
    exit();
}

หรือ

/* change character set to utf8 | Object Oriented*/
if (!$mysqli->set_charset("utf8")) {
        printf("Error loading character set utf8: %s\n", $mysqli->error);
        exit();
 }

ลิงค์: http://php.net/manual/en/mysqli.set-charset.php


4

ฉันพบปัญหานี้บนเซิร์ฟเวอร์ที่ใช้ PHP เวอร์ชันเก่ากว่า (5.2) ฉันใช้แฟล็ก JSON_FORCE_OBJECT และดูเหมือนว่าจะไม่รองรับจนถึง 5.3

ดังนั้นหากคุณใช้แฟล็กนั้นอย่าลืมตรวจสอบเวอร์ชันของคุณ!

วิธีแก้ปัญหาดูเหมือนจะเป็นเพียงการส่งไปยังวัตถุก่อนที่จะเข้ารหัสเช่น:

json_encode((object)$myvar);

3

การส่งคืนmb_detect_encodingอาจไม่ถูกต้อง:

$data = iconv('UTF-8', 'ISO-8859-1', 'La Tronche Hôpital');
var_dump(
    mb_detect_encoding($data),
    mb_detect_encoding($data, array('ISO-8859-1', 'UTF-8'))
);

ขึ้นอยู่กับลำดับการตรวจจับเริ่มต้นข้างต้นอาจให้ผลลัพธ์ที่แตกต่างกันดังนั้นการเข้ารหัสจึงถูกรายงานว่าเป็น UTF-8 อย่างไม่ถูกต้อง ( นี่คือตัวอย่างที่ใหญ่กว่า )

มันอาจเป็นไปได้ว่าข้อมูลของคุณไม่ได้เข้ารหัสเป็น UTF-8 จึงจะกลับมาjson_encode falseคุณควรดูการแปลงสตริงของคุณเป็น UTF-8 ก่อนการเข้ารหัส JSON:

$fromEncoding = 'ISO-8859-1'; // This depends on the data

array_walk_recursive($array, function (&$value, $key, $fromEncoding) {
    if (is_string($value)) {
        $value = iconv($fromEncoding, 'UTF-8', $value);
    }
}, $fromEncoding);

3

ฉันได้รับข้อมูลจาก ob_get_clean () และมีปัญหาเดียวกัน แต่วิธีแก้ปัญหาข้างต้นไม่ได้ผลสำหรับฉัน ในกรณีของฉันวิธีแก้ปัญหานี้บางทีมันอาจจะช่วยใครสักคน

$var = mb_convert_encoding($var, 'UTF-8');


1

ฉันปรับปรุงคำตอบของ Adam Bubela แล้ว ฉันเกลียดมันเมื่อไม่มีการปิดกั้นโดย {and} มันสะอาดกว่าและคุณไม่ได้แนะนำจุดบกพร่องหรืออาจเป็นเพราะฉันเคยใช้ Perl มาก่อน :)

<?php

class App_Updater_String_Util {    
    /**
     * Usage: App_Updater_String_Util::utf8_encode( $data );
     *
     * @param mixed $d
     * @return mixed
     * @see http://stackoverflow.com/questions/19361282/why-would-json-encode-returns-an-empty-string
     */
    public static function utf8_encode($d) {
        if (is_array($d)) {
            foreach ($d as $k => $v) {
                $d[$k] = self::utf8_encode($v);
            }
        } elseif (is_object($d)) {
            foreach ($d as $k => $v) {
                $d->$k = self::utf8_encode($v);
            }
        } elseif (is_scalar($d)) {
            $d = utf8_encode($d);
        }

        return $d;
    }
}

?>


0

ปัญหานี้เกิดขึ้นในบางครั้ง - คุณไม่ได้ผ่านการควบคุมการเข้าถึงส่วนหัว

ในกรณีของฉันถ้าฉันถูกเพิ่ม echo ก่อน json_encode กำลังแสดงผลลัพธ์ไม่เช่นนั้นหน้าว่างก็มา

ฉันเพิ่ม

header('Access-Control-Allow-Origin: *'); 

และปัญหาของฉันได้รับการแก้ไข

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.