Najszybszy sposób sprawdzenia, czy ciąg znaków to JSON w PHP?

385

Potrzebuję naprawdę, bardzo szybkiej metody sprawdzenia, czy ciąg znaków to JSON, czy nie. Wydaje mi się, że nie jest to najlepszy sposób:

function isJson($string) {
    return ((is_string($string) &&
            (is_object(json_decode($string)) ||
            is_array(json_decode($string))))) ? true : false;
}

Jakiś entuzjasta wydajności chce ulepszyć tę metodę?

Kirk Ouimet
źródło
3
Rozważ użycie tylko json_decoderaz ... sprawdź także wejściowe i zwracane wartości json_decode.
5
Która z nich jest odpowiedzią?
Farid Rn
8
Przełącznik trójskładnikowy tutaj jest zbędny. Twoje oświadczenie jest już oceniane jako boolean.
Raz walczyłem z niedźwiedziem.
Zaakceptuj odpowiedź Lewisa Donovana ... działa dobrze
Poonam Bhatt

Odpowiedzi:

573
function isJson($string) {
 json_decode($string);
 return (json_last_error() == JSON_ERROR_NONE);
}
Henrik P. Hessel
źródło
19
Wygląda na to, że wszyscy uwielbiają tę odpowiedź. Jakieś wyjaśnienie, dlaczego?
Kirk Ouimet,
8
Uważam, że PHP 5.3> jest potrzebne do korzystania z funkcji json_last_error
Chris Harrison
97
Sprawdzanie pierwszy znak ciąg dla {, [lub pierwszego symbolu innego dosłownym potencjalnie może znacznie przyspieszyć ten jeden w górę, kiedy wielu przychodzących ciągów oczekuje się być non-JSON.
Oleg V. Volkov
20
$ phone = „021234567”; var_dump (isJson ($ phone)); zwróć prawdę nie! powinien zwrócić false.
vee
23
Uwaga: ta funkcja zwróci również wartość true dla dowolnej liczby, niezależnie od tego, czy zostanie ona podana jako ciąg, czy liczba rzeczywista. 6.5 = true, '300' = true, 9 = trueitd. Więc może to być poprawna wartość JSON, ale funkcja może nie działać zgodnie z oczekiwaniami, jeśli chcesz sprawdzać tylko poprawne ciągi JSON za pomocą {}lub [];
BadHorsie
156

Odpowiedz na pytanie

Funkcja json_last_errorzwraca ostatni błąd, który wystąpił podczas kodowania i dekodowania JSON. Tak więc najszybszym sposobem sprawdzenia poprawnego JSON jest

// decode the JSON data
// set second parameter boolean TRUE for associative array output.
$result = json_decode($json);

if (json_last_error() === JSON_ERROR_NONE) {
    // JSON is valid
}

// OR this is equivalent

if (json_last_error() === 0) {
    // JSON is valid
}

Zauważ, że json_last_errorjest obsługiwany tylko w PHP> = 5.3.0.

Pełny program sprawdzający dokładny BŁĄD

Zawsze dobrze jest znać dokładny błąd w czasie programowania. Oto pełny program do sprawdzania dokładnego błędu na podstawie dokumentów PHP.

function json_validate($string)
{
    // decode the JSON data
    $result = json_decode($string);

    // switch and check possible JSON errors
    switch (json_last_error()) {
        case JSON_ERROR_NONE:
            $error = ''; // JSON is valid // No error has occurred
            break;
        case JSON_ERROR_DEPTH:
            $error = 'The maximum stack depth has been exceeded.';
            break;
        case JSON_ERROR_STATE_MISMATCH:
            $error = 'Invalid or malformed JSON.';
            break;
        case JSON_ERROR_CTRL_CHAR:
            $error = 'Control character error, possibly incorrectly encoded.';
            break;
        case JSON_ERROR_SYNTAX:
            $error = 'Syntax error, malformed JSON.';
            break;
        // PHP >= 5.3.3
        case JSON_ERROR_UTF8:
            $error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
            break;
        // PHP >= 5.5.0
        case JSON_ERROR_RECURSION:
            $error = 'One or more recursive references in the value to be encoded.';
            break;
        // PHP >= 5.5.0
        case JSON_ERROR_INF_OR_NAN:
            $error = 'One or more NAN or INF values in the value to be encoded.';
            break;
        case JSON_ERROR_UNSUPPORTED_TYPE:
            $error = 'A value of a type that cannot be encoded was given.';
            break;
        default:
            $error = 'Unknown JSON error occured.';
            break;
    }

    if ($error !== '') {
        // throw the Exception or exit // or whatever :)
        exit($error);
    }

    // everything is OK
    return $result;
}

Testowanie przy użyciu prawidłowego JSON INPUT

$json = '[{"user_id":13,"username":"stack"},{"user_id":14,"username":"over"}]';
$output = json_validate($json);
print_r($output);

Prawidłowe wyjście

Array
(
    [0] => stdClass Object
        (
            [user_id] => 13
            [username] => stack
        )

    [1] => stdClass Object
        (
            [user_id] => 14
            [username] => over
        )
)

Testowanie z niepoprawnym JSON

$json = '{background-color:yellow;color:#000;padding:10px;width:650px;}';
$output = json_validate($json);
print_r($output);

Niepoprawne WYJŚCIE

Syntax error, malformed JSON.

Dodatkowa uwaga dla (PHP> = 5.2 i& PHP <5.3.0)

Ponieważ json_last_errornie jest obsługiwane w PHP 5.2, możesz sprawdzić, czy kodowanie lub dekodowanie zwraca wartość logiczną FALSE. Oto przykład

// decode the JSON data
$result = json_decode($json);
if ($result === FALSE) {
    // JSON is invalid
}

Mam nadzieję, że to jest pomocne. Happy Coding!

Madan Sapkota
źródło
Mała precyzja: jeśli ten Json jest prawidłowy, ale poprzedni dekodowany jest nieprawidłowy, kod będzie działał poprawnie, ponieważ: „ Zwraca ostatni błąd (jeśli wystąpił) podczas ostatniego kodowania / dekodowania JSON.
Bruno
Dzięki @Madan, weryfikacja „json_decode” rozwiązała dla mnie, że korzystam z PHP 7.0.
Francis Rodrigues,
Z pewnością json_decode może po prostu zwrócić false dla dosłownego false, więc ((strlen($json) === 5) && ($json !== 'false'))należy również sprawdzić, aby uniknąć tej krawędzi?
MrMesees,
@Bruno Jeśli ostatnie dekodowanie działa bez błędów, wówczas json_last_errorpowraca JSON_ERROR_NONE.
Andrea
81

Wszystko, co naprawdę musisz zrobić, to ...

if (is_object(json_decode($MyJSONArray))) 
{ 
    ... do something ...
}

To żądanie nie wymaga nawet oddzielnej funkcji. Wystarczy owinąć is_object wokół json_decode i przejść dalej. Wydaje się, że w tym rozwiązaniu ludzie zbyt wiele się nad tym zastanawiają.

użytkownik1653711
źródło
@ RomanM.Kos Żeby było jasne, jeśli tablica jest prostą tablicą, musisz użyć is_arraydodatkowo is_object, w przeciwnym razie is_objectzwróci false dla prostych tablic zakodowanych jako JSON. Więc @ggutenberg ma rację w tym przypadku. Przekazanie prawdziwego argumentu w celu json_decodewymuszenia zwrócenia obiektu jako tablicy. Teoretycznie zawsze możesz wymusić dekodowanie do tablicy i po prostu sprawdzić is_array, czy to powinno zadziałać.
userabuser
@ userabuser Jeśli ja json_encode($array)dla prostej tablicy PHP, a następnie czy json_decode($str)otrzymam obiekt, ale nie tablicę. json_decode($str, true)zmusza do konwersji na tablicę. Dlaczego skomplikowany ciąg w kodzie? Sprawdź, is_array(json_decode($str, true))a po jakimś czasie po przeczytaniu zrozumiesz, że dekodowany musi być tylko tablicą. Znacznie trudniej zgadnąć is_object(json_decode($MyJSONArray))„Och, tu sprawdzam, czy dekodowana jest tablica, czy nie?”
Roman M. Koss
@ RomanM.Kos Nie, to nie jest poprawne, codepad.viper-7.com/OFrtsq - jak już powiedziałem, zawsze możesz zmusić json_decodedo zwrócenia tablicy, aby oszczędzić ci sprawdzania obiektu i tablicy, ale jeśli nie I OTO json_decodeco była prosta tablica na początek, w zamian otrzymasz dekodę, a nie obiekt. Musisz użyć, JSON_FORCE_OBJECTjeśli chcesz zawsze wymuszać kodowanie obiektu JEŚLI przekazując prostą tablicę.
userabuser
11
Downvote za powiedzenie: This request does not require a separate function even. Ściśle mówiąc, żadne rozwiązanie nie wymaga osobnej funkcji. Celem funkcji nie jest spowodowanie, aby wiele linii kodu wyglądało jak jedna linia kodu. Celem tej funkcji jest ustawienie standardowego procesu sprawdzania JSON wszędzie w aplikacji, tak aby różni programiści (lub ten sam programista w czasie) nie używali różnych procedur sprawdzania na różnych etapach przepływu programu.
cartbeforehorse
71

Używanie json_decodedo „sondowania” może nie być najszybszym sposobem. Jeśli jest to struktura głęboko zagnieżdżona, wówczas tworzenie wielu obiektów tablic w celu ich wyrzucenia jest stratą pamięci i czasu.

Może być więc szybszy w użyciu, preg_matcha wyrażenie RFC4627 regex, aby również zapewnić ważność :

  // in JS:
  var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
         text.replace(/"(\\.|[^"\\])*"/g, '')));

To samo w PHP:

  return !preg_match('/[^,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]/',
       preg_replace('/"(\\.|[^"\\\\])*"/', '', $json_string));

Jednak nie ma wystarczającej liczby entuzjastów wydajności, aby zawracać sobie głowę testami.

Mario
źródło
11
Wypełnij rekursywne wyrażenie regularne, aby zweryfikować JSON tutaj: stackoverflow.com/questions/2583472/regex-to-validate-json/… - Ale okazuje się, że PHP json_decodejest zawsze szybsze niż wyrażenie PCRE. (Chociaż nie jest bardzo zoptymalizowany, nie znaleziono testów syntetycznych i może zachowywać się inaczej w Perlu ..)
mario
3
@vee Tak, dziękuję za notatkę. Ale zatrzymajmy to tutaj [niepoprawnie], aby nikt nie używał tego w produkcji.
Mario
1
@cartbeforehorse Dobra, dzięki. Naprawiłem wtedy ucieczkę dla podwójnego cudzysłowu w PHP.
mario
1
@cartbeforehorse Nie ma. Głównie dekoracja. To tylko dosłowny odwrotny ukośnik, który rzeczywiście wymaga podwójnego ucieczki. Ma \r \n \tto sens tylko dlatego, że PHP ich nie interpoluje, ale niech PCRE je interpretuje (było to wymagane tylko w /xtrybie). Inne okazje tego nie potrzebują; jednak wciąż „odwrotny ukośnik ucieka się” we wszystkich ciągach PHP. Można więc uznać to za bardziej dokładne.
mario
4
@mario Dobra, rozumiem. Zasadniczo PHP ucieka przed ukośnikami, zanim silnik reg-exp go zobaczy. Jeśli chodzi o silnik reg-exp, istnieje o połowę mniejsza liczba odwrotnych ukośników w łańcuchu niż to, co widzą ludzie. „Jak reg-exp nie było już wystarczająco skomplikowane”
cartbeforehorse
39

Zwróci wartość true, jeśli ciąg znaków reprezentuje tablicę lub obiekt Json :

function isJson($str) {
    $json = json_decode($str);
    return $json && $str != $json;
}

Odrzuca ciągi JSON, które zawierają tylko liczbę, ciąg lub wartość logiczną, chociaż ciągi te są technicznie poprawne JSON.

var_dump(isJson('{"a":5}')); // bool(true)
var_dump(isJson('[1,2,3]')); // bool(true)
var_dump(isJson('1')); // bool(false)
var_dump(isJson('1.5')); // bool(false)
var_dump(isJson('true')); // bool(false)
var_dump(isJson('false')); // bool(false)
var_dump(isJson('null')); // bool(false)
var_dump(isJson('hello')); // bool(false)
var_dump(isJson('')); // bool(false)

To najkrótsza droga, jaką mogę wymyślić.

Cyryl
źródło
Zamiast var_dump, możesz umieścić to w przypadku testowym PHPUnit. W przeciwnym razie jestem zarówno zaskoczony, jak i szczęśliwy, gdy dowiaduję się, że to prawda.
MrMesees,
3
Dlaczego wszyscy inni mają tak wyczerpujące odpowiedzi, kiedy to działa świetnie? Dzięki.
toddmo
1
Po prostu cudownie! Nie sprawdziłem „najszybszego sposobu” ani wydajności, ale ten z pewnością obejmuje wszystkie przypadki, w których kiedykolwiek sprawdzałem. Jest to klasyczny przykład niesławnego przysłowia „Nie używaj młota do zgryzienia orzecha” . Z punktu widzenia programisty zawsze lepiej jest zachować kod prosty, krótki i łatwy do zrozumienia, wydajność a prostota to kolejna debata poza tym wątkiem.
Fr0zenFyr
Jest to porządna logika, ale należy również pamiętać, że zwraca false dla pustych tablic. Na przykład: var_dump(isJson('[]')); // bool(false). Zgodnie z dokumentacją dotyczącą boolanów jest tak, ponieważ PHP ocenia tablice z zerowymi elementami jako fałszywe. Oto niewielka poprawka w celu dostosowania deklaracji zwrotu; wykonuje identyczne porównanie na zdekodowanym wyjściu, który obsługuje ten przypadek:return $json !== false && $str != $json;
j13k
@ j13k Identyczne porównanie ma wartość isJson('hello')true, co nie jest prawidłowym jsonem. Tutaj wybiera się luźne porównanie. Nie mam szybkiego rozwiązania sytuacji pustej tablicy / obiektu, z wyjątkiem brzydkiegoreturn $json == '[]' || ...
Cyryla,
21

Najprostszy i najszybszy sposób, którego używam, jest następujący;

$json_array = json_decode( $raw_json , true );

if( $json_array == NULL )   //check if it was invalid json string
    die ('Invalid');  // Invalid JSON error

 // you can execute some else condition over here in case of valid JSON

Jest tak, ponieważ json_decode () zwraca NULL, jeśli wprowadzony ciąg nie jest json lub nieprawidłowy json.


Prosta funkcja sprawdzania poprawności JSON

Jeśli musisz sprawdzić JSON w wielu miejscach, zawsze możesz skorzystać z następującej funkcji.

function is_valid_json( $raw_json ){
    return ( json_decode( $raw_json , true ) == NULL ) ? false : true ; // Yes! thats it.
}

W powyższej funkcji otrzymasz true w zamian, jeśli jest to poprawny JSON.

Mohammad Mursaleen
źródło
3
json_decode('null') == NULLi nulljest prawidłową wartością JSON.
zzzzBov
Testowałem, czy „null” jest poprawnym jsonem na json.parser.online, ale wydaje się, że to nie jest poprawny json. A json_decode () to podstawowa funkcja php do sprawdzania poprawności json, więc wątpię, aby uzyskać jakiś fałszywy wynik w naszych wynikach.
Mohammad Mursaleen
Zamiast ufać jakiejś niezweryfikowanej witrynie, rozważ sprawdzenie specyfikacji, która się nie zgadza (str. 2) . Możesz też spróbować JSON.parse('null')w konsoli programisty.
zzzzBov
19
function is_json($str){ 
    return json_decode($str) != null;
}

http://tr.php.net/manual/en/function.json-decode.php wartość zwracana jest pusta, gdy wykryte zostanie nieprawidłowe kodowanie.

AhmetB - Google
źródło
4
Zwróci również niepoprawnie wartość null dla „null” (co nie jest poprawnym JSON, ale w przeciwnym razie może być całkowicie „prawidłowe” do json_decode). Domyśl.
Myślę, że powinno to być: w json_decode($str)!=null;przeciwnym razie funkcja powinna zostać wywołana is_not_json.
Yoshi
Ta funkcja powinna zostać przemianowana na „to coś innego niż JSON”!
lonesomeday
2
@ user166390, json_decode('null')jest poprawnym JSON zgodnie ze specyfikacją i powinien zwrócić wartość null.
zzzzBov
Należy również pamiętać, że z tą metodą is_json('false')i is_json('[]')wróci, falseponieważ typ nie jest zaznaczony. Myślę, że ta metoda powinna raczej wrócić $str === null || json_decode($str) !== null.
Antoine Pinsard,
11

Musisz sprawdzić poprawność danych wejściowych, aby upewnić się, że przekazany ciąg nie jest pusty i jest w rzeczywistości ciągiem. Pusty ciąg jest niepoprawny JSON.

function is_json($string) {
  return !empty($string) && is_string($string) && is_array(json_decode($string, true)) && json_last_error() == 0;
}

Myślę, że w PHP ważniejsze jest ustalenie, czy obiekt JSON ma nawet dane, ponieważ aby użyć danych, musisz zadzwonić json_encode()lub json_decode(). Sugeruję odrzucenie pustych obiektów JSON, abyś nie musiał niepotrzebnie uruchamiać kodowania i dekodowania pustych danych.

function has_json_data($string) {
  $array = json_decode($string, true);
  return !empty($string) && is_string($string) && is_array($array) && !empty($array) && json_last_error() == 0;
}
żartobliwy
źródło
+1 za faktyczne myślenie o problemie w kontekście rzeczywistym.
cartbeforehorse
Ale czy '0'to nie ważne, Json ... dlaczego miałbym być ostrożny? @Kzqai
upful
11

To zrobi to:

function isJson($string) {
    $decoded = json_decode($string); // decode our JSON string
    if ( !is_object($decoded) && !is_array($decoded) ) {
        /*
        If our string doesn't produce an object or array
        it's invalid, so we should return false
        */
        return false;
    }
    /*
    If the following line resolves to true, then there was
    no error and our JSON is valid, so we return true.
    Otherwise it isn't, so we return false.
    */
    return (json_last_error() == JSON_ERROR_NONE);
}

if ( isJson($someJsonString) ) {
    echo "valid JSON";
} else {
    echo "not valid JSON";
}

Jak pokazano w innych odpowiedziach, json_last_error()zwraca każdy błąd z naszego ostatniego json_decode (). Istnieją jednak przypadki użycia krawędzi, w których sama ta funkcja nie jest wystarczająco kompleksowa. Na przykład, jeśli masz json_decode()liczbę całkowitą (np .:) 123lub ciąg liczb bez spacji lub innych znaków (np .: "123":), json_last_error()funkcja nie wykryje błędu.

Aby temu przeciwdziałać, dodałem dodatkowy krok, który gwarantuje, że wynikiem naszego działania json_decode()będzie obiekt lub tablica. Jeśli nie, wrócimy false.

Aby zobaczyć to w działaniu, sprawdź te dwa przykłady:

Lewis Donovan
źródło
"hello"jest poprawnym JSON i nie jest obiektem ani tablicą, json_last_error()wystarczy
JoniJnm
1
json_last_error()zwraca kod błędu, 4gdy json_decode()ciąg "hello". Przykład tutaj: 3v4l.org/lSsEo
Lewis Donovan
Twój kod jest niepoprawny, hellonie jest prawidłowym JSON, ale "hello"jest to 3v4l.org/OEJrQ
JoniJnm
9

Prostą metodą jest sprawdzenie wyniku JSON ..

$result = @json_decode($json,true);
    if (is_array($result)) {
        echo 'JSON is valid';
    }else{
        echo 'JSON is not valid';
    }
Rameez Rami
źródło
6

w GuzzleHttp :

/**
 * Wrapper for json_decode that throws when an error occurs.
 *
 * @param string $json    JSON data to parse
 * @param bool $assoc     When true, returned objects will be converted
 *                        into associative arrays.
 * @param int    $depth   User specified recursion depth.
 * @param int    $options Bitmask of JSON decode options.
 *
 * @return mixed
 * @throws \InvalidArgumentException if the JSON cannot be decoded.
 * @link http://www.php.net/manual/en/function.json-decode.php
 */
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
{
    $data = \json_decode($json, $assoc, $depth, $options);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_decode error: ' . json_last_error_msg());
    }

    return $data;
}

