¿La forma más rápida de verificar si una cadena es JSON en PHP?

385

Necesito un método muy, muy rápido para verificar si una cadena es JSON o no. Siento que esta no es la mejor manera:

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

¿Algún entusiasta del rendimiento quiere mejorar este método?

Kirk Ouimet
fuente
3
Considere usar solo json_decodeuna vez ... también, verifique los valores de entrada y retorno de json_decode.
55
Entonces, ¿cuál es la respuesta?
Farid Rn
8
El interruptor ternario aquí es redundante. Su declaración ya se evalúa como booleana.
Luché con un oso una vez.
Acepte la respuesta de Lewis Donovan ... está funcionando bien
Poonam Bhatt

Respuestas:

574
function isJson($string) {
 json_decode($string);
 return (json_last_error() == JSON_ERROR_NONE);
}
Henrik P. Hessel
fuente
19
Parece que a todos les encanta esta respuesta. ¿Alguna explicación por qué?
Kirk Ouimet
8
Creo que PHP 5.3> es necesario para usar la función json_last_error
Chris Harrison
97
Verificar el primer carácter de la cadena {, [o el primer símbolo de cualquier otro literal, puede acelerar enormemente este cuando se espera que muchas de las cadenas entrantes no sean JSON.
Oleg V. Volkov
20
$ phone = '021234567'; var_dump (isJson ($ phone)); volver verdadero no! Debería devolver falso.
vee
23
Tenga cuidado, esta función también devolverá verdadero para cualquier número, ya sea que lo especifique como una cadena o un número verdadero. 6.5 = true, '300' = true, 9 = trueetc. Por lo tanto, este podría ser un valor JSON válido, pero la función podría no comportarse como espera, si desea verificar solo las cadenas JSON válidas con {}o [];
BadHorsie
156

Respuesta a la pregunta

La función json_last_errordevuelve el último error ocurrido durante la codificación y decodificación JSON. Entonces, la forma más rápida de verificar el JSON válido es

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

Tenga en cuenta que solo json_last_errores compatible con PHP> = 5.3.0.

Programa completo para verificar el ERROR exacto

Siempre es bueno saber el error exacto durante el tiempo de desarrollo. Aquí hay un programa completo para verificar el error exacto basado en documentos 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;
}

Prueba con ENTRADA JSON válida

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

SALIDA válida

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

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

Prueba con JSON no válido

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

SALIDA inválida

Syntax error, malformed JSON.

Nota adicional para (PHP> = 5.2 && PHP <5.3.0)

Como json_last_errorno es compatible con PHP 5.2, puede verificar si la codificación o decodificación devuelve un valor booleano FALSE. Aquí hay un ejemplo

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

Espero que esto sea útil. ¡Feliz codificación!

Madan Sapkota
fuente
Poca precisión: si esta json es válida pero una decodificada anterior no es válida, su código funcionará correctamente, porque: " Devuelve el último error (si lo hubiera) ocurrido durante la última codificación / decodificación JSON "
Bruno
Gracias @Madan, la verificación "json_decode" me resolvió que estaba ejecutando PHP 7.0.
Francis Rodrigues
¿Seguramente json_decode podría devolver falso para el falso literal, por lo ((strlen($json) === 5) && ($json !== 'false'))que también se debe realizar una comprobación para evitar esa ventaja?
MrMesees
@Bruno Si la última decodificación funciona sin errores, json_last_errorregresa JSON_ERROR_NONE.
Andrea
80

Todo lo que realmente necesitas hacer es esto ...

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

Esta solicitud ni siquiera requiere una función separada. Simplemente envuelva is_object alrededor de json_decode y continúe. Parece que esta solución hace que la gente piense demasiado en ella.

usuario1653711
fuente
1
@ RomanM.Kos Solo para que quede claro, si la matriz es una matriz simple, debe usarla is_arrayademás is_object, de lo contrario is_object, devolverá falso para las matrices simples codificadas como JSON. Entonces @ggutenberg tiene razón en este caso. Pasar el argumento verdadero a json_decodeobliga a un objeto a ser devuelto como una matriz. En teoría, siempre podría forzar la decodificación a una matriz y simplemente verificar is_array, eso debería funcionar.
userabuser
@userabuser Si busco json_encode($array)una matriz PHP simple, y luego json_decode($str)recibo un objeto, pero no una matriz. json_decode($str, true)obliga a convertir en matriz. ¿Por qué hacer una cadena complicada en su código? Verifique is_array(json_decode($str, true))y, algún tiempo después, cuando lo lea, comprenderá que la decodificación debe ser solo una matriz. Mucho más difícil de adivinar is_object(json_decode($MyJSONArray))"Oh, ¿estoy comprobando si la decodificación es una matriz o no?"
Roman M. Koss
@ RomanM.Kos No, eso no es correcto, codepad.viper-7.com/OFrtsq : como dije, siempre puede forzar la json_decodedevolución de una matriz para evitar que compruebe el objeto y la matriz, pero si no lo hace Y usted json_decodequé Era una matriz simple para empezar, recibirá una matriz a cambio de la decodificación, no un objeto. Debe usarlo JSON_FORCE_OBJECTsi desea forzar siempre que un objeto en la codificación IF pase una matriz simple.
userabuser
11
Downvote por decir: This request does not require a separate function even. Estrictamente hablando, ninguna solución requiere una función separada. El objetivo de una función no es hacer que varias líneas de código se vean como una sola línea de código. El objetivo de la función es hacer que el proceso de verificación JSON sea estándar en todas partes en su aplicación, de modo que los diferentes programadores (o el mismo programador a lo largo del tiempo) no utilicen diferentes procedimientos de verificación en diferentes etapas del flujo del programa.
cartbeforehorse
71

Usar json_decodepara "sondear" podría no ser la forma más rápida. Si se trata de una estructura profundamente anidada, crear instancias de muchos objetos de matrices para tirarlas es una pérdida de memoria y tiempo.

Por lo tanto, podría ser más rápido de usar preg_matchy la expresión regular RFC4627 para garantizar también la validez :

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

Lo mismo en PHP:

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

Sin embargo, no hay suficiente entusiasta del rendimiento para molestarse con los puntos de referencia aquí.

mario
fuente
11
Complete la expresión regular recursiva para verificar JSON aquí: stackoverflow.com/questions/2583472/regex-to-validate-json/… - Pero resulta que PHP json_decodesiempre es más rápido que una expresión regular PCRE. (Aunque no está muy optimizado, no se encontraron pruebas sintéticas, y podrían comportarse de manera diferente en Perl ..)
Mario
3
@vee Sí, gracias por la nota. Pero vamos a mantenerlo aquí [incorrectamente], para que nadie lo use en producción.
mario
1
@cartbeforehorse Bien, gracias. Entonces arreglé el escape saludable para el contexto de cadena doblemente citado de PHP.
mario
1
@cartbeforehorse No lo hace. Principalmente decoración. Es solo la barra diagonal inversa que realmente requiere doble escape. Porque \r \n \tsolo tiene sentido para que PHP no los interpole, sino que permita que PCRE los interprete (solo era necesario para el /xmodo). Las otras ocurrencias no lo necesitan estrictamente; sin embargo, "la barra invertida se escapa" en todos los contextos de cadenas de PHP. Entonces uno podría considerarlo más exacto.
mario
44
@mario Bien, ya veo. Básicamente, el PHP escapa de las barras diagonales inversas antes de que el motor de reg-exp lo vea. En lo que respecta al motor de reg-exp, hay la mitad del número de barras invertidas en la cadena que lo que vemos los humanos. "Como reg-exp ya no era lo suficientemente complicado"
cartbeforehorse
39

Esto devolverá verdadero si su cadena representa una matriz u objeto json :

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

Rechaza cadenas json que solo contienen un número, cadena o booleano, aunque esas cadenas son json técnicamente válidas.

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)

