1<?php
2
3/**
4 * library with user functions
5 *  *.
6 */
7require_once dirname(__FILE__).'/accesscheck.php';
8
9function initialiseUserSession()
10{
11    if (!is_array($_SESSION['userdata'])) {
12        $_SESSION['userdata'] = array();
13    }
14}
15
16function getEveryoneGroupID()
17{
18    $ev_req = Sql_Fetch_Row_Query('select id from groups where name = "Everyone"');
19    $everyone_groupid = $ev_req[0];
20    if (!$everyone_groupid) {
21        Sql_Query('insert into groups (name) values("Everyone")');
22        $everyone_groupid = Sql_Insert_Id();
23    }
24
25    return $everyone_groupid;
26}
27
28function getUniqid($table = '')
29{
30    global $tables;
31    if (!$table) {
32        if ($tables['user']) {
33            $table = $tables['user'];
34        } else {
35            $table = 'user';
36        }
37    }
38    $id = bin2hex(random_bytes(16));
39
40    return $id;
41}
42
43function obfuscateString($string)
44{
45    $l = strlen(($string));
46    if ($l > 3) {
47        $obf = substr($string, 0, 1);
48        $obf .= str_repeat('*', $l - 2);
49        $obf .= substr($string, -1, 1);
50    } else {
51        $obf = str_repeat('*', $l);
52    }
53
54    return $obf;
55}
56
57function obfuscateEmailAddress($emailAddress)
58{
59    if (is_email($emailAddress)) {
60        list($userName, $domain) = explode('@', strtolower($emailAddress));
61
62        $obf = obfuscateString($userName).'@';
63
64        $domainParts = explode('.', $domain);
65        $TLD = array_pop($domainParts);
66
67        foreach ($domainParts as $dPart) {
68            $obf .= obfuscateString($dPart).'.';
69        }
70
71        return $obf.$TLD;
72    }
73
74    return $emailAddress;
75}
76
77function userSelect($fieldname, $current = '')
78{
79    global $tables;
80    $html = sprintf('<select name="%s">', $fieldname);
81    $req = Sql_Query(sprintf('select id,email from %s order by email', $tables['user']));
82    while ($row = Sql_Fetch_Array($req)) {
83        $html .= sprintf('<option value="%d" %s>%s</option>', $row['id'],
84            $current == $row['id'] ? 'selected="selected"' : '', $row['email']);
85    }
86    $html .= '</select>';
87
88    return $html;
89}
90
91/**
92 * Delete a subscriber's records from user group table
93 */
94function deleteUserGroup($id)
95{
96    if (Sql_table_exists('user_group')) {
97        Sql_Query(sprintf('delete from user_group where userid = %d', $id), 1);
98    }
99}
100
101/**
102 * Trigger deleteUser() hook for plugins
103 */
104function triggerDeleteUserPluginsHook($id)
105{
106    global $plugins;
107
108    // allow plugins to delete their data
109    foreach ($plugins as $plugin) {
110        $plugin->deleteUser($id);
111    }
112}
113
114/**
115 * Delete a subscriber's records from blacklist tables
116 */
117function deleteUserBlacklistRecords($id)
118{
119    global $tables;
120    $userEmail = getUserEmail($id);
121
122    Sql_Query('delete from '.$tables['user_blacklist'].' where email = "'.$userEmail.'"');
123    Sql_Query('delete from '.$tables['user_blacklist_data'].' where email = "'.$userEmail.'"');
124}
125
126/**
127 * Delete a subscriber's records except from blacklist tables
128 */
129function deleteUserRecordsLeaveBlacklistRecords($id)
130{
131    global $tables;
132
133    Sql_Query('delete from '.$tables['linktrack_uml_click'].' where userid = '.$id);
134    Sql_Query('delete from '.$tables['listuser'].' where userid = '.$id);
135    Sql_Query('delete from '.$tables['usermessage'].' where userid = '.$id);
136    Sql_Query('delete from '.$tables['user_attribute'].' where userid = '.$id);
137    Sql_Query('delete from '.$tables['user_history'].' where userid = '.$id);
138    Sql_Query('delete from '.$tables['user_message_bounce'].' where user = '.$id);
139    Sql_Query('delete from '.$tables['user_message_forward'].' where user = '.$id);
140    Sql_Query('delete from '.$tables['user'].' where id = '.$id);
141    Sql_Query('delete from '.$tables['user_message_view'].' where userid = '.$id);
142}
143
144/**
145 * Delete a subscriber but leave blacklist data
146 */
147function deleteUserLeaveBlacklist($id)
148{
149    deleteUserRecordsLeaveBlacklistRecords($id);
150    deleteUserGroup($id);
151    triggerDeleteUserPluginsHook($id);
152}
153
154/**
155 * Delete a subscriber including blacklist data
156 */
157function deleteUserIncludeBlacklist($id)
158{
159    // Note: deleteUserBlacklistRecords() must be executed first, else the ID
160    // to email lookup fails due to the missing record
161    deleteUserBlacklistRecords($id);
162    deleteUserRecordsLeaveBlacklistRecords($id);
163    deleteUserGroup($id);
164    triggerDeleteUserPluginsHook($id);
165}
166
167/**
168 * Wrapper for backwards compatibility
169 */
170function deleteUser($id)
171{
172    deleteUserLeaveBlacklist($id);
173}
174
175function addNewUser($email, $password = '')
176{
177    if (empty($GLOBALS['tables']['user'])) {
178        $GLOBALS['tables']['user'] = 'user';
179    }
180    /*
181        "id" => array("integer not null primary key auto_increment","sys:ID"),
182        "email" => array("varchar(255) not null","Email"),
183        "confirmed" => array("tinyint default 0","sys:Is the email of this user confirmed"),
184        "entered" => array("datetime","sys:Time Created"),
185        "modified" => array("timestamp","sys:Time modified"),
186        "uniqid" => array("varchar(255)","sys:Unique ID for User"),
187        "unique" => array("(email)","sys:unique"),
188        "htmlemail" => array("tinyint default 0","Send this user HTML emails"),
189        "subscribepage" => array("integer","sys:Which page was used to subscribe"),
190        "rssfrequency" => array("varchar(100)","rss Frequency"), // Leftover from the preplugin era
191        "password" => array("varchar(255)","Password"),
192        "passwordchanged" => array("datetime","sys:Last time password was changed"),
193        "disabled" => array("tinyint default 0","Is this account disabled?"),
194        "extradata" => array("text","Additional data"),
195    */
196    // insert into user db
197    $exists = Sql_Fetch_Row_Query(sprintf('select id from %s where email = "%s"',
198        $GLOBALS['tables']['user'], $email));
199    if ($exists[0]) {
200        return $exists[0];
201    }
202
203    $blacklist = isBlackListed($email);
204    $passwordEnc = encryptPass($password);
205    Sql_Query(sprintf('insert into %s set email = "%s", blacklisted = "%d",
206    entered = now(),modified = now(),password = "%s",
207    passwordchanged = now(),disabled = 0,
208    uniqid = "%s",htmlemail = 1, uuid = "%s"
209    ', $GLOBALS['tables']['user'], sql_escape($email), $blacklist, $passwordEnc, getUniqid(), (string) uuid::generate(4)));
210
211    $id = Sql_Insert_Id();
212
213    return $id;
214}
215
216function getAttributeIDbyName($sName)
217{
218    // Looks for an attribute named sName.
219    // Returns table ID or 0 if not found.
220    // Can also be used as 'isAttribute'
221
222    if (empty($sName)) {
223        return 0;
224    }
225    global $usertable_prefix, $tables;
226    // workaround for integration webbler/phplist
227    if (!isset($usertable_prefix)) {
228        $usertable_prefix = '';
229    }
230    if ($tables['attribute']) {
231        $att_table = $tables['attribute'];
232        $user_att_table = $tables['user_attribute'];
233    } else {
234        $att_table = 'attribute';
235        $user_att_table = 'user_attribute';
236    }
237
238    $res = Sql_Query(sprintf('SELECT id FROM %s%s WHERE name = "%s"',
239        $usertable_prefix, $att_table, $sName));
240    $row = Sql_Fetch_row($res);
241
242//  dbg($row,'$$row');
243    return $row[0];
244}
245
246/**
247 * Returns attribute name for ID.
248 *
249 * @param $iAttribute
250 *
251 * @return unknown_type
252 */
253function getAttributeNamebyID($iAttribute)
254{
255    if (empty($iAttribute)) {
256        return;
257    }
258    global $usertable_prefix;
259    // workaround for integration webbler/phplist
260    if (!isset($usertable_prefix)) {
261        $usertable_prefix = '';
262    }
263    if ($tables['attribute']) {
264        $att_table = $tables['attribute'];
265        $user_att_table = $tables['user_attribute'];
266    } else {
267        $att_table = 'attribute';
268        $user_att_table = 'user_attribute';
269    }
270
271    $res = Sql_Query(sprintf('SELECT name FROM %s%s WHERE id = %d',
272        $usertable_prefix, $att_table, $iAttribute));
273    $row = Sql_Fetch_row($res);
274
275//  dbg($row,'$$row');
276    return $row[0];
277}
278
279function AttributeValue($table, $value)
280{
281    global $table_prefix;
282    // workaround for integration webbler/phplist
283    if (!isset($table_prefix)) {
284        $table_prefix = 'phplist_';
285    }
286
287    if (strpos($value, ',') !== false) {
288        $result = '';
289        $res = Sql_Query(sprintf('select name from %slistattr_%s where id in (%s)',
290            $table_prefix, $table, $value));
291        while ($row = Sql_Fetch_row($res)) {
292            $result .= $row[0].'; ';
293        }
294
295        return substr($result, 0, -2);
296    } elseif ($value) {
297        $res = Sql_Query(sprintf('select name from %slistattr_%s where id = %d',
298            $table_prefix, $table, $value));
299        $row = Sql_Fetch_row($res);
300
301        return $row[0];
302    } else {
303        //    return "Invalid Attribute Index";
304    }
305
306    return '';
307}
308
309/**
310 * Convert subscriber ID to email address simply
311 */
312function getUserEmail($id)
313{
314    global $tables;
315
316    $userid = Sql_Fetch_Row_Query("select email from {$tables['user']} where id = \"$id\"");
317    return $userid[0];
318}
319
320function existUserID($id = 0)
321{
322    global $table_prefix, $tables;
323    // workaround for integration webbler/phplist
324    if (!isset($table_prefix)) {
325        $table_prefix = 'phplist_';
326    }
327
328    if (isset($tables['attribute'])) {
329        $usertable = $tables['user'];
330    } else {
331        $usertable = 'user';
332    }
333
334    $userid = Sql_Fetch_Row_Query("select id from {$usertable} where id = \"$id\"");
335
336    return $userid[0];
337}
338
339function getUserAttributeValues($email = '', $id = 0, $bIndexWithShortnames = false)
340{
341    global $table_prefix, $tables;
342    if (!$email && !$id) {
343        return;
344    }
345    // workaround for integration webbler/phplist
346    if (!isset($table_prefix)) {
347        $table_prefix = 'phplist_';
348    }
349
350    if (isset($tables['attribute'])) {
351        $att_table = $tables['attribute'];
352        $user_att_table = $tables['user_attribute'];
353        $usertable = $tables['user'];
354    } else {
355        $att_table = 'attribute';
356        $user_att_table = 'user_attribute';
357        $usertable = 'user';
358    }
359    $result = array();
360    if ($email && !$id) {
361        $userid = Sql_Fetch_Row_Query("select id from {$usertable} where email = \"$email\"");
362        $id = $userid[0];
363    }
364    if (!$id) {
365        return $result;
366    }
367    /* https://mantis.phplist.org/view.php?id=17708
368     * instead of only returning the attributes for which a subscriber has a value
369     * return all attributes
370     */
371    //$att_req = Sql_Query(sprintf('select
372    //%s.name,%s.id from %s,%s
373    //where %s.userid = %s and %s.id = %s.attributeid',
374    //$att_table,
375    //$att_table,
376    //$user_att_table,
377    //$att_table,
378    //$user_att_table,
379    //$id,
380    //$att_table,
381    //$user_att_table
382    //));
383
384    $att_req = Sql_Query(sprintf('select id,name from %s', $att_table));
385    while ($att = Sql_fetch_array($att_req)) {
386        if ($bIndexWithShortnames) {
387            $result['attribute'.$att['id']] = UserAttributeValue($id, $att['id']);
388        } else {
389            $result[$att['name']] = UserAttributeValue($id, $att['id']);
390        }
391    }
392
393    return $result;
394}
395
396function UserAttributeValue($user = 0, $attribute = 0)
397{
398    // workaround for integration webbler/phplist
399    global $table_prefix, $tables;
400    if (!isset($table_prefix)) {
401        $table_prefix = 'phplist_';
402    }
403    if (!$user || !$attribute) {
404        return;
405    }
406
407    if (isset($tables['attribute'])) {
408        $att_table = $tables['attribute'];
409        $user_att_table = $tables['user_attribute'];
410    } else {
411        $att_table = 'attribute';
412        $user_att_table = 'user_attribute';
413    }
414    $att = Sql_Fetch_array_Query("select * from $att_table where id = $attribute");
415    switch ($att['type']) {
416        case 'checkboxgroup':
417            //     print "select value from $user_att_table where userid = $user and attributeid = $attribute";
418            $val_ids = Sql_Fetch_Row_Query("select value from $user_att_table where userid = $user and attributeid = $attribute");
419            if ($val_ids && $val_ids[0]) {
420                //       print '<br/>1 <b>'.$val_ids[0].'</b>';
421                if (function_exists('cleancommalist')) {
422                    $val_ids[0] = cleanCommaList($val_ids[0]);
423                }
424                //# make sure the val_ids as numbers
425                $values = explode(',', $val_ids[0]);
426                $ids = array();
427                foreach ($values as $valueIndex) {
428                    $iValue = sprintf('%d', $valueIndex);
429                    if ($iValue) {
430                        $ids[] = $iValue;
431                    }
432                }
433                if (!count($ids)) {
434                    return '';
435                }
436                $val_ids[0] = implode(',', $ids);
437                //       print '<br/>2 <b>'.$val_ids[0].'</b>';
438                $value = '';
439                $res = Sql_Query("select $table_prefix".'listattr_'.$att['tablename'].".name
440          from $user_att_table,$table_prefix".'listattr_'.$att['tablename']."
441          where $user_att_table".'.userid = '.$user." and
442          $table_prefix".'listattr_'.$att['tablename'].".id in ($val_ids[0]) and
443          $user_att_table".'.attributeid = '.$attribute);
444                while ($row = Sql_Fetch_row($res)) {
445                    $value .= $row[0].'; ';
446                }
447                $value = substr($value, 0, -2);
448            } else {
449                $value = '';
450            }
451            break;
452        case 'select':
453        case 'radio':
454            $res = Sql_Query("select $table_prefix".'listattr_'.$att['tablename'].".name
455        from $user_att_table,$table_prefix".'listattr_'.$att['tablename']."
456        where $user_att_table".'.userid = '.$user." and
457        $table_prefix".'listattr_'.$att['tablename'].".id = $user_att_table".".value and
458        $user_att_table".'.attributeid = '.$attribute);
459            $row = Sql_Fetch_row($res);
460            $value = $row ? $row[0] : '';
461            break;
462        default:
463            $res = Sql_Query(sprintf('select value from %s where
464        userid = %d and attributeid = %d', $user_att_table, $user, $attribute));
465            $row = Sql_Fetch_row($res);
466            $value = $row ? $row[0] : '';
467    }
468
469    return stripslashes($value);
470}
471
472function userName()
473{
474    global $config;
475    if (!is_array($config['nameattributes'])) {
476        return '';
477    }
478    $res = '';
479    foreach ($config['nameattributes'] as $att) {
480        if (isset($_SESSION['userdata'][$att]['displayvalue'])) {
481            $res .= $_SESSION['userdata'][$att]['displayvalue'].' ';
482        }
483    }
484
485    return rtrim($res);
486}
487
488/**
489 * Check if a subscriber is blacklisted in blacklist data tables
490 * @note Ignores the user table
491 */
492function isBlackListed($email = '', $immediate = true)
493{
494    if (!$email) {
495        return 0;
496    }
497    if (!Sql_Table_exists($GLOBALS['tables']['user_blacklist'])) {
498        return 0;
499    }
500    if (!$immediate) {
501        // allow 5 minutes to send the last message acknowledging unsubscription
502        $gracetime = sprintf('%d', $GLOBALS['blacklist_gracetime']);
503        if (!$gracetime || $gracetime > 15 || $gracetime < 0) {
504            $gracetime = 5;
505        }
506    } else {
507        $gracetime = 0;
508    }
509    $req = Sql_Query(sprintf('select * from %s where email = "%s" and date_add(added,interval %d minute) < now()',
510        $GLOBALS['tables']['user_blacklist'], sql_escape($email), $gracetime));
511
512    $isBlackListed = Sql_Affected_Rows();
513    ## ask plugins as well
514    if (!$isBlackListed) {
515        if (isset($GLOBALS['plugins']) && is_array($GLOBALS['plugins'])) {
516            foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
517                if (method_exists($plugin, "isBlacklistedEmail")) {
518                    $isBlackListed = $plugin->isBlacklistedEmail($email);
519                }
520                if ($isBlackListed) break;
521            }
522        }
523    }
524    return $isBlackListed;
525}
526
527/**
528 * Check if a subscriber is blacklisted in the user table
529 * @note Ignores blacklist data tables
530 */
531function isBlackListedID($userid = 0)
532{
533    if (!$userid) {
534        return 0;
535    }
536    $email = Sql_Fetch_Row_Query("select email from {$GLOBALS['tables']['user']} where id = $userid");
537
538    return isBlackListed($email[0]);
539}
540
541function unBlackList($userid = 0)
542{
543    if (!$userid) {
544        return;
545    }
546    $email = Sql_Fetch_Row_Query("select email from {$GLOBALS['tables']['user']} where id = $userid");
547    Sql_Query(sprintf('delete from %s where email = "%s"',
548        $GLOBALS['tables']['user_blacklist'], $email[0]));
549    Sql_Query(sprintf('delete from %s where email = "%s"',
550        $GLOBALS['tables']['user_blacklist_data'], $email[0]));
551    Sql_Query(sprintf('update %s set blacklisted = 0 where id = %d', $GLOBALS['tables']['user'], $userid));
552    if (isset($_SESSION['logindetails']['adminname'])) {
553        $msg = s('Removed from blacklist by %s', $_SESSION['logindetails']['adminname']);
554    } else {
555        $msg = s('Removed from blacklist');
556    }
557    addUserHistory($email[0], $msg, '');
558}
559
560function addUserToBlackList($email, $reason = '')
561{
562    Sql_Query(sprintf('update %s set blacklisted = 1 where email = "%s"',
563        $GLOBALS['tables']['user'], addslashes($email)));
564    //0012262: blacklist only email when email bounces. (not users): Function split so email can be blacklisted without blacklisting user
565    addEmailToBlackList($email, $reason);
566}
567
568function addUserToBlackListID($id, $reason = '')
569{
570    Sql_Query(sprintf('update %s set blacklisted = 1 where id = %s',
571        $GLOBALS['tables']['user'], $id));
572    //0012262: blacklist only email when email bounces. (not users): Function split so email can be blacklisted without blacklisting user
573    $email = Sql_Fetch_Row_Query("select email from {$GLOBALS['tables']['user']} where id = $id");
574    addEmailToBlackList($email[0], $reason);
575}
576
577function addEmailToBlackList($email, $reason = '', $date = '')
578{
579    if (empty($date)) {
580        $sqldate = 'now()';
581    } else {
582        $sqldate = '"'.$date.'"';
583    }
584    //0012262: blacklist only email when email bounces. (not users): Function split so email can be blacklisted without blacklisting user
585    Sql_Query(sprintf('insert ignore into %s (email,added) values("%s",%s)',
586        $GLOBALS['tables']['user_blacklist'], sql_escape($email), $sqldate));
587    // save the reason, and other data
588    Sql_Query(sprintf('insert ignore into %s (email,name,data) values("%s","%s","%s")',
589        $GLOBALS['tables']['user_blacklist_data'], sql_escape($email),
590        'reason', addslashes($reason)));
591    foreach (array('REMOTE_ADDR','HTTP_X_FORWARDED_FOR') as $item) { // @@@do we want to know more?
592        if (isset($_SERVER[$item])) {
593            Sql_Query(sprintf('insert ignore into %s (email,name,data) values("%s","%s","%s")',
594                $GLOBALS['tables']['user_blacklist_data'], addslashes($email),
595                $item, addslashes($_SERVER[$item])));
596        }
597    }
598    addUserHistory($email, s('Added to blacklist'), s('Added to blacklist for reason %s', $reason));
599    //# call plugins to tell them
600    if (isset($GLOBALS['plugins']) && is_array($GLOBALS['plugins'])) {
601        foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
602            if (method_exists($plugin, 'blacklistEmail')) {
603                $plugin->blacklistEmail($email);
604            }
605        }
606    }
607}
608
609function UserAttributeValueSelect($user = 0, $attribute = 0)
610{
611    //  if (!$user || !$attribute) return;
612    global $table_prefix, $tables;
613    // workaround for integration webbler/phplist
614    if (!isset($table_prefix)) {
615        $table_prefix = 'phplist_';
616    }
617
618    if ($tables['attribute']) {
619        $att_table = $tables['attribute'];
620        $user_att_table = $tables['user_attribute'];
621    } else {
622        $att_table = 'attribute';
623        $user_att_table = 'user_attribute';
624    }
625    if (!Sql_Table_exists($att_table)) {
626        return "broken attribute $attribute";
627    }
628    $att = Sql_Fetch_array_Query("select * from $att_table where id = $attribute");
629    // $value = UserAttributeValue($att["tablename"],$attribute);
630    $value = UserAttributeValue($user, $attribute);
631//  $html = 'Value: '.$value;
632    $html = sprintf('<select name="attribute[%d]" style="attributeinput" >', $attribute);
633    $res = Sql_Query("select id,name from $table_prefix".'listattr_'.$att['tablename'].' order by listorder,name');
634    if (!Sql_Affected_Rows()) {
635        return '(No values available)';
636    }
637    $html .= '<option value="0">-- no value</option>';
638    while ($row = Sql_Fetch_Row($res)) {
639        if ($row[1] != '') {
640            $html .= sprintf('<option value="%d" %s>%s </option>', $row[0],
641                $row[1] == $value ? 'selected="selected"' : '', $row[1]);
642        }
643    }
644
645    return $html.'</select>';
646}
647
648function UserAttributeValueCbGroup($user = 0, $attribute = 0)
649{
650    //  if (!$user || !$attribute) return;
651    global $table_prefix, $tables;
652    if ($tables['attribute']) {
653        $att_table = $tables['attribute'];
654        $user_att_table = $tables['user_attribute'];
655    } else {
656        $att_table = 'attribute';
657        $user_att_table = 'user_attribute';
658    }
659    // workaround for integration webbler/phplist
660    if (!isset($table_prefix)) {
661        $table_prefix = 'phplist_';
662    }
663
664    $att = Sql_Fetch_array_Query("select * from $att_table where id = $attribute");
665    $values_req = Sql_Fetch_Row_Query("select value from $user_att_table where userid = $user and attributeid = $attribute");
666    $values = explode(',', $values_req[0]);
667    $html = sprintf('<input type="hidden" name="cbgroup[]" value="%d" /><table>', $attribute);
668    // $html = sprintf('<select name="attribute[%d]" style="attributeinput" >',$attribute);
669    $res = Sql_Query("select id,name from $table_prefix".'listattr_'.$att['tablename'].' order by listorder,name');
670    if (!Sql_Affected_Rows()) {
671        return '(No values available)';
672    }
673    while ($row = Sql_Fetch_Row($res)) {
674        $html .= sprintf('<tr><td><input type="checkbox" name="cbgroup%d[]" value="%d" %s /></td><td>%s</td></tr>',
675            $attribute, $row[0], in_array($row[0], $values) ? 'checked' : '', $row[1]);
676    }
677
678    return $html.'</table>';
679}
680
681function userGroups($loginname)
682{
683    $result = array();
684    if (Sql_Table_exists('user_group')) {
685        $req = Sql_Query(sprintf('select groupid from user_group,user where user_group.userid = user.id and user.email = "%s"',
686            addslashes($loginname)));
687        while ($row = Sql_Fetch_Row($req)) {
688            array_push($result, $row[0]);
689        }
690        $ev = getEveryoneGroupID();
691        array_push($result, $ev);
692    }
693
694    return $result;
695}
696
697function is_email($email)
698{
699    if (function_exists('idn_to_ascii') && mb_strlen($email) != strlen($email)) {
700        $elements = explode('@', strrev($email), 2);
701        if (!empty($elements[0]) && !empty($elements[1])) {
702            $email = strrev($elements[1]).'@'.idn_to_ascii(strrev($elements[0]));
703        }
704        unset($elements);
705    }
706
707    //@@ dont_require_validemail should be replaced by EMAIL_ADDRESS_VALIDATION_LEVEL
708    if (isset($GLOBALS['config']) && isset($GLOBALS['config']['dont_require_validemail']) && $GLOBALS['config']['dont_require_validemail']) {
709        return 1;
710    }
711
712    $email = trim($email);
713    //# remove XN-- before matching
714    $email = preg_replace('/@XN--/i', '@', $email);
715
716    //# do some basic validation first
717    // quite often emails have two @ signs
718    $ats = substr_count($email, '@');
719    if ($ats != 1) {
720        return 0;
721    }
722
723    //# fail on emails starting or ending "-" or "." in the pre-at, seems to happen quite often, probably cut-n-paste errors
724    if (preg_match('/^-/', $email) ||
725        preg_match('/-@/', $email) ||
726        preg_match('/\.@/', $email) ||
727        preg_match('/^\./', $email) ||
728        preg_match('/^\-/', $email) ||
729        strpos($email, '\\') === 0
730    ) {
731        return 0;
732    }
733
734    $tlds = getConfig('internet_tlds');
735    if (empty($tlds)) {
736        $tlds = 'ac|ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|asia|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cat|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dev|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|home|hr|ht|hu|id|ie|il|im|in|info|int|io|iq|ir|is|it|jm|je|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|loc|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tm|tn|to|tp|tr|travel|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw';
737    }
738
739    switch (EMAIL_ADDRESS_VALIDATION_LEVEL) {
740        case 0: // No email address validation.
741            return 1;
742            break;
743
744        case 2: // RFC821 email validation without escaping and quoting of local part
745        case 3: // RFC821 email validation.
746            // $email is a valid address as defined by RFC821
747            // Except:
748            //   Length of domainPart is not checked
749            //   Not accepted are CR and LF even if escaped by \
750            //   Not accepted is Folding
751            //   Not accepted is literal domain-part (eg. [1.0.0.127])
752            //   Not accepted is comments (eg. (this is a comment)@example.com)
753            // Extra:
754            //   topLevelDomain can only be one of the defined ones
755            $escapedChar = '\\\\[\\x01-\\x09\\x0B-\\x0C\\x0E-\\x7F]';   // CR and LF excluded for safety reasons
756            $unescapedChar = "[a-zA-Z0-9!#$%&'*\+\-\/=?^_`{|}~]";
757            if (EMAIL_ADDRESS_VALIDATION_LEVEL == 2) {
758                $char = "$unescapedChar";
759            } else {
760                $char = "($unescapedChar|$escapedChar)";
761            }
762            $dotString = "$char((\.)?$char){0,63}";
763
764            $qtext = '[\\x01-\\x09\\x0B-\\x0C\\x0E-\\x21\\x23-\\x5B\\x5D-\\x7F]'; // All but <LF> x0A, <CR> x0D, quote (") x22 and backslash (\) x5c
765            $qchar = "$qtext|$escapedChar";
766            $quotedString = "\"($qchar){1,62}\"";
767            if (EMAIL_ADDRESS_VALIDATION_LEVEL == 2) {
768                $localPart = "$dotString";  // without escaping and quoting of local part
769            } else {
770                $localPart = "($dotString|$quotedString)";
771            }
772            $topLevelDomain = '('.$tlds.')';
773            $domainLiteral = "((([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))";
774
775            $domainPart = "([a-zA-Z0-9](-?[a-zA-Z0-9])*(\.[a-zA-Z0-9](-?[a-zA-Z0-9])*)*\.$topLevelDomain|$domainLiteral)";
776            $validEmailPattern = "/^$localPart@$domainPart$/i"; // result: /^(([a-zA-Z0-9!#$%&'*\+\-\/=?^_`{|}~]|\\[\x01-\x09\x0B-\x0C\x0E-\x7F])((\.)?([a-zA-Z0-9!#$%&'*\+\-\/=?^_`{|}~]|\\[\x01-\x09\x0B-\x0C\x0E-\x7F])){0,63}|"([\x01-\x09\x0B-\x0C\x0E-\x21\x23-\x5B\x5D-\x7F]|\\[\x01-\x09\x0B-\x0C\x0E-\x7F]){1,62}")@([a-zA-Z0-9](-?[a-zA-Z0-9])*(\.[a-zA-Z](-?[a-zA-Z0-9])*)*\.(ac|ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cat|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dev|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|home|hr|ht|hu|id|ie|il|im|in|info|int|io|iq|ir|is|it|jm|je|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|loc|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|quipu|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)|((([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])))$/i
777
778            if (preg_match($validEmailPattern, $email)) {
779                return 1;
780            } else {
781                return 0;
782            }
783            break;
784
785        default: // 10.4 style email validation
786
787            // hmm, it seems people are starting to have emails with & and ' or ` chars in the name
788
789            $pattern = "/^[\&\'-_.[:alnum:]]+@((([[:alnum:]]|[[:alnum:]][[:alnum:]-]*[[:alnum:]])\.)+('.$tlds.')|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$/i";
790
791            if (preg_match($pattern, $email)) {
792                return 1;
793            } else {
794                return 0;
795            }
796            break;
797    }
798}
799
800function addUserHistory($email, $msg, $detail)
801{
802    global $table_prefix, $tables;
803    if (isset($tables['user'])) {
804        $user_table = $tables['user'];
805    } else {
806        $user_table = 'user';
807    }
808    if (isset($tables['user_history'])) {
809        $user_his_table = $tables['user_history'];
810    } else {
811        $user_his_table = 'user_history';
812    }
813    if (empty($detail)) { //# ok duplicated, but looks better :-)
814        $detail = $msg;
815    }
816
817    $sysinfo = '';
818    $sysarrays = array_merge($_ENV, $_SERVER);
819    if (isset($GLOBALS['userhistory_systeminfo']) && is_array($GLOBALS['userhistory_systeminfo'])) {
820        foreach ($GLOBALS['userhistory_systeminfo'] as $key) {
821            if (isset($sysarrays[$key])) {
822                $sysinfo .= "\n$key = $sysarrays[$key]";
823            }
824        }
825    } elseif (isset($GLOBALS['config']['userhistory_systeminfo']) && is_array($GLOBALS['config']['userhistory_systeminfo'])) {
826        foreach ($GLOBALS['config']['userhistory_systeminfo'] as $key) {
827            if ($sysarrays[$key]) {
828                $sysinfo .= "\n$key = $sysarrays[$key]";
829            }
830        }
831    } else {
832        $default = array('HTTP_USER_AGENT', 'HTTP_REFERER', 'REMOTE_ADDR', 'REQUEST_URI','HTTP_X_FORWARDED_FOR');
833        foreach ($sysarrays as $key => $val) {
834            if (in_array($key, $default)) {
835                $sysinfo .= "\n".strip_tags($key).' = '.htmlspecialchars($val);
836            }
837        }
838    }
839
840    $userid = Sql_Fetch_Row_Query("select id from $user_table where email = \"$email\"");
841    if ($userid[0]) {
842        Sql_Query(sprintf('insert into %s (ip,userid,date,summary,detail,systeminfo)
843            values("%s",%d,now(),"%s","%s","%s")', $user_his_table, getClientIP(), $userid[0], sql_escape($msg),
844            sql_escape(htmlspecialchars($detail)), sql_escape($sysinfo)));
845    }
846}
847
848function validateEmail($email)
849{
850    if (!empty($GLOBALS['config']['dont_require_validemail'])) {
851        return 1;
852    }
853    //if (!isset($GLOBALS["check_for_host"])) {
854    $GLOBALS['check_for_host'] = 0;
855    //}
856    if (!empty($email) && $GLOBALS['check_for_host']) {
857        if (strpos($email, '@')) {
858            list($username, $domaincheck) = explode('@', $email);
859            // checking for an MX is not sufficient
860            //    $mxhosts = array();
861            //    $validhost = getmxrr ($domaincheck,$mxhosts);
862            $validhost = checkdnsrr($domaincheck, 'MX') || checkdnsrr($domaincheck, 'A');
863        } else {
864            $validhost = 0;
865        }
866    } else {
867        $validhost = 1;
868    }
869    $pluginValidated = true;
870    foreach ($GLOBALS['plugins'] as $plName => $plugin) {
871        $pluginValidated = $pluginValidated && $plugin->validateEmailAddress($email);
872    }
873
874    return $pluginValidated && $validhost && is_email($email);
875}
876
877function validMod10($no)
878{
879    $dups = array();
880    $rev = strrev($no);
881    for ($i = 0; $i < strlen($rev); ++$i) {
882        if ($i % 2 == 1) {
883            array_push($dups, substr($rev, $i, 1) * 2);
884        } else {
885            array_push($dups, substr($rev, $i, 1));
886        }
887    }
888    $total = 0;
889    foreach ($dups as $dig) {
890        for ($i = 0; $i < strlen($dig); ++$i) {
891            $total += substr($dig, $i, 1);
892        }
893        // print "$dig - $total<br/>";
894    }
895
896    return $total % 10 == 0;
897
898// print "$no";
899}
900
901function validateCC($ccno)
902{
903    // credit card validation routines here
904    // major credit cards that you might want to validate.
905
906    //CARD TYPE Prefix Length Check digit algorithm
907    //MASTERCARD 51-55 16 mod 10
908    //VISA 4 13,16 mod 10
909    //AMEX 34,37 15 mod 10
910    //Diners Club/Carte Blanche 300-305,36,38 14 mod 10
911    //Discover 6011 16 mod 10
912    //enRoute 2014,2149 15 any
913    //JCB 3 16 mod 10
914    //JCB 2131,1800 15 mod 10
915    $ccno = preg_replace("/\D/", '', $ccno);
916    $length = strlen($ccno);
917    $firsttwo = substr($ccno, 0, 2);
918    $firstthree = substr($ccno, 0, 3);
919    $first = substr($ccno, 0, 1);
920    $firstfour = substr($ccno, 0, 4);
921
922    if ($firsttwo >= 51 && $firsttwo <= 55) { // Mastercard
923        return $length == 16 && validMod10($ccno);
924    } elseif ($first == 4) { // visa
925        return ($length == 13 || $length == 16) && validMod10($ccno);
926    } elseif ($firsttwo == 34 || $firsttwo == 37) { // Amex
927        return $length == 15 && validMod10($ccno);
928    } elseif (($firstthree >= 300 && $firstthree <= 305) // Diners1
929        || ($firsttwo == 36 || $firsttwo == 38)
930    ) { // Diners2
931        return $length == 14 && validMod10($ccno);
932    } elseif ($firstfour == 6011) { // discover
933        return $length == 16 && validMod10($ccno);
934    } elseif ($firstfour == 2014 || $firstfour == 2149) { // enRoute
935        return $length == 15;
936    } else {
937        // if it is not any of the above, we do not know how to validate it
938
939        // reject 4 and 15 1s anyway apart when request is from tincan offices
940        if ($ccno == '4111111111111111') {
941            return 0;
942        }
943    }
944
945    return 1;
946}
947
948function loadCCvalidationFile($ccrangefile)
949{
950    if (!is_file($ccrangefile)) {
951        return array();
952    }
953    $range = array();
954    $fp = fopen($ccrangefile, 'rb');
955    $contents = fread($fp, filesize($ccrangefile));
956    fclose($fp);
957    $lines = explode("\n", $contents);
958    foreach ($lines as $line) {
959        if (!preg_match("/^\s*#/", $line) && !preg_match("/^\s+$/", $line)) {
960            if (preg_match("#(\d+),(\d+),(\d+)#", $line, $regs)) {
961                //        print "RANGE".$line."<br/>";
962                array_push($range, array(
963                    'start'   => substr($regs[1], 0, 6),
964                    'end'     => substr($regs[2], 0, 6),
965                    'company' => sprintf('%02d', $regs[3]),
966                ));
967                //   dbg($regs[1]. " ". $regs[2]. " -> ".$regs[3]);
968            } elseif (preg_match("#\((\d+)\)\s*=\s*'(.*)'#", $line, $regs)) {
969                //        print "COMPANY".$line."<br/>";
970                $company[sprintf('%02d', $regs[1])] = $regs[2];
971                //   dbg($regs[1]. " = " . $regs[2]);
972            }
973        }
974    }
975
976    return array($range, $company);
977}
978
979function ccCompany($ccno)
980{
981    global $config;
982    $ccrangefile = $config['code_root'].'/'.$config['uploader_dir'].'/codelib/ccvalidation.txt';
983    list($ranges, $companies) = loadCCvalidationFile($ccrangefile);
984    $first6 = substr($ccno, 0, 6);
985    if (is_array($ranges)) {
986        foreach ($ranges as $range) {
987            //  dbg($range["start"]);
988//    print "CHECKING ".$range["start"].' TO '.$range["end"].'<br/>';
989            if ($range['start'] <= $first6 && $range['end'] >= $first6) {
990                return array($range['company'], $companies[$range['company']]);
991            }
992        }
993    }
994
995    return -1;
996}
997
998function checkCCrange($ccno)
999{
1000    global $config;
1001    $ccrangefile = $config['code_root'].'/'.$config['uploader_dir'].'/codelib/ccvalidation.txt';
1002    if (!is_file($ccrangefile) || !is_array($config['cc_accept_company'])) {
1003        return 1;
1004    }
1005    list($companyid, $companyname) = ccCompany($ccno);
1006    if ($companyid > 0 && in_array($companyid, $config['cc_accept_company'])) {
1007        //  dbg($ccno . " is valid for company $companyid $companyname");
1008        return 1;
1009    } elseif ($companyid < 0) {
1010        return -1;
1011    } else {
1012        return 0;
1013    }
1014}
1015
1016function validateCCExpiry($ccexpiry)
1017{
1018    // expiry date validation here
1019    $mon = substr($ccexpiry, 0, 2);
1020    if (strlen($ccexpiry) == 5) {
1021        // I presume it is with a separator
1022        $year = substr($ccexpiry, 3, 2);
1023    } elseif (strlen($ccexpiry) == 4) {
1024        $year = substr($ccexpiry, 2, 2);
1025    } else {
1026        return 0;
1027    }
1028    $yeardiff = $year - date('y');
1029
1030    return $mon < 13 && $yeardiff < 9 && (($year > date('y')) || ($year == date('y') && $mon >= date('m')));
1031}
1032
1033function obscureCreditCard($cardno)
1034{
1035    if (strlen($cardno) < 5) {
1036        return $cardno;
1037    }
1038
1039    $res = substr($cardno, strlen($cardno) - 4, 4);
1040    for ($i = 0; $i < strlen($cardno) - 4; ++$i) {
1041        $prefix .= '*';
1042    }
1043    $res = $prefix.$res;
1044
1045    return $res;
1046}
1047
1048function loadUser($loginname = '')
1049{
1050    if (!Sql_Table_exists('user')) {
1051        return;
1052    }
1053    initialiseUserSession();
1054    if (!$loginname) {
1055        if ($_SESSION['userloggedin'] != '' && $_SESSION['username'] != '') {
1056            $loginname = $_SESSION['username'];
1057        } else {
1058            return '';
1059        }
1060    }
1061    $att_req = Sql_Query(sprintf('select attribute.id,
1062    %s.name,%s.type,
1063    %s.value,%s.tablename from %s,%s,%s
1064    where %s.userid = %s.id and %s.email = "%s" and %s.id = %s.attributeid',
1065        'attribute',
1066        'attribute',
1067        'user_attribute',
1068        'attribute',
1069        'user',
1070        'user_attribute',
1071        'attribute',
1072        'user_attribute',
1073        'user',
1074        'user',
1075        addslashes($loginname),
1076        'attribute',
1077        'user_attribute'
1078    ));
1079    while ($att = Sql_fetch_array($att_req)) {
1080        //   if (!defined($_SESSION["userdata"]["attribute".$att["id"]])) {
1081        $_SESSION['userdata']['attribute'.$att['id']] = array(
1082            'name'         => $att['name'],
1083            'value'        => $att['value'],
1084            'type'         => $att['type'],
1085            'attid'        => $att['id'],
1086            'displayvalue' => $att['value'],
1087        );
1088        switch ($att['type']) {
1089            case 'textline':
1090            case 'hidden':
1091                $_SESSION['userdata']['attribute'.$att['id']]['displayvalue'] =
1092                    $att['value'];
1093                break;
1094            case 'creditcardno':
1095                $_SESSION['userdata']['attribute'.$att['id']]['displayvalue'] =
1096                    obscureCreditCard($att['value']);
1097                break;
1098            case 'select':
1099                $_SESSION['userdata']['attribute'.$att['id']]['displayvalue'] =
1100                    AttributeValue($att['tablename'], $att['value']);
1101                break;
1102            case 'date':
1103                $_SESSION['userdata']['attribute'.$att['id']]['displayvalue'] =
1104                    formatDate($att['value']);
1105                break;
1106        }
1107//    }
1108    }
1109    $d_req = Sql_Fetch_Array_Query("select * from user where email = \"$loginname\"");
1110    $_SESSION['userid'] = $d_req['id'];
1111    foreach (array('email', 'disabled', 'confirmed', 'htmlemail', 'uniqid', 'password', 'foreignkey') as $field) {
1112        //   if (!defined($_SESSION["userdata"][$field])) {
1113        $_SESSION['userdata'][$field] = array(
1114            'name'         => $field,
1115            'value'        => $d_req[$field],
1116            'type'         => 'static',
1117            'displayvalue' => $d_req[$field],
1118        );
1119//     }
1120    }
1121    $_SESSION['usergroups'] = userGroups($loginname);
1122    if (is_array($GLOBALS['config']['usergreeting'])) {
1123        $_SESSION['usergreeting'] = '';
1124        foreach ($GLOBALS['config']['usergreeting'] as $att) {
1125            $_SESSION['usergreeting'] .= $_SESSION['userdata'][$att]['displayvalue'].' ';
1126        }
1127        $_SESSION['usergreeting'] = rtrim($_SESSION['usergreeting']);
1128    }
1129    dbg('done loading user');
1130
1131    return 1;
1132}
1133
1134function addKeywordLibrary($name)
1135{
1136    $req = Sql_Query(sprintf('select id from keywordlib where name = "%s"', $name));
1137    if (Sql_affected_Rows()) {
1138        $row = Sql_Fetch_Row($req);
1139
1140        return $row[0];
1141    }
1142    Sql_Query(sprintf('insert into keywordlib (name) values("%s")', $name));
1143
1144    return Sql_Insert_id();
1145}
1146
1147function getNewAttributeTablename($name)
1148{
1149    global $table_prefix, $tables;
1150    if ($tables['attribute']) {
1151        $table = $tables['attribute'];
1152    } else {
1153        $table = 'attribute';
1154    }
1155    $lc_name = substr(preg_replace("/\W/", '', strtolower($name)), 0, 25);
1156//  if ($lc_name == "") Fatal_Error("Name cannot be empty: $lc_name");
1157    if (!$lc_name) {
1158        $lc_name = 'attribute';
1159    }
1160    Sql_Query("select * from $table where tablename = \"$lc_name\"");
1161//  if (Sql_Affected_Rows()) Fatal_Error("Name is not unique enough");
1162    $c = 1;
1163    $basename = $lc_name;
1164    while (Sql_Affected_Rows() && $c < 100) {
1165        $lc_name = $basename.$c;
1166        Sql_Query("select * from $table where tablename = \"$lc_name\"");
1167        ++$c;
1168    }
1169
1170    return $lc_name;
1171}
1172
1173function isGuestAccount()
1174{
1175    if (!is_array($_SESSION['userdata'])) {
1176        return 1;
1177    }
1178    if ($GLOBALS['config']['guestaccount_attribute']) {
1179        return $_SESSION['userdata'][$GLOBALS['config']['guestaccount_attribute']]['value'];
1180    }
1181    if ($GLOBALS['config']['guestaccount_email_match']) {
1182        return preg_match($GLOBALS['config']['guestaccount_email_match'], $_SESSION['userdata']['email']['value']);
1183    }
1184}
1185
1186function saveUserAttribute($userid, $attid, $data)
1187{
1188    global $usertable_prefix, $table_prefix, $tables;
1189    // workaround for integration webbler/phplist
1190    if (!isset($usertable_prefix)) {
1191        $usertable_prefix = '';
1192    }
1193    if (!isset($table_prefix)) {
1194        $table_prefix = 'phplist_';
1195    }
1196    if (!empty($tables['attribute'])) {
1197        $att_table = $usertable_prefix.$tables['attribute'];
1198        $user_att_table = $usertable_prefix.$tables['user_attribute'];
1199    } else {
1200        $att_table = $usertable_prefix.'attribute';
1201        $user_att_table = $usertable_prefix.'user_attribute';
1202    }
1203
1204    if (!is_array($data)) {
1205        $tmp = $data;
1206        $data = Sql_Fetch_Assoc_Query(sprintf('select * from %s where id = %d', $att_table, $attid));
1207        $data['value'] = $tmp;
1208        $data['displayvalue'] = $tmp;
1209    }
1210    // dbg($data,'$data to store for '.$userid.' '.$attid);
1211
1212    if ($data['nodbsave']) {
1213        //   dbg($attid, "Not saving, nodbsave");
1214        return;
1215    }
1216    if ($attid == 'emailcheck' || $attid == 'passwordcheck') {
1217        //   dbg($attid, "Not saving, emailcheck/passwordcheck");
1218        return;
1219    }
1220
1221    if (!$data['type']) {
1222        $data['type'] = 'textline';
1223    }
1224
1225    if ($data['type'] == 'static' || $data['type'] == 'password' || $data['type'] == 'htmlpref') {
1226        if (!empty($GLOBALS['config']['dontsave_userpassword']) && $data['type'] == 'password') {
1227            $data['value'] = 'not authoritative';
1228        }
1229        Sql_Query(sprintf('update user set %s = "%s" where id = %d',
1230            $attid, $data['value'], $userid));
1231        dbg('Saving', $data['value'], DBG_TRACE);
1232        if ($data['type'] == 'password') {
1233            Sql_Query(sprintf('update user set passwordchanged = now(),password="%s" where id = %d',
1234                hash('sha256', $data['value']), $userid));
1235        }
1236
1237        return 1;
1238    }
1239
1240    $attributetype = $data['type'];
1241    $attid_req = Sql_Fetch_Row_Query(sprintf('
1242    select id,type,tablename from %s where id = %d', $att_table, $attid));
1243    if (!$attid_req[0]) {
1244        $attid_req = Sql_Fetch_Row_Query(sprintf('
1245      select id,type,tablename from %s where name = "%s"', $att_table, $data['name']));
1246        if (!$attid_req[0]) {
1247            if (!empty($data['name']) && $GLOBALS['config']['autocreate_attributes']) {
1248                //      Dbg("Creating new Attribute: ".$data["name"]);
1249                sendError('creating new attribute '.$data['name']);
1250                $atttable = getNewAttributeTablename($data['name']);
1251                Sql_Query(sprintf('insert into %s (name,type,tablename) values("%s","%s","%s")', $att_table,
1252                    $data['name'], $data['type'], $atttable));
1253                $attid = Sql_Insert_Id();
1254            } else {
1255                //     dbg("Not creating new Attribute: ".$data["name"]);
1256                // sendError("Not creating new attribute ".$data["name"]);
1257            }
1258        } else {
1259            $attid = $attid_req[0];
1260            if (empty($attributetype)) {
1261                $attributetype = $attid_req[1];
1262            }
1263            $atttable = $attid_req[2];
1264        }
1265    } else {
1266        $attid = $attid_req[0];
1267        if (empty($attributetype)) {
1268            $attributetype = $attid_req[1];
1269        }
1270        $atttable = $attid_req[2];
1271    }
1272
1273    if (!$atttable && !empty($data['name'])) {
1274        $atttable = getNewAttributeTablename($data['name']);
1275        // fix attribute without tablename
1276        Sql_Query(sprintf('update %s set tablename ="%s" where id = %d',
1277            $att_table, $atttable, $attid));
1278//   sendError("Attribute without Tablename $attid");
1279    }
1280
1281    switch ($attributetype) {
1282        case 'static':
1283        case 'password':
1284            //  dbg('SAVING STATIC OR  PASSWORD');
1285            if (!empty($GLOBALS['config']['dontsave_userpassword']) && $data['type'] == 'password') {
1286                $data['value'] = 'not authoritative';
1287            }
1288            Sql_Query(sprintf('update user set %s = "%s" where id = %d',
1289                $attid, $data['value'], $userid));
1290            break;
1291        case 'select':
1292            $curval = Sql_Fetch_Row_Query(sprintf('select id from '.$table_prefix.'listattr_%s
1293        where name = "%s"', $atttable, $data['displayvalue']), 1);
1294            if (!$curval[0] && $data['displayvalue'] && $data['displayvalue'] != '') {
1295                Sql_Query(sprintf('insert into '.$table_prefix.'listattr_%s (name) values("%s")', $atttable,
1296                    $data['displayvalue']));
1297                sendError('Added '.$data['displayvalue']." to $atttable");
1298                $valid = Sql_Insert_id();
1299            } else {
1300                $valid = $curval[0];
1301            }
1302            Sql_Query(sprintf('replace into %s (userid,attributeid,value)
1303        values(%d,%d,"%s")', $user_att_table, $userid, $attid, $valid));
1304
1305            break;
1306        case 'avatar':
1307            if (is_array($_FILES)) { //# only avatars are files, for now
1308                if (!defined('MAX_AVATAR_SIZE')) {
1309                    define('MAX_AVATAR_SIZE', 100000);
1310                }
1311
1312                $formfield = 'attribute'.$attid.'_file'; //# the name of the fileupload element
1313                if (!empty($_FILES[$formfield]['name']) && !empty($_FILES[$formfield]['tmp_name'])) {
1314                    $tmpnam = $_FILES[$formfield]['tmp_name'];
1315                    move_uploaded_file($tmpnam, '/tmp/avatar'.$userid.'.jpg');
1316                    $size = filesize('/tmp/avatar'.$userid.'.jpg');
1317//          dbg('New size: '.$size);
1318                    if ($size < MAX_AVATAR_SIZE) {
1319                        $avatar = file_get_contents('/tmp/avatar'.$userid.'.jpg');
1320                        Sql_Query(sprintf('replace into %s (userid,attributeid,value)
1321              values(%d,%d,"%s")', $user_att_table, $userid, $attid, base64_encode($avatar)));
1322                        unlink('/tmp/avatar'.$userid.'.jpg');
1323                    }
1324                }
1325            }
1326            break;
1327        default:
1328            Sql_Query(sprintf('replace into %s (userid,attributeid,value)
1329        values(%d,%d,"%s")', $user_att_table, $userid, $attid, $data['value']));
1330            break;
1331    }
1332
1333    return 1;
1334}
1335
1336function saveUserByID($userid, $data)
1337{
1338    dbg("Saving user by id $userid");
1339    foreach ($data as $key => $val) {
1340        if (preg_match("/^attribute(\d+)/", $key, $regs)) {
1341            $attid = $regs[1];
1342        } else {
1343            $attid = $key;
1344        }
1345        dbg("Saving attribute $key, $attid, $val for $userid");
1346        if ($userid && $attid && $data[$key]['type'] != 'userfield' && !$data[$key]['nodbsave']) {
1347            saveUserAttribute($userid, $attid, $val);
1348        }
1349    }
1350}
1351
1352function saveUser($loginname, $data)
1353{
1354    dbg("Saving user $loginname");
1355    // saves user to database
1356    $id_req = Sql_Fetch_Row_Query("select id from user where email = \"$loginname\"");
1357    if ($id_req[0]) {
1358        $userid = $id_req[0];
1359        foreach ($data as $key => $val) {
1360            if (preg_match("/^attribute(\d+)/", $key, $regs)) {
1361                $attid = $regs[1];
1362            }
1363            //     dbg("Saving attribute $key, $attid, $val for $loginname, $userid");
1364            if ($userid && $attid) {
1365                saveUserAttribute($userid, $key, $val);
1366            }
1367        }
1368    }
1369
1370    return 1;
1371}
1372
1373function saveUserData($username, $fields)
1374{
1375    // saves data in session, not in database
1376    if (!is_array($_SESSION['userdata'])) {
1377        initialiseUserSession();
1378    }
1379    if (!empty($GLOBALS['usersaved'])) {
1380        return;
1381    }
1382    if (!$username) {
1383        $username = 'Unknown User';
1384    }
1385    dbg("Saving user in session $username", '', DBG_TRACE);
1386
1387    $res = '';
1388    $required_fields = explode(',', $_POST['required']);
1389    if ($_POST['unrequire']) {
1390        $unrequired_fields = explode(',', $_POST['unrequire']);
1391        $required_fields = array_diff($required_fields, $unrequired_fields);
1392    } else {
1393        $unrequired_fields = array();
1394    }
1395    $required_formats = explode(',', $_POST['required_formats']);
1396    $description_fields = explode(',', $_POST['required_description']);
1397
1398    reset($fields);
1399//  dbg("Checking fields");
1400    foreach ($fields as $fname => $fielddetails) {
1401        dbg('Saving user Saving '.$fname.' to session '.$_POST[$fname]);
1402        //   dbg($fielddetails);
1403        $key = $fname;
1404        $val = $_POST[$fname];
1405        if (strpos($key, 'required') === false && $key != 'unrequire' &&
1406            $fields[$key]['type'] != 'separator' &&
1407            $fields[$key]['type'] != 'emailcheck' &&
1408            $fields[$key]['type'] != 'passwordcheck'
1409        ) {
1410            //   dbg($fname ." of type ".$fields[$key]["type"]);
1411            if (!is_array($_SESSION['userdata'][$key])) {
1412                $_SESSION['userdata'][$key] = array();
1413            }
1414            $_SESSION['userdata'][$key]['name'] = $fields[$key]['name'];
1415            $_SESSION['userdata'][$key]['type'] = $fields[$key]['type'];
1416            if ($fields[$key]['type'] == 'date') {
1417                $_SESSION['userdata'][$key]['value'] = sprintf('%04d-%02d-%02d',
1418                    $_POST['year'][$key], $_POST['month'][$key], $_POST['day'][$key]);
1419                $_SESSION['userdata'][$key]['displayvalue'] = $_SESSION['userdata'][$key]['value'];
1420            } elseif ($fields[$key]['type'] == 'creditcardno') {
1421                // dont overwrite known CC with ***
1422                if (!preg_match("#^\*+#", $val)) {
1423                    $_SESSION['userdata'][$key]['value'] = ltrim($val);
1424                }
1425            } else {
1426                $_SESSION['userdata'][$key]['value'] = ltrim($val);
1427            }
1428            if ($fields[$key]['type'] == 'select') {
1429                if (!empty($val) && is_array($fields[$key]['values'])) {
1430                    $_SESSION['userdata'][$key]['displayvalue'] = $fields[$key]['values'][$val];
1431                }
1432            } elseif ($fields[$key]['type'] == 'checkboxgroup') {
1433                if (is_array($val)) { // if val is empty join crashes
1434                    $_SESSION['userdata'][$key]['value'] = implode(',', $val);
1435                }
1436            } elseif ($fields[$key]['type'] == 'creditcardno') {
1437                // erase any non digits from the CC numbers
1438                $_SESSION['userdata'][$key]['value'] = preg_replace("/\D/", '', $_SESSION['userdata'][$key]['value']);
1439                $_SESSION['userdata'][$key]['displayvalue'] = obscureCreditCard($_SESSION['userdata'][$key]['value']);
1440            } elseif ($fields[$key]['name'] == 'Card Number') {
1441                $_SESSION['userdata'][$key]['value'] = preg_replace("/\D/", '', $_SESSION['userdata'][$key]['value']);
1442                $_SESSION['userdata'][$key]['displayvalue'] = obscureCreditCard($_SESSION['userdata'][$key]['value']);
1443                /*          $_SESSION["userdata"][$key]["displayvalue"] = substr($_SESSION["userdata"][$key]["displayvalue"],0,4);
1444                          for ($i=0;$i<strlen($_SESSION["userdata"][$key]["value"]-4);$i++) {
1445                            $_SESSION["userdata"][$key]["displayvalue"] .= '*';
1446                          }
1447                */
1448            } else {
1449                $_SESSION['userdata'][$key]['displayvalue'] = $val;
1450            }
1451
1452            foreach ($fielddetails as $field_attr => $field_attr_value) {
1453                if (!isset($_SESSION['userdata'][$key][$field_attr]) && !preg_match("/^\d+$/", $key)
1454                    && !preg_match("/^\d+$/", $field_attr)
1455                ) {
1456                    $_SESSION['userdata'][$key][$field_attr] = $field_attr_value;
1457                }
1458            }
1459            // save it to the DB as well
1460        } else {
1461            //       dbg("Not checking ".$fname ." of type ".$fields[$key]["type"]);
1462        }
1463    }
1464
1465    // fix UK postcodes to correct format
1466    if ($_SESSION['userdata'][$GLOBALS['config']['country_attribute']]['displayvalue'] == 'United Kingdom' && isset($_SESSION['userdata'][$GLOBALS['config']['postcode_attribute']]['value'])) {
1467        $postcode = $_SESSION['userdata'][$GLOBALS['config']['postcode_attribute']]['value'];
1468        $postcode = strtoupper(str_replace(' ', '', $postcode));
1469        if (preg_match("/(.*)(\d\w\w)$/", $postcode, $regs)) {
1470            $_SESSION['userdata'][$GLOBALS['config']['postcode_attribute']]['value'] = trim($regs[1]).' '.$regs[2];
1471            $_SESSION['userdata'][$GLOBALS['config']['postcode_attribute']]['displayvalue'] = trim($regs[1]).' '.$regs[2];
1472        }
1473    }
1474
1475    dbg('Checking required fields');
1476    reset($required_fields);
1477    foreach ($required_fields as $index => $field) {
1478        $type = $fields[$field]['type'];
1479        // dbg("$field of type $type");
1480        if ($type != 'userfield' && $type != '') { //## @@@ need to check why type is not set
1481            if ($field && !$_SESSION['userdata'][$field]['value']) {
1482                $res = 'Information missing: '.$description_fields[$index];
1483                break;
1484            } elseif ($required_formats[$index] && !preg_match(stripslashes($required_formats[$index]),
1485                    $_SESSION['userdata'][$field]['value'])
1486            ) {
1487                $res = 'Sorry, you entered an invalid '.$description_fields[$index].': '.$_SESSION['userdata'][$field]['value'];
1488                break;
1489            } elseif ($field == 'email' && !validateEmail($_SESSION['userdata'][$field]['value'])) {
1490                $res = 'Sorry, the following field cannot be validated: '.$description_fields[$index].': '.$_SESSION['userdata'][$field]['value'];
1491                break;
1492            } elseif ($field == 'emailcheck' && $_SESSION['userdata']['email']['value'] != $_SESSION['userdata']['emailcheck']['value']) {
1493                $res = 'Emails entered are not the same';
1494                break;
1495            } elseif ($field == 'cardtype' && $_SESSION['userdata'][$field]['value'] == 'WSWITCH' && !preg_match("/\d/",
1496                    $_SESSION['userdata']['attribute82']['value'])
1497            ) {
1498                $res = 'Sorry, a Switch Card requires a valid issue number. If you have a new Switch card without an issue number, please use 0 as the issue number.';
1499                break;
1500            } elseif ($field == 'cardtype' && isset($_SESSION['userdata'][$field]['value']) && $_SESSION['userdata'][$field]['value'] != 'WSWITCH' && $_SESSION['userdata']['attribute82']['value']) {
1501                $res = 'Sorry, an issue number is not valid when not using a Switch Card';
1502                break;
1503            } elseif (($type == 'creditcardno' || $field == 'cardnumber') && isset($_SESSION['userdata'][$field]['value']) && !checkCCrange($_SESSION['userdata'][$field]['value'])) {
1504                list($cid, $cname) = ccCompany($_SESSION['userdata'][$field]['value']);
1505                if (!$cname) {
1506                    $cname = '(Unknown Credit card)';
1507                }
1508                $res = "Sorry, we currently don't accept $cname cards";
1509                break;
1510            } elseif (($type == 'creditcardno' || $field == 'cardnumber') && isset($_SESSION['userdata'][$field]['value']) && !validateCC($_SESSION['userdata'][$field]['value'])) {
1511                $res = 'Sorry, you entered an invalid '.$description_fields[$index]; //.": ".$_SESSION["userdata"][$field]["value"];
1512                break;
1513            } elseif (($type == 'creditcardexpiry' || $field == 'cardexpiry') && isset($_SESSION['userdata'][$field]['value']) && !validateCCExpiry($_SESSION['userdata'][$field]['value'])) {
1514                $res = 'Sorry, you entered an invalid '.$description_fields[$index].': '.$_SESSION['userdata'][$field]['value'];
1515                break;
1516            }
1517        }
1518    }
1519    if (0 && isset($_SESSION['userdata'][$GLOBALS['config']['country_attribute']]['displayvalue']) && $_SESSION['userdata'][$GLOBALS['config']['country_attribute']]['displayvalue'] == 'United Kingdom' && isset($_SESSION['userdata'][$GLOBALS['config']['postcode_attribute']]['value'])) {
1520        $postcode = $_SESSION['userdata'][$GLOBALS['config']['postcode_attribute']]['displayvalue'];
1521        if (!preg_match("/(.*)(\d\w\w)$/", $postcode, $regs)) {
1522            $res = 'That does not seem to be a valid UK postcode';
1523        } elseif (!preg_match("/^[\s\w\d]+$/", $postcode, $regs)) {
1524            $res = 'That does not seem to be a valid UK postcode';
1525        }
1526    }
1527    /*  if (is_array($GLOBALS["config"]["bocs_dpa"])) {
1528        if (!is_array($_SESSION["DPA"]))
1529          $_SESSION["DPA"] = array();
1530        foreach ($GLOBALS["config"]["bocs_dpa"] as $dpaatt => $val) {
1531          if ($_SESSION["userdata"][$dpaatt]["displayvalue"]) {
1532            $_SESSION["DPA"][$val] = "Y";
1533          } else {
1534            $_SESSION["DPA"][$val] = "N";
1535          }
1536        }
1537      }*/
1538    // if no error in form check for subscriptions
1539    if (!$res && is_object($GLOBALS['config']['plugins']['phplist'])) {
1540        $phplist = $GLOBALS['config']['plugins']['phplist'];
1541        foreach ($_SESSION['userdata'] as $key => $field) {
1542            if (($field['formtype'] == 'List Subscription' || $field['type'] == 'List Subscription') && $field['listid']) {
1543                $listid = $field['listid'];
1544                if ($field['value'] && isset($_SESSION['userdata']['email'])) {
1545                    if ($phplist->addEmailToList($_SESSION['userdata']['email']['value'], $listid)) {
1546                        $phplist->confirmEmail($_SESSION['userdata']['email']['value']);
1547                        //  sendError("User added to list: $listid");
1548                    } else {
1549                        // sendError("Error adding user to list: $listid");
1550                    }
1551                } //else {
1552                //$phplist->removeEmailFromList($_SESSION["userdata"]["email"]["value"],$listid);
1553                //}
1554            }
1555        }
1556    }
1557    $GLOBALS['usersaved'] = time();
1558
1559    return $res;
1560}
1561