/**
 * Wrapper for JSON encoding that throws when an error occurs.
 *
 * @param mixed $value   The value being encoded
 * @param int    $options JSON encode option bitmask
 * @param int    $depth   Set the maximum depth. Must be greater than zero.
 *
 * @return string
 * @throws \InvalidArgumentException if the JSON cannot be encoded.
 * @link http://www.php.net/manual/en/function.json-encode.php
 */
function json_encode($value, $options = 0, $depth = 512)
{
    $json = \json_encode($value, $options, $depth);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_encode error: ' . json_last_error_msg());
    }

    return $json;
}
Parsa
źródło
5

Wcześniej sprawdzałem tylko wartość zerową, co w rzeczywistości było błędne.

    $data = "ahad";
    $r_data = json_decode($data);
    if($r_data){//json_decode will return null, which is the behavior we expect
        //success
    }

Powyższy fragment kodu działa dobrze z łańcuchami. Jednak jak tylko podam numer, to się rozpada. Na przykład.

    $data = "1213145";
    $r_data = json_decode($data);

    if($r_data){//json_decode will return 1213145, which is the behavior we don't expect
        //success
    }

Naprawienie tego, co zrobiłem, było bardzo proste.

    $data = "ahad";
    $r_data = json_decode($data);

    if(($r_data != $data) && $r_data)
        print "Json success";
    else
        print "Json error";
