Ignore:
Timestamp:
2013/08/28 13:26:44 (11 years ago)
Author:
m_uehara
Message:

#2275
影響が大きいため、2.13.0では対応を行わない r23125 r23128 r23133 を差し戻します。

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/version-2_13-dev/data/module/Services/JSON.php

    r23125 r23141  
    11<?php 
    22/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 
     3 
    34/** 
    45 * Converts to and from JSON format. 
     
    5152 * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com> 
    5253 * @copyright   2005 Michal Migurski 
    53  * @version     CVS: $Id: JSON.php 305040 2010-11-02 23:19:03Z alan_k $ 
     54 * @version     CVS: $Id$ 
    5455 * @license     http://www.opensource.org/licenses/bsd-license.php 
    5556 * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198 
     
    9091 */ 
    9192define('SERVICES_JSON_SUPPRESS_ERRORS', 32); 
    92  
    93 /** 
    94  * Behavior switch for Services_JSON::decode() 
    95  */ 
    96 define('SERVICES_JSON_USE_TO_JSON', 64); 
    9793 
    9894/** 
     
    134130    *                                   bubble up with an error, so all return values 
    135131    *                                   from encode() should be checked with isError() 
    136     *                           - SERVICES_JSON_USE_TO_JSON:  call toJSON when serializing objects 
    137     *                                   It serializes the return value from the toJSON call rather  
    138     *                                   than the object it'self,  toJSON can return associative arrays,  
    139     *                                   strings or numbers, if you return an object, make sure it does 
    140     *                                   not have a toJSON method, otherwise an error will occur. 
    141132    */ 
    142133    function Services_JSON($use = 0) 
    143134    { 
    144135        $this->use = $use; 
    145         $this->_mb_strlen            = function_exists('mb_strlen'); 
    146         $this->_mb_convert_encoding  = function_exists('mb_convert_encoding'); 
    147         $this->_mb_substr            = function_exists('mb_substr'); 
    148     } 
    149     // private - cache the mbstring lookup results.. 
    150     var $_mb_strlen = false; 
    151     var $_mb_substr = false; 
    152     var $_mb_convert_encoding = false; 
    153      
     136    } 
     137 
    154138   /** 
    155139    * convert a string from one UTF-16 char to one UTF-8 char 
     
    166150    { 
    167151        // oh please oh please oh please oh please oh please 
    168         if($this->_mb_convert_encoding) { 
     152        if(function_exists('mb_convert_encoding')) { 
    169153            return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); 
    170154        } 
     
    210194    { 
    211195        // oh please oh please oh please oh please oh please 
    212         if($this->_mb_convert_encoding) { 
     196        if(function_exists('mb_convert_encoding')) { 
    213197            return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); 
    214198        } 
    215199 
    216         switch($this->strlen8($utf8)) { 
     200        switch(strlen($utf8)) { 
    217201            case 1: 
    218202                // this case should never be reached, because we are in ASCII range 
     
    241225 
    242226   /** 
    243     * encodes an arbitrary variable into JSON format (and sends JSON Header) 
     227    * encodes an arbitrary variable into JSON format 
    244228    * 
    245229    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded. 
     
    253237    function encode($var) 
    254238    { 
    255         header('Content-type: application/json'); 
    256         return $this->encodeUnsafe($var); 
    257     } 
    258     /** 
    259     * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!) 
    260     * 
    261     * @param    mixed   $var    any number, boolean, string, array, or object to be encoded. 
    262     *                           see argument 1 to Services_JSON() above for array-parsing behavior. 
    263     *                           if var is a strng, note that encode() always expects it 
    264     *                           to be in ASCII or UTF-8 format! 
    265     * 
    266     * @return   mixed   JSON string representation of input var or an error if a problem occurs 
    267     * @access   public 
    268     */ 
    269     function encodeUnsafe($var) 
    270     { 
    271         // see bug #16908 - regarding numeric locale printing 
    272         $lc = setlocale(LC_NUMERIC, 0); 
    273         setlocale(LC_NUMERIC, 'C'); 
    274         $ret = $this->_encode($var); 
    275         setlocale(LC_NUMERIC, $lc); 
    276         return $ret; 
    277          
    278     } 
    279     /** 
    280     * PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format  
    281     * 
    282     * @param    mixed   $var    any number, boolean, string, array, or object to be encoded. 
    283     *                           see argument 1 to Services_JSON() above for array-parsing behavior. 
    284     *                           if var is a strng, note that encode() always expects it 
    285     *                           to be in ASCII or UTF-8 format! 
    286     * 
    287     * @return   mixed   JSON string representation of input var or an error if a problem occurs 
    288     * @access   public 
    289     */ 
    290     function _encode($var)  
    291     { 
    292           
    293239        switch (gettype($var)) { 
    294240            case 'boolean': 
     
    303249            case 'double': 
    304250            case 'float': 
    305                 return  (float) $var; 
     251                return (float) $var; 
    306252 
    307253            case 'string': 
    308254                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT 
    309255                $ascii = ''; 
    310                 $strlen_var = $this->strlen8($var); 
     256                $strlen_var = strlen($var); 
    311257 
    312258               /* 
     
    350296                            // characters U-00000080 - U-000007FF, mask 110XXXXX 
    351297                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    352                             if ($c+1 >= $strlen_var) { 
    353                                 $c += 1; 
    354                                 $ascii .= '?'; 
    355                                 break; 
    356                             } 
    357                              
    358298                            $char = pack('C*', $ord_var_c, ord($var{$c + 1})); 
    359299                            $c += 1; 
     
    363303 
    364304                        case (($ord_var_c & 0xF0) == 0xE0): 
    365                             if ($c+2 >= $strlen_var) { 
    366                                 $c += 2; 
    367                                 $ascii .= '?'; 
    368                                 break; 
    369                             } 
    370305                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX 
    371306                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    372307                            $char = pack('C*', $ord_var_c, 
    373                                          @ord($var{$c + 1}), 
    374                                          @ord($var{$c + 2})); 
     308                                         ord($var{$c + 1}), 
     309                                         ord($var{$c + 2})); 
    375310                            $c += 2; 
    376311                            $utf16 = $this->utf82utf16($char); 
     
    379314 
    380315                        case (($ord_var_c & 0xF8) == 0xF0): 
    381                             if ($c+3 >= $strlen_var) { 
    382                                 $c += 3; 
    383                                 $ascii .= '?'; 
    384                                 break; 
    385                             } 
    386316                            // characters U-00010000 - U-001FFFFF, mask 11110XXX 
    387317                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
     
    398328                            // characters U-00200000 - U-03FFFFFF, mask 111110XX 
    399329                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    400                             if ($c+4 >= $strlen_var) { 
    401                                 $c += 4; 
    402                                 $ascii .= '?'; 
    403                                 break; 
    404                             } 
    405330                            $char = pack('C*', $ord_var_c, 
    406331                                         ord($var{$c + 1}), 
     
    414339 
    415340                        case (($ord_var_c & 0xFE) == 0xFC): 
    416                         if ($c+5 >= $strlen_var) { 
    417                                 $c += 5; 
    418                                 $ascii .= '?'; 
    419                                 break; 
    420                             } 
    421341                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X 
    422342                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
     
    433353                    } 
    434354                } 
    435                 return  '"'.$ascii.'"'; 
     355 
     356                return '"'.$ascii.'"'; 
    436357 
    437358            case 'array': 
     
    470391 
    471392                // treat it like a regular array 
    472                 $elements = array_map(array($this, '_encode'), $var); 
     393                $elements = array_map(array($this, 'encode'), $var); 
    473394 
    474395                foreach($elements as $element) { 
     
    481402 
    482403            case 'object': 
    483              
    484                 // support toJSON methods. 
    485                 if (($this->use & SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) { 
    486                     // this may end up allowing unlimited recursion 
    487                     // so we check the return value to make sure it's not got the same method. 
    488                     $recode = $var->toJSON(); 
    489                      
    490                     if (method_exists($recode, 'toJSON')) { 
    491                          
    492                         return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) 
    493                         ? 'null' 
    494                         : new Services_JSON_Error(class_name($var). 
    495                             " toJSON returned an object with a toJSON method."); 
    496                              
    497                     } 
    498                      
    499                     return $this->_encode( $recode ); 
    500                 }  
    501                  
    502404                $vars = get_object_vars($var); 
    503                  
     405 
    504406                $properties = array_map(array($this, 'name_value'), 
    505407                                        array_keys($vars), 
     
    532434    function name_value($name, $value) 
    533435    { 
    534         $encoded_value = $this->_encode($value); 
     436        $encoded_value = $this->encode($value); 
    535437 
    536438        if(Services_JSON::isError($encoded_value)) { 
     
    538440        } 
    539441 
    540         return $this->_encode(strval($name)) . ':' . $encoded_value; 
     442        return $this->encode(strval($name)) . ':' . $encoded_value; 
    541443    } 
    542444 
     
    611513                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { 
    612514                    // STRINGS RETURNED IN UTF-8 FORMAT 
    613                     $delim = $this->substr8($str, 0, 1); 
    614                     $chrs = $this->substr8($str, 1, -1); 
     515                    $delim = substr($str, 0, 1); 
     516                    $chrs = substr($str, 1, -1); 
    615517                    $utf8 = ''; 
    616                     $strlen_chrs = $this->strlen8($chrs); 
     518                    $strlen_chrs = strlen($chrs); 
    617519 
    618520                    for ($c = 0; $c < $strlen_chrs; ++$c) { 
    619521 
    620                         $substr_chrs_c_2 = $this->substr8($chrs, $c, 2); 
     522                        $substr_chrs_c_2 = substr($chrs, $c, 2); 
    621523                        $ord_chrs_c = ord($chrs{$c}); 
    622524 
     
    653555                                break; 
    654556 
    655                             case preg_match('/\\\u[0-9A-F]{4}/i', $this->substr8($chrs, $c, 6)): 
     557                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): 
    656558                                // single, escaped unicode character 
    657                                 $utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2))) 
    658                                        . chr(hexdec($this->substr8($chrs, ($c + 4), 2))); 
     559                                $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) 
     560                                       . chr(hexdec(substr($chrs, ($c + 4), 2))); 
    659561                                $utf8 .= $this->utf162utf8($utf16); 
    660562                                $c += 5; 
     
    668570                                // characters U-00000080 - U-000007FF, mask 110XXXXX 
    669571                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    670                                 $utf8 .= $this->substr8($chrs, $c, 2); 
     572                                $utf8 .= substr($chrs, $c, 2); 
    671573                                ++$c; 
    672574                                break; 
     
    675577                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX 
    676578                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    677                                 $utf8 .= $this->substr8($chrs, $c, 3); 
     579                                $utf8 .= substr($chrs, $c, 3); 
    678580                                $c += 2; 
    679581                                break; 
     
    682584                                // characters U-00010000 - U-001FFFFF, mask 11110XXX 
    683585                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    684                                 $utf8 .= $this->substr8($chrs, $c, 4); 
     586                                $utf8 .= substr($chrs, $c, 4); 
    685587                                $c += 3; 
    686588                                break; 
     
    689591                                // characters U-00200000 - U-03FFFFFF, mask 111110XX 
    690592                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    691                                 $utf8 .= $this->substr8($chrs, $c, 5); 
     593                                $utf8 .= substr($chrs, $c, 5); 
    692594                                $c += 4; 
    693595                                break; 
     
    696598                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X 
    697599                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
    698                                 $utf8 .= $this->substr8($chrs, $c, 6); 
     600                                $utf8 .= substr($chrs, $c, 6); 
    699601                                $c += 5; 
    700602                                break; 
     
    726628                                           'delim' => false)); 
    727629 
    728                     $chrs = $this->substr8($str, 1, -1); 
     630                    $chrs = substr($str, 1, -1); 
    729631                    $chrs = $this->reduce_string($chrs); 
    730632 
     
    741643                    //print("\nparsing {$chrs}\n"); 
    742644 
    743                     $strlen_chrs = $this->strlen8($chrs); 
     645                    $strlen_chrs = strlen($chrs); 
    744646 
    745647                    for ($c = 0; $c <= $strlen_chrs; ++$c) { 
    746648 
    747649                        $top = end($stk); 
    748                         $substr_chrs_c_2 = $this->substr8($chrs, $c, 2); 
     650                        $substr_chrs_c_2 = substr($chrs, $c, 2); 
    749651 
    750652                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { 
    751653                            // found a comma that is not inside a string, array, etc., 
    752654                            // OR we've reached the end of the character list 
    753                             $slice = $this->substr8($chrs, $top['where'], ($c - $top['where'])); 
     655                            $slice = substr($chrs, $top['where'], ($c - $top['where'])); 
    754656                            array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); 
    755                             //print("Found split at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
     657                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
    756658 
    757659                            if (reset($stk) == SERVICES_JSON_IN_ARR) { 
     
    766668                                $parts = array(); 
    767669                                 
    768                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:/Uis', $slice, $parts)) { 
    769                                   // "name":value pair 
     670                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { 
     671                                    // "name":value pair 
    770672                                    $key = $this->decode($parts[1]); 
    771                                     $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); 
     673                                    $val = $this->decode($parts[2]); 
     674 
    772675                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 
    773676                                        $obj[$key] = $val; 
     
    775678                                        $obj->$key = $val; 
    776679                                    } 
    777                                 } elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) { 
     680                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { 
    778681                                    // name:value pair, where name is unquoted 
    779682                                    $key = $parts[1]; 
    780                                     $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); 
     683                                    $val = $this->decode($parts[2]); 
    781684 
    782685                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) { 
     
    796699                        } elseif (($chrs{$c} == $top['delim']) && 
    797700                                 ($top['what'] == SERVICES_JSON_IN_STR) && 
    798                                  (($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($chrs, 0, $c), '\\'))) % 2 != 1)) { 
     701                                 ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { 
    799702                            // found a quote, we're in a string, and it's not escaped 
    800703                            // we know that it's not escaped becase there is _not_ an 
    801704                            // odd number of backslashes at the end of the string so far 
    802705                            array_pop($stk); 
    803                             //print("Found end of string at {$c}: ".$this->substr8($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); 
     706                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); 
    804707 
    805708                        } elseif (($chrs{$c} == '[') && 
     
    812715                            // found a right-bracket, and we're in an array 
    813716                            array_pop($stk); 
    814                             //print("Found end of array at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
     717                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
    815718 
    816719                        } elseif (($chrs{$c} == '{') && 
     
    823726                            // found a right-brace, and we're in an object 
    824727                            array_pop($stk); 
    825                             //print("Found end of object at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
     728                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
    826729 
    827730                        } elseif (($substr_chrs_c_2 == '/*') && 
     
    840743                                $chrs = substr_replace($chrs, ' ', $i, 1); 
    841744 
    842                             //print("Found end of comment at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
     745                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); 
    843746 
    844747                        } 
     
    872775        return false; 
    873776    } 
    874      
    875     /** 
    876     * Calculates length of string in bytes 
    877     * @param string  
    878     * @return integer length 
    879     */ 
    880     function strlen8( $str )  
    881     { 
    882         if ( $this->_mb_strlen ) { 
    883             return mb_strlen( $str, "8bit" ); 
    884         } 
    885         return strlen( $str ); 
    886     } 
    887      
    888     /** 
    889     * Returns part of a string, interpreting $start and $length as number of bytes. 
    890     * @param string  
    891     * @param integer start  
    892     * @param integer length  
    893     * @return integer length 
    894     */ 
    895     function substr8( $string, $start, $length=false )  
    896     { 
    897         if ( $length === false ) { 
    898             $length = $this->strlen8( $string ) - $start; 
    899         } 
    900         if ( $this->_mb_substr ) { 
    901             return mb_substr( $string, $start, $length, "8bit" ); 
    902         } 
    903         return substr( $string, $start, $length ); 
    904     } 
    905  
    906777} 
    907778 
     
    930801        } 
    931802    } 
     803 
     804} 
    932805     
    933 } 
     806?> 
Note: See TracChangeset for help on using the changeset viewer.