Commit 47bad912c6c0c2d727556c79de5b65e0c3d4de71
1 parent
e249362a
Exists in
master
and in
7 other branches
movido cpaint para pacotes
Showing
12 changed files
with
5260 additions
and
0 deletions
Show diff stats
@@ -0,0 +1,377 @@ | @@ -0,0 +1,377 @@ | ||
1 | +/* | ||
2 | +Copyright (c) 2005 JSON.org | ||
3 | + | ||
4 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | +of this software and associated documentation files (the "Software"), to deal | ||
6 | +in the Software without restriction, including without limitation the rights | ||
7 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
8 | +copies of the Software, and to permit persons to whom the Software is | ||
9 | +furnished to do so, subject to the following conditions: | ||
10 | + | ||
11 | +The Software shall be used for Good, not Evil. | ||
12 | + | ||
13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | +SOFTWARE. | ||
20 | +*/ | ||
21 | + | ||
22 | +Array.prototype.______array = '______array'; | ||
23 | + | ||
24 | +var JSON = { | ||
25 | + org: 'http://www.JSON.org', | ||
26 | + copyright: '(c)2005 JSON.org', | ||
27 | + license: 'http://www.crockford.com/JSON/license.html', | ||
28 | + | ||
29 | + stringify: function (arg) { | ||
30 | + var c, i, l, s = '', v; | ||
31 | + var numeric = true; | ||
32 | + | ||
33 | + switch (typeof arg) { | ||
34 | + case 'object': | ||
35 | + if (arg) { | ||
36 | + if (arg.______array == '______array') { | ||
37 | + // do a test whether all array keys are numeric | ||
38 | + for (i in arg) { | ||
39 | + if (i != '______array' | ||
40 | + && (isNaN(i) | ||
41 | + || !isFinite(i))) { | ||
42 | + numeric = false; | ||
43 | + break; | ||
44 | + } | ||
45 | + } | ||
46 | + | ||
47 | + if (numeric == true) { | ||
48 | + for (i = 0; i < arg.length; ++i) { | ||
49 | + if (typeof arg[i] != 'undefined') { | ||
50 | + v = this.stringify(arg[i]); | ||
51 | + if (s) { | ||
52 | + s += ','; | ||
53 | + } | ||
54 | + s += v; | ||
55 | + } else { | ||
56 | + s += ',null'; | ||
57 | + } | ||
58 | + } | ||
59 | + return '[' + s + ']'; | ||
60 | + } else { | ||
61 | + for (i in arg) { | ||
62 | + if (i != '______array') { | ||
63 | + v = arg[i]; | ||
64 | + if (typeof v != 'undefined' && typeof v != 'function') { | ||
65 | + v = this.stringify(v); | ||
66 | + if (s) { | ||
67 | + s += ','; | ||
68 | + } | ||
69 | + s += this.stringify(i) + ':' + v; | ||
70 | + } | ||
71 | + } | ||
72 | + } | ||
73 | + // return as object | ||
74 | + return '{' + s + '}'; | ||
75 | + } | ||
76 | + } else if (typeof arg.toString != 'undefined') { | ||
77 | + for (i in arg) { | ||
78 | + v = arg[i]; | ||
79 | + if (typeof v != 'undefined' && typeof v != 'function') { | ||
80 | + v = this.stringify(v); | ||
81 | + if (s) { | ||
82 | + s += ','; | ||
83 | + } | ||
84 | + s += this.stringify(i) + ':' + v; | ||
85 | + } | ||
86 | + } | ||
87 | + return '{' + s + '}'; | ||
88 | + } | ||
89 | + } | ||
90 | + return 'null'; | ||
91 | + case 'number': | ||
92 | + return isFinite(arg) ? String(arg) : 'null'; | ||
93 | + case 'string': | ||
94 | + l = arg.length; | ||
95 | + s = '"'; | ||
96 | + for (i = 0; i < l; i += 1) { | ||
97 | + c = arg.charAt(i); | ||
98 | + if (c >= ' ') { | ||
99 | + if (c == '\\' || c == '"') { | ||
100 | + s += '\\'; | ||
101 | + } | ||
102 | + s += c; | ||
103 | + } else { | ||
104 | + switch (c) { | ||
105 | + case '\b': | ||
106 | + s += '\\b'; | ||
107 | + break; | ||
108 | + case '\f': | ||
109 | + s += '\\f'; | ||
110 | + break; | ||
111 | + case '\n': | ||
112 | + s += '\\n'; | ||
113 | + break; | ||
114 | + case '\r': | ||
115 | + s += '\\r'; | ||
116 | + break; | ||
117 | + case '\t': | ||
118 | + s += '\\t'; | ||
119 | + break; | ||
120 | + default: | ||
121 | + c = c.charCodeAt(); | ||
122 | + s += '\\u00' + Math.floor(c / 16).toString(16) + | ||
123 | + (c % 16).toString(16); | ||
124 | + } | ||
125 | + } | ||
126 | + } | ||
127 | + return s + '"'; | ||
128 | + case 'boolean': | ||
129 | + return String(arg); | ||
130 | + default: | ||
131 | + return 'null'; | ||
132 | + } | ||
133 | + }, | ||
134 | + parse: function (text) { | ||
135 | + var at = 0; | ||
136 | + var ch = ' '; | ||
137 | + | ||
138 | + function error(m) { | ||
139 | + throw { | ||
140 | + name: 'JSONError', | ||
141 | + message: m, | ||
142 | + at: at - 1, | ||
143 | + text: text | ||
144 | + }; | ||
145 | + } | ||
146 | + | ||
147 | + function next() { | ||
148 | + ch = text.charAt(at); | ||
149 | + at += 1; | ||
150 | + return ch; | ||
151 | + } | ||
152 | + | ||
153 | + function white() { | ||
154 | + while (ch != '' && ch <= ' ') { | ||
155 | + next(); | ||
156 | + } | ||
157 | + } | ||
158 | + | ||
159 | + function str() { | ||
160 | + var i, s = '', t, u; | ||
161 | + | ||
162 | + if (ch == '"') { | ||
163 | +outer: while (next()) { | ||
164 | + if (ch == '"') { | ||
165 | + next(); | ||
166 | + return s; | ||
167 | + } else if (ch == '\\') { | ||
168 | + switch (next()) { | ||
169 | + case 'b': | ||
170 | + s += '\b'; | ||
171 | + break; | ||
172 | + case 'f': | ||
173 | + s += '\f'; | ||
174 | + break; | ||
175 | + case 'n': | ||
176 | + s += '\n'; | ||
177 | + break; | ||
178 | + case 'r': | ||
179 | + s += '\r'; | ||
180 | + break; | ||
181 | + case 't': | ||
182 | + s += '\t'; | ||
183 | + break; | ||
184 | + case 'u': | ||
185 | + u = 0; | ||
186 | + for (i = 0; i < 4; i += 1) { | ||
187 | + t = parseInt(next(), 16); | ||
188 | + if (!isFinite(t)) { | ||
189 | + break outer; | ||
190 | + } | ||
191 | + u = u * 16 + t; | ||
192 | + } | ||
193 | + s += String.fromCharCode(u); | ||
194 | + break; | ||
195 | + default: | ||
196 | + s += ch; | ||
197 | + } | ||
198 | + } else { | ||
199 | + s += ch; | ||
200 | + } | ||
201 | + } | ||
202 | + } | ||
203 | + error("Bad string"); | ||
204 | + } | ||
205 | + | ||
206 | + function arr() { | ||
207 | + var a = []; | ||
208 | + | ||
209 | + if (ch == '[') { | ||
210 | + next(); | ||
211 | + white(); | ||
212 | + if (ch == ']') { | ||
213 | + next(); | ||
214 | + return a; | ||
215 | + } | ||
216 | + while (ch) { | ||
217 | + a.push(val()); | ||
218 | + white(); | ||
219 | + if (ch == ']') { | ||
220 | + next(); | ||
221 | + return a; | ||
222 | + } else if (ch != ',') { | ||
223 | + break; | ||
224 | + } | ||
225 | + next(); | ||
226 | + white(); | ||
227 | + } | ||
228 | + } | ||
229 | + error("Bad array"); | ||
230 | + } | ||
231 | + | ||
232 | + function obj() { | ||
233 | + var k, o = {}; | ||
234 | + | ||
235 | + if (ch == '{') { | ||
236 | + next(); | ||
237 | + white(); | ||
238 | + if (ch == '}') { | ||
239 | + next(); | ||
240 | + return o; | ||
241 | + } | ||
242 | + while (ch) { | ||
243 | + k = str(); | ||
244 | + white(); | ||
245 | + if (ch != ':') { | ||
246 | + break; | ||
247 | + } | ||
248 | + next(); | ||
249 | + o[k] = val(); | ||
250 | + white(); | ||
251 | + if (ch == '}') { | ||
252 | + next(); | ||
253 | + return o; | ||
254 | + } else if (ch != ',') { | ||
255 | + break; | ||
256 | + } | ||
257 | + next(); | ||
258 | + white(); | ||
259 | + } | ||
260 | + } | ||
261 | + error("Bad object"); | ||
262 | + } | ||
263 | + | ||
264 | + function assoc() { | ||
265 | + var k, a = []; | ||
266 | + | ||
267 | + if (ch == '<') { | ||
268 | + next(); | ||
269 | + white(); | ||
270 | + if (ch == '>') { | ||
271 | + next(); | ||
272 | + return a; | ||
273 | + } | ||
274 | + while (ch) { | ||
275 | + k = str(); | ||
276 | + white(); | ||
277 | + if (ch != ':') { | ||
278 | + break; | ||
279 | + } | ||
280 | + next(); | ||
281 | + a[k] = val(); | ||
282 | + white(); | ||
283 | + if (ch == '>') { | ||
284 | + next(); | ||
285 | + return a; | ||
286 | + } else if (ch != ',') { | ||
287 | + break; | ||
288 | + } | ||
289 | + next(); | ||
290 | + white(); | ||
291 | + } | ||
292 | + } | ||
293 | + error("Bad associative array"); | ||
294 | + } | ||
295 | + | ||
296 | + function num() { | ||
297 | + var n = '', v; | ||
298 | + if (ch == '-') { | ||
299 | + n = '-'; | ||
300 | + next(); | ||
301 | + } | ||
302 | + while (ch >= '0' && ch <= '9') { | ||
303 | + n += ch; | ||
304 | + next(); | ||
305 | + } | ||
306 | + if (ch == '.') { | ||
307 | + n += '.'; | ||
308 | + while (next() && ch >= '0' && ch <= '9') { | ||
309 | + n += ch; | ||
310 | + } | ||
311 | + } | ||
312 | + if (ch == 'e' || ch == 'E') { | ||
313 | + n += 'e'; | ||
314 | + next(); | ||
315 | + if (ch == '-' || ch == '+') { | ||
316 | + n += ch; | ||
317 | + next(); | ||
318 | + } | ||
319 | + while (ch >= '0' && ch <= '9') { | ||
320 | + n += ch; | ||
321 | + next(); | ||
322 | + } | ||
323 | + } | ||
324 | + v = +n; | ||
325 | + if (!isFinite(v)) { | ||
326 | + error("Bad number"); | ||
327 | + } else { | ||
328 | + return v; | ||
329 | + } | ||
330 | + } | ||
331 | + | ||
332 | + function word() { | ||
333 | + switch (ch) { | ||
334 | + case 't': | ||
335 | + if (next() == 'r' && next() == 'u' && next() == 'e') { | ||
336 | + next(); | ||
337 | + return true; | ||
338 | + } | ||
339 | + break; | ||
340 | + case 'f': | ||
341 | + if (next() == 'a' && next() == 'l' && next() == 's' && | ||
342 | + next() == 'e') { | ||
343 | + next(); | ||
344 | + return false; | ||
345 | + } | ||
346 | + break; | ||
347 | + case 'n': | ||
348 | + if (next() == 'u' && next() == 'l' && next() == 'l') { | ||
349 | + next(); | ||
350 | + return null; | ||
351 | + } | ||
352 | + break; | ||
353 | + } | ||
354 | + error("Syntax error"); | ||
355 | + } | ||
356 | + | ||
357 | + function val() { | ||
358 | + white(); | ||
359 | + switch (ch) { | ||
360 | + case '{': | ||
361 | + return obj(); | ||
362 | + case '[': | ||
363 | + return arr(); | ||
364 | + case '<': | ||
365 | + return assoc(); | ||
366 | + case '"': | ||
367 | + return str(); | ||
368 | + case '-': | ||
369 | + return num(); | ||
370 | + default: | ||
371 | + return ch >= '0' && ch <= '9' ? num() : word(); | ||
372 | + } | ||
373 | + } | ||
374 | + | ||
375 | + return val(); | ||
376 | + } | ||
377 | +}; |
@@ -0,0 +1,663 @@ | @@ -0,0 +1,663 @@ | ||
1 | +<?php | ||
2 | +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ | ||
3 | + | ||
4 | +/** | ||
5 | +* Converts to and from JSON format. | ||
6 | +* | ||
7 | +* JSON (JavaScript Object Notation) is a lightweight data-interchange | ||
8 | +* format. It is easy for humans to read and write. It is easy for machines | ||
9 | +* to parse and generate. It is based on a subset of the JavaScript | ||
10 | +* Programming Language, Standard ECMA-262 3rd Edition - December 1999. | ||
11 | +* This feature can also be found in Python. JSON is a text format that is | ||
12 | +* completely language independent but uses conventions that are familiar | ||
13 | +* to programmers of the C-family of languages, including C, C++, C#, Java, | ||
14 | +* JavaScript, Perl, TCL, and many others. These properties make JSON an | ||
15 | +* ideal data-interchange language. | ||
16 | +* | ||
17 | +* This package provides a simple encoder and decoder for JSON notation. It | ||
18 | +* is intended for use with client-side Javascript applications that make | ||
19 | +* use of HTTPRequest to perform server communication functions - data can | ||
20 | +* be encoded into JSON notation for use in a client-side javascript, or | ||
21 | +* decoded from incoming Javascript requests. JSON format is native to | ||
22 | +* Javascript, and can be directly eval()'ed with no further parsing | ||
23 | +* overhead | ||
24 | +* | ||
25 | +* All strings should be in ASCII or UTF-8 format! | ||
26 | +* | ||
27 | +* LICENSE: Redistribution and use in source and binary forms, with or | ||
28 | +* without modification, are permitted provided that the following | ||
29 | +* conditions are met: Redistributions of source code must retain the | ||
30 | +* above copyright notice, this list of conditions and the following | ||
31 | +* disclaimer. Redistributions in binary form must reproduce the above | ||
32 | +* copyright notice, this list of conditions and the following disclaimer | ||
33 | +* in the documentation and/or other materials provided with the | ||
34 | +* distribution. | ||
35 | +* | ||
36 | +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
37 | +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
38 | +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
39 | +* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
40 | +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
41 | +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
42 | +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
43 | +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
44 | +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
45 | +* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
46 | +* DAMAGE. | ||
47 | +* | ||
48 | +* @category | ||
49 | +* @package Services_JSON | ||
50 | +* @author Michal Migurski <mike-json@teczno.com> | ||
51 | +* @author Matt Knapp <mdknapp[at]gmail[dot]com> | ||
52 | +* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com> | ||
53 | +* @copyright 2005 Michal Migurski | ||
54 | +* @license http://www.opensource.org/licenses/bsd-license.php | ||
55 | +* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 | ||
56 | +*/ | ||
57 | + | ||
58 | +/** | ||
59 | +* Marker constant for Services_JSON::decode(), used to flag stack state | ||
60 | +*/ | ||
61 | +define('SERVICES_JSON_SLICE', 1); | ||
62 | + | ||
63 | +/** | ||
64 | +* Marker constant for Services_JSON::decode(), used to flag stack state | ||
65 | +*/ | ||
66 | +define('SERVICES_JSON_IN_STR', 2); | ||
67 | + | ||
68 | +/** | ||
69 | +* Marker constant for Services_JSON::decode(), used to flag stack state | ||
70 | +*/ | ||
71 | +define('SERVICES_JSON_IN_ARR', 4); | ||
72 | + | ||
73 | +/** | ||
74 | +* Marker constant for Services_JSON::decode(), used to flag stack state | ||
75 | +*/ | ||
76 | +define('SERVICES_JSON_IN_OBJ', 8); | ||
77 | + | ||
78 | +/** | ||
79 | +* Marker constant for Services_JSON::decode(), used to flag stack state | ||
80 | +*/ | ||
81 | +define('SERVICES_JSON_IN_CMT', 16); | ||
82 | + | ||
83 | +/** | ||
84 | +* Behavior switch for Services_JSON::decode() | ||
85 | +*/ | ||
86 | +define('SERVICES_JSON_LOOSE_TYPE', 10); | ||
87 | + | ||
88 | +/** | ||
89 | +* Behavior switch for Services_JSON::decode() | ||
90 | +*/ | ||
91 | +define('SERVICES_JSON_STRICT_TYPE', 11); | ||
92 | + | ||
93 | +/** | ||
94 | +* Converts to and from JSON format. | ||
95 | +* | ||
96 | +* Brief example of use: | ||
97 | +* | ||
98 | +* <code> | ||
99 | +* // create a new instance of Services_JSON | ||
100 | +* $json = new Services_JSON(); | ||
101 | +* | ||
102 | +* // convert a complexe value to JSON notation, and send it to the browser | ||
103 | +* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); | ||
104 | +* $output = $json->encode($value); | ||
105 | +* | ||
106 | +* print($output); | ||
107 | +* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] | ||
108 | +* | ||
109 | +* // accept incoming POST data, assumed to be in JSON notation | ||
110 | +* $input = file_get_contents('php://input', 1000000); | ||
111 | +* $value = $json->decode($input); | ||
112 | +* </code> | ||
113 | +*/ | ||
114 | +class Services_JSON | ||
115 | +{ | ||
116 | + /** | ||
117 | + * constructs a new JSON instance | ||
118 | + * | ||
119 | + * @param int $use object behavior: when encoding or decoding, | ||
120 | + * be loose or strict about object/array usage | ||
121 | + * | ||
122 | + * possible values: | ||
123 | + * - SERVICES_JSON_STRICT_TYPE: strict typing, default. | ||
124 | + * "{...}" syntax creates objects in decode(). | ||
125 | + * - SERVICES_JSON_LOOSE_TYPE: loose typing. | ||
126 | + * "{...}" syntax creates associative arrays in decode(). | ||
127 | + */ | ||
128 | + function Services_JSON($use = SERVICES_JSON_STRICT_TYPE) | ||
129 | + { | ||
130 | + $this->use = $use; | ||
131 | + } | ||
132 | + | ||
133 | + /** | ||
134 | + * convert a string from one UTF-16 char to one UTF-8 char | ||
135 | + * | ||
136 | + * Normally should be handled by mb_convert_encoding, but | ||
137 | + * provides a slower PHP-only method for installations | ||
138 | + * that lack the multibye string extension. | ||
139 | + * | ||
140 | + * @param string $utf16 UTF-16 character | ||
141 | + * @return string UTF-8 character | ||
142 | + * @access private | ||
143 | + */ | ||
144 | + function utf162utf8($utf16) | ||
145 | + { | ||
146 | + // oh please oh please oh please oh please oh please | ||
147 | + if(function_exists('mb_convert_encoding')) | ||
148 | + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); | ||
149 | + | ||
150 | + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); | ||
151 | + | ||
152 | + switch(true) { | ||
153 | + case ((0x7F & $bytes) == $bytes): | ||
154 | + // this case should never be reached, because we are in ASCII range | ||
155 | + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
156 | + return chr(0x7F & $bytes); | ||
157 | + | ||
158 | + case (0x07FF & $bytes) == $bytes: | ||
159 | + // return a 2-byte UTF-8 character | ||
160 | + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
161 | + return chr(0xC0 | (($bytes >> 6) & 0x1F)) | ||
162 | + . chr(0x80 | ($bytes & 0x3F)); | ||
163 | + | ||
164 | + case (0xFFFF & $bytes) == $bytes: | ||
165 | + // return a 3-byte UTF-8 character | ||
166 | + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
167 | + return chr(0xE0 | (($bytes >> 12) & 0x0F)) | ||
168 | + . chr(0x80 | (($bytes >> 6) & 0x3F)) | ||
169 | + . chr(0x80 | ($bytes & 0x3F)); | ||
170 | + } | ||
171 | + | ||
172 | + // ignoring UTF-32 for now, sorry | ||
173 | + return ''; | ||
174 | + } | ||
175 | + | ||
176 | + /** | ||
177 | + * convert a string from one UTF-8 char to one UTF-16 char | ||
178 | + * | ||
179 | + * Normally should be handled by mb_convert_encoding, but | ||
180 | + * provides a slower PHP-only method for installations | ||
181 | + * that lack the multibye string extension. | ||
182 | + * | ||
183 | + * @param string $utf8 UTF-8 character | ||
184 | + * @return string UTF-16 character | ||
185 | + * @access private | ||
186 | + */ | ||
187 | + function utf82utf16($utf8) | ||
188 | + { | ||
189 | + // oh please oh please oh please oh please oh please | ||
190 | + if(function_exists('mb_convert_encoding')) | ||
191 | + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); | ||
192 | + | ||
193 | + switch(strlen($utf8)) { | ||
194 | + case 1: | ||
195 | + // this case should never be reached, because we are in ASCII range | ||
196 | + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
197 | + return $utf8; //$ut8 | ||
198 | + | ||
199 | + case 2: | ||
200 | + // return a UTF-16 character from a 2-byte UTF-8 char | ||
201 | + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
202 | + return chr(0x07 & (ord($utf8{0}) >> 2)) | ||
203 | + . chr((0xC0 & (ord($utf8{0}) << 6)) | ||
204 | + | (0x3F & ord($utf8{1}))); | ||
205 | + | ||
206 | + case 3: | ||
207 | + // return a UTF-16 character from a 3-byte UTF-8 char | ||
208 | + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
209 | + return chr((0xF0 & (ord($utf8{0}) << 4)) | ||
210 | + | (0x0F & (ord($utf8{1}) >> 2))) | ||
211 | + . chr((0xC0 & (ord($utf8{1}) << 6)) | ||
212 | + | (0x7F & ord($utf8{2}))); | ||
213 | + } | ||
214 | + | ||
215 | + // ignoring UTF-32 for now, sorry | ||
216 | + return ''; | ||
217 | + } | ||
218 | + | ||
219 | + /** | ||
220 | + * encodes an arbitrary variable into JSON format | ||
221 | + * | ||
222 | + * @param mixed $var any number, boolean, string, array, or object to be encoded. | ||
223 | + * see argument 1 to Services_JSON() above for array-parsing behavior. | ||
224 | + * if var is a strng, note that encode() always expects it | ||
225 | + * to be in ASCII or UTF-8 format! | ||
226 | + * | ||
227 | + * @return string JSON string representation of input var | ||
228 | + * @access public | ||
229 | + */ | ||
230 | + function encode($var) | ||
231 | + { | ||
232 | + switch (gettype($var)) { | ||
233 | + case 'boolean': | ||
234 | + return $var ? 'true' : 'false'; | ||
235 | + | ||
236 | + case 'NULL': | ||
237 | + return 'null'; | ||
238 | + | ||
239 | + case 'integer': | ||
240 | + return (int) $var; | ||
241 | + | ||
242 | + case 'double': | ||
243 | + case 'float': | ||
244 | + return (float) $var; | ||
245 | + | ||
246 | + case 'string': | ||
247 | + $arg = $var; | ||
248 | + $l = strlen($var); | ||
249 | + $s = '"'; | ||
250 | + | ||
251 | + for ($i = 0; $i < $l; $i++) { | ||
252 | + $c = $var{$i}; | ||
253 | + | ||
254 | + if (ord($c) >= ord(' ')) { | ||
255 | + | ||
256 | + if ($c == '\\' | ||
257 | + || $c == '"') { | ||
258 | + | ||
259 | + $s .= '\\'; | ||
260 | + } | ||
261 | + $s .= $c; | ||
262 | + | ||
263 | + } else { | ||
264 | + | ||
265 | + switch ($c) { | ||
266 | + | ||
267 | + case '\b': | ||
268 | + $s .= '\\b'; | ||
269 | + break; | ||
270 | + | ||
271 | + case '\f': | ||
272 | + $s .= '\\f'; | ||
273 | + break; | ||
274 | + | ||
275 | + case '\n': | ||
276 | + $s .= '\\n'; | ||
277 | + break; | ||
278 | + | ||
279 | + case '\r': | ||
280 | + $s .= '\\r'; | ||
281 | + break; | ||
282 | + | ||
283 | + case '\t': | ||
284 | + $s .= '\\t'; | ||
285 | + break; | ||
286 | + | ||
287 | + default: | ||
288 | + $s .= '\u00' . sprintf('%02x', ord($c)); | ||
289 | + } | ||
290 | + } | ||
291 | + } | ||
292 | + return $s . '"'; | ||
293 | + break; | ||
294 | + | ||
295 | + | ||
296 | + case 'array': | ||
297 | + /* | ||
298 | + * As per JSON spec if any array key is not an integer | ||
299 | + * we must treat the the whole array as an object. We | ||
300 | + * also try to catch a sparsely populated associative | ||
301 | + * array with numeric keys here because some JS engines | ||
302 | + * will create an array with empty indexes up to | ||
303 | + * max_index which can cause memory issues and because | ||
304 | + * the keys, which may be relevant, will be remapped | ||
305 | + * otherwise. | ||
306 | + * | ||
307 | + * As per the ECMA and JSON specification an object may | ||
308 | + * have any string as a property. Unfortunately due to | ||
309 | + * a hole in the ECMA specification if the key is a | ||
310 | + * ECMA reserved word or starts with a digit the | ||
311 | + * parameter is only accessible using ECMAScript's | ||
312 | + * bracket notation. | ||
313 | + */ | ||
314 | + | ||
315 | + // treat as a JSON object | ||
316 | + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { | ||
317 | + return "{/*Array*/" . | ||
318 | + join(',', array_map(array($this, 'name_value'), | ||
319 | + array_keys($var), | ||
320 | + array_values($var))) | ||
321 | + . '}'; | ||
322 | + } | ||
323 | + | ||
324 | + // treat it like a regular array | ||
325 | + return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']'; | ||
326 | + | ||
327 | + case 'object': | ||
328 | + $vars = get_object_vars($var); | ||
329 | + return '{' . | ||
330 | + join(',', array_map(array($this, 'name_value'), | ||
331 | + array_keys($vars), | ||
332 | + array_values($vars))) | ||
333 | + . '}'; | ||
334 | + | ||
335 | + default: | ||
336 | + return ''; | ||
337 | + } | ||
338 | + } | ||
339 | + | ||
340 | + /** | ||
341 | + * array-walking function for use in generating JSON-formatted name-value pairs | ||
342 | + * | ||
343 | + * @param string $name name of key to use | ||
344 | + * @param mixed $value reference to an array element to be encoded | ||
345 | + * | ||
346 | + * @return string JSON-formatted name-value pair, like '"name":value' | ||
347 | + * @access private | ||
348 | + */ | ||
349 | + function name_value($name, $value) | ||
350 | + { | ||
351 | + return $this->encode(strval($name)) . ':' . $this->encode($value); | ||
352 | + } | ||
353 | + | ||
354 | + /** | ||
355 | + * reduce a string by removing leading and trailing comments and whitespace | ||
356 | + * | ||
357 | + * @param $str string string value to strip of comments and whitespace | ||
358 | + * | ||
359 | + * @return string string value stripped of comments and whitespace | ||
360 | + * @access private | ||
361 | + */ | ||
362 | + function reduce_string($str) | ||
363 | + { | ||
364 | + $str = preg_replace(array( | ||
365 | + | ||
366 | + // eliminate single line comments in '// ...' form | ||
367 | + '#^\s*//(.+)$#m', | ||
368 | + | ||
369 | + // eliminate multi-line comments in '/* ... */' form, at start of string | ||
370 | + '#^\s*/\*(.+)\*/#Us', | ||
371 | + | ||
372 | + // eliminate multi-line comments in '/* ... */' form, at end of string | ||
373 | + '#/\*(.+)\*/\s*$#Us' | ||
374 | + | ||
375 | + ), '', $str); | ||
376 | + | ||
377 | + // eliminate extraneous space | ||
378 | + return trim($str); | ||
379 | + } | ||
380 | + | ||
381 | + /** | ||
382 | + * decodes a JSON string into appropriate variable | ||
383 | + * | ||
384 | + * @param string $str JSON-formatted string | ||
385 | + * | ||
386 | + * @return mixed number, boolean, string, array, or object | ||
387 | + * corresponding to given JSON input string. | ||
388 | + * See argument 1 to Services_JSON() above for object-output behavior. | ||
389 | + * Note that decode() always returns strings | ||
390 | + * in ASCII or UTF-8 format! | ||
391 | + * @access public | ||
392 | + */ | ||
393 | + function decode($str) | ||
394 | + { | ||
395 | + $imarray = false; | ||
396 | + $str = $this->reduce_string($str); | ||
397 | + | ||
398 | + switch (strtolower($str)) { | ||
399 | + case 'true': | ||
400 | + return true; | ||
401 | + | ||
402 | + case 'false': | ||
403 | + return false; | ||
404 | + | ||
405 | + case 'null': | ||
406 | + return null; | ||
407 | + | ||
408 | + default: | ||
409 | + if (is_numeric($str)) { | ||
410 | + // Lookie-loo, it's a number | ||
411 | + | ||
412 | + // This would work on its own, but I'm trying to be | ||
413 | + // good about returning integers where appropriate: | ||
414 | + // return (float)$str; | ||
415 | + | ||
416 | + // Return float or int, as appropriate | ||
417 | + return ((float)$str == (integer)$str) | ||
418 | + ? (integer)$str | ||
419 | + : (float)$str; | ||
420 | + | ||
421 | + } elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) { | ||
422 | + // STRINGS RETURNED IN UTF-8 FORMAT | ||
423 | + $delim = substr($str, 0, 1); | ||
424 | + $chrs = substr($str, 1, -1); | ||
425 | + $utf8 = ''; | ||
426 | + $strlen_chrs = strlen($chrs); | ||
427 | + | ||
428 | + for ($c = 0; $c < $strlen_chrs; ++$c) { | ||
429 | + | ||
430 | + $substr_chrs_c_2 = substr($chrs, $c, 2); | ||
431 | + $ord_chrs_c = ord($chrs{$c}); | ||
432 | + | ||
433 | + switch (true) { | ||
434 | + case $substr_chrs_c_2 == '\b': | ||
435 | + $utf8 .= chr(0x08); | ||
436 | + ++$c; | ||
437 | + break; | ||
438 | + case $substr_chrs_c_2 == '\t': | ||
439 | + $utf8 .= chr(0x09); | ||
440 | + ++$c; | ||
441 | + break; | ||
442 | + case $substr_chrs_c_2 == '\n': | ||
443 | + $utf8 .= chr(0x0A); | ||
444 | + ++$c; | ||
445 | + break; | ||
446 | + case $substr_chrs_c_2 == '\f': | ||
447 | + $utf8 .= chr(0x0C); | ||
448 | + ++$c; | ||
449 | + break; | ||
450 | + case $substr_chrs_c_2 == '\r': | ||
451 | + $utf8 .= chr(0x0D); | ||
452 | + ++$c; | ||
453 | + break; | ||
454 | + | ||
455 | + case $substr_chrs_c_2 == '\\"': | ||
456 | + case $substr_chrs_c_2 == '\\\'': | ||
457 | + case $substr_chrs_c_2 == '\\\\': | ||
458 | + case $substr_chrs_c_2 == '\\/': | ||
459 | + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || | ||
460 | + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { | ||
461 | + $utf8 .= $chrs{++$c}; | ||
462 | + } | ||
463 | + break; | ||
464 | + | ||
465 | + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): | ||
466 | + // single, escaped unicode character | ||
467 | + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) | ||
468 | + . chr(hexdec(substr($chrs, ($c + 4), 2))); | ||
469 | + $utf8 .= $this->utf162utf8($utf16); | ||
470 | + $c += 5; | ||
471 | + break; | ||
472 | + | ||
473 | + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): | ||
474 | + $utf8 .= $chrs{$c}; | ||
475 | + break; | ||
476 | + | ||
477 | + case ($ord_chrs_c & 0xE0) == 0xC0: | ||
478 | + // characters U-00000080 - U-000007FF, mask 110XXXXX | ||
479 | + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
480 | + $utf8 .= substr($chrs, $c, 2); | ||
481 | + ++$c; | ||
482 | + break; | ||
483 | + | ||
484 | + case ($ord_chrs_c & 0xF0) == 0xE0: | ||
485 | + // characters U-00000800 - U-0000FFFF, mask 1110XXXX | ||
486 | + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
487 | + $utf8 .= substr($chrs, $c, 3); | ||
488 | + $c += 2; | ||
489 | + break; | ||
490 | + | ||
491 | + case ($ord_chrs_c & 0xF8) == 0xF0: | ||
492 | + // characters U-00010000 - U-001FFFFF, mask 11110XXX | ||
493 | + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
494 | + $utf8 .= substr($chrs, $c, 4); | ||
495 | + $c += 3; | ||
496 | + break; | ||
497 | + | ||
498 | + case ($ord_chrs_c & 0xFC) == 0xF8: | ||
499 | + // characters U-00200000 - U-03FFFFFF, mask 111110XX | ||
500 | + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
501 | + $utf8 .= substr($chrs, $c, 5); | ||
502 | + $c += 4; | ||
503 | + break; | ||
504 | + | ||
505 | + case ($ord_chrs_c & 0xFE) == 0xFC: | ||
506 | + // characters U-04000000 - U-7FFFFFFF, mask 1111110X | ||
507 | + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | ||
508 | + $utf8 .= substr($chrs, $c, 6); | ||
509 | + $c += 5; | ||
510 | + break; | ||
511 | + | ||
512 | + } | ||
513 | + | ||
514 | + } | ||
515 | + | ||
516 | + return $utf8; | ||
517 | + | ||
518 | + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { | ||
519 | + // array, or object notation | ||
520 | + | ||
521 | + if ($str{0} == '[') { | ||
522 | + $stk = array(SERVICES_JSON_IN_ARR); | ||
523 | + $arr = array(); | ||
524 | + } else { | ||
525 | + if ($str{1} == '/' && $str{2} == '*' && $str{3} == 'A') | ||
526 | + { | ||
527 | + $stk = array(SERVICES_JSON_IN_OBJ); | ||
528 | + $obj = array(); | ||
529 | + | ||
530 | + } | ||
531 | + else | ||
532 | + { | ||
533 | + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { | ||
534 | + $stk = array(SERVICES_JSON_IN_OBJ); | ||
535 | + $obj = array(); | ||
536 | + | ||
537 | + } else { | ||
538 | + $stk = array(SERVICES_JSON_IN_OBJ); | ||
539 | + $obj = new stdClass(); | ||
540 | + } | ||
541 | + } | ||
542 | + } | ||
543 | + | ||
544 | + array_push($stk, array('what' => SERVICES_JSON_SLICE, | ||
545 | + 'where' => 0, | ||
546 | + 'delim' => false)); | ||
547 | + | ||
548 | + $chrs = substr($str, 1, -1); | ||
549 | + $chrs = $this->reduce_string($chrs); | ||
550 | + | ||
551 | + if ($chrs == '') { | ||
552 | + if (reset($stk) == SERVICES_JSON_IN_ARR) { | ||
553 | + return $arr; | ||
554 | + | ||
555 | + } else { | ||
556 | + return $obj; | ||
557 | + | ||
558 | + } | ||
559 | + } | ||
560 | + | ||
561 | + //print("\nparsing {$chrs}\n"); | ||
562 | + | ||
563 | + $strlen_chrs = strlen($chrs); | ||
564 | + | ||
565 | + for ($c = 0; $c <= $strlen_chrs; ++$c) { | ||
566 | + | ||
567 | + $top = end($stk); | ||
568 | + $substr_chrs_c_2 = substr($chrs, $c, 2); | ||
569 | + | ||
570 | + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { | ||
571 | + // found a comma that is not inside a string, array, etc., | ||
572 | + // OR we've reached the end of the character list | ||
573 | + $slice = substr($chrs, $top['where'], ($c - $top['where'])); | ||
574 | + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); | ||
575 | + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); | ||
576 | + | ||
577 | + if (reset($stk) == SERVICES_JSON_IN_ARR) { | ||
578 | + // we are in an array, so just push an element onto the stack | ||
579 | + array_push($arr, $this->decode($slice)); | ||
580 | + | ||
581 | + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { | ||
582 | + // we are in an object, so figure | ||
583 | + // out the property name and set an | ||
584 | + // element in an associative array, | ||
585 | + // for now | ||
586 | + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { | ||
587 | + // "name":value pair | ||
588 | + $key = $this->decode($parts[1]); | ||
589 | + $val = $this->decode($parts[2]); | ||
590 | + | ||
591 | + if ($this->use == SERVICES_JSON_LOOSE_TYPE || is_array($obj)) { | ||
592 | + $obj[$key] = $val; | ||
593 | + } else { | ||
594 | + $obj->$key = $val; | ||
595 | + } | ||
596 | + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { | ||
597 | + // name:value pair, where name is unquoted | ||
598 | + $key = $parts[1]; | ||
599 | + $val = $this->decode($parts[2]); | ||
600 | + if ($this->use == SERVICES_JSON_LOOSE_TYPE|| is_array($obj)) { | ||
601 | + $obj[$key] = $val; | ||
602 | + } else { | ||
603 | + $obj->$key = $val; | ||
604 | + } | ||
605 | + } | ||
606 | + | ||
607 | + } | ||
608 | + | ||
609 | + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { | ||
610 | + // found a quote, and we are not inside a string | ||
611 | + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); | ||
612 | + //print("Found start of string at {$c}\n"); | ||
613 | + | ||
614 | + } elseif (($chrs{$c} == $top['delim']) && | ||
615 | + ($top['what'] == SERVICES_JSON_IN_STR) && | ||
616 | + (($chrs{$c - 1} != '\\') || | ||
617 | + ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) { | ||
618 | + // found a quote, we're in a string, and it's not escaped | ||
619 | + array_pop($stk); | ||
620 | + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); | ||
621 | + | ||
622 | + } elseif (($chrs{$c} == '[') && | ||
623 | + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { | ||
624 | + // found a left-bracket, and we are in an array, object, or slice | ||
625 | + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); | ||
626 | + //print("Found start of array at {$c}\n"); | ||
627 | + | ||
628 | + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { | ||
629 | + // found a right-bracket, and we're in an array | ||
630 | + array_pop($stk); | ||
631 | + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); | ||
632 | + | ||
633 | + } elseif (($chrs{$c} == '{') && | ||
634 | + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { | ||
635 | + // found a left-brace, and we are in an array, object, or slice | ||
636 | + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); | ||
637 | + //print("Found start of object at {$c}\n"); | ||
638 | + | ||
639 | + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { | ||
640 | + // found a right-brace, and we're in an object | ||
641 | + array_pop($stk); | ||
642 | + | ||
643 | + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); | ||
644 | + | ||
645 | + } | ||
646 | + | ||
647 | + } | ||
648 | + | ||
649 | + if (reset($stk) == SERVICES_JSON_IN_ARR) { | ||
650 | + return $arr; | ||
651 | + | ||
652 | + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { | ||
653 | + return $obj; | ||
654 | + | ||
655 | + } | ||
656 | + | ||
657 | + } | ||
658 | + } | ||
659 | + } | ||
660 | + | ||
661 | +} | ||
662 | + | ||
663 | +?> | ||
0 | \ No newline at end of file | 664 | \ No newline at end of file |
@@ -0,0 +1,351 @@ | @@ -0,0 +1,351 @@ | ||
1 | +<?php | ||
2 | +/** | ||
3 | +* The content of this file is (c) 2003-2005 digital media center GmbH | ||
4 | +* All rights reserved | ||
5 | +* | ||
6 | +* JSON parser / generator test | ||
7 | +* | ||
8 | +* @package JSON | ||
9 | +* @access public | ||
10 | +* @copyright (c) 2003-2005 digital media center GmbH, all rights reserved | ||
11 | +* @author Dominique Stender <dst@dmc.de> | ||
12 | +*/ | ||
13 | + | ||
14 | +//---- includes ---------------------------------------------------------------- | ||
15 | + /** | ||
16 | + * @include JSON | ||
17 | + */ | ||
18 | + require_once('../json.php'); | ||
19 | + | ||
20 | +//---- class ------------------------------------------------------------------- | ||
21 | + class MyObj { | ||
22 | + var $id = ''; | ||
23 | + var $name = ''; | ||
24 | + var $attribs = array("first",'4'); | ||
25 | + | ||
26 | + function setId($id) { | ||
27 | + $this->id = $id; | ||
28 | + } | ||
29 | + | ||
30 | + function getId() { | ||
31 | + return $this->id; | ||
32 | + } | ||
33 | + | ||
34 | + function setName($name) { | ||
35 | + $this->name = $name; | ||
36 | + } | ||
37 | + | ||
38 | + function getName() { | ||
39 | + return $this->name; | ||
40 | + } | ||
41 | + } | ||
42 | + | ||
43 | +//---- variables --------------------------------------------------------------- | ||
44 | + $JSON = new JSON(); | ||
45 | + $myObj = new MyObj(); | ||
46 | + | ||
47 | +//---- logic ------------------------------------------------------------------- | ||
48 | + /* initialize object */ | ||
49 | + $myObj->setId('Äl' . chr(18) . "ie\nn"); | ||
50 | + $myObj->setName('objectName'); | ||
51 | + array_push($myObj->attribs, 'øfirst'); | ||
52 | + array_push($myObj->attribs, 'second'); | ||
53 | + array_push($myObj->attribs, 3); | ||
54 | + | ||
55 | + /* create JSON representation */ | ||
56 | + $jsonStr = $JSON->stringify($myObj); | ||
57 | + | ||
58 | +//---- clean-up ---------------------------------------------------------------- | ||
59 | +//---- content ----------------------------------------------------------------- | ||
60 | + | ||
61 | +?><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | ||
62 | +<head> | ||
63 | + <title>JSON parser test</title> | ||
64 | + <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> | ||
65 | + <script type="text/javascript" src="json.js"></script> | ||
66 | + <script type="text/javascript"> | ||
67 | +JSON.arrayObj = new Array(); | ||
68 | +JSON.parse2 = function (text) | ||
69 | +{ | ||
70 | + var p = /^\s*(([,:{}\[\]])|"(\\.|[^\x00-\x1f"\\])*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null|\/\*Array\*\/)\s*/, | ||
71 | + token, | ||
72 | + operator; | ||
73 | + | ||
74 | + function error(m, t) { | ||
75 | + throw { | ||
76 | + name: 'JSONError', | ||
77 | + message: m, | ||
78 | + text: t || operator || token | ||
79 | + }; | ||
80 | + } | ||
81 | + | ||
82 | + function next() { | ||
83 | + if (text) { | ||
84 | + var t = p.exec(text); | ||
85 | + if (t) { | ||
86 | + | ||
87 | + if (t[2]) { | ||
88 | + token = null; | ||
89 | + operator = t[2]; | ||
90 | + } else { | ||
91 | + operator = null; | ||
92 | + if(t[1].search (/^\/\*Array\*\/$/g) > -1) | ||
93 | + { | ||
94 | + token = function(){}; | ||
95 | + } | ||
96 | + else | ||
97 | + { | ||
98 | + try { | ||
99 | + token = eval(t[1]); | ||
100 | + } catch (e) { | ||
101 | + error("Bad token", t[1]); | ||
102 | + } | ||
103 | + } | ||
104 | + } | ||
105 | + text = text.substring(t[0].length); | ||
106 | + } else { | ||
107 | + error("Unrecognized token", text); | ||
108 | + } | ||
109 | + } else { | ||
110 | + token = operator = undefined; | ||
111 | + } | ||
112 | + } | ||
113 | + | ||
114 | + | ||
115 | + function arr() { | ||
116 | + var a = []; | ||
117 | + | ||
118 | + next(); | ||
119 | + if (operator == ']') { | ||
120 | + next(); | ||
121 | + return a; | ||
122 | + } | ||
123 | + for (;;) { | ||
124 | + a.push(val()); | ||
125 | + switch (operator) { | ||
126 | + case ']': | ||
127 | + next(); | ||
128 | + return a; | ||
129 | + case ',': | ||
130 | + next(); | ||
131 | + break; | ||
132 | + default: | ||
133 | + error("Missing ']'"); | ||
134 | + } | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + function obj() { | ||
139 | + var k, o = {}; | ||
140 | + | ||
141 | + next(); | ||
142 | + if (operator == '}') { | ||
143 | + next(); | ||
144 | + return o; | ||
145 | + } | ||
146 | + if (typeof(token) == 'function') | ||
147 | + { | ||
148 | + o = []; | ||
149 | + next(); | ||
150 | + } | ||
151 | + for (;;) | ||
152 | + { | ||
153 | + | ||
154 | + | ||
155 | + if (operator ||typeof token != 'string') { | ||
156 | + error("Missing key"); | ||
157 | + } | ||
158 | + k = token; | ||
159 | + next(); | ||
160 | + | ||
161 | + if (operator != ':') { | ||
162 | + error("Missing ':'"); | ||
163 | + } | ||
164 | + | ||
165 | + next(); | ||
166 | + o[k] = val(); | ||
167 | + | ||
168 | + switch (operator) { | ||
169 | + case '}': | ||
170 | + next(); | ||
171 | + return o; | ||
172 | + case ',': | ||
173 | + next(); | ||
174 | + break; | ||
175 | + case '#': | ||
176 | + next(); | ||
177 | + break; | ||
178 | + default: | ||
179 | + error("Missing '}'"); | ||
180 | + } | ||
181 | + } | ||
182 | + } | ||
183 | + | ||
184 | + function val() { | ||
185 | + switch (operator) { | ||
186 | + case '{': | ||
187 | + return obj(); | ||
188 | + case '[': | ||
189 | + return arr(); | ||
190 | + default: | ||
191 | + if (operator !== null) { | ||
192 | + error("Missing value"); | ||
193 | + } | ||
194 | + var t = token; | ||
195 | + next(); | ||
196 | + return t; | ||
197 | + } | ||
198 | + } | ||
199 | + next(); | ||
200 | + return val(); | ||
201 | +}; | ||
202 | + | ||
203 | +JSON.stringify2 = function(arg) | ||
204 | +{ | ||
205 | + var jsonstring = []; | ||
206 | + var b = this; | ||
207 | + function add(str) | ||
208 | + { | ||
209 | + jsonstring[jsonstring.length] = str; | ||
210 | + } | ||
211 | + function validObj(obj) | ||
212 | + { | ||
213 | + if (typeof(obj) != 'undefined' && typeof(obj) != 'function') | ||
214 | + { | ||
215 | + return true; | ||
216 | + } | ||
217 | + return false; | ||
218 | + } | ||
219 | + function recurse(obj, prefix) | ||
220 | + { | ||
221 | + switch (typeof(obj)) | ||
222 | + { | ||
223 | + case 'object': | ||
224 | + if (obj) | ||
225 | + { | ||
226 | + var first = true; | ||
227 | + if (obj.constructor == b.arrayObj.constructor) | ||
228 | + { | ||
229 | + add('{/*Array*/'); | ||
230 | + //add ('{'); | ||
231 | + } | ||
232 | + else | ||
233 | + { | ||
234 | + add ('{'); | ||
235 | + } | ||
236 | + for (prop in obj) | ||
237 | + { | ||
238 | + if (validObj(obj[prop])) | ||
239 | + { | ||
240 | + if (!first) | ||
241 | + { | ||
242 | + add(','); | ||
243 | + } | ||
244 | + recurse(prop); | ||
245 | + add(':'); | ||
246 | + recurse (obj[prop]); | ||
247 | + first =false; | ||
248 | + } | ||
249 | + } | ||
250 | + return add ('}'); | ||
251 | + } | ||
252 | + return add('null'); | ||
253 | + break; | ||
254 | + case 'number': | ||
255 | + return add(isFinite(obj) ? String(obj) : 'null'); | ||
256 | + break; | ||
257 | + case 'string': | ||
258 | + l = obj.length; | ||
259 | + add('"'); | ||
260 | + for (i = 0; i < l; i += 1) { | ||
261 | + c = obj.charAt(i); | ||
262 | + if (c >= ' ') { | ||
263 | + if (c == '\\' || c == '"') { | ||
264 | + add('\\'); | ||
265 | + } | ||
266 | + add(c); | ||
267 | + } else { | ||
268 | + switch (c) { | ||
269 | + case '\b': | ||
270 | + add('\\b'); | ||
271 | + break; | ||
272 | + case '\f': | ||
273 | + add('\\f'); | ||
274 | + break; | ||
275 | + case '\n': | ||
276 | + add('\\n'); | ||
277 | + break; | ||
278 | + case '\r': | ||
279 | + add('\\r'); | ||
280 | + break; | ||
281 | + case '\t': | ||
282 | + add('\\t'); | ||
283 | + break; | ||
284 | + default: | ||
285 | + c = c.charCodeAt(); | ||
286 | + add('\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16)); | ||
287 | + } | ||
288 | + } | ||
289 | + } | ||
290 | + return add('"'); | ||
291 | + break; | ||
292 | + case 'boolean': | ||
293 | + return add(String(obj)); | ||
294 | + break; | ||
295 | + default: | ||
296 | + return add('null'); | ||
297 | + break; | ||
298 | + } | ||
299 | + } | ||
300 | + recurse(arg); | ||
301 | + return jsonstring.join(''); | ||
302 | +}; | ||
303 | + </script> | ||
304 | +</head> | ||
305 | +<body> | ||
306 | + <?php echo 'php JSONstr: ' . $jsonStr . "<br />\n"; ?> | ||
307 | + <script type="text/javascript"> | ||
308 | + <!-- | ||
309 | + /* print JSON representation */ | ||
310 | + var jsonStr = '<?php echo addslashes($jsonStr); ?>'; | ||
311 | + | ||
312 | + document.write('JavaScript JSONstr: ' + jsonStr); | ||
313 | + | ||
314 | + /* create another object from jsonStr */ | ||
315 | + try | ||
316 | + { | ||
317 | + var myObj2 = JSON.parse(jsonStr); | ||
318 | + | ||
319 | + var myObj3 = JSON.parse2(jsonStr); | ||
320 | + | ||
321 | + | ||
322 | + /* test the clone */ | ||
323 | + document.write('<br /><br />Original JSON implementation'); | ||
324 | + document.write('<br />id: ' + myObj2.id); | ||
325 | + document.write('<br />name: ' + myObj2.name); | ||
326 | + | ||
327 | + for (var i = 0; i < myObj2.attribs.length; i++) { | ||
328 | + document.write('<br />attrib[' + i + ']: ' + myObj2.attribs[i]); | ||
329 | + } | ||
330 | + document.write('<br /><br />new JSON implementation'); | ||
331 | + document.write('<br />id: ' + myObj3.id); | ||
332 | + document.write('<br />name: ' + myObj3.name); | ||
333 | + | ||
334 | + for (var i = 0; i < myObj3.attribs.length; i++) { | ||
335 | + document.write('<br />attrib[' + i + ']: ' + myObj3.attribs[i]); | ||
336 | + } | ||
337 | + | ||
338 | + /* convert newline to JSON */ | ||
339 | + var nl = "\n" + String.fromCharCode(18); | ||
340 | + document.write('<br /><br /> Original JSON <br />newline as JSON: ' + JSON.stringify(nl)); | ||
341 | + document.write('<br /><br /> New JSON <br />newline as JSON: ' + JSON.stringify2(nl)); | ||
342 | + | ||
343 | + //--> | ||
344 | +} | ||
345 | + catch(e) | ||
346 | + { | ||
347 | + alert(e.message); | ||
348 | + } | ||
349 | + </script> | ||
350 | +</body> | ||
351 | +</html> | ||
0 | \ No newline at end of file | 352 | \ No newline at end of file |
@@ -0,0 +1,413 @@ | @@ -0,0 +1,413 @@ | ||
1 | +<?php | ||
2 | + | ||
3 | +// New TestSuite | ||
4 | +//---- includes ---------------------------------------------------------------- | ||
5 | + /** | ||
6 | + * @include JSON | ||
7 | + */ | ||
8 | + require_once('../json.php'); | ||
9 | + require_once('json2.php'); | ||
10 | + | ||
11 | +// ----- PHP Test Objects | ||
12 | +class object1 | ||
13 | +{ | ||
14 | + var $firstattr = 'firstvalue'; | ||
15 | + var $foreignchars = "Äø\r\n"; | ||
16 | + var $regarray = array("item1", "item2"); | ||
17 | + var $assocarray = array("item1"=>"value1", "item2"=>"value2"); | ||
18 | + var $boolean = true; | ||
19 | + var $integer = 5; | ||
20 | + var $float = 1.12; | ||
21 | + var $innerobject; | ||
22 | + function object1() | ||
23 | + { | ||
24 | + $this->innerobject = new object2(); | ||
25 | + } | ||
26 | +} | ||
27 | +class object2 | ||
28 | +{ | ||
29 | + var $firstattr = 'firstvalue'; | ||
30 | + var $secondattr = 'secondvalue'; | ||
31 | +} | ||
32 | +//---- variables --------------------------------------------------------------- | ||
33 | + $JSON = new JSON(); | ||
34 | + $object1 = new object1(); | ||
35 | + $JSON2 = new Services_JSON(); | ||
36 | + $submitted = false; | ||
37 | +//---- logic ------------------------------------------------------------------- | ||
38 | + $origjsonstring = $JSON->stringify($object1); | ||
39 | + $newjsonstring = $JSON2->encode($object1); | ||
40 | + $origjson = $_REQUEST["origjson"]; | ||
41 | + if (!empty($origjson)) | ||
42 | + { | ||
43 | + $origjsonprintr = $JSON->parse(stripslashes($origjson)); | ||
44 | + $submitted = true; | ||
45 | + } | ||
46 | + else | ||
47 | + { | ||
48 | + $origjsonprintr = "Not submitted"; | ||
49 | + } | ||
50 | + $newjson = $_REQUEST["newjson"]; | ||
51 | + if (!empty($newjson)) | ||
52 | + { | ||
53 | + $newjsonprintr = $JSON2->decode(stripslashes($newjson)); | ||
54 | + } | ||
55 | + else | ||
56 | + { | ||
57 | + $newjsonprintr = "Not submitted"; | ||
58 | + } | ||
59 | + | ||
60 | +//---- content ----------------------------------------------------------------- | ||
61 | +?> | ||
62 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | ||
63 | +<head> | ||
64 | + <title>JSON parser test</title> | ||
65 | + <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> | ||
66 | + <script type="text/javascript" src="json.js"></script> | ||
67 | + <script type="text/javascript"> | ||
68 | +JSON.arrayObj = new Array(); | ||
69 | +JSON.parse2 = function (text) | ||
70 | +{ | ||
71 | + var p = /^\s*(([,:{}\[\]])|"(\\.|[^\x00-\x1f"\\])*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null|\/\*Array\*\/)\s*/, | ||
72 | + token, | ||
73 | + operator; | ||
74 | + | ||
75 | + function error(m, t) { | ||
76 | + throw { | ||
77 | + name: 'JSONError', | ||
78 | + message: m, | ||
79 | + text: t || operator || token | ||
80 | + }; | ||
81 | + } | ||
82 | + | ||
83 | + function next() { | ||
84 | + if (text) { | ||
85 | + var t = p.exec(text); | ||
86 | + if (t) { | ||
87 | + | ||
88 | + if (t[2]) { | ||
89 | + token = null; | ||
90 | + operator = t[2]; | ||
91 | + } else { | ||
92 | + operator = null; | ||
93 | + if(t[1].search (/^\/\*Array\*\/$/g) > -1) | ||
94 | + { | ||
95 | + token = function(){}; | ||
96 | + } | ||
97 | + else | ||
98 | + { | ||
99 | + try { | ||
100 | + token = eval(t[1]); | ||
101 | + } catch (e) { | ||
102 | + error("Bad token", t[1]); | ||
103 | + } | ||
104 | + } | ||
105 | + } | ||
106 | + text = text.substring(t[0].length); | ||
107 | + } else { | ||
108 | + error("Unrecognized token", text); | ||
109 | + } | ||
110 | + } else { | ||
111 | + token = operator = undefined; | ||
112 | + } | ||
113 | + } | ||
114 | + | ||
115 | + | ||
116 | + function arr() { | ||
117 | + var a = []; | ||
118 | + | ||
119 | + next(); | ||
120 | + if (operator == ']') { | ||
121 | + next(); | ||
122 | + return a; | ||
123 | + } | ||
124 | + for (;;) { | ||
125 | + a.push(val()); | ||
126 | + switch (operator) { | ||
127 | + case ']': | ||
128 | + next(); | ||
129 | + return a; | ||
130 | + case ',': | ||
131 | + next(); | ||
132 | + break; | ||
133 | + default: | ||
134 | + error("Missing ']'"); | ||
135 | + } | ||
136 | + } | ||
137 | + } | ||
138 | + | ||
139 | + function obj() { | ||
140 | + var k, o = {}; | ||
141 | + | ||
142 | + next(); | ||
143 | + if (operator == '}') { | ||
144 | + next(); | ||
145 | + return o; | ||
146 | + } | ||
147 | + if (typeof(token) == 'function') | ||
148 | + { | ||
149 | + o = []; | ||
150 | + next(); | ||
151 | + } | ||
152 | + for (;;) | ||
153 | + { | ||
154 | + | ||
155 | + | ||
156 | + if (operator ||typeof token != 'string') { | ||
157 | + error("Missing key"); | ||
158 | + } | ||
159 | + k = token; | ||
160 | + next(); | ||
161 | + | ||
162 | + if (operator != ':') { | ||
163 | + error("Missing ':'"); | ||
164 | + } | ||
165 | + | ||
166 | + next(); | ||
167 | + o[k] = val(); | ||
168 | + | ||
169 | + switch (operator) { | ||
170 | + case '}': | ||
171 | + next(); | ||
172 | + return o; | ||
173 | + case ',': | ||
174 | + next(); | ||
175 | + break; | ||
176 | + case '#': | ||
177 | + next(); | ||
178 | + break; | ||
179 | + default: | ||
180 | + error("Missing '}'"); | ||
181 | + } | ||
182 | + } | ||
183 | + } | ||
184 | + | ||
185 | + function val() { | ||
186 | + switch (operator) { | ||
187 | + case '{': | ||
188 | + return obj(); | ||
189 | + case '[': | ||
190 | + return arr(); | ||
191 | + default: | ||
192 | + if (operator !== null) { | ||
193 | + error("Missing value"); | ||
194 | + } | ||
195 | + var t = token; | ||
196 | + next(); | ||
197 | + return t; | ||
198 | + } | ||
199 | + } | ||
200 | + next(); | ||
201 | + return val(); | ||
202 | +}; | ||
203 | + | ||
204 | +JSON.stringify2 = function(arg) | ||
205 | +{ | ||
206 | + var jsonstring = []; | ||
207 | + var b = this; | ||
208 | + function add(str) | ||
209 | + { | ||
210 | + jsonstring[jsonstring.length] = str; | ||
211 | + } | ||
212 | + function validObj(obj) | ||
213 | + { | ||
214 | + if (typeof(obj) != 'undefined' && typeof(obj) != 'function') | ||
215 | + { | ||
216 | + return true; | ||
217 | + } | ||
218 | + return false; | ||
219 | + } | ||
220 | + function recurse(obj, prefix) | ||
221 | + { | ||
222 | + switch (typeof(obj)) | ||
223 | + { | ||
224 | + case 'object': | ||
225 | + if (obj) | ||
226 | + { | ||
227 | + var first = true; | ||
228 | + if (obj.constructor == b.arrayObj.constructor) | ||
229 | + { | ||
230 | + add('{/*Array*/'); | ||
231 | + //add ('{'); | ||
232 | + } | ||
233 | + else | ||
234 | + { | ||
235 | + add ('{'); | ||
236 | + } | ||
237 | + for (prop in obj) | ||
238 | + { | ||
239 | + if (validObj(obj[prop])) | ||
240 | + { | ||
241 | + if (!first) | ||
242 | + { | ||
243 | + add(','); | ||
244 | + } | ||
245 | + recurse(prop); | ||
246 | + add(':'); | ||
247 | + recurse (obj[prop]); | ||
248 | + first =false; | ||
249 | + } | ||
250 | + } | ||
251 | + return add ('}'); | ||
252 | + } | ||
253 | + return add('null'); | ||
254 | + break; | ||
255 | + case 'number': | ||
256 | + return add(isFinite(obj) ? String(obj) : 'null'); | ||
257 | + break; | ||
258 | + case 'string': | ||
259 | + l = obj.length; | ||
260 | + add('"'); | ||
261 | + for (i = 0; i < l; i += 1) { | ||
262 | + c = obj.charAt(i); | ||
263 | + if (c >= ' ') { | ||
264 | + if (c == '\\' || c == '"') { | ||
265 | + add('\\'); | ||
266 | + } | ||
267 | + add(c); | ||
268 | + } else { | ||
269 | + switch (c) { | ||
270 | + case '\b': | ||
271 | + add('\\b'); | ||
272 | + break; | ||
273 | + case '\f': | ||
274 | + add('\\f'); | ||
275 | + break; | ||
276 | + case '\n': | ||
277 | + add('\\n'); | ||
278 | + break; | ||
279 | + case '\r': | ||
280 | + add('\\r'); | ||
281 | + break; | ||
282 | + case '\t': | ||
283 | + add('\\t'); | ||
284 | + break; | ||
285 | + default: | ||
286 | + c = c.charCodeAt(); | ||
287 | + add('\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16)); | ||
288 | + } | ||
289 | + } | ||
290 | + } | ||
291 | + return add('"'); | ||
292 | + break; | ||
293 | + case 'boolean': | ||
294 | + return add(String(obj)); | ||
295 | + break; | ||
296 | + default: | ||
297 | + return add('null'); | ||
298 | + break; | ||
299 | + } | ||
300 | + } | ||
301 | + recurse(arg); | ||
302 | + return jsonstring.join(''); | ||
303 | +}; | ||
304 | + </script> | ||
305 | +</head> | ||
306 | +<body> | ||
307 | + <table width="100%"> | ||
308 | + <tr> | ||
309 | + <td> | ||
310 | + <table width="100%"> | ||
311 | + <caption>Original JSON PHP/Javascript</caption> | ||
312 | + <tr> | ||
313 | + <td> | ||
314 | + Original PHP object (print_r) | ||
315 | + <textarea rows="5" cols="50"><?php echo print_r($object1); ?></textarea> | ||
316 | + </td> | ||
317 | + </tr> | ||
318 | + <tr> | ||
319 | + <td>Result of PHP Stringify<br /><textarea rows="5" cols="50"><?php echo ($origjsonstring); ?></textarea></td> | ||
320 | + </tr> | ||
321 | + <tr> | ||
322 | + <td>Did it Convert to a Javascript Object origjsobj ?<br /> | ||
323 | + <script> | ||
324 | + try | ||
325 | + { | ||
326 | + var origjsobj = JSON.parse('<?php echo addslashes($origjsonstring); ?>'); | ||
327 | + document.write('Successful'); | ||
328 | + } | ||
329 | + catch(e) | ||
330 | + { | ||
331 | + document.write('Failed'); | ||
332 | + document.write(' Original Parse Failed with this error "' + e.message + '"'); | ||
333 | + } | ||
334 | + </script> | ||
335 | + <br /><button onclick="s=document.body.appendChild(document.createElement('script'));s.id='sst';s.language='javascript';void(s.src='http://snmp-dev.cableaz.com/beta/print_r_0_3.js');">Invoke Print_R</button> | ||
336 | + </td> | ||
337 | + </tr> | ||
338 | + <tr> | ||
339 | + <td>Result of Javascript Stringify<br /> | ||
340 | + <script> | ||
341 | + var origjsstr = JSON.stringify(origjsobj); | ||
342 | + document.write('<textarea rows="5" cols="50">' + origjsstr + '</textarea>'); | ||
343 | + </script> | ||
344 | + </td> | ||
345 | + </tr> | ||
346 | + <tr> | ||
347 | + <td> | ||
348 | + Result of Conversion Back to PHP object (print_r) | ||
349 | + <textarea rows="5" cols="50"><?php echo print_r($origjsonprintr); ?></textarea> | ||
350 | + </td> | ||
351 | + </tr> | ||
352 | + </table> | ||
353 | + </td> | ||
354 | + <td> | ||
355 | + <table width="100%"> | ||
356 | + <caption>New JSON PHP/Javascript</caption> | ||
357 | + <tr> | ||
358 | + <td> | ||
359 | + Original PHP object (print_r) | ||
360 | + <textarea rows="5" cols="50"><?php echo print_r($object1); ?></textarea> | ||
361 | + </td> | ||
362 | + </tr> | ||
363 | + <tr> | ||
364 | + <td>Result of PHP Stringify<br /><textarea rows="5" cols="50"><?php echo ($newjsonstring); ?></textarea></td> | ||
365 | + </tr> | ||
366 | + <tr> | ||
367 | + <td>Did it Convert to a Javascript Object newjsobj ?<br /> | ||
368 | + <script> | ||
369 | + try | ||
370 | + { | ||
371 | + var newjsobj = JSON.parse2('<?php echo addslashes($newjsonstring); ?>'); | ||
372 | + document.write('Successful'); | ||
373 | + } | ||
374 | + catch(e) | ||
375 | + { | ||
376 | + document.write('Failed'); | ||
377 | + document.write(' New Parse Failed with this error "' + e.message + '"'); | ||
378 | + } | ||
379 | + </script> | ||
380 | + <br /><button onclick="s=document.body.appendChild(document.createElement('script'));s.id='sst';s.language='javascript';void(s.src='http://snmp-dev.cableaz.com/beta/print_r_0_3.js');">Invoke Print_R</button> | ||
381 | + </td> | ||
382 | + </tr> | ||
383 | + <tr> | ||
384 | + <td>Result of Javascript Stringify<br /> | ||
385 | + <script> | ||
386 | + var newjsstr = JSON.stringify2(newjsobj); | ||
387 | + document.write('<textarea rows="5" cols="50">' + newjsstr + '</textarea>'); | ||
388 | + </script> | ||
389 | + </td> | ||
390 | + </tr> | ||
391 | + <tr> | ||
392 | + <td> | ||
393 | + Result of Conversion Back to PHP object (print_r) | ||
394 | + <textarea rows="5" cols="50"><?php echo print_r($newjsonprintr); ?></textarea> | ||
395 | + </td> | ||
396 | + </tr> | ||
397 | + </table> | ||
398 | + </td> | ||
399 | + </table> | ||
400 | +<form method="GET" action="testsuite2.php" id="hiddenform"> | ||
401 | + <script> | ||
402 | + document.write ('<input name="origjson" type="hidden" value=\'' + origjsstr + '\' />'); | ||
403 | + document.write ('<input name="newjson" type="hidden" value=\'' + newjsstr + '\' />'); | ||
404 | + <?php | ||
405 | + if (!$submitted) | ||
406 | + { | ||
407 | + echo "document.getElementById('hiddenform').submit();"; | ||
408 | + } | ||
409 | + ?> | ||
410 | + </script> | ||
411 | +</form> | ||
412 | +</body> | ||
413 | +</html> | ||
0 | \ No newline at end of file | 414 | \ No newline at end of file |
@@ -0,0 +1,134 @@ | @@ -0,0 +1,134 @@ | ||
1 | +CPAINT changelog | ||
2 | + | ||
3 | +//---- v2.0.3 (Released Feburary 8, 2006) -------------------------- | ||
4 | +- PHP: nixed potential security hole with invalid response types | ||
5 | + (Thanks to James Bercegay) | ||
6 | + | ||
7 | +//---- v2.0.2 (Released January 20, 2006) -------------------------- | ||
8 | +- JS: check HTTP response code and throw an error if request was | ||
9 | + not accepted by server. (thanks gloomyandy) | ||
10 | +- JS: allowing the underscore in node names. | ||
11 | +- JS: added support for the passing of arrays and objects to the | ||
12 | + backend. | ||
13 | +- JS: added X-Powered-By request header. | ||
14 | +- JS: node names, attribute names and -values from backend are now | ||
15 | + expected to be valid ISO-8859-1. | ||
16 | +- JS: fixed wrong initialization of the data property to int zero in | ||
17 | + class cpaint_result_object. | ||
18 | +- JS: removed unneccessary setter() methods from internal classes | ||
19 | + to reduce size. | ||
20 | +- JS: added debugging level cp.set_debug(-1) to suppress errors. | ||
21 | +- JS: fixed type conversion issue where non-empty, pure whitespace | ||
22 | + strings where interpreted as numbers. | ||
23 | +- JS: fixed problem with callback being called twice. | ||
24 | + (thanks to Lance Rushing) | ||
25 | +- JS: fixed problem with URLs with existing GET parameters. | ||
26 | + (thanks to Nelson Antunes) | ||
27 | +- JS / PHP: added support for JSON as response type. | ||
28 | +- JS / PHP: added support for E4X as response type. | ||
29 | +- PHP: added cpaint::unregister() | ||
30 | +- PHP: added cpaint::get_response_type(); | ||
31 | +- PHP: removed a bug in JSON library that prevented the generation of valid JSON | ||
32 | + when including a leading zero character. | ||
33 | +- PHP: Removed unneccessary unescaping of parameters in proxy script. | ||
34 | +- PHP: added support for array and object parameters from JavaScript (JSON!). | ||
35 | +- PHP: added X-Powered-By response header. | ||
36 | +- PHP: removed encoding of node names, attribute names and attribute | ||
37 | + values to UTF-8 if possible. those values must now be valid | ||
38 | + ISO-8859-1. | ||
39 | +- PHP: removed output buffer to make it possible to include backend | ||
40 | + and frontend in the same file. | ||
41 | +- PHP: fixed error output (a function was called...) when no | ||
42 | + parameters where sent to CPAINT indicating a function call, thus | ||
43 | + making it possible to include backend and frontend in the same file | ||
44 | + (thanks S. Alexandre M. Lemaire) | ||
45 | +- PHP: added backend debugger code to main source tree & documentation. | ||
46 | +- PHP: secured proxy utility (see documentation). | ||
47 | +- PHP: added backend configuration file (for proxy security and future use) | ||
48 | +- ASP: removed from distribution to focus on PHP and other ports. | ||
49 | + | ||
50 | +//---- v2.0.1 (Released September 5, 2005) -------------------------- | ||
51 | +- JS: added the returning of plain-text response when using XML|OBJECT | ||
52 | + response type as second parameter to user-defined callback function | ||
53 | + (thanks Gunther) | ||
54 | +- JS: added cpaint.capable property to determine AJAX-compatible | ||
55 | + browsers | ||
56 | +- JS: cleaned up CPAINT parameters when not using CPAINT API w/ proxy | ||
57 | +- PHP: fixed callability of object methods (thanks Markus Wolf) | ||
58 | +- PHP: fixed HTTP authentication in proxy file | ||
59 | +- ASP: improved security regarding incoming function arguments | ||
60 | + | ||
61 | +//---- v2.0 (Released August 20, 2005) ------------------------------ | ||
62 | +- completely rewrote the JavaScript frontend. | ||
63 | + - 100% OOP approach. | ||
64 | + - completely configurable through setter methods. | ||
65 | + - support for syncronized calls (SJAX?) ;-). | ||
66 | + - automatic XML parsing into JavaScript document structure if | ||
67 | + response_type='object'. | ||
68 | + - support for arbitrary character sets, including non-printable | ||
69 | + characters. | ||
70 | + - automatic detection and conversion of numeric data into | ||
71 | + integers / floats. | ||
72 | + - unified use of call() for local and remote targets. | ||
73 | + - can now use frontend to retrieve static files or backend | ||
74 | + functions not implemented with CPAINT | ||
75 | + - use of a single (persistent) connection for multiple calls. | ||
76 | + - XML to JavaScript parser is able to parse any XML structure now. | ||
77 | + - support for XML attributes. | ||
78 | + - added find_item_by_type() to cpaint_result_object. | ||
79 | + - added get_attribute(), set_attribute() to cpaint_result_object. | ||
80 | + - improved debugging, added debuglevels 1, 2. see set_debug() | ||
81 | + | ||
82 | +- completely rewrote the PHP and ASP backends. | ||
83 | + - 100% OOP approach. | ||
84 | + - protection against remote code-execution. | ||
85 | + - support for object methods as callable functions. | ||
86 | + - nested XML support through composite pattern. | ||
87 | + - arbitrary XML structure creation support. | ||
88 | + - support for arbitrary character sets. | ||
89 | + - replaced remote code-execution blacklisting approach of v1.3-SP | ||
90 | + with whitelisting through cpaint.register(). | ||
91 | + - changed XML name convention. Attributes and tagnames are send | ||
92 | + as-is, not in uppercase. | ||
93 | + | ||
94 | +- improved readability of the ASP and PHP proxy utilities. | ||
95 | + - fixed GET requests. | ||
96 | + - proxy now uses attributenames identical to the CPAINT backend | ||
97 | + itself whenever possible. | ||
98 | + - added support for target ports other than 80. | ||
99 | + - added support for Basic Authentication. | ||
100 | + - completely redesigned and rewritten documentation! | ||
101 | + | ||
102 | +//---- v1.3-SP2 (Released August 16, 2005) -------------------------- | ||
103 | +- improved the remote-code execution fix. | ||
104 | + | ||
105 | +//---- v1.3-SP (Released August 15, 2005) --------------------------- | ||
106 | +- fixed a remote code-execution vulnerability on the backend by | ||
107 | + adding a blacklist test on the function name passed by the | ||
108 | + frontend. | ||
109 | + | ||
110 | +//---- v1.3 (Released July 10, 2005) -------------------------------- | ||
111 | +- rewrote cpaint_parse_ajax_xml() to be able to parse arbitrary XML. | ||
112 | +- added bugfix from v1.01 to cpaint_get_remote_file() as well. | ||
113 | + | ||
114 | +//---- v1.2 (Released June 20, 2005) -------------------------------- | ||
115 | +- added method cpaint_parse_ajax_xml() to the JavaScript frontend for | ||
116 | + primitive XML to JavaScript transformation of response data. | ||
117 | + | ||
118 | +//---- v1.01 (Released June 16, 2005) ------------------------------- | ||
119 | +- bugfix regarding Unicode character encoding in cpaint_call(). | ||
120 | + | ||
121 | +//---- v1.0 (Released June 13, 2005) -------------------------------- | ||
122 | +- added support for XML/DOM document object returns. | ||
123 | +- added support for XML on the backend. | ||
124 | +- added proxy files for accessing remote functions & data. | ||
125 | +- greatly improved documentation & examples. | ||
126 | +- code stablized | ||
127 | +- development effort moved to SourceForge.Net | ||
128 | + | ||
129 | +//---- Pre-1.0 Releases and Dates ----------------------------------- | ||
130 | +- v0.7 - released June 8, 2005 | ||
131 | +- v0.5 & 0.6 - released June 6, 2005 | ||
132 | +- v0.4 - released June 3, 2005 | ||
133 | +- v0.2 & 0.3 - released June 2, 2005 | ||
134 | +- v0.1 - released May 31, 2005 (first release) |
@@ -0,0 +1,104 @@ | @@ -0,0 +1,104 @@ | ||
1 | +<? | ||
2 | +/* | ||
3 | + CPAINT Backend Debug Interface | ||
4 | + | ||
5 | + released under the terms of the GPL | ||
6 | + see http://www.fsf.org/licensing/licenses/gpl.txt for details | ||
7 | + | ||
8 | + @package CPAINT | ||
9 | + @access public | ||
10 | + @author Paul Sullivan <wiley14@gmail.com> | ||
11 | + @author Stephan Tijink <stijink@googlemail.com> | ||
12 | + @copyright Copyright (c) 2005-2006 Paul Sullivan - http://sf.net/projects/cpaint | ||
13 | + @version 2.0.3 | ||
14 | +*/ | ||
15 | + | ||
16 | +if (!(isset($_REQUEST["cpaint_function"]))) { | ||
17 | + $debug_html_start = ' | ||
18 | + <html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | ||
19 | + <title>CPAINT Debug Interface</title> | ||
20 | + <style type="text/css">body { background-color: #9999CC; margin-top: 0px; } | ||
21 | + .style3 { font-family: Arial, Helvetica, sans-serif; font-size: 12px; } | ||
22 | + .style4 { font-size: 20px; color: #FFFFFF; font-family: Arial, Helvetica, sans-serif;} | ||
23 | + .style5 { font-size: 16px; color: #FFFFFF; font-family: Arial, Helvetica, sans-serif; font-weight: bold; } | ||
24 | + .style6 { font-size: 12px; color: #FFFFFF; font-family: Arial, Helvetica, sans-serif; font-weight: bold; } | ||
25 | + div, iframe { margin: 0px; border: 1px solid #9999CC; } | ||
26 | + </style> | ||
27 | + <script type="text/javascript"> | ||
28 | + function showForm(divId) { | ||
29 | + if (document.getElementById(divId).style.display == "block") { | ||
30 | + document.getElementById(divId).style.display = "none"; | ||
31 | + } else { | ||
32 | + document.getElementById(divId).style.display = "block"; | ||
33 | + } | ||
34 | + } | ||
35 | + </script> | ||
36 | + </head> | ||
37 | + <body> | ||
38 | + <table width="100%" border="0" cellspacing="0" cellpadding="0"> | ||
39 | + <tr><td bgcolor="#9999CC"><div align="justify"><span class="style4">CPAINT Debug Interface</span></div></td></tr> | ||
40 | + <tr><td bgcolor="#9999CC"><div align="justify"><span class="style6" style="color:#FFFFFF;">backend filename: '.$_SERVER["SCRIPT_NAME"].'</span></div></td></tr> | ||
41 | + <tr><td height="10" bgcolor="#9999CC" class="style3"></td></tr> | ||
42 | + <tr><td height="10" bgcolor="#9999CC" class="style3"></td></tr> | ||
43 | + <tr><td bgcolor="#FFFFFF" class="style3"><blockquote>'; | ||
44 | + $debug_html_end = "</blockquote></td></tr></table><br><iframe name=\"results\" class=\"style3\" width=\"100%\" height=\"100%\" scrolling=\"yes\" allowtransparency=\"false\" style=\"background-color: #FFFFFF\"></iframe></body></html>"; | ||
45 | + | ||
46 | + // get function names and function variables/values | ||
47 | + $functionArray = getCallableCode(); | ||
48 | + | ||
49 | + $debug_body = ""; | ||
50 | + if (count($functionArray) > 0) { | ||
51 | + foreach ($functionArray as $func_name=>$func_variables) { | ||
52 | + $debug_body = $debug_body . "<form method=\"get\" target=\"results\"><a href=\"javascript:showForm('" . $func_name . "_form');\">" . $func_name . "</a><div id=\"" . $func_name . "_form\" style=\"display: none;\">"; | ||
53 | + | ||
54 | + $debug_body = $debug_body . '<table border="0">'; | ||
55 | + if ( count($func_variables) > 0) { | ||
56 | + foreach ($func_variables as $var_name=>$var_preset) { | ||
57 | + $debug_body = $debug_body . '<tr><td class="style3">Parameter (<strong>$'.$var_name.'</strong>):</td><td><input type="text" name="cpaint_argument[]"></td>'; | ||
58 | + if (strlen($var_preset) > 0) { $debug_body = $debug_body . "<td class=\"style3\"> default value is <strong>".$var_preset." </strong></td>"; } | ||
59 | + $debug_body = $debug_body . '</tr>'; | ||
60 | + } | ||
61 | + } | ||
62 | + $debug_body = $debug_body . "<tr><td class=\"style3\">Response Type:</td><td><select name=\"cpaint_response_type\"><option>TEXT</option><option>XML</option><option>OBJECT</option></select></td></tr>"; | ||
63 | + $debug_body = $debug_body . "<tr><td colspan=\"3\"><input type=\"hidden\" name=\"cpaint_function\" value=\"" . $func_name . "\"><input type=\"submit\"></td></tr></table></div></form>"; | ||
64 | + } | ||
65 | + } | ||
66 | + | ||
67 | + print($debug_html_start . $debug_body . $debug_html_end); | ||
68 | + die(); | ||
69 | +} | ||
70 | + | ||
71 | +function getCallableCode() { | ||
72 | + $scriptName = $_SERVER['SCRIPT_FILENAME']; | ||
73 | + $fileLines = file($scriptName); | ||
74 | + for ($i=0; $i < sizeof($fileLines); $i++) { | ||
75 | + $line = trim($fileLines[$i]); | ||
76 | + if (substr($line, 0, 9) == "FUNCTION " || substr($line,0,9) == "function ") { | ||
77 | + $match[] = $line; | ||
78 | + } | ||
79 | + } | ||
80 | + for ($i = 0; $i < sizeof($match); $i++) { | ||
81 | + $line = str_replace("function ", "", $match[$i]); | ||
82 | + $line = str_replace("FUNCTION ", "", $line); | ||
83 | + $line = str_replace("{", "", $line); | ||
84 | + $parts = explode("(", $line); | ||
85 | + $func_name = trim($parts[0]); | ||
86 | + | ||
87 | + $Tempargs = explode(")", $parts[1]); | ||
88 | + $args = explode(",", $Tempargs[0]); | ||
89 | + $argSize = sizeof($args); | ||
90 | + | ||
91 | + // check args for preset values | ||
92 | + if ($argSize > 0) { | ||
93 | + foreach ($args as $arg) { | ||
94 | + $arg = trim ($arg); | ||
95 | + $varArray = explode ("=", $arg); | ||
96 | + $var_name = trim (str_replace ("$", "", $varArray["0"])); | ||
97 | + $var_value = trim ($varArray["1"]); | ||
98 | + $resultArray[$func_name][$var_name] = $var_value; | ||
99 | + } | ||
100 | + } | ||
101 | + } | ||
102 | + return $resultArray; | ||
103 | +} | ||
104 | +?> | ||
0 | \ No newline at end of file | 105 | \ No newline at end of file |
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +<? | ||
2 | +/** | ||
3 | +* CPAINT (Cross-Platform Asynchronous INterface Toolkit) | ||
4 | +* | ||
5 | +* http://sf.net/projects/cpaint | ||
6 | +* | ||
7 | +* released under the terms of the GPL | ||
8 | +* see http://www.fsf.org/licensing/licenses/gpl.txt for details | ||
9 | +* | ||
10 | +* $Id$ | ||
11 | +* $Log$ | ||
12 | +* | ||
13 | +* Configuration file for backend scripts, including proxy | ||
14 | +* | ||
15 | +* @package CPAINT | ||
16 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
17 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
18 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
19 | +* @version 2.0.3 | ||
20 | +*/ | ||
21 | + | ||
22 | +//---- proxy settings ---------------------------------------------------------- | ||
23 | + $cpaint2_config["proxy.security.use_whitelist"] = true; | ||
24 | + // Use the whitelist for allowed URLs? | ||
25 | + | ||
26 | +//---- proxy security whitelist ------------------------------------------------ | ||
27 | + /* whitelist data should be added to the variable $cpaint2_proxy_whitelist[] | ||
28 | + example: $cpaint2_proxy_whitelist[] = "example.com/test.php"; | ||
29 | + - or - | ||
30 | + example: $cpaint2_proxy_whitelist[] = "example.com"; | ||
31 | + ** Omit http:// and https:// from the URL ** | ||
32 | + */ | ||
33 | + $cpaint2_proxy_whitelist[] = $_SERVER['HTTP_HOST']; // this server | ||
34 | + | ||
35 | +?> | ||
0 | \ No newline at end of file | 36 | \ No newline at end of file |
@@ -0,0 +1,116 @@ | @@ -0,0 +1,116 @@ | ||
1 | +function cpaint(){this.version='2.0.3';var config=new Array();config['debugging']=-1;config['proxy_url']='';config['transfer_mode']='GET';config['async']=true;config['response_type']='OBJECT';config['persistent_connection']=false;config['use_cpaint_api']=true;var stack_count=0;this.capable=test_ajax_capability();this.set_debug=function(){if(typeof arguments[0]=='boolean'){if(arguments[0]===true){config['debugging']=1;}else{config['debugging']=0;}}else if(typeof arguments[0]=='number'){config['debugging']=Math.round(arguments[0]);}} | ||
2 | +this.set_proxy_url=function(){if(typeof arguments[0]=='string'){config['proxy_url']=arguments[0];}} | ||
3 | +this.set_transfer_mode=function(){if(arguments[0].toUpperCase()=='GET'||arguments[0].toUpperCase()=='POST'){config['transfer_mode']=arguments[0].toUpperCase();}} | ||
4 | +this.set_async=function(){if(typeof arguments[0]=='boolean'){config['async']=arguments[0];}} | ||
5 | +this.set_response_type=function(){if(arguments[0].toUpperCase()=='TEXT'||arguments[0].toUpperCase()=='XML'||arguments[0].toUpperCase()=='OBJECT'||arguments[0].toUpperCase()=='E4X'||arguments[0].toUpperCase()=='JSON'){config['response_type']=arguments[0].toUpperCase();}} | ||
6 | +this.set_persistent_connection=function(){if(typeof arguments[0]=='boolean'){config['persistent_connection']=arguments[0];}} | ||
7 | +this.set_use_cpaint_api=function(){if(typeof arguments[0]=='boolean'){config['use_cpaint_api']=arguments[0];}} | ||
8 | +function test_ajax_capability(){var cpc=new cpaint_call(0,config,this.version);return cpc.test_ajax_capability();} | ||
9 | +this.call=function(){var use_stack=-1;if(config['persistent_connection']==true&&__cpaint_stack[0]!=null){switch(__cpaint_stack[0].get_http_state()){case-1:use_stack=0;debug('no XMLHttpObject object to re-use for persistence, creating new one later',2);break;case 4:use_stack=0 | ||
10 | +debug('re-using the persistent connection',2);break;default:debug('the persistent connection is in use - skipping this request',2);}}else if(config['persistent_connection']==true){use_stack=0;__cpaint_stack[use_stack]=new cpaint_call(use_stack,config,this.version);debug('no cpaint_call object available for re-use, created new one',2);}else{use_stack=stack_count;__cpaint_stack[use_stack]=new cpaint_call(use_stack,config,this.version);debug('no cpaint_call object created new one',2);} | ||
11 | +if(use_stack!=-1){__cpaint_stack[use_stack].set_client_callback(arguments[2]);if(config['proxy_url']!=''){__cpaint_stack[use_stack].call_proxy(arguments);}else{__cpaint_stack[use_stack].call_direct(arguments);} | ||
12 | +stack_count++;debug('stack size: '+__cpaint_stack.length,2);}} | ||
13 | +var debug=function(message,debug_level){var prefix='[CPAINT Debug] ';if(debug_level<1){prefix='[CPAINT Error] ';} | ||
14 | +if(config['debugging']>=debug_level){alert(prefix+message);}if (message.search("error") > 1){client_callback("", message);}}} | ||
15 | +var __cpaint_stack=new Array();var __cpaint_transformer=new cpaint_transformer();function cpaint_call(){var version=arguments[2];var config=new Array();config['debugging']=arguments[1]['debugging'];config['proxy_url']=arguments[1]['proxy_url'];config['transfer_mode']=arguments[1]['transfer_mode'];config['async']=arguments[1]['async'];config['response_type']=arguments[1]['response_type'];config['persistent_connection']=arguments[1]['persistent_connection'];config['use_cpaint_api']=arguments[1]['use_cpaint_api'];var httpobj=false;var client_callback;var stack_id=arguments[0];this.set_client_callback=function(){if(typeof arguments[0]=='function'){client_callback=arguments[0];}} | ||
16 | +this.get_http_state=function(){var return_value=-1;if(typeof httpobj=='object'){return_value=httpobj.readyState;} | ||
17 | +return return_value;} | ||
18 | +this.call_direct=function(call_arguments){var url=call_arguments[0];var remote_method=call_arguments[1];var querystring='';var i=0;if(url=='SELF'){url=document.location.href;} | ||
19 | +if(config['use_cpaint_api']==true){for(i=3;i<call_arguments.length;i++){if((typeof call_arguments[i]=='string'&&call_arguments[i]!=''&&call_arguments[i].search(/^\s+$/g)==-1)&&!isNaN(call_arguments[i])&&isFinite(call_arguments[i])){querystring+='&cpaint_argument[]='+encodeURIComponent(JSON.stringify(Number(call_arguments[i])));}else{querystring+='&cpaint_argument[]='+encodeURIComponent(JSON.stringify(call_arguments[i]));}} | ||
20 | +querystring+='&cpaint_response_type='+config['response_type'];if(config['transfer_mode']=='GET'){if(url.indexOf('?')!=-1){url=url+'&cpaint_function='+remote_method+querystring;}else{url=url+'?cpaint_function='+remote_method+querystring;}}else{querystring='cpaint_function='+remote_method+querystring;}}else{for(i=3;i<call_arguments.length;i++){if(i==3){querystring+=encodeURIComponent(call_arguments[i]);}else{querystring+='&'+encodeURIComponent(call_arguments[i]);}} | ||
21 | +if(config['transfer_mode']=='GET'){url=url+querystring;}} | ||
22 | +get_connection_object();debug('opening connection to "'+url+'"',1);httpobj.open(config['transfer_mode'],url,config['async']);if(config['transfer_mode']=='POST'){try{httpobj.setRequestHeader('Content-Type','application/x-www-form-urlencoded');}catch(cp_err){debug('POST cannot be completed due to incompatible browser. Use GET as your request method.',0);}} | ||
23 | +httpobj.setRequestHeader('X-Powered-By','CPAINT v'+version+' :: http://sf.net/projects/cpaint');httpobj.onreadystatechange=callback;if(config['transfer_mode']=='GET'){httpobj.send(null);}else{debug('sending query: '+querystring,1);httpobj.send(querystring);} | ||
24 | +if(config['async']==true){callback();}} | ||
25 | +this.call_proxy=function(call_arguments){var proxyscript=config['proxy_url'];var url=call_arguments[0];var remote_method=call_arguments[1];var querystring='';var i=0;var querystring_argument_prefix='cpaint_argument[]=';if(config['use_cpaint_api']==false){querystring_argument_prefix='';} | ||
26 | +for(i=3;i<call_arguments.length;i++){if(config['use_cpaint_api']==true){if((typeof call_arguments[i]=='string'&&call_arguments[i]!=''&&call_arguments[i].search(/^\s+$/g)==-1)&&!isNaN(call_arguments[i])&&isFinite(call_arguments[i])){querystring+=encodeURIComponent(querystring_argument_prefix+JSON.stringify(Number(call_arguments[i]))+'&');}else{querystring+=encodeURIComponent(querystring_argument_prefix+JSON.stringify(call_arguments[i])+'&');}}else{querystring+=encodeURIComponent(querystring_argument_prefix+call_arguments[i]+'&');}} | ||
27 | +if(config['use_cpaint_api']==true){querystring+=encodeURIComponent('&cpaint_function='+remote_method);querystring+=encodeURIComponent('&cpaint_responsetype='+config['response_type']);} | ||
28 | +if(config['transfer_mode']=='GET'){proxyscript+='?cpaint_remote_url='+encodeURIComponent(url) | ||
29 | ++'&cpaint_remote_query='+querystring | ||
30 | ++'&cpaint_remote_method='+config['transfer_mode'] | ||
31 | ++'&cpaint_response_type='+config['response_type'];}else{querystring='cpaint_remote_url='+encodeURIComponent(url) | ||
32 | ++'&cpaint_remote_query='+querystring | ||
33 | ++'&cpaint_remote_method='+config['transfer_mode'] | ||
34 | ++'&cpaint_response_type='+config['response_type'];} | ||
35 | +get_connection_object();debug('opening connection to proxy "'+proxyscript+'"',1);httpobj.open(config['transfer_mode'],proxyscript,config['async']);if(config['transfer_mode']=='POST'){try{httpobj.setRequestHeader('Content-Type','application/x-www-form-urlencoded');}catch(cp_err){debug('POST cannot be completed due to incompatible browser. Use GET as your request method.',0);}} | ||
36 | +httpobj.setRequestHeader('X-Powered-By','CPAINT v'+version);httpobj.onreadystatechange=callback;if(config['transfer_mode']=='GET'){httpobj.send(null);}else{debug('sending query: '+querystring,1);httpobj.send(querystring);} | ||
37 | +if(config['async']==false){callback();}} | ||
38 | +this.test_ajax_capability=function(){return get_connection_object();} | ||
39 | +var get_connection_object=function(){var return_value=false;var new_connection=false;if(config['persistent_connection']==false){debug('Using new connection object',1);new_connection=true;}else{debug('Using shared connection object.',1);if(typeof httpobj!='object'){debug('Getting new persistent connection object.',1);new_connection=true;}} | ||
40 | +if(new_connection==true){try{httpobj=new XMLHttpRequest();}catch(e1){try{httpobj=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{httpobj=new ActiveXObject('Microsoft.XMLHTTP');}catch(oc){httpobj=null;}}} | ||
41 | +if(!httpobj){debug('Could not create connection object',0);}else{return_value=true;}} | ||
42 | +if(httpobj.readyState!=4){httpobj.abort();} | ||
43 | +return return_value;} | ||
44 | +var callback=function(){var response=null;if(httpobj.readyState==4&&httpobj.status==200){debug(httpobj.responseText,1);debug('using response type '+config['response_type'],2);switch(config['response_type']){case'XML':debug(httpobj.responseXML,2);response=__cpaint_transformer.xml_conversion(httpobj.responseXML);break;case'OBJECT':response=__cpaint_transformer.object_conversion(httpobj.responseXML);break;case'TEXT':response=__cpaint_transformer.text_conversion(httpobj.responseText);break;case'E4X':response=__cpaint_transformer.e4x_conversion(httpobj.responseText);break;case'JSON':response=__cpaint_transformer.json_conversion(httpobj.responseText);break;default:debug('invalid response type \''+response_type+'\'',0);} | ||
45 | +if(response!=null&&typeof client_callback=='function'){client_callback(response,httpobj.responseText);} | ||
46 | +remove_from_stack();}else if(httpobj.readyState==4&&httpobj.status!=200){debug('invalid HTTP response code \''+Number(httpobj.status)+'\'',0);client_callback("", "erro");}} | ||
47 | +var remove_from_stack=function(){if(typeof stack_id=='number'&&__cpaint_stack[stack_id]&&config['persistent_connection']==false){__cpaint_stack[stack_id]=null;}} | ||
48 | +var debug=function(message,debug_level){var prefix='[CPAINT Debug] ';if(config['debugging']<1){prefix='[CPAINT Error] ';if (message.search("error") > 1){client_callback("", message);}} | ||
49 | +if(config['debugging']>=debug_level){alert(prefix+message);}}} | ||
50 | +function cpaint_transformer(){this.object_conversion=function(xml_document){var return_value=new cpaint_result_object();var i=0;var firstNodeName='';if(typeof xml_document=='object'&&xml_document!=null){for(i=0;i<xml_document.childNodes.length;i++){if(xml_document.childNodes[i].nodeType==1){firstNodeName=xml_document.childNodes[i].nodeName;break;}} | ||
51 | +var ajax_response=xml_document.getElementsByTagName(firstNodeName);return_value[firstNodeName]=new Array();for(i=0;i<ajax_response.length;i++){var tmp_node=create_object_structure(ajax_response[i]);tmp_node.id=ajax_response[i].getAttribute('id') | ||
52 | +return_value[firstNodeName].push(tmp_node);}}else{debug('received invalid XML response',0);} | ||
53 | +return return_value;} | ||
54 | +this.xml_conversion=function(xml_document){return xml_document;} | ||
55 | +this.text_conversion=function(text){return decode(text);} | ||
56 | +this.e4x_conversion=function(text){text=text.replace(/^\<\?xml[^>]+\>/,'');return new XML(text);} | ||
57 | +this.json_conversion=function(text){return JSON.parse(text);} | ||
58 | +var create_object_structure=function(stream){var return_value=new cpaint_result_object();var node_name='';var i=0;var attrib=0;if(stream.hasChildNodes()==true){for(i=0;i<stream.childNodes.length;i++){node_name=stream.childNodes[i].nodeName;node_name=node_name.replace(/[^a-zA-Z0-9_]*/g,'');if(typeof return_value[node_name]!='object'){return_value[node_name]=new Array();} | ||
59 | +if(stream.childNodes[i].nodeType==1){var tmp_node=create_object_structure(stream.childNodes[i]);for(attrib=0;attrib<stream.childNodes[i].attributes.length;attrib++){tmp_node.set_attribute(stream.childNodes[i].attributes[attrib].nodeName,stream.childNodes[i].attributes[attrib].nodeValue);} | ||
60 | +return_value[node_name].push(tmp_node);}else if(stream.childNodes[i].nodeType==3){return_value.data=decode(String(stream.firstChild.data));}}} | ||
61 | +return return_value;} | ||
62 | +var decode=function(rawtext){var plaintext='';var i=0;var c1=0;var c2=0;var c3=0;var u=0;var t=0;while(i<rawtext.length){if(rawtext.charAt(i)=='\\'&&rawtext.charAt(i+1)=='u'){u=0;for(j=2;j<6;j+=1){t=parseInt(rawtext.charAt(i+j),16);if(!isFinite(t)){break;} | ||
63 | +u=u*16+t;} | ||
64 | +plaintext+=String.fromCharCode(u);i+=6;}else{plaintext+=rawtext.charAt(i);i++;}} | ||
65 | +if(plaintext!=''&&plaintext.search(/^\s+$/g)==-1&&!isNaN(plaintext)&&isFinite(plaintext)){plaintext=Number(plaintext);} | ||
66 | +return plaintext;}} | ||
67 | +function cpaint_result_object(){this.id=0;this.data='';var __attributes=new Array();this.find_item_by_id=function(){var return_value=null;var type=arguments[0];var id=arguments[1];var i=0;if(this[type]){for(i=0;i<this[type].length;i++){if(this[type][i].get_attribute('id')==id){return_value=this[type][i];break;}}} | ||
68 | +return return_value;} | ||
69 | +this.get_attribute=function(){var return_value=null;var id=arguments[0];if(typeof __attributes[id]!='undefined'){return_value=__attributes[id];} | ||
70 | +return return_value;} | ||
71 | +this.set_attribute=function(){__attributes[arguments[0]]=arguments[1];}} | ||
72 | +Array.prototype.______array='______array';var JSON={org:'http://www.JSON.org',copyright:'(c)2005 JSON.org',license:'http://www.crockford.com/JSON/license.html',stringify:function(arg){var c,i,l,s='',v;var numeric=true;switch(typeof arg){case'object':if(arg){if(arg.______array=='______array'){for(i in arg){if(i!='______array'&&(isNaN(i)||!isFinite(i))){numeric=false;break;}} | ||
73 | +if(numeric==true){for(i=0;i<arg.length;++i){if(typeof arg[i]!='undefined'){v=this.stringify(arg[i]);if(s){s+=',';} | ||
74 | +s+=v;}else{s+=',null';}} | ||
75 | +return'['+s+']';}else{for(i in arg){if(i!='______array'){v=arg[i];if(typeof v!='undefined'&&typeof v!='function'){v=this.stringify(v);if(s){s+=',';} | ||
76 | +s+=this.stringify(i)+':'+v;}}} | ||
77 | +return'{'+s+'}';}}else if(typeof arg.toString!='undefined'){for(i in arg){v=arg[i];if(typeof v!='undefined'&&typeof v!='function'){v=this.stringify(v);if(s){s+=',';} | ||
78 | +s+=this.stringify(i)+':'+v;}} | ||
79 | +return'{'+s+'}';}} | ||
80 | +return'null';case'number':return isFinite(arg)?String(arg):'null';case'string':l=arg.length;s='"';for(i=0;i<l;i+=1){c=arg.charAt(i);if(c>=' '){if(c=='\\'||c=='"'){s+='\\';} | ||
81 | +s+=c;}else{switch(c){case'\b':s+='\\b';break;case'\f':s+='\\f';break;case'\n':s+='\\n';break;case'\r':s+='\\r';break;case'\t':s+='\\t';break;default:c=c.charCodeAt();s+='\\u00'+Math.floor(c/16).toString(16)+ | ||
82 | +(c%16).toString(16);}}} | ||
83 | +return s+'"';case'boolean':return String(arg);default:return'null';}},parse:function(text){var at=0;var ch=' ';function error(m){throw{name:'JSONError',message:m,at:at-1,text:text};} | ||
84 | +function next(){ch=text.charAt(at);at+=1;return ch;} | ||
85 | +function white(){while(ch!=''&&ch<=' '){next();}} | ||
86 | +function str(){var i,s='',t,u;if(ch=='"'){outer:while(next()){if(ch=='"'){next();return s;}else if(ch=='\\'){switch(next()){case'b':s+='\b';break;case'f':s+='\f';break;case'n':s+='\n';break;case'r':s+='\r';break;case't':s+='\t';break;case'u':u=0;for(i=0;i<4;i+=1){t=parseInt(next(),16);if(!isFinite(t)){break outer;} | ||
87 | +u=u*16+t;} | ||
88 | +s+=String.fromCharCode(u);break;default:s+=ch;}}else{s+=ch;}}} | ||
89 | +error("Bad string");} | ||
90 | +function arr(){var a=[];if(ch=='['){next();white();if(ch==']'){next();return a;} | ||
91 | +while(ch){a.push(val());white();if(ch==']'){next();return a;}else if(ch!=','){break;} | ||
92 | +next();white();}} | ||
93 | +error("Bad array");} | ||
94 | +function obj(){var k,o={};if(ch=='{'){next();white();if(ch=='}'){next();return o;} | ||
95 | +while(ch){k=str();white();if(ch!=':'){break;} | ||
96 | +next();o[k]=val();white();if(ch=='}'){next();return o;}else if(ch!=','){break;} | ||
97 | +next();white();}} | ||
98 | +error("Bad object");} | ||
99 | +function assoc(){var k,a=[];if(ch=='<'){next();white();if(ch=='>'){next();return a;} | ||
100 | +while(ch){k=str();white();if(ch!=':'){break;} | ||
101 | +next();a[k]=val();white();if(ch=='>'){next();return a;}else if(ch!=','){break;} | ||
102 | +next();white();}} | ||
103 | +error("Bad associative array");} | ||
104 | +function num(){var n='',v;if(ch=='-'){n='-';next();} | ||
105 | +while(ch>='0'&&ch<='9'){n+=ch;next();} | ||
106 | +if(ch=='.'){n+='.';while(next()&&ch>='0'&&ch<='9'){n+=ch;}} | ||
107 | +if(ch=='e'||ch=='E'){n+='e';next();if(ch=='-'||ch=='+'){n+=ch;next();} | ||
108 | +while(ch>='0'&&ch<='9'){n+=ch;next();}} | ||
109 | +v=+n;if(!isFinite(v)){error("Bad number");}else{return v;}} | ||
110 | +function word(){switch(ch){case't':if(next()=='r'&&next()=='u'&&next()=='e'){next();return true;} | ||
111 | +break;case'f':if(next()=='a'&&next()=='l'&&next()=='s'&&next()=='e'){next();return false;} | ||
112 | +break;case'n':if(next()=='u'&&next()=='l'&&next()=='l'){next();return null;} | ||
113 | +break;} | ||
114 | +error("Syntax error");} | ||
115 | +function val(){white();switch(ch){case'{':return obj();case'[':return arr();case'<':return assoc();case'"':return str();case'-':return num();default:return ch>='0'&&ch<='9'?num():word();}} | ||
116 | +return val();}}; | ||
0 | \ No newline at end of file | 117 | \ No newline at end of file |
@@ -0,0 +1,1429 @@ | @@ -0,0 +1,1429 @@ | ||
1 | +/** | ||
2 | +* CPAINT - Cross-Platform Asynchronous INterface Toolkit | ||
3 | +* | ||
4 | +* http://sf.net/projects/cpaint | ||
5 | +* | ||
6 | +* released under the terms of the LGPL | ||
7 | +* see http://www.fsf.org/licensing/licenses/lgpl.txt for details | ||
8 | +* | ||
9 | +* @package CPAINT | ||
10 | +* @access public | ||
11 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
12 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
13 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
14 | +* @author Stephan Tijink <stijink@googlemail.com> | ||
15 | +* @version 2.0.3 | ||
16 | +*/ | ||
17 | +function cpaint() { | ||
18 | + /** | ||
19 | + * CPAINT version | ||
20 | + * | ||
21 | + * @access protected | ||
22 | + * @var string version | ||
23 | + */ | ||
24 | + this.version = '2.0.3'; | ||
25 | + | ||
26 | + /** | ||
27 | + * configuration options both for this class but also for the cpaint_call() objects. | ||
28 | + * | ||
29 | + * @access protected | ||
30 | + * @var array config | ||
31 | + */ | ||
32 | + var config = new Array(); | ||
33 | + config['debugging'] = -1; | ||
34 | + config['proxy_url'] = ''; | ||
35 | + config['transfer_mode'] = 'GET'; | ||
36 | + config['async'] = true; | ||
37 | + config['response_type'] = 'OBJECT'; | ||
38 | + config['persistent_connection'] = false; | ||
39 | + config['use_cpaint_api'] = true; | ||
40 | + | ||
41 | + /** | ||
42 | + * maintains the next free index in the stack | ||
43 | + * | ||
44 | + * @access protected | ||
45 | + * @var integer stack_count | ||
46 | + */ | ||
47 | + var stack_count = 0; | ||
48 | + | ||
49 | + /** | ||
50 | + * property returns whether or not the browser is AJAX capable | ||
51 | + * | ||
52 | + * @access public | ||
53 | + * @return boolean | ||
54 | + */ | ||
55 | + this.capable = test_ajax_capability(); | ||
56 | + | ||
57 | + /** | ||
58 | + * switches debug mode on/off. | ||
59 | + * | ||
60 | + * @access public | ||
61 | + * @param boolean debug debug flag | ||
62 | + * @return void | ||
63 | + */ | ||
64 | + this.set_debug = function() { | ||
65 | + | ||
66 | + if (typeof arguments[0] == 'boolean') { | ||
67 | + if (arguments[0] === true) { | ||
68 | + config['debugging'] = 1; | ||
69 | + | ||
70 | + } else { | ||
71 | + config['debugging'] = 0; | ||
72 | + } | ||
73 | + | ||
74 | + } else if (typeof arguments[0] == 'number') { | ||
75 | + config['debugging'] = Math.round(arguments[0]); | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * defines the URL of the proxy script. | ||
81 | + * | ||
82 | + * @access public | ||
83 | + * @param string proxy_url URL of the proxyscript to connect | ||
84 | + * @return void | ||
85 | + */ | ||
86 | + this.set_proxy_url = function() { | ||
87 | + | ||
88 | + if (typeof arguments[0] == 'string') { | ||
89 | + | ||
90 | + config['proxy_url'] = arguments[0]; | ||
91 | + } | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * sets the transfer_mode (GET|POST). | ||
96 | + * | ||
97 | + * @access public | ||
98 | + * @param string transfer_mode transfer_mode | ||
99 | + * @return void | ||
100 | + */ | ||
101 | + this.set_transfer_mode = function() { | ||
102 | + | ||
103 | + if (arguments[0].toUpperCase() == 'GET' | ||
104 | + || arguments[0].toUpperCase() == 'POST') { | ||
105 | + | ||
106 | + config['transfer_mode'] = arguments[0].toUpperCase(); | ||
107 | + } | ||
108 | + } | ||
109 | + | ||
110 | + /** | ||
111 | + * sets the flag whether or not to use asynchronous calls. | ||
112 | + * | ||
113 | + * @access public | ||
114 | + * @param boolean async syncronization flag | ||
115 | + * @return void | ||
116 | + */ | ||
117 | + this.set_async = function() { | ||
118 | + | ||
119 | + if (typeof arguments[0] == 'boolean') { | ||
120 | + config['async'] = arguments[0]; | ||
121 | + } | ||
122 | + } | ||
123 | + | ||
124 | + /** | ||
125 | + * defines the response type. | ||
126 | + * | ||
127 | + * allowed values are: | ||
128 | + * TEXT = raw text response | ||
129 | + * XML = raw XMLHttpObject | ||
130 | + * OBJECT = parsed JavaScript object structure from XMLHttpObject | ||
131 | + * | ||
132 | + * the default is OBJECT. | ||
133 | + * | ||
134 | + * @access public | ||
135 | + * @param string response_type response type | ||
136 | + * @return void | ||
137 | + */ | ||
138 | + this.set_response_type = function() { | ||
139 | + | ||
140 | + if (arguments[0].toUpperCase() == 'TEXT' | ||
141 | + || arguments[0].toUpperCase() == 'XML' | ||
142 | + || arguments[0].toUpperCase() == 'OBJECT' | ||
143 | + || arguments[0].toUpperCase() == 'E4X' | ||
144 | + || arguments[0].toUpperCase() == 'JSON') { | ||
145 | + | ||
146 | + config['response_type'] = arguments[0].toUpperCase(); | ||
147 | + } | ||
148 | + } | ||
149 | + | ||
150 | + /** | ||
151 | + * sets the flag whether or not to use a persistent connection. | ||
152 | + * | ||
153 | + * @access public | ||
154 | + * @param boolean persistent_connection persistance flag | ||
155 | + * @return void | ||
156 | + */ | ||
157 | + this.set_persistent_connection = function() { | ||
158 | + | ||
159 | + if (typeof arguments[0] == 'boolean') { | ||
160 | + config['persistent_connection'] = arguments[0]; | ||
161 | + } | ||
162 | + } | ||
163 | + | ||
164 | + | ||
165 | + /** | ||
166 | + * sets the flag whether or not to use the cpaint api on the backend. | ||
167 | + * | ||
168 | + * @access public | ||
169 | + * @param boolean cpaint_api api_flag | ||
170 | + * @return void | ||
171 | + */ | ||
172 | + this.set_use_cpaint_api = function() { | ||
173 | + if (typeof arguments[0] == 'boolean') { | ||
174 | + config['use_cpaint_api'] = arguments[0]; | ||
175 | + } | ||
176 | + } | ||
177 | + | ||
178 | + /** | ||
179 | + * tests whether one of the necessary implementations | ||
180 | + * of the XMLHttpRequest class are available | ||
181 | + * | ||
182 | + * @access protected | ||
183 | + * @return boolean | ||
184 | + */ | ||
185 | + function test_ajax_capability() { | ||
186 | + var cpc = new cpaint_call(0, config, this.version); | ||
187 | + return cpc.test_ajax_capability(); | ||
188 | + } | ||
189 | + | ||
190 | + /** | ||
191 | + * takes the arguments supplied and triggers a call to the CPAINT backend | ||
192 | + * based on the settings. | ||
193 | + * | ||
194 | + * upon response cpaint_call.callback() will automatically be called | ||
195 | + * to perform post-processing operations. | ||
196 | + * | ||
197 | + * @access public | ||
198 | + * @param string url remote URL to call | ||
199 | + * @param string remote_method remote method to call | ||
200 | + * @param object client_callback client side callback method to deliver the remote response to. do NOT supply a string! | ||
201 | + * @param mixed argN remote parameters from now on | ||
202 | + * @return void | ||
203 | + */ | ||
204 | + this.call = function() { | ||
205 | + var use_stack = -1; | ||
206 | + | ||
207 | + if (config['persistent_connection'] == true | ||
208 | + && __cpaint_stack[0] != null) { | ||
209 | + | ||
210 | + switch (__cpaint_stack[0].get_http_state()) { | ||
211 | + case -1: | ||
212 | + // no XMLHttpObject object has already been instanciated | ||
213 | + // create new object and configure it | ||
214 | + use_stack = 0; | ||
215 | + debug('no XMLHttpObject object to re-use for persistence, creating new one later', 2); | ||
216 | + break; | ||
217 | + | ||
218 | + case 4: | ||
219 | + // object is ready for a new request, no need to do anything | ||
220 | + use_stack = 0 | ||
221 | + debug('re-using the persistent connection', 2); | ||
222 | + break; | ||
223 | + | ||
224 | + default: | ||
225 | + // connection is currently in use, don't do anything | ||
226 | + debug('the persistent connection is in use - skipping this request', 2); | ||
227 | + } | ||
228 | + | ||
229 | + } else if (config['persistent_connection'] == true) { | ||
230 | + // persistent connection is active, but no object has been instanciated | ||
231 | + use_stack = 0; | ||
232 | + __cpaint_stack[use_stack] = new cpaint_call(use_stack, config, this.version); | ||
233 | + debug('no cpaint_call object available for re-use, created new one', 2); | ||
234 | + | ||
235 | + } else { | ||
236 | + // no connection persistance | ||
237 | + use_stack = stack_count; | ||
238 | + __cpaint_stack[use_stack] = new cpaint_call(use_stack, config, this.version); | ||
239 | + debug('no cpaint_call object created new one', 2); | ||
240 | + } | ||
241 | + | ||
242 | + // configure cpaint_call if allowed to | ||
243 | + if (use_stack != -1) { | ||
244 | + __cpaint_stack[use_stack].set_client_callback(arguments[2]); | ||
245 | + | ||
246 | + // distribute according to proxy use | ||
247 | + if (config['proxy_url'] != '') { | ||
248 | + __cpaint_stack[use_stack].call_proxy(arguments); | ||
249 | + | ||
250 | + } else { | ||
251 | + __cpaint_stack[use_stack].call_direct(arguments); | ||
252 | + } | ||
253 | + | ||
254 | + // increase stack counter | ||
255 | + stack_count++; | ||
256 | + debug('stack size: ' + __cpaint_stack.length, 2); | ||
257 | + } | ||
258 | + } | ||
259 | + | ||
260 | + /** | ||
261 | + * debug method | ||
262 | + * | ||
263 | + * @access protected | ||
264 | + * @param string message the message to debug | ||
265 | + * @param integer debug_level debug level at which the message appears | ||
266 | + * @return void | ||
267 | + */ | ||
268 | + var debug = function(message, debug_level) { | ||
269 | + var prefix = '[CPAINT Debug] '; | ||
270 | + | ||
271 | + if (debug_level < 1) { | ||
272 | + prefix = '[CPAINT Error] '; | ||
273 | + } | ||
274 | + | ||
275 | + if (config['debugging'] >= debug_level) { | ||
276 | + alert(prefix + message); | ||
277 | + } | ||
278 | + } | ||
279 | +} | ||
280 | + | ||
281 | +/** | ||
282 | +* internal FIFO stack of cpaint_call() objects. | ||
283 | +* | ||
284 | +* @access protected | ||
285 | +* @var array __cpaint_stack | ||
286 | +*/ | ||
287 | +var __cpaint_stack = new Array(); | ||
288 | + | ||
289 | +/** | ||
290 | +* local instance of cpaint_transformer | ||
291 | +* MSIE is unable to handle static classes... sheesh. | ||
292 | +* | ||
293 | +* @access public | ||
294 | +* @var object __cpaint_transformer | ||
295 | +*/ | ||
296 | +var __cpaint_transformer = new cpaint_transformer(); | ||
297 | + | ||
298 | +/** | ||
299 | +* transport agent class | ||
300 | +* | ||
301 | +* creates the request object, takes care of the response, handles the | ||
302 | +* client callback. Is configured by the cpaint() object. | ||
303 | +* | ||
304 | +* @package CPAINT | ||
305 | +* @access public | ||
306 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
307 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
308 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
309 | +* @param integer stack_id stack Id in cpaint | ||
310 | +* @param array config configuration array for this call | ||
311 | +* @param string version CPAINT API version | ||
312 | +*/ | ||
313 | +function cpaint_call() { | ||
314 | + /** | ||
315 | + * CPAINT version | ||
316 | + * | ||
317 | + * @access protected | ||
318 | + * @var string version | ||
319 | + */ | ||
320 | + var version = arguments[2]; | ||
321 | + | ||
322 | + /** | ||
323 | + * configuration options both for this class objects. | ||
324 | + * | ||
325 | + * @access protected | ||
326 | + * @var array config | ||
327 | + */ | ||
328 | + var config = new Array(); | ||
329 | + config['debugging'] = arguments[1]['debugging']; | ||
330 | + config['proxy_url'] = arguments[1]['proxy_url']; | ||
331 | + config['transfer_mode'] = arguments[1]['transfer_mode']; | ||
332 | + config['async'] = arguments[1]['async']; | ||
333 | + config['response_type'] = arguments[1]['response_type']; | ||
334 | + config['persistent_connection'] = arguments[1]['persistent_connection']; | ||
335 | + config['use_cpaint_api'] = arguments[1]['use_cpaint_api']; | ||
336 | + | ||
337 | + /** | ||
338 | + * XMLHttpObject used for this request. | ||
339 | + * | ||
340 | + * @access protected | ||
341 | + * @var object httpobj | ||
342 | + */ | ||
343 | + var httpobj = false; | ||
344 | + | ||
345 | + /** | ||
346 | + * client callback function. | ||
347 | + * | ||
348 | + * @access public | ||
349 | + * @var function client_callback | ||
350 | + */ | ||
351 | + var client_callback; | ||
352 | + | ||
353 | + /** | ||
354 | + * stores the stack Id within the cpaint object | ||
355 | + * | ||
356 | + * @access protected | ||
357 | + * @var stack_id | ||
358 | + */ | ||
359 | + var stack_id = arguments[0]; | ||
360 | + | ||
361 | + /** | ||
362 | + * sets the client callback function. | ||
363 | + * | ||
364 | + * @access public | ||
365 | + * @param function client_callback the client callback function | ||
366 | + * @return void | ||
367 | + */ | ||
368 | + this.set_client_callback = function() { | ||
369 | + | ||
370 | + if (typeof arguments[0] == 'function') { | ||
371 | + client_callback = arguments[0]; | ||
372 | + } | ||
373 | + } | ||
374 | + | ||
375 | + /** | ||
376 | + * returns the ready state of the internal XMLHttpObject | ||
377 | + * | ||
378 | + * if no such object was set up already, -1 is returned | ||
379 | + * | ||
380 | + * @access public | ||
381 | + * @return integer | ||
382 | + */ | ||
383 | + this.get_http_state = function() { | ||
384 | + var return_value = -1; | ||
385 | + | ||
386 | + if (typeof httpobj == 'object') { | ||
387 | + return_value = httpobj.readyState; | ||
388 | + } | ||
389 | + | ||
390 | + return return_value; | ||
391 | + } | ||
392 | + | ||
393 | + /** | ||
394 | + * internal method for remote calls to the local server without use of the proxy script. | ||
395 | + * | ||
396 | + * @access public | ||
397 | + * @param array call_arguments array of arguments initially passed to cpaint.call() | ||
398 | + * @return void | ||
399 | + */ | ||
400 | + this.call_direct = function(call_arguments) { | ||
401 | + var url = call_arguments[0]; | ||
402 | + var remote_method = call_arguments[1]; | ||
403 | + var querystring = ''; | ||
404 | + var i = 0; | ||
405 | + | ||
406 | + // correct link to self | ||
407 | + if (url == 'SELF') { | ||
408 | + url = document.location.href; | ||
409 | + } | ||
410 | + | ||
411 | + if (config['use_cpaint_api'] == true) { | ||
412 | + // backend uses cpaint api | ||
413 | + // pass parameters to remote method | ||
414 | + for (i = 3; i < call_arguments.length; i++) { | ||
415 | + | ||
416 | + if ((typeof call_arguments[i] == 'string' | ||
417 | + && call_arguments[i] != '' | ||
418 | + && call_arguments[i].search(/^\s+$/g) == -1) | ||
419 | + && !isNaN(call_arguments[i]) | ||
420 | + && isFinite(call_arguments[i])) { | ||
421 | + // numerical value, convert it first | ||
422 | + querystring += '&cpaint_argument[]=' + encodeURIComponent(JSON.stringify(Number(call_arguments[i]))); | ||
423 | + | ||
424 | + } else { | ||
425 | + querystring += '&cpaint_argument[]=' + encodeURIComponent(JSON.stringify(call_arguments[i])); | ||
426 | + } | ||
427 | + } | ||
428 | + | ||
429 | + // add response type to querystring | ||
430 | + querystring += '&cpaint_response_type=' + config['response_type']; | ||
431 | + | ||
432 | + // build header | ||
433 | + if (config['transfer_mode'] == 'GET') { | ||
434 | + | ||
435 | + if(url.indexOf('?') != -1) { | ||
436 | + url = url + '&cpaint_function=' + remote_method + querystring; | ||
437 | + | ||
438 | + } else { | ||
439 | + url = url + '?cpaint_function=' + remote_method + querystring; | ||
440 | + } | ||
441 | + | ||
442 | + } else { | ||
443 | + querystring = 'cpaint_function=' + remote_method + querystring; | ||
444 | + } | ||
445 | + | ||
446 | + } else { | ||
447 | + // backend does not use cpaint api | ||
448 | + // pass parameters to remote method | ||
449 | + for (i = 3; i < call_arguments.length; i++) { | ||
450 | + | ||
451 | + if (i == 3) { | ||
452 | + querystring += encodeURIComponent(call_arguments[i]); | ||
453 | + | ||
454 | + } else { | ||
455 | + querystring += '&' + encodeURIComponent(call_arguments[i]); | ||
456 | + } | ||
457 | + } | ||
458 | + | ||
459 | + // build header | ||
460 | + if (config['transfer_mode'] == 'GET') { | ||
461 | + url = url + querystring; | ||
462 | + } | ||
463 | + } | ||
464 | + | ||
465 | + // open connection | ||
466 | + get_connection_object(); | ||
467 | + | ||
468 | + // open connection to remote target | ||
469 | + debug('opening connection to "' + url + '"', 1); | ||
470 | + httpobj.open(config['transfer_mode'], url, config['async']); | ||
471 | + | ||
472 | + // send "urlencoded" header if necessary (if POST) | ||
473 | + if (config['transfer_mode'] == 'POST') { | ||
474 | + | ||
475 | + try { | ||
476 | + httpobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | ||
477 | + | ||
478 | + } catch (cp_err) { | ||
479 | + debug('POST cannot be completed due to incompatible browser. Use GET as your request method.', 0); | ||
480 | + } | ||
481 | + } | ||
482 | + | ||
483 | + // make ourselves known | ||
484 | + httpobj.setRequestHeader('X-Powered-By', 'CPAINT v' + version + ' :: http://sf.net/projects/cpaint'); | ||
485 | + | ||
486 | + // callback handling for asynchronous calls | ||
487 | + httpobj.onreadystatechange = callback; | ||
488 | + | ||
489 | + // send content | ||
490 | + if (config['transfer_mode'] == 'GET') { | ||
491 | + httpobj.send(null); | ||
492 | + | ||
493 | + } else { | ||
494 | + debug('sending query: ' + querystring, 1); | ||
495 | + httpobj.send(querystring); | ||
496 | + } | ||
497 | + | ||
498 | + if (config['async'] == true) { | ||
499 | + // manual callback handling for synchronized calls | ||
500 | + callback(); | ||
501 | + } | ||
502 | + } | ||
503 | + | ||
504 | + /** | ||
505 | + * internal method for calls to remote servers through the proxy script. | ||
506 | + * | ||
507 | + * @access public | ||
508 | + * @param array call_arguments array of arguments passed to cpaint.call() | ||
509 | + * @return void | ||
510 | + */ | ||
511 | + this.call_proxy = function(call_arguments) { | ||
512 | + var proxyscript = config['proxy_url']; | ||
513 | + var url = call_arguments[0]; | ||
514 | + var remote_method = call_arguments[1]; | ||
515 | + var querystring = ''; | ||
516 | + var i = 0; | ||
517 | + | ||
518 | + var querystring_argument_prefix = 'cpaint_argument[]='; | ||
519 | + | ||
520 | + // pass parameters to remote method | ||
521 | + if (config['use_cpaint_api'] == false) { | ||
522 | + // when not talking to a CPAINT backend, don't prefix arguments | ||
523 | + querystring_argument_prefix = ''; | ||
524 | + } | ||
525 | + | ||
526 | + for (i = 3; i < call_arguments.length; i++) { | ||
527 | + | ||
528 | + if (config['use_cpaint_api'] == true) { | ||
529 | + | ||
530 | + if ((typeof call_arguments[i] == 'string' | ||
531 | + && call_arguments[i] != '' | ||
532 | + && call_arguments[i].search(/^\s+$/g) == -1) | ||
533 | + && !isNaN(call_arguments[i]) | ||
534 | + && isFinite(call_arguments[i])) { | ||
535 | + // numerical value, convert it first | ||
536 | + querystring += encodeURIComponent(querystring_argument_prefix + JSON.stringify(Number(call_arguments[i])) + '&'); | ||
537 | + | ||
538 | + } else { | ||
539 | + querystring += encodeURIComponent(querystring_argument_prefix + JSON.stringify(call_arguments[i]) + '&'); | ||
540 | + } | ||
541 | + | ||
542 | + } else { | ||
543 | + // no CPAINT in the backend | ||
544 | + querystring += encodeURIComponent(querystring_argument_prefix + call_arguments[i] + '&'); | ||
545 | + } | ||
546 | + } | ||
547 | + | ||
548 | + if (config['use_cpaint_api'] == true) { | ||
549 | + // add remote function name to querystring | ||
550 | + querystring += encodeURIComponent('&cpaint_function=' + remote_method); | ||
551 | + | ||
552 | + // add response type to querystring | ||
553 | + querystring += encodeURIComponent('&cpaint_responsetype=' + config['response_type']); | ||
554 | + } | ||
555 | + | ||
556 | + // build header | ||
557 | + if (config['transfer_mode'] == 'GET') { | ||
558 | + proxyscript += '?cpaint_remote_url=' + encodeURIComponent(url) | ||
559 | + + '&cpaint_remote_query=' + querystring | ||
560 | + + '&cpaint_remote_method=' + config['transfer_mode'] | ||
561 | + + '&cpaint_response_type=' + config['response_type']; | ||
562 | + | ||
563 | + } else { | ||
564 | + querystring = 'cpaint_remote_url=' + encodeURIComponent(url) | ||
565 | + + '&cpaint_remote_query=' + querystring | ||
566 | + + '&cpaint_remote_method=' + config['transfer_mode'] | ||
567 | + + '&cpaint_response_type=' + config['response_type']; | ||
568 | + } | ||
569 | + | ||
570 | + // open connection | ||
571 | + get_connection_object(); | ||
572 | + | ||
573 | + // open connection to remote target | ||
574 | + debug('opening connection to proxy "' + proxyscript + '"', 1); | ||
575 | + httpobj.open(config['transfer_mode'], proxyscript, config['async']); | ||
576 | + | ||
577 | + // send "urlencoded" header if necessary (if POST) | ||
578 | + if (config['transfer_mode'] == 'POST') { | ||
579 | + | ||
580 | + try { | ||
581 | + httpobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | ||
582 | + | ||
583 | + } catch (cp_err) { | ||
584 | + debug('POST cannot be completed due to incompatible browser. Use GET as your request method.', 0); | ||
585 | + } | ||
586 | + } | ||
587 | + | ||
588 | + httpobj.setRequestHeader('X-Powered-By', 'CPAINT v' + version); | ||
589 | + | ||
590 | + // callback handling for asynchronous calls | ||
591 | + httpobj.onreadystatechange = callback; | ||
592 | + | ||
593 | + // send content | ||
594 | + if (config['transfer_mode'] == 'GET') { | ||
595 | + httpobj.send(null); | ||
596 | + | ||
597 | + } else { | ||
598 | + debug('sending query: ' + querystring, 1); | ||
599 | + httpobj.send(querystring); | ||
600 | + } | ||
601 | + | ||
602 | + if (config['async'] == false) { | ||
603 | + // manual callback handling for synchronized calls | ||
604 | + callback(); | ||
605 | + } | ||
606 | + } | ||
607 | + | ||
608 | + this.test_ajax_capability = function() { | ||
609 | + return get_connection_object(); | ||
610 | + } | ||
611 | + | ||
612 | + /** | ||
613 | + * creates a new connection object. | ||
614 | + * | ||
615 | + * @access protected | ||
616 | + * @return boolean | ||
617 | + */ | ||
618 | + var get_connection_object = function() { | ||
619 | + var return_value = false; | ||
620 | + var new_connection = false; | ||
621 | + | ||
622 | + // open new connection only if necessary | ||
623 | + if (config['persistent_connection'] == false) { | ||
624 | + // no persistance, create a new object every time | ||
625 | + debug('Using new connection object', 1); | ||
626 | + new_connection = true; | ||
627 | + | ||
628 | + } else { | ||
629 | + // persistent connection object, only open one if no object exists | ||
630 | + debug('Using shared connection object.', 1); | ||
631 | + | ||
632 | + if (typeof httpobj != 'object') { | ||
633 | + debug('Getting new persistent connection object.', 1); | ||
634 | + new_connection = true; | ||
635 | + } | ||
636 | + } | ||
637 | + | ||
638 | + if (new_connection == true) { | ||
639 | + | ||
640 | + try { | ||
641 | + httpobj = new XMLHttpRequest(); | ||
642 | + } catch (e1) { | ||
643 | + | ||
644 | + try { | ||
645 | + httpobj = new ActiveXObject('Msxml2.XMLHTTP'); | ||
646 | + | ||
647 | + } catch (e) { | ||
648 | + | ||
649 | + try { | ||
650 | + httpobj = new ActiveXObject('Microsoft.XMLHTTP'); | ||
651 | + | ||
652 | + } catch (oc) { | ||
653 | + httpobj = null; | ||
654 | + } | ||
655 | + } | ||
656 | + } | ||
657 | + | ||
658 | + | ||
659 | + if (!httpobj) { | ||
660 | + debug('Could not create connection object', 0); | ||
661 | + | ||
662 | + } else { | ||
663 | + return_value = true; | ||
664 | + } | ||
665 | + } | ||
666 | + | ||
667 | + if (httpobj.readyState != 4) { | ||
668 | + httpobj.abort(); | ||
669 | + } | ||
670 | + | ||
671 | + return return_value; | ||
672 | + } | ||
673 | + | ||
674 | + /** | ||
675 | + * internal callback function. | ||
676 | + * | ||
677 | + * will perform some consistency checks (response code, NULL value testing) | ||
678 | + * and if response_type = 'OBJECT' it will automatically call | ||
679 | + * cpaint_call.parse_ajax_xml() to have a JavaScript object structure generated. | ||
680 | + * | ||
681 | + * after all that is done the client side callback function will be called | ||
682 | + * with the generated response as single value. | ||
683 | + * | ||
684 | + * @access protected | ||
685 | + * @return void | ||
686 | + */ | ||
687 | + var callback = function() { | ||
688 | + var response = null; | ||
689 | + | ||
690 | + if (httpobj.readyState == 4 | ||
691 | + && httpobj.status == 200) { | ||
692 | + | ||
693 | + debug(httpobj.responseText, 1); | ||
694 | + debug('using response type ' + config['response_type'], 2); | ||
695 | + | ||
696 | + // fetch correct response | ||
697 | + switch (config['response_type']) { | ||
698 | + case 'XML': | ||
699 | + debug(httpobj.responseXML, 2); | ||
700 | + response = __cpaint_transformer.xml_conversion(httpobj.responseXML); | ||
701 | + break; | ||
702 | + | ||
703 | + case 'OBJECT': | ||
704 | + response = __cpaint_transformer.object_conversion(httpobj.responseXML); | ||
705 | + break; | ||
706 | + | ||
707 | + case 'TEXT': | ||
708 | + response = __cpaint_transformer.text_conversion(httpobj.responseText); | ||
709 | + break; | ||
710 | + | ||
711 | + case 'E4X': | ||
712 | + response = __cpaint_transformer.e4x_conversion(httpobj.responseText); | ||
713 | + break; | ||
714 | + | ||
715 | + case 'JSON': | ||
716 | + response = __cpaint_transformer.json_conversion(httpobj.responseText); | ||
717 | + break; | ||
718 | + | ||
719 | + default: | ||
720 | + debug('invalid response type \'' + response_type + '\'', 0); | ||
721 | + } | ||
722 | + | ||
723 | + // call client side callback | ||
724 | + if (response != null | ||
725 | + && typeof client_callback == 'function') { | ||
726 | + client_callback(response, httpobj.responseText); | ||
727 | + } | ||
728 | + // remove ourselves from the stack | ||
729 | + remove_from_stack(); | ||
730 | + | ||
731 | + } else if (httpobj.readyState == 4 | ||
732 | + && httpobj.status != 200) { | ||
733 | + // HTTP error of some kind | ||
734 | + debug('invalid HTTP response code \'' + Number(httpobj.status) + '\'', 0); | ||
735 | + //client_callback("", "erro"); | ||
736 | + } | ||
737 | + } | ||
738 | + | ||
739 | + /** | ||
740 | + * removes an entry from the stack | ||
741 | + * | ||
742 | + * @access protected | ||
743 | + * @return void | ||
744 | + */ | ||
745 | + var remove_from_stack = function() { | ||
746 | + // remove only if everything is okay and we're not configured as persistent connection | ||
747 | + if (typeof stack_id == 'number' | ||
748 | + && __cpaint_stack[stack_id] | ||
749 | + && config['persistent_connection'] == false) { | ||
750 | + | ||
751 | + __cpaint_stack[stack_id] = null; | ||
752 | + } | ||
753 | + } | ||
754 | + | ||
755 | + /** | ||
756 | + * debug method | ||
757 | + * | ||
758 | + * @access protected | ||
759 | + * @param string message the message to debug | ||
760 | + * @param integer debug_level debug level at which the message appears | ||
761 | + * @return void | ||
762 | + */ | ||
763 | + var debug = function(message, debug_level) { | ||
764 | + var prefix = '[CPAINT Debug] '; | ||
765 | + | ||
766 | + if (config['debugging'] < 1) { | ||
767 | + prefix = '[CPAINT Error] '; | ||
768 | + } | ||
769 | + | ||
770 | + if (config['debugging'] >= debug_level) { | ||
771 | + alert(prefix + message); | ||
772 | + } | ||
773 | + if (message.search("error") > 1){client_callback("", message);} | ||
774 | + } | ||
775 | +} | ||
776 | + | ||
777 | +/** | ||
778 | +* CPAINT transformation object | ||
779 | +* | ||
780 | +* @package CPAINT | ||
781 | +* @access public | ||
782 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
783 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
784 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
785 | +*/ | ||
786 | +function cpaint_transformer() { | ||
787 | + | ||
788 | + /** | ||
789 | + * will take a XMLHttpObject and generate a JavaScript | ||
790 | + * object structure from it. | ||
791 | + * | ||
792 | + * is internally called by cpaint_call.callback() if necessary. | ||
793 | + * will call cpaint_call.create_object_structure() to create nested object structures. | ||
794 | + * | ||
795 | + * @access public | ||
796 | + * @param object xml_document a XMLHttpObject | ||
797 | + * @return object | ||
798 | + */ | ||
799 | + this.object_conversion = function(xml_document) { | ||
800 | + var return_value = new cpaint_result_object(); | ||
801 | + var i = 0; | ||
802 | + var firstNodeName = ''; | ||
803 | + | ||
804 | + if (typeof xml_document == 'object' | ||
805 | + && xml_document != null) { | ||
806 | + | ||
807 | + // find the first element node - for MSIE the <?xml?> node is the very first... | ||
808 | + for (i = 0; i < xml_document.childNodes.length; i++) { | ||
809 | + | ||
810 | + if (xml_document.childNodes[i].nodeType == 1) { | ||
811 | + firstNodeName = xml_document.childNodes[i].nodeName; | ||
812 | + break; | ||
813 | + } | ||
814 | + } | ||
815 | + | ||
816 | + var ajax_response = xml_document.getElementsByTagName(firstNodeName); | ||
817 | + | ||
818 | + return_value[firstNodeName] = new Array(); | ||
819 | + | ||
820 | + for (i = 0; i < ajax_response.length; i++) { | ||
821 | + var tmp_node = create_object_structure(ajax_response[i]); | ||
822 | + tmp_node.id = ajax_response[i].getAttribute('id') | ||
823 | + return_value[firstNodeName].push(tmp_node); | ||
824 | + } | ||
825 | + | ||
826 | + } else { | ||
827 | + debug('received invalid XML response', 0); | ||
828 | + } | ||
829 | + | ||
830 | + return return_value; | ||
831 | + } | ||
832 | + | ||
833 | + /** | ||
834 | + * performs the necessary conversions for the XML response type | ||
835 | + * | ||
836 | + * @access public | ||
837 | + * @param object xml_document a XMLHttpObject | ||
838 | + * @return object | ||
839 | + */ | ||
840 | + this.xml_conversion = function(xml_document) { | ||
841 | + return xml_document; | ||
842 | + } | ||
843 | + | ||
844 | + /** | ||
845 | + * performs the necessary conversions for the TEXT response type | ||
846 | + * | ||
847 | + * @access public | ||
848 | + * @param string text the response text | ||
849 | + * @return string | ||
850 | + */ | ||
851 | + this.text_conversion = function(text) { | ||
852 | + return decode(text); | ||
853 | + } | ||
854 | + | ||
855 | + /** | ||
856 | + * performs the necessary conversions for the E4X response type | ||
857 | + * | ||
858 | + * @access public | ||
859 | + * @param string text the response text | ||
860 | + * @return string | ||
861 | + */ | ||
862 | + this.e4x_conversion = function(text) { | ||
863 | + // remove <?xml ?>tag | ||
864 | + text = text.replace(/^\<\?xml[^>]+\>/, ''); | ||
865 | + return new XML(text); | ||
866 | + } | ||
867 | + | ||
868 | + /** | ||
869 | + * performs the necessary conversions for the JSON response type | ||
870 | + * | ||
871 | + * @access public | ||
872 | + * @param string text the response text | ||
873 | + * @return string | ||
874 | + */ | ||
875 | + this.json_conversion = function(text) { | ||
876 | + return JSON.parse(text); | ||
877 | + } | ||
878 | + | ||
879 | + /** | ||
880 | + * this method takes a HTML / XML node object and creates a | ||
881 | + * JavaScript object structure from it. | ||
882 | + * | ||
883 | + * @access public | ||
884 | + * @param object stream a node in the XML structure | ||
885 | + * @return object | ||
886 | + */ | ||
887 | + var create_object_structure = function(stream) { | ||
888 | + var return_value = new cpaint_result_object(); | ||
889 | + var node_name = ''; | ||
890 | + var i = 0; | ||
891 | + var attrib = 0; | ||
892 | + | ||
893 | + if (stream.hasChildNodes() == true) { | ||
894 | + for (i = 0; i < stream.childNodes.length; i++) { | ||
895 | + | ||
896 | + node_name = stream.childNodes[i].nodeName; | ||
897 | + node_name = node_name.replace(/[^a-zA-Z0-9_]*/g, ''); | ||
898 | + | ||
899 | + // reset / create subnode | ||
900 | + if (typeof return_value[node_name] != 'object') { | ||
901 | + return_value[node_name] = new Array(); | ||
902 | + } | ||
903 | + | ||
904 | + if (stream.childNodes[i].nodeType == 1) { | ||
905 | + var tmp_node = create_object_structure(stream.childNodes[i]); | ||
906 | + | ||
907 | + for (attrib = 0; attrib < stream.childNodes[i].attributes.length; attrib++) { | ||
908 | + tmp_node.set_attribute(stream.childNodes[i].attributes[attrib].nodeName, stream.childNodes[i].attributes[attrib].nodeValue); | ||
909 | + } | ||
910 | + | ||
911 | + return_value[node_name].push(tmp_node); | ||
912 | + | ||
913 | + } else if (stream.childNodes[i].nodeType == 3) { | ||
914 | + return_value.data = decode(String(stream.firstChild.data)); | ||
915 | + } | ||
916 | + } | ||
917 | + } | ||
918 | + | ||
919 | + return return_value; | ||
920 | + } | ||
921 | + | ||
922 | + /** | ||
923 | + * converts an encoded text back to viewable characters. | ||
924 | + * | ||
925 | + * @access public | ||
926 | + * @param string rawtext raw text as provided by the backend | ||
927 | + * @return mixed | ||
928 | + */ | ||
929 | + var decode = function(rawtext) { | ||
930 | + var plaintext = ''; | ||
931 | + var i = 0; | ||
932 | + var c1 = 0; | ||
933 | + var c2 = 0; | ||
934 | + var c3 = 0; | ||
935 | + var u = 0; | ||
936 | + var t = 0; | ||
937 | + | ||
938 | + // remove special JavaScript encoded non-printable characters | ||
939 | + while (i < rawtext.length) { | ||
940 | + if (rawtext.charAt(i) == '\\' | ||
941 | + && rawtext.charAt(i + 1) == 'u') { | ||
942 | + | ||
943 | + u = 0; | ||
944 | + | ||
945 | + for (j = 2; j < 6; j += 1) { | ||
946 | + t = parseInt(rawtext.charAt(i + j), 16); | ||
947 | + | ||
948 | + if (!isFinite(t)) { | ||
949 | + break; | ||
950 | + } | ||
951 | + u = u * 16 + t; | ||
952 | + } | ||
953 | + | ||
954 | + plaintext += String.fromCharCode(u); | ||
955 | + i += 6; | ||
956 | + | ||
957 | + } else { | ||
958 | + plaintext += rawtext.charAt(i); | ||
959 | + i++; | ||
960 | + } | ||
961 | + } | ||
962 | + | ||
963 | + // convert numeric data to number type | ||
964 | + if (plaintext != '' | ||
965 | + && plaintext.search(/^\s+$/g) == -1 | ||
966 | + && !isNaN(plaintext) | ||
967 | + && isFinite(plaintext)) { | ||
968 | + | ||
969 | + plaintext = Number(plaintext); | ||
970 | + } | ||
971 | + | ||
972 | + return plaintext; | ||
973 | + } | ||
974 | +} | ||
975 | + | ||
976 | +/** | ||
977 | +* this is the basic prototype for a cpaint node object | ||
978 | +* as used in cpaint_call.parse_ajax_xml() | ||
979 | +* | ||
980 | +* @package CPAINT | ||
981 | +* @access public | ||
982 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
983 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
984 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
985 | +*/ | ||
986 | +function cpaint_result_object() { | ||
987 | + this.id = 0; | ||
988 | + this.data = ''; | ||
989 | + var __attributes = new Array(); | ||
990 | + | ||
991 | + /** | ||
992 | + * Returns a subnode with the given type and id. | ||
993 | + * | ||
994 | + * @access public | ||
995 | + * @param string type The type of the subnode. Equivalent to the XML tag name. | ||
996 | + * @param string id The id of the subnode. Equivalent to the XML tag names id attribute. | ||
997 | + * @return object | ||
998 | + */ | ||
999 | + this.find_item_by_id = function() { | ||
1000 | + var return_value = null; | ||
1001 | + var type = arguments[0]; | ||
1002 | + var id = arguments[1]; | ||
1003 | + var i = 0; | ||
1004 | + | ||
1005 | + if (this[type]) { | ||
1006 | + | ||
1007 | + for (i = 0; i < this[type].length; i++) { | ||
1008 | + | ||
1009 | + if (this[type][i].get_attribute('id') == id) { | ||
1010 | + return_value = this[type][i]; | ||
1011 | + break; | ||
1012 | + } | ||
1013 | + } | ||
1014 | + } | ||
1015 | + | ||
1016 | + return return_value; | ||
1017 | + } | ||
1018 | + | ||
1019 | + /** | ||
1020 | + * retrieves the value of an attribute. | ||
1021 | + * | ||
1022 | + * @access public | ||
1023 | + * @param string name name of the attribute | ||
1024 | + * @return mixed | ||
1025 | + */ | ||
1026 | + this.get_attribute = function() { | ||
1027 | + var return_value = null; | ||
1028 | + var id = arguments[0]; | ||
1029 | + | ||
1030 | + if (typeof __attributes[id] != 'undefined') { | ||
1031 | + return_value = __attributes[id]; | ||
1032 | + } | ||
1033 | + | ||
1034 | + return return_value; | ||
1035 | + } | ||
1036 | + | ||
1037 | + /** | ||
1038 | + * assigns a value to an attribute. | ||
1039 | + * | ||
1040 | + * if that attribute does not exist it will be created. | ||
1041 | + * | ||
1042 | + * @access public | ||
1043 | + * @param string name name of the attribute | ||
1044 | + * @param string value value of the attribute | ||
1045 | + * @return void | ||
1046 | + */ | ||
1047 | + this.set_attribute = function() { | ||
1048 | + __attributes[arguments[0]] = arguments[1]; | ||
1049 | + } | ||
1050 | +} | ||
1051 | + | ||
1052 | + | ||
1053 | +/* | ||
1054 | +Copyright (c) 2005 JSON.org | ||
1055 | + | ||
1056 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
1057 | +of this software and associated documentation files (the "Software"), to deal | ||
1058 | +in the Software without restriction, including without limitation the rights | ||
1059 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
1060 | +copies of the Software, and to permit persons to whom the Software is | ||
1061 | +furnished to do so, subject to the following conditions: | ||
1062 | + | ||
1063 | +The Software shall be used for Good, not Evil. | ||
1064 | + | ||
1065 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
1066 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
1067 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
1068 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
1069 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
1070 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
1071 | +SOFTWARE. | ||
1072 | +*/ | ||
1073 | + | ||
1074 | +Array.prototype.______array = '______array'; | ||
1075 | + | ||
1076 | +var JSON = { | ||
1077 | + org: 'http://www.JSON.org', | ||
1078 | + copyright: '(c)2005 JSON.org', | ||
1079 | + license: 'http://www.crockford.com/JSON/license.html', | ||
1080 | + | ||
1081 | + stringify: function (arg) { | ||
1082 | + var c, i, l, s = '', v; | ||
1083 | + var numeric = true; | ||
1084 | + | ||
1085 | + switch (typeof arg) { | ||
1086 | + case 'object': | ||
1087 | + if (arg) { | ||
1088 | + if (arg.______array == '______array') { | ||
1089 | + // do a test whether all array keys are numeric | ||
1090 | + for (i in arg) { | ||
1091 | + if (i != '______array' | ||
1092 | + && (isNaN(i) | ||
1093 | + || !isFinite(i))) { | ||
1094 | + numeric = false; | ||
1095 | + break; | ||
1096 | + } | ||
1097 | + } | ||
1098 | + | ||
1099 | + if (numeric == true) { | ||
1100 | + for (i = 0; i < arg.length; ++i) { | ||
1101 | + if (typeof arg[i] != 'undefined') { | ||
1102 | + v = this.stringify(arg[i]); | ||
1103 | + if (s) { | ||
1104 | + s += ','; | ||
1105 | + } | ||
1106 | + s += v; | ||
1107 | + } else { | ||
1108 | + s += ',null'; | ||
1109 | + } | ||
1110 | + } | ||
1111 | + return '[' + s + ']'; | ||
1112 | + } else { | ||
1113 | + for (i in arg) { | ||
1114 | + if (i != '______array') { | ||
1115 | + v = arg[i]; | ||
1116 | + if (typeof v != 'undefined' && typeof v != 'function') { | ||
1117 | + v = this.stringify(v); | ||
1118 | + if (s) { | ||
1119 | + s += ','; | ||
1120 | + } | ||
1121 | + s += this.stringify(i) + ':' + v; | ||
1122 | + } | ||
1123 | + } | ||
1124 | + } | ||
1125 | + // return as object | ||
1126 | + return '{' + s + '}'; | ||
1127 | + } | ||
1128 | + } else if (typeof arg.toString != 'undefined') { | ||
1129 | + for (i in arg) { | ||
1130 | + v = arg[i]; | ||
1131 | + if (typeof v != 'undefined' && typeof v != 'function') { | ||
1132 | + v = this.stringify(v); | ||
1133 | + if (s) { | ||
1134 | + s += ','; | ||
1135 | + } | ||
1136 | + s += this.stringify(i) + ':' + v; | ||
1137 | + } | ||
1138 | + } | ||
1139 | + return '{' + s + '}'; | ||
1140 | + } | ||
1141 | + } | ||
1142 | + return 'null'; | ||
1143 | + case 'number': | ||
1144 | + return isFinite(arg) ? String(arg) : 'null'; | ||
1145 | + case 'string': | ||
1146 | + l = arg.length; | ||
1147 | + s = '"'; | ||
1148 | + for (i = 0; i < l; i += 1) { | ||
1149 | + c = arg.charAt(i); | ||
1150 | + if (c >= ' ') { | ||
1151 | + if (c == '\\' || c == '"') { | ||
1152 | + s += '\\'; | ||
1153 | + } | ||
1154 | + s += c; | ||
1155 | + } else { | ||
1156 | + switch (c) { | ||
1157 | + case '\b': | ||
1158 | + s += '\\b'; | ||
1159 | + break; | ||
1160 | + case '\f': | ||
1161 | + s += '\\f'; | ||
1162 | + break; | ||
1163 | + case '\n': | ||
1164 | + s += '\\n'; | ||
1165 | + break; | ||
1166 | + case '\r': | ||
1167 | + s += '\\r'; | ||
1168 | + break; | ||
1169 | + case '\t': | ||
1170 | + s += '\\t'; | ||
1171 | + break; | ||
1172 | + default: | ||
1173 | + c = c.charCodeAt(); | ||
1174 | + s += '\\u00' + Math.floor(c / 16).toString(16) + | ||
1175 | + (c % 16).toString(16); | ||
1176 | + } | ||
1177 | + } | ||
1178 | + } | ||
1179 | + return s + '"'; | ||
1180 | + case 'boolean': | ||
1181 | + return String(arg); | ||
1182 | + default: | ||
1183 | + return 'null'; | ||
1184 | + } | ||
1185 | + }, | ||
1186 | + parse: function (text) { | ||
1187 | + var at = 0; | ||
1188 | + var ch = ' '; | ||
1189 | + | ||
1190 | + function error(m) { | ||
1191 | + throw { | ||
1192 | + name: 'JSONError', | ||
1193 | + message: m, | ||
1194 | + at: at - 1, | ||
1195 | + text: text | ||
1196 | + }; | ||
1197 | + } | ||
1198 | + | ||
1199 | + function next() { | ||
1200 | + ch = text.charAt(at); | ||
1201 | + at += 1; | ||
1202 | + return ch; | ||
1203 | + } | ||
1204 | + | ||
1205 | + function white() { | ||
1206 | + while (ch != '' && ch <= ' ') { | ||
1207 | + next(); | ||
1208 | + } | ||
1209 | + } | ||
1210 | + | ||
1211 | + function str() { | ||
1212 | + var i, s = '', t, u; | ||
1213 | + | ||
1214 | + if (ch == '"') { | ||
1215 | +outer: while (next()) { | ||
1216 | + if (ch == '"') { | ||
1217 | + next(); | ||
1218 | + return s; | ||
1219 | + } else if (ch == '\\') { | ||
1220 | + switch (next()) { | ||
1221 | + case 'b': | ||
1222 | + s += '\b'; | ||
1223 | + break; | ||
1224 | + case 'f': | ||
1225 | + s += '\f'; | ||
1226 | + break; | ||
1227 | + case 'n': | ||
1228 | + s += '\n'; | ||
1229 | + break; | ||
1230 | + case 'r': | ||
1231 | + s += '\r'; | ||
1232 | + break; | ||
1233 | + case 't': | ||
1234 | + s += '\t'; | ||
1235 | + break; | ||
1236 | + case 'u': | ||
1237 | + u = 0; | ||
1238 | + for (i = 0; i < 4; i += 1) { | ||
1239 | + t = parseInt(next(), 16); | ||
1240 | + if (!isFinite(t)) { | ||
1241 | + break outer; | ||
1242 | + } | ||
1243 | + u = u * 16 + t; | ||
1244 | + } | ||
1245 | + s += String.fromCharCode(u); | ||
1246 | + break; | ||
1247 | + default: | ||
1248 | + s += ch; | ||
1249 | + } | ||
1250 | + } else { | ||
1251 | + s += ch; | ||
1252 | + } | ||
1253 | + } | ||
1254 | + } | ||
1255 | + error("Bad string"); | ||
1256 | + } | ||
1257 | + | ||
1258 | + function arr() { | ||
1259 | + var a = []; | ||
1260 | + | ||
1261 | + if (ch == '[') { | ||
1262 | + next(); | ||
1263 | + white(); | ||
1264 | + if (ch == ']') { | ||
1265 | + next(); | ||
1266 | + return a; | ||
1267 | + } | ||
1268 | + while (ch) { | ||
1269 | + a.push(val()); | ||
1270 | + white(); | ||
1271 | + if (ch == ']') { | ||
1272 | + next(); | ||
1273 | + return a; | ||
1274 | + } else if (ch != ',') { | ||
1275 | + break; | ||
1276 | + } | ||
1277 | + next(); | ||
1278 | + white(); | ||
1279 | + } | ||
1280 | + } | ||
1281 | + error("Bad array"); | ||
1282 | + } | ||
1283 | + | ||
1284 | + function obj() { | ||
1285 | + var k, o = {}; | ||
1286 | + | ||
1287 | + if (ch == '{') { | ||
1288 | + next(); | ||
1289 | + white(); | ||
1290 | + if (ch == '}') { | ||
1291 | + next(); | ||
1292 | + return o; | ||
1293 | + } | ||
1294 | + while (ch) { | ||
1295 | + k = str(); | ||
1296 | + white(); | ||
1297 | + if (ch != ':') { | ||
1298 | + break; | ||
1299 | + } | ||
1300 | + next(); | ||
1301 | + o[k] = val(); | ||
1302 | + white(); | ||
1303 | + if (ch == '}') { | ||
1304 | + next(); | ||
1305 | + return o; | ||
1306 | + } else if (ch != ',') { | ||
1307 | + break; | ||
1308 | + } | ||
1309 | + next(); | ||
1310 | + white(); | ||
1311 | + } | ||
1312 | + } | ||
1313 | + error("Bad object"); | ||
1314 | + } | ||
1315 | + | ||
1316 | + function assoc() { | ||
1317 | + var k, a = []; | ||
1318 | + | ||
1319 | + if (ch == '<') { | ||
1320 | + next(); | ||
1321 | + white(); | ||
1322 | + if (ch == '>') { | ||
1323 | + next(); | ||
1324 | + return a; | ||
1325 | + } | ||
1326 | + while (ch) { | ||
1327 | + k = str(); | ||
1328 | + white(); | ||
1329 | + if (ch != ':') { | ||
1330 | + break; | ||
1331 | + } | ||
1332 | + next(); | ||
1333 | + a[k] = val(); | ||
1334 | + white(); | ||
1335 | + if (ch == '>') { | ||
1336 | + next(); | ||
1337 | + return a; | ||
1338 | + } else if (ch != ',') { | ||
1339 | + break; | ||
1340 | + } | ||
1341 | + next(); | ||
1342 | + white(); | ||
1343 | + } | ||
1344 | + } | ||
1345 | + error("Bad associative array"); | ||
1346 | + } | ||
1347 | + | ||
1348 | + function num() { | ||
1349 | + var n = '', v; | ||
1350 | + if (ch == '-') { | ||
1351 | + n = '-'; | ||
1352 | + next(); | ||
1353 | + } | ||
1354 | + while (ch >= '0' && ch <= '9') { | ||
1355 | + n += ch; | ||
1356 | + next(); | ||
1357 | + } | ||
1358 | + if (ch == '.') { | ||
1359 | + n += '.'; | ||
1360 | + while (next() && ch >= '0' && ch <= '9') { | ||
1361 | + n += ch; | ||
1362 | + } | ||
1363 | + } | ||
1364 | + if (ch == 'e' || ch == 'E') { | ||
1365 | + n += 'e'; | ||
1366 | + next(); | ||
1367 | + if (ch == '-' || ch == '+') { | ||
1368 | + n += ch; | ||
1369 | + next(); | ||
1370 | + } | ||
1371 | + while (ch >= '0' && ch <= '9') { | ||
1372 | + n += ch; | ||
1373 | + next(); | ||
1374 | + } | ||
1375 | + } | ||
1376 | + v = +n; | ||
1377 | + if (!isFinite(v)) { | ||
1378 | + error("Bad number"); | ||
1379 | + } else { | ||
1380 | + return v; | ||
1381 | + } | ||
1382 | + } | ||
1383 | + | ||
1384 | + function word() { | ||
1385 | + switch (ch) { | ||
1386 | + case 't': | ||
1387 | + if (next() == 'r' && next() == 'u' && next() == 'e') { | ||
1388 | + next(); | ||
1389 | + return true; | ||
1390 | + } | ||
1391 | + break; | ||
1392 | + case 'f': | ||
1393 | + if (next() == 'a' && next() == 'l' && next() == 's' && | ||
1394 | + next() == 'e') { | ||
1395 | + next(); | ||
1396 | + return false; | ||
1397 | + } | ||
1398 | + break; | ||
1399 | + case 'n': | ||
1400 | + if (next() == 'u' && next() == 'l' && next() == 'l') { | ||
1401 | + next(); | ||
1402 | + return null; | ||
1403 | + } | ||
1404 | + break; | ||
1405 | + } | ||
1406 | + error("Syntax error"); | ||
1407 | + } | ||
1408 | + | ||
1409 | + function val() { | ||
1410 | + white(); | ||
1411 | + switch (ch) { | ||
1412 | + case '{': | ||
1413 | + return obj(); | ||
1414 | + case '[': | ||
1415 | + return arr(); | ||
1416 | + case '<': | ||
1417 | + return assoc(); | ||
1418 | + case '"': | ||
1419 | + return str(); | ||
1420 | + case '-': | ||
1421 | + return num(); | ||
1422 | + default: | ||
1423 | + return ch >= '0' && ch <= '9' ? num() : word(); | ||
1424 | + } | ||
1425 | + } | ||
1426 | + | ||
1427 | + return val(); | ||
1428 | + } | ||
1429 | +}; |
@@ -0,0 +1,941 @@ | @@ -0,0 +1,941 @@ | ||
1 | +<?php | ||
2 | +/** | ||
3 | +* CPAINT - Cross-Platform Asynchronous INterface Toolkit | ||
4 | +* | ||
5 | +* http://sf.net/projects/cpaint | ||
6 | +* | ||
7 | +* released under the terms of the LGPL | ||
8 | +* see http://www.fsf.org/licensing/licenses/lgpl.txt for details | ||
9 | +* | ||
10 | +* @package CPAINT | ||
11 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
12 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
13 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
14 | +* @version 2.0.3 | ||
15 | +*/ | ||
16 | + | ||
17 | +//---- includes ---------------------------------------------------------------- | ||
18 | + /** | ||
19 | + * @include JSON | ||
20 | + */ | ||
21 | + require_once(dirname(__FILE__) . '/json.php'); | ||
22 | + | ||
23 | + /** | ||
24 | + * @include config | ||
25 | + */ | ||
26 | + require_once("cpaint2.config.php"); | ||
27 | + | ||
28 | +//---- variables --------------------------------------------------------------- | ||
29 | + $GLOBALS['__cpaint_json'] = new JSON(); | ||
30 | + | ||
31 | +//---- error reporting --------------------------------------------------------- | ||
32 | + error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING); | ||
33 | + | ||
34 | +//---- classes ----------------------------------------------------------------- | ||
35 | + /** | ||
36 | + * cpaint base class. | ||
37 | + * | ||
38 | + * @package CPAINT | ||
39 | + * @access public | ||
40 | + * @author Paul Sullivan <wiley14@gmail.com> | ||
41 | + * @author Dominique Stender <dstender@st-webdevelopment.de> | ||
42 | + * @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
43 | + * @version 2.0.3 | ||
44 | + */ | ||
45 | + class cpaint { | ||
46 | + /** | ||
47 | + * version number | ||
48 | + * | ||
49 | + * @access private | ||
50 | + * @var string $version | ||
51 | + */ | ||
52 | + var $version = '2.0.3'; | ||
53 | + | ||
54 | + /** | ||
55 | + * response type. | ||
56 | + * | ||
57 | + * @access protected | ||
58 | + * @var string $response_type | ||
59 | + */ | ||
60 | + var $response_type; | ||
61 | + | ||
62 | + /** | ||
63 | + * the basenode ajaxResponse. | ||
64 | + * | ||
65 | + * @access protected | ||
66 | + * @var object $basenode | ||
67 | + */ | ||
68 | + var $basenode; | ||
69 | + | ||
70 | + /** | ||
71 | + * list of registered methods available through the CPAINT API | ||
72 | + * | ||
73 | + * @access protected | ||
74 | + * @var array $api_functions | ||
75 | + */ | ||
76 | + var $api_functions; | ||
77 | + | ||
78 | + /** | ||
79 | + * list of registered complex types used in the CPAINT API | ||
80 | + * | ||
81 | + * @access protected | ||
82 | + * @var array $api_datatypes | ||
83 | + */ | ||
84 | + var $api_datatypes; | ||
85 | + | ||
86 | + /** | ||
87 | + * whether or not the CPAINT API generates a WSDL when called with ?wsdl querystring | ||
88 | + * | ||
89 | + * @access private | ||
90 | + * @var boolean $use_wsdl | ||
91 | + */ | ||
92 | + var $use_wsdl; | ||
93 | + | ||
94 | + /** | ||
95 | + * PHP4 constructor. | ||
96 | + * | ||
97 | + * @access public | ||
98 | + * @return void | ||
99 | + */ | ||
100 | + function cpaint() { | ||
101 | + $this->__construct(); | ||
102 | + } | ||
103 | + | ||
104 | + /** | ||
105 | + * PHP 5 constructor. | ||
106 | + * | ||
107 | + * @access public | ||
108 | + * @return void | ||
109 | + * @todo -o"Dominique Stender" -ccpaint implement a better debugging | ||
110 | + */ | ||
111 | + function __construct() { | ||
112 | + // initialize properties | ||
113 | + $this->basenode = new cpaint_node(); | ||
114 | + $this->basenode->set_name('ajaxResponse'); | ||
115 | + $this->basenode->set_attribute('id', ''); | ||
116 | + $this->basenode->set_encoding('UTF-8'); | ||
117 | + | ||
118 | + $this->response_type = 'TEXT'; | ||
119 | + $this->api_functions = array(); | ||
120 | + $this->api_datatypes = array(); | ||
121 | + $this->use_wsdl = true; | ||
122 | + | ||
123 | + $this->complex_type(array( | ||
124 | + 'name' => 'cpaintResponseType', | ||
125 | + 'type' => 'restriction', // (restriction|complex|list) | ||
126 | + 'base_type' => 'string', // scalar type of all values, e.g. 'string', for type = (restriction|list) only | ||
127 | + 'values' => array( // for type = 'restriction' only: list of allowed values | ||
128 | + 'XML', 'TEXT', 'OBJECT', 'E4X', 'JSON', | ||
129 | + ), | ||
130 | + ) | ||
131 | + ); | ||
132 | + $this->complex_type(array( | ||
133 | + 'name' => 'cpaintDebugLevel', | ||
134 | + 'type' => 'restriction', | ||
135 | + 'base_type' => 'long', | ||
136 | + 'values' => array( | ||
137 | + -1, 0, 1, 2 | ||
138 | + ), | ||
139 | + ) | ||
140 | + ); | ||
141 | + $this->complex_type(array( | ||
142 | + 'name' => 'cpaintDebugMessage', | ||
143 | + 'type' => 'list', | ||
144 | + 'base_type' => 'string', | ||
145 | + ) | ||
146 | + ); | ||
147 | + | ||
148 | + $this->complex_type(array( | ||
149 | + 'name' => 'cpaintRequestHead', | ||
150 | + 'type' => 'complex', | ||
151 | + 'struct' => array( | ||
152 | + 0 => array('name' => 'functionName', 'type' => 'string'), | ||
153 | + 1 => array('name' => 'responseType', 'type' => 'cpaintResponseType'), | ||
154 | + 2 => array('name' => 'debugLevel', 'type' => 'cpaintDebugLevel'), | ||
155 | + ), | ||
156 | + ) | ||
157 | + ); | ||
158 | + | ||
159 | + $this->complex_type(array( | ||
160 | + 'name' => 'cpaintResponseHead', | ||
161 | + 'type' => 'complex', | ||
162 | + 'struct' => array( | ||
163 | + 0 => array('name' => 'success', 'type' => 'boolean'), | ||
164 | + 1 => array('name' => 'debugger', 'type' => 'cpaintDebugMessage'), | ||
165 | + ), | ||
166 | + ) | ||
167 | + ); | ||
168 | + | ||
169 | + // determine response type | ||
170 | + if (isset($_REQUEST['cpaint_response_type'])) { | ||
171 | + $this->response_type = htmlentities(strip_tags(strtoupper((string) $_REQUEST['cpaint_response_type']))); | ||
172 | + } // end: if | ||
173 | + } | ||
174 | + | ||
175 | + /** | ||
176 | + * calls the user function responsible for this specific call. | ||
177 | + * | ||
178 | + * @access public | ||
179 | + * @param string $input_encoding input data character encoding, default is UTF-8 | ||
180 | + * @return void | ||
181 | + */ | ||
182 | + function start($input_encoding = 'UTF-8') { | ||
183 | + $user_function = ''; | ||
184 | + $arguments = array(); | ||
185 | + | ||
186 | + // work only if there is no API version request | ||
187 | + if (!isset($_REQUEST['api_query']) | ||
188 | + && !isset($_REQUEST['wsdl'])) { | ||
189 | + $this->basenode->set_encoding($input_encoding); | ||
190 | + | ||
191 | + if ($_REQUEST['cpaint_function'] != '') { | ||
192 | + $user_function = $_REQUEST['cpaint_function']; | ||
193 | + if(@$_REQUEST['cpaint_argument']) | ||
194 | + $arguments = $_REQUEST['cpaint_argument']; | ||
195 | + else | ||
196 | + $arguments = array(); | ||
197 | + } | ||
198 | + | ||
199 | + // perform character conversion on every argument | ||
200 | + foreach ($arguments as $key => $value) { | ||
201 | + | ||
202 | + if (get_magic_quotes_gpc() == true) { | ||
203 | + $value = stripslashes($value); | ||
204 | + } // end: if | ||
205 | + | ||
206 | + // convert from JSON string | ||
207 | + $arguments[$key] = $GLOBALS['__cpaint_json']->parse($value); | ||
208 | + } // end: foreach | ||
209 | + | ||
210 | + $arguments = cpaint_transformer::decode_array($arguments, $this->basenode->get_encoding()); | ||
211 | + | ||
212 | + if (is_array($this->api_functions[$user_function]) | ||
213 | + && is_callable($this->api_functions[$user_function]['call'])) { | ||
214 | + // a valid API function is to be called | ||
215 | + call_user_func_array($this->api_functions[$user_function]['call'], $arguments); | ||
216 | + } else if ($user_function != '') { | ||
217 | + // desired function is not registered as API function | ||
218 | + $this->basenode->set_data('[CPAINT] A function name was passed that is not allowed to execute on this server.'); | ||
219 | + } | ||
220 | + } // end: if | ||
221 | + } | ||
222 | + | ||
223 | + /** | ||
224 | + * generates and prints the response based on response type supplied by the frontend. | ||
225 | + * | ||
226 | + * @access public | ||
227 | + * @return void | ||
228 | + */ | ||
229 | + function return_data() { | ||
230 | + // send appropriate headers to avoid caching | ||
231 | + header('Expires: Fri, 14 Mar 1980 20:53:00 GMT'); | ||
232 | + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); | ||
233 | + header('Cache-Control: no-cache, must-revalidate'); | ||
234 | + header('Pragma: no-cache'); | ||
235 | + header('X-Powered-By: CPAINT v' . $this->version . '/PHP v' . phpversion()); | ||
236 | + | ||
237 | + // work only if there is no API version request | ||
238 | + | ||
239 | + if (!isset($_REQUEST['api_query']) | ||
240 | + && !isset($_REQUEST['wsdl'])) { | ||
241 | + // trigger generation of response | ||
242 | + switch (trim($this->response_type)) { | ||
243 | + | ||
244 | + case 'TEXT': | ||
245 | + header('Content-type: text/plain; charset=' . cpaint_transformer::find_output_charset($this->basenode->get_encoding())); | ||
246 | + echo cpaint_transformer::toString($this->basenode); | ||
247 | + break; | ||
248 | + | ||
249 | + case 'JSON': | ||
250 | + header('Content-type: text/plain; charset=' . cpaint_transformer::find_output_charset($this->basenode->get_encoding())); | ||
251 | + echo cpaint_transformer::toJSON($this->basenode); | ||
252 | + break; | ||
253 | + | ||
254 | + case 'OBJECT': | ||
255 | + case 'E4X': | ||
256 | + case 'XML': | ||
257 | + header('Content-type: text/xml; charset=' . cpaint_transformer::find_output_charset($this->basenode->get_encoding())); | ||
258 | + echo '<?xml version="1.0" encoding="' . cpaint_transformer::find_output_charset($this->basenode->get_encoding()) . '"?>' | ||
259 | + . cpaint_transformer::toXML($this->basenode); | ||
260 | + break; | ||
261 | + | ||
262 | + default: | ||
263 | + echo 'ERROR: invalid response type \'' . $this->response_type . '\''; | ||
264 | + } // end: switch | ||
265 | + | ||
266 | + } elseif (isset($_REQUEST['api_query'])) { | ||
267 | + // API version request | ||
268 | + header('Content-type: text/plain; charset=ISO-8859-1'); | ||
269 | + echo 'CPAINT v' . $this->version . '/PHP v' . phpversion(); | ||
270 | + | ||
271 | + } elseif ($this->use_wsdl == true | ||
272 | + && isset($_REQUEST['wsdl'])) { | ||
273 | + | ||
274 | + if (is_file(dirname(__FILE__) . '/cpaint2.wsdl.php') | ||
275 | + && is_readable(dirname(__FILE__) . '/cpaint2.wsdl.php')) { | ||
276 | + | ||
277 | + require_once(dirname(__FILE__) . '/cpaint2.wsdl.php'); | ||
278 | + | ||
279 | + if (class_exists('cpaint_wsdl')) { | ||
280 | + // create new instance of WSDL library | ||
281 | + $wsdl = new cpaint_wsdl(); | ||
282 | + | ||
283 | + // build WSDL info | ||
284 | + header('Content-type: text/xml; charset=UTF-8'); | ||
285 | + echo $wsdl->generate($this->api_functions, $this->api_datatypes); | ||
286 | + | ||
287 | + } else { | ||
288 | + header('Content-type: text/plain; charset=ISO-8859-1'); | ||
289 | + echo 'WSDL generator is unavailable'; | ||
290 | + } // end: if | ||
291 | + | ||
292 | + } else { | ||
293 | + header('Content-type: text/plain; charset=ISO-8859-1'); | ||
294 | + echo 'WSDL generator is unavailable'; | ||
295 | + } // end: if | ||
296 | + } // end: if | ||
297 | + } | ||
298 | + | ||
299 | + /** | ||
300 | + * registers a new function or method as part of the CPAINT API | ||
301 | + * | ||
302 | + * @access public | ||
303 | + * @param mixed $func function name, array(&$object, 'function_name') or array('class', 'function_name') | ||
304 | + * @param array $input function input parameters (not yet used by CPAINT and subject to change) | ||
305 | + * @param array $output function output format (not yed used by CPAINT and subject to change) | ||
306 | + * @param string $comment description of the functionality | ||
307 | + * @return boolean | ||
308 | + */ | ||
309 | + function register($func, $input = array(), $output = array(), $comment = '') { | ||
310 | + $return_value = false; | ||
311 | + $input = (array) $input; | ||
312 | + $output = (array) $output; | ||
313 | + $comment = (string) $comment; | ||
314 | + | ||
315 | + if (is_array($func) | ||
316 | + && (is_object($func[0]) || is_string($func[0])) | ||
317 | + && is_string($func[1]) | ||
318 | + && is_callable($func)) { | ||
319 | + | ||
320 | + // calling a method of an object | ||
321 | + $this->api_functions[$func[1]] = array( | ||
322 | + 'call' => $func, | ||
323 | + 'input' => $input, | ||
324 | + 'output' => $output, | ||
325 | + 'comment' => $comment, | ||
326 | + ); | ||
327 | + $return_value = true; | ||
328 | + | ||
329 | + } elseif (is_string($func)) { | ||
330 | + // calling a standalone function | ||
331 | + $this->api_functions[$func] = array( | ||
332 | + 'call' => $func, | ||
333 | + 'input' => $input, | ||
334 | + 'output' => $output, | ||
335 | + 'comment' => $comment, | ||
336 | + ); | ||
337 | + $return_value = true; | ||
338 | + } // end: if | ||
339 | + | ||
340 | + return $return_value; | ||
341 | + } | ||
342 | + | ||
343 | + | ||
344 | + | ||
345 | + /** | ||
346 | + * unregisters a function that is currently part of the CPAINT API. | ||
347 | + * | ||
348 | + * proves useful when the same set of functions is to be used in the | ||
349 | + * frontend and in some kind of administration environment. you might | ||
350 | + * want to unregister a few (admin) functions for the frontend in this | ||
351 | + * case. | ||
352 | + * | ||
353 | + * @access public | ||
354 | + * @param string $func function name | ||
355 | + * @return boolean | ||
356 | + */ | ||
357 | + function unregister($func) { | ||
358 | + $retval = false; | ||
359 | + | ||
360 | + if (is_array($this->api_functions[$func])) { | ||
361 | + unset($this->api_functions[$func]); | ||
362 | + } // end: if | ||
363 | + | ||
364 | + return $retval; | ||
365 | + } | ||
366 | + | ||
367 | + | ||
368 | + | ||
369 | + /** | ||
370 | + * registers a complex data type | ||
371 | + * | ||
372 | + * @access public | ||
373 | + * @param array $schema schema definition for the complex type | ||
374 | + * @return boolean | ||
375 | + */ | ||
376 | + function complex_type($schema) { | ||
377 | + $return_value = false; | ||
378 | + $schema = (array) $schema; | ||
379 | + | ||
380 | + if ($schema['name'] != '' | ||
381 | + && in_array($schema['type'], array('restriction', 'complex', 'list'))) { | ||
382 | + | ||
383 | + $this->api_datatypes[] = $schema; | ||
384 | + $return_value = true; | ||
385 | + } // end: if | ||
386 | + | ||
387 | + return $return_value; | ||
388 | + } | ||
389 | + | ||
390 | + /** | ||
391 | + * switches the generation of WSDL on/off. default is on | ||
392 | + * | ||
393 | + * @access public | ||
394 | + * @param boolean $state state of WSDL generation | ||
395 | + * @return void | ||
396 | + */ | ||
397 | + function use_wsdl($state) { | ||
398 | + $this->use_wsdl = (boolean) $state; | ||
399 | + } | ||
400 | + | ||
401 | + /** | ||
402 | + * adds a new subnode to the basenode. | ||
403 | + * | ||
404 | + * will return a reference to it for further processing. | ||
405 | + * | ||
406 | + * @access public | ||
407 | + * @param string $nodename name of the new node | ||
408 | + * @param string $id id of the new node | ||
409 | + * @return object | ||
410 | + */ | ||
411 | + function &add_node($nodename, $id = '') { | ||
412 | + return $this->basenode->add_node($nodename, $id); | ||
413 | + } | ||
414 | + | ||
415 | + /** | ||
416 | + * assigns textual data to the basenode. | ||
417 | + * | ||
418 | + * @access public | ||
419 | + * @param mixed $data data to assign to this node | ||
420 | + * @return void | ||
421 | + */ | ||
422 | + function set_data($data) { | ||
423 | + $this->basenode->set_data($data); | ||
424 | + } | ||
425 | + | ||
426 | + /** | ||
427 | + * returns the data assigned to the basenode. | ||
428 | + * | ||
429 | + * @access public | ||
430 | + * @return mixed | ||
431 | + */ | ||
432 | + function get_data() { | ||
433 | + return $this->basenode->get_data(); | ||
434 | + } | ||
435 | + | ||
436 | + /** | ||
437 | + * sets the id property of the basenode. | ||
438 | + * | ||
439 | + * @deprecated deprecated since version 2.0.0 | ||
440 | + * @access public | ||
441 | + * @param string $id the id | ||
442 | + * @return void | ||
443 | + */ | ||
444 | + function set_id($id) { | ||
445 | + $this->basenode->set_attribute('id', $id); | ||
446 | + } | ||
447 | + | ||
448 | + /** | ||
449 | + * gets the id property of the basenode. | ||
450 | + * | ||
451 | + * @deprecated deprecated since version 2.0.0 | ||
452 | + * @access public | ||
453 | + * @return string | ||
454 | + */ | ||
455 | + function get_id() { | ||
456 | + return $this->basenode->get_attribute('id'); | ||
457 | + } | ||
458 | + | ||
459 | + /** | ||
460 | + * adds a new attribute to the basenode. | ||
461 | + * | ||
462 | + * @access public | ||
463 | + * @param string $name attribute name | ||
464 | + * @param mixed $value attribute value | ||
465 | + * @return void | ||
466 | + */ | ||
467 | + function set_attribute($name, $value) { | ||
468 | + $this->basenode->set_attribute($name, $value); | ||
469 | + } | ||
470 | + | ||
471 | + /** | ||
472 | + * retrieves an attribute of the basenode by name. | ||
473 | + * | ||
474 | + * @access public | ||
475 | + * @param string $name attribute name | ||
476 | + * @return string | ||
477 | + */ | ||
478 | + function get_attribute($name) { | ||
479 | + return $this->basenode->get_attributes($name); | ||
480 | + } | ||
481 | + | ||
482 | + /** | ||
483 | + * set name property of the basenode. | ||
484 | + * | ||
485 | + * @access public | ||
486 | + * @param string $name the name | ||
487 | + * @return void | ||
488 | + */ | ||
489 | + function set_name($name) { | ||
490 | + $this->basenode->set_name($name); | ||
491 | + } | ||
492 | + | ||
493 | + /** | ||
494 | + * get name property of the basenode. | ||
495 | + * | ||
496 | + * @access public | ||
497 | + * @return string | ||
498 | + */ | ||
499 | + function get_name() { | ||
500 | + return $this->basenode->get_name(); | ||
501 | + } | ||
502 | + | ||
503 | + | ||
504 | + | ||
505 | + /** | ||
506 | + * returns the response type as requested by the client | ||
507 | + * | ||
508 | + * @access public | ||
509 | + * @return string | ||
510 | + */ | ||
511 | + function get_response_type() { | ||
512 | + return $this->response_type; | ||
513 | + } | ||
514 | + | ||
515 | + } | ||
516 | + | ||
517 | + /** | ||
518 | + * a cpaint data node. Data nodes are used to build up the response. | ||
519 | + * | ||
520 | + * @package CPAINT | ||
521 | + * @access public | ||
522 | + * @author Dominique Stender <dstender@st-webdevelopment.de> | ||
523 | + * @copyright 2005-2006 (Dominique Stender); All rights reserved | ||
524 | + * @version 2.0.3 | ||
525 | + */ | ||
526 | + class cpaint_node { | ||
527 | + /** | ||
528 | + * array of subnodes. | ||
529 | + * | ||
530 | + * @access public | ||
531 | + * @var array $composites | ||
532 | + */ | ||
533 | + var $composites; | ||
534 | + | ||
535 | + /** | ||
536 | + * node attributes. | ||
537 | + * | ||
538 | + * @access public | ||
539 | + * @var array $attributes | ||
540 | + */ | ||
541 | + var $attributes; | ||
542 | + | ||
543 | + /** | ||
544 | + * name of this node. | ||
545 | + * | ||
546 | + * @access public | ||
547 | + * @var string $nodename | ||
548 | + */ | ||
549 | + var $nodename; | ||
550 | + | ||
551 | + /** | ||
552 | + * textual data of this node. | ||
553 | + * | ||
554 | + * @access public | ||
555 | + * @var string $data | ||
556 | + */ | ||
557 | + var $data; | ||
558 | + | ||
559 | + /** | ||
560 | + * character encoding for input data | ||
561 | + * | ||
562 | + * @access private | ||
563 | + * @var $input_encoding | ||
564 | + */ | ||
565 | + var $input_encoding; | ||
566 | + | ||
567 | + /** | ||
568 | + * PHP4 constructor. | ||
569 | + * | ||
570 | + * @package CPAINT | ||
571 | + * @access public | ||
572 | + * @return void | ||
573 | + */ | ||
574 | + function cpaint_node() { | ||
575 | + $this->__construct(); | ||
576 | + } | ||
577 | + | ||
578 | + /** | ||
579 | + * PHP 5 constructor. | ||
580 | + * | ||
581 | + * @access public | ||
582 | + * @return void | ||
583 | + */ | ||
584 | + function __construct() { | ||
585 | + // initialize properties | ||
586 | + $this->composites = array(); | ||
587 | + $this->attributes = array(); | ||
588 | + $this->data = ''; | ||
589 | + | ||
590 | + $this->set_encoding('UTF-8'); | ||
591 | + $this->set_name(''); | ||
592 | + $this->set_attribute('id', ''); | ||
593 | + } | ||
594 | + | ||
595 | + /** | ||
596 | + * adds a new subnode to this node. | ||
597 | + * | ||
598 | + * will return a reference to it for further processing. | ||
599 | + * | ||
600 | + * @access public | ||
601 | + * @param string $nodename name of the new node | ||
602 | + * @param string $id id of the new node | ||
603 | + * @return object | ||
604 | + */ | ||
605 | + function &add_node($nodename, $id = '') { | ||
606 | + $composites = count($this->composites); | ||
607 | + | ||
608 | + // create new node | ||
609 | + $this->composites[$composites] =& new cpaint_node(); | ||
610 | + $this->composites[$composites]->set_name($nodename); | ||
611 | + $this->composites[$composites]->set_attribute('id', $id); | ||
612 | + $this->composites[$composites]->set_encoding($this->input_encoding); | ||
613 | + | ||
614 | + return $this->composites[$composites]; | ||
615 | + } | ||
616 | + | ||
617 | + /** | ||
618 | + * assigns textual data to this node. | ||
619 | + * | ||
620 | + * @access public | ||
621 | + * @param mixed $data data to assign to this node | ||
622 | + * @return void | ||
623 | + */ | ||
624 | + function set_data($data) { | ||
625 | + $this->data = $data; | ||
626 | + } | ||
627 | + | ||
628 | + /** | ||
629 | + * returns the textual data assigned to this node. | ||
630 | + * | ||
631 | + * @access public | ||
632 | + * @return mixed | ||
633 | + */ | ||
634 | + function get_data() { | ||
635 | + return $this->data; | ||
636 | + } | ||
637 | + | ||
638 | + /** | ||
639 | + * sets the id property of this node. | ||
640 | + * | ||
641 | + * @deprecated deprecated since version 2.0.0 | ||
642 | + * @access public | ||
643 | + * @param string id the id | ||
644 | + * @return void | ||
645 | + */ | ||
646 | + function set_id($id) { | ||
647 | + if ($id != '') { | ||
648 | + $this->set_attribute('id', $id); | ||
649 | + } // end: if | ||
650 | + } | ||
651 | + | ||
652 | + /** | ||
653 | + * returns the id property if this node. | ||
654 | + * | ||
655 | + * @deprecated deprecated since version 2.0.0 | ||
656 | + * @access public | ||
657 | + * @return string | ||
658 | + */ | ||
659 | + function get_id() { | ||
660 | + return $this->get_attribute('id'); | ||
661 | + } | ||
662 | + | ||
663 | + /** | ||
664 | + * adds a new attribute to this node. | ||
665 | + * | ||
666 | + * @access public | ||
667 | + * @param string $name attribute name | ||
668 | + * @param mixed $value attribute value | ||
669 | + * @return void | ||
670 | + */ | ||
671 | + function set_attribute($name, $value) { | ||
672 | + $this->attributes[$name] = (string) $value; | ||
673 | + } | ||
674 | + | ||
675 | + /** | ||
676 | + * retrieves an attribute by name. | ||
677 | + * | ||
678 | + * @access public | ||
679 | + * @param string $name attribute name | ||
680 | + * @return string | ||
681 | + */ | ||
682 | + function get_attribute($name) { | ||
683 | + return $this->attributes[$name]; | ||
684 | + } | ||
685 | + | ||
686 | + /** | ||
687 | + * set name property. | ||
688 | + * | ||
689 | + * @access public | ||
690 | + * @param string $name the name | ||
691 | + * @return void | ||
692 | + */ | ||
693 | + function set_name($name) { | ||
694 | + $this->nodename = (string) $name; | ||
695 | + } | ||
696 | + | ||
697 | + /** | ||
698 | + * get name property. | ||
699 | + * | ||
700 | + * @access public | ||
701 | + * @return string | ||
702 | + */ | ||
703 | + function get_name() { | ||
704 | + return $this->nodename; | ||
705 | + } | ||
706 | + | ||
707 | + /** | ||
708 | + * sets the character encoding for this node | ||
709 | + * | ||
710 | + * @access public | ||
711 | + * @param string $encoding character encoding | ||
712 | + * @return void | ||
713 | + */ | ||
714 | + function set_encoding($encoding) { | ||
715 | + $this->input_encoding = strtoupper((string) $encoding); | ||
716 | + } | ||
717 | + | ||
718 | + /** | ||
719 | + * returns the character encoding for this node | ||
720 | + * | ||
721 | + * @access public | ||
722 | + * @return string | ||
723 | + */ | ||
724 | + function get_encoding() { | ||
725 | + return $this->input_encoding; | ||
726 | + } | ||
727 | + } | ||
728 | + | ||
729 | + /** | ||
730 | + * static class of output transformers. | ||
731 | + * | ||
732 | + * @package CPAINT | ||
733 | + * @access public | ||
734 | + * @author Dominique Stender <dstender@st-webdevelopment.de> | ||
735 | + * @copyright 2003-2006 (Dominique Stender); All rights reserved | ||
736 | + * @version 2.0.3 | ||
737 | + */ | ||
738 | + class cpaint_transformer { | ||
739 | + /** | ||
740 | + * toString method, used to generate response of type TEXT. | ||
741 | + * will perform character transformation according to parameters. | ||
742 | + * | ||
743 | + * @access public | ||
744 | + * @param object $node a cpaint_node object | ||
745 | + * @return string | ||
746 | + */ | ||
747 | + function toString(&$node) { | ||
748 | + $return_value = ''; | ||
749 | + | ||
750 | + foreach ($node->composites as $composite) { | ||
751 | + $return_value .= cpaint_transformer::toString($composite); | ||
752 | + } | ||
753 | + | ||
754 | + $return_value .= cpaint_transformer::encode($node->get_data(), $node->get_encoding()); | ||
755 | + | ||
756 | + return $return_value; | ||
757 | + } | ||
758 | + | ||
759 | + /** | ||
760 | + * XML response generator. | ||
761 | + * will perform character transformation according to parameters. | ||
762 | + * | ||
763 | + * @access public | ||
764 | + * @param object $node a cpaint_node object | ||
765 | + * @return string | ||
766 | + */ | ||
767 | + function toXML(&$node) { | ||
768 | + $return_value = '<' . $node->get_name(); | ||
769 | + | ||
770 | + // handle attributes | ||
771 | + foreach ($node->attributes as $name => $value) { | ||
772 | + if ($value != '') { | ||
773 | + $return_value .= ' ' . $name . '="' . $node->get_attribute($name) . '"'; | ||
774 | + } | ||
775 | + } // end: foreach | ||
776 | + | ||
777 | + $return_value .= '>'; | ||
778 | + | ||
779 | + // handle subnodes | ||
780 | + foreach ($node->composites as $composite) { | ||
781 | + $return_value .= cpaint_transformer::toXML($composite); | ||
782 | + } | ||
783 | + | ||
784 | + $return_value .= cpaint_transformer::encode($node->get_data(), $node->get_encoding()) | ||
785 | + . '</' . $node->get_name() . '>'; | ||
786 | + | ||
787 | + return $return_value; | ||
788 | + } | ||
789 | + | ||
790 | + /** | ||
791 | + * JSON response generator. | ||
792 | + * will perform character transformation according to parameters. | ||
793 | + * | ||
794 | + * @access public | ||
795 | + * @param object $node a cpaint_node object | ||
796 | + * @return string | ||
797 | + */ | ||
798 | + function toJSON($node) { | ||
799 | + $return_value = ''; | ||
800 | + $JSON_node = new stdClass(); | ||
801 | + | ||
802 | + // handle attributes | ||
803 | + $JSON_node->attributes = $node->attributes; | ||
804 | + | ||
805 | + // handle subnodes | ||
806 | + foreach ($node->composites as $composite) { | ||
807 | + | ||
808 | + if (!is_array($JSON_node->{$composite->nodename})) { | ||
809 | + $JSON_node->{$composite->nodename} = array(); | ||
810 | + } // end: if | ||
811 | + | ||
812 | + // we need to parse the JSON object again to avoid multiple encoding | ||
813 | + $JSON_node->{$composite->nodename}[] = $GLOBALS['__cpaint_json']->parse(cpaint_transformer::toJSON($composite)); | ||
814 | + } | ||
815 | + | ||
816 | + // handle data | ||
817 | + $JSON_node->data = $node->data; | ||
818 | + | ||
819 | + return $GLOBALS['__cpaint_json']->stringify($JSON_node); | ||
820 | + } | ||
821 | + | ||
822 | + /** | ||
823 | + * performs conversion to JavaScript-safe UTF-8 characters | ||
824 | + * | ||
825 | + * @access public | ||
826 | + * @param string $data data to convert | ||
827 | + * @param string $encoding character encoding | ||
828 | + * @return string | ||
829 | + */ | ||
830 | + function encode($data, $encoding) { | ||
831 | + // convert string | ||
832 | + if (function_exists('iconv')) { | ||
833 | + // iconv is by far the most flexible approach, try this first | ||
834 | + $return_value = iconv($encoding, 'UTF-8', $data); | ||
835 | + | ||
836 | + } elseif ($encoding == 'ISO-8859-1') { | ||
837 | + // for ISO-8859-1 we can use utf8-encode() | ||
838 | + $return_value = utf8_encode($data); | ||
839 | + | ||
840 | + } else { | ||
841 | + // give up. if UTF-8 data was supplied everything is fine! | ||
842 | + $return_value = $data; | ||
843 | + } /* end: if */ | ||
844 | + | ||
845 | + // now encode non-printable characters | ||
846 | + for ($i = 0; $i < 32; $i++) { | ||
847 | + $return_value = str_replace(chr($i), '\u00' . sprintf('%02x', $i), $return_value); | ||
848 | + } // end: for | ||
849 | + | ||
850 | + // encode <, >, and & respectively for XML sanity | ||
851 | + $return_value = str_replace(chr(0x26), '\u0026', $return_value); | ||
852 | + $return_value = str_replace(chr(0x3c), '\u003c', $return_value); | ||
853 | + $return_value = str_replace(chr(0x3e), '\u003e', $return_value); | ||
854 | + | ||
855 | + return $return_value; | ||
856 | + } | ||
857 | + | ||
858 | + /** | ||
859 | + * performs conversion from JavaScript encodeURIComponent() string (UTF-8) to | ||
860 | + * the charset in use. | ||
861 | + * | ||
862 | + * @access public | ||
863 | + * @param string $data data to convert | ||
864 | + * @param string $encoding character encoding | ||
865 | + * @return string | ||
866 | + */ | ||
867 | + function decode($data, $encoding) { | ||
868 | + // convert string | ||
869 | + | ||
870 | + if (is_string($data)) { | ||
871 | + if (function_exists('iconv')) { | ||
872 | + // iconv is by far the most flexible approach, try this first | ||
873 | + $return_value = iconv('UTF-8', $encoding, $data); | ||
874 | + | ||
875 | + } elseif ($encoding == 'ISO-8859-1') { | ||
876 | + // for ISO-8859-1 we can use utf8-decode() | ||
877 | + $return_value = utf8_decode($data); | ||
878 | + | ||
879 | + } else { | ||
880 | + // give up. if data was supplied in the correct format everything is fine! | ||
881 | + $return_value = $data; | ||
882 | + } // end: if | ||
883 | + | ||
884 | + } else { | ||
885 | + // non-string value | ||
886 | + $return_value = $data; | ||
887 | + } // end: if | ||
888 | + | ||
889 | + return $return_value; | ||
890 | + } | ||
891 | + | ||
892 | + /** | ||
893 | + * decodes a (nested) array of data from UTF-8 into the configured character set | ||
894 | + * | ||
895 | + * @access public | ||
896 | + * @param array $data data to convert | ||
897 | + * @param string $encoding character encoding | ||
898 | + * @return array | ||
899 | + */ | ||
900 | + function decode_array($data, $encoding) { | ||
901 | + $return_value = array(); | ||
902 | + | ||
903 | + foreach ($data as $key => $value) { | ||
904 | + | ||
905 | + if (!is_array($value)) { | ||
906 | + $return_value[$key] = cpaint_transformer::decode($value, $encoding); | ||
907 | + | ||
908 | + } else { | ||
909 | + $return_value[$key] = cpaint_transformer::decode_array($value, $encoding); | ||
910 | + } | ||
911 | + } | ||
912 | + | ||
913 | + return $return_value; | ||
914 | + } | ||
915 | + | ||
916 | + /** | ||
917 | + * determines the output character set | ||
918 | + * based on input character set | ||
919 | + * | ||
920 | + * @access public | ||
921 | + * @param string $encoding character encoding | ||
922 | + * @return string | ||
923 | + */ | ||
924 | + function find_output_charset($encoding) { | ||
925 | + $return_value = 'UTF-8'; | ||
926 | + | ||
927 | + if (function_exists('iconv') | ||
928 | + || $encoding == 'UTF-8' | ||
929 | + || $encoding == 'ISO-8859-1') { | ||
930 | + | ||
931 | + $return_value = 'UTF-8'; | ||
932 | + | ||
933 | + } else { | ||
934 | + $return_value = $encoding; | ||
935 | + } // end: if | ||
936 | + | ||
937 | + return $return_value; | ||
938 | + } | ||
939 | + } | ||
940 | + | ||
941 | +?> | ||
0 | \ No newline at end of file | 942 | \ No newline at end of file |
@@ -0,0 +1,117 @@ | @@ -0,0 +1,117 @@ | ||
1 | +<?php | ||
2 | +/** | ||
3 | +* CPAINT (Cross-Platform Asynchronous INterface Toolkit) | ||
4 | +* | ||
5 | +* http://sf.net/projects/cpaint | ||
6 | +* | ||
7 | +* released under the terms of the GPL | ||
8 | +* see http://www.fsf.org/licensing/licenses/gpl.txt for details | ||
9 | +* | ||
10 | +* | ||
11 | +* proxy script to pass request on to remote servers | ||
12 | +* | ||
13 | +* @package CPAINT | ||
14 | +* @author Paul Sullivan <wiley14@gmail.com> | ||
15 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
16 | +* @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint | ||
17 | +* @version 2.0.3 | ||
18 | +*/ | ||
19 | + | ||
20 | +//---- includes ---------------------------------------------------------------- | ||
21 | + /** | ||
22 | + * @include config | ||
23 | + */ | ||
24 | + require_once("cpaint2.config.php"); | ||
25 | + | ||
26 | +//---- main code --------------------------------------------------------------- | ||
27 | + | ||
28 | + error_reporting (E_ALL ^ E_NOTICE ^ E_WARNING); | ||
29 | + set_time_limit(0); | ||
30 | + | ||
31 | + if ($_REQUEST['cpaint_remote_url'] != "") { | ||
32 | + $cp_remote_url = urldecode($_REQUEST['cpaint_remote_url']); | ||
33 | + $cp_remote_method = urldecode($_REQUEST['cpaint_remote_method']); | ||
34 | + $cp_remote_query = urldecode($_REQUEST['cpaint_remote_query']); | ||
35 | + $cp_response_type = strtoupper($_REQUEST['cpaint_response_type']); | ||
36 | + } | ||
37 | + | ||
38 | + // propagate XML header if necessary | ||
39 | + if ($cp_response_type == 'XML' | ||
40 | + || $cp_response_type == 'OBJECT') { | ||
41 | + header("Content-type: text/xml"); | ||
42 | + } | ||
43 | + | ||
44 | + // transfer mode specifics | ||
45 | + if ($cp_remote_method == 'GET') { | ||
46 | + $cp_remote_url .= '?' . $cp_remote_query; | ||
47 | + $cp_request_body = ''; | ||
48 | + | ||
49 | + // prepare parameters | ||
50 | + $url_parts = parse_url($cp_remote_url); | ||
51 | + | ||
52 | + // build basic header | ||
53 | + $cp_request_header = 'GET ' . $url_parts['path'] . '?' . str_replace(' ', '+', $url_parts['query']) . " HTTP/1.0\r\n" | ||
54 | + . "Host: " . $url_parts['host'] . "\r\n"; | ||
55 | + | ||
56 | + } elseif ($cp_remote_method == 'POST') { | ||
57 | + $cp_request_body = '&' . $cp_remote_query; | ||
58 | + | ||
59 | + // prepare parameters | ||
60 | + $url_parts = parse_url($cp_remote_url); | ||
61 | + | ||
62 | + // check against whitelist | ||
63 | + if ($cpaint2_config["proxy.security.use_whitelist"] == true) { | ||
64 | + $url_allowed = false; | ||
65 | + foreach($cpaint2_proxy_whitelist as $whitelistURL) { | ||
66 | + $whiteList_parts = parse_url("http://" . $whitelistURL); | ||
67 | + $url_parts_temp = parse_url("http://" . $cp_remote_url); | ||
68 | + if (array_key_exists("path", $whiteList_parts)) { | ||
69 | + if ((strtolower($whiteList_parts["path"]) == strtolower($url_parts_temp["path"])) && (strtolower($whiteList_parts["host"]) == strtolower($url_parts_temp["host"]))) $url_allowed = true; | ||
70 | + } else { // no path, check only host | ||
71 | + if (strtolower($whiteList_parts["host"]) == strtolower($url_parts_temp["host"])) $url_allowed = true; | ||
72 | + } | ||
73 | + } | ||
74 | + if ($url_allowed == false) die("[CPAINT] The host or script cannot be accessed through this proxy."); | ||
75 | + } | ||
76 | + | ||
77 | + // build basic header | ||
78 | + $cp_request_header = 'POST ' . $url_parts['path'] . " HTTP/1.0\r\n" | ||
79 | + . "Host: " . $url_parts['host'] . "\r\n" | ||
80 | + . "Content-Type: application/x-www-form-urlencoded\r\n"; | ||
81 | + } | ||
82 | + | ||
83 | + // add port if none exists | ||
84 | + if (!isset($url_parts['port'])) { | ||
85 | + $url_parts['port'] = 80; | ||
86 | + } | ||
87 | + | ||
88 | + // add content-length header | ||
89 | + $cp_request_header .= "Content-Length: " . strlen($cp_request_body) . "\r\n"; | ||
90 | + | ||
91 | + // add authentication to header if necessary | ||
92 | + if ($url_parts['user'] != '') { | ||
93 | + $cp_request_header .= 'Authorization: Basic ' . base64_encode($url_parts['user'] . ':' . $url_parts['pass']) . "\r\n"; | ||
94 | + } | ||
95 | + | ||
96 | + // open connection | ||
97 | + $cp_socket = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr, 10); | ||
98 | + | ||
99 | + if ($cp_socket !== false) { | ||
100 | + // send headers | ||
101 | + @fwrite($cp_socket, $cp_request_header . "\r\n\r\n"); | ||
102 | + | ||
103 | + // send body if necessary | ||
104 | + if ($cp_request_body != '') { | ||
105 | + @fwrite($cp_socket, $cp_request_body . "\r\n"); | ||
106 | + } | ||
107 | + | ||
108 | + while (!feof($cp_socket)) { | ||
109 | + $http_data = $http_data . fgets($cp_socket); | ||
110 | + } | ||
111 | + | ||
112 | + list($http_headers, $http_body) = split("\r\n\r\n", $http_data, 2); | ||
113 | + echo($http_body); | ||
114 | + @fclose($cp_socket); | ||
115 | + } | ||
116 | + | ||
117 | +?> | ||
0 | \ No newline at end of file | 118 | \ No newline at end of file |
@@ -0,0 +1,580 @@ | @@ -0,0 +1,580 @@ | ||
1 | +<?php | ||
2 | +/** | ||
3 | +* The content of this file is (c) 2003-2005 digital media center GmbH | ||
4 | +* All rights reserved | ||
5 | +* | ||
6 | +* a JSON parser / generator. | ||
7 | +* implemented as 100% compatible port of the original JSON parser | ||
8 | +* by Douglas Crockford on http://www.JSON.org. | ||
9 | +* | ||
10 | +* @package JSON | ||
11 | +* @access public | ||
12 | +* @copyright Copyright (c) 2005-2006 Dominique Stender - http://sf.net/projects/cpaint | ||
13 | +* @license http://www.crockford.com/JSON/license.html | ||
14 | +* @author Dominique Stender <dstender@st-webdevelopment.de> | ||
15 | +* @version 1.0.1 | ||
16 | +*/ | ||
17 | + | ||
18 | + | ||
19 | + | ||
20 | + /** | ||
21 | + * a JSON parser / generator | ||
22 | + * | ||
23 | + * @access public | ||
24 | + * @author Dominique Stender <dst@dmc.de> | ||
25 | + * @version 1.0.1 | ||
26 | + */ | ||
27 | + class JSON { | ||
28 | + /** | ||
29 | + * line counter | ||
30 | + * | ||
31 | + * @access private | ||
32 | + * @var integer $at | ||
33 | + */ | ||
34 | + var $at = 0; | ||
35 | + | ||
36 | + /** | ||
37 | + * | ||
38 | + * @access private | ||
39 | + * @var string $ch | ||
40 | + */ | ||
41 | + var $ch = ' '; | ||
42 | + | ||
43 | + /** | ||
44 | + * JSON representation | ||
45 | + * | ||
46 | + * @access private | ||
47 | + * @var string $text | ||
48 | + */ | ||
49 | + var $text = ''; | ||
50 | + | ||
51 | + /** | ||
52 | + * takes an arbitrary PHP data structure and generates a valid JSON representation from it | ||
53 | + * | ||
54 | + * @param mixed $arg an arbitrary PHP data structure | ||
55 | + * @access public | ||
56 | + * @return string | ||
57 | + * @version 1.0.1 fixed tests whether $s has content by using strlen(). this enables the user to use 0 as very first character | ||
58 | + */ | ||
59 | + function stringify($arg) { | ||
60 | + $returnValue = ''; | ||
61 | + $c = ''; | ||
62 | + $i = ''; | ||
63 | + $l = ''; | ||
64 | + $s = ''; | ||
65 | + $v = ''; | ||
66 | + $numeric = true; | ||
67 | + | ||
68 | + switch (gettype($arg)) { | ||
69 | + | ||
70 | + case 'array': | ||
71 | + // do a test whether all array keys are numeric | ||
72 | + foreach ($arg as $i => $v) { | ||
73 | + if (!is_numeric($i)) { | ||
74 | + $numeric = false; | ||
75 | + break; | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + if ($numeric) { | ||
80 | + | ||
81 | + foreach ($arg as $i => $v) { | ||
82 | + if (strlen($s) > 0) { | ||
83 | + $s .= ','; | ||
84 | + } | ||
85 | + | ||
86 | + $s .= $this->stringify($arg[$i]); | ||
87 | + } // end: foreach | ||
88 | + | ||
89 | + $returnValue = '[' . $s . ']'; | ||
90 | + | ||
91 | + } else { | ||
92 | + // associative array | ||
93 | + foreach ($arg as $i => $v) { | ||
94 | + if (strlen($s) > 0) { | ||
95 | + $s .= ','; | ||
96 | + } | ||
97 | + $s .= $this->stringify($i) . ':' . $this->stringify($arg[$i]); | ||
98 | + } | ||
99 | + // return as object | ||
100 | + $returnValue = '{' . $s . '}'; | ||
101 | + } | ||
102 | + break; | ||
103 | + | ||
104 | + case 'object': | ||
105 | + | ||
106 | + foreach (get_object_vars($arg) as $i => $v) { | ||
107 | + $v = $this->stringify($v); | ||
108 | + | ||
109 | + if (strlen($s) > 0) { | ||
110 | + $s .= ','; | ||
111 | + } | ||
112 | + | ||
113 | + $s .= $this->stringify($i) . ':' . $v; | ||
114 | + } | ||
115 | + | ||
116 | + $returnValue = '{' . $s . '}'; | ||
117 | + break; | ||
118 | + | ||
119 | + case 'integer': | ||
120 | + case 'double': | ||
121 | + $returnValue = is_numeric($arg) ? (string) $arg : 'null'; | ||
122 | + break; | ||
123 | + | ||
124 | + case 'string': | ||
125 | + $l = strlen($arg); | ||
126 | + $s = '"'; | ||
127 | + | ||
128 | + for ($i = 0; $i < $l; $i++) { | ||
129 | + $c = $arg{$i}; | ||
130 | + | ||
131 | + if (ord($c) >= ord(' ')) { | ||
132 | + | ||
133 | + if ($c == '\\' | ||
134 | + || $c == '"') { | ||
135 | + | ||
136 | + $s .= '\\'; | ||
137 | + } | ||
138 | + $s .= $c; | ||
139 | + | ||
140 | + } else { | ||
141 | + | ||
142 | + switch ($c) { | ||
143 | + | ||
144 | + case '\b': | ||
145 | + $s .= '\\b'; | ||
146 | + break; | ||
147 | + | ||
148 | + case '\f': | ||
149 | + $s .= '\\f'; | ||
150 | + break; | ||
151 | + | ||
152 | + case '\n': | ||
153 | + $s .= '\\n'; | ||
154 | + break; | ||
155 | + | ||
156 | + case '\r': | ||
157 | + $s .= '\\r'; | ||
158 | + break; | ||
159 | + | ||
160 | + case '\t': | ||
161 | + $s .= '\\t'; | ||
162 | + break; | ||
163 | + | ||
164 | + default: | ||
165 | + $s .= '\u00' . sprintf('%02x', ord($c)); | ||
166 | + } | ||
167 | + } | ||
168 | + } | ||
169 | + $returnValue = $s . '"'; | ||
170 | + break; | ||
171 | + | ||
172 | + case 'boolean': | ||
173 | + $returnValue = (string) $arg; | ||
174 | + break; | ||
175 | + | ||
176 | + default: | ||
177 | + $returnValue = 'null'; | ||
178 | + } | ||
179 | + | ||
180 | + return $returnValue; | ||
181 | + } | ||
182 | + | ||
183 | + | ||
184 | + /** | ||
185 | + * parses the given string into a PHP data structure | ||
186 | + * | ||
187 | + * @param string $text JSON data representation | ||
188 | + * @access public | ||
189 | + * @return mixed | ||
190 | + */ | ||
191 | + function parse($text) { | ||
192 | + $this->at = 0; | ||
193 | + $this->ch = ' '; | ||
194 | + $this->text = $text; | ||
195 | + | ||
196 | + return $this->val(); | ||
197 | + } | ||
198 | + | ||
199 | + /** | ||
200 | + * triggers a PHP_ERROR | ||
201 | + * | ||
202 | + * @access private | ||
203 | + * @param string $m error message | ||
204 | + * @return void | ||
205 | + */ | ||
206 | + function error($m) { | ||
207 | + trigger_error($m . ' at offset ' . $this->at . ': ' . $this->text, E_USER_ERROR); | ||
208 | + } | ||
209 | + | ||
210 | + /** | ||
211 | + * returns the next character of a JSON string | ||
212 | + * | ||
213 | + * @access private | ||
214 | + * @return string | ||
215 | + */ | ||
216 | + function next() { | ||
217 | + $this->ch = $this->text{$this->at}; | ||
218 | + $this->at++; | ||
219 | + return $this->ch; | ||
220 | + } | ||
221 | + | ||
222 | + /** | ||
223 | + * handles whitespace and comments | ||
224 | + * | ||
225 | + * @access private | ||
226 | + * @return void | ||
227 | + */ | ||
228 | + function white() { | ||
229 | + | ||
230 | + while ($this->ch != '' | ||
231 | + && ord($this->ch) <= ord(' ')) { | ||
232 | + | ||
233 | + $this->next(); | ||
234 | + } | ||
235 | + } | ||
236 | + | ||
237 | + /** | ||
238 | + * handles strings | ||
239 | + * | ||
240 | + * @access private | ||
241 | + * @return void | ||
242 | + */ | ||
243 | + function str() { | ||
244 | + $i = ''; | ||
245 | + $s = ''; | ||
246 | + $t = ''; | ||
247 | + $u = ''; | ||
248 | + | ||
249 | + if ($this->ch == '"') { | ||
250 | + | ||
251 | + while ($this->next() !== null) { | ||
252 | + | ||
253 | + if ($this->ch == '"') { | ||
254 | + $this->next(); | ||
255 | + return $s; | ||
256 | + | ||
257 | + } elseif ($this->ch == '\\') { | ||
258 | + | ||
259 | + switch ($this->next()) { | ||
260 | + case 'b': | ||
261 | + $s .= '\b'; | ||
262 | + break; | ||
263 | + | ||
264 | + case 'f': | ||
265 | + $s .= '\f'; | ||
266 | + break; | ||
267 | + | ||
268 | + case 'n': | ||
269 | + $s .= '\n'; | ||
270 | + break; | ||
271 | + | ||
272 | + case 'r': | ||
273 | + $s .= '\r'; | ||
274 | + break; | ||
275 | + | ||
276 | + case 't': | ||
277 | + $s .= '\t'; | ||
278 | + break; | ||
279 | + | ||
280 | + case 'u': | ||
281 | + $u = 0; | ||
282 | + | ||
283 | + for ($i = 0; $i < 4; $i += 1) { | ||
284 | + $t = (integer) sprintf('%01c', hexdec($this->next())); | ||
285 | + | ||
286 | + if (!is_numeric($t)) { | ||
287 | + break 2; | ||
288 | + } | ||
289 | + $u = $u * 16 + $t; | ||
290 | + } | ||
291 | + | ||
292 | + $s .= chr($u); | ||
293 | + break; | ||
294 | + | ||
295 | + default: | ||
296 | + $s .= $this->ch; | ||
297 | + } | ||
298 | + } else { | ||
299 | + $s .= $this->ch; | ||
300 | + } | ||
301 | + } | ||
302 | + } | ||
303 | + | ||
304 | + $this->error('Bad string'); | ||
305 | + } | ||
306 | + | ||
307 | + /** | ||
308 | + * handless arrays | ||
309 | + * | ||
310 | + * @access private | ||
311 | + * @return void | ||
312 | + */ | ||
313 | + function arr() { | ||
314 | + $a = array(); | ||
315 | + | ||
316 | + if ($this->ch == '[') { | ||
317 | + $this->next(); | ||
318 | + $this->white(); | ||
319 | + | ||
320 | + if ($this->ch == ']') { | ||
321 | + $this->next(); | ||
322 | + return $a; | ||
323 | + } | ||
324 | + | ||
325 | + while ($this->ch) { | ||
326 | + array_push($a, $this->val()); | ||
327 | + $this->white(); | ||
328 | + | ||
329 | + if ($this->ch == ']') { | ||
330 | + $this->next(); | ||
331 | + return $a; | ||
332 | + | ||
333 | + } elseif ($this->ch != ',') { | ||
334 | + break; | ||
335 | + } | ||
336 | + | ||
337 | + $this->next(); | ||
338 | + $this->white(); | ||
339 | + } | ||
340 | + | ||
341 | + $this->error('Bad array'); | ||
342 | + } | ||
343 | + } | ||
344 | + | ||
345 | + /** | ||
346 | + * handles objects | ||
347 | + * | ||
348 | + * @access public | ||
349 | + * @return void | ||
350 | + */ | ||
351 | + function obj() { | ||
352 | + $k = ''; | ||
353 | + $o = new stdClass(); | ||
354 | + | ||
355 | + if ($this->ch == '{') { | ||
356 | + $this->next(); | ||
357 | + $this->white(); | ||
358 | + | ||
359 | + if ($this->ch == '}') { | ||
360 | + $this->next(); | ||
361 | + return $o; | ||
362 | + } | ||
363 | + | ||
364 | + while ($this->ch) { | ||
365 | + $k = $this->str(); | ||
366 | + $this->white(); | ||
367 | + | ||
368 | + if ($this->ch != ':') { | ||
369 | + break; | ||
370 | + } | ||
371 | + | ||
372 | + $this->next(); | ||
373 | + $o->$k = $this->val(); | ||
374 | + $this->white(); | ||
375 | + | ||
376 | + if ($this->ch == '}') { | ||
377 | + $this->next(); | ||
378 | + return $o; | ||
379 | + | ||
380 | + } elseif ($this->ch != ',') { | ||
381 | + break; | ||
382 | + } | ||
383 | + | ||
384 | + $this->next(); | ||
385 | + $this->white(); | ||
386 | + } | ||
387 | + } | ||
388 | + | ||
389 | + $this->error('Bad object'); | ||
390 | + } | ||
391 | + | ||
392 | + /** | ||
393 | + * handles objects | ||
394 | + * | ||
395 | + * @access public | ||
396 | + * @return void | ||
397 | + */ | ||
398 | + function assoc() { | ||
399 | + $k = ''; | ||
400 | + $a = array(); | ||
401 | + | ||
402 | + if ($this->ch == '<') { | ||
403 | + $this->next(); | ||
404 | + $this->white(); | ||
405 | + | ||
406 | + if ($this->ch == '>') { | ||
407 | + $this->next(); | ||
408 | + return $a; | ||
409 | + } | ||
410 | + | ||
411 | + while ($this->ch) { | ||
412 | + $k = $this->str(); | ||
413 | + $this->white(); | ||
414 | + | ||
415 | + if ($this->ch != ':') { | ||
416 | + break; | ||
417 | + } | ||
418 | + | ||
419 | + $this->next(); | ||
420 | + $a[$k] = $this->val(); | ||
421 | + $this->white(); | ||
422 | + | ||
423 | + if ($this->ch == '>') { | ||
424 | + $this->next(); | ||
425 | + return $a; | ||
426 | + | ||
427 | + } elseif ($this->ch != ',') { | ||
428 | + break; | ||
429 | + } | ||
430 | + | ||
431 | + $this->next(); | ||
432 | + $this->white(); | ||
433 | + } | ||
434 | + } | ||
435 | + | ||
436 | + $this->error('Bad associative array'); | ||
437 | + } | ||
438 | + | ||
439 | + /** | ||
440 | + * handles numbers | ||
441 | + * | ||
442 | + * @access private | ||
443 | + * @return void | ||
444 | + */ | ||
445 | + function num() { | ||
446 | + $n = ''; | ||
447 | + $v = ''; | ||
448 | + | ||
449 | + if ($this->ch == '-') { | ||
450 | + $n = '-'; | ||
451 | + $this->next(); | ||
452 | + } | ||
453 | + | ||
454 | + while ($this->ch >= '0' | ||
455 | + && $this->ch <= '9') { | ||
456 | + | ||
457 | + $n .= $this->ch; | ||
458 | + $this->next(); | ||
459 | + } | ||
460 | + | ||
461 | + if ($this->ch == '.') { | ||
462 | + $n .= '.'; | ||
463 | + | ||
464 | + while ($this->next() | ||
465 | + && $this->ch >= '0' | ||
466 | + && $this->ch <= '9') { | ||
467 | + | ||
468 | + $n .= $this->ch; | ||
469 | + } | ||
470 | + } | ||
471 | + | ||
472 | + if ($this->ch == 'e' | ||
473 | + || $this->ch == 'E') { | ||
474 | + | ||
475 | + $n .= 'e'; | ||
476 | + $this->next(); | ||
477 | + | ||
478 | + if ($this->ch == '-' | ||
479 | + || $this->ch == '+') { | ||
480 | + | ||
481 | + $n .= $this->ch; | ||
482 | + $this->next(); | ||
483 | + } | ||
484 | + | ||
485 | + while ($this->ch >= '0' | ||
486 | + && $this->ch <= '9') { | ||
487 | + | ||
488 | + $n .= $this->ch; | ||
489 | + $this->next(); | ||
490 | + } | ||
491 | + } | ||
492 | + | ||
493 | + $v += $n; | ||
494 | + | ||
495 | + if (!is_numeric($v)) { | ||
496 | + $this->error('Bad number'); | ||
497 | + | ||
498 | + } else { | ||
499 | + return $v; | ||
500 | + } // end: if | ||
501 | + } | ||
502 | + | ||
503 | + /** | ||
504 | + * handles words | ||
505 | + * | ||
506 | + * @access private | ||
507 | + * @return mixed | ||
508 | + */ | ||
509 | + function word() { | ||
510 | + switch ($this->ch) { | ||
511 | + | ||
512 | + case 't': | ||
513 | + | ||
514 | + if ($this->next() == 'r' | ||
515 | + && $this->next() == 'u' | ||
516 | + && $this->next() == 'e') { | ||
517 | + | ||
518 | + $this->next(); | ||
519 | + return true; | ||
520 | + } | ||
521 | + break; | ||
522 | + | ||
523 | + case 'f': | ||
524 | + if ($this->next() == 'a' | ||
525 | + && $this->next() == 'l' | ||
526 | + && $this->next() == 's' | ||
527 | + && $this->next() == 'e') { | ||
528 | + | ||
529 | + $this->next(); | ||
530 | + return false; | ||
531 | + } | ||
532 | + break; | ||
533 | + | ||
534 | + case 'n': | ||
535 | + if ($this->next() == 'u' | ||
536 | + && $this->next() == 'l' | ||
537 | + && $this->next() == 'l') { | ||
538 | + | ||
539 | + $this->next(); | ||
540 | + return null; | ||
541 | + } | ||
542 | + break; | ||
543 | + } | ||
544 | + | ||
545 | + $this->error('Syntax error'); | ||
546 | + } | ||
547 | + | ||
548 | + /** | ||
549 | + * generic value handler | ||
550 | + * | ||
551 | + * @access private | ||
552 | + * @return mixed | ||
553 | + */ | ||
554 | + function val() { | ||
555 | + $this->white(); | ||
556 | + | ||
557 | + switch ($this->ch) { | ||
558 | + | ||
559 | + case '{': | ||
560 | + return $this->obj(); | ||
561 | + | ||
562 | + case '[': | ||
563 | + return $this->arr(); | ||
564 | + | ||
565 | + case '<': | ||
566 | + return $this->assoc(); | ||
567 | + | ||
568 | + case '"': | ||
569 | + return $this->str(); | ||
570 | + | ||
571 | + case '-': | ||
572 | + return $this->num(); | ||
573 | + | ||
574 | + default: | ||
575 | + return ($this->ch >= '0' && $this->ch <= '9') ? $this->num() : $this->word(); | ||
576 | + } | ||
577 | + } | ||
578 | + } | ||
579 | + | ||
580 | +?> | ||
0 | \ No newline at end of file | 581 | \ No newline at end of file |