Ahad Ali
źródło
Niezłe rozwiązanie. Bardzo dobrze radzi sobie z pisaniem!
Chaoix,
5
//Tested thoroughly, Should do the job:
public static function is_json(string $json):bool
{
    json_decode($json);
    if (json_last_error() === JSON_ERROR_NONE) {
        return true;
    }
    return false;
}
PM7Temp
źródło
4

Kolejny prosty sposób

function is_json($str)
{
    return is_array(json_decode($str,true));
}
h0mayun
źródło
1
To nie jest poprawne Każdy typ PHP może być zakodowany w JSON, taki jak obiekty, ciągi znaków itp. Oczekuje się, że funkcja json_decode je zwróci. Jest to prawdą tylko wtedy, gdy zawsze dekodujesz tablice, a nie inne typy zmiennych.
Chaoix,
@Chaoix przy użyciu json_decode($str,true)powoduje, że konwertuje obiekty na tablice, dzięki czemu przejdzie kontrolę is_array. Jednak poprawiasz ciągi, liczby całkowite itp.
Paul Phillips
Rozumiem, co masz na myśli przez drugi parametr na json_encode. Nadal uważam, że rozwiązanie @Ahad Ali jest znacznie lepsze pod względem pisania i robienia json_decode tylko raz w twoich algorytmach.
Chaoix,
4

