[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/authpdo/ -> auth.php (source)

   1  <?php
   2  use dokuwiki\Utf8\Sort;
   3  
   4  /**
   5   * DokuWiki Plugin authpdo (Auth Component)
   6   *
   7   * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
   8   * @author  Andreas Gohr <andi@splitbrain.org>
   9   */
  10  
  11  /**
  12   * Class auth_plugin_authpdo
  13   */
  14  class auth_plugin_authpdo extends DokuWiki_Auth_Plugin
  15  {
  16  
  17      /** @var PDO */
  18      protected $pdo;
  19  
  20      /** @var null|array The list of all groups */
  21      protected $groupcache = null;
  22  
  23      /**
  24       * Constructor.
  25       */
  26      public function __construct()
  27      {
  28          parent::__construct(); // for compatibility
  29  
  30          if (!class_exists('PDO')) {
  31              $this->debugMsg('PDO extension for PHP not found.', -1, __LINE__);
  32              $this->success = false;
  33              return;
  34          }
  35  
  36          if (!$this->getConf('dsn')) {
  37              $this->debugMsg('No DSN specified', -1, __LINE__);
  38              $this->success = false;
  39              return;
  40          }
  41  
  42          try {
  43              $this->pdo = new PDO(
  44                  $this->getConf('dsn'),
  45                  $this->getConf('user'),
  46                  conf_decodeString($this->getConf('pass')),
  47                  array(
  48                      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // always fetch as array
  49                      PDO::ATTR_EMULATE_PREPARES => true, // emulating prepares allows us to reuse param names
  50                      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
  51                  )
  52              );
  53          } catch (PDOException $e) {
  54              $this->debugMsg($e);
  55              msg($this->getLang('connectfail'), -1);
  56              $this->success = false;
  57              return;
  58          }
  59  
  60          // can Users be created?
  61          $this->cando['addUser'] = $this->checkConfig(
  62              array(
  63                  'select-user',
  64                  'select-user-groups',
  65                  'select-groups',
  66                  'insert-user',
  67                  'insert-group',
  68                  'join-group'
  69              )
  70          );
  71  
  72          // can Users be deleted?
  73          $this->cando['delUser'] = $this->checkConfig(
  74              array(
  75                  'select-user',
  76                  'select-user-groups',
  77                  'select-groups',
  78                  'leave-group',
  79                  'delete-user'
  80              )
  81          );
  82  
  83          // can login names be changed?
  84          $this->cando['modLogin'] = $this->checkConfig(
  85              array(
  86                  'select-user',
  87                  'select-user-groups',
  88                  'update-user-login'
  89              )
  90          );
  91  
  92          // can passwords be changed?
  93          $this->cando['modPass'] = $this->checkConfig(
  94              array(
  95                  'select-user',
  96                  'select-user-groups',
  97                  'update-user-pass'
  98              )
  99          );
 100  
 101          // can real names be changed?
 102          $this->cando['modName'] = $this->checkConfig(
 103              array(
 104                  'select-user',
 105                  'select-user-groups',
 106                  'update-user-info:name'
 107              )
 108          );
 109  
 110          // can real email be changed?
 111          $this->cando['modMail'] = $this->checkConfig(
 112              array(
 113                  'select-user',
 114                  'select-user-groups',
 115                  'update-user-info:mail'
 116              )
 117          );
 118  
 119          // can groups be changed?
 120          $this->cando['modGroups'] = $this->checkConfig(
 121              array(
 122                  'select-user',
 123                  'select-user-groups',
 124                  'select-groups',
 125                  'leave-group',
 126                  'join-group',
 127                  'insert-group'
 128              )
 129          );
 130  
 131          // can a filtered list of users be retrieved?
 132          $this->cando['getUsers'] = $this->checkConfig(
 133              array(
 134                  'list-users'
 135              )
 136          );
 137  
 138          // can the number of users be retrieved?
 139          $this->cando['getUserCount'] = $this->checkConfig(
 140              array(
 141                  'count-users'
 142              )
 143          );
 144  
 145          // can a list of available groups be retrieved?
 146          $this->cando['getGroups'] = $this->checkConfig(
 147              array(
 148                  'select-groups'
 149              )
 150          );
 151  
 152          $this->success = true;
 153      }
 154  
 155      /**
 156       * Check user+password
 157       *
 158       * @param string $user the user name
 159       * @param string $pass the clear text password
 160       * @return  bool
 161       */
 162      public function checkPass($user, $pass)
 163      {
 164  
 165          $userdata = $this->selectUser($user);
 166          if ($userdata == false) return false;
 167  
 168          // password checking done in SQL?
 169          if ($this->checkConfig(array('check-pass'))) {
 170              $userdata['clear'] = $pass;
 171              $userdata['hash'] = auth_cryptPassword($pass);
 172              $result = $this->query($this->getConf('check-pass'), $userdata);
 173              if ($result === false) return false;
 174              return (count($result) == 1);
 175          }
 176  
 177          // we do password checking on our own
 178          if (isset($userdata['hash'])) {
 179              // hashed password
 180              $passhash = new \dokuwiki\PassHash();
 181              return $passhash->verify_hash($pass, $userdata['hash']);
 182          } else {
 183              // clear text password in the database O_o
 184              return ($pass === $userdata['clear']);
 185          }
 186      }
 187  
 188      /**
 189       * Return user info
 190       *
 191       * Returns info about the given user needs to contain
 192       * at least these fields:
 193       *
 194       * name string  full name of the user
 195       * mail string  email addres of the user
 196       * grps array   list of groups the user is in
 197       *
 198       * @param string $user the user name
 199       * @param bool $requireGroups whether or not the returned data must include groups
 200       * @return array|bool containing user data or false
 201       */
 202      public function getUserData($user, $requireGroups = true)
 203      {
 204          $data = $this->selectUser($user);
 205          if ($data == false) return false;
 206  
 207          if (isset($data['hash'])) unset($data['hash']);
 208          if (isset($data['clean'])) unset($data['clean']);
 209  
 210          if ($requireGroups) {
 211              $data['grps'] = $this->selectUserGroups($data);
 212              if ($data['grps'] === false) return false;
 213          }
 214  
 215          return $data;
 216      }
 217  
 218      /**
 219       * Create a new User [implement only where required/possible]
 220       *
 221       * Returns false if the user already exists, null when an error
 222       * occurred and true if everything went well.
 223       *
 224       * The new user HAS TO be added to the default group by this
 225       * function!
 226       *
 227       * Set addUser capability when implemented
 228       *
 229       * @param string $user
 230       * @param string $clear
 231       * @param string $name
 232       * @param string $mail
 233       * @param null|array $grps
 234       * @return bool|null
 235       */
 236      public function createUser($user, $clear, $name, $mail, $grps = null)
 237      {
 238          global $conf;
 239  
 240          if (($info = $this->getUserData($user, false)) !== false) {
 241              msg($this->getLang('userexists'), -1);
 242              return false; // user already exists
 243          }
 244  
 245          // prepare data
 246          if ($grps == null) $grps = array();
 247          array_unshift($grps, $conf['defaultgroup']);
 248          $grps = array_unique($grps);
 249          $hash = auth_cryptPassword($clear);
 250          $userdata = compact('user', 'clear', 'hash', 'name', 'mail');
 251  
 252          // action protected by transaction
 253          $this->pdo->beginTransaction();
 254          {
 255              // insert the user
 256              $ok = $this->query($this->getConf('insert-user'), $userdata);
 257              if ($ok === false) goto FAIL;
 258              $userdata = $this->getUserData($user, false);
 259              if ($userdata === false) goto FAIL;
 260  
 261              // create all groups that do not exist, the refetch the groups
 262              $allgroups = $this->selectGroups();
 263              foreach ($grps as $group) {
 264                  if (!isset($allgroups[$group])) {
 265                      $ok = $this->addGroup($group);
 266                      if ($ok === false) goto FAIL;
 267                  }
 268              }
 269              $allgroups = $this->selectGroups();
 270  
 271              // add user to the groups
 272              foreach ($grps as $group) {
 273                  $ok = $this->joinGroup($userdata, $allgroups[$group]);
 274                  if ($ok === false) goto FAIL;
 275              }
 276          }
 277          $this->pdo->commit();
 278          return true;
 279  
 280          // something went wrong, rollback
 281          FAIL:
 282          $this->pdo->rollBack();
 283          $this->debugMsg('Transaction rolled back', 0, __LINE__);
 284          msg($this->getLang('writefail'), -1);
 285          return null; // return error
 286      }
 287  
 288      /**
 289       * Modify user data
 290       *
 291       * @param string $user nick of the user to be changed
 292       * @param array $changes array of field/value pairs to be changed (password will be clear text)
 293       * @return  bool
 294       */
 295      public function modifyUser($user, $changes)
 296      {
 297          // secure everything in transaction
 298          $this->pdo->beginTransaction();
 299          {
 300              $olddata = $this->getUserData($user);
 301              $oldgroups = $olddata['grps'];
 302              unset($olddata['grps']);
 303  
 304              // changing the user name?
 305              if (isset($changes['user'])) {
 306                  if ($this->getUserData($changes['user'], false)) goto FAIL;
 307                  $params = $olddata;
 308                  $params['newlogin'] = $changes['user'];
 309  
 310                  $ok = $this->query($this->getConf('update-user-login'), $params);
 311                  if ($ok === false) goto FAIL;
 312              }
 313  
 314              // changing the password?
 315              if (isset($changes['pass'])) {
 316                  $params = $olddata;
 317                  $params['clear'] = $changes['pass'];
 318                  $params['hash'] = auth_cryptPassword($changes['pass']);
 319  
 320                  $ok = $this->query($this->getConf('update-user-pass'), $params);
 321                  if ($ok === false) goto FAIL;
 322              }
 323  
 324              // changing info?
 325              if (isset($changes['mail']) || isset($changes['name'])) {
 326                  $params = $olddata;
 327                  if (isset($changes['mail'])) $params['mail'] = $changes['mail'];
 328                  if (isset($changes['name'])) $params['name'] = $changes['name'];
 329  
 330                  $ok = $this->query($this->getConf('update-user-info'), $params);
 331                  if ($ok === false) goto FAIL;
 332              }
 333  
 334              // changing groups?
 335              if (isset($changes['grps'])) {
 336                  $allgroups = $this->selectGroups();
 337  
 338                  // remove membership for previous groups
 339                  foreach ($oldgroups as $group) {
 340                      if (!in_array($group, $changes['grps']) && isset($allgroups[$group])) {
 341                          $ok = $this->leaveGroup($olddata, $allgroups[$group]);
 342                          if ($ok === false) goto FAIL;
 343                      }
 344                  }
 345  
 346                  // create all new groups that are missing
 347                  $added = 0;
 348                  foreach ($changes['grps'] as $group) {
 349                      if (!isset($allgroups[$group])) {
 350                          $ok = $this->addGroup($group);
 351                          if ($ok === false) goto FAIL;
 352                          $added++;
 353                      }
 354                  }
 355                  // reload group info
 356                  if ($added > 0) $allgroups = $this->selectGroups();
 357  
 358                  // add membership for new groups
 359                  foreach ($changes['grps'] as $group) {
 360                      if (!in_array($group, $oldgroups)) {
 361                          $ok = $this->joinGroup($olddata, $allgroups[$group]);
 362                          if ($ok === false) goto FAIL;
 363                      }
 364                  }
 365              }
 366  
 367          }
 368          $this->pdo->commit();
 369          return true;
 370  
 371          // something went wrong, rollback
 372          FAIL:
 373          $this->pdo->rollBack();
 374          $this->debugMsg('Transaction rolled back', 0, __LINE__);
 375          msg($this->getLang('writefail'), -1);
 376          return false; // return error
 377      }
 378  
 379      /**
 380       * Delete one or more users
 381       *
 382       * Set delUser capability when implemented
 383       *
 384       * @param array $users
 385       * @return  int    number of users deleted
 386       */
 387      public function deleteUsers($users)
 388      {
 389          $count = 0;
 390          foreach ($users as $user) {
 391              if ($this->deleteUser($user)) $count++;
 392          }
 393          return $count;
 394      }
 395  
 396      /**
 397       * Bulk retrieval of user data [implement only where required/possible]
 398       *
 399       * Set getUsers capability when implemented
 400       *
 401       * @param int $start index of first user to be returned
 402       * @param int $limit max number of users to be returned
 403       * @param array $filter array of field/pattern pairs, null for no filter
 404       * @return  array list of userinfo (refer getUserData for internal userinfo details)
 405       */
 406      public function retrieveUsers($start = 0, $limit = -1, $filter = null)
 407      {
 408          if ($limit < 0) $limit = 10000; // we don't support no limit
 409          if (is_null($filter)) $filter = array();
 410  
 411          if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
 412          foreach (array('user', 'name', 'mail', 'group') as $key) {
 413              if (!isset($filter[$key])) {
 414                  $filter[$key] = '%';
 415              } else {
 416                  $filter[$key] = '%' . $filter[$key] . '%';
 417              }
 418          }
 419          $filter['start'] = (int)$start;
 420          $filter['end'] = (int)$start + $limit;
 421          $filter['limit'] = (int)$limit;
 422  
 423          $result = $this->query($this->getConf('list-users'), $filter);
 424          if (!$result) return array();
 425          $users = array();
 426          if (is_array($result)) {
 427              foreach ($result as $row) {
 428                  if (!isset($row['user'])) {
 429                      $this->debugMsg("list-users statement did not return 'user' attribute", -1, __LINE__);
 430                      return array();
 431                  }
 432                  $users[] = $this->getUserData($row['user']);
 433              }
 434          } else {
 435              $this->debugMsg("list-users statement did not return a list of result", -1, __LINE__);
 436          }
 437          return $users;
 438      }
 439  
 440      /**
 441       * Return a count of the number of user which meet $filter criteria
 442       *
 443       * @param array $filter array of field/pattern pairs, empty array for no filter
 444       * @return int
 445       */
 446      public function getUserCount($filter = array())
 447      {
 448          if (is_null($filter)) $filter = array();
 449  
 450          if (isset($filter['grps'])) $filter['group'] = $filter['grps'];
 451          foreach (array('user', 'name', 'mail', 'group') as $key) {
 452              if (!isset($filter[$key])) {
 453                  $filter[$key] = '%';
 454              } else {
 455                  $filter[$key] = '%' . $filter[$key] . '%';
 456              }
 457          }
 458  
 459          $result = $this->query($this->getConf('count-users'), $filter);
 460          if (!$result || !isset($result[0]['count'])) {
 461              $this->debugMsg("Statement did not return 'count' attribute", -1, __LINE__);
 462          }
 463          return (int)$result[0]['count'];
 464      }
 465  
 466      /**
 467       * Create a new group with the given name
 468       *
 469       * @param string $group
 470       * @return bool
 471       */
 472      public function addGroup($group)
 473      {
 474          $sql = $this->getConf('insert-group');
 475  
 476          $result = $this->query($sql, array(':group' => $group));
 477          $this->clearGroupCache();
 478          if ($result === false) return false;
 479          return true;
 480      }
 481  
 482      /**
 483       * Retrieve groups
 484       *
 485       * Set getGroups capability when implemented
 486       *
 487       * @param int $start
 488       * @param int $limit
 489       * @return  array
 490       */
 491      public function retrieveGroups($start = 0, $limit = 0)
 492      {
 493          $groups = array_keys($this->selectGroups());
 494          if ($groups === false) return array();
 495  
 496          if (!$limit) {
 497              return array_splice($groups, $start);
 498          } else {
 499              return array_splice($groups, $start, $limit);
 500          }
 501      }
 502  
 503      /**
 504       * Select data of a specified user
 505       *
 506       * @param string $user the user name
 507       * @return bool|array user data, false on error
 508       */
 509      protected function selectUser($user)
 510      {
 511          $sql = $this->getConf('select-user');
 512  
 513          $result = $this->query($sql, array(':user' => $user));
 514          if (!$result) return false;
 515  
 516          if (count($result) > 1) {
 517              $this->debugMsg('Found more than one matching user', -1, __LINE__);
 518              return false;
 519          }
 520  
 521          $data = array_shift($result);
 522          $dataok = true;
 523  
 524          if (!isset($data['user'])) {
 525              $this->debugMsg("Statement did not return 'user' attribute", -1, __LINE__);
 526              $dataok = false;
 527          }
 528          if (!isset($data['hash']) && !isset($data['clear']) && !$this->checkConfig(array('check-pass'))) {
 529              $this->debugMsg("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__);
 530              $dataok = false;
 531          }
 532          if (!isset($data['name'])) {
 533              $this->debugMsg("Statement did not return 'name' attribute", -1, __LINE__);
 534              $dataok = false;
 535          }
 536          if (!isset($data['mail'])) {
 537              $this->debugMsg("Statement did not return 'mail' attribute", -1, __LINE__);
 538              $dataok = false;
 539          }
 540  
 541          if (!$dataok) return false;
 542          return $data;
 543      }
 544  
 545      /**
 546       * Delete a user after removing all their group memberships
 547       *
 548       * @param string $user
 549       * @return bool true when the user was deleted
 550       */
 551      protected function deleteUser($user)
 552      {
 553          $this->pdo->beginTransaction();
 554          {
 555              $userdata = $this->getUserData($user);
 556              if ($userdata === false) goto FAIL;
 557              $allgroups = $this->selectGroups();
 558  
 559              // remove group memberships (ignore errors)
 560              foreach ($userdata['grps'] as $group) {
 561                  if (isset($allgroups[$group])) {
 562                      $this->leaveGroup($userdata, $allgroups[$group]);
 563                  }
 564              }
 565  
 566              $ok = $this->query($this->getConf('delete-user'), $userdata);
 567              if ($ok === false) goto FAIL;
 568          }
 569          $this->pdo->commit();
 570          return true;
 571  
 572          FAIL:
 573          $this->pdo->rollBack();
 574          return false;
 575      }
 576  
 577      /**
 578       * Select all groups of a user
 579       *
 580       * @param array $userdata The userdata as returned by _selectUser()
 581       * @return array|bool list of group names, false on error
 582       */
 583      protected function selectUserGroups($userdata)
 584      {
 585          global $conf;
 586          $sql = $this->getConf('select-user-groups');
 587          $result = $this->query($sql, $userdata);
 588          if ($result === false) return false;
 589  
 590          $groups = array($conf['defaultgroup']); // always add default config
 591          if (is_array($result)) {
 592              foreach ($result as $row) {
 593                  if (!isset($row['group'])) {
 594                      $this->debugMsg("No 'group' field returned in select-user-groups statement", -1, __LINE__);
 595                      return false;
 596                  }
 597                  $groups[] = $row['group'];
 598              }
 599          } else {
 600              $this->debugMsg("select-user-groups statement did not return a list of result", -1, __LINE__);
 601          }
 602  
 603          $groups = array_unique($groups);
 604          Sort::sort($groups);
 605          return $groups;
 606      }
 607  
 608      /**
 609       * Select all available groups
 610       *
 611       * @return array|bool list of all available groups and their properties
 612       */
 613      protected function selectGroups()
 614      {
 615          if ($this->groupcache) return $this->groupcache;
 616  
 617          $sql = $this->getConf('select-groups');
 618          $result = $this->query($sql);
 619          if ($result === false) return false;
 620  
 621          $groups = array();
 622          if (is_array($result)) {
 623              foreach ($result as $row) {
 624                  if (!isset($row['group'])) {
 625                      $this->debugMsg("No 'group' field returned from select-groups statement", -1, __LINE__);
 626                      return false;
 627                  }
 628  
 629                  // relayout result with group name as key
 630                  $group = $row['group'];
 631                  $groups[$group] = $row;
 632              }
 633          } else {
 634              $this->debugMsg("select-groups statement did not return a list of result", -1, __LINE__);
 635          }
 636  
 637          Sort::ksort($groups);
 638          return $groups;
 639      }
 640  
 641      /**
 642       * Remove all entries from the group cache
 643       */
 644      protected function clearGroupCache()
 645      {
 646          $this->groupcache = null;
 647      }
 648  
 649      /**
 650       * Adds the user to the group
 651       *
 652       * @param array $userdata all the user data
 653       * @param array $groupdata all the group data
 654       * @return bool
 655       */
 656      protected function joinGroup($userdata, $groupdata)
 657      {
 658          $data = array_merge($userdata, $groupdata);
 659          $sql = $this->getConf('join-group');
 660          $result = $this->query($sql, $data);
 661          if ($result === false) return false;
 662          return true;
 663      }
 664  
 665      /**
 666       * Removes the user from the group
 667       *
 668       * @param array $userdata all the user data
 669       * @param array $groupdata all the group data
 670       * @return bool
 671       */
 672      protected function leaveGroup($userdata, $groupdata)
 673      {
 674          $data = array_merge($userdata, $groupdata);
 675          $sql = $this->getConf('leave-group');
 676          $result = $this->query($sql, $data);
 677          if ($result === false) return false;
 678          return true;
 679      }
 680  
 681      /**
 682       * Executes a query
 683       *
 684       * @param string $sql The SQL statement to execute
 685       * @param array $arguments Named parameters to be used in the statement
 686       * @return array|int|bool The result as associative array for SELECTs, affected rows for others, false on error
 687       */
 688      protected function query($sql, $arguments = array())
 689      {
 690          $sql = trim($sql);
 691          if (empty($sql)) {
 692              $this->debugMsg('No SQL query given', -1, __LINE__);
 693              return false;
 694          }
 695  
 696          // execute
 697          $params = array();
 698          $sth = $this->pdo->prepare($sql);
 699          $result = false;
 700          try {
 701              // prepare parameters - we only use those that exist in the SQL
 702              foreach ($arguments as $key => $value) {
 703                  if (is_array($value)) continue;
 704                  if (is_object($value)) continue;
 705                  if ($key[0] != ':') $key = ":$key"; // prefix with colon if needed
 706                  if (strpos($sql, $key) === false) continue; // skip if parameter is missing
 707  
 708                  if (is_int($value)) {
 709                      $sth->bindValue($key, $value, PDO::PARAM_INT);
 710                  } else {
 711                      $sth->bindValue($key, $value);
 712                  }
 713                  $params[$key] = $value; //remember for debugging
 714              }
 715  
 716              $sth->execute();
 717              // only report last line's result
 718              $hasnextrowset = true;
 719              $currentsql = $sql;
 720              while ($hasnextrowset) {
 721                  if (strtolower(substr($currentsql, 0, 6)) == 'select') {
 722                      $result = $sth->fetchAll();
 723                  } else {
 724                      $result = $sth->rowCount();
 725                  }
 726                  $semi_pos = strpos($currentsql, ';');
 727                  if ($semi_pos) {
 728                      $currentsql = trim(substr($currentsql, $semi_pos + 1));
 729                  }
 730                  try {
 731                      $hasnextrowset = $sth->nextRowset(); // run next rowset
 732                  } catch (PDOException $rowset_e) {
 733                      $hasnextrowset = false; // driver does not support multi-rowset, should be executed in one time
 734                  }
 735              }
 736          } catch (Exception $e) {
 737              // report the caller's line
 738              $trace = debug_backtrace();
 739              $line = $trace[0]['line'];
 740              $dsql = $this->debugSQL($sql, $params, !defined('DOKU_UNITTEST'));
 741              $this->debugMsg($e, -1, $line);
 742              $this->debugMsg("SQL: <pre>$dsql</pre>", -1, $line);
 743          }
 744          $sth->closeCursor();
 745          $sth = null;
 746  
 747          return $result;
 748      }
 749  
 750      /**
 751       * Wrapper around msg() but outputs only when debug is enabled
 752       *
 753       * @param string|Exception $message
 754       * @param int $err
 755       * @param int $line
 756       */
 757      protected function debugMsg($message, $err = 0, $line = 0)
 758      {
 759          if (!$this->getConf('debug')) return;
 760          if (is_a($message, 'Exception')) {
 761              $err = -1;
 762              $msg = $message->getMessage();
 763              if (!$line) $line = $message->getLine();
 764          } else {
 765              $msg = $message;
 766          }
 767  
 768          if (defined('DOKU_UNITTEST')) {
 769              printf("\n%s, %s:%d\n", $msg, __FILE__, $line);
 770          } else {
 771              msg('authpdo: ' . $msg, $err, $line, __FILE__);
 772          }
 773      }
 774  
 775      /**
 776       * Check if the given config strings are set
 777       *
 778       * @param string[] $keys
 779       * @return  bool
 780       * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
 781       *
 782       */
 783      protected function checkConfig($keys)
 784      {
 785          foreach ($keys as $key) {
 786              $params = explode(':', $key);
 787              $key = array_shift($params);
 788              $sql = trim($this->getConf($key));
 789  
 790              // check if sql is set
 791              if (!$sql) return false;
 792              // check if needed params are there
 793              foreach ($params as $param) {
 794                  if (strpos($sql, ":$param") === false) return false;
 795              }
 796          }
 797  
 798          return true;
 799      }
 800  
 801      /**
 802       * create an approximation of the SQL string with parameters replaced
 803       *
 804       * @param string $sql
 805       * @param array $params
 806       * @param bool $htmlescape Should the result be escaped for output in HTML?
 807       * @return string
 808       */
 809      protected function debugSQL($sql, $params, $htmlescape = true)
 810      {
 811          foreach ($params as $key => $val) {
 812              if (is_int($val)) {
 813                  $val = $this->pdo->quote($val, PDO::PARAM_INT);
 814              } elseif (is_bool($val)) {
 815                  $val = $this->pdo->quote($val, PDO::PARAM_BOOL);
 816              } elseif (is_null($val)) {
 817                  $val = 'NULL';
 818              } else {
 819                  $val = $this->pdo->quote($val);
 820              }
 821              $sql = str_replace($key, $val, $sql);
 822          }
 823          if ($htmlescape) $sql = hsc($sql);
 824          return $sql;
 825      }
 826  }
 827  
 828  // vim:ts=4:sw=4:et: