MDL-25637 Fixed whitespace
[moodle.git] / enrol / database / lib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * Database enrolment plugin.
20  *
21  * This plugin synchronises enrolment and roles with external database table.
22  *
23  * @package    enrol
24  * @subpackage database
25  * @copyright  2010 Petr Skoda {@link http://skodak.org}
26  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27  */
29 defined('MOODLE_INTERNAL') || die();
31 /**
32  * Database enrolment plugin implementation.
33  * @author  Petr Skoda - based on code by Martin Dougiamas, Martin Langhoff and others
34  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class enrol_database_plugin extends enrol_plugin {
37     /**
38      * Is it possible to delete enrol instance via standard UI?
39      *
40      * @param object $instance
41      * @return bool
42      */
43     public function instance_deleteable($instance) {
44         if (!enrol_is_enabled('database')) {
45             return true;
46         }
47         if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
48             return true;
49         }
51         //TODO: connect to external system and make sure no users are to be enrolled in this course
52         return false;
53     }
55     /**
56      * Forces synchronisation of user enrolments with external database,
57      * does not create new courses.
58      *
59      * @param object $user user record
60      * @return void
61      */
62     public function sync_user_enrolments($user) {
63         global $CFG, $DB;
65         // we do not create courses here intentionally because it requires full sync and is slow
66         if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
67             return;
68         }
70         $table            = $this->get_config('remoteenroltable');
71         $coursefield      = strtolower($this->get_config('remotecoursefield'));
72         $userfield        = strtolower($this->get_config('remoteuserfield'));
73         $rolefield        = strtolower($this->get_config('remoterolefield'));
75         $localrolefield   = $this->get_config('localrolefield');
76         $localuserfield   = $this->get_config('localuserfield');
77         $localcoursefiled = $this->get_config('localcoursefield');
79         $unenrolaction    = $this->get_config('unenrolaction');
80         $defaultrole      = $this->get_config('defaultrole');
82         $ignorehidden     = $this->get_config('ignorehiddencourses');
84         if (!is_object($user) or !property_exists($user, 'id')) {
85             throw new coding_exception('Invalid $user parameter in sync_user_enrolments()');
86         }
88         if (!property_exists($user, $localuserfield)) {
89             debugging('Invalid $user parameter in sync_user_enrolments(), missing '.$localuserfield);
90             $user = $DB->get_record('user', array('id'=>$user->id));
91         }
93         // create roles mapping
94         $allroles = get_all_roles();
95         if (!isset($allroles[$defaultrole])) {
96             $defaultrole = 0;
97         }
98         $roles = array();
99         foreach ($allroles as $role) {
100             $roles[$role->$localrolefield] = $role->id;
101         }
103         $enrols = array();
104         $instances = array();
106         $extdb = $this->db_init();
108         // read remote enrols and create instances
109         $sql = $this->db_get_sql($table, array($userfield=>$user->$localuserfield), array(), false);
111         if ($rs = $extdb->Execute($sql)) {
112             if (!$rs->EOF) {
113                 while ($fields = $rs->FetchRow()) {
114                     $fields = $this->db_decode($fields);
116                     if (empty($fields[$coursefield])) {
117                         // missing course info
118                         continue;
119                     }
120                     if (!$course = $DB->get_record('course', array($localcoursefiled=>$fields[$coursefield]), 'id,visible')) {
121                         continue;
122                     }
123                     if (!$course->visible and $ignorehidden) {
124                         continue;
125                     }
127                     if (empty($fields[$rolefield]) or !isset($roles[$fields[$rolefield]])) {
128                         if (!$defaultrole) {
129                             // role is mandatory
130                             continue;
131                         }
132                         $roleid = $defaultrole;
133                     } else {
134                         $roleid = $roles[$fields[$rolefield]];
135                     }
137                     if (empty($enrols[$course->id])) {
138                         $enrols[$course->id] = array();
139                     }
140                     $enrols[$course->id][] = $roleid;
142                     if ($instance = $DB->get_record('enrol', array('courseid'=>$course->id, 'enrol'=>'database'), '*', IGNORE_MULTIPLE)) {
143                         $instances[$course->id] = $instance;
144                         continue;
145                     }
147                     $enrolid = $this->add_instance($course);
148                     $instances[$course->id] = $DB->get_record('enrol', array('id'=>$enrolid));
149                 }
150             }
151             $rs->Close();
152             $extdb->Close();
153         } else {
154             // bad luck, something is wrong with the db connection
155             $extdb->Close();
156             return;
157         }
159         // enrol user into courses and sync roles
160         foreach ($enrols as $courseid => $roles) {
161             if (!isset($instances[$courseid])) {
162                 // ignored
163                 continue;
164             }
165             $instance = $instances[$courseid];
167             if ($e = $DB->get_record('user_enrolments', array('userid'=>$user->id, 'enrolid'=>$instance->id))) {
168                 // reenable enrolment when previously disable enrolment refreshed
169                 if ($e->status == ENROL_USER_SUSPENDED) {
170                     $DB->set_field('user_enrolments', 'status', ENROL_USER_ACTIVE, array('enrolid'=>$instance->id, 'userid'=>$user->id));
171                 }
172             } else {
173                 $roleid = reset($roles);
174                 $this->enrol_user($instance, $user->id, $roleid);
175             }
177             if (!$context = get_context_instance(CONTEXT_COURSE, $instance->courseid)) {
178                 //weird
179                 continue;
180             }
181             $current = $DB->get_records('role_assignments', array('contextid'=>$context->id, 'userid'=>$user->id, 'component'=>'enrol_database', 'itemid'=>$instance->id), '', 'id, roleid');
183             $existing = array();
184             foreach ($current as $r) {
185                 if (in_array($r->id, $roles)) {
186                     $existing[$r->roleid] = $r->roleid;
187                 } else {
188                     role_unassign($r->roleid, $user->id, $context->id, 'enrol_database', $instance->id);
189                 }
190             }
191             foreach ($roles as $rid) {
192                 if (!isset($existing[$rid])) {
193                     role_assign($rid, $user->id, $context->id, 'enrol_database', $instance->id);
194                 }
195             }
196         }
198         // unenrol as necessary
199         $sql = "SELECT e.*, c.visible AS cvisible, ue.status AS ustatus
200                   FROM {enrol} e
201                   JOIN {user_enrolments} ue ON ue.enrolid = e.id
202                   JOIN {course} c ON c.id = e.courseid
203                  WHERE ue.userid = :userid AND e.enrol = 'database'";
204         $rs = $DB->get_recordset_sql($sql, array('userid'=>$user->id));
205         foreach ($rs as $instance) {
206             if (!$instance->cvisible and $ignorehidden) {
207                 continue;
208             }
210             if (!$context = get_context_instance(CONTEXT_COURSE, $instance->courseid)) {
211                 //weird
212                 continue;
213             }
215             if (!empty($enrols[$instance->courseid])) {
216                 // we want this user enrolled
217                 continue;
218             }
220             // deal with enrolments removed from external table
221             if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
222                 // unenrol
223                 $this->unenrol_user($instance, $user->id);
225             } else if ($unenrolaction == ENROL_EXT_REMOVED_KEEP) {
226                 // keep - only adding enrolments
228             } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND or $unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
229                 // disable
230                 if ($instance->ustatus != ENROL_USER_SUSPENDED) {
231                     $DB->set_field('user_enrolments', 'status', ENROL_USER_SUSPENDED, array('enrolid'=>$instance->id, 'userid'=>$user->id));
232                 }
233                 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
234                     role_unassign_all(array('contextid'=>$context->id, 'userid'=>$user->id, 'component'=>'enrol_database', 'itemid'=>$instance->id));
235                 }
236             }
237         }
238         $rs->close();
239     }
241     /**
242      * Forces synchronisation of all enrolments with external database.
243      *
244      * @return void
245      */
246     public function sync_enrolments() {
247         global $CFG, $DB;
249         // we do not create courses here intentionally because it requires full sync and is slow
250         if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
251             return;
252         }
254         // we may need a lot of memory here
255         @set_time_limit(0);
256         raise_memory_limit(MEMORY_HUGE);
258         $extdb = $this->db_init();
260         // second step is to sync instances and users
261         $table            = $this->get_config('remoteenroltable');
262         $coursefield      = strtolower($this->get_config('remotecoursefield'));
263         $userfield        = strtolower($this->get_config('remoteuserfield'));
264         $rolefield        = strtolower($this->get_config('remoterolefield'));
266         $localrolefield   = $this->get_config('localrolefield');
267         $localuserfield   = $this->get_config('localuserfield');
268         $localcoursefiled = $this->get_config('localcoursefield');
270         $unenrolaction    = $this->get_config('unenrolaction');
271         $defaultrole      = $this->get_config('defaultrole');
273         // create roles mapping
274         $allroles = get_all_roles();
275         if (!isset($allroles[$defaultrole])) {
276             $defaultrole = 0;
277         }
278         $roles = array();
279         foreach ($allroles as $role) {
280             $roles[$role->$localrolefield] = $role->id;
281         }
283         // get a list of courses to be synced that are in external table
284         $externalcourses = array();
285         $sql = $this->db_get_sql($table, array(), array($coursefield), true);
286         if ($rs = $extdb->Execute($sql)) {
287             if (!$rs->EOF) {
288                 while ($mapping = $rs->FetchRow()) {
289                     $mapping = reset($mapping);
290                     $mapping = $this->db_decode($mapping);
291                     if (empty($mapping)) {
292                         // invalid mapping
293                         continue;
294                     }
295                     $externalcourses[$mapping] = true;
296                 }
297             }
298             $rs->Close();
299         } else {
300             debugging('Error while communicating with external enrolment database');
301             $extdb->Close();
302             return;
303         }
304         $preventfullunenrol = empty($externalcourses);
305         if ($preventfullunenrol and $unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
306             debugging('Preventing unenrolment of all current users, because it might result in major data loss, there has to be at least one record in external enrol table, sorry.');
307         }
309         // first find all existing courses with enrol instance
310         $existing = array();
311         $sql = "SELECT c.id, c.visible, c.$localcoursefiled AS mapping, e.id AS enrolid
312                   FROM {course} c
313                   JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')";
314         $rs = $DB->get_recordset_sql($sql); // watch out for idnumber duplicates
315         foreach ($rs as $course) {
316             if (empty($course->mapping)) {
317                 continue;
318             }
319             $existing[$course->mapping] = $course;
320         }
321         $rs->close();
323         // add necessary enrol instances that are not present yet
324         $sql = "SELECT c.id, c.visible, c.$localcoursefiled AS mapping
325                   FROM {course} c
326              LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')
327                  WHERE e.id IS NULL AND c.$localcoursefiled <> ?";
328         $rs = $DB->get_recordset_sql($sql, array($DB->sql_empty()));
329         foreach ($rs as $course) {
330             if (empty($course->mapping)) {
331                 continue;
332             }
333             if (!isset($externalcourses[$course->mapping])) {
334                 // course not synced
335                 continue;
336             }
337             if (isset($existing[$course->mapping])) {
338                 // some duplicate, sorry
339                 continue;
340             }
341             $course->enrolid = $this->add_instance($course);
342             $existing[$course->mapping] = $course;
343         }
344         $rs->close();
346         // free memory
347         unset($externalcourses);
349         // sync enrolments
350         $ignorehidden = $this->get_config('ignorehiddencourses');
351         $sqlfields = array($userfield);
352         if ($rolefield) {
353             $sqlfields[] = $rolefield;
354         }
355         foreach ($existing as $course) {
356             if ($ignorehidden and !$course->visible) {
357                 continue;
358             }
359             if (!$instance = $DB->get_record('enrol', array('id'=>$course->enrolid))) {
360                 continue; //weird
361             }
362             $context = get_context_instance(CONTEXT_COURSE, $course->id);
364             // get current list of enrolled users with their roles
365             $current_roles  = array();
366             $current_status = array();
367             $user_mapping   = array();
368             $sql = "SELECT u.$localuserfield AS mapping, u.id, ue.status, ue.userid, ra.roleid
369                       FROM {user} u
370                       JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
371                       JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.itemid = ue.enrolid AND ra.component = 'enrol_database')
372                      WHERE u.deleted = 0";
373             $params = array('enrolid'=>$instance->id);
374             if ($localuserfield === 'username') {
375                 $sql .= " AND u.mnethostid = :mnethostid";
376                 $params['mnethostid'] = $CFG->mnet_localhost_id;
377             }
378             $rs = $DB->get_recordset_sql($sql, $params);
379             foreach ($rs as $ue) {
380                 $current_roles[$ue->userid][$ue->roleid] = $ue->roleid;
381                 $current_status[$ue->userid] = $ue->status;
382                 $user_mapping[$ue->mapping] = $ue->userid;
383             }
384             $rs->close();
386             // get list of users that need to be enrolled and their roles
387             $requested_roles = array();
388             $sql = $this->db_get_sql($table, array($coursefield=>$course->mapping), $sqlfields);
389             if ($rs = $extdb->Execute($sql)) {
390                 if (!$rs->EOF) {
391                     if ($localuserfield === 'username') {
392                         $usersearch = array('mnethostid'=>$CFG->mnet_localhost_id, 'deleted' =>0);
393                     }
394                     while ($fields = $rs->FetchRow()) {
395                         $fields = array_change_key_case($fields, CASE_LOWER);
396                         if (empty($fields[$userfield])) {
397                             //user identification is mandatory!
398                         }
399                         $mapping = $fields[$userfield];
400                         if (!isset($user_mapping[$mapping])) {
401                             $usersearch[$localuserfield] = $mapping;
402                             if (!$user = $DB->get_record('user', $usersearch, 'id', IGNORE_MULTIPLE)) {
403                                 // user does not exist or was deleted
404                                 continue;
405                             }
406                             $user_mapping[$mapping] = $user->id;
407                             $userid = $user->id;
408                         } else {
409                             $userid = $user_mapping[$mapping];
410                         }
411                         if (empty($fields[$rolefield]) or !isset($roles[$fields[$rolefield]])) {
412                             if (!$defaultrole) {
413                                 // role is mandatory
414                                 continue;
415                             }
416                             $roleid = $defaultrole;
417                         } else {
418                             $roleid = $roles[$fields[$rolefield]];
419                         }
421                         $requested_roles[$userid][$roleid] = $roleid;
422                     }
423                 }
424                 $rs->Close();
425             } else {
426                 debugging('Error while communicating with external enrolment database');
427                 $extdb->Close();
428                 return;
429             }
430             unset($user_mapping);
432             // enrol all users and sync roles
433             foreach ($requested_roles as $userid=>$userroles) {
434                 foreach ($userroles as $roleid) {
435                     if (empty($current_roles[$userid])) {
436                         $this->enrol_user($instance, $userid, $roleid);
437                         $current_roles[$userid][$roleid] = $roleid;
438                         $current_status[$userid] = ENROL_USER_ACTIVE;
439                     }
440                 }
442                 // unassign removed roles
443                 foreach($current_roles[$userid] as $cr) {
444                     if (empty($userroles[$cr])) {
445                         role_unassign($cr, $userid, $context->id, 'enrol_database', $instance->id);
446                         unset($current_roles[$userid][$cr]);
447                     }
448                 }
450                 // reenable enrolment when previously disable enrolment refreshed
451                 if ($current_status[$userid] == ENROL_USER_SUSPENDED) {
452                     $DB->set_field('user_enrolments', 'status', ENROL_USER_ACTIVE, array('enrolid'=>$instance->id, 'userid'=>$userid));
453                 }
454             }
456             // deal with enrolments removed from external table
457             if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
458                 if (!$preventfullunenrol) {
459                     // unenrol
460                     foreach ($current_status as $userid=>$status) {
461                         if (isset($requested_roles[$userid])) {
462                             continue;
463                         }
464                         $this->unenrol_user($instance, $userid);
465                     }
466                 }
468             } else if ($unenrolaction == ENROL_EXT_REMOVED_KEEP) {
469                 // keep - only adding enrolments
471             } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND or $unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
472                 // disable
473                 foreach ($current_status as $userid=>$status) {
474                     if (isset($requested_roles[$userid])) {
475                         continue;
476                     }
477                     if ($status != ENROL_USER_SUSPENDED) {
478                         $DB->set_field('user_enrolments', 'status', ENROL_USER_SUSPENDED, array('enrolid'=>$instance->id, 'userid'=>$userid));
479                     }
480                     if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
481                         role_unassign_all(array('contextid'=>$context->id, 'userid'=>$userid, 'component'=>'enrol_database', 'itemid'=>$instance->id));
482                     }
483                 }
484             }
485         }
487         // close db connection
488         $extdb->Close();
489     }
491     /**
492      * Performs a full sync with external database.
493      *
494      * First it creates new courses if necessary, then
495      * enrols and unenrols users.
496      * @return void
497      */
498     public function sync_courses() {
499         global $CFG, $DB;
501         // make sure we sync either enrolments or courses
502         if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('newcoursetable') or !$this->get_config('newcoursefullname') or !$this->get_config('newcourseshortname')) {
503             return;
504         }
506         // we may need a lot of memory here
507         @set_time_limit(0);
508         raise_memory_limit(MEMORY_HUGE);
510         $extdb = $this->db_init();
512         // first create new courses
513         $table     = $this->get_config('newcoursetable');
514         $fullname  = strtolower($this->get_config('newcoursefullname'));
515         $shortname = strtolower($this->get_config('newcourseshortname'));
516         $idnumber  = strtolower($this->get_config('newcourseidnumber'));
517         $category  = strtolower($this->get_config('newcoursecategory'));
519         $sqlfields = array($fullname, $shortname);
520         if ($category) {
521             $sqlfields[] = $category;
522         }
523         if ($idnumber) {
524             $sqlfields[] = $idnumber;
525         }
526         $sql = $this->db_get_sql($table, array(), $sqlfields);
527         $createcourses = array();
528         if ($rs = $extdb->Execute($sql)) {
529             if (!$rs->EOF) {
530                 $courselist = array();
531                 while ($fields = $rs->FetchRow()) {
532                     $fields = array_change_key_case($fields, CASE_LOWER);
533                     if (empty($fields[$shortname]) or empty($fields[$fullname])) {
534                         //invalid record - these two are mandatory
535                         continue;
536                     }
537                     $fields = $this->db_decode($fields);
538                     if ($DB->record_exists('course', array('shortname'=>$fields[$shortname]))) {
539                         // already exists
540                         continue;
541                     }
542                     if ($idnumber and $DB->record_exists('course', array('idnumber'=>$fields[$idnumber]))) {
543                         // idnumber duplicates are not allowed
544                         continue;
545                     }
546                     if ($category and !$DB->record_exists('course_categories', array('id'=>$fields[$category]))) {
547                         // invalid category id, better to skip
548                         continue;
549                     }
550                     $course = new stdClass();
551                     $course->fullname  = $fields[$fullname];
552                     $course->shortname = $fields[$shortname];
553                     $course->idnumber  = $idnumber ? $fields[$idnumber] : NULL;
554                     $course->category  = $category ? $fields[$category] : NULL;
555                     $createcourses[] = $course;
556                 }
557             }
558             $rs->Close();
559         } else {
560             debugging('Error while communicating with external enrolment database');
561             $extdb->Close();
562             return;
563         }
564         if ($createcourses) {
565             require_once("$CFG->dirroot/course/lib.php");
567             $template        = $this->get_config('templatecourse');
568             $defaultcategory = $this->get_config('defaultcategory');
570             if ($template) {
571                 if ($template = $DB->get_record('course', array('shortname'=>$template))) {
572                     unset($template->id);
573                     unset($template->fullname);
574                     unset($template->shortname);
575                     unset($template->idnumber);
576                 } else {
577                     $template = new stdClass();
578                 }
579             } else {
580                 $template = new stdClass();
581             }
582             if (!$DB->record_exists('course_categories', array('id'=>$defaultcategory))) {
583                 $categories = $DB->get_records('course_categories', array(), 'sortorder', 'id', 0, 1);
584                 $first = reset($categories);
585                 $defaultcategory = $first->id;
586             }
588             foreach ($createcourses as $fields) {
589                 $newcourse = clone($template);
590                 $newcourse->fullname  = $fields->fullname;
591                 $newcourse->shortname = $fields->shortname;
592                 $newcourse->idnumber  = $fields->idnumber;
593                 $newcourse->category  = $fields->category ? $fields->category : $defaultcategory;
595                 create_course($newcourse);
596             }
598             unset($createcourses);
599             unset($template);
600         }
602         // close db connection
603         $extdb->Close();
604     }
606     protected function db_get_sql($table, array $conditions, array $fields, $distinct = false, $sort = "") {
607         $fields = $fields ? implode(',', $fields) : "*";
608         $where = array();
609         if ($conditions) {
610             foreach ($conditions as $key=>$value) {
611                 $value = $this->db_encode($this->db_addslashes($value));
613                 $where[] = "$key = '$value'";
614             }
615         }
616         $where = $where ? "WHERE ".implode(" AND ", $where) : "";
617         $sort = $sort ? "ORDER BY $sort" : "";
618         $distinct = $distinct ? "DISTINCT" : "";
619         $sql = "SELECT $distinct $fields
620                   FROM $table
621                  $where
622                   $sort";
624         return $sql;
625     }
627     protected function db_init() {
628         global $CFG;
630         require_once($CFG->libdir.'/adodb/adodb.inc.php');
632         // Connect to the external database (forcing new connection)
633         $extdb = ADONewConnection($this->get_config('dbtype'));
634         if ($this->get_config('debugdb')) {
635             $extdb->debug = true;
636             ob_start(); //start output buffer to allow later use of the page headers
637         }
639         $extdb->Connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'), $this->get_config('dbname'), true);
640         $extdb->SetFetchMode(ADODB_FETCH_ASSOC);
641         if ($this->get_config('dbsetupsql')) {
642             $extdb->Execute($this->get_config('dbsetupsql'));
643         }
644         return $extdb;
645     }
647     protected function db_addslashes($text) {
648         // using custom made function for now
649         if ($this->get_config('dbsybasequoting')) {
650             $text = str_replace('\\', '\\\\', $text);
651             $text = str_replace(array('\'', '"', "\0"), array('\\\'', '\\"', '\\0'), $text);
652         } else {
653             $text = str_replace("'", "''", $text);
654         }
655         return $text;
656     }
658     protected function db_encode($text) {
659         $dbenc = $this->get_config('dbencoding');
660         if (empty($dbenc) or $dbenc == 'utf-8') {
661             return $text;
662         }
663         if (is_array($text)) {
664             foreach($text as $k=>$value) {
665                 $text[$k] = $this->db_encode($value);
666             }
667             return $text;
668         } else {
669             return textlib_get_instance()->convert($text, 'utf-8', $dbenc);
670         }
671     }
673     protected function db_decode($text) {
674         $dbenc = $this->get_config('dbencoding');
675         if (empty($dbenc) or $dbenc == 'utf-8') {
676             return $text;
677         }
678         if (is_array($text)) {
679             foreach($text as $k=>$value) {
680                 $text[$k] = $this->db_decode($value);
681             }
682             return $text;
683         } else {
684             return textlib_get_instance()->convert($text, $dbenc, 'utf-8');
685         }
686     }