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 @@ |
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 @@ |
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 | 664 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 352 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 414 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 @@ |
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 | 105 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 36 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 117 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 @@ |
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 | 942 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 118 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 | 581 | \ No newline at end of file | ... | ... |