See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Authentication Plugin: External Database Authentication 19 * 20 * Checks against an external database. 21 * 22 * @package auth_db 23 * @author Martin Dougiamas 24 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 require_once($CFG->libdir.'/authlib.php'); 30 31 /** 32 * External database authentication plugin. 33 */ 34 class auth_plugin_db extends auth_plugin_base { 35 36 /** 37 * Constructor. 38 */ 39 function __construct() { 40 global $CFG; 41 require_once($CFG->libdir.'/adodb/adodb.inc.php'); 42 43 $this->authtype = 'db'; 44 $this->config = get_config('auth_db'); 45 $this->errorlogtag = '[AUTH DB] '; 46 if (empty($this->config->extencoding)) { 47 $this->config->extencoding = 'utf-8'; 48 } 49 } 50 51 /** 52 * Returns true if the username and password work and false if they are 53 * wrong or don't exist. 54 * 55 * @param string $username The username 56 * @param string $password The password 57 * @return bool Authentication success or failure. 58 */ 59 function user_login($username, $password) { 60 global $CFG, $DB; 61 62 if ($this->is_configured() === false) { 63 debugging(get_string('auth_notconfigured', 'auth', $this->authtype)); 64 return false; 65 } 66 67 $extusername = core_text::convert($username, 'utf-8', $this->config->extencoding); 68 $extpassword = core_text::convert($password, 'utf-8', $this->config->extencoding); 69 70 if ($this->is_internal()) { 71 // Lookup username externally, but resolve 72 // password locally -- to support backend that 73 // don't track passwords. 74 75 if (isset($this->config->removeuser) and $this->config->removeuser == AUTH_REMOVEUSER_KEEP) { 76 // No need to connect to external database in this case because users are never removed and we verify password locally. 77 if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype))) { 78 return validate_internal_user_password($user, $password); 79 } else { 80 return false; 81 } 82 } 83 84 $authdb = $this->db_init(); 85 86 $rs = $authdb->Execute("SELECT * 87 FROM {$this->config->table} 88 WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."'"); 89 if (!$rs) { 90 $authdb->Close(); 91 debugging(get_string('auth_dbcantconnect','auth_db')); 92 return false; 93 } 94 95 if (!$rs->EOF) { 96 $rs->Close(); 97 $authdb->Close(); 98 // User exists externally - check username/password internally. 99 if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype))) { 100 return validate_internal_user_password($user, $password); 101 } 102 } else { 103 $rs->Close(); 104 $authdb->Close(); 105 // User does not exist externally. 106 return false; 107 } 108 109 } else { 110 // Normal case: use external db for both usernames and passwords. 111 112 $authdb = $this->db_init(); 113 114 $rs = $authdb->Execute("SELECT {$this->config->fieldpass} 115 FROM {$this->config->table} 116 WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."'"); 117 if (!$rs) { 118 $authdb->Close(); 119 debugging(get_string('auth_dbcantconnect','auth_db')); 120 return false; 121 } 122 123 if ($rs->EOF) { 124 $authdb->Close(); 125 return false; 126 } 127 128 $fields = array_change_key_case($rs->fields, CASE_LOWER); 129 $fromdb = $fields[strtolower($this->config->fieldpass)]; 130 $rs->Close(); 131 $authdb->Close(); 132 133 if ($this->config->passtype === 'plaintext') { 134 return ($fromdb === $extpassword); 135 } else if ($this->config->passtype === 'md5') { 136 return (strtolower($fromdb) === md5($extpassword)); 137 } else if ($this->config->passtype === 'sha1') { 138 return (strtolower($fromdb) === sha1($extpassword)); 139 } else if ($this->config->passtype === 'saltedcrypt') { 140 return password_verify($extpassword, $fromdb); 141 } else { 142 return false; 143 } 144 145 } 146 } 147 148 /** 149 * Connect to external database. 150 * 151 * @return ADOConnection 152 * @throws moodle_exception 153 */ 154 function db_init() { 155 if ($this->is_configured() === false) { 156 throw new moodle_exception('auth_dbcantconnect', 'auth_db'); 157 } 158 159 // Connect to the external database (forcing new connection). 160 $authdb = ADONewConnection($this->config->type); 161 if (!empty($this->config->debugauthdb)) { 162 $authdb->debug = true; 163 ob_start(); //Start output buffer to allow later use of the page headers. 164 } 165 $authdb->Connect($this->config->host, $this->config->user, $this->config->pass, $this->config->name, true); 166 $authdb->SetFetchMode(ADODB_FETCH_ASSOC); 167 if (!empty($this->config->setupsql)) { 168 $authdb->Execute($this->config->setupsql); 169 } 170 171 return $authdb; 172 } 173 174 /** 175 * Returns user attribute mappings between moodle and the external database. 176 * 177 * @return array 178 */ 179 function db_attributes() { 180 $moodleattributes = array(); 181 // If we have custom fields then merge them with user fields. 182 $customfields = $this->get_custom_user_profile_fields(); 183 if (!empty($customfields) && !empty($this->userfields)) { 184 $userfields = array_merge($this->userfields, $customfields); 185 } else { 186 $userfields = $this->userfields; 187 } 188 189 foreach ($userfields as $field) { 190 if (!empty($this->config->{"field_map_$field"})) { 191 $moodleattributes[$field] = $this->config->{"field_map_$field"}; 192 } 193 } 194 $moodleattributes['username'] = $this->config->fielduser; 195 return $moodleattributes; 196 } 197 198 /** 199 * Reads any other information for a user from external database, 200 * then returns it in an array. 201 * 202 * @param string $username 203 * @return array 204 */ 205 function get_userinfo($username) { 206 global $CFG; 207 208 $extusername = core_text::convert($username, 'utf-8', $this->config->extencoding); 209 210 $authdb = $this->db_init(); 211 212 // Array to map local fieldnames we want, to external fieldnames. 213 $selectfields = $this->db_attributes(); 214 215 $result = array(); 216 // If at least one field is mapped from external db, get that mapped data. 217 if ($selectfields) { 218 $select = array(); 219 $fieldcount = 0; 220 foreach ($selectfields as $localname=>$externalname) { 221 // Without aliasing, multiple occurrences of the same external 222 // name can coalesce in only occurrence in the result. 223 $select[] = "$externalname AS F".$fieldcount; 224 $fieldcount++; 225 } 226 $select = implode(', ', $select); 227 $sql = "SELECT $select 228 FROM {$this->config->table} 229 WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."'"; 230 231 if ($rs = $authdb->Execute($sql)) { 232 if (!$rs->EOF) { 233 $fields = $rs->FetchRow(); 234 // Convert the associative array to an array of its values so we don't have to worry about the case of its keys. 235 $fields = array_values($fields); 236 foreach (array_keys($selectfields) as $index => $localname) { 237 $value = $fields[$index]; 238 $result[$localname] = core_text::convert($value, $this->config->extencoding, 'utf-8'); 239 } 240 } 241 $rs->Close(); 242 } 243 } 244 $authdb->Close(); 245 return $result; 246 } 247 248 /** 249 * Change a user's password. 250 * 251 * @param stdClass $user User table object 252 * @param string $newpassword Plaintext password 253 * @return bool True on success 254 */ 255 function user_update_password($user, $newpassword) { 256 global $DB; 257 258 if ($this->is_internal()) { 259 $puser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST); 260 // This will also update the stored hash to the latest algorithm 261 // if the existing hash is using an out-of-date algorithm (or the 262 // legacy md5 algorithm). 263 if (update_internal_user_password($puser, $newpassword)) { 264 $user->password = $puser->password; 265 return true; 266 } else { 267 return false; 268 } 269 } else { 270 // We should have never been called! 271 return false; 272 } 273 } 274 275 /** 276 * Synchronizes user from external db to moodle user table. 277 * 278 * Sync should be done by using idnumber attribute, not username. 279 * You need to pass firstsync parameter to function to fill in 280 * idnumbers if they don't exists in moodle user table. 281 * 282 * Syncing users removes (disables) users that don't exists anymore in external db. 283 * Creates new users and updates coursecreator status of users. 284 * 285 * This implementation is simpler but less scalable than the one found in the LDAP module. 286 * 287 * @param progress_trace $trace 288 * @param bool $do_updates Optional: set to true to force an update of existing accounts 289 * @return int 0 means success, 1 means failure 290 */ 291 function sync_users(progress_trace $trace, $do_updates=false) { 292 global $CFG, $DB; 293 294 require_once($CFG->dirroot . '/user/lib.php'); 295 296 // List external users. 297 $userlist = $this->get_userlist(); 298 299 // Delete obsolete internal users. 300 if (!empty($this->config->removeuser)) { 301 302 $suspendselect = ""; 303 if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { 304 $suspendselect = "AND u.suspended = 0"; 305 } 306 307 // Find obsolete users. 308 if (count($userlist)) { 309 $removeusers = array(); 310 $params['authtype'] = $this->authtype; 311 $sql = "SELECT u.id, u.username 312 FROM {user} u 313 WHERE u.auth=:authtype 314 AND u.deleted=0 315 AND u.mnethostid=:mnethostid 316 $suspendselect"; 317 $params['mnethostid'] = $CFG->mnet_localhost_id; 318 $internalusersrs = $DB->get_recordset_sql($sql, $params); 319 320 $usernamelist = array_flip($userlist); 321 foreach ($internalusersrs as $internaluser) { 322 if (!array_key_exists($internaluser->username, $usernamelist)) { 323 $removeusers[] = $internaluser; 324 } 325 } 326 $internalusersrs->close(); 327 } else { 328 $sql = "SELECT u.id, u.username 329 FROM {user} u 330 WHERE u.auth=:authtype AND u.deleted=0 AND u.mnethostid=:mnethostid $suspendselect"; 331 $params = array(); 332 $params['authtype'] = $this->authtype; 333 $params['mnethostid'] = $CFG->mnet_localhost_id; 334 $removeusers = $DB->get_records_sql($sql, $params); 335 } 336 337 if (!empty($removeusers)) { 338 $trace->output(get_string('auth_dbuserstoremove', 'auth_db', count($removeusers))); 339 340 foreach ($removeusers as $user) { 341 if ($this->config->removeuser == AUTH_REMOVEUSER_FULLDELETE) { 342 delete_user($user); 343 $trace->output(get_string('auth_dbdeleteuser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)), 1); 344 } else if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { 345 $updateuser = new stdClass(); 346 $updateuser->id = $user->id; 347 $updateuser->suspended = 1; 348 user_update_user($updateuser, false); 349 $trace->output(get_string('auth_dbsuspenduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)), 1); 350 } 351 } 352 } 353 unset($removeusers); 354 } 355 356 if (!count($userlist)) { 357 // Exit right here, nothing else to do. 358 $trace->finished(); 359 return 0; 360 } 361 362 // Update existing accounts. 363 if ($do_updates) { 364 // Narrow down what fields we need to update. 365 $all_keys = array_keys(get_object_vars($this->config)); 366 $updatekeys = array(); 367 foreach ($all_keys as $key) { 368 if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) { 369 if ($this->config->{$key} === 'onlogin') { 370 array_push($updatekeys, $match[1]); // The actual key name. 371 } 372 } 373 } 374 unset($all_keys); unset($key); 375 376 // Only go ahead if we actually have fields to update locally. 377 if (!empty($updatekeys)) { 378 $update_users = array(); 379 // All the drivers can cope with chunks of 10,000. See line 4491 of lib/dml/tests/dml_est.php 380 $userlistchunks = array_chunk($userlist , 10000); 381 foreach($userlistchunks as $userlistchunk) { 382 list($in_sql, $params) = $DB->get_in_or_equal($userlistchunk, SQL_PARAMS_NAMED, 'u', true); 383 $params['authtype'] = $this->authtype; 384 $params['mnethostid'] = $CFG->mnet_localhost_id; 385 $sql = "SELECT u.id, u.username, u.suspended 386 FROM {user} u 387 WHERE u.auth = :authtype AND u.deleted = 0 AND u.mnethostid = :mnethostid AND u.username {$in_sql}"; 388 $update_users = $update_users + $DB->get_records_sql($sql, $params); 389 } 390 391 if ($update_users) { 392 $trace->output("User entries to update: ".count($update_users)); 393 394 foreach ($update_users as $user) { 395 if ($this->update_user_record($user->username, $updatekeys, false, (bool) $user->suspended)) { 396 $trace->output(get_string('auth_dbupdatinguser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)), 1); 397 } else { 398 $trace->output(get_string('auth_dbupdatinguser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id))." - ".get_string('skipped'), 1); 399 } 400 } 401 unset($update_users); 402 } 403 } 404 } 405 406 407 // Create missing accounts. 408 // NOTE: this is very memory intensive and generally inefficient. 409 $suspendselect = ""; 410 if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { 411 $suspendselect = "AND u.suspended = 0"; 412 } 413 $sql = "SELECT u.id, u.username 414 FROM {user} u 415 WHERE u.auth=:authtype AND u.deleted='0' AND mnethostid=:mnethostid $suspendselect"; 416 417 $users = $DB->get_records_sql($sql, array('authtype'=>$this->authtype, 'mnethostid'=>$CFG->mnet_localhost_id)); 418 419 // Simplify down to usernames. 420 $usernames = array(); 421 if (!empty($users)) { 422 foreach ($users as $user) { 423 array_push($usernames, $user->username); 424 } 425 unset($users); 426 } 427 428 $add_users = array_diff($userlist, $usernames); 429 unset($usernames); 430 431 if (!empty($add_users)) { 432 $trace->output(get_string('auth_dbuserstoadd','auth_db',count($add_users))); 433 // Do not use transactions around this foreach, we want to skip problematic users, not revert everything. 434 foreach($add_users as $user) { 435 $username = $user; 436 if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { 437 if ($olduser = $DB->get_record('user', array('username' => $username, 'deleted' => 0, 'suspended' => 1, 438 'mnethostid' => $CFG->mnet_localhost_id, 'auth' => $this->authtype))) { 439 $updateuser = new stdClass(); 440 $updateuser->id = $olduser->id; 441 $updateuser->suspended = 0; 442 user_update_user($updateuser); 443 $trace->output(get_string('auth_dbreviveduser', 'auth_db', array('name' => $username, 444 'id' => $olduser->id)), 1); 445 continue; 446 } 447 } 448 449 // Do not try to undelete users here, instead select suspending if you ever expect users will reappear. 450 451 // Prep a few params. 452 $user = $this->get_userinfo_asobj($user); 453 $user->username = $username; 454 $user->confirmed = 1; 455 $user->auth = $this->authtype; 456 $user->mnethostid = $CFG->mnet_localhost_id; 457 if (empty($user->lang)) { 458 $user->lang = $CFG->lang; 459 } 460 if ($collision = $DB->get_record_select('user', "username = :username AND mnethostid = :mnethostid AND auth <> :auth", array('username'=>$user->username, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype), 'id,username,auth')) { 461 $trace->output(get_string('auth_dbinsertuserduplicate', 'auth_db', array('username'=>$user->username, 'auth'=>$collision->auth)), 1); 462 continue; 463 } 464 try { 465 $id = user_create_user($user, false, false); // It is truly a new user. 466 $trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)), 1); 467 } catch (moodle_exception $e) { 468 $trace->output(get_string('auth_dbinsertusererror', 'auth_db', $user->username), 1); 469 continue; 470 } 471 // If relevant, tag for password generation. 472 if ($this->is_internal()) { 473 set_user_preference('auth_forcepasswordchange', 1, $id); 474 set_user_preference('create_password', 1, $id); 475 } 476 477 // Save custom profile fields here. 478 require_once($CFG->dirroot . '/user/profile/lib.php'); 479 $user->id = $id; 480 profile_save_data($user); 481 482 // Make sure user context is present. 483 context_user::instance($id); 484 485 \core\event\user_created::create_from_userid($id)->trigger(); 486 } 487 unset($add_users); 488 } 489 $trace->finished(); 490 return 0; 491 } 492 493 function user_exists($username) { 494 495 // Init result value. 496 $result = false; 497 498 $extusername = core_text::convert($username, 'utf-8', $this->config->extencoding); 499 500 $authdb = $this->db_init(); 501 502 $rs = $authdb->Execute("SELECT * 503 FROM {$this->config->table} 504 WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."' "); 505 506 if (!$rs) { 507 print_error('auth_dbcantconnect','auth_db'); 508 } else if (!$rs->EOF) { 509 // User exists externally. 510 $result = true; 511 } 512 513 $authdb->Close(); 514 return $result; 515 } 516 517 518 function get_userlist() { 519 520 // Init result value. 521 $result = array(); 522 523 $authdb = $this->db_init(); 524 525 // Fetch userlist. 526 $rs = $authdb->Execute("SELECT {$this->config->fielduser} 527 FROM {$this->config->table} "); 528 529 if (!$rs) { 530 print_error('auth_dbcantconnect','auth_db'); 531 } else if (!$rs->EOF) { 532 while ($rec = $rs->FetchRow()) { 533 $rec = array_change_key_case((array)$rec, CASE_LOWER); 534 array_push($result, $rec[strtolower($this->config->fielduser)]); 535 } 536 } 537 538 $authdb->Close(); 539 return $result; 540 } 541 542 /** 543 * Reads user information from DB and return it in an object. 544 * 545 * @param string $username username 546 * @return array 547 */ 548 function get_userinfo_asobj($username) { 549 $user_array = truncate_userinfo($this->get_userinfo($username)); 550 $user = new stdClass(); 551 foreach($user_array as $key=>$value) { 552 $user->{$key} = $value; 553 } 554 return $user; 555 } 556 557 /** 558 * Called when the user record is updated. 559 * Modifies user in external database. It takes olduser (before changes) and newuser (after changes) 560 * compares information saved modified information to external db. 561 * 562 * @param stdClass $olduser Userobject before modifications 563 * @param stdClass $newuser Userobject new modified userobject 564 * @return boolean result 565 * 566 */ 567 function user_update($olduser, $newuser) { 568 if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) { 569 error_log("ERROR:User renaming not allowed in ext db"); 570 return false; 571 } 572 573 if (isset($olduser->auth) and $olduser->auth != $this->authtype) { 574 return true; // Just change auth and skip update. 575 } 576 577 $curruser = $this->get_userinfo($olduser->username); 578 if (empty($curruser)) { 579 error_log("ERROR:User $olduser->username found in ext db"); 580 return false; 581 } 582 583 $extusername = core_text::convert($olduser->username, 'utf-8', $this->config->extencoding); 584 585 $authdb = $this->db_init(); 586 587 $update = array(); 588 foreach($curruser as $key=>$value) { 589 if ($key == 'username') { 590 continue; // Skip this. 591 } 592 if (empty($this->config->{"field_updateremote_$key"})) { 593 continue; // Remote update not requested. 594 } 595 if (!isset($newuser->$key)) { 596 continue; 597 } 598 $nuvalue = $newuser->$key; 599 // Support for textarea fields. 600 if (isset($nuvalue['text'])) { 601 $nuvalue = $nuvalue['text']; 602 } 603 if ($nuvalue != $value) { 604 $update[] = $this->config->{"field_map_$key"}."='".$this->ext_addslashes(core_text::convert($nuvalue, 'utf-8', $this->config->extencoding))."'"; 605 } 606 } 607 if (!empty($update)) { 608 $sql = "UPDATE {$this->config->table} 609 SET ".implode(',', $update)." 610 WHERE {$this->config->fielduser} = ?"; 611 if (!$authdb->Execute($sql, array($this->ext_addslashes($extusername)))) { 612 print_error('auth_dbupdateerror', 'auth_db'); 613 } 614 } 615 $authdb->Close(); 616 return true; 617 } 618 619 function prevent_local_passwords() { 620 return !$this->is_internal(); 621 } 622 623 /** 624 * Returns true if this authentication plugin is "internal". 625 * 626 * Internal plugins use password hashes from Moodle user table for authentication. 627 * 628 * @return bool 629 */ 630 function is_internal() { 631 if (!isset($this->config->passtype)) { 632 return true; 633 } 634 return ($this->config->passtype === 'internal'); 635 } 636 637 /** 638 * Returns false if this plugin is enabled but not configured. 639 * 640 * @return bool 641 */ 642 public function is_configured() { 643 if (!empty($this->config->type)) { 644 return true; 645 } 646 return false; 647 } 648 649 /** 650 * Indicates if moodle should automatically update internal user 651 * records with data from external sources using the information 652 * from auth_plugin_base::get_userinfo(). 653 * 654 * @return bool true means automatically copy data from ext to user table 655 */ 656 function is_synchronised_with_external() { 657 return true; 658 } 659 660 /** 661 * Returns true if this authentication plugin can change the user's 662 * password. 663 * 664 * @return bool 665 */ 666 function can_change_password() { 667 return ($this->is_internal() or !empty($this->config->changepasswordurl)); 668 } 669 670 /** 671 * Returns the URL for changing the user's pw, or empty if the default can 672 * be used. 673 * 674 * @return moodle_url 675 */ 676 function change_password_url() { 677 if ($this->is_internal() || empty($this->config->changepasswordurl)) { 678 // Standard form. 679 return null; 680 } else { 681 // Use admin defined custom url. 682 return new moodle_url($this->config->changepasswordurl); 683 } 684 } 685 686 /** 687 * Returns true if plugin allows resetting of internal password. 688 * 689 * @return bool 690 */ 691 function can_reset_password() { 692 return $this->is_internal(); 693 } 694 695 /** 696 * Add slashes, we can not use placeholders or system functions. 697 * 698 * @param string $text 699 * @return string 700 */ 701 function ext_addslashes($text) { 702 if (empty($this->config->sybasequoting)) { 703 $text = str_replace('\\', '\\\\', $text); 704 $text = str_replace(array('\'', '"', "\0"), array('\\\'', '\\"', '\\0'), $text); 705 } else { 706 $text = str_replace("'", "''", $text); 707 } 708 return $text; 709 } 710 711 /** 712 * Test if settings are ok, print info to output. 713 * @private 714 */ 715 public function test_settings() { 716 global $CFG, $OUTPUT; 717 718 // NOTE: this is not localised intentionally, admins are supposed to understand English at least a bit... 719 720 raise_memory_limit(MEMORY_HUGE); 721 722 if (empty($this->config->table)) { 723 echo $OUTPUT->notification(get_string('auth_dbnoexttable', 'auth_db'), 'notifyproblem'); 724 return; 725 } 726 727 if (empty($this->config->fielduser)) { 728 echo $OUTPUT->notification(get_string('auth_dbnouserfield', 'auth_db'), 'notifyproblem'); 729 return; 730 } 731 732 $olddebug = $CFG->debug; 733 $olddisplay = ini_get('display_errors'); 734 ini_set('display_errors', '1'); 735 $CFG->debug = DEBUG_DEVELOPER; 736 $olddebugauthdb = $this->config->debugauthdb; 737 $this->config->debugauthdb = 1; 738 error_reporting($CFG->debug); 739 740 $adodb = $this->db_init(); 741 742 if (!$adodb or !$adodb->IsConnected()) { 743 $this->config->debugauthdb = $olddebugauthdb; 744 $CFG->debug = $olddebug; 745 ini_set('display_errors', $olddisplay); 746 error_reporting($CFG->debug); 747 ob_end_flush(); 748 749 echo $OUTPUT->notification(get_string('auth_dbcannotconnect', 'auth_db'), 'notifyproblem'); 750 return; 751 } 752 753 $rs = $adodb->Execute("SELECT * 754 FROM {$this->config->table} 755 WHERE {$this->config->fielduser} <> 'random_unlikely_username'"); // Any unlikely name is ok here. 756 757 if (!$rs) { 758 echo $OUTPUT->notification(get_string('auth_dbcannotreadtable', 'auth_db'), 'notifyproblem'); 759 760 } else if ($rs->EOF) { 761 echo $OUTPUT->notification(get_string('auth_dbtableempty', 'auth_db'), 'notifyproblem'); 762 $rs->close(); 763 764 } else { 765 $fields_obj = $rs->FetchObj(); 766 $columns = array_keys((array)$fields_obj); 767 768 echo $OUTPUT->notification(get_string('auth_dbcolumnlist', 'auth_db', implode(', ', $columns)), 'notifysuccess'); 769 $rs->close(); 770 } 771 772 $adodb->Close(); 773 774 $this->config->debugauthdb = $olddebugauthdb; 775 $CFG->debug = $olddebug; 776 ini_set('display_errors', $olddisplay); 777 error_reporting($CFG->debug); 778 ob_end_flush(); 779 } 780 781 /** 782 * Clean the user data that comes from an external database. 783 * @deprecated since 3.1, please use core_user::clean_data() instead. 784 * @param array $user the user data to be validated against properties definition. 785 * @return stdClass $user the cleaned user data. 786 */ 787 public function clean_data($user) { 788 debugging('The method clean_data() has been deprecated, please use core_user::clean_data() instead.', 789 DEBUG_DEVELOPER); 790 return core_user::clean_data($user); 791 } 792 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body