Spam protection, AntiSpam, FireWall by CleanTalk - Version 5.4

Version Description

2015-04-27 = * Some interface and functionality changes in plugin settings page * Added counter for anti-spam statistics in admin bar

Download this release

Release Info

Developer Vlad Cleantalk
Plugin Icon 128x128 Spam protection, AntiSpam, FireWall by CleanTalk
Version 5.4
Comparing to
See all releases

Code changes from version 5.3 to 5.4

JSON.php CHANGED
@@ -1,806 +1,806 @@
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
- * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
55
- * @license http://www.opensource.org/licenses/bsd-license.php
56
- * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
57
- */
58
-
59
- /**
60
- * Marker constant for Services_JSON::decode(), used to flag stack state
61
- */
62
- define('SERVICES_JSON_SLICE', 1);
63
-
64
- /**
65
- * Marker constant for Services_JSON::decode(), used to flag stack state
66
- */
67
- define('SERVICES_JSON_IN_STR', 2);
68
-
69
- /**
70
- * Marker constant for Services_JSON::decode(), used to flag stack state
71
- */
72
- define('SERVICES_JSON_IN_ARR', 3);
73
-
74
- /**
75
- * Marker constant for Services_JSON::decode(), used to flag stack state
76
- */
77
- define('SERVICES_JSON_IN_OBJ', 4);
78
-
79
- /**
80
- * Marker constant for Services_JSON::decode(), used to flag stack state
81
- */
82
- define('SERVICES_JSON_IN_CMT', 5);
83
-
84
- /**
85
- * Behavior switch for Services_JSON::decode()
86
- */
87
- define('SERVICES_JSON_LOOSE_TYPE', 16);
88
-
89
- /**
90
- * Behavior switch for Services_JSON::decode()
91
- */
92
- define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
93
-
94
- /**
95
- * Converts to and from JSON format.
96
- *
97
- * Brief example of use:
98
- *
99
- * <code>
100
- * // create a new instance of Services_JSON
101
- * $json = new Services_JSON();
102
- *
103
- * // convert a complexe value to JSON notation, and send it to the browser
104
- * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
105
- * $output = $json->encode($value);
106
- *
107
- * print($output);
108
- * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
109
- *
110
- * // accept incoming POST data, assumed to be in JSON notation
111
- * $input = file_get_contents('php://input', 1000000);
112
- * $value = $json->decode($input);
113
- * </code>
114
- */
115
- class Services_JSON
116
- {
117
- /**
118
- * constructs a new JSON instance
119
- *
120
- * @param int $use object behavior flags; combine with boolean-OR
121
- *
122
- * possible values:
123
- * - SERVICES_JSON_LOOSE_TYPE: loose typing.
124
- * "{...}" syntax creates associative arrays
125
- * instead of objects in decode().
126
- * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
127
- * Values which can't be encoded (e.g. resources)
128
- * appear as NULL instead of throwing errors.
129
- * By default, a deeply-nested resource will
130
- * bubble up with an error, so all return values
131
- * from encode() should be checked with isError()
132
- */
133
- function Services_JSON($use = 0)
134
- {
135
- $this->use = $use;
136
- }
137
-
138
- /**
139
- * convert a string from one UTF-16 char to one UTF-8 char
140
- *
141
- * Normally should be handled by mb_convert_encoding, but
142
- * provides a slower PHP-only method for installations
143
- * that lack the multibye string extension.
144
- *
145
- * @param string $utf16 UTF-16 character
146
- * @return string UTF-8 character
147
- * @access private
148
- */
149
- function utf162utf8($utf16)
150
- {
151
- // oh please oh please oh please oh please oh please
152
- if(function_exists('mb_convert_encoding')) {
153
- return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
154
- }
155
-
156
- $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
157
-
158
- switch(true) {
159
- case ((0x7F & $bytes) == $bytes):
160
- // this case should never be reached, because we are in ASCII range
161
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
162
- return chr(0x7F & $bytes);
163
-
164
- case (0x07FF & $bytes) == $bytes:
165
- // return a 2-byte UTF-8 character
166
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
167
- return chr(0xC0 | (($bytes >> 6) & 0x1F))
168
- . chr(0x80 | ($bytes & 0x3F));
169
-
170
- case (0xFFFF & $bytes) == $bytes:
171
- // return a 3-byte UTF-8 character
172
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
173
- return chr(0xE0 | (($bytes >> 12) & 0x0F))
174
- . chr(0x80 | (($bytes >> 6) & 0x3F))
175
- . chr(0x80 | ($bytes & 0x3F));
176
- }
177
-
178
- // ignoring UTF-32 for now, sorry
179
- return '';
180
- }
181
-
182
- /**
183
- * convert a string from one UTF-8 char to one UTF-16 char
184
- *
185
- * Normally should be handled by mb_convert_encoding, but
186
- * provides a slower PHP-only method for installations
187
- * that lack the multibye string extension.
188
- *
189
- * @param string $utf8 UTF-8 character
190
- * @return string UTF-16 character
191
- * @access private
192
- */
193
- function utf82utf16($utf8)
194
- {
195
- // oh please oh please oh please oh please oh please
196
- if(function_exists('mb_convert_encoding')) {
197
- return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
198
- }
199
-
200
- switch(strlen($utf8)) {
201
- case 1:
202
- // this case should never be reached, because we are in ASCII range
203
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
204
- return $utf8;
205
-
206
- case 2:
207
- // return a UTF-16 character from a 2-byte UTF-8 char
208
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
209
- return chr(0x07 & (ord($utf8{0}) >> 2))
210
- . chr((0xC0 & (ord($utf8{0}) << 6))
211
- | (0x3F & ord($utf8{1})));
212
-
213
- case 3:
214
- // return a UTF-16 character from a 3-byte UTF-8 char
215
- // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
216
- return chr((0xF0 & (ord($utf8{0}) << 4))
217
- | (0x0F & (ord($utf8{1}) >> 2)))
218
- . chr((0xC0 & (ord($utf8{1}) << 6))
219
- | (0x7F & ord($utf8{2})));
220
- }
221
-
222
- // ignoring UTF-32 for now, sorry
223
- return '';
224
- }
225
-
226
- /**
227
- * encodes an arbitrary variable into JSON format
228
- *
229
- * @param mixed $var any number, boolean, string, array, or object to be encoded.
230
- * see argument 1 to Services_JSON() above for array-parsing behavior.
231
- * if var is a strng, note that encode() always expects it
232
- * to be in ASCII or UTF-8 format!
233
- *
234
- * @return mixed JSON string representation of input var or an error if a problem occurs
235
- * @access public
236
- */
237
- function encode($var)
238
- {
239
- switch (gettype($var)) {
240
- case 'boolean':
241
- return $var ? 'true' : 'false';
242
-
243
- case 'NULL':
244
- return 'null';
245
-
246
- case 'integer':
247
- return (int) $var;
248
-
249
- case 'double':
250
- case 'float':
251
- return (float) $var;
252
-
253
- case 'string':
254
- // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
255
- $ascii = '';
256
- $strlen_var = strlen($var);
257
-
258
- /*
259
- * Iterate over every character in the string,
260
- * escaping with a slash or encoding to UTF-8 where necessary
261
- */
262
- for ($c = 0; $c < $strlen_var; ++$c) {
263
-
264
- $ord_var_c = ord($var{$c});
265
-
266
- switch (true) {
267
- case $ord_var_c == 0x08:
268
- $ascii .= '\b';
269
- break;
270
- case $ord_var_c == 0x09:
271
- $ascii .= '\t';
272
- break;
273
- case $ord_var_c == 0x0A:
274
- $ascii .= '\n';
275
- break;
276
- case $ord_var_c == 0x0C:
277
- $ascii .= '\f';
278
- break;
279
- case $ord_var_c == 0x0D:
280
- $ascii .= '\r';
281
- break;
282
-
283
- case $ord_var_c == 0x22:
284
- case $ord_var_c == 0x2F:
285
- case $ord_var_c == 0x5C:
286
- // double quote, slash, slosh
287
- $ascii .= '\\'.$var{$c};
288
- break;
289
-
290
- case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
291
- // characters U-00000000 - U-0000007F (same as ASCII)
292
- $ascii .= $var{$c};
293
- break;
294
-
295
- case (($ord_var_c & 0xE0) == 0xC0):
296
- // characters U-00000080 - U-000007FF, mask 110XXXXX
297
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
298
- $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
299
- $c += 1;
300
- $utf16 = $this->utf82utf16($char);
301
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
302
- break;
303
-
304
- case (($ord_var_c & 0xF0) == 0xE0):
305
- // characters U-00000800 - U-0000FFFF, mask 1110XXXX
306
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
307
- $char = pack('C*', $ord_var_c,
308
- ord($var{$c + 1}),
309
- ord($var{$c + 2}));
310
- $c += 2;
311
- $utf16 = $this->utf82utf16($char);
312
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
313
- break;
314
-
315
- case (($ord_var_c & 0xF8) == 0xF0):
316
- // characters U-00010000 - U-001FFFFF, mask 11110XXX
317
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
318
- $char = pack('C*', $ord_var_c,
319
- ord($var{$c + 1}),
320
- ord($var{$c + 2}),
321
- ord($var{$c + 3}));
322
- $c += 3;
323
- $utf16 = $this->utf82utf16($char);
324
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
325
- break;
326
-
327
- case (($ord_var_c & 0xFC) == 0xF8):
328
- // characters U-00200000 - U-03FFFFFF, mask 111110XX
329
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
330
- $char = pack('C*', $ord_var_c,
331
- ord($var{$c + 1}),
332
- ord($var{$c + 2}),
333
- ord($var{$c + 3}),
334
- ord($var{$c + 4}));
335
- $c += 4;
336
- $utf16 = $this->utf82utf16($char);
337
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
338
- break;
339
-
340
- case (($ord_var_c & 0xFE) == 0xFC):
341
- // characters U-04000000 - U-7FFFFFFF, mask 1111110X
342
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
343
- $char = pack('C*', $ord_var_c,
344
- ord($var{$c + 1}),
345
- ord($var{$c + 2}),
346
- ord($var{$c + 3}),
347
- ord($var{$c + 4}),
348
- ord($var{$c + 5}));
349
- $c += 5;
350
- $utf16 = $this->utf82utf16($char);
351
- $ascii .= sprintf('\u%04s', bin2hex($utf16));
352
- break;
353
- }
354
- }
355
-
356
- return '"'.$ascii.'"';
357
-
358
- case 'array':
359
- /*
360
- * As per JSON spec if any array key is not an integer
361
- * we must treat the the whole array as an object. We
362
- * also try to catch a sparsely populated associative
363
- * array with numeric keys here because some JS engines
364
- * will create an array with empty indexes up to
365
- * max_index which can cause memory issues and because
366
- * the keys, which may be relevant, will be remapped
367
- * otherwise.
368
- *
369
- * As per the ECMA and JSON specification an object may
370
- * have any string as a property. Unfortunately due to
371
- * a hole in the ECMA specification if the key is a
372
- * ECMA reserved word or starts with a digit the
373
- * parameter is only accessible using ECMAScript's
374
- * bracket notation.
375
- */
376
-
377
- // treat as a JSON object
378
- if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
379
- $properties = array_map(array($this, 'name_value'),
380
- array_keys($var),
381
- array_values($var));
382
-
383
- foreach($properties as $property) {
384
- if(Services_JSON::isError($property)) {
385
- return $property;
386
- }
387
- }
388
-
389
- return '{' . join(',', $properties) . '}';
390
- }
391
-
392
- // treat it like a regular array
393
- $elements = array_map(array($this, 'encode'), $var);
394
-
395
- foreach($elements as $element) {
396
- if(Services_JSON::isError($element)) {
397
- return $element;
398
- }
399
- }
400
-
401
- return '[' . join(',', $elements) . ']';
402
-
403
- case 'object':
404
- $vars = get_object_vars($var);
405
-
406
- $properties = array_map(array($this, 'name_value'),
407
- array_keys($vars),
408
- array_values($vars));
409
-
410
- foreach($properties as $property) {
411
- if(Services_JSON::isError($property)) {
412
- return $property;
413
- }
414
- }
415
-
416
- return '{' . join(',', $properties) . '}';
417
-
418
- default:
419
- return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
420
- ? 'null'
421
- : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
422
- }
423
- }
424
-
425
- /**
426
- * array-walking function for use in generating JSON-formatted name-value pairs
427
- *
428
- * @param string $name name of key to use
429
- * @param mixed $value reference to an array element to be encoded
430
- *
431
- * @return string JSON-formatted name-value pair, like '"name":value'
432
- * @access private
433
- */
434
- function name_value($name, $value)
435
- {
436
- $encoded_value = $this->encode($value);
437
-
438
- if(Services_JSON::isError($encoded_value)) {
439
- return $encoded_value;
440
- }
441
-
442
- return $this->encode(strval($name)) . ':' . $encoded_value;
443
- }
444
-
445
- /**
446
- * reduce a string by removing leading and trailing comments and whitespace
447
- *
448
- * @param $str string string value to strip of comments and whitespace
449
- *
450
- * @return string string value stripped of comments and whitespace
451
- * @access private
452
- */
453
- function reduce_string($str)
454
- {
455
- $str = preg_replace(array(
456
-
457
- // eliminate single line comments in '// ...' form
458
- '#^\s*//(.+)$#m',
459
-
460
- // eliminate multi-line comments in '/* ... */' form, at start of string
461
- '#^\s*/\*(.+)\*/#Us',
462
-
463
- // eliminate multi-line comments in '/* ... */' form, at end of string
464
- '#/\*(.+)\*/\s*$#Us'
465
-
466
- ), '', $str);
467
-
468
- // eliminate extraneous space
469
- return trim($str);
470
- }
471
-
472
- /**
473
- * decodes a JSON string into appropriate variable
474
- *
475
- * @param string $str JSON-formatted string
476
- *
477
- * @return mixed number, boolean, string, array, or object
478
- * corresponding to given JSON input string.
479
- * See argument 1 to Services_JSON() above for object-output behavior.
480
- * Note that decode() always returns strings
481
- * in ASCII or UTF-8 format!
482
- * @access public
483
- */
484
- function decode($str)
485
- {
486
- $str = $this->reduce_string($str);
487
-
488
- switch (strtolower($str)) {
489
- case 'true':
490
- return true;
491
-
492
- case 'false':
493
- return false;
494
-
495
- case 'null':
496
- return null;
497
-
498
- default:
499
- $m = array();
500
-
501
- if (is_numeric($str)) {
502
- // Lookie-loo, it's a number
503
-
504
- // This would work on its own, but I'm trying to be
505
- // good about returning integers where appropriate:
506
- // return (float)$str;
507
-
508
- // Return float or int, as appropriate
509
- return ((float)$str == (integer)$str)
510
- ? (integer)$str
511
- : (float)$str;
512
-
513
- } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
514
- // STRINGS RETURNED IN UTF-8 FORMAT
515
- $delim = substr($str, 0, 1);
516
- $chrs = substr($str, 1, -1);
517
- $utf8 = '';
518
- $strlen_chrs = strlen($chrs);
519
-
520
- for ($c = 0; $c < $strlen_chrs; ++$c) {
521
-
522
- $substr_chrs_c_2 = substr($chrs, $c, 2);
523
- $ord_chrs_c = ord($chrs{$c});
524
-
525
- switch (true) {
526
- case $substr_chrs_c_2 == '\b':
527
- $utf8 .= chr(0x08);
528
- ++$c;
529
- break;
530
- case $substr_chrs_c_2 == '\t':
531
- $utf8 .= chr(0x09);
532
- ++$c;
533
- break;
534
- case $substr_chrs_c_2 == '\n':
535
- $utf8 .= chr(0x0A);
536
- ++$c;
537
- break;
538
- case $substr_chrs_c_2 == '\f':
539
- $utf8 .= chr(0x0C);
540
- ++$c;
541
- break;
542
- case $substr_chrs_c_2 == '\r':
543
- $utf8 .= chr(0x0D);
544
- ++$c;
545
- break;
546
-
547
- case $substr_chrs_c_2 == '\\"':
548
- case $substr_chrs_c_2 == '\\\'':
549
- case $substr_chrs_c_2 == '\\\\':
550
- case $substr_chrs_c_2 == '\\/':
551
- if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
552
- ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
553
- $utf8 .= $chrs{++$c};
554
- }
555
- break;
556
-
557
- case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
558
- // single, escaped unicode character
559
- $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
560
- . chr(hexdec(substr($chrs, ($c + 4), 2)));
561
- $utf8 .= $this->utf162utf8($utf16);
562
- $c += 5;
563
- break;
564
-
565
- case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
566
- $utf8 .= $chrs{$c};
567
- break;
568
-
569
- case ($ord_chrs_c & 0xE0) == 0xC0:
570
- // characters U-00000080 - U-000007FF, mask 110XXXXX
571
- //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
572
- $utf8 .= substr($chrs, $c, 2);
573
- ++$c;
574
- break;
575
-
576
- case ($ord_chrs_c & 0xF0) == 0xE0:
577
- // characters U-00000800 - U-0000FFFF, mask 1110XXXX
578
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
579
- $utf8 .= substr($chrs, $c, 3);
580
- $c += 2;
581
- break;
582
-
583
- case ($ord_chrs_c & 0xF8) == 0xF0:
584
- // characters U-00010000 - U-001FFFFF, mask 11110XXX
585
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
586
- $utf8 .= substr($chrs, $c, 4);
587
- $c += 3;
588
- break;
589
-
590
- case ($ord_chrs_c & 0xFC) == 0xF8:
591
- // characters U-00200000 - U-03FFFFFF, mask 111110XX
592
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
593
- $utf8 .= substr($chrs, $c, 5);
594
- $c += 4;
595
- break;
596
-
597
- case ($ord_chrs_c & 0xFE) == 0xFC:
598
- // characters U-04000000 - U-7FFFFFFF, mask 1111110X
599
- // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
600
- $utf8 .= substr($chrs, $c, 6);
601
- $c += 5;
602
- break;
603
-
604
- }
605
-
606
- }
607
-
608
- return $utf8;
609
-
610
- } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
611
- // array, or object notation
612
-
613
- if ($str{0} == '[') {
614
- $stk = array(SERVICES_JSON_IN_ARR);
615
- $arr = array();
616
- } else {
617
- if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
618
- $stk = array(SERVICES_JSON_IN_OBJ);
619
- $obj = array();
620
- } else {
621
- $stk = array(SERVICES_JSON_IN_OBJ);
622
- $obj = new stdClass();
623
- }
624
- }
625
-
626
- array_push($stk, array('what' => SERVICES_JSON_SLICE,
627
- 'where' => 0,
628
- 'delim' => false));
629
-
630
- $chrs = substr($str, 1, -1);
631
- $chrs = $this->reduce_string($chrs);
632
-
633
- if ($chrs == '') {
634
- if (reset($stk) == SERVICES_JSON_IN_ARR) {
635
- return $arr;
636
-
637
- } else {
638
- return $obj;
639
-
640
- }
641
- }
642
-
643
- //print("\nparsing {$chrs}\n");
644
-
645
- $strlen_chrs = strlen($chrs);
646
-
647
- for ($c = 0; $c <= $strlen_chrs; ++$c) {
648
-
649
- $top = end($stk);
650
- $substr_chrs_c_2 = substr($chrs, $c, 2);
651
-
652
- if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
653
- // found a comma that is not inside a string, array, etc.,
654
- // OR we've reached the end of the character list
655
- $slice = substr($chrs, $top['where'], ($c - $top['where']));
656
- array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
657
- //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
658
-
659
- if (reset($stk) == SERVICES_JSON_IN_ARR) {
660
- // we are in an array, so just push an element onto the stack
661
- array_push($arr, $this->decode($slice));
662
-
663
- } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
664
- // we are in an object, so figure
665
- // out the property name and set an
666
- // element in an associative array,
667
- // for now
668
- $parts = array();
669
-
670
- if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
671
- // "name":value pair
672
- $key = $this->decode($parts[1]);
673
- $val = $this->decode($parts[2]);
674
-
675
- if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
676
- $obj[$key] = $val;
677
- } else {
678
- $obj->$key = $val;
679
- }
680
- } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
681
- // name:value pair, where name is unquoted
682
- $key = $parts[1];
683
- $val = $this->decode($parts[2]);
684
-
685
- if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
686
- $obj[$key] = $val;
687
- } else {
688
- $obj->$key = $val;
689
- }
690
- }
691
-
692
- }
693
-
694
- } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
695
- // found a quote, and we are not inside a string
696
- array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
697
- //print("Found start of string at {$c}\n");
698
-
699
- } elseif (($chrs{$c} == $top['delim']) &&
700
- ($top['what'] == SERVICES_JSON_IN_STR) &&
701
- ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
702
- // found a quote, we're in a string, and it's not escaped
703
- // we know that it's not escaped becase there is _not_ an
704
- // odd number of backslashes at the end of the string so far
705
- array_pop($stk);
706
- //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
707
-
708
- } elseif (($chrs{$c} == '[') &&
709
- in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
710
- // found a left-bracket, and we are in an array, object, or slice
711
- array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
712
- //print("Found start of array at {$c}\n");
713
-
714
- } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
715
- // found a right-bracket, and we're in an array
716
- array_pop($stk);
717
- //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
718
-
719
- } elseif (($chrs{$c} == '{') &&
720
- in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
721
- // found a left-brace, and we are in an array, object, or slice
722
- array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
723
- //print("Found start of object at {$c}\n");
724
-
725
- } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
726
- // found a right-brace, and we're in an object
727
- array_pop($stk);
728
- //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
729
-
730
- } elseif (($substr_chrs_c_2 == '/*') &&
731
- in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
732
- // found a comment start, and we are in an array, object, or slice
733
- array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
734
- $c++;
735
- //print("Found start of comment at {$c}\n");
736
-
737
- } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
738
- // found a comment end, and we're in one now
739
- array_pop($stk);
740
- $c++;
741
-
742
- for ($i = $top['where']; $i <= $c; ++$i)
743
- $chrs = substr_replace($chrs, ' ', $i, 1);
744
-
745
- //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
746
-
747
- }
748
-
749
- }
750
-
751
- if (reset($stk) == SERVICES_JSON_IN_ARR) {
752
- return $arr;
753
-
754
- } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
755
- return $obj;
756
-
757
- }
758
-
759
- }
760
- }
761
- }
762
-
763
- /**
764
- * @todo Ultimately, this should just call PEAR::isError()
765
- */
766
- function isError($data, $code = null)
767
- {
768
- if (class_exists('pear')) {
769
- return PEAR::isError($data, $code);
770
- } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
771
- is_subclass_of($data, 'services_json_error'))) {
772
- return true;
773
- }
774
-
775
- return false;
776
- }
777
- }
778
-
779
- if (class_exists('PEAR_Error')) {
780
-
781
- class Services_JSON_Error extends PEAR_Error
782
- {
783
- function Services_JSON_Error($message = 'unknown error', $code = null,
784
- $mode = null, $options = null, $userinfo = null)
785
- {
786
- parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
787
- }
788
- }
789
-
790
- } else {
791
-
792
- /**
793
- * @todo Ultimately, this class shall be descended from PEAR_Error
794
- */
795
- class Services_JSON_Error
796
- {
797
- function Services_JSON_Error($message = 'unknown error', $code = null,
798
- $mode = null, $options = null, $userinfo = null)
799
- {
800
-
801
- }
802
- }
803
-
804
- }
805
-
806
- ?>
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
+ * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
55
+ * @license http://www.opensource.org/licenses/bsd-license.php
56
+ * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
57
+ */
58
+
59
+ /**
60
+ * Marker constant for Services_JSON::decode(), used to flag stack state
61
+ */
62
+ define('SERVICES_JSON_SLICE', 1);
63
+
64
+ /**
65
+ * Marker constant for Services_JSON::decode(), used to flag stack state
66
+ */
67
+ define('SERVICES_JSON_IN_STR', 2);
68
+
69
+ /**
70
+ * Marker constant for Services_JSON::decode(), used to flag stack state
71
+ */
72
+ define('SERVICES_JSON_IN_ARR', 3);
73
+
74
+ /**
75
+ * Marker constant for Services_JSON::decode(), used to flag stack state
76
+ */
77
+ define('SERVICES_JSON_IN_OBJ', 4);
78
+
79
+ /**
80
+ * Marker constant for Services_JSON::decode(), used to flag stack state
81
+ */
82
+ define('SERVICES_JSON_IN_CMT', 5);
83
+
84
+ /**
85
+ * Behavior switch for Services_JSON::decode()
86
+ */
87
+ define('SERVICES_JSON_LOOSE_TYPE', 16);
88
+
89
+ /**
90
+ * Behavior switch for Services_JSON::decode()
91
+ */
92
+ define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
93
+
94
+ /**
95
+ * Converts to and from JSON format.
96
+ *
97
+ * Brief example of use:
98
+ *
99
+ * <code>
100
+ * // create a new instance of Services_JSON
101
+ * $json = new Services_JSON();
102
+ *
103
+ * // convert a complexe value to JSON notation, and send it to the browser
104
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
105
+ * $output = $json->encode($value);
106
+ *
107
+ * print($output);
108
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
109
+ *
110
+ * // accept incoming POST data, assumed to be in JSON notation
111
+ * $input = file_get_contents('php://input', 1000000);
112
+ * $value = $json->decode($input);
113
+ * </code>
114
+ */
115
+ class Services_JSON
116
+ {
117
+ /**
118
+ * constructs a new JSON instance
119
+ *
120
+ * @param int $use object behavior flags; combine with boolean-OR
121
+ *
122
+ * possible values:
123
+ * - SERVICES_JSON_LOOSE_TYPE: loose typing.
124
+ * "{...}" syntax creates associative arrays
125
+ * instead of objects in decode().
126
+ * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
127
+ * Values which can't be encoded (e.g. resources)
128
+ * appear as NULL instead of throwing errors.
129
+ * By default, a deeply-nested resource will
130
+ * bubble up with an error, so all return values
131
+ * from encode() should be checked with isError()
132
+ */
133
+ function Services_JSON($use = 0)
134
+ {
135
+ $this->use = $use;
136
+ }
137
+
138
+ /**
139
+ * convert a string from one UTF-16 char to one UTF-8 char
140
+ *
141
+ * Normally should be handled by mb_convert_encoding, but
142
+ * provides a slower PHP-only method for installations
143
+ * that lack the multibye string extension.
144
+ *
145
+ * @param string $utf16 UTF-16 character
146
+ * @return string UTF-8 character
147
+ * @access private
148
+ */
149
+ function utf162utf8($utf16)
150
+ {
151
+ // oh please oh please oh please oh please oh please
152
+ if(function_exists('mb_convert_encoding')) {
153
+ return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
154
+ }
155
+
156
+ $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
157
+
158
+ switch(true) {
159
+ case ((0x7F & $bytes) == $bytes):
160
+ // this case should never be reached, because we are in ASCII range
161
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
162
+ return chr(0x7F & $bytes);
163
+
164
+ case (0x07FF & $bytes) == $bytes:
165
+ // return a 2-byte UTF-8 character
166
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
167
+ return chr(0xC0 | (($bytes >> 6) & 0x1F))
168
+ . chr(0x80 | ($bytes & 0x3F));
169
+
170
+ case (0xFFFF & $bytes) == $bytes:
171
+ // return a 3-byte UTF-8 character
172
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
173
+ return chr(0xE0 | (($bytes >> 12) & 0x0F))
174
+ . chr(0x80 | (($bytes >> 6) & 0x3F))
175
+ . chr(0x80 | ($bytes & 0x3F));
176
+ }
177
+
178
+ // ignoring UTF-32 for now, sorry
179
+ return '';
180
+ }
181
+
182
+ /**
183
+ * convert a string from one UTF-8 char to one UTF-16 char
184
+ *
185
+ * Normally should be handled by mb_convert_encoding, but
186
+ * provides a slower PHP-only method for installations
187
+ * that lack the multibye string extension.
188
+ *
189
+ * @param string $utf8 UTF-8 character
190
+ * @return string UTF-16 character
191
+ * @access private
192
+ */
193
+ function utf82utf16($utf8)
194
+ {
195
+ // oh please oh please oh please oh please oh please
196
+ if(function_exists('mb_convert_encoding')) {
197
+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
198
+ }
199
+
200
+ switch(strlen($utf8)) {
201
+ case 1:
202
+ // this case should never be reached, because we are in ASCII range
203
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
204
+ return $utf8;
205
+
206
+ case 2:
207
+ // return a UTF-16 character from a 2-byte UTF-8 char
208
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
209
+ return chr(0x07 & (ord($utf8{0}) >> 2))
210
+ . chr((0xC0 & (ord($utf8{0}) << 6))
211
+ | (0x3F & ord($utf8{1})));
212
+
213
+ case 3:
214
+ // return a UTF-16 character from a 3-byte UTF-8 char
215
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
216
+ return chr((0xF0 & (ord($utf8{0}) << 4))
217
+ | (0x0F & (ord($utf8{1}) >> 2)))
218
+ . chr((0xC0 & (ord($utf8{1}) << 6))
219
+ | (0x7F & ord($utf8{2})));
220
+ }
221
+
222
+ // ignoring UTF-32 for now, sorry
223
+ return '';
224
+ }
225
+
226
+ /**
227
+ * encodes an arbitrary variable into JSON format
228
+ *
229
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
230
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
231
+ * if var is a strng, note that encode() always expects it
232
+ * to be in ASCII or UTF-8 format!
233
+ *
234
+ * @return mixed JSON string representation of input var or an error if a problem occurs
235
+ * @access public
236
+ */
237
+ function encode($var)
238
+ {
239
+ switch (gettype($var)) {
240
+ case 'boolean':
241
+ return $var ? 'true' : 'false';
242
+
243
+ case 'NULL':
244
+ return 'null';
245
+
246
+ case 'integer':
247
+ return (int) $var;
248
+
249
+ case 'double':
250
+ case 'float':
251
+ return (float) $var;
252
+
253
+ case 'string':
254
+ // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
255
+ $ascii = '';
256
+ $strlen_var = strlen($var);
257
+
258
+ /*
259
+ * Iterate over every character in the string,
260
+ * escaping with a slash or encoding to UTF-8 where necessary
261
+ */
262
+ for ($c = 0; $c < $strlen_var; ++$c) {
263
+
264
+ $ord_var_c = ord($var{$c});
265
+
266
+ switch (true) {
267
+ case $ord_var_c == 0x08:
268
+ $ascii .= '\b';
269
+ break;
270
+ case $ord_var_c == 0x09:
271
+ $ascii .= '\t';
272
+ break;
273
+ case $ord_var_c == 0x0A:
274
+ $ascii .= '\n';
275
+ break;
276
+ case $ord_var_c == 0x0C:
277
+ $ascii .= '\f';
278
+ break;
279
+ case $ord_var_c == 0x0D:
280
+ $ascii .= '\r';
281
+ break;
282
+
283
+ case $ord_var_c == 0x22:
284
+ case $ord_var_c == 0x2F:
285
+ case $ord_var_c == 0x5C:
286
+ // double quote, slash, slosh
287
+ $ascii .= '\\'.$var{$c};
288
+ break;
289
+
290
+ case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
291
+ // characters U-00000000 - U-0000007F (same as ASCII)
292
+ $ascii .= $var{$c};
293
+ break;
294
+
295
+ case (($ord_var_c & 0xE0) == 0xC0):
296
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
297
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
298
+ $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
299
+ $c += 1;
300
+ $utf16 = $this->utf82utf16($char);
301
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
302
+ break;
303
+
304
+ case (($ord_var_c & 0xF0) == 0xE0):
305
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
306
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
307
+ $char = pack('C*', $ord_var_c,
308
+ ord($var{$c + 1}),
309
+ ord($var{$c + 2}));
310
+ $c += 2;
311
+ $utf16 = $this->utf82utf16($char);
312
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
313
+ break;
314
+
315
+ case (($ord_var_c & 0xF8) == 0xF0):
316
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
317
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
318
+ $char = pack('C*', $ord_var_c,
319
+ ord($var{$c + 1}),
320
+ ord($var{$c + 2}),
321
+ ord($var{$c + 3}));
322
+ $c += 3;
323
+ $utf16 = $this->utf82utf16($char);
324
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
325
+ break;
326
+
327
+ case (($ord_var_c & 0xFC) == 0xF8):
328
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
329
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
330
+ $char = pack('C*', $ord_var_c,
331
+ ord($var{$c + 1}),
332
+ ord($var{$c + 2}),
333
+ ord($var{$c + 3}),
334
+ ord($var{$c + 4}));
335
+ $c += 4;
336
+ $utf16 = $this->utf82utf16($char);
337
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
338
+ break;
339
+
340
+ case (($ord_var_c & 0xFE) == 0xFC):
341
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
342
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
343
+ $char = pack('C*', $ord_var_c,
344
+ ord($var{$c + 1}),
345
+ ord($var{$c + 2}),
346
+ ord($var{$c + 3}),
347
+ ord($var{$c + 4}),
348
+ ord($var{$c + 5}));
349
+ $c += 5;
350
+ $utf16 = $this->utf82utf16($char);
351
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
352
+ break;
353
+ }
354
+ }
355
+
356
+ return '"'.$ascii.'"';
357
+
358
+ case 'array':
359
+ /*
360
+ * As per JSON spec if any array key is not an integer
361
+ * we must treat the the whole array as an object. We
362
+ * also try to catch a sparsely populated associative
363
+ * array with numeric keys here because some JS engines
364
+ * will create an array with empty indexes up to
365
+ * max_index which can cause memory issues and because
366
+ * the keys, which may be relevant, will be remapped
367
+ * otherwise.
368
+ *
369
+ * As per the ECMA and JSON specification an object may
370
+ * have any string as a property. Unfortunately due to
371
+ * a hole in the ECMA specification if the key is a
372
+ * ECMA reserved word or starts with a digit the
373
+ * parameter is only accessible using ECMAScript's
374
+ * bracket notation.
375
+ */
376
+
377
+ // treat as a JSON object
378
+ if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
379
+ $properties = array_map(array($this, 'name_value'),
380
+ array_keys($var),
381
+ array_values($var));
382
+
383
+ foreach($properties as $property) {
384
+ if(Services_JSON::isError($property)) {
385
+ return $property;
386
+ }
387
+ }
388
+
389
+ return '{' . join(',', $properties) . '}';
390
+ }
391
+
392
+ // treat it like a regular array
393
+ $elements = array_map(array($this, 'encode'), $var);
394
+
395
+ foreach($elements as $element) {
396
+ if(Services_JSON::isError($element)) {
397
+ return $element;
398
+ }
399
+ }
400
+
401
+ return '[' . join(',', $elements) . ']';
402
+
403
+ case 'object':
404
+ $vars = get_object_vars($var);
405
+
406
+ $properties = array_map(array($this, 'name_value'),
407
+ array_keys($vars),
408
+ array_values($vars));
409
+
410
+ foreach($properties as $property) {
411
+ if(Services_JSON::isError($property)) {
412
+ return $property;
413
+ }
414
+ }
415
+
416
+ return '{' . join(',', $properties) . '}';
417
+
418
+ default:
419
+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
420
+ ? 'null'
421
+ : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
422
+ }
423
+ }
424
+
425
+ /**
426
+ * array-walking function for use in generating JSON-formatted name-value pairs
427
+ *
428
+ * @param string $name name of key to use
429
+ * @param mixed $value reference to an array element to be encoded
430
+ *
431
+ * @return string JSON-formatted name-value pair, like '"name":value'
432
+ * @access private
433
+ */
434
+ function name_value($name, $value)
435
+ {
436
+ $encoded_value = $this->encode($value);
437
+
438
+ if(Services_JSON::isError($encoded_value)) {
439
+ return $encoded_value;
440
+ }
441
+
442
+ return $this->encode(strval($name)) . ':' . $encoded_value;
443
+ }
444
+
445
+ /**
446
+ * reduce a string by removing leading and trailing comments and whitespace
447
+ *
448
+ * @param $str string string value to strip of comments and whitespace
449
+ *
450
+ * @return string string value stripped of comments and whitespace
451
+ * @access private
452
+ */
453
+ function reduce_string($str)
454
+ {
455
+ $str = preg_replace(array(
456
+
457
+ // eliminate single line comments in '// ...' form
458
+ '#^\s*//(.+)$#m',
459
+
460
+ // eliminate multi-line comments in '/* ... */' form, at start of string
461
+ '#^\s*/\*(.+)\*/#Us',
462
+
463
+ // eliminate multi-line comments in '/* ... */' form, at end of string
464
+ '#/\*(.+)\*/\s*$#Us'
465
+
466
+ ), '', $str);
467
+
468
+ // eliminate extraneous space
469
+ return trim($str);
470
+ }
471
+
472
+ /**
473
+ * decodes a JSON string into appropriate variable
474
+ *
475
+ * @param string $str JSON-formatted string
476
+ *
477
+ * @return mixed number, boolean, string, array, or object
478
+ * corresponding to given JSON input string.
479
+ * See argument 1 to Services_JSON() above for object-output behavior.
480
+ * Note that decode() always returns strings
481
+ * in ASCII or UTF-8 format!
482
+ * @access public
483
+ */
484
+ function decode($str)
485
+ {
486
+ $str = $this->reduce_string($str);
487
+
488
+ switch (strtolower($str)) {
489
+ case 'true':
490
+ return true;
491
+
492
+ case 'false':
493
+ return false;
494
+
495
+ case 'null':
496
+ return null;
497
+
498
+ default:
499
+ $m = array();
500
+
501
+ if (is_numeric($str)) {
502
+ // Lookie-loo, it's a number
503
+
504
+ // This would work on its own, but I'm trying to be
505
+ // good about returning integers where appropriate:
506
+ // return (float)$str;
507
+
508
+ // Return float or int, as appropriate
509
+ return ((float)$str == (integer)$str)
510
+ ? (integer)$str
511
+ : (float)$str;
512
+
513
+ } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
514
+ // STRINGS RETURNED IN UTF-8 FORMAT
515
+ $delim = substr($str, 0, 1);
516
+ $chrs = substr($str, 1, -1);
517
+ $utf8 = '';
518
+ $strlen_chrs = strlen($chrs);
519
+
520
+ for ($c = 0; $c < $strlen_chrs; ++$c) {
521
+
522
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
523
+ $ord_chrs_c = ord($chrs{$c});
524
+
525
+ switch (true) {
526
+ case $substr_chrs_c_2 == '\b':
527
+ $utf8 .= chr(0x08);
528
+ ++$c;
529
+ break;
530
+ case $substr_chrs_c_2 == '\t':
531
+ $utf8 .= chr(0x09);
532
+ ++$c;
533
+ break;
534
+ case $substr_chrs_c_2 == '\n':
535
+ $utf8 .= chr(0x0A);
536
+ ++$c;
537
+ break;
538
+ case $substr_chrs_c_2 == '\f':
539
+ $utf8 .= chr(0x0C);
540
+ ++$c;
541
+ break;
542
+ case $substr_chrs_c_2 == '\r':
543
+ $utf8 .= chr(0x0D);
544
+ ++$c;
545
+ break;
546
+
547
+ case $substr_chrs_c_2 == '\\"':
548
+ case $substr_chrs_c_2 == '\\\'':
549
+ case $substr_chrs_c_2 == '\\\\':
550
+ case $substr_chrs_c_2 == '\\/':
551
+ if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
552
+ ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
553
+ $utf8 .= $chrs{++$c};
554
+ }
555
+ break;
556
+
557
+ case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
558
+ // single, escaped unicode character
559
+ $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
560
+ . chr(hexdec(substr($chrs, ($c + 4), 2)));
561
+ $utf8 .= $this->utf162utf8($utf16);
562
+ $c += 5;
563
+ break;
564
+
565
+ case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
566
+ $utf8 .= $chrs{$c};
567
+ break;
568
+
569
+ case ($ord_chrs_c & 0xE0) == 0xC0:
570
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
571
+ //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
572
+ $utf8 .= substr($chrs, $c, 2);
573
+ ++$c;
574
+ break;
575
+
576
+ case ($ord_chrs_c & 0xF0) == 0xE0:
577
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
578
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
579
+ $utf8 .= substr($chrs, $c, 3);
580
+ $c += 2;
581
+ break;
582
+
583
+ case ($ord_chrs_c & 0xF8) == 0xF0:
584
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
585
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
586
+ $utf8 .= substr($chrs, $c, 4);
587
+ $c += 3;
588
+ break;
589
+
590
+ case ($ord_chrs_c & 0xFC) == 0xF8:
591
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
592
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
593
+ $utf8 .= substr($chrs, $c, 5);
594
+ $c += 4;
595
+ break;
596
+
597
+ case ($ord_chrs_c & 0xFE) == 0xFC:
598
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
599
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
600
+ $utf8 .= substr($chrs, $c, 6);
601
+ $c += 5;
602
+ break;
603
+
604
+ }
605
+
606
+ }
607
+
608
+ return $utf8;
609
+
610
+ } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
611
+ // array, or object notation
612
+
613
+ if ($str{0} == '[') {
614
+ $stk = array(SERVICES_JSON_IN_ARR);
615
+ $arr = array();
616
+ } else {
617
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
618
+ $stk = array(SERVICES_JSON_IN_OBJ);
619
+ $obj = array();
620
+ } else {
621
+ $stk = array(SERVICES_JSON_IN_OBJ);
622
+ $obj = new stdClass();
623
+ }
624
+ }
625
+
626
+ array_push($stk, array('what' => SERVICES_JSON_SLICE,
627
+ 'where' => 0,
628
+ 'delim' => false));
629
+
630
+ $chrs = substr($str, 1, -1);
631
+ $chrs = $this->reduce_string($chrs);
632
+
633
+ if ($chrs == '') {
634
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
635
+ return $arr;
636
+
637
+ } else {
638
+ return $obj;
639
+
640
+ }
641
+ }
642
+
643
+ //print("\nparsing {$chrs}\n");
644
+
645
+ $strlen_chrs = strlen($chrs);
646
+
647
+ for ($c = 0; $c <= $strlen_chrs; ++$c) {
648
+
649
+ $top = end($stk);
650
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
651
+
652
+ if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
653
+ // found a comma that is not inside a string, array, etc.,
654
+ // OR we've reached the end of the character list
655
+ $slice = substr($chrs, $top['where'], ($c - $top['where']));
656
+ array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
657
+ //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
658
+
659
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
660
+ // we are in an array, so just push an element onto the stack
661
+ array_push($arr, $this->decode($slice));
662
+
663
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
664
+ // we are in an object, so figure
665
+ // out the property name and set an
666
+ // element in an associative array,
667
+ // for now
668
+ $parts = array();
669
+
670
+ if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
671
+ // "name":value pair
672
+ $key = $this->decode($parts[1]);
673
+ $val = $this->decode($parts[2]);
674
+
675
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
676
+ $obj[$key] = $val;
677
+ } else {
678
+ $obj->$key = $val;
679
+ }
680
+ } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
681
+ // name:value pair, where name is unquoted
682
+ $key = $parts[1];
683
+ $val = $this->decode($parts[2]);
684
+
685
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
686
+ $obj[$key] = $val;
687
+ } else {
688
+ $obj->$key = $val;
689
+ }
690
+ }
691
+
692
+ }
693
+
694
+ } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
695
+ // found a quote, and we are not inside a string
696
+ array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
697
+ //print("Found start of string at {$c}\n");
698
+
699
+ } elseif (($chrs{$c} == $top['delim']) &&
700
+ ($top['what'] == SERVICES_JSON_IN_STR) &&
701
+ ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
702
+ // found a quote, we're in a string, and it's not escaped
703
+ // we know that it's not escaped becase there is _not_ an
704
+ // odd number of backslashes at the end of the string so far
705
+ array_pop($stk);
706
+ //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
707
+
708
+ } elseif (($chrs{$c} == '[') &&
709
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
710
+ // found a left-bracket, and we are in an array, object, or slice
711
+ array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
712
+ //print("Found start of array at {$c}\n");
713
+
714
+ } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
715
+ // found a right-bracket, and we're in an array
716
+ array_pop($stk);
717
+ //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
718
+
719
+ } elseif (($chrs{$c} == '{') &&
720
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
721
+ // found a left-brace, and we are in an array, object, or slice
722
+ array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
723
+ //print("Found start of object at {$c}\n");
724
+
725
+ } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
726
+ // found a right-brace, and we're in an object
727
+ array_pop($stk);
728
+ //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
729
+
730
+ } elseif (($substr_chrs_c_2 == '/*') &&
731
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
732
+ // found a comment start, and we are in an array, object, or slice
733
+ array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
734
+ $c++;
735
+ //print("Found start of comment at {$c}\n");
736
+
737
+ } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
738
+ // found a comment end, and we're in one now
739
+ array_pop($stk);
740
+ $c++;
741
+
742
+ for ($i = $top['where']; $i <= $c; ++$i)
743
+ $chrs = substr_replace($chrs, ' ', $i, 1);
744
+
745
+ //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
746
+
747
+ }
748
+
749
+ }
750
+
751
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
752
+ return $arr;
753
+
754
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
755
+ return $obj;
756
+
757
+ }
758
+
759
+ }
760
+ }
761
+ }
762
+
763
+ /**
764
+ * @todo Ultimately, this should just call PEAR::isError()
765
+ */
766
+ function isError($data, $code = null)
767
+ {
768
+ if (class_exists('pear')) {
769
+ return PEAR::isError($data, $code);
770
+ } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
771
+ is_subclass_of($data, 'services_json_error'))) {
772
+ return true;
773
+ }
774
+
775
+ return false;
776
+ }
777
+ }
778
+
779
+ if (class_exists('PEAR_Error')) {
780
+
781
+ class Services_JSON_Error extends PEAR_Error
782
+ {
783
+ function Services_JSON_Error($message = 'unknown error', $code = null,
784
+ $mode = null, $options = null, $userinfo = null)
785
+ {
786
+ parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
787
+ }
788
+ }
789
+
790
+ } else {
791
+
792
+ /**
793
+ * @todo Ultimately, this class shall be descended from PEAR_Error
794
+ */
795
+ class Services_JSON_Error
796
+ {
797
+ function Services_JSON_Error($message = 'unknown error', $code = null,
798
+ $mode = null, $options = null, $userinfo = null)
799
+ {
800
+
801
+ }
802
+ }
803
+
804
+ }
805
+
806
+ ?>
cleantalk-admin.js CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  jQuery(document).ready(function(){
2
  var d = new Date();
3
  var n = d.getTimezoneOffset();
@@ -14,4 +17,25 @@ jQuery(document).ready(function(){
14
  //
15
  }
16
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  });
1
+ var ct_adv_settings=null;
2
+ var ct_adv_settings_title=null;
3
+ var ct_adv_settings_show=false;
4
  jQuery(document).ready(function(){
5
  var d = new Date();
6
  var n = d.getTimezoneOffset();
17
  //
18
  }
19
  });
