json_encode - ¿La forma más rápida de verificar si una cadena es JSON en PHP?
print json php (26)
Necesito un método realmente 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 por ahí quiere mejorar este método?
Respuesta a la pregunta
La función json_last_error
devuelve el último error ocurrido durante la codificación y decodificación JSON. Así que 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 json_last_error
es 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í está el 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;
}
Pruebas con la 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
)
)
Pruebas con JSON inválido
$json = ''{background-color:yellow;color:#000;padding:10px;width:650px;}'';
$output = json_validate($json);
print_r($output);
SALIDA VÁLIDA
Syntax error, malformed JSON.
Nota adicional para (PHP> = 5.2 && PHP <5.3.0)
Dado que json_last_error
no es compatible con PHP 5.2, puede verificar si la codificación o decodificación devuelve FALSE
booleano. Aquí hay un ejemplo
// decode the JSON data
$result = json_decode($json);
if ($result === FALSE) {
// JSON is invalid
}
Espero que esto sea de ayuda. ¡Feliz codificación!
Ampliando en esta respuesta ¿Qué hay de 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);
?>
Anteriormente estaba comprobando un valor nulo, que en realidad estaba equivocado.
$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 cuerdas. Sin embargo, tan pronto como proporciono el 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 arreglarlo 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";
Debe validar su entrada para asegurarse de que la cadena que pasa no esté vacía y, de hecho, es 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 tiene datos, porque para usar los datos deberá llamar a 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;
}
Esto devolverá verdadero si su cadena representa una matriz u objeto json :
function isJson($str) {
$json = json_decode($str);
return $json && $str != $json;
}
Rechaza las cadenas json que solo contienen un número, una cadena o un valor booleano, aunque esas cadenas son 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.
Esto lo hará:
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";
}
Función recién creada para la compatibilidad con PHP 5.2, si necesita que los datos descodificados sean exitosos:
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)
He intentado algo como eso
<?php
/* valid json */
$json1 =
json_encode([
''foo'' => ''bar'',
''bar'',
''foo2 '' => [
''bar'' => ''foo'',
''try''=> 32,
''foo'',
''bar'',
[[[[[[]]]]]]
],
''foobar''=>[
''foo''=>''bar'',
''bar''=>''foo''
]
]);
$json2 =
json_encode([
''foo'' => ''bar'',
''bar'',
''foo2 '' => [
''bar'' => ''foo'',
''try''=> 32,
''foo'',
''bar'',
[[[[[[]]]]]]
],
''foobar''=>[
''foo''=>''bar'',
''bar''=>''foo''
]
]) . '';''; // << invalid json
$mt = microtime(1);
for($i=0;$i<1000000;$i++){
check1($json1);
check1($json2);
}
echo "PROCESS TOOK: " . (microtime(1) - $mt) . " seconds/n";
$mt = microtime(1);
for($i=0;$i<1000000;$i++){
check2($json1);
check2($json2);
}
echo "PROCESS TOOK: " . (microtime(1) - $mt) . " seconds/n";
function check1($json){
return preg_match(''/(?(DEFINE)(?<number>-?(?=[1-9]|0(?!/d))/d+(/./d+)?([eE][+-]?/d+)?)(?<boolean>true|false|null)(?<string>"([^"////]*|////["////bfnrt//]|////u[0-9a-f]{4})*")(?<array>/[(?:(?&json)(?:,(?&json))*)?/s*/])(?<pair>/s*(?&string)/s*:(?&json))(?<object>/{(?:(?&pair)(?:,(?&pair))*)?/s*/})(?<json>/s*(?:(?&number)|(?&boolean)|(?&string)|(?&array)|(?&object))/s*))/A(?&json)/Z/six'', $json);
}
function check2($json){
json_decode($json);
return (json_last_error() === JSON_ERROR_NONE);
}
salida
PROCESS TOOK: 7.5640170574188 seconds
PROCESS TOOK: 4.4907619953156 seconds
hay ~ 3 segundos de diferencia entre la función de expresión regular y la función nativa json_decode, pero ocurre después de 1 millón de veces de repetición, por lo que no es demasiado breve de todos modos
Edición: después de algunos pensamientos prefiero esto;
if(checkjson($json)){
echo "this is json :3/n";
var_dump($json);
} else {
die(''omg this is not json!!!'');
}
function checkjson(&$json){
$json = json_decode($json);
return (json_last_error() === JSON_ERROR_NONE);
}
He intentado algunas de esas soluciones, pero nada estaba funcionando para mí. Intento esta cosa 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 comprobar si es una matriz.
La forma más rápida de decodificar un posible objeto JSON a un objeto / matriz 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;
}
La forma más sencilla y rápida que utilizo es seguirla;
$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
Se debe a que json_decode() devuelve NULL si la cadena ingresada no es json o no es 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.
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;
}
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 ...
}
}
Ya que todas mis cadenas codificadas en JSON comienzan con {"es suficiente probar esto con un RegEx. No soy del todo fluido con RegEx, así que podría haber una mejor manera de hacerlo. También: strpos() podría ser más rápido.
Solo trato de ceder en mi valor de tuppence.
PS Just actualizó la cadena RegEx a /^[/[/{]/"/
para encontrar también cadenas de matriz JSON. Por lo tanto, ahora busca [" o {"al principio de la cadena.
Otra forma sencilla
function is_json($str)
{
return is_array(json_decode($str,true));
}
Todo lo que necesitas hacer es esto ...
if (is_object(json_decode($MyJSONArray)))
{
... do something ...
}
Esta solicitud no requiere una función separada incluso. Solo envuelve is_object alrededor de json_decode y sigue adelante. Parece que esta solución tiene gente que piensa demasiado en ella.
Un 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'';
}
Una simple modificación de la respuesta de henrik para tocar las posibilidades más necesarias.
(incluyendo "{} 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;
}
Uno debería considerar algunos métodos de alineación de json más complicados. Prefiero usar https://github.com/Seldaek/jsonlint que no devuelve las falsas posividades mencionadas en las alternativas anteriores.
Usar json_decode
para "sondear" podría no ser la manera más rápida. Si se trata de una estructura profundamente anidada, la creación de una gran cantidad de objetos de arreglos para simplemente desecharlos es una pérdida de tiempo y memoria.
Por lo tanto, podría ser más rápido usar preg_match
y la RFC4627 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 es suficiente para los entusiastas del rendimiento como para preocuparse por los puntos de referencia.
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;
}
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);
}
}
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
function isJson($string) {
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
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));
}
function is_json($str){
return json_decode($str) != null;
}
http://tr.php.net/manual/en/function.json-decode.php valor de retorno de http://tr.php.net/manual/en/function.json-decode.php es nulo cuando se detecta una codificación no válida.
if(!empty(json_decode($data)))
{
echo "real json";
}