web-dev-qa-db-fra.com

Le moyen le plus rapide de vérifier si une chaîne est JSON en PHP?

J'ai besoin d'une méthode très rapide pour vérifier si une chaîne est au format JSON ou non. J'ai l'impression que ce n'est pas la meilleure façon:

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

Les amateurs de performance veulent-ils améliorer cette méthode?

316
Kirk Ouimet
function isJson($string) {
 json_decode($string);
 return (json_last_error() == JSON_ERROR_NONE);
}
496
Henrik P. Hessel

Réponse à la question

La fonction json_last_error renvoie la dernière erreur survenue lors du codage et du décodage JSON. Donc, le moyen le plus rapide de vérifier le JSON valide est

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

Notez que json_last_error est pris en charge dans PHP> = 5.3.0 uniquement.

Programme complet pour vérifier l'ERREUR exacte

Il est toujours bon de connaître l'erreur exacte pendant la période de développement. Voici le programme complet pour vérifier l'erreur exacte en fonction de la documentation 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;
}

Test avec une entrée JSON valide

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

SORTIE valide

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

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

Test avec JSON invalide

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

SORTIE invalide

Syntax error, malformed JSON.

Note supplémentaire pour (PHP> = 5.2 && PHP <5.3.0)

Étant donné que json_last_error n'est pas pris en charge dans PHP 5.2, vous pouvez vérifier si le codage ou le décodage retourne boolean FALSE. Voici un exemple

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

J'espère que c'est utile. Bon codage!

137
Madan Sapkota

Utiliser json_decode pour "sonder" ce n’est peut-être pas le moyen le plus rapide. S'il s'agit d'une structure profondément imbriquée, alors instancier un grand nombre d'objets de tableaux pour les jeter, est un gaspillage de mémoire et de temps. 

Il serait donc plus rapide d’utiliser preg_match et le RFC4627 regex pour également assurer la validité:

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

La même chose en PHP:

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

Pas assez d'un amateur de performance à se soucier de repères ici cependant. 

69
mario

Tout ce que vous avez vraiment besoin de faire, c'est ceci ...

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

Cette demande ne nécessite même pas une fonction séparée. Enroulez simplement is_object autour de json_decode et continuez. On dirait que cette solution fait que les gens y mettent beaucoup trop de réflexion.

69
user1653711

Cela retournera true si votre chaîne représente un tableau ou objet json:

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

Il rejette les chaînes JSON contenant uniquement un nombre, une chaîne ou un booléen, bien que ces chaînes soient techniquement valides.

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)

C'est le moyen le plus court que je puisse trouver.

24
Cyril
function is_json($str){ 
    return json_decode($str) != null;
}

http://tr.php.net/manual/en/function.json-decode.php La valeur de retour est null si un codage non valide est détecté.

16
AhmetB - Google

Le moyen le plus simple et le plus rapide que j'utilise est le suivant.

$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

C'est parce que json_decode () renvoie NULL si la chaîne entrée n'est pas json ou json invalide. 


Fonction simple pour valider JSON

Si vous devez valider votre code JSON à plusieurs endroits, vous pouvez toujours utiliser la fonction suivante.

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

Dans la fonction ci-dessus, vous obtiendrez la valeur true si c'est un JSON valide.

14
Mohammad Mursaleen

Vous devez valider votre entrée pour vous assurer que la chaîne que vous transmettez n'est pas vide et est en fait une chaîne. Une chaîne vide n'est pas un JSON valide.

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

Dans PHP, je pense qu'il est plus important de déterminer si l'objet JSON même has data, car pour utiliser les données, vous devez appeler json_encode() ou json_decode(). Je suggère de refuser les objets JSON vides afin d'éviter toute exécution inutile d'encodages et de décodages sur des données vides.

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

Méthode simple est de vérifier le résultat JSON.

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

Cela va le faire:

function isJson($string) {
    $decoded = json_decode($string);
    if ( !is_object($decoded) && !is_array($decoded) ) {
        return false;
    }
    return (json_last_error() == JSON_ERROR_NONE);
}

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

Auparavant, je cherchais simplement une valeur nulle, ce qui était faux en réalité.

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

Le code ci-dessus fonctionne bien avec des chaînes. Cependant, dès que je fournis un numéro, il se sépare par exemple.

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

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

Pour résoudre ce que j'ai fait était très simple.

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

    if(($r_data != $data) && $r_data)
        print "Json success";
    else
        print "Json error";
5
Ahad Ali

dans 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;
}
5
Parsa

Un autre moyen simple

function is_json($str)
{
    return is_array(json_decode($str,true));
}
4
h0mayun

Nous devons vérifier si la chaîne transmise n'est pas numérique car dans ce cas, json_decode ne génère aucune erreur.

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

    return $result;
}
4

J'ai essayé certaines de ces solutions mais rien ne fonctionnait pour moi. J'essaye cette chose simple:

$isJson = json_decode($myJSON);

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

Je pense que c’est une bonne solution puisque JSON décode sans le second paramètre donner un objet.

EDIT: Si vous savez quelle sera l'entrée, vous pouvez adapter ce code à vos besoins. Dans mon cas, je sais que j'ai un Json qui commence par "{", donc je n'ai pas besoin de vérifier si c'est un tableau.

3
Greco Jonathan

Devrait être quelque chose comme ça:

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

Test de l'unité

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);
    }
}
1
Tinh Dang

Je ne connais pas les performances ni l'élégance de ma solution, mais c'est ce que j'utilise:

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

Puisque toutes mes chaînes encodées JSON commencent par {", il suffit de tester cela avec un RegEx. Je ne parle pas du tout couramment RegEx, il pourrait donc y avoir un meilleur moyen de le faire. Aussi: strpos () pourrait être plus rapide.

J'essaie juste de donner ma valeur à tuppence.

P.S. Vient de mettre à jour la chaîne RegEx sur /^[\[\{]\"/ afin de rechercher également les chaînes de tableau JSON. Donc, il cherche maintenant soit ["ou {" au début de la chaîne.

1
maxpower9000

Développer cette réponse Que diriez-vous de ce qui suit:

<?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);
?>
1
Sevenearths

Fonction fraîchement créée pour la compatibilité PHP 5.2, si vous avez besoin des données décodées en cas de succès:

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

Usage:

$json_or_not = ...;

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

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

Quelques tests:

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
biziclop

Une autre suggestion de moi :)

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

Bonjour, voici un petit extrait de ma bibliothèque. Dans cette première condition, je vérifie simplement si les données sont au format json, puis nous les renvoyons si elles sont correctement décodées. Veuillez noter l’utilisation de sous-substrat pour les performances (je n’ai encore vu aucun fichier json ne commençant ni par {ou [

$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
    }
}
0
Jack
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));
}
0
GONZO

Le moyen le plus rapide de peut-être de décoder un objet JSON possible en un objet/tableau 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;
}
0
Philipp

La fonction personnalisée

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

Cas

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

}

Ressources

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

0
RafaSashi

Une simple modification de la réponse de henrik pour toucher la plupart des possibilités requises.

(y compris "{} et []")

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;

}
0
user4395445