Es el camino más corto que se me ocurre.

Cirilo
fuente
En lugar de var_dump, podría poner esto en un caso de prueba PHPUnit. De lo contrario, estoy sorprendido y feliz de saber que es verdad.
MrMesees
3
¿Por qué todos los demás tienen respuestas tan largas cuando esto funciona muy bien? Gracias.
toddmo
1
Simplemente encantador! No busqué la "forma más rápida" o el rendimiento inteligente, pero este seguro cubre todos los casos que verificaría. Este es un ejemplo clásico para el infame proverbio "No uses mazo para romper una nuez" . Desde el punto de vista del programador, siempre es mejor mantener el código simple, corto y fácil de entender, el rendimiento frente a la simplicidad es otro debate fuera de alcance para este hilo.
Fr0zenFyr
Esta es una buena lógica, pero también tenga en cuenta que devuelve falso para las matrices vacías. Por ejemplo: var_dump(isJson('[]')); // bool(false). Según la documentación sobre booleanos, esto se debe a que PHP evalúa las matrices con cero elementos como falsas. Aquí hay una enmienda menor para ajustar la declaración de devolución; realiza una comparación idéntica en la salida decodificada que maneja este caso:return $json !== false && $str != $json;
j13k
@ j13k La comparación idéntica se evalúa isJson('hello')como verdadera, lo que no es válido json. La comparación suelta se elige a propósito aquí. No tengo una solución rápida para la situación de matriz / objeto vacía, excepto una feareturn $json == '[]' || ...
Cyril
21

