programing

json_encode()가 잘못된 문자를 가진 문자열을 삭제하지 않도록 하는 방법

mytipbox 2023. 3. 19. 17:47
반응형

json_encode()가 잘못된 문자를 가진 문자열을 삭제하지 않도록 하는 방법

json_encode()null비활성(UTF-8 이외) 문자를 포함하는 문자열에 대해 어떻게 생각하십니까?

복잡한 시스템에서 디버깅하는 것은 골칫거리일 수 있습니다.잘못된 문자를 실제로 보거나 최소한 생략하는 것이 훨씬 더 적합할 것입니다.json_encode()문자열 전체가 자동으로 드롭됩니다.

예(UTF-8의 경우):

$string = 
  array(utf8_decode("Düsseldorf"), // Deliberately produce broken string
        "Washington",
        "Nairobi"); 

print_r(json_encode($string));

결과:

[null,"Washington","Nairobi"]

원하는 결과:

["D�sseldorf","Washington","Nairobi"]

주의: 끊어진 문자열을 json_encode()로 동작시킬 생각은 없습니다.인코딩 오류를 쉽게 진단할 수 있는 방법을 찾고 있습니다.anull문자열은 도움이 되지 않습니다.

php는 오류를 발생시키려 하지만 display_display를 꺼야 합니다.이것은 이상합니다.왜냐하면display_errors설정은 오류가 표준 출력으로 인쇄되는지 여부를 제어하는 것일 뿐 오류가 트리거되는지 여부를 제어하는 것은 아닙니다.제가 강조하고 싶은 것은, 여러분이 이 모든 것을display_errorson, 다른 모든 종류의 php 오류를 볼 수 있지만, php는 이 오류를 숨길 뿐만 아니라 트리거하지도 않습니다.즉, 에러 로그에 표시되지 않고 커스텀error_handler도 호출되지 않습니다.에러는 발생하지 않습니다.

이를 나타내는 코드는 다음과 같습니다.

error_reporting(-1);//report all errors
$invalid_utf8_char = chr(193);

ini_set('display_errors', 1);//display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());//nothing

ini_set('display_errors', 0);//do not display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());// json_encode(): Invalid UTF-8 sequence in argument

이 기괴하고 불행한 행동은 이 버그 https://bugs.php.net/bug.php?id=47494과 다른 몇몇 버그와 관련이 있으며, 결코 고쳐지지 않을 것으로 보인다.

회피책:

json_encode에 전달하기 전에 문자열을 청소하는 것이 효과적일 수 있습니다.

$stripped_of_invalid_utf8_chars_string = iconv('UTF-8', 'UTF-8//IGNORE', $orig_string);
if ($stripped_of_invalid_utf8_chars_string !== $orig_string) {
    // one or more chars were invalid, and so they were stripped out.
    // if you need to know where in the string the first stripped character was, 
    // then see http://stackoverflow.com/questions/7475437/find-first-character-that-is-different-between-two-strings
}
$json = json_encode($stripped_of_invalid_utf8_chars_string);

http://php.net/manual/en/function.iconv.php

매뉴얼에 기재되어 있습니다.

//IGNORE는 대상 문자 집합에서 잘못된 문자를 자동으로 폐기합니다.

따라서 먼저 문제가 있는 문자를 삭제함으로써 이론적으로 json_encode()는 문제가 있는 문자를 초크하여 실패하는 것을 얻을 수 없습니다.//IGNOREflag는 유효한 utf8 문자의 json_encodes 개념과 완벽하게 호환되므로 구매자는 주의해 주십시오.이것은 여전히 엣지가 실패할 수 있기 때문입니다.아, 난 캐릭터 세트 문제가 싫어.

★★★★★
7에는 php 7.2+에 것 .json_encodeJSON_INVALID_UTF8_IGNORE ★★★★★★★★★★★★★★★★★」JSON_INVALID_UTF8_SUBSTITUTE
아직 많은 문서는 없지만, 현시점에서는 이 테스트를 통해 예상되는 동작을 이해할 수 있습니다.https://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phpt

.3에는 새로운 「hp 7.3+"가 JSON_THROW_ON_ERRORhttp://php.net/manual/en/class.jsonexception.php 를 참조해 주세요.

이 함수는 문자열에서 잘못된 UTF8 문자를 모두 제거합니다.

