Самый быстрый способ проверить, является ли строка JSON в PHP? - PullRequest
342 голосов
/ 18 мая 2011

Мне нужен действительно очень быстрый способ проверки, является ли строка JSON или нет. Я чувствую, что это не лучший способ:

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

Любые энтузиасты производительности хотят улучшить этот метод?

Ответы [ 25 ]

5 голосов
/ 27 июня 2014

Раньше я просто проверял нулевое значение, что на самом деле было неверно.

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

Приведенный выше фрагмент кода отлично работает со строками. Однако, как только я предоставлю номер, он сломается. Например.

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

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

Исправить это было очень просто.

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

    if(($r_data != $data) && $r_data)
        print "Json success";
    else
        print "Json error";
5 голосов
/ 20 декабря 2016

in 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;
}
4 голосов
/ 11 мая 2016

Нам нужно проверить, не является ли переданная строка не числовой, потому что в этом случае json_decode не вызывает ошибок.

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

    return $result;
}
4 голосов
/ 08 февраля 2014

Еще один простой способ

function is_json($str)
{
    return is_array(json_decode($str,true));
}
3 голосов
/ 06 октября 2017

Я пробовал некоторые из этих решений, но у меня ничего не получалось. Я пробую эту простую вещь:

$isJson = json_decode($myJSON);

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

Я думаю, что это хорошее решение, так как декодирование JSON без второго параметра дает объект.

РЕДАКТИРОВАТЬ: Если вы знаете, что будет вход, вы можете адаптировать этот код для ваших нужд. В моем случае я знаю, что у меня есть Json, начинающийся с "{", поэтому мне не нужно проверять, является ли он массивом.

1 голос
/ 14 февраля 2013

Я не знаю о производительности или элегантности моего решения, но это то, что я использую:

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

Поскольку все мои строки в кодировке JSON начинаются с {", достаточно проверить это с помощью RegEx. Я не очень хорошо разбираюсь в RegEx, поэтому может быть лучший способ сделать это. Также: strpos () может быть быстрее.

Просто пытаюсь отдать мою стоимость в дар.

P.S. Просто обновил строку RegEx до /^[\[\{]\"/, чтобы также найти строки массива JSON. Так что теперь он ищет либо [", либо {" в начале строки.

1 голос
/ 09 июня 2015

Расширение на этот ответ Как насчет следующего:

<?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 голос
/ 09 апреля 2018

Должно быть примерно так:

 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);
    }
}
1 голос
/ 05 декабря 2018

Привет, вот небольшой фрагмент из моей библиотеки, в этом первом условии я просто проверяю, являются ли данные json, а затем возвращает их, если они правильно декодированы. Обратите внимание на использование substr для производительности (я еще не видел ни одного файла jsonне начинается ни {или [

$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 голосов
/ 05 июня 2019

Еще одно предложение от меня:)

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