Merge lp:~t7-vla7-lz/psiphon/psiphon into lp:psiphon

Proposed by Vlad
Status: Merged
Merged at revision: 308
Proposed branch: lp:~t7-vla7-lz/psiphon/psiphon
Merge into: lp:psiphon
Diff against target: 517 lines (+255/-178)
6 files modified
trunk/cronjobs/cleanup_sessions_captcha_cron.php (+49/-0)
trunk/cronjobs/crontab (+5/-4)
trunk/sql/upgrades/upgrade-2.7.010.sql (+9/-0)
trunk/www/create_account.php (+27/-8)
trunk/www/image-code.php (+74/-166)
trunk/www/includes/sess.php (+91/-0)
To merge this branch: bzr merge lp:~t7-vla7-lz/psiphon/psiphon
Reviewer Review Type Date Requested Status
e.fryntov Approve
Review via email: mp+116756@code.launchpad.net

Description of the change

Replacing Captcha, based on php sessions to the new one, based on mysql sessions (includes/sess.php).

It is necessary to replace file-based php sessions to mysql-based for ability to create a mirrored servers (N * apache/php servers connected to a single database).

To post a comment you must log in.
Revision history for this message
e.fryntov (e-fryntov) wrote :

the SQL upgrade script should be placed into the sql/upgrade/ directory, otherwise it will not be executed by automation script. I need to update the old README

review: Needs Fixing
Revision history for this message
e.fryntov (e-fryntov) :
review: Approve
lp:~t7-vla7-lz/psiphon/psiphon updated
307. By e-fryntov

Removed console.debug(..) from the JS

308. By e-fryntov