function removeInvalidChars( $text) {
    $regex = '/( [\x00-\x7F] | [\xC0-\xDF][\x80-\xBF] | [\xE0-\xEF][\x80-\xBF]{2} | [\xF0-\xF7][\x80-\xBF]{3} ) | ./x';
    return preg_replace($regex, '$1', $text);
}

Excel 문서를 json으로 변환한 후 사용하는데, Excel 문서는 UTF8에 있을 수 없기 때문입니다.

유효하지 않은 문자를 보이면서도 유효한 문자로 변환할 수 있는 특별한 합리적인 방법은 없다고 생각합니다.위의 regex를 돌려 비활성 문자를 Unicode 대체 문자인 U+FFD로 대체할 수 있지만, 이는 비활성 문자를 삭제하는 것보다 더 나은 사용자 경험을 제공하지 않습니다.

$s = iconv('UTF-8', 'UTF-8//IGNORE', $s);

이치노나는 왜 php의 사람들이 수정으로 삶을 더 쉽게 만들지 않았는지 모르겠다.json_encode().

위의 방법을 사용하면 데이터에 특수 문자(스웨덴 문자 등)가 포함되어 있어도 json_encode()는 개체를 만들 수 있습니다.

후 데이터를할 수 ('javascript'를 사용합니다).escape(),unescape(),encodeURIComponent(),decodeURIComponent()

php : php (smarty)에서 .에서는 이렇게 사용하고 있습니다.

$template = iconv('UTF-8', 'UTF-8//IGNORE', $screen->fetch("my_template.tpl"));

, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★innerHTML을 사용하다

은 「이행」에 가 있습니다.json_encode()어떤 인코딩으로도 작동하도록 하기 위해서요.

당신이 다루고 있는 모든 문자열의 부호화를 알아야 해요 그렇지 않으면 고통의 세계로 들어갈 거예요

UTF-8은 사용하기 쉬운 부호화입니다.또한 JSON은 UTF-8(http://www.json.org/JSONRequest.html)을 사용하도록 정의되어 있습니다.그럼 왜 사용하지 않는 거죠?

간단한 답변: json_encode() 문자열이 손실되는 것을 방지하는 방법은 문자열이 유효한 UTF-8인지 확인하는 것입니다.

iconv 함수를 사용하는 대신 json_encode를 JSON_UNESCAPED_와 함께 사용할 수 있습니다.UNICODE 옵션( > = PHP5.4.0 )

php 파일 헤더에 "charset=utf-8"을 넣어야 합니다.

헤더('Content-Type: application/json; charset=utf-8');

json 장애에 대한 정보 오류 알림을 받으려면 다음 도우미를 사용합니다.

  • 는 일시적으로 커스텀에러 핸들러를 인스톨 하고, 부호화/복호화에 관한 json 에러를 검출합니다.
  • 실행 시간을 설정하다오류에 대한 예외
<?php

/**
 * usage:
 * $json = HelperJson::encode(['bla'=>'foo']);
 * $array = HelperJson::decode('{"bla":"foo"}');
 * 
 * throws exception on failure
 * 
 */
class HelperJson {

    /**
     * @var array
     */
    static private $jsonErrors = [
            JSON_ERROR_NONE => '',
            JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',
            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
            JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
            JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
            JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
    ];

    /**
     * ! assoc ! (reverse logic to php function)
     * @param string $jsonString
     * @param bool $assoc
     * @throws RuntimeException
     * @return array|null
     */
    static public function decode($jsonString, $assoc=true){

        HelperJson_ErrorHandler::reset(); // siehe unten
        set_error_handler('HelperJson_ErrorHandler::handleError');

        $result = json_decode($jsonString, $assoc);

        $errStr = HelperJson_ErrorHandler::getErrstr();
        restore_error_handler();

        $jsonError = json_last_error();
        if( $jsonError!=JSON_ERROR_NONE ) {
            $errorMsg = isset(self::$jsonErrors[$jsonError]) ? self::$jsonErrors[$jsonError] : 'unknown error code: '.$jsonError;
            throw new \RuntimeException('json decoding error: '.$errorMsg.' JSON: '.substr($jsonString,0, 250));
        }
        if( $errStr!='' ){
            throw new \RuntimeException('json decoding problem: '.$errStr.' JSON: '.substr($jsonString,0, 250));
        }
        return $result;
    }

    /**
     * encode with error "throwing"
     * @param mixed $data
     * @param int $options   $options=JSON_PRESERVE_ZERO_FRACTION+JSON_UNESCAPED_SLASHES : 1024 + 64 = 1088
     * @return string
     * @throws \RuntimeException
     */
    static public function encode($data, $options=1088){

        HelperJson_ErrorHandler::reset();// scheint notwendg da sonst bei utf-8 problemen nur eine warnung geflogen ist, die hier aber nicht durchschlug, verdacht der error handler macht selbst was mit json und reset damit json_last_error
        set_error_handler('HelperJson_ErrorHandler::handleError');

        $result = json_encode($data, $options);

        $errStr = HelperJson_ErrorHandler::getErrstr();
        restore_error_handler();

        $jsonError = json_last_error();
        if( $jsonError!=JSON_ERROR_NONE ){
            $errorMsg = isset(self::$jsonErrors[$jsonError]) ? self::$jsonErrors[$jsonError] : 'unknown error code: '.$jsonError;
            throw new \RuntimeException('json encoding error: '.$errorMsg);
        }
        if( $errStr!='' ){
            throw new \RuntimeException('json encoding problem: '.$errStr);
        }
        return $result;
    }

}

/**

HelperJson_ErrorHandler::install();
preg_match('~a','');
$errStr = HelperJson_ErrorHandler::getErrstr();
HelperJson_ErrorHandler::remove();

 *
 */
class HelperJson_ErrorHandler {

    static protected  $errno = 0;
    static protected  $errstr = '';
    static protected  $errfile = '';
    static protected  $errline = '';
    static protected  $errcontext = array();

    /**
     * @param int $errno
     * @param string $errstr
     * @param string $errfile
     * @param int $errline
     * @param array $errcontext
     * @return bool
     */
    static public function handleError($errno, $errstr, $errfile, $errline, $errcontext){
        self::$errno = $errno;
        self::$errstr = $errstr;
        self::$errfile = $errfile;
        self::$errline = $errline;
        self::$errcontext = $errcontext;
        return true;
    }

    /**
     * @return int
     */
    static public function getErrno(){
        return self::$errno;
    }
    /**
     * @return int
     */
    static public function getErrstr(){
        return self::$errstr;
    }
    /**
     * @return int
     */
    static public function getErrfile(){
        return self::$errfile;
    }
    /**
     * @return int
     */
    static public function getErrline(){
        return self::$errline;
    }
    /**
     * @return array
     */
    static public function getErrcontext(){
        return self::$errcontext;
    }
    /**
     * reset last error
     */
    static public function reset(){
        self::$errno = 0;
        self::$errstr = '';
        self::$errfile = '';
        self::$errline = 0;
        self::$errcontext = array();
    }

    /**
     * set black-hole error handler
     */
    static public function install(){
        self::reset();
        set_error_handler('HelperJson_ErrorHandler::handleError');
    }

    /**
     * restore previous error handler
     */
    static function remove(){
        restore_error_handler();
    }
}

WordPress는 이 문제를 방지하기 위해 JSON 주위에 래퍼가 있습니다. wp_json_encode의 소스 코드를 볼 수 있지만 요약하면 다음과 같습니다.

$data = [ utf8_decode("Düsseldorf"), "Washington", "Nairobi" ];

foreach ( $data as &$string ) {
  $encoding = mb_detect_encoding( $string, mb_detect_order(), true );
  if ( $encoding ) {
      return mb_convert_encoding( $string, 'UTF-8', $encoding );
  } else {
      return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' );
  }
}

json_encode( $data );

// Result: ["D?sseldorf","Washington","Nairobi"]

재귀 배열, 객체 또는 스칼라가 아닌 데이터에 대해서는 _wp_json_sanity_check에서 보다 자세한 코드를 확인하십시오.

문자열에서 인쇄할 수 없는 문자 제거

$result = preg_replace/[:^print:]]/, , $string];

https://alvinalexander.com/php/how-to-remove-non-printable-characters-in-string-regex/에 의한 솔루션

언급URL : https://stackoverflow.com/questions/4663743/how-to-keep-json-encode-from-dropping-strings-with-invalid-characters

반응형