La forma más simple y rápida que uso es la siguiente;

$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

Es porque json_decode () devuelve NULL si la cadena ingresada no es json o json no válida.


Función simple para validar JSON

Si tiene que validar su JSON en varios lugares, siempre puede usar la siguiente función.

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

En la función anterior, obtendrá true a cambio si es un JSON válido.

Mohammad Mursaleen
fuente
3
json_decode('null') == NULLy nulles un valor JSON válido.
zzzzBov
He probado si 'null' es json válido en json.parser.online pero parece que no es json válido. Y json_decode () es la función central de php para validar json, así que dudo obtener algún resultado falso en nuestra salida.
Mohammad Mursaleen
En lugar de confiar en un sitio web no verificado, considere consultar la especificación, que no está de acuerdo (página 2) . Alternativamente, intente JSON.parse('null')en su consola de desarrollo.
zzzzBov
19
function is_json($str){ 
    return json_decode($str) != null;
}

El valor de retorno http://tr.php.net/manual/en/function.json-decode.php es nulo cuando se detecta una codificación no válida.

AhmetB - Google
fuente
44
También devolverá incorrectamente nulo para "nulo" (que no es válido JSON, pero de lo contrario puede ser completamente "válido" para json_decode). Imagínate.
Creo que esto debería ser: json_decode($str)!=null;o de lo contrario, la función debería llamarse is_not_json.
Yoshi
¡Esa función sería mejor renombrada "es algo diferente a JSON"!
solitario
2
@ user166390, json_decode('null')es JSON válido de acuerdo con la especificación y debe devolver el valor de null.
zzzzBov
Tenga en cuenta también que con este método is_json('false')y is_json('[]')regresará falseya que el tipo no está marcado. Creo que este método debería regresar $str === null || json_decode($str) !== null.
Antoine Pinsard
11

Debe validar su entrada para asegurarse de que la cadena que pasa no esté vacía y que, de hecho, sea una cadena. Una cadena vacía no es JSON válida.

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

Creo que en PHP es más importante determinar si el objeto JSON incluso tiene datos, porque para usar los datos tendrá que llamar json_encode()o json_decode(). Sugiero negar objetos JSON vacíos para que no esté ejecutando codificaciones y decodificaciones innecesariamente en datos vacíos.

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;
}
alegre
fuente
+1 por pensar realmente en el problema en un contexto del mundo real.
cartbeforehorse
Pero '0'no es válido json ... ¿por qué sería cauteloso? @Kzqai
hasta el
11

Esto lo hará:

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

Como se muestra en otras respuestas, json_last_error()devuelve cualquier error de nuestro último json_decode (). Sin embargo, hay algunos casos de uso en los que esta función por sí sola no es lo suficientemente completa. Por ejemplo, si usted es json_decode()un número entero (por ejemplo:) 123, o una cadena de números sin espacios u otros caracteres (por ejemplo:) "123", la json_last_error()función no detectará un error.

Para combatir esto, agregué un paso adicional que garantiza que el resultado de nuestro json_decode()sea ​​un objeto o una matriz. Si no es así, volvemos false.

Para ver esto en acción, consulte estos dos ejemplos:

Lewis Donovan
fuente
"hello"es un JSON válido, y no es un objeto ni una matriz, json_last_error()es suficiente
JoniJnm
1
json_last_error()devuelve el código de error 4cuando json_decode()la cadena "hello". Ejemplo aquí: 3v4l.org/lSsEo
Lewis Donovan
Su código es incorrecto, hellono es un JSON válido, pero "hello"es 3v4l.org/OEJrQ
JoniJnm el
9

El método fácil es verificar el resultado de json.

$result = @json_decode($json,true);
    if (is_array($result)) {
        echo 'JSON is valid';
    }else{
        echo 'JSON is not valid';
    }
Rameez Rami
fuente
6

en 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
fuente
5

Anteriormente solo estaba buscando un valor nulo, que en realidad estaba mal.

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

El código anterior funciona bien con cadenas. Sin embargo, tan pronto como proporciono un número, se rompe, por ejemplo.

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

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

Para solucionarlo, lo que hice fue muy simple.

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

    if(($r_data != $data) && $r_data)
        print "Json success";
    else
        print "Json error";
Ahad Ali
fuente
Buena solución ¡Maneja muy bien el problema de mecanografía!
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
fuente
4

Otra forma simple