20
+ ct_adv_settings=jQuery('#cleantalk_registrations_test1').parent().parent().parent().parent();
21
+ ct_adv_settings.hide();
22
+ ct_adv_settings_title=ct_adv_settings.prev();
23
+ ct_adv_settings.wrap("<div id='ct_advsettings_hide'>");
24
+ ct_adv_settings_title.append(" <span id='ct_adv_showhide' style='cursor:pointer'><b>+</b></span>");
25
+ ct_adv_settings_title.css('cursor','pointer');
26
+ ct_adv_settings_title.click(function(){
27
+ if(ct_adv_settings_show)
28
+ {
29
+ ct_adv_settings.hide();
30
+ ct_adv_settings_show=false;
31
+ jQuery('#ct_adv_showhide').html('+');
32
+ }
33
+ else
34
+ {
35
+ ct_adv_settings.show();
36
+ ct_adv_settings_show=true;
37
+ jQuery('#ct_adv_showhide').html('-');
38
+ }
39
+
40
+ });
41
  });
cleantalk-admin.php CHANGED
@@ -2,6 +2,8 @@
2
 
3
  $ct_plugin_basename = 'cleantalk-spam-protect/cleantalk.php';
4
 
 
 
5
  // Timeout to get app server
6
  $ct_server_timeout = 10;
7
 
@@ -10,6 +12,15 @@ $ct_server_timeout = 10;
10
  * Admin action 'admin_print_footer_scripts' - Enqueue admin script for checking if timezone offset is saved in settings
11
  */
12
 
 
 
 
 
 
 
 
 
 
13
 
14
  /**
15
  * Admin action 'wp_ajax_ajax_get_timezone' - Ajax method for getting timezone offset
@@ -49,10 +60,25 @@ function ct_admin_add_page() {
49
  * Admin action 'admin_init' - Add the admin settings and such
50
  */
51
  function ct_admin_init() {
52
- global $ct_server_timeout, $show_ct_notice_autokey, $ct_notice_autokey_label, $ct_notice_autokey_value, $show_ct_notice_renew, $ct_notice_renew_label, $show_ct_notice_trial, $ct_notice_trial_label, $show_ct_notice_online, $ct_notice_online_label, $renew_notice_showtime, $trial_notice_showtime, $ct_plugin_name, $ct_options, $ct_data, $trial_notice_check_timeout, $account_notice_check_timeout, $ct_user_token_label;
53
 
54
  $ct_options = ct_get_options();
55
  $ct_data = ct_get_data();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  $show_ct_notice_trial = false;
58
  if (isset($_COOKIE[$ct_notice_trial_label])) {
@@ -74,36 +100,16 @@ function ct_admin_init() {
74
  setcookie($ct_notice_autokey_label, '', 1, '/');
75
  }
76
  }
77
-
78
- if (isset($_POST['get_apikey_auto']) && function_exists('curl_init') && function_exists('json_decode')){
79
- $url = 'https://api.cleantalk.org';
80
- $data = array();
81
- $data['method_name'] = 'get_api_key';
82
- $data['email'] = get_option('admin_email');
83
- $data['website'] = parse_url(get_option('siteurl'),PHP_URL_HOST);
84
- $data['platform'] = 'wordpress';
85
- $data['timezone'] = $ct_data['timezone'];
86
- $data['locale'] = get_locale();
87
-
88
- $ch = curl_init();
89
- curl_setopt($ch, CURLOPT_URL, $url);
90
- curl_setopt($ch, CURLOPT_TIMEOUT, $ct_server_timeout);
91
- curl_setopt($ch, CURLOPT_POST, true);
92
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
93
-
94
- // receive server response ...
95
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
96
- // resolve 'Expect: 100-continue' issue
97
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
98
-
99
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
100
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
101
-
102
- $result = curl_exec($ch);
103
- curl_close($ch);
104
 
105
  if ($result) {
106
- $result = json_decode($result, true);
107
  if (isset($result['data']) && is_array($result['data'])) {
108
  $result = $result['data'];
109
  }
@@ -126,27 +132,7 @@ function ct_admin_init() {
126
  if (time() > $ct_data['next_account_status_check']) {
127
  $result = false;
128
  if (function_exists('curl_init') && function_exists('json_decode') && ct_valid_key($ct_options['apikey'])) {
129
- $url = 'https://api.cleantalk.org';
130
- $data = array();
131
- $data['method_name'] = 'notice_paid_till';
132
- $data['auth_key'] = $ct_options['apikey'];
133
-
134
- $ch = curl_init();
135
- curl_setopt($ch, CURLOPT_URL, $url);
136
- curl_setopt($ch, CURLOPT_TIMEOUT, $ct_server_timeout);
137
- curl_setopt($ch, CURLOPT_POST, true);
138
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
139
-
140
- // receive server response ...
141
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
142
- // resolve 'Expect: 100-continue' issue
143
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
144
-
145
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
146
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
147
-
148
- $result = curl_exec($ch);
149
- curl_close($ch);
150
 
151
  if ($result) {
152
  $result = json_decode($result, true);
@@ -202,9 +188,11 @@ function ct_admin_init() {
202
 
203
  register_setting('cleantalk_settings', 'cleantalk_settings', 'ct_settings_validate');
204
  add_settings_section('cleantalk_settings_main', __($ct_plugin_name, 'cleantalk'), 'ct_section_settings_main', 'cleantalk');
205
- add_settings_section('cleantalk_settings_anti_spam', __('Anti-spam settings', 'cleantalk'), 'ct_section_settings_anti_spam', 'cleantalk');
 
 
206
  add_settings_field('cleantalk_apikey', __('Access key', 'cleantalk'), 'ct_input_apikey', 'cleantalk', 'cleantalk_settings_main');
207
- add_settings_field('cleantalk_remove_old_spam', __('Automatically delete spam comments', 'cleantalk'), 'ct_input_remove_old_spam', 'cleantalk', 'cleantalk_settings_main');
208
 
209
  add_settings_field('cleantalk_registrations_test', __('Registration forms', 'cleantalk'), 'ct_input_registrations_test', 'cleantalk', 'cleantalk_settings_anti_spam');
210
  add_settings_field('cleantalk_comments_test', __('Comments form', 'cleantalk'), 'ct_input_comments_test', 'cleantalk', 'cleantalk_settings_anti_spam');
@@ -226,17 +214,127 @@ function ct_section_settings_anti_spam() {
226
  return true;
227
  }
228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  /**
230
  * Admin callback function - Displays inputs of 'apikey' plugin parameter
231
  */
232
  function ct_input_apikey() {
233
  global $ct_options, $ct_data, $ct_notice_online_label;
234
 
 
 
235
  $value = $ct_options['apikey'];
236
  $def_value = '';
237
  echo "<input id='cleantalk_apikey' name='cleantalk_settings[apikey]' size='20' type='text' value='$value' style=\"font-size: 14pt;\"/>";
238
  if (ct_valid_key($value) === false) {
239
- echo "<script src='".plugins_url( 'cleantalk-admin.js', __FILE__ )."'></script>\n";
240
  echo "<a target='__blank' style='margin-left: 10px' href='https://cleantalk.org/register?platform=wordpress&email=".urlencode(get_option('admin_email'))."&website=".urlencode(parse_url(get_option('siteurl'),PHP_URL_HOST))."'>".__('Click here to get access key manually', 'cleantalk')."</a>";
241
  if (function_exists('curl_init') && function_exists('json_decode')) {
242
  echo '<br /><br /><input name="get_apikey_auto" type="submit" value="' . __('Get access key automatically', 'cleantalk') . '" />';
@@ -245,7 +343,7 @@ function ct_input_apikey() {
245
  }
246
  } else {
247
  if (isset($_COOKIE[$ct_notice_online_label]) && $_COOKIE[$ct_notice_online_label] > 0) {
248
- echo '&nbsp;&nbsp;<span style="text-decoration: underline;">The key accepted!</span>&nbsp;<img src="' . plugin_dir_url(__FILE__) . 'inc/images/yes.png" alt="" height="" />';
249
  }
250
  echo "<br /><br /><a target='__blank' href='https://cleantalk.org/my?user_token=".@$ct_data['user_token']."'>".__('Click here to get anti-spam statistics', 'cleantalk')."</a>";
251
  }
@@ -358,7 +456,8 @@ input[type=submit] {padding: 10px; background: #3399FF; color: #fff; border:0 no
358
  <br />
359
  <br />
360
  <div>
361
- <?php echo __('Plugin Homepage at', 'cleantalk'); ?> <a href="http://cleantalk.org" target="_blank">cleantalk.org</a>.
 
362
  </div>
363
  <?php
364
  }
@@ -592,6 +691,7 @@ function ct_update_option($option_name) {
592
 
593
  $key_valid = true;
594
  $app_server_error = false;
 
595
  if (function_exists('curl_init') && function_exists('json_decode')) {
596
  $url = 'https://cleantalk.org/app_notice';
597
  $data['auth_key'] = $api_key;
@@ -617,13 +717,17 @@ function ct_update_option($option_name) {
617
  $result = json_decode($result, true);
618
  if (isset($result['valid']) && $result['valid'] == 0) {
619
  $key_valid = false;
 
620
  }
621
  }
622
  if (!$result || !isset($result['valid'])) {
623
  $app_server_error = true;
 
624
  }
625
  }
626
 
 
 
627
  if ($key_valid) {
628
  // Removes cookie for server errors
629
  if ($app_server_error) {
2
 
3
  $ct_plugin_basename = 'cleantalk-spam-protect/cleantalk.php';
4
 
5
+ require_once('cleantalk.class.php');
6
+
7
  // Timeout to get app server
8
  $ct_server_timeout = 10;
9
 
12
  * Admin action 'admin_print_footer_scripts' - Enqueue admin script for checking if timezone offset is saved in settings
13
  */
14
 
15
+ add_action( 'admin_print_footer_scripts', 'ct_add_stats_js' );
16
+
17
+ function ct_add_stats_js()
18
+ {
19
+ echo "<script src='".plugins_url( 'cleantalk-stats.js', __FILE__ )."'></script>\n";
20
+ }
21
+
22
+
23
+
24
 
25
  /**
26
  * Admin action 'wp_ajax_ajax_get_timezone' - Ajax method for getting timezone offset
60
  * Admin action 'admin_init' - Add the admin settings and such
61
  */
62
  function ct_admin_init() {
63
+ global $ct_server_timeout, $show_ct_notice_autokey, $ct_notice_autokey_label, $ct_notice_autokey_value, $show_ct_notice_renew, $ct_notice_renew_label, $show_ct_notice_trial, $ct_notice_trial_label, $show_ct_notice_online, $ct_notice_online_label, $renew_notice_showtime, $trial_notice_showtime, $ct_plugin_name, $ct_options, $ct_data, $trial_notice_check_timeout, $account_notice_check_timeout, $ct_user_token_label, $cleantalk_plugin_version;
64
 
65
  $ct_options = ct_get_options();
66
  $ct_data = ct_get_data();
67
+
68
+ $current_version=@trim($ct_data['current_version']);
69
+ if($current_version!=$cleantalk_plugin_version)
70
+ {
71
+ $ct_data['current_version']=$cleantalk_plugin_version;
72
+ update_option('cleantalk_data', $ct_data);
73
+ $ct_base_call_result = ct_base_call(array(
74
+ 'message' => 'CleanTalk connection test',
75
+ 'example' => null,
76
+ 'sender_email' => 'stop_email@example.com',
77
+ 'sender_nickname' => 'CleanTalk',
78
+ 'post_info' => '',
79
+ 'checkjs' => 1
80
+ ));
81
+ }
82
 
83
  $show_ct_notice_trial = false;
84
  if (isset($_COOKIE[$ct_notice_trial_label])) {
100
  setcookie($ct_notice_autokey_label, '', 1, '/');
101
  }
102
  }
103
+
104
+ if (isset($_POST['get_apikey_auto'])){
105
+ $email = get_option('admin_email');
106
+ $website = parse_url(get_option('siteurl'),PHP_URL_HOST);
107
+ $platform = 'wordpress';
108
+
109
+ $result = getAutoKey($email, $website, $platform);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  if ($result) {
112
+ $result = json_decode($result, true);
113
  if (isset($result['data']) && is_array($result['data'])) {
114
  $result = $result['data'];
115
  }
132
  if (time() > $ct_data['next_account_status_check']) {
133
  $result = false;
134
  if (function_exists('curl_init') && function_exists('json_decode') && ct_valid_key($ct_options['apikey'])) {
135
+ $result=noticePaidTill($ct_options['apikey']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  if ($result) {
138
  $result = json_decode($result, true);
188
 
189
  register_setting('cleantalk_settings', 'cleantalk_settings', 'ct_settings_validate');
190
  add_settings_section('cleantalk_settings_main', __($ct_plugin_name, 'cleantalk'), 'ct_section_settings_main', 'cleantalk');
191
+ add_settings_section('cleantalk_settings_state', "<hr>".__('Protection is active for:', 'cleantalk'), 'ct_section_settings_state', 'cleantalk');
192
+ //add_settings_section('cleantalk_settings_autodel', "<hr>", 'ct_section_settings_autodel', 'cleantalk');
193
+ add_settings_section('cleantalk_settings_anti_spam', "<hr>".__('Advanced settings', 'cleantalk'), 'ct_section_settings_anti_spam', 'cleantalk');
194
  add_settings_field('cleantalk_apikey', __('Access key', 'cleantalk'), 'ct_input_apikey', 'cleantalk', 'cleantalk_settings_main');
195
+ add_settings_field('cleantalk_remove_old_spam', __('Automatically delete spam comments', 'cleantalk'), 'ct_input_remove_old_spam', 'cleantalk', 'cleantalk_settings_anti_spam');
196
 
197
  add_settings_field('cleantalk_registrations_test', __('Registration forms', 'cleantalk'), 'ct_input_registrations_test', 'cleantalk', 'cleantalk_settings_anti_spam');
198
  add_settings_field('cleantalk_comments_test', __('Comments form', 'cleantalk'), 'ct_input_comments_test', 'cleantalk', 'cleantalk_settings_anti_spam');
214
  return true;
215
  }
216
 
217
+ add_action( 'admin_bar_menu', 'ct_add_admin_menu', 999 );
218
+
219
+ function ct_add_admin_menu( $wp_admin_bar ) {
220
+ // add a parent item
221
+ if ( current_user_can('activate_plugins') )
222
+ {
223
+ $ct_data=ct_get_data();
224
+ $args = array(
225
+ 'id' => 'ct_parent_node',
226
+ 'title' => '<img src="' . plugin_dir_url(__FILE__) . 'inc/images/logo_small1.png" alt="" height="" style="margin-top:9px;" /><a href="#" class="ab-item alignright" title="allowed / blocked" alt="allowed / blocked"><span class="ab-label" id="ct_stats"></span></a>'
227
+ );
228
+ $wp_admin_bar->add_node( $args );
229
+
230
+ // add a child item to our parent item
231
+ $args = array(
232
+ 'id' => 'ct_dashboard_link',
233
+ 'title' => '<a href="https://cleantalk.org/my/?user_token='.@$ct_data['user_token'].'" target="_blank">CleanTalk dashboard</a>',
234
+ 'parent' => 'ct_parent_node'
235
+ );
236
+ $wp_admin_bar->add_node( $args );
237
+
238
+ // add another child item to our parent item (not to our first group)
239
+ $args = array(
240
+ 'id' => 'ct_settings_link',
241
+ 'title' => '<a href="options-general.php?page=cleantalk">Settings</a>',
242
+ 'parent' => 'ct_parent_node'
243
+ );
244
+ $wp_admin_bar->add_node( $args );
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Admin callback function - Displays description of 'state' plugin parameters section
250
+ */
251
+ function ct_section_settings_state() {
252
+ global $ct_options, $ct_data;
253
+
254
+ //print_r($ct_options);
255
+
256
+ $img="yes.png";
257
+ $img_no="no.png";
258
+ $color="black";
259
+ $test_failed=false;
260
+ //if(isset($ct_data['testing_failed'])&&$ct_data['testing_failed']==1)
261
+ if(trim($ct_options['apikey'])=='')
262
+ {
263
+ $img="yes_gray.png";
264
+ $img_no="no_gray.png";
265
+ $color="gray";
266
+ }
267
+ if(isset($ct_data['testing_failed'])&&$ct_data['testing_failed']==1)
268
+ {
269
+ $img="no.png";
270
+ $img_no="no.png";
271
+ $color="black";
272
+ $test_failed=true;
273
+ }
274
+ print "<div style='color:$color'>";
275
+ if($ct_options['registrations_test']==1)
276
+ {
277
+ print '<img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img.'" alt="" height="" /> '.__('Registration forms', 'cleantalk');
278
+ }
279
+ else
280
+ {
281
+ print '<img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img_no.'" alt="" height="" /> '.__('Registration forms', 'cleantalk');
282
+ }
283
+
284
+ if($ct_options['comments_test']==1)
285
+ {
286
+ print ' &nbsp; <img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img.'" alt="" height="" /> '.__('Comments form', 'cleantalk');
287
+ }
288
+ else
289
+ {
290
+ print ' &nbsp; <img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img_no.'" alt="" height="" /> '.__('Comments form', 'cleantalk');
291
+ }
292
+
293
+ if($ct_options['contact_forms_test']==1)
294
+ {
295
+ print ' &nbsp; <img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img.'" alt="" height="" /> '.__('Contact forms', 'cleantalk');
296
+ }
297
+ else
298
+ {
299
+ print ' &nbsp; <img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img_no.'" alt="" height="" /> '.__('Contact forms', 'cleantalk');
300
+ }
301
+
302
+ if($ct_options['general_contact_forms_test']==1)
303
+ {
304
+ print ' &nbsp; <img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img.'" alt="" height="" /> '.__('Custom contact forms', 'cleantalk');
305
+ }
306
+ else
307
+ {
308
+ print ' &nbsp; <img src="' . plugin_dir_url(__FILE__) . 'inc/images/'.$img_no.'" alt="" height="" /> '.__('Custom contact forms', 'cleantalk');
309
+ }
310
+ print "</div>";
311
+ if($test_failed)
312
+ {
313
+ print "Testing is failed, check settings. Tech support <a target=_blank href='mailto:support@cleantalk.org'>support@cleantalk.org</a>";
314
+ }
315
+ return true;
316
+ }
317
+
318
+ /**
319
+ * Admin callback function - Displays description of 'autodel' plugin parameters section
320
+ */
321
+ function ct_section_settings_autodel() {
322
+ return true;
323
+ }
324
+
325
  /**
326
  * Admin callback function - Displays inputs of 'apikey' plugin parameter
327
  */
328
  function ct_input_apikey() {
329
  global $ct_options, $ct_data, $ct_notice_online_label;
330
 
331
+ echo "<script src='".plugins_url( 'cleantalk-admin.js', __FILE__ )."'></script>\n";
332
+
333
  $value = $ct_options['apikey'];
334
  $def_value = '';
335
  echo "<input id='cleantalk_apikey' name='cleantalk_settings[apikey]' size='20' type='text' value='$value' style=\"font-size: 14pt;\"/>";
336
  if (ct_valid_key($value) === false) {
337
+
338
  echo "<a target='__blank' style='margin-left: 10px' href='https://cleantalk.org/register?platform=wordpress&email=".urlencode(get_option('admin_email'))."&website=".urlencode(parse_url(get_option('siteurl'),PHP_URL_HOST))."'>".__('Click here to get access key manually', 'cleantalk')."</a>";
339
  if (function_exists('curl_init') && function_exists('json_decode')) {
340
  echo '<br /><br /><input name="get_apikey_auto" type="submit" value="' . __('Get access key automatically', 'cleantalk') . '" />';
343
  }
344
  } else {
345
  if (isset($_COOKIE[$ct_notice_online_label]) && $_COOKIE[$ct_notice_online_label] > 0) {
346
+ echo '&nbsp;&nbsp;<span style="text-decoration: underline;">The key accepted!</span>&nbsp;';
347
  }
348
  echo "<br /><br /><a target='__blank' href='https://cleantalk.org/my?user_token=".@$ct_data['user_token']."'>".__('Click here to get anti-spam statistics', 'cleantalk')."</a>";
349
  }
456
  <br />
457
  <br />
458
  <div>
459
+ <?php echo __('Plugin Homepage at', 'cleantalk'); ?> <a href="http://cleantalk.org" target="_blank">cleantalk.org</a>.<br />
460
+ <?php echo __('Tech support CleanTalk:', 'cleantalk'); ?> <a href="https://cleantalk.org/forum/viewforum.php?f=25" target="_blank"><?php echo __('CleanTalk tech forum', 'cleantalk'); ?></a>.<br />
461
  </div>
462
  <?php
463
  }
691
 
692
  $key_valid = true;
693
  $app_server_error = false;
694
+ $ct_data['testing_failed']=0;
695
  if (function_exists('curl_init') && function_exists('json_decode')) {
696
  $url = 'https://cleantalk.org/app_notice';
697
  $data['auth_key'] = $api_key;
717
  $result = json_decode($result, true);
718
  if (isset($result['valid']) && $result['valid'] == 0) {
719
  $key_valid = false;
720
+ $ct_data['testing_failed']=1;
721
  }
722
  }
723
  if (!$result || !isset($result['valid'])) {
724
  $app_server_error = true;
725
+ $ct_data['testing_failed']=1;
726
  }
727
  }
728
 
729
+ update_option('cleantalk_data', $ct_data);
730
+
731
  if ($key_valid) {
732
  // Removes cookie for server errors
733
  if ($app_server_error) {
cleantalk-ajax.php CHANGED
@@ -41,6 +41,44 @@ add_action( 'wp_ajax_request_appointment', 'ct_sm_ra',1 );
41
  add_action( 'wp_ajax_nopriv_zn_do_login', 'ct_zn_do_login',1 );
42
  add_action( 'wp_ajax_zn_do_login', 'ct_zn_do_login',1 );
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  function ct_validate_email_ajaxlogin($email=null, $is_ajax=true)
46
  {
@@ -532,7 +570,64 @@ function ct_zn_do_login()
532
  }
533
  }
534
 
 
 
 
 
 
 
 
 
 
 
 
535
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  function ct_get_fields(&$email,&$message,$arr)
537
  {
538
  foreach($arr as $key=>$value)
41
  add_action( 'wp_ajax_nopriv_zn_do_login', 'ct_zn_do_login',1 );
42
  add_action( 'wp_ajax_zn_do_login', 'ct_zn_do_login',1 );
43
 
44
+ /*hooks for zn_do_login */
45
+ add_action( 'wp_ajax_nopriv_cscf-submitform', 'ct_cscf_submitform',1 );
46
+ add_action( 'wp_ajax_cscf-submitform', 'ct_cscf_submitform',1 );
47
+
48
+ /*hooks for stats */
49
+ add_action( 'wp_ajax_nopriv_ajax_get_stats', 'ct_get_stats',1 );
50
+ add_action( 'wp_ajax_ajax_get_stats', 'ct_get_stats',1 );
51
+
52
+ function ct_get_stats()
53
+ {
54
+ check_ajax_referer( 'ct_secret_nonce', 'security' );
55
+ global $ct_data;
56
+ $ct_data=ct_get_data();
57
+ $t=time();
58
+
59
+ if(!isset($ct_data['stat_accepted']))
60
+ {
61
+ $ct_data['stat_accepted']=0;
62
+ $ct_data['stat_blocked']=0;
63
+ $ct_data['stat_all']=0;
64
+ $ct_data['last_time']=$t;
65
+ update_option('cleantalk_data', $ct_data);
66
+ }
67
+
68
+ $last_time=intval($ct_data['last_time']);
69
+ if($t-$last_time>86400)
70
+ {
71
+ $ct_data['stat_accepted']=0;
72
+ $ct_data['stat_blocked']=0;
73
+ $ct_data['stat_all']=0;
74
+ $ct_data['last_time']=$t;
75
+ update_option('cleantalk_data', $ct_data);
76
+ }
77
+
78
+ $ret=Array('stat_accepted'=>$ct_data['stat_accepted'],'stat_blocked'=>$ct_data['stat_blocked'],'stat_all'=>$ct_data['stat_all']);
79
+ print json_encode($ret);
80
+ die();
81
+ }
82
 
83
  function ct_validate_email_ajaxlogin($email=null, $is_ajax=true)
84
  {
570
  }
571
  }
572
 
573
+ function ct_cscf_submitform()
574
+ {
575
+ require_once(CLEANTALK_PLUGIN_DIR . 'cleantalk-public.php');
576
+ global $ct_agent_version, $ct_checkjs_register_form, $ct_session_request_id_label, $ct_session_register_ok_label, $bp, $ct_signup_done, $ct_formtime_label, $ct_negative_comment, $ct_options, $ct_data;
577
+
578
+ $ct_data=ct_get_data();
579
+
580
+ $ct_options=ct_get_options();
581
+
582
+ $sender_email = null;
583
+ $message = '';
584
 
585
+ if(isset($_POST['cscf']['confirm-email']))
586
+ {
587
+ $tmp=$_POST['cscf']['confirm-email'];
588
+ $_POST['cscf']['confirm-email']=1;
589
+ }
590
+
591
+ ct_get_fields($sender_email,$message,$_POST);
592
+
593
+ if(isset($_POST['cscf']['confirm-email']))
594
+ {
595
+ $_POST['cscf']['confirm-email']=$tmp;
596
+ }
597
+
598
+
599
+ if($sender_email!=null)
600
+ {
601
+ $checkjs = js_test('ct_checkjs', $_COOKIE, true);
602
+ $submit_time = submit_time_test();
603
+ $sender_info = get_sender_info();
604
+ $sender_info['post_checkjs_passed']=$checkjs;
605
+
606
+ $sender_info = json_encode($sender_info);
607
+ if ($sender_info === false)
608
+ {
609
+ $sender_info= '';
610
+ }
611
+
612
+ $ct_base_call_result = ct_base_call(array(
613
+ 'message' => $message,
614
+ 'example' => null,
615
+ 'sender_email' => $sender_email,
616
+ 'sender_nickname' => null,
617
+ 'sender_info' => $sender_info,
618
+ 'post_info'=>null,
619
+ 'checkjs' => $checkjs));
620
+
621
+ $ct = $ct_base_call_result['ct'];
622
+ $ct_result = $ct_base_call_result['ct_result'];
623
+ if ($ct_result->allow == 0)
624
+ {
625
+ $result=Array('sent'=>true,'valid'=>false,'errorlist'=>Array('name'=>$ct_result->comment));
626
+ print json_encode($result);
627
+ die();
628
+ }
629
+ }
630
+ }
631
  function ct_get_fields(&$email,&$message,$arr)
632
  {
633
  foreach($arr as $key=>$value)
cleantalk-comments.php CHANGED
@@ -240,10 +240,11 @@ function ct_ajax_check_comments()
240
  'compare' => 'NOT EXISTS'
241
  )
242
  ),
243
- 'number'=>999
244
  );
245
 
246
  $u=get_comments($args_unchecked);
 
247
  if(sizeof($u)>0)
248
  {
249
  //print_r($unchecked);
240
  'compare' => 'NOT EXISTS'
241
  )
242
  ),
243
+ 'number'=>500
244
  );
245
 
246
  $u=get_comments($args_unchecked);
247
+ $u=array_slice($u,0,500);
248
  if(sizeof($u)>0)
249
  {
250
  //print_r($unchecked);
cleantalk-common.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- $ct_agent_version = 'wordpress-53';
4
  $ct_plugin_name = 'Anti-spam by CleanTalk';
5
  $ct_checkjs_frm = 'ct_checkjs_frm';
6
  $ct_checkjs_register_form = 'ct_checkjs_register_form';
@@ -182,6 +182,11 @@ function ct_base_call($params = array()) {
182
  // Restart submit form counter for failed requests
183
  if ($ct_result->allow == 0) {
184
  $_SESSION[$ct_formtime_label] = time();
 
 
 
 
 
185
  }
186
 
187
  return array('ct' => $ct, 'ct_result' => $ct_result);
@@ -284,6 +289,7 @@ function ct_cookies_test ($test = false) {
284
  */
285
  function ct_get_checkjs_value($random_key = false) {
286
  global $ct_options, $ct_data;
 
287
 
288
  if ($random_key) {
289
  $keys = $ct_data['js_keys'];
1
  <?php
2
 
3
+ $ct_agent_version = 'wordpress-54';
4
  $ct_plugin_name = 'Anti-spam by CleanTalk';
5
  $ct_checkjs_frm = 'ct_checkjs_frm';
6
  $ct_checkjs_register_form = 'ct_checkjs_register_form';
182
  // Restart submit form counter for failed requests
183
  if ($ct_result->allow == 0) {
184
  $_SESSION[$ct_formtime_label] = time();
185
+ ct_add_event('no');
186
+ }
187
+ else
188
+ {
189
+ ct_add_event('yes');
190
  }
191
 
192
  return array('ct' => $ct, 'ct_result' => $ct_result);
289
  */
290
  function ct_get_checkjs_value($random_key = false) {
291
  global $ct_options, $ct_data;
292
+ $ct_data=ct_get_data();
293
 
294
  if ($random_key) {
295
  $keys = $ct_data['js_keys'];
cleantalk-public.php CHANGED
@@ -8,7 +8,6 @@ function ct_init() {
8
  global $ct_wplp_result_label, $ct_jp_comments, $ct_post_data_label, $ct_post_data_authnet_label, $ct_formtime_label, $ct_direct_post, $ct_options, $ct_data;
9
 
10
  $ct_options = ct_get_options();
11
- $ct_data = ct_get_data();
12
 
13
  ct_init_session();
14
 
@@ -1083,15 +1082,15 @@ function ct_wpcf7_spam($param) {
1083
  if ($sender_email === null && preg_match("/^\S+@\S+\.\S+$/", $v)) {
1084
  $sender_email = $v;
1085
  }
1086
- if ($message === '' && preg_match("/(\-message|\w*message\w*|contact|comment)$/", $k)) {
1087
- $message = $v;
1088
- }
1089
- if ($sender_nickname === null && preg_match("/-name$/", $k)) {
1090
  $sender_nickname = $v;
1091
  }
1092
- if ($subject === '' && ct_get_data_from_submit($k, 'subject')) {
1093
  $subject = $v;
1094
  }
 
 
 
1095
 
1096
  }
1097
 
@@ -1376,7 +1375,9 @@ function ct_contact_form_validate () {
1376
  global $pagenow;
1377
 
1378
  if ($_SERVER['REQUEST_METHOD'] != 'POST' ||
1379
- (isset($_POST['log']) && isset($_POST['pwd']) && isset($pagenow) && $pagenow == 'wp-login.php') // WordPress log in form
 
 
1380
  ) {
1381
  return null;
1382
  }
8
  global $ct_wplp_result_label, $ct_jp_comments, $ct_post_data_label, $ct_post_data_authnet_label, $ct_formtime_label, $ct_direct_post, $ct_options, $ct_data;
9
 
10
  $ct_options = ct_get_options();
 
11
 
12
  ct_init_session();
13
 
1082
  if ($sender_email === null && preg_match("/^\S+@\S+\.\S+$/", $v)) {
1083
  $sender_email = $v;
1084
  }
1085
+ else if ($sender_nickname === null && preg_match("/-name$/", $k)) {
 
 
 
1086
  $sender_nickname = $v;
1087
  }
1088
+ else if ($subject === '' && ct_get_data_from_submit($k, 'subject')) {
1089
  $subject = $v;
1090
  }
1091
+ else {
1092
+ $message .= $v."\n";
1093
+ }
1094
 
1095
  }
1096
 
1375
  global $pagenow;
1376
 
1377
  if ($_SERVER['REQUEST_METHOD'] != 'POST' ||
1378
+ (isset($_POST['log']) && isset($_POST['pwd']) && isset($pagenow) && $pagenow == 'wp-login.php') || // WordPress log in form
1379
+ (isset($pagenow) && $pagenow == 'wp-login.php' && isset($_GET['action']) && $_GET['action']=='lostpassword') ||
1380
+ defined('JETPACK__VERSION')
1381
  ) {
1382
  return null;
1383
  }
cleantalk-stats.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function ct_update_stats()
2
+ {
3
+ var data = {
4
+ 'action': 'ajax_get_stats',
5
+ 'security': ajax_nonce
6
+ };
7
+ jQuery.ajax({
8
+ type: "POST",
9
+ url: ajaxurl,
10
+ data: data,
11
+ dataType: 'json',
12
+ success: function(msg){
13
+ jQuery('#ct_stats').html('<span>' + msg.stat_accepted + '</span> / <span>' + msg.stat_blocked + '</span>');
14
+ setTimeout(ct_update_stats,5000);
15
+ }
16
+ });
17
+ }
18
+ jQuery(document).ready(function(){
19
+ ct_update_stats();
20
+ });
cleantalk.class.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Cleantalk base class
4
  *
5
- * @version 1.35
6
  * @package Cleantalk
7
  * @subpackage Base
8
  * @author Cleantalk team (welcome@cleantalk.org)
@@ -43,7 +43,7 @@ class CleantalkResponse {
43
  * @var int
44
  */
45
  public $stop_words = null;
46
-
47
  /**
48
  * Cleantalk comment
49
  * @var string
@@ -185,6 +185,12 @@ class CleantalkResponse {
185
  */
186
  class CleantalkRequest {
187
 
 
 
 
 
 
 
188
  /**
189
  * User message
190
  * @var string
@@ -664,6 +670,7 @@ class Cleantalk {
664
  */
665
  private function httpRequest($msg) {
666
  $result = false;
 
667
  if (((isset($this->work_url) && $this->work_url !== '') && ($this->server_changed + $this->server_ttl > time()))
668
  || $this->stay_on_server == true) {
669
 
@@ -960,4 +967,121 @@ class Cleantalk {
960
  }
961
  }
962
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963
  ?>
2
  /**
3
  * Cleantalk base class
4
  *
5
+ * @version 2.0
6
  * @package Cleantalk
7
  * @subpackage Base
8
  * @author Cleantalk team (welcome@cleantalk.org)
43
  * @var int
44
  */
45
  public $stop_words = null;
46
+
47
  /**
48
  * Cleantalk comment
49
  * @var string
185
  */
186
  class CleantalkRequest {
187
 
188
+ /**
189
+ * All http request headers
190
+ * @var string
191
+ */
192
+ public $all_headers = null;
193
+
194
  /**
195
  * User message
196
  * @var string
670
  */
671
  private function httpRequest($msg) {
672
  $result = false;
673
+ $msg->all_headers=json_encode(apache_request_headers());
674
  if (((isset($this->work_url) && $this->work_url !== '') && ($this->server_changed + $this->server_ttl > time()))
675
  || $this->stay_on_server == true) {
676
 
967
  }
968
  }
969
 
970
+ /**
971
+ * Function gets access key automatically
972
+ *
973
+ * @param string website admin email
974
+ * @param string website host
975
+ * @param string website platform
976
+ * @return type
977
+ */
978
+
979
+ function getAutoKey($email, $host, $platform)
980
+ {
981
+ $request=Array();
982
+ $request['method_name'] = 'get_api_key';
983
+ $request['email'] = $email;
984
+ $request['website'] = $host;
985
+ $request['platform'] = $platform;
986
+ $url='https://api.cleantalk.org';
987
+ $result=sendRawRequest($url,$request);
988
+ return $result;
989
+ }
990
+
991
+ /**
992
+ * Function gets information about renew notice
993
+ *
994
+ * @param string api_key
995
+ * @return type
996
+ */
997
+
998
+ function noticePaidTill($api_key)
999
+ {
1000
+ $request=Array();
1001
+ $request['method_name'] = 'notice_paid_till';
1002
+ $request['auth_key'] = $api_key;
1003
+ $url='https://api.cleantalk.org';
1004
+ $result=sendRawRequest($url,$request);
1005
+ return $result;
1006
+ }
1007
+
1008
+ /**
1009
+ * Function sends raw request to API server
1010
+ *
1011
+ * @param string url of API server
1012
+ * @param array data to send
1013
+ * @param boolean is data have to be JSON encoded or not
1014
+ * @param integer connect timeout
1015
+ * @return type
1016
+ */
1017
+
1018
+ function sendRawRequest($url,$data,$isJSON=false,$timeout=3)
1019
+ {
1020
+ $result=null;
1021
+ if(!$isJSON)
1022
+ {
1023
+ $data=http_build_query($data);
1024
+ }
1025
+ else
1026
+ {
1027
+ $data= json_encode($data);
1028
+ }
1029
+ if (function_exists('curl_init') && function_exists('json_decode'))
1030
+ {
1031
+
1032
+ $ch = curl_init();
1033
+ curl_setopt($ch, CURLOPT_URL, $url);
1034
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1035
+ curl_setopt($ch, CURLOPT_POST, true);
1036
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
1037
+
1038
+ // receive server response ...
1039
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1040
+ // resolve 'Expect: 100-continue' issue
1041
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
1042
+
1043
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
1044
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
1045
+
1046
+ $result = curl_exec($ch);
1047
+ curl_close($ch);
1048
+ }
1049
+ else
1050
+ {
1051
+ $opts = array(
1052
+ 'http'=>array(
1053
+ 'method'=>"POST",
1054
+ 'content'=>$data)
1055
+ );
1056
+ $context = stream_context_create($opts);
1057
+ $result = @file_get_contents($url, 0, $context);
1058
+ }
1059
+ return $result;
1060
+ }
1061
+
1062
+ if( !function_exists('apache_request_headers') )
1063
+ {
1064
+ function apache_request_headers()
1065
+ {
1066
+ $arh = array();
1067
+ $rx_http = '/\AHTTP_/';
1068
+ foreach($_SERVER as $key => $val)
1069
+ {
1070
+ if( preg_match($rx_http, $key) )
1071
+ {
1072
+ $arh_key = preg_replace($rx_http, '', $key);
1073
+ $rx_matches = array();
1074
+ $rx_matches = explode('_', $arh_key);
1075
+ if( count($rx_matches) > 0 and strlen($arh_key) > 2 )
1076
+ {
1077
+ foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val);
1078
+ $arh_key = implode('-', $rx_matches);
1079
+ }
1080
+ $arh[$arh_key] = $val;
1081
+ }
1082
+ }
1083
+ return( $arh );
1084
+ }
1085
+ }
1086
+
1087
  ?>
cleantalk.php CHANGED
@@ -3,10 +3,11 @@
3
  Plugin Name: Anti-spam by CleanTalk
4
  Plugin URI: http://cleantalk.org
5
  Description: Max power, all-in-one, captcha less, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
6
- Version: 5.3
7
  Author: СleanTalk <welcome@cleantalk.org>
8
  Author URI: http://cleantalk.org
9
  */
 
10
 
11
  if(!defined('CLEANTALK_PLUGIN_DIR')){
12
  define('CLEANTALK_PLUGIN_DIR', plugin_dir_path(__FILE__));
@@ -111,6 +112,23 @@ function ct_plugin_redirect()
111
  }
112
  }
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  require_once(CLEANTALK_PLUGIN_DIR . 'cleantalk-comments.php');
116
 
3
  Plugin Name: Anti-spam by CleanTalk
4
  Plugin URI: http://cleantalk.org
5
  Description: Max power, all-in-one, captcha less, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
6
+ Version: 5.4
7
  Author: СleanTalk <welcome@cleantalk.org>
8
  Author URI: http://cleantalk.org
9
  */
10
+ $cleantalk_plugin_version='5.4';
11
 
12
  if(!defined('CLEANTALK_PLUGIN_DIR')){
13
  define('CLEANTALK_PLUGIN_DIR', plugin_dir_path(__FILE__));
112
  }
113
  }
114
 
115
+ function ct_add_event($event_type)
116
+ {
117
+ global $ct_data;
118
+ $ct_data = ct_get_data();
119
+ $t=time();
120
+ if($event_type=='yes')
121
+ {
122
+ @$ct_data['stat_accepted']++;
123
+ }
124
+ if($event_type=='no')
125
+ {
126
+ @$ct_data['stat_blocked']++;
127
+ }
128
+ $ct_data['stat_all']++;
129
+ update_option('cleantalk_data', $ct_data);
130
+ }
131
+
132
 
133
  require_once(CLEANTALK_PLUGIN_DIR . 'cleantalk-comments.php');
134
 
inc/images/logo.png ADDED
Binary file
inc/images/logo_small.png ADDED
Binary file
inc/images/logo_small1.png ADDED
Binary file
inc/images/no.png ADDED
Binary file
inc/images/no_gray.png ADDED
Binary file
inc/images/yes.png CHANGED
Binary file
inc/images/yes2.png ADDED
Binary file
inc/images/yes_gray.png ADDED
Binary file
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: znaeff, shagimuratov, vlad-cleantalk
3
  Tags: akismet, anti-spam, antispam, bbpress spam, buddypress spam, captcha antispam, cf7 spam, comments spam, contact form spam, form, Formidable spam, jetpack spam, math, registration spam, s2member spam, signup spam, spam, spammers, spammy, WooCommerce spam, wordpress spam, booking spam, order spam, subscriptions spam, comments, gravity spam, gravity forms spam, widget, widget antispam, registration
4
  Requires at least: 3.0
5
  Tested up to: 4.2
6
- Stable tag: 5.3
7
  License: GPLv2
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -181,6 +181,10 @@ WordPress 3.0 at least. PHP 5 with CURL or file_get_contents() function and enab
181
  1. Setup Android/iOS app to have push notices when new legitiamte comments/registrations or contactcs appears on the website.
182
 
183
  == Changelog ==
 
 
 
 
184
  = 5.3 2015-04-13 =
185
  * Added anti-spam protection for Divi theme contact forms
186
  * Added anti-spam protection for MyMail contact forms
@@ -546,6 +550,10 @@ WordPress 3.0 at least. PHP 5 with CURL or file_get_contents() function and enab
546
  * First version
547
 
548
  == Upgrade Notice ==
 
 
 
 
549
  = 5.3 2015-04-13 =
550
  * Added anti-spam protection for Divi theme contact forms
551
  * Added anti-spam protection for MyMail contact forms
3
  Tags: akismet, anti-spam, antispam, bbpress spam, buddypress spam, captcha antispam, cf7 spam, comments spam, contact form spam, form, Formidable spam, jetpack spam, math, registration spam, s2member spam, signup spam, spam, spammers, spammy, WooCommerce spam, wordpress spam, booking spam, order spam, subscriptions spam, comments, gravity spam, gravity forms spam, widget, widget antispam, registration
4
  Requires at least: 3.0
5
  Tested up to: 4.2
6
+ Stable tag: 5.4
7
  License: GPLv2
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
181
  1. Setup Android/iOS app to have push notices when new legitiamte comments/registrations or contactcs appears on the website.
182
 
183
  == Changelog ==
184
+ = 5.4 2015-04-27 =
185
+ * Some interface and functionality changes in plugin settings page
186
+ * Added counter for anti-spam statistics in admin bar
187
+
188
  = 5.3 2015-04-13 =
189
  * Added anti-spam protection for Divi theme contact forms
190
  * Added anti-spam protection for MyMail contact forms
550
  * First version
551
 
552
  == Upgrade Notice ==
553
+ = 5.4 2015-04-27 =
554
+ * Some interface and functionality changes in plugin settings page
555
+ * Added counter for anti-spam statistics in admin bar
556
+
557
  = 5.3 2015-04-13 =
558
  * Added anti-spam protection for Divi theme contact forms
559
  * Added anti-spam protection for MyMail contact forms