Musimy sprawdzić, czy przekazany ciąg nie jest liczbowy, ponieważ w tym przypadku kod_json nie zgłasza błędu.

function isJson($str) {
    $result = false;
    if (!preg_match("/^\d+$/", trim($str))) {
        json_decode($str);
        $result = (json_last_error() == JSON_ERROR_NONE);
    }

    return $result;
}
Siergiej Onishchenko
źródło
3

Wypróbowałem niektóre z tych rozwiązań, ale nic mi nie działało. Próbuję tej prostej rzeczy:

$isJson = json_decode($myJSON);

if ($isJson instanceof \stdClass || is_array($isJson)) {
   echo("it's JSON confirmed");
} else {
   echo("nope");
}

Myślę, że to dobre rozwiązanie, ponieważ dekodowanie JSON bez drugiego parametru daje obiekt.

EDYCJA: Jeśli wiesz, co będzie dane wejściowe, możesz dostosować ten kod do swoich potrzeb. W moim przypadku wiem, że mam Jsona, który zaczyna się od „{”, więc nie muszę sprawdzać, czy jest to tablica.

Greco Jonathan
źródło
Twój JSON może potencjalnie być po prostu tablicą, w którym to przypadku byłaby tablicą zamiast zamiast stdClass $ foo = "[1, 1, 2, 3]"; var_dump (json_decode ($ foo)); => array (4) {[0] => int (1) [1] => int (1) [2] => int (2) [3] => int (3)}
Misha Nasledov
3

Korzystając z PHPBench z następującą klasą, osiągnięto poniższe wyniki:

<?php

declare(strict_types=1);

/**
 * Benchmark doctrine persistent collection count method vs sizeof toArray
 * Revs is the number of times you want the benchmark to run
 * @Revs(1000)
 * @Iterations(100)
 */
class BenchmarkJson
{
    public function benchCatchValid(): bool
    {
        $validJson = '{"validJson":true}';
        try {
            json_decode($validJson, true, 512, JSON_THROW_ON_ERROR);
            return true;
        } catch(\JsonException $exception) {}
        return false;
    }

    public function benchCatchInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        try {
            json_decode($invalidJson, true, 512, JSON_THROW_ON_ERROR);
            return true;
        } catch(\JsonException $exception) {}
        return false;
    }

    public function benchLastErrorValid(): bool
    {
        $validJson = '{"validJson":true}';
        json_decode($validJson, true);
        return (json_last_error() === JSON_ERROR_NONE);
    }

    public function benchLastErrorInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        json_decode($invalidJson, true);
        return (json_last_error() === JSON_ERROR_NONE);
    }

    public function benchNullValid(): bool
    {
        $validJson = '{"validJson":true}';
        return (json_decode($validJson, true) !== null);
    }

    public function benchNullInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        return (json_decode($invalidJson, true) !== null);
    }
}
6 subjects, 600 iterations, 6,000 revs, 0 rejects, 0 failures, 0 warnings
(best [mean mode] worst) = 0.714 [1.203 1.175] 1.073 s)
T: 721.504μs μSD/r 0.089μs μRSD/r: 7.270%
suite: 1343ab9a3590de6065bc0bc6eeb344c9f6eba642, date: 2020-01-21, stime: 12:50:14
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+
| benchmark     | subject               | set | revs | its | mem_peak   | best    | mean    | mode    | worst   | stdev   | rstdev | diff  |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+
| BenchmarkJson | benchCatchValid       | 0   | 1000 | 100 | 2,980,168b | 0.954μs | 1.032μs | 1.016μs | 1.428μs | 0.062μs | 6.04%  | 1.33x |
| BenchmarkJson | benchCatchInvalid     | 0   | 1000 | 100 | 2,980,184b | 2.033μs | 2.228μs | 2.166μs | 3.001μs | 0.168μs | 7.55%  | 2.88x |
| BenchmarkJson | benchLastErrorValid   | 0   | 1000 | 100 | 2,980,184b | 1.076μs | 1.195μs | 1.169μs | 1.616μs | 0.083μs | 6.97%  | 1.54x |
| BenchmarkJson | benchLastErrorInvalid | 0   | 1000 | 100 | 2,980,184b | 0.785μs | 0.861μs | 0.863μs | 1.132μs | 0.056μs | 6.54%  | 1.11x |
| BenchmarkJson | benchNullValid        | 0   | 1000 | 100 | 2,980,168b | 0.985μs | 1.124μs | 1.077μs | 1.731μs | 0.114μs | 10.15% | 1.45x |
| BenchmarkJson | benchNullInvalid      | 0   | 1000 | 100 | 2,980,184b | 0.714μs | 0.775μs | 0.759μs | 1.073μs | 0.049μs | 6.36%  | 1.00x |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+

