[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/auth/db/ -> auth.php (source)

   1  <?php
   2  
   3  /**
   4   * @author Martin Dougiamas
   5   * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
   6   * @package moodle multiauth
   7   *
   8   * Authentication Plugin: External Database Authentication
   9   *
  10   * Checks against an external database.
  11   *
  12   * 2006-08-28  File created.
  13   */
  14  
  15  if (!defined('MOODLE_INTERNAL')) {
  16      die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
  17  }
  18  
  19  require_once($CFG->libdir.'/authlib.php');
  20  
  21  /**
  22   * External database authentication plugin.
  23   */
  24  class auth_plugin_db extends auth_plugin_base {
  25  
  26      /**
  27       * Constructor.
  28       */
  29      function auth_plugin_db() {
  30          $this->authtype = 'db';
  31          $this->config = get_config('auth/db');
  32          if (empty($this->config->extencoding)) {
  33              $this->config->extencoding = 'utf-8';
  34          }
  35      }
  36  
  37      /**
  38       * Returns true if the username and password work and false if they are
  39       * wrong or don't exist.
  40       *
  41       * @param string $username The username (with system magic quotes)
  42       * @param string $password The password (with system magic quotes)
  43       *
  44       * @return bool Authentication success or failure.
  45       */
  46      function user_login($username, $password) {
  47  
  48          global $CFG;
  49  
  50          $textlib = textlib_get_instance();
  51          $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->extencoding);
  52          $extpassword = $textlib->convert(stripslashes($password), 'utf-8', $this->config->extencoding);
  53  
  54          $authdb = $this->db_init();
  55  
  56          if ($this->config->passtype === 'internal') {
  57              // lookup username externally, but resolve
  58              // password locally -- to support backend that
  59              // don't track passwords
  60              $rs = $authdb->Execute("SELECT * FROM {$this->config->table}
  61                                       WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."' ");
  62              if (!$rs) {
  63                  $authdb->Close();
  64                  print_error('auth_dbcantconnect','auth');
  65                  return false;
  66              }
  67  
  68              if ( !$rs->EOF ) {
  69                  $rs->Close();
  70                  $authdb->Close();
  71                  // user exists exterally
  72                  // check username/password internally
  73                  if ($user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id)) {
  74                      return validate_internal_user_password($user, $password);
  75                  }
  76              } else {
  77                  $rs->Close();
  78                  $authdb->Close();
  79                  // user does not exist externally
  80                  return false;
  81              }
  82  
  83          } else {
  84              // normal case: use external db for passwords
  85  
  86              if ($this->config->passtype === 'md5') {   // Re-format password accordingly
  87                  $extpassword = md5($extpassword);
  88              } else if ($this->config->passtype === 'sha1') {
  89                  $extpassword = sha1($extpassword);
  90              }
  91  
  92              $rs = $authdb->Execute("SELECT * FROM {$this->config->table}
  93                                  WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."'
  94                                    AND {$this->config->fieldpass} = '".$this->ext_addslashes($extpassword)."' ");
  95              if (!$rs) {
  96                  $authdb->Close();
  97                  print_error('auth_dbcantconnect','auth');
  98                  return false;
  99              }
 100  
 101              if (!$rs->EOF) {
 102                  $rs->Close();
 103                  $authdb->Close();
 104                  return true;
 105              } else {
 106                  $rs->Close();
 107                  $authdb->Close();
 108                  return false;
 109              }
 110  
 111          }
 112      }
 113  
 114      function db_init() {
 115          // Connect to the external database (forcing new connection)
 116          $authdb = &ADONewConnection($this->config->type);
 117          if (!empty($this->config->debugauthdb)) {
 118              $authdb->debug = true;
 119              ob_start();//start output buffer to allow later use of the page headers
 120          }
 121          $authdb->Connect($this->config->host, $this->config->user, $this->config->pass, $this->config->name, true);
 122          $authdb->SetFetchMode(ADODB_FETCH_ASSOC);
 123          if (!empty($this->config->setupsql)) {
 124              $authdb->Execute($this->config->setupsql);
 125          }
 126  
 127          return $authdb;
 128      }
 129      /**
 130       * retuns user attribute mappings between moodle and ldap
 131       *
 132       * @return array
 133       */
 134      function db_attributes() {
 135          $moodleattributes = array();
 136          foreach ($this->userfields as $field) {
 137              if (!empty($this->config->{"field_map_$field"})) {
 138                  $moodleattributes[$field] = $this->config->{"field_map_$field"};
 139              }
 140          }
 141          $moodleattributes['username'] = $this->config->fielduser;
 142          return $moodleattributes;
 143      }
 144  
 145      /**
 146       * Reads any other information for a user from external database,
 147       * then returns it in an array
 148       *
 149       * @param string $username (with system magic quotes)
 150       *
 151       * @return array without magic quotes
 152       */
 153      function get_userinfo($username) {
 154  
 155          global $CFG;
 156  
 157          $textlib = textlib_get_instance();
 158          $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->extencoding);
 159  
 160          $authdb = $this->db_init();
 161  
 162          //Array to map local fieldnames we want, to external fieldnames
 163          $selectfields = $this->db_attributes();
 164  
 165          $result = array();
 166          //If at least one field is mapped from external db, get that mapped data:
 167          if ($selectfields) {
 168              $select = '';
 169              foreach ($selectfields as $localname=>$externalname) {
 170                  $select .= ", $externalname AS $localname";
 171              }
 172              $select = 'SELECT ' . substr($select,1);
 173              $sql = $select .
 174                  " FROM {$this->config->table}" .
 175                  " WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."'";
 176              if ($rs = $authdb->Execute($sql)) {
 177                  if ( !$rs->EOF ) {
 178                      $fields_obj = rs_fetch_record($rs);
 179                      $fields_obj = (object)array_change_key_case((array)$fields_obj , CASE_LOWER);                 
 180                      foreach ($selectfields as $localname=>$externalname) {
 181                          $result[$localname] = $textlib->convert($fields_obj->{$localname}, $this->config->extencoding, 'utf-8');
 182                       }
 183                   }
 184                   rs_close($rs);
 185              }
 186          }
 187          $authdb->Close();
 188          return $result;
 189  
 190      }
 191  
 192  
 193      /**
 194       * Change a user's password
 195       *
 196       * @param  object  $user        User table object  (with system magic quotes)
 197       * @param  string  $newpassword Plaintext password (with system magic quotes)
 198       *
 199       * @return bool                  True on success
 200       */
 201      function user_update_password($user, $newpassword) {
 202  
 203          global $CFG;
 204          if ($this->config->passtype === 'internal') {
 205              return update_internal_user_password($user, $newpassword);
 206          } else {
 207              // we should have never been called!
 208              return false;
 209          }
 210      }
 211  
 212      /**
 213       * syncronizes user fron external db to moodle user table
 214       *
 215       * Sync shouid be done by using idnumber attribute, not username.
 216       * You need to pass firstsync parameter to function to fill in
 217       * idnumbers if they dont exists in moodle user table.
 218       *
 219       * Syncing users removes (disables) users that dont exists anymore in external db.
 220       * Creates new users and updates coursecreator status of users.
 221       *
 222       * @param bool $do_updates  Optional: set to true to force an update of existing accounts
 223       *
 224       * This implementation is simpler but less scalable than the one found in the LDAP module.
 225       *
 226       */
 227      function sync_users($do_updates=false) {
 228  
 229          global $CFG;
 230          $pcfg = get_config('auth/db');
 231  
 232  /// list external users
 233          $userlist = $this->get_userlist();
 234          $quoteduserlist = implode("', '", addslashes_recursive($userlist));
 235          $quoteduserlist = "'$quoteduserlist'";
 236  
 237  /// delete obsolete internal users
 238          if (!empty($this->config->removeuser)) {
 239  
 240              // find obsolete users
 241              if (count($userlist)) {
 242                  $sql = "SELECT u.id, u.username, u.email, u.auth
 243                          FROM {$CFG->prefix}user u
 244                          WHERE u.auth='db' AND u.deleted=0 AND u.username NOT IN ($quoteduserlist)";
 245              } else {
 246                  $sql = "SELECT u.id, u.username, u.email, u.auth
 247                          FROM {$CFG->prefix}user u
 248                          WHERE u.auth='db' AND u.deleted=0";
 249              }
 250              $remove_users = get_records_sql($sql);
 251  
 252              if (!empty($remove_users)) {
 253                  print_string('auth_dbuserstoremove','auth', count($remove_users)); echo "\n";
 254  
 255                  foreach ($remove_users as $user) {
 256                      if ($this->config->removeuser == 2) {
 257                          if (delete_user($user)) {
 258                              echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n";
 259                          } else {
 260                              echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n";
 261                          }
 262                      } else if ($this->config->removeuser == 1) {
 263                          $updateuser = new object();
 264                          $updateuser->id   = $user->id;
 265                          $updateuser->auth = 'nologin';
 266                          if (update_record('user', $updateuser)) {
 267                              echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n";
 268                          } else {
 269                              echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n";
 270                          }
 271                      }
 272                  }
 273              }
 274              unset($remove_users); // free mem!
 275          }
 276  
 277          if (!count($userlist)) {
 278              // exit right here
 279              // nothing else to do
 280              return true;
 281          }
 282  
 283          ///
 284          /// update existing accounts
 285          ///
 286          if ($do_updates) {
 287              // narrow down what fields we need to update
 288              $all_keys = array_keys(get_object_vars($this->config));
 289              $updatekeys = array();
 290              foreach ($all_keys as $key) {
 291                  if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) {
 292                      if ($this->config->{$key} === 'onlogin') {
 293                          array_push($updatekeys, $match[1]); // the actual key name
 294                      }
 295                  }
 296              }
 297              // print_r($all_keys); print_r($updatekeys);
 298              unset($all_keys); unset($key);
 299  
 300              // only go ahead if we actually
 301              // have fields to update locally
 302              if (!empty($updatekeys)) {
 303                  $sql = 'SELECT u.id, u.username
 304                          FROM ' . $CFG->prefix .'user u
 305                          WHERE u.auth=\'db\' AND u.deleted=\'0\' AND u.username IN (' . $quoteduserlist . ')';
 306                  if ($update_users = get_records_sql($sql)) {
 307                      print "User entries to update: ". count($update_users). "\n";
 308  
 309                      foreach ($update_users as $user) {
 310                          echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id));
 311                          if (!$this->update_user_record(addslashes($user->username), $updatekeys)) {
 312                              echo " - ".get_string('skipped');
 313                          }
 314                          echo "\n";
 315                      }
 316                      unset($update_users); // free memory
 317                  }
 318              }
 319          }
 320  
 321  
 322          ///
 323          /// create missing accounts
 324          ///
 325          // NOTE: this is very memory intensive
 326          // and generally inefficient
 327          $sql = 'SELECT u.id, u.username
 328                  FROM ' . $CFG->prefix .'user u
 329                  WHERE u.auth=\'db\' AND u.deleted=\'0\'';
 330  
 331          $users = get_records_sql($sql);
 332  
 333          // simplify down to usernames
 334          $usernames = array();
 335          if (!empty($users)) {
 336              foreach ($users as $user) {
 337                  array_push($usernames, $user->username);
 338              }
 339              unset($users);
 340          }
 341  
 342          $add_users = array_diff($userlist, $usernames);
 343          unset($usernames);
 344  
 345          if (!empty($add_users)) {
 346              print_string('auth_dbuserstoadd','auth',count($add_users)); echo "\n";
 347              begin_sql();
 348              foreach($add_users as $user) {
 349                  $username = $user;
 350                  $user = $this->get_userinfo_asobj($user);
 351  
 352                  // prep a few params
 353                  $user->username   = $username;
 354                  $user->modified   = time();
 355                  $user->confirmed  = 1;
 356                  $user->auth       = 'db';
 357                  $user->mnethostid = $CFG->mnet_localhost_id;
 358                  if (empty($user->lang)) {
 359                      $user->lang = $CFG->lang;
 360                  }
 361  
 362                  $user = addslashes_object($user);
 363                  // maybe the user has been deleted before
 364                  if ($old_user = get_record('user', 'username', $user->username, 'deleted', 1, 'mnethostid', $user->mnethostid)) {
 365                      $user->id = $old_user->id;
 366                      set_field('user', 'deleted', 0, 'username', $user->username);
 367                      echo "\t"; print_string('auth_dbreviveuser', 'auth', array(stripslashes($user->username), $user->id)); echo "\n";
 368                  } elseif ($id = insert_record ('user',$user)) { // it is truly a new user
 369                      echo "\t"; print_string('auth_dbinsertuser','auth',array(stripslashes($user->username), $id)); echo "\n";
 370                      // if relevant, tag for password generation
 371                      if ($this->config->passtype === 'internal') {
 372                          set_user_preference('auth_forcepasswordchange', 1, $id);
 373                          set_user_preference('create_password',          1, $id);
 374                      }
 375                  } else {
 376                      echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n";
 377                  }
 378              }
 379              commit_sql();
 380              unset($add_users); // free mem
 381          }
 382          return true;
 383      }
 384  
 385      function user_exists($username) {
 386  
 387      /// Init result value
 388          $result = false;
 389  
 390          $textlib = textlib_get_instance();
 391          $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->extencoding);
 392  
 393          $authdb = $this->db_init();
 394  
 395          $rs = $authdb->Execute("SELECT * FROM {$this->config->table}
 396                                       WHERE {$this->config->fielduser} = '".$this->ext_addslashes($extusername)."' ");
 397  
 398          if (!$rs) {
 399              print_error('auth_dbcantconnect','auth');
 400          } else if ( !$rs->EOF ) {
 401              // user exists exterally
 402              $result = true;
 403          }
 404  
 405          $authdb->Close();
 406          return $result;
 407      }
 408  
 409  
 410      function get_userlist() {
 411  
 412      /// Init result value
 413          $result = array();
 414  
 415          $authdb = $this->db_init();
 416  
 417          // fetch userlist
 418          $rs = $authdb->Execute("SELECT {$this->config->fielduser} AS username
 419                                  FROM   {$this->config->table} ");
 420  
 421          if (!$rs) {
 422              print_error('auth_dbcantconnect','auth');
 423          } else if ( !$rs->EOF ) {
 424              while ($rec = rs_fetch_next_record($rs)) {
 425                  $rec = (object)array_change_key_case((array)$rec , CASE_LOWER);
 426                  array_push($result, $rec->username);
 427              }
 428          }
 429  
 430          $authdb->Close();
 431          return $result;
 432      }
 433  
 434      /**
 435       * reads userinformation from DB and return it in an object
 436       *
 437       * @param string $username username (with system magic quotes)
 438       * @return array
 439       */
 440      function get_userinfo_asobj($username) {
 441          $user_array = truncate_userinfo($this->get_userinfo($username));
 442          $user = new object();
 443          foreach($user_array as $key=>$value) {
 444              $user->{$key} = $value;
 445          }
 446          return $user;
 447      }
 448  
 449      /**
 450       * will update a local user record from an external source.
 451       * is a lighter version of the one in moodlelib -- won't do
 452       * expensive ops such as enrolment
 453       *
 454       * If you don't pass $updatekeys, there is a performance hit and
 455       * values removed from DB won't be removed from moodle.
 456       *
 457       * @param string $username username (with system magic quotes)
 458       */
 459      function update_user_record($username, $updatekeys=false) {
 460          global $CFG;
 461  
 462          //just in case check text case
 463          $username = trim(moodle_strtolower($username));
 464  
 465          // get the current user record
 466          $user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id);
 467          if (empty($user)) { // trouble
 468              error_log("Cannot update non-existent user: $username");
 469              print_error('auth_dbusernotexist','auth',$username);
 470              die;
 471          }
 472  
 473          // Ensure userid is not overwritten
 474          $userid = $user->id;
 475  
 476          if ($newinfo = $this->get_userinfo($username)) {
 477              $newinfo = truncate_userinfo($newinfo);
 478  
 479              if (empty($updatekeys)) { // all keys? this does not support removing values
 480                  $updatekeys = array_keys($newinfo);
 481              }
 482  
 483              foreach ($updatekeys as $key) {
 484                  if (isset($newinfo[$key])) {
 485                      $value = $newinfo[$key];
 486                  } else {
 487                      $value = '';
 488                  }
 489  
 490                  if (!empty($this->config->{'field_updatelocal_' . $key})) {
 491                      if ($user->{$key} != $value) { // only update if it's changed
 492                          set_field('user', $key, addslashes($value), 'id', $userid);
 493                      }
 494                  }
 495              }
 496          }
 497          return get_record_select('user', "id = $userid AND deleted = 0");
 498      }
 499  
 500      /**
 501       * Called when the user record is updated.
 502       * Modifies user in external database. It takes olduser (before changes) and newuser (after changes)
 503       * conpares information saved modified information to external db.
 504       *
 505       * @param mixed $olduser     Userobject before modifications    (without system magic quotes)
 506       * @param mixed $newuser     Userobject new modified userobject (without system magic quotes)
 507       * @return boolean result
 508       *
 509       */
 510      function user_update($olduser, $newuser) {
 511          if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) {
 512              error_log("ERROR:User renaming not allowed in ext db");
 513              return false;
 514          }
 515  
 516          if (isset($olduser->auth) and $olduser->auth != 'db') {
 517              return true; // just change auth and skip update
 518          }
 519  
 520          $curruser = $this->get_userinfo($olduser->username);
 521          if (empty($curruser)) {
 522              error_log("ERROR:User $olduser->username found in ext db");
 523              return false;
 524          }
 525  
 526          $textlib = textlib_get_instance();
 527          $extusername = $textlib->convert($olduser->username, 'utf-8', $this->config->extencoding);
 528  
 529          $authdb = $this->db_init();
 530  
 531          $update = array();
 532          foreach($curruser as $key=>$value) {
 533              if ($key == 'username') {
 534                  continue; // skip this
 535              }
 536              if (empty($this->config->{"field_updateremote_$key"})) {
 537                  continue; // remote update not requested
 538              }
 539              if (!isset($newuser->$key)) {
 540                  continue;
 541              }
 542              $nuvalue = stripslashes($newuser->$key);
 543              if ($nuvalue != $value) {
 544                  $update[] = $this->config->{"field_map_$key"}."='".$this->ext_addslashes($textlib->convert($nuvalue, 'utf-8', $this->config->extencoding))."'";
 545              }
 546          }
 547          if (!empty($update)) {
 548              $authdb->Execute("UPDATE {$this->config->table}
 549                                  SET ".implode(',', $update)."
 550                                  WHERE {$this->config->fielduser}='".$this->ext_addslashes($extusername)."'");
 551          }
 552          $authdb->Close();
 553          return true;
 554      }
 555  
 556      /**
 557       * A chance to validate form data, and last chance to
 558       * do stuff before it is inserted in config_plugin
 559       */
 560       function validate_form(&$form, &$err) {
 561          if ($form->passtype === 'internal') {
 562              $this->config->changepasswordurl = '';
 563              set_config('changepasswordurl', '', 'auth/db');
 564          }
 565      }
 566  
 567      /**
 568       * Returns true if this authentication plugin is 'internal'.
 569       *
 570       * @return bool
 571       */
 572      function is_internal() {
 573          return ($this->config->passtype == 'internal');
 574      }
 575  
 576      /**
 577       * Returns true if this authentication plugin can change the user's
 578       * password.
 579       *
 580       * @return bool
 581       */
 582      function can_change_password() {
 583          return ($this->config->passtype == 'internal' or !empty($this->config->changepasswordurl));
 584      }
 585  
 586      /**
 587       * Returns the URL for changing the user's pw, or empty if the default can
 588       * be used.
 589       *
 590       * @return string
 591       */
 592      function change_password_url() {
 593          if ($this->config->passtype == 'internal') {
 594              // standard form
 595              return '';
 596          } else {
 597              // use custom url
 598              return $this->config->changepasswordurl;
 599          }
 600      }
 601  
 602      /**
 603       * Returns true if plugin allows resetting of internal password.
 604       *
 605       * @return bool
 606       */
 607      function can_reset_password() {
 608          return ($this->config->passtype == 'internal');
 609      }
 610  
 611      /**
 612       * Prints a form for configuring this authentication plugin.
 613       *
 614       * This function is called from admin/auth.php, and outputs a full page with
 615       * a form for configuring this plugin.
 616       *
 617       * @param array $page An object containing all the data for this page.
 618       */
 619      function config_form($config, $err, $user_fields) {
 620          include  'config.html';
 621      }
 622  
 623      /**
 624       * Processes and stores configuration data for this authentication plugin.
 625       */
 626      function process_config($config) {
 627          // set to defaults if undefined
 628          if (!isset($config->host)) {
 629              $config->host = 'localhost';
 630          }
 631          if (!isset($config->type)) {
 632              $config->type = 'mysql';
 633          }
 634          if (!isset($config->sybasequoting)) {
 635              $config->sybasequoting = 0;
 636          }
 637          if (!isset($config->name)) {
 638              $config->name = '';
 639          }
 640          if (!isset($config->user)) {
 641              $config->user = '';
 642          }
 643          if (!isset($config->pass)) {
 644              $config->pass = '';
 645          }
 646          if (!isset($config->table)) {
 647              $config->table = '';
 648          }
 649          if (!isset($config->fielduser)) {
 650              $config->fielduser = '';
 651          }
 652          if (!isset($config->fieldpass)) {
 653              $config->fieldpass = '';
 654          }
 655          if (!isset($config->passtype)) {
 656              $config->passtype = 'plaintext';
 657          }
 658          if (!isset($config->extencoding)) {
 659              $config->extencoding = 'utf-8';
 660          }
 661          if (!isset($config->setupsql)) {
 662              $config->setupsql = '';
 663          }
 664          if (!isset($config->debugauthdb)) {
 665              $config->debugauthdb = 0;
 666          }
 667          if (!isset($config->removeuser)) {
 668              $config->removeuser = 0;
 669          }
 670          if (!isset($config->changepasswordurl)) {
 671              $config->changepasswordurl = '';
 672          }
 673  
 674          $config = stripslashes_recursive($config);
 675          // save settings
 676          set_config('host',          $config->host,          'auth/db');
 677          set_config('type',          $config->type,          'auth/db');
 678          set_config('sybasequoting', $config->sybasequoting, 'auth/db');
 679          set_config('name',          $config->name,          'auth/db');
 680          set_config('user',          $config->user,          'auth/db');
 681          set_config('pass',          $config->pass,          'auth/db');
 682          set_config('table',         $config->table,         'auth/db');
 683          set_config('fielduser',     $config->fielduser,     'auth/db');
 684          set_config('fieldpass',     $config->fieldpass,     'auth/db');
 685          set_config('passtype',      $config->passtype,      'auth/db');
 686          set_config('extencoding',   trim($config->extencoding), 'auth/db');
 687          set_config('setupsql',      trim($config->setupsql),'auth/db');
 688          set_config('debugauthdb',   $config->debugauthdb,   'auth/db');
 689          set_config('removeuser',    $config->removeuser,    'auth/db');
 690          set_config('changepasswordurl', trim($config->changepasswordurl), 'auth/db');
 691  
 692          return true;
 693      }
 694  
 695      function ext_addslashes($text) {
 696          // using custom made function for now
 697          if (empty($this->config->sybasequoting)) {
 698              $text = str_replace('\\', '\\\\', $text);
 699              $text = str_replace(array('\'', '"', "\0"), array('\\\'', '\\"', '\\0'), $text);
 700          } else {
 701              $text = str_replace("'", "''", $text);
 702          }
 703          return $text;
 704      }
 705  }
 706  
 707  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7