function is_json($str)
{
    return is_array(json_decode($str,true));
}
h0mayun
fuente
1
Esto no es correcto Cualquier tipo de PHP se puede codificar en JSON, como objetos, cadenas, etc. y se espera que la función json_decode los devuelva. Esto solo es cierto si siempre está decodificando matrices y no hay otros tipos de variables.
Chaoix
El uso de @Chaoix json_decode($str,true)hace que convierta los objetos en matrices para que pase la verificación is_array. Sin embargo, corrige sobre cadenas, enteros, etc.
Paul Phillips
Veo lo que quieres decir sobre el segundo parámetro en json_encode. Todavía creo que la solución de @Ahad Ali es mucho mejor en términos de tipeo y solo hacer un json_decode una vez en sus algoritmos.
Chaoix
4

Necesitamos verificar si la cadena pasada no es numérica porque en este caso json_decode no genera ningún error.

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

    return $result;
}
Sergey Onishchenko
fuente
4

Encontré esta pregunta después de encontrar algo similar en mi trabajo, ayer. Mi solución al final fue un híbrido de algunos de los enfoques anteriores:

function is_JSON($string) {

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

  return $String_Is_JSON;
}
Rounin
fuente
3

He probado algunas de esas soluciones, pero nada funcionaba para mí. Intento esto simple:

$isJson = json_decode($myJSON);

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

Creo que es una buena solución ya que la decodificación JSON sin el segundo parámetro da un objeto.

EDITAR: si sabe cuál será la entrada, puede adaptar este código a sus necesidades. En mi caso, sé que tengo un Json que comienza por "{", así que no necesito verificar si es una matriz.

Greco Jonathan
fuente
Su JSON podría ser simplemente una matriz, en cuyo caso sería una matriz en lugar de 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

Usando PHPBench con la siguiente clase, se lograron los siguientes resultados:

<?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 |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+

Conclusión: la forma más rápida de verificar si json es válido es regresar json_decode($json, true) !== null).

Matthew Anderson
fuente
muy agradable :) te admiro
Mahdi
2

No sé sobre el rendimiento o la elegancia de mi solución, pero es lo que estoy usando:

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

Dado que todas mis cadenas codificadas con JSON comienzan con {"es suficiente probar esto con un RegEx. No tengo fluidez en absoluto con RegEx, por lo que podría haber una mejor manera de hacerlo. Además: strpos () podría ser más rápido.

Solo trato de ceder mi valor de tuppence.

PD: acabo de actualizar la cadena RegEx /^[\[\{]\"/para también encontrar cadenas de matriz JSON. Por lo tanto, ahora busca ["o {" al comienzo de la cadena.

maxpower9000
fuente
2

Debería ser algo como esto:

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

Prueba de unidad

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
fuente
Me gusta que estés comprobando si es una cuerda. Combina bien con la primera solución para evitar ErrorExceptionsi la cadena es una matriz o un objeto.
sykez
1

Ampliando esta respuesta ¿Qué tal lo siguiente:

<?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
fuente
1
¿No debería realizarse la comprobación de la subcadena antes de ejecutar la decodificación para ahorrar tiempo si se encuentra el error en esa comprobación? Me imagino que 4 comprobaciones de subcadenas serían más rápidas que un json_decode, pero si alguien pudiera respaldarme con esta suposición, agradecería cualquier idea al respecto.
Mark
Ese es un argumento de tarifa. No sé el tiempo de procesamiento involucrado, pero si es más rápido, entonces sí.
Sevenearths
1

Hola, aquí hay un pequeño fragmento de mi biblioteca, en esta primera condición solo estoy verificando si los datos son json y luego los devuelvo si están decodificados correctamente, tenga en cuenta el uso de substr para el rendimiento (aún no he visto ningún archivo json que no comience ni por {o [

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

Se han publicado 34 respuestas a esta pregunta, muchas de las cuales también se suscriben a la creencia (errónea) de que JSON tiene que representar una matriz o un objeto. ¿Esta respuesta hace algo diferente de las otras 3 docenas de respuestas?
miken32

1

Otra sugerencia mía :)

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

0

La función personalizada

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

Casos

$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;

}

Recursos

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


0

Función recién hecha para compatibilidad con PHP 5.2, si necesita los datos decodificados en caso de éxito:

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

Uso:

$json_or_not = ...;

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

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

Algunas pruebas:

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
@ uso para depurar (ocultar un error) pero no es absolutamente recomendable
aswzen

0

Una modificación simple a la respuesta de henrik para tocar las posibilidades más requeridas.

(incluidos "{} y []")

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;

}

fuente
0

La manera más rápida de tal decodificar un posible objeto JSON a un objeto PHP / matriz:

/**
 * 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
fuente
0

Aquí hay una función simple y de alto rendimiento que creé (que usa la validación básica de cadenas antes de usar json_decodepara cadenas más grandes):

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

fuente