See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 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 458 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')) { 459 $trace->output(get_string('auth_dbinsertuserduplicate', 'auth_db', array('username'=>$user->username, 'auth'=>$collision->auth)), 1); 460 continue; 461 } 462 try { 463 $id = user_create_user($user, false, false); // It is truly a new user. 464 $trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)), 1); 465 } catch (moodle_exception $e) { 466 $trace->output(get_string('auth_dbinsertusererror', 'auth_db', $user->username), 1); 467 continue; 468 } 469 // If relevant, tag for password generation. 470 if ($this->is_internal()) { 471 set_user_preference('auth_forcepasswordchange', 1, $id); 472 set_user_preference('create_password', 1, $id); 473 } 474 475 // Save custom profile fields here. 476 require_once($CFG->dirroot . '/user/profile/lib.php'); 477 $user->id = $id; 478 profile_save_data($user); 479 480 // Make sure user context is present. 481 context_user::instance($id); 482 483 \core\event\user_created::create_from_userid($id)->trigger(); 484 } 485 unset($add_users); 486 } 487 $trace->finished(); 488 return 0; 489 } 490 491 function user_exists($username) { 492 493 // Init result value. 494 $result = false; 495 496 $extusername = core_text::convert($username, 'utf-8', $this->config->extencoding); 497 498 $authdb = $this->db_init(); 499 500 $rs = $authdb->Execute("SELECT * 501 FROM {$this->config->table} 502 WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."' "); 503 504 if (!$rs) { 505 throw new \moodle_exception('auth_dbcantconnect', 'auth_db'); 506 } else if (!$rs->EOF) { 507 // User exists externally. 508 $result = true; 509 } 510 511 $authdb->Close(); 512 return $result; 513 } 514 515 516 function get_userlist() { 517 518 // Init result value. 519 $result = array(); 520 521 $authdb = $this->db_init(); 522 523 // Fetch userlist. 524 $rs = $authdb->Execute("SELECT {$this->config->fielduser} 525 FROM {$this->config->table} "); 526 527 if (!$rs) { 528 throw new \moodle_exception('auth_dbcantconnect', 'auth_db'); 529 } else if (!$rs->EOF) { 530 while ($rec = $rs->FetchRow()) { 531 $rec = array_change_key_case((array)$rec, CASE_LOWER); 532 array_push($result, $rec[strtolower($this->config->fielduser)]); 533 } 534 } 535 536 $authdb->Close(); 537 return $result; 538 } 539 540 /** 541 * Reads user information from DB and return it in an object. 542 * 543 * @param string $username username 544 * @return array 545 */ 546 function get_userinfo_asobj($username) { 547 $user_array = truncate_userinfo($this->get_userinfo($username)); 548 $user = new stdClass(); 549 foreach($user_array as $key=>$value) { 550 $user->{$key} = $value; 551 } 552 return $user; 553 } 554 555 /** 556 * Called when the user record is updated. 557 * Modifies user in external database. It takes olduser (before changes) and newuser (after changes) 558 * compares information saved modified information to external db. 559 * 560 * @param stdClass $olduser Userobject before modifications 561 * @param stdClass $newuser Userobject new modified userobject 562 * @return boolean result 563 * 564 */ 565 function user_update($olduser, $newuser) { 566 if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) { 567 error_log("ERROR:User renaming not allowed in ext db"); 568 return false; 569 } 570 571 if (isset($olduser->auth) and $olduser->auth != $this->authtype) { 572 return true; // Just change auth and skip update. 573 } 574 575 $curruser = $this->get_userinfo($olduser->username); 576 if (empty($curruser)) { 577 error_log("ERROR:User $olduser->username found in ext db"); 578 return false; 579 } 580 581 $extusername = core_text::convert($olduser->username, 'utf-8', $this->config->extencoding); 582 583 $authdb = $this->db_init(); 584 585 $update = array(); 586 foreach($curruser as $key=>$value) { 587 if ($key == 'username') { 588 continue; // Skip this. 589 } 590 if (empty($this->config->{"field_updateremote_$key"})) { 591 continue; // Remote update not requested. 592 } 593 if (!isset($newuser->$key)) { 594 continue; 595 } 596 $nuvalue = $newuser->$key; 597 // Support for textarea fields. 598 if (isset($nuvalue['text'])) { 599 $nuvalue = $nuvalue['text']; 600 } 601 if ($nuvalue != $value) { 602 $update[] = $this->config->{"field_map_$key"}."='".$this->ext_addslashes(core_text::convert($nuvalue, 'utf-8', $this->config->extencoding))."'"; 603 } 604 } 605 if (!empty($update)) { 606 $sql = "UPDATE {$this->config->table} 607 SET ".implode(',', $update)." 608 WHERE {$this->config->fielduser} = ?"; 609 if (!$authdb->Execute($sql, array($this->ext_addslashes($extusername)))) { 610 throw new \moodle_exception('auth_dbupdateerror', 'auth_db'); 611 } 612 } 613 $authdb->Close(); 614 return true; 615 } 616 617 function prevent_local_passwords() { 618 return !$this->is_internal(); 619 } 620 621 /** 622 * Returns true if this authentication plugin is "internal". 623 * 624 * Internal plugins use password hashes from Moodle user table for authentication. 625 * 626 * @return bool 627 */ 628 function is_internal() { 629 if (!isset($this->config->passtype)) { 630 return true; 631 } 632 return ($this->config->passtype === 'internal'); 633 } 634 635 /** 636 * Returns false if this plugin is enabled but not configured. 637 * 638 * @return bool 639 */ 640 public function is_configured() { 641 if (!empty($this->config->type)) { 642 return true; 643 } 644 return false; 645 } 646 647 /** 648 * Indicates if moodle should automatically update internal user 649 * records with data from external sources using the information 650 * from auth_plugin_base::get_userinfo(). 651 * 652 * @return bool true means automatically copy data from ext to user table 653 */ 654 function is_synchronised_with_external() { 655 return true; 656 } 657 658 /** 659 * Returns true if this authentication plugin can change the user's 660 * password. 661 * 662 * @return bool 663 */ 664 function can_change_password() { 665 return ($this->is_internal() or !empty($this->config->changepasswordurl)); 666 } 667 668 /** 669 * Returns the URL for changing the user's pw, or empty if the default can 670 * be used. 671 * 672 * @return moodle_url 673 */ 674 function change_password_url() { 675 if ($this->is_internal() || empty($this->config->changepasswordurl)) { 676 // Standard form. 677 return null; 678 } else { 679 // Use admin defined custom url. 680 return new moodle_url($this->config->changepasswordurl); 681 } 682 } 683 684 /** 685 * Returns true if plugin allows resetting of internal password. 686 * 687 * @return bool 688 */ 689 function can_reset_password() { 690 return $this->is_internal(); 691 } 692 693 /** 694 * Add slashes, we can not use placeholders or system functions. 695 * 696 * @param string $text 697 * @return string 698 */ 699 function ext_addslashes($text) { 700 if (empty($this->config->sybasequoting)) { 701 $text = str_replace('\\', '\\\\', $text); 702 $text = str_replace(array('\'', '"', "\0"), array('\\\'', '\\"', '\\0'), $text); 703 } else { 704 $text = str_replace("'", "''", $text); 705 } 706 return $text; 707 } 708 709 /** 710 * Test if settings are ok, print info to output. 711 * @private 712 */ 713 public function test_settings() { 714 global $CFG, $OUTPUT; 715 716 // NOTE: this is not localised intentionally, admins are supposed to understand English at least a bit... 717 718 raise_memory_limit(MEMORY_HUGE); 719 720 if (empty($this->config->table)) { 721 echo $OUTPUT->notification(get_string('auth_dbnoexttable', 'auth_db'), 'notifyproblem'); 722 return; 723 } 724 725 if (empty($this->config->fielduser)) { 726 echo $OUTPUT->notification(get_string('auth_dbnouserfield', 'auth_db'), 'notifyproblem'); 727 return; 728 } 729 730 $olddebug = $CFG->debug; 731 $olddisplay = ini_get('display_errors'); 732 ini_set('display_errors', '1'); 733 $CFG->debug = DEBUG_DEVELOPER; 734 $olddebugauthdb = $this->config->debugauthdb; 735 $this->config->debugauthdb = 1; 736 error_reporting($CFG->debug); 737 738 $adodb = $this->db_init(); 739 740 if (!$adodb or !$adodb->IsConnected()) { 741 $this->config->debugauthdb = $olddebugauthdb; 742 $CFG->debug = $olddebug; 743 ini_set('display_errors', $olddisplay); 744 error_reporting($CFG->debug); 745 ob_end_flush(); 746 747 echo $OUTPUT->notification(get_string('auth_dbcannotconnect', 'auth_db'), 'notifyproblem'); 748 return; 749 } 750 751 $rs = $adodb->Execute("SELECT * 752 FROM {$this->config->table} 753 WHERE {$this->config->fielduser} <> 'random_unlikely_username'"); // Any unlikely name is ok here. 754 755 if (!$rs) { 756 echo $OUTPUT->notification(get_string('auth_dbcannotreadtable', 'auth_db'), 'notifyproblem'); 757 758 } else if ($rs->EOF) { 759 echo $OUTPUT->notification(get_string('auth_dbtableempty', 'auth_db'), 'notifyproblem'); 760 $rs->close(); 761 762 } else { 763 $fields_obj = $rs->FetchObj(); 764 $columns = array_keys((array)$fields_obj); 765 766 echo $OUTPUT->notification(get_string('auth_dbcolumnlist', 'auth_db', implode(', ', $columns)), 'notifysuccess'); 767 $rs->close(); 768 } 769 770 $adodb->Close(); 771 772 $this->config->debugauthdb = $olddebugauthdb; 773 $CFG->debug = $olddebug; 774 ini_set('display_errors', $olddisplay); 775 error_reporting($CFG->debug); 776 ob_end_flush(); 777 } 778 779 /** 780 * Clean the user data that comes from an external database. 781 * @deprecated since 3.1, please use core_user::clean_data() instead. 782 * @param array $user the user data to be validated against properties definition. 783 * @return stdClass $user the cleaned user data. 784 */ 785 public function clean_data($user) { 786 debugging('The method clean_data() has been deprecated, please use core_user::clean_data() instead.', 787 DEBUG_DEVELOPER); 788 return core_user::clean_data($user); 789 } 790 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body