File: lib.php

package info (click to toggle)
moodle 1.6.3-2%2Betch3
  • links: PTS
  • area: main
  • in suites: etch
  • size: 37,172 kB
  • ctags: 51,688
  • sloc: php: 231,916; sql: 5,631; xml: 2,688; sh: 1,185; perl: 638; makefile: 48; pascal: 36
file content (461 lines) | stat: -rw-r--r-- 15,465 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
<?php  // $Id: lib.php,v 1.21.2.3 2006/09/28 01:04:49 martinlanghoff Exp $
       // Authentication by looking up an external database table


function auth_user_login ($username, $password) {
// Returns true if the username and password work
// and false if they are wrong or don't exist.

    global $CFG;

    // This is a hack to workaround what seems to be a bug in ADOdb with accessing 
    // two databases of the same kind ... it seems to get confused when trying to access
    // the first database again, after having accessed the second.
    // The following hack will make the database explicit which keeps it happy
    // This seems to broke postgesql so ..

    $prefix = $CFG->prefix.'';    // Remember it.  The '' is to prevent PHP5 reference.. see bug 3223

    if ($CFG->dbtype != 'postgres7') {
        $CFG->prefix = $CFG->dbname.$CFG->prefix;
    }

    // Connect to the external database
    $authdb = &ADONewConnection($CFG->auth_dbtype); 
    $authdb->PConnect($CFG->auth_dbhost,$CFG->auth_dbuser,$CFG->auth_dbpass,$CFG->auth_dbname); 

    if ($CFG->auth_dbpasstype === 'internal') { 
        // lookup username externally, but resolve
        // password locally -- to support backend that
        // don't track passwords
        $rs = $authdb->Execute("SELECT * FROM $CFG->auth_dbtable 
                                 WHERE $CFG->auth_dbfielduser = '$username' ");
        $authdb->Close();

        if (!$rs) {
            notify("Could not connect to the specified authentication database...");

            return false;
        }
    
        if ( $rs->RecordCount() ) {
            // user exists exterally
            // check username/password internally
            if ($user = get_record('user', 'username', $username)) {
                return validate_internal_user_password($user, $password);
            }
        } else {
            // user does not exist externally
            return false;
        }  

    } else { 
        // normal case: use external db for passwords

        if ($CFG->auth_dbpasstype === 'md5') {   // Re-format password accordingly
            $password = md5($password);
        }

        $rs = $authdb->Execute("SELECT * FROM $CFG->auth_dbtable 
                            WHERE $CFG->auth_dbfielduser = '$username' 
                              AND $CFG->auth_dbfieldpass = '$password' ");
        $authdb->Close();
        
        $CFG->prefix = $prefix;
        
        if (!$rs) {
            notify("Could not connect to the specified authentication database...");
            return false;
        }
    
        if ( $rs->RecordCount() ) {
            return true;
        } else {
            return false;
        }        
        
    }
}


function auth_get_userinfo($username){
// Reads any other information for a user from external database,
// then returns it in an array

    global $CFG;

    $config = (array) $CFG;

    $pcfg = get_config('auth/db');
    $pcfg = (array) $pcfg;

    ADOLoadCode($CFG->auth_dbtype);          
    $authdb = &ADONewConnection();         
    $authdb->PConnect($CFG->auth_dbhost,$CFG->auth_dbuser,$CFG->auth_dbpass,$CFG->auth_dbname); 

    $fields = array("firstname", "lastname", "email", "phone1", "phone2", 
                    "department", "address", "city", "country", "description", 
                    "idnumber", "lang");

    $result = array();

    foreach ($fields as $field) {
        if ($pcfg["field_map_$field"]) {
            if ($rs = $authdb->Execute("SELECT ".$pcfg["field_map_$field"]." FROM $CFG->auth_dbtable
                                        WHERE $CFG->auth_dbfielduser = '$username'")) {
                if ( $rs->RecordCount() == 1 ) {
                    if (!empty($CFG->unicodedb)) {
                        $result["$field"] = addslashes(stripslashes($rs->fields[0]));
                    } else {
                        $result["$field"] = addslashes(stripslashes(utf8_decode($rs->fields[0])));
                    }
                }
            }
        }
    }

    return $result;
}


function auth_user_update_password($username, $newpassword) {
    global $CFG;
    if ($CFG->auth_dbpasstype === 'internal') {
        return set_field('user', 'password', md5($newpassword), 'username', $username);
    } else {
        // we should have never been called!
        return false;
    }
}

/**
 * syncronizes user fron external db to moodle user table
 *
 * Sync shouid be done by using idnumber attribute, not username.
 * You need to pass firstsync parameter to function to fill in
 * idnumbers if they dont exists in moodle user table.
 * 
 * Syncing users removes (disables) users that dont exists anymore in external db.
 * Creates new users and updates coursecreator status of users. 
 * 
 * @param bool $do_updates  Optional: set to true to force an update of existing accounts
 *
 * This implementation is simpler but less scalable than the one found in the LDAP module.
 *
 */
function auth_sync_users ($do_updates=0) {
    
    global $CFG;
    $pcfg = get_config('auth/db');

    ///
    /// list external users
    ///
    $userlist = auth_get_userlist();
    $quoteduserlist = implode("', '", $userlist);
    $quoteduserlist = "'$quoteduserlist'";

    ///
    /// delete obsolete internal users
    ///
       
    // find obsolete users
    if (count($userlist)) {
        $sql = 'SELECT u.id, u.username 
                FROM ' . $CFG->prefix .'user u 
                WHERE u.auth=\'db\' AND u.deleted=\'0\' AND u.username NOT IN (' . $quoteduserlist . ')';
    } else {
        $sql = 'SELECT u.id, u.username 
                FROM ' . $CFG->prefix .'user u 
                WHERE u.auth=\'db\' AND u.deleted=\'0\' ';
    }
    $remove_users = get_records_sql($sql); 

    if (!empty($remove_users)){
        print "User entries to remove: ". count($remove_users) . "\n";

        begin_sql();
        foreach ($remove_users as $user) {
            //following is copy pasted from admin/user.php
            //maybe this should moved to function in lib/datalib.php
            unset($updateuser);
            $updateuser->id = $user->id;
            $updateuser->deleted = "1";
            $updateuser->timemodified = time();
            if (update_record("user", $updateuser)) {
                unenrol_student($user->id);  // From all courses
                remove_teacher($user->id);   // From all courses
                remove_admin($user->id);
                notify(get_string("deletedactivity", "", fullname($user, true)) );
            } else {
                notify(get_string("deletednot", "", fullname($user, true)));
            }
            //copy pasted part ends
        }     
        commit_sql();
    } 
    unset($remove_users); // free mem!   

    if (!count($userlist)) {
        // exit right here
        // nothing else to do
        return true;
    }

    ///
    /// update existing accounts
    ///
    if ($do_updates) {
        // narrow down what fields we need to update
        $all_keys = array_keys(get_object_vars($pcfg));
        $updatekeys = array();
        foreach ($all_keys as $key) {
            if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) {
                if ($pcfg->{$key} === 'onlogin') {
                    array_push($updatekeys, $match[1]); // the actual key name
                }
            }
        }
        // print_r($all_keys); print_r($updatekeys);
        unset($all_keys); unset($key);

        // only go ahead if we actually
        // have fields to update locally
        if (!empty($updatekeys)) {
            $sql = 'SELECT u.id, u.username 
                    FROM ' . $CFG->prefix .'user u 
                    WHERE u.auth=\'db\' AND u.deleted=\'0\' AND u.username IN (' . $quoteduserlist . ')';
            $update_users = get_records_sql($sql);
        
            foreach ($update_users as $user) {
                auth_db_update_user_record($user->username, $updatekeys);
            }
            unset($update_users); // free memory
        }
    }


    ///
    /// create missing accounts
    ///
    // NOTE: this is very memory intensive
    // and generally inefficient
    $sql = 'SELECT u.id, u.username 
            FROM ' . $CFG->prefix .'user u 
            WHERE u.auth=\'db\' AND u.deleted=\'0\'';

    $users = get_records_sql($sql);
    
    // simplify down to usernames
    $usernames = array();
    foreach ($users as $user) {
        array_push($usernames, $user->username);
    }
    unset($users);

    $add_users = array_diff($userlist, $usernames);
    unset($usernames);

    if(!empty($add_users)){
        print "User entries to add: ". count($add_users). "\n";
        begin_sql();
        foreach($add_users as $user){
            $username = $user;
            $user = auth_get_userinfo_asobj($user);
            
            // prep a few params
            $user->username  = $username;
            $user->modified  = time();
            $user->confirmed = 1;
            $user->auth      = 'db';
            
            // insert it
            $old_debug=$CFG->debug; 
            $CFG->debug=10;
            
            // maybe the user has been deleted before
            if ($old_user = get_record('user', 'username', $user->username, 'deleted', 1)) {
                $user->id = $old_user->id;
                set_field('user', 'deleted', 0, 'username', $user->username);
                echo "Revived user $user->username id $user->id\n";
            } elseif ($id=insert_record ('user',$user)) { // it is truly a new user
                echo "inserted user $user->username id $id\n";
                $user->id = $id;
                // if relevant, tag for password generation
                if ($CFG->auth_dbpasstype === 'internal') {
                    set_user_preference('auth_forcepasswordchange', 1, $id);
                    set_user_preference('create_password',          1, $id);
                }
            } else {
                echo "error inserting user $user->username \n";
            }
            $CFG->debug=$old_debug;                        
        }
        commit_sql();
        unset($add_users); // free mem
    }
    return true;
}

function auth_user_exists ($username) {
    global $CFG;
    $authdb = &ADONewConnection($CFG->auth_dbtype); 
    $authdb->PConnect($CFG->auth_dbhost,$CFG->auth_dbuser,$CFG->auth_dbpass,$CFG->auth_dbname); 

    $rs = $authdb->Execute("SELECT * FROM $CFG->auth_dbtable 
                                 WHERE $CFG->auth_dbfielduser = '$username' ");
    $authdb->Close();

    if (!$rs) {
        notify("Could not connect to the specified authentication database...");
        return false;
    }
    
    if ( $rs->RecordCount() ) {
        // user exists exterally
        // check username/password internally
        // ?? there is no $password variable, so why??
        /*if ($user = get_record('user', 'username', $username)) {
            return ($user->password == md5($password));
        }*/
        return $rs->RecordCount();
    } else {
        // user does not exist externally
        return false;
    }  
}


function auth_get_userlist() {

    global $CFG;

    // Connect to the external database
    $authdb = &ADONewConnection($CFG->auth_dbtype); 
    $authdb->PConnect($CFG->auth_dbhost,$CFG->auth_dbuser,$CFG->auth_dbpass,$CFG->auth_dbname); 

    // fetch userlist
    $rs = $authdb->Execute("SELECT $CFG->auth_dbfielduser AS username
                            FROM   $CFG->auth_dbtable ");
    $authdb->Close();

    if (!$rs) {
        notify("Could not connect to the specified authentication database...");
        return false;
    }
    
    if ( $rs->RecordCount() ) {
        $userlist = array();
        while ($rec = $rs->FetchRow()) {
            array_push($userlist, $rec['username']);
        }
        return $userlist;
    } else {
        return array();
    }        
}

/**
 * reads userinformation from DB and return it in an object
 *
 * @param string $username username
 * @return array
 */
function auth_get_userinfo_asobj($username){
    $user_array = truncate_userinfo(auth_get_userinfo($username));
    $user = new object;
    foreach($user_array as $key=>$value){
        $user->{$key} = $value;
    }
    return $user;
}

function auth_db_update_user_record($username, $updatekeys=false) {
/// will update a local user record from an external source. 
/// is a lighter version of the one in moodlelib -- won't do 
/// expensive ops such as enrolment
///
/// If you don't pass $updatekeys, there is a performance hit and 
/// values removed from DB won't be removed from moodle. 

    global $CFG;

    $pcfg = get_config('auth/db');

    //just in case check text case
    $username = trim(moodle_strtolower($username));
    
    // get the current user record
    $user = get_record('user', 'username', $username);
    if (empty($user)) { // trouble
        error_log("Cannot update non-existent user: $username");
        die;
    }

    if (function_exists('auth_get_userinfo')) {
        if ($newinfo = auth_get_userinfo($username)) {
            $newinfo = truncate_userinfo($newinfo);
            
            if (empty($updatekeys)) { // all keys? this does not support removing values
                $updatekeys = array_keys($newinfo);
            }
            
            foreach ($updatekeys as $key){
                unset($value);
                if (isset($newinfo[$key])) {
                    $value = $newinfo[$key];
                    $value = addslashes(stripslashes($value)); // Just in case
                } else {
                    $value = '';
                }
                if (!empty($pcfg->{'field_updatelocal_' . $key})) { 
                       if ($user->{$key} != $value) { // only update if it's changed
                           set_field('user', $key, $value, 'username', $username);
                       }
                }
            }
        }
    }
    return get_record_select("user", "username = '$username' AND deleted <> '1'");
}

// A chance to validate form data, and last chance to 
// do stuff before it is inserted in config_plugin
function auth_validate_form(&$form, &$err) {
    
    // compat until we rework auth a bit
    if ($form['auth_dbpasstype'] === 'internal') {
        $CFG->auth_db_stdchangepassword = true;
        if ($conf = get_record('config', 'name', 'auth_db_stdchangepassword')) {
            $conf->value = 1;
            if (! update_record('config', $conf)) {
                notify("Could not update $name to $value");
            }
        } else {
            $conf = new StdClass;
            $conf->name = 'auth_db_stdchangepassword';
            $conf->value = 1;
            if (! insert_record('config', $conf)) {
                notify("Error: could not add new variable $name !");
            }
        }
    } else {
        $CFG->auth_db_stdchangepassword = false;
        if ($conf = get_record('config', 'name', 'auth_db_stdchangepassword')) {
            $conf->value = 0;
            if (! update_record('config', $conf)) {
                notify("Could not update $name to $value");
            }
        } else {
            $conf = new StdClass;
            $conf->name = 'auth_db_stdchangepassword';
            $conf->value = 0;
            if (! insert_record('config', $conf)) {
                notify("Error: could not add new variable $name !");
            }
        }
    }
    return true;
}

?>