Merged Vlad's mysql session for CAPTCHA branch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'trunk/cronjobs/cleanup_sessions_captcha_cron.php'
--- trunk/cronjobs/cleanup_sessions_captcha_cron.php 1970-01-01 00:00:00 +0000
+++ trunk/cronjobs/cleanup_sessions_captcha_cron.php 2012-07-26 17:56:19 +0000
@@ -0,0 +1,49 @@
1<?
2/*
3 Psiphon Circumvention Platform
4 Copyright (C) 2009 Psiphon Inc.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20// Add to crontab (to have it run once a day):
21//
22// 15 3 * * * /usr/local/bin/php /home/ppcron/cronjobs/cleanup_sessions_captcha_cron.php
23//
24
25// pwd of a cronjob seems to be the cron user's (ppcron) home directory.
26// This messes up includes, so we're going to explicitly use the directory
27// of this file.
28$current_directory = substr($argv[0], 0, strrpos($argv[0], "/"));
29
30//
31// Remove expired mysql-sessions used in captcha
32// Any session older than 1 day is deleted.
33//
34$_SERVER["DOCUMENT_ROOT"] = $current_directory;
35include($current_directory."/config.php");
36
37include($current_directory."/includes/sql_error_cli.php");
38
39// Clean up expired sessions
40
41$query = "DELETE FROM sess WHERE updated < :expire";
42
43if (!db_query_execute($config, $query, convert_null_array(array(":expire" => strftime("%Y%m%d%H%M%S", time() - 86400))), true))
44{
45 sql_error_cli($query, $config['sql']);
46}
47
48exit(0);
49?>
050
=== modified file 'trunk/cronjobs/crontab'
--- trunk/cronjobs/crontab 2011-05-17 21:34:54 +0000
+++ trunk/cronjobs/crontab 2012-07-26 17:56:19 +0000
@@ -1,4 +1,5 @@
13 2 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_invitations_cron.php110 4 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_email_candidates_cron.php
24 2 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_email_candidates_cron.php213 4 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_invitations_cron.php
36 5 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_sessions_cron.php316 4 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_sessions_captcha_cron.php
45 4 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_unused_accounts_cron.php419 4 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_sessions_cron.php
522 4 * * * #dest#/php/bin/php #dest#/ppcron/cleanup_unused_accounts_cron.php
56
=== added file 'trunk/sql/upgrades/upgrade-2.7.010.sql'
--- trunk/sql/upgrades/upgrade-2.7.010.sql 1970-01-01 00:00:00 +0000
+++ trunk/sql/upgrades/upgrade-2.7.010.sql 2012-07-26 17:56:19 +0000
@@ -0,0 +1,9 @@
1drop table if exists sess;
2
3create table sess (
4 id char(32) not null,
5 data char(255) default "", -- change it to "blob" for larger sessions
6 updated datetime,
7 primary key (id),
8 key idx_updated (updated)
9);
010
=== modified file 'trunk/www/create_account.php'
--- trunk/www/create_account.php 2012-03-01 19:21:32 +0000
+++ trunk/www/create_account.php 2012-07-26 17:56:19 +0000
@@ -34,6 +34,7 @@
34include_once($_SERVER[DOCUMENT_ROOT]."/includes/common_includes.php");34include_once($_SERVER[DOCUMENT_ROOT]."/includes/common_includes.php");
35include_once($_SERVER[DOCUMENT_ROOT]."/includes/cr.php");35include_once($_SERVER[DOCUMENT_ROOT]."/includes/cr.php");
36include_once($_SERVER[DOCUMENT_ROOT]."/includes/geoip_helpers.php");36include_once($_SERVER[DOCUMENT_ROOT]."/includes/geoip_helpers.php");
37include_once($_SERVER[DOCUMENT_ROOT]."/includes/sess.php");
3738
38// mode sanity check39// mode sanity check
3940
@@ -59,9 +60,6 @@
59// Business logic60// Business logic
60//61//
6162
62// create PHP session for CAPCHA (see image-code.php)
63
64session_start();
6563
66// Set invitation code from GET parameter in invite URL64// Set invitation code from GET parameter in invite URL
6765
@@ -94,6 +92,7 @@
94// By default, invite and anonymous forms use invite and anonymous92// By default, invite and anonymous forms use invite and anonymous
95// session languages, respectively93// session languages, respectively
9694
95
97if ($create_account_mode == create_account_mode_anonymous)96if ($create_account_mode == create_account_mode_anonymous)
98{97{
99 // validation: check that this is an anonymous session98 // validation: check that this is an anonymous session
@@ -227,18 +226,37 @@
227 if ($create_account_mode == create_account_mode_create226 if ($create_account_mode == create_account_mode_create
228 || $create_account_mode == create_account_mode_anonymous)227 || $create_account_mode == create_account_mode_anonymous)
229 {228 {
229 // create PHP session for CAPCHA (see image-code.php)
230 if (($s=sess_open()) === false)
231 {
232 syslog(LOG_DEBUG, getenv("HTTP_HOST").getenv("REQUEST_URI").": client ".getenv("REMOTE_ADDR").": Can not open a session");
233 include($_SERVER[DOCUMENT_ROOT]."/http-errors/500.php");
234 }
235
230 // "code" is the session variable set by image-code.php236 // "code" is the session variable set by image-code.php
231 // also, see image-code.php reference below237 // also, see image-code.php reference below
238
239 if (!isset($s["code"]))
240 {
241 $processing_errors[] = ___("Error: Wrong security code");
242 $curs = "create_account.create_account_security_code";
243 $valid = false; // v: ???
244 break;
245 }
246
247 // Making sure CAPTCHA session is not re-used
248 $code=$s["code"];
249 unset($s["code"]);
250 sess_close($s);
251
232 $_POST[create_account_security_code] = trim($_POST[create_account_security_code]);252 $_POST[create_account_security_code] = trim($_POST[create_account_security_code]);
233 if (!strlen($_POST[create_account_security_code]) ||253 if (!strlen($_POST[create_account_security_code]) ||
234 ($_POST[create_account_security_code] != $_SESSION[code]))254 ($_POST[create_account_security_code] != $code))
235 {255 {
236 $processing_errors[] = ___("Error: Wrong security code");256 $processing_errors[] = ___("Error: Wrong security code");
237 $curs = "create_account.create_account_security_code";257 $curs = "create_account.create_account_security_code";
238 $valid = false;258 $valid = false;
239 }259 }
240 //Making sure CAPTCHA session is not re-used
241 unset($_SESSION[code]);
242 }260 }
243261
244 // check lang262 // check lang
@@ -672,8 +690,9 @@
672 <td valign="top"><font class="fourteenblue"><?=___("Security code")?></font></td>690 <td valign="top"><font class="fourteenblue"><?=___("Security code")?></font></td>
673 <td><input type="text" name="create_account_security_code" value="" size="15" maxlength="4">691 <td><input type="text" name="create_account_security_code" value="" size="15" maxlength="4">
674 <br/>692 <br/>
675 <?/* image-code generates a CAPTCHA which is associated with a PHP session (e.g., _SESSION) */?>693 <?/* image-code generates a CAPTCHA which is associated with a mysql session, see includes/sess.php file */?>
676 <img src="image-code.php?<?=strtoupper(bin2hex(secure_rand(8)))?>" border="0" hspace="0" vspace="2" alt=""></td>694 <img src="image-code.php?<?=strtoupper(bin2hex(secure_rand(8)))?>" border="0" hspace="0" vspace="2" alt="" onClick="this.src='image-code.php?r='+Math.random(); document.create_account.create_account_security_code.focus();" title="<?=___("Click to refresh")?>" style="cursor: pointer; border: none;"></td>
695
677 </tr>696 </tr>
678 <?}?>697 <?}?>
679 <tr>698 <tr>
680699
=== added file 'trunk/www/image-code.pfb'
681Binary files trunk/www/image-code.pfb 1970-01-01 00:00:00 +0000 and trunk/www/image-code.pfb 2012-07-26 17:56:19 +0000 differ700Binary files trunk/www/image-code.pfb 1970-01-01 00:00:00 +0000 and trunk/www/image-code.pfb 2012-07-26 17:56:19 +0000 differ
=== modified file 'trunk/www/image-code.php'
--- trunk/www/image-code.php 2009-11-23 23:23:36 +0000
+++ trunk/www/image-code.php 2012-07-26 17:56:19 +0000
@@ -1,8 +1,7 @@
1<?php1<?
2
3/*2/*
4 Psiphon Circumvention Platform3 Psiphon Circumvention Platform
5 Copyright (C) 2009 Psiphon Inc.4 Copyright (C) 2010 Psiphon Inc.
65
7 This program is free software: you can redistribute it and/or modify6 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by7 it under the terms of the GNU General Public License as published by
@@ -18,167 +17,76 @@
18 along with this program. If not, see <http://www.gnu.org/licenses/>.17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/18*/
2019
21/*20include_once($_SERVER[DOCUMENT_ROOT]."/includes/common_includes.php");
22============================21include_once($_SERVER[DOCUMENT_ROOT]."/includes/sess.php");
23QuickCaptcha 1.0 - A bot-thwarting text-in-image web tool.22
24Copyright (c) 2006 Web 1 Marketing, Inc.23$config["len"] = 4;
2524$config["chars"] = "012345689";
26This program is free software; you can redistribute it and/or25$config["lines"] = 6;
27modify it under the terms of the GNU General Public License26$config["width"] = 55;
28as published by the Free Software Foundation; either version 227$config["height"] = 37;
29of the License, or (at your option) any later version.28$config["overlap"] = 0.85; // 0 - over, > 1 - none
3029$config["font_size"] = 34;
31This program is distributed in the hope that it will be useful,30$config["font"] = $_SERVER[DOCUMENT_ROOT]."/image-code.pfb";
32but WITHOUT ANY WARRANTY; without even the implied warranty of31
33MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the32// password
34GNU General Public License for more details.33$max = strlen($config["chars"]) - 1;
35============================34$pwd = "";
36Pretty much everything that you'll need to change/adjust35for ($i = 0; $i < $config["len"]; $i++)
37should be right here in this file.36{
38============================37 $pwd .= $config["chars"]{mt_rand(0, $max)};
39*/38}
4039
41//////////////settings40if (($s = sess_open()) === false)
42$acceptedChars = 'AEFHJKLMNPQRTWX234689';41{
43$acceptedChars = '012345689';42 syslog(LOG_DEBUG, $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"].": Can not open the session");
4443 include($_SERVER[DOCUMENT_ROOT]."/http-errors/500.php");
45// Number of characters in image.44}
46$stringlength = 4;45
4746$s["code"]=$pwd;
48// A value between 0 and 100 describing how much color overlap47
49// there is between text and other objects. Lower is more48// syslog(LOG_DEBUG, $pwd);
50// secure against bots, but also harder to read.49if (!sess_close($s))
51$contrast = 60;50{
5251 syslog(LOG_DEBUG, $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"].": Can not save the session");
53// Various obfuscation techniques.52 include("/home/httpd/common/500.php");
54$num_polygons = 3; // Number of triangles to draw. 0 = none53}
55$num_ellipses = 3; // Number of ellipses to draw. 0 = none54
56$num_lines = 3; // Number of lines to draw. 0 = none55if (($font = @imagepsloadfont($config["font"])) === false)
57$num_dots = 90; // Number of dots to draw. 0 = none56{
5857 syslog(LOG_DEBUG, $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"].": Can not load \"{$config["font"]}\"");
59$min_thickness = 1; // Minimum thickness in pixels of lines58 include($_SERVER[DOCUMENT_ROOT]."/http-errors/500.php");
60$max_thickness = 3; // Maximum thickness in pixles of lines59}
61$min_radius = 5; // Minimum radius in pixels of ellipses60
62$max_radius = 10; // Maximum radius in pixels of ellipses61$image = imagecreate($config["width"], $config["height"]);
6362
64// How opaque should the obscuring objects be. 0 is opaque, 12763$bg = imagecolorallocate($image, 255, 255, 255);
65// is transparent.64$fg = imagecolorallocate($image, 0, 0, 0);
66$object_alpha = 70;65
67////////////////end settings///////////////////////66imagefill($image, 0, 0, $bg);
6867
69// Keep #'s reasonable.68$x = 2;
70$min_thickness = max(1,$min_thickness);69$y = (int)($config["height"] * 0.85);
71$max_thickness = min(20,$max_thickness);70
72// Make radii into height/width71for ($i = 0; $i < $config["len"]; $i++)
73$min_radius *= 2;72{
74$max_radius *= 2;73 $res = @imagepstext($image, $pwd{$i}, $font, $config["font_size"], $fg, $bg, $x, $y, 0, 0, mt_rand(-10, 10), 4);
75// Renormalize contrast74 if (!is_array($res))
76$contrast = 255 * ($contrast / 100.0);75 {
77$o_contrast = 1.3 * $contrast;76 syslog(LOG_DEBUG, $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"].": imagepstext() returned an error");
7877 include($_SERVER[DOCUMENT_ROOT]."/http-errors/503.php");
79$width = 12 * imagefontwidth(5);78 }
80$height = 2.5 * imagefontheight(5);79 $x += (int)($res[2] * $config["overlap"]);
81$image = imagecreatetruecolor($width, $height);80}
82imagealphablending($image, true);81
83$black = imagecolorallocatealpha($image,0,0,0,0);82for ($i = 0; $i < $config["lines"]; $i++)
8483{
85// Build the validation string84 imagesetthickness($image, mt_rand(1, 2));
86$max = strlen($acceptedChars)-1;85 imageline($image, mt_rand(0, $config["width"]), mt_rand(0, $config["height"]), mt_rand(0, $config["width"]), mt_rand(0, $config["height"]), ($i % 2) ? $fg : $bg);
87$password = NULL;86}
88for ($i=0; $i<$stringlength; $i++) {87
89 $cnum[$i] = $acceptedChars{mt_rand(0, $max)};88
90 $password .= $cnum[$i];89header("Content-type: image/gif");
91 }90imagegif($image);
92
93// Add string to image
94$rotated = imagecreatetruecolor(70, 70);
95for ($i = 0; $i < $stringlength; $i++) {
96 $buffer = imagecreatetruecolor (20, 20);
97 $buffer2 = imagecreatetruecolor (40, 40);
98
99 // Get a random color
100 $red = mt_rand(150,255);
101 $green = mt_rand(150,255);
102 $blue = 255 - sqrt($red * $red + $green * $green);
103 $color = imagecolorallocate($buffer, $red, $green, $blue);
104
105 // Create character
106 imagestring($buffer, 5, 0, 0, $cnum[$i], $color);
107
108 // Resize character
109 imagecopyresized($buffer2, $buffer, 0, 0, 0, 0, 25 + mt_rand(0,12), 25 + mt_rand(0,12), 20, 20);
110
111 // Rotate characters a little
112 if (function_exists("imagerotate")) {
113 $rotated = imagerotate($buffer2, mt_rand(-20, 20),imagecolorallocatealpha($buffer2,0,0,0,0));
114 } else {
115 $rotated = $buffer2;
116 }
117
118 imagecolortransparent ($rotated, imagecolorallocatealpha($rotated,0,0,0,0));
119
120 // Move characters around a little
121 $y = mt_rand(1, 3);
122 $x += mt_rand(2, 4);
123 imagecopymerge($image, $rotated, $x, $y, 0, 0, 40, 40, 100);
124 $x += 22;
125
126 imagedestroy ($buffer);
127 imagedestroy ($buffer2);
128}
129
130// Draw polygons
131if ($num_polygons > 0) for ($i = 0; $i < $num_polygons; $i++) {
132 $vertices = array (
133 mt_rand(-0.25*$width,$width*1.25),mt_rand(-0.25*$width,$width*1.25),
134 mt_rand(-0.25*$width,$width*1.25),mt_rand(-0.25*$width,$width*1.25),
135 mt_rand(-0.25*$width,$width*1.25),mt_rand(-0.25*$width,$width*1.25)
136 );
137 $color = imagecolorallocatealpha ($image, mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), $object_alpha);
138 imagefilledpolygon($image, $vertices, 3, $color);
139}
140
141// Draw random circles
142if ($num_ellipses > 0) for ($i = 0; $i < $num_ellipses; $i++) {
143 $x1 = mt_rand(0,$width);
144 $y1 = mt_rand(0,$height);
145 $color = imagecolorallocatealpha ($image, mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), $object_alpha);
146// $color = imagecolorallocate($image, mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), mt_rand(0,$o_contrast));
147 imagefilledellipse($image, $x1, $y1, mt_rand($min_radius,$max_radius), mt_rand($min_radius,$max_radius), $color);
148}
149
150// Draw random lines
151if ($num_lines > 0) for ($i = 0; $i < $num_lines; $i++) {
152 $x1 = mt_rand(-$width*0.25,$width*1.25);
153 $y1 = mt_rand(-$height*0.25,$height*1.25);
154 $x2 = mt_rand(-$width*0.25,$width*1.25);
155 $y2 = mt_rand(-$height*0.25,$height*1.25);
156 $color = imagecolorallocatealpha ($image, mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), $object_alpha);
157 imagesetthickness ($image, mt_rand($min_thickness,$max_thickness));
158 imageline($image, $x1, $y1, $x2, $y2 , $color);
159}
160
161// Draw random dots
162if ($num_dots > 0) for ($i = 0; $i < $num_dots; $i++) {
163 $x1 = mt_rand(0,$width);
164 $y1 = mt_rand(0,$height);
165 $color = imagecolorallocatealpha($image, mt_rand(0,$o_contrast), mt_rand(0,$o_contrast), mt_rand(0,$o_contrast),$object_alpha);
166 imagesetpixel($image, $x1, $y1, $color);
167}
168
169session_start();
170
171if (session_id())
172 $_SESSION['code'] = $password;
173
174header("Content-type: image/jpeg");
175imagejpeg($image);
176imagedestroy($image);91imagedestroy($image);
17792?>
178/**** to check *****
179form: <img src="image-code.php" border="0" alt="">
180
181process: session_start(); if ($_POST["code"]!=$_SESSION["code"]) exit("Wrong code");
182*******************/
183
184?>
18593
=== added file 'trunk/www/includes/sess.php'
--- trunk/www/includes/sess.php 1970-01-01 00:00:00 +0000
+++ trunk/www/includes/sess.php 2012-07-26 17:56:19 +0000
@@ -0,0 +1,91 @@
1<?
2/*
3 Psiphon Circumvention Platform
4 Copyright (C) 2010 Psiphon Inc.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20include_once($_SERVER[DOCUMENT_ROOT]."/includes/common_includes.php");
21
22$config["sess_name"]="S"; // session cookie name
23$config["sess_path"]="/"; // session cookie path
24
25/*
26 * Initialize the session, or read the data from an exising one
27 *
28 * RETURN: - session array on success (empty on the first call)
29 * - returns false on error
30 */
31function sess_open()
32{
33 global $config;
34
35 if (!isset($_COOKIE[$config["sess_name"]]))
36 {
37 $id=md5(microtime().$_SERVER["REMOTE_ADDR"].mt_rand().$_SERVER["REQUEST_URI"]);
38 $_COOKIE[$config["sess_name"]]=$id;
39 header("Set-Cookie: {$config["sess_name"]}={$id}; path={$config["sess_path"]}", false);
40 return(array());
41 }
42
43 $query="SELECT * FROM sess WHERE id = :sess_name";
44 $result = db_query_execute($config, $query, convert_null_array(array(":sess_name" => $_COOKIE[$config["sess_name"]])));
45
46 if (!($record = db_fetch_result($config, $result)))
47 {
48 return(array());
49 }
50
51 if (($res = unserialize($record["data"])) === false)
52 {
53 syslog(LOG_DEBUG, $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"].": sess_open(): Can not unserialize the data");
54 return(false);
55 }
56
57 return($res);
58}
59
60
61/*
62 * Save session data, delete expired data from the session table
63 *
64 * $s a session array
65 *
66 * RETURN: - true on success
67 * - false on error
68 */
69function sess_close($s)
70{
71 global $config;
72
73 if (!isset($_COOKIE[$config["sess_name"]]))
74 {
75 syslog(LOG_DEBUG, $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"].": sess_close(): No session id");
76 return(false);
77 }
78
79 $query="INSERT INTO sess (id, data, updated) VALUES (:id, :data, now())";
80 if (!db_query_execute($config, $query, convert_null_array(array(":id" => $_COOKIE[$config["sess_name"]], ":data" => serialize($s))), true))
81 {
82 $query="UPDATE sess SET data = :data, updated=now() WHERE id = :id";
83 if (!db_query_execute($config, $query, convert_null_array(array(":data" => serialize($s), ":id" => $_COOKIE[$config["sess_name"]])), true))
84 {
85 return(false);
86 }
87 }
88
89 return(true);
90}
91?>

Subscribers

People subscribed via source and target branches

to all changes: