1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @package toolkit |
||
5 | */ |
||
6 | |||
7 | /** |
||
8 | * The `JSONException` class extends the base `Exception` class. It's only |
||
9 | * difference is that it will translate the `$code` to a human readable |
||
10 | * error. |
||
11 | * |
||
12 | * @since Symphony 2.3 |
||
13 | */ |
||
14 | if (!class_exists('JSONException', false)) { |
||
15 | class JSONException extends Exception |
||
16 | { |
||
17 | /** |
||
18 | * Constructor takes a `$message`, `$code` and the original Exception, `$ex`. |
||
19 | * Upon translating the `$code` into a more human readable message, it will |
||
20 | * initialise the base `Exception` class. If the `$code` is unfamiliar, the original |
||
21 | * `$message` will be passed. |
||
22 | * |
||
23 | * @param string $message |
||
24 | * @param integer $code |
||
25 | * @param Exception $ex |
||
26 | */ |
||
27 | public function __construct($message, $code = -1, Exception $ex = null) |
||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||
28 | { |
||
29 | switch ($code) { |
||
30 | case JSON_ERROR_NONE: |
||
31 | $message = __('No errors.'); |
||
32 | break; |
||
33 | case JSON_ERROR_DEPTH: |
||
34 | $message = __('Maximum stack depth exceeded.'); |
||
35 | break; |
||
36 | case JSON_ERROR_STATE_MISMATCH: |
||
37 | $message = __('Underflow or the modes mismatch.'); |
||
38 | break; |
||
39 | case JSON_ERROR_CTRL_CHAR: |
||
40 | $message = __('Unexpected control character found.'); |
||
41 | break; |
||
42 | case JSON_ERROR_SYNTAX: |
||
43 | $message = __('Syntax error, malformed JSON.'); |
||
44 | break; |
||
45 | case JSON_ERROR_UTF8: |
||
46 | $message = __('Malformed UTF-8 characters, possibly incorrectly encoded.'); |
||
47 | break; |
||
48 | default: |
||
49 | if (!$message) { |
||
50 | $message = __('Unknown JSON error'); |
||
51 | } |
||
52 | break; |
||
53 | } |
||
54 | |||
55 | parent::__construct($message, $code, $ex); |
||
56 | } |
||
57 | } |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * The `JSON` class takes a JSON formatted string and converts it to XML. |
||
62 | * The majority of this class was originally written by Brent Burgoyne, thank you. |
||
63 | * |
||
64 | * @since Symphony 2.3 |
||
65 | * @author Brent Burgoyne |
||
66 | */ |
||
67 | class JSON |
||
68 | { |
||
69 | private static $dom; |
||
70 | |||
71 | /** |
||
72 | * Given a JSON formatted string, this function will convert it to an |
||
73 | * equivalent XML version (either standalone or as a fragment). The JSON |
||
74 | * will be added under a root node of `<data>`. |
||
75 | * |
||
76 | * @throws JSONException |
||
77 | * @param string $json |
||
78 | * The JSON formatted class |
||
79 | * @param boolean $standalone |
||
80 | * If passed true (which is the default), this parameter will cause |
||
81 | * the function to return the XML with an XML declaration, otherwise |
||
82 | * the XML will be returned as a fragment. |
||
83 | * @return string |
||
84 | * Returns a XML string |
||
85 | */ |
||
86 | public static function convertToXML($json, $standalone = true) |
||
0 ignored issues
–
show
|
|||
87 | { |
||
88 | self::$dom = new DomDocument('1.0', 'utf-8'); |
||
89 | self::$dom->formatOutput = true; |
||
90 | |||
91 | // remove callback functions from JSONP |
||
92 | if (preg_match('/(\{|\[).*(\}|\])/s', $json, $matches)) { |
||
93 | $json = $matches[0]; |
||
94 | } else { |
||
95 | throw new JSONException(__("JSON not formatted correctly")); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
JSON not formatted correctly does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
96 | } |
||
97 | |||
98 | $data = json_decode($json); |
||
99 | if (function_exists('json_last_error')) { |
||
100 | if (json_last_error() !== JSON_ERROR_NONE) { |
||
101 | throw new JSONException(__("JSON not formatted correctly"), json_last_error()); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
JSON not formatted correctly does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
102 | } |
||
103 | } elseif (!$data) { |
||
104 | throw new JSONException(__("JSON not formatted correctly")); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
JSON not formatted correctly does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
105 | } |
||
106 | |||
107 | $data_element = self::_process($data, self::$dom->createElement('data')); |
||
108 | self::$dom->appendChild($data_element); |
||
109 | |||
110 | if ($standalone) { |
||
111 | return self::$dom->saveXML(); |
||
112 | } else { |
||
113 | return self::$dom->saveXML(self::$dom->documentElement); |
||
114 | } |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * This function recursively iterates over `$data` and uses `self::$dom` |
||
119 | * to create an XML structure that mirrors the JSON. The results are added |
||
120 | * to `$element` and then returned. Any arrays that are encountered are added |
||
121 | * to 'item' elements. |
||
122 | * |
||
123 | * @param mixed $data |
||
124 | * The initial call to this function will be of `stdClass` and directly |
||
125 | * from `json_decode`. Recursive calls after that may be of `stdClass`, |
||
126 | * `array` or `string` types. |
||
127 | * @param DOMElement $element |
||
128 | * The `DOMElement` to append the data to. The root node is `<data>`. |
||
129 | * @return DOMElement |
||
130 | */ |
||
131 | private static function _process($data, DOMElement $element) |
||
132 | { |
||
133 | if (is_array($data)) { |
||
134 | foreach ($data as $item) { |
||
135 | $item_element = self::_process($item, self::$dom->createElement('item')); |
||
136 | $element->appendChild($item_element); |
||
137 | } |
||
138 | } elseif (is_object($data)) { |
||
139 | $vars = get_object_vars($data); |
||
140 | foreach ($vars as $key => $value) { |
||
141 | $key = self::_valid_element_name($key); |
||
142 | |||
143 | $var_element = self::_process($value, $key); |
||
144 | $element->appendChild($var_element); |
||
145 | } |
||
146 | } else { |
||
147 | $element->appendChild(self::$dom->createTextNode($data)); |
||
148 | } |
||
149 | |||
150 | return $element; |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * This function takes a string and returns an empty DOMElement |
||
155 | * with a valid name. If the passed `$name` is a valid QName, the handle of |
||
156 | * this name will be the name of the element, otherwise this will fallback to 'key'. |
||
157 | * |
||
158 | * @see toolkit.Lang#createHandle |
||
159 | * @param string $name |
||
160 | * If the `$name` is not a valid QName it will be ignored and replaced with |
||
161 | * 'key'. If this happens, a `@value` attribute will be set with the original |
||
162 | * `$name`. If `$name` is a valid QName, it will be run through `Lang::createHandle` |
||
163 | * to create a handle for the element. |
||
164 | * @return DOMElement |
||
165 | * An empty DOMElement with `@handle` and `@value` attributes. |
||
166 | */ |
||
167 | private static function _valid_element_name($name) |
||
168 | { |
||
169 | if (Lang::isUnicodeCompiled()) { |
||
170 | $valid_name = preg_match('/^[\p{L}]([0-9\p{L}\.\-\_]+)?$/u', $name); |
||
171 | } else { |
||
172 | $valid_name = preg_match('/^[A-z]([\w\d\-_\.]+)?$/i', $name); |
||
173 | } |
||
174 | |||
175 | if ($valid_name) { |
||
176 | $xKey = self::$dom->createElement( |
||
177 | Lang::createHandle($name) |
||
178 | ); |
||
179 | } else { |
||
180 | $xKey = self::$dom->createElement('key'); |
||
181 | } |
||
182 | |||
183 | $xKey->setAttribute('handle', Lang::createHandle($name)); |
||
184 | $xKey->setAttribute('value', General::sanitize($name)); |
||
185 | |||
186 | return $xKey; |
||
187 | } |
||
188 | } |
||
189 |