Wniosek: najszybszym sposobem sprawdzenia, czy json jest prawidłowy, jest zwrócenie json_decode($json, true) !== null).

Matthew Anderson
źródło
bardzo miło :) Podziwiam cię
Mahdi
3

Znalazłem to pytanie po wczorajszym napotkaniu czegoś podobnego w mojej pracy. Moje rozwiązanie ostatecznie stanowiło hybrydę niektórych z powyższych podejść:

function is_JSON($string) {

  $String_Is_JSON = (is_null(json_decode($string, TRUE))) ? FALSE : TRUE;

  return $String_Is_JSON;
}
Rounin
źródło
2

Nie wiem o wydajności ani elegancji mojego rozwiązania, ale właśnie tego używam:

if (preg_match('/^[\[\{]\"/', $string)) {
    $aJson = json_decode($string, true);
    if (!is_null($aJson)) {
       ... do stuff here ...
    }
}

Ponieważ wszystkie moje ciągi kodowane w JSON zaczynają się od {", wystarczy przetestować to za pomocą RegEx. W ogóle nie jestem biegły w RegEx, więc może być lepszy sposób, aby to zrobić. Ponadto: strpos () może być szybszy.

Po prostu próbuję oddać moją wartość dwupensową.

PS Właśnie zaktualizowałem ciąg RegEx, /^[\[\{]\"/aby znaleźć również ciągi tablic JSON. Więc teraz szuka albo „” albo {”na początku łańcucha.

maxpower9000
źródło
2

Powinno być coś takiego:

 function isJson($string)
 {
    // 1. Speed up the checking & prevent exception throw when non string is passed
    if (is_numeric($string) ||
        !is_string($string) ||
        !$string) {
        return false;
    }

    $cleaned_str = trim($string);
    if (!$cleaned_str || !in_array($cleaned_str[0], ['{', '['])) {
        return false;
    }

    // 2. Actual checking
    $str = json_decode($string);
    return (json_last_error() == JSON_ERROR_NONE) && $str && $str != $string;
}

UnitTest

public function testIsJson()
{
    $non_json_values = [
        "12",
        0,
        1,
        12,
        -1,
        '',
        null,
        0.1,
        '.',
        "''",
        true,
        false,
        [],
        '""',
        '[]',
        '   {',
        '   [',
    ];

   $json_values = [
        '{}',
        '{"foo": "bar"}',
        '[{}]',
        '  {}',
        ' {}  '
    ];

   foreach ($non_json_values as $non_json_value) {
        $is_json = isJson($non_json_value);
        $this->assertFalse($is_json);
    }

    foreach ($json_values as $json_value) {
        $is_json = isJson($json_value);
        $this->assertTrue($is_json);
    }
}
Tinh Dang
źródło
Podoba mi się, że sprawdzasz, czy to ciąg. Dobrze idzie w połączeniu z pierwszym rozwiązaniem, aby uniknąć, ErrorExceptionjeśli ciąg znaków jest tablicą lub obiektem.
sykez
1

Rozszerzanie tej odpowiedzi Co powiesz na następujące kwestie:

<?php

    $json = '[{"user_id":13,"username":"stack"},{"user_id":14,"username":"over"}]';
    //$json = '12';

    function isJson($string) {
        json_decode($string);
        if(json_last_error() == JSON_ERROR_NONE) {
            if(substr($string,0,1) == '[' && substr($string,-1) == ']') { return TRUE; }
            else if(substr($string,0,1) == '{' && substr($string,-1) == '}') { return TRUE; }
            else { return FALSE; }
        }
    }

    echo isJson($json);
?>
Sevenearths
źródło
1
Czy nie należy sprawdzać podciągu przed wykonaniem dekodowania, aby zaoszczędzić czas, jeśli błąd zostanie wykryty podczas tego sprawdzania? Wyobrażam sobie, że 4 kontrole podciągów byłyby szybsze niż kod_json, ale jeśli ktoś mógłby poprzeć mnie tym założeniem, doceniłbym wszelkie przemyślenia na ten temat.
Mark
To argument za taryfą. Nie znam wymaganego czasu przetwarzania, ale jeśli jest to szybsze, to tak.
Sevenearths
1

Cześć, oto mały fragment z mojej biblioteki, w tym pierwszym stanie sprawdzam tylko, czy dane to json, a następnie zwracam je, jeśli są poprawnie zdekodowane, zwróć uwagę na użycie substratu dla wydajności (nie widziałem jeszcze żadnego pliku json, który nie zaczynał przez {lub [

$input=trim($input);
if ((substr($input, 0, 1) == '{' && substr($input, -1) == '}') or (substr($input, 0, 1) == '[' && substr($input, -1) == ']')) {
    $output = json_decode($input, 1);
    if (in_array(gettype($output),['object','array'])) {
        #then it's definitely JSON
    }
}

Na to pytanie wysłano 34 odpowiedzi, z których wiele zgadza się z (błędnym) przekonaniem, że JSON musi reprezentować tablicę lub obiekt. Czy ta odpowiedź robi coś innego niż pozostałe 3 tuziny odpowiedzi?
miken32,

1

Kolejna sugestia ode mnie :)

function isJson(string $string) {
  return ($result = json_decode($string, true)) ? $result : $string;
}

0

Funkcja niestandardowa

function custom_json_decode(&$contents=NULL, $normalize_contents=true, $force_array=true){

    //---------------decode contents---------------------

    $decoded_contents=NULL;

    if(is_string($contents)){

        $decoded_contents=json_decode($contents,$force_array);

    }

    //---------------normalize contents---------------------

    if($normalize_contents===true){

        if(is_string($decoded_contents)){

            if($decoded_contents==='NULL'||$decoded_contents==='null'){

                $contents=NULL;
            }
            elseif($decoded_contents==='FALSE'||$decoded_contents==='false'){

                $contents=false;
            }
        }
        elseif(!is_null($decoded_contents)){

            $contents=$decoded_contents;
        }
    }
    else{

        //---------------validation contents---------------------

        $contents=$decoded_contents;
    }

    return $contents;
}

Skrzynie

$none_json_str='hello';

//------------decoding a none json str---------------

$contents=custom_json_decode($none_json_str); // returns 'hello'

//------------checking a none json str---------------

custom_json_decode($none_json_str,false);

$valid_json=false;

if(!is_null($none_json_str)){

    $valid_json=true;

}

Zasoby

https://gist.github.com/rafasashi/93d06bae83cc1a1f440b


0

Świeżo wykonana funkcja dla zgodności z PHP 5.2, jeśli potrzebujesz zdekodowanych danych na sukces:

function try_json_decode( $json, & $success = null ){
  // non-strings may cause warnings
  if( !is_string( $json )){
    $success = false;
    return $json;
  }

  $data = json_decode( $json );

  // output arg
  $success =

    // non-null data: success!
    $data !==  null  ||

    // null data from 'null' json: success!
    $json === 'null' ||

    // null data from '  null  ' json padded with whitespaces: success!
    preg_match('/^\s*null\s*$/', $json );

  // return decoded or original data
  return $success ? $data : $json;
}

Stosowanie:

$json_or_not = ...;

$data = try_json_decode( $json_or_not, $success );

if( $success )
     process_data( $data );
else what_the_hell_is_it( $data );

Niektóre testy:

var_dump( try_json_decode( array(), $success ), $success );
// ret = array(0){}, $success == bool(false)

var_dump( try_json_decode( 123, $success ), $success );
// ret = int(123), $success == bool(false)

var_dump( try_json_decode('      ', $success ), $success );
// ret = string(6) "      ", $success == bool(false)

var_dump( try_json_decode( null, $success ), $success );
// ret = NULL, $success == bool(false)

var_dump( try_json_decode('null', $success ), $success );
// ret = NULL, $success == bool(true)

var_dump( try_json_decode('  null  ', $success ), $success );
// ret = NULL, $success == bool(true)

var_dump( try_json_decode('  true  ', $success ), $success );
// ret = bool(true), $success == bool(true)

var_dump( try_json_decode('  "hello"  ', $success ), $success );
// ret = string(5) "hello", $success == bool(true)

var_dump( try_json_decode('  {"a":123}  ', $success ), $success );
// ret = object(stdClass)#2 (1) { ["a"]=> int(123) }, $success == bool(true)

0
function is_json($input) {

    $input = trim($input);

    if (substr($input,0,1)!='{' OR substr($input,-1,1)!='}')
        return false;

    return is_array(@json_decode($input, true));
}

2
@ użyj do debugowania (ukrywania błędu), ale absolutnie nie jest to zalecane
aswzen

0

Prosta modyfikacja odpowiedzi Henryka, aby dotknąć najbardziej wymaganych możliwości.

(w tym „{} i []”)

function isValidJson($string) {
    json_decode($string);
    if(json_last_error() == JSON_ERROR_NONE) {

        if( $string[0] == "{" || $string[0] == "[" ) { 
            $first = $string [0];

            if( substr($string, -1) == "}" || substr($string, -1) == "]" ) {
                $last = substr($string, -1);

                if($first == "{" && $last == "}"){
                    return true;
                }

                if($first == "[" && $last == "]"){
                    return true;
                }

                return false;

            }
            return false;
        }

        return false;
    }

    return false;

}

źródło
0

Najszybszym sposobem może być dekodowanie możliwego obiektu JSON na obiekt / tablicę PHP:

/**
 * If $value is a JSON encoded object or array it will be decoded 
 * and returned.
 * If $value is not JSON format, then it will be returned unmodified.
 */
function get_data( $value ) {
    if ( ! is_string( $value ) ) { return $value; }
    if ( strlen( $value ) < 2 ) { return $value; }
    if ( '{' != $value[0] && '[' != $value[0] ) { return $value; }

    $json_data = json_decode( $value );
    if ( ! $json_data ) { return $value; }
    return $json_data;
}
Philipp
źródło
0

Oto wydajna i prosta funkcja, którą utworzyłem (która wykorzystuje podstawową weryfikację ciągu przed użyciem json_decodedla większych ciągów):

function isJson($string) {
    $response = false;

    if (
        is_string($string) &&
        ($string = trim($string)) &&
        ($stringLength = strlen($string)) &&
        (
            (
                stripos($string, '{') === 0 &&
                (stripos($string, '}', -1) + 1) === $stringLength
            ) ||
            (
                stripos($string, '[{') === 0 &&
                (stripos($string, '}]', -1) + 2) === $stringLength
            )
        ) &&
        ($decodedString = json_decode($string, true)) &&
        is_array($decodedString)
    ) {
        $response = true;
    }

    return $response;
}

źródło