<?php

  /**
   * Classe json - traduzir PHP <=> JSON
   * -----------------------------------
   * 
   * @author Cau Guanabara <caugb@ibest.com.br>
   * @date 2006-09-01
   * ------------------------------------------
   * 
   *   Este script oferece funcionalidades para traduzir vari�veis 
   *   PHP* (veja os tipos suportados) para strings JSON e vice-versa.
   *
   *   *tipos suportados: boolean, NULL, integer, float, string e array
   *    ----------------
   * 
   *                                      H� apenas dois m�todos para uso p�blico:
   * -----------------------------------------------------------------------------
   *   toJson -> recebe uma vari�vel PHP e devolve uma string equivalente 
   *   ------    no formato JSON. Tipos n�o suportados s�o ignorados pelo sistema.
   *
   *     string json->toJson(mixed input_var)
   * 
   * -----------------------------------------------------------------------------
   *   toVar -> recebe uma string no formato JSON e devolve uma vari�vel PHP, 
   *   -----    do tipo correspondente.
   *
   *     mixed json->toVar(string input_var)
   *
   * -----------------------------------------------------------------------------
   */

// testes
/* 
$jsn = new json;
$arr = $jsn->toVar('{
    "type": "menu",
    "value": "File",
    "items": [
        {"value": "New", "action": "CreateNewDoc"},
        {"value": "Open", "action": "OpenDoc"},
        {"testarray": ["abc", false, true, null, [1,2.5,3], "as", ["q","e","j"]]},
        {"value": "Close", "action": "CloseDoc"}
    ]
}');
var_dump($arr);
print "<br /><br />";
print $jsn->toJson(array(1,2,3,array(false, NULL, 12.09, 'string')));
*/

class json {
  // Converte a variavel enviada para uma string JSON
  function toJson($input) {
    switch(gettype($input)) {
    case 'NULL': 
      return 'null';
    case 'boolean': 
      return $input ? "true" : "false";
    case 'integer': case 'float': case 'double': case 'real': 
      return $input;
    case 'string': 
      $prs = array('p' => array("/\n/","/\r/","/\'/"), 'r' => array('\\\n',"","\\'"));
      return "'".preg_replace($prs['p'], $prs['r'],$input)."'";
    case 'array': 
      $rar = array();
      $op = $this->isNumeric($input) ? "[ " : "{ ";
      $cl = $this->isNumeric($input) ? " ]" : " }";
        if($this->isNumeric($input)) foreach($input as $val) $rar[] = $this->toJson($val);
        else foreach($input as $ind => $val) $rar[] = $this->toJson($ind).": ".$this->toJson($val);
      return $op.join(", ",$rar).$cl; 
    default: return '';
    }
  }
  
  // Converte uma string JSON em um valor PHP do tipo apropriado
  function toVar($jstxt) {
  $js = trim($jstxt);
  $first = substr($js, 0, 1);
    if(preg_match("/^(true|false)$/", $js)) return $js == 'true' ? true : false;   // boolean
    elseif(preg_match("/^null$/i", $js)) return NULL;                              // null
    elseif(is_numeric($js)) return (int)$js == (float)$js ? (int)$js : (float)$js; // integer/float
    elseif(preg_match("/[\'\"]/", $first)) return substr($js,1,(count($js) - 2));  // string
    elseif(preg_match("/^[[{]/", $first)) return $this->parseArray($js);           // array/object
  }
  
  // Converte um array/object JSON para um array PHP.   
  // A string tem que come�ar com'[' ou '{' e terminar com ']' ou '}'
  function parseArray($js) {
    if(!preg_match("/^[\{\[]([\w\W]+)[\}\]]$/",$js)) return $js; // only arrays or objects
  $ret = $js;
  $er = "/\[([^][]+)\]/"; // array
    while(preg_match($er,$ret)) $ret = preg_replace($er,"array($1)",$ret,-1);
  $er = "/\{([^}{]+)\}/"; // object
  $functxt = '$arr = preg_split("/\s*,\s*/",$matches[1]); $ret = array(); '.
             'foreach($arr as $val) $ret[] = preg_replace("/\s*\:\s*/", " => ", $val, -1); '.
             'return "array(".join(", ", $ret).")";';
  $func = create_function('$matches', $functxt);
    while(preg_match($er,$ret)) $ret = preg_replace_callback($er, $func, $ret,-1);
  @eval('$retvar = '.$ret.';');
  return $retvar ? $retvar : 'Invalid JSON input';
  }
  
  // returna true se o array tem apenas chaves numericas
  function isNumeric($arr) {
    foreach($arr as $i => $v) if(gettype($i) != 'integer') return false;
  return true;
  }
}
?>