ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
DB.php
Go to the documentation of this file.
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
3 
28 require_once 'Auth/Container.php';
32 require_once 'DB.php';
33 
50 {
51 
52  // {{{ properties
53 
58  var $options = array();
59 
64  var $db = null;
65  var $dsn = '';
66 
71  var $activeUser = '';
72 
73  // }}}
74  // {{{ Auth_Container_DB [constructor]
75 
86  {
87  $this->_setDefaults();
88 
89  if (is_array($dsn)) {
90  $this->_parseOptions($dsn);
91 
92  if (empty($this->options['dsn'])) {
93  PEAR::raiseError('No connection parameters specified!');
94  }
95  } else {
96  $this->options['dsn'] = $dsn;
97  }
98  }
99 
100  // }}}
101  // {{{ _connect()
102 
110  function _connect($dsn)
111  {
112  $this->log('Auth_Container_DB::_connect() called.', AUTH_LOG_DEBUG);
113 
114  if (is_string($dsn) || is_array($dsn)) {
115  $this->db = DB::Connect($dsn, $this->options['db_options']);
116  } elseif (is_subclass_of($dsn, 'db_common')) {
117  $this->db = $dsn;
118  } elseif (DB::isError($dsn)) {
119  return PEAR::raiseError($dsn->getMessage(), $dsn->getCode());
120  } else {
121  return PEAR::raiseError('The given dsn was not valid in file ' . __FILE__ . ' at line ' . __LINE__,
122  41,
124  null,
125  null
126  );
127  }
128 
129  if (DB::isError($this->db) || PEAR::isError($this->db)) {
130  return PEAR::raiseError($this->db->getMessage(), $this->db->getCode());
131  } else {
132  return true;
133  }
134  }
135 
136  // }}}
137  // {{{ _prepare()
138 
148  function _prepare()
149  {
150  if (!DB::isConnection($this->db)) {
151  $res = $this->_connect($this->options['dsn']);
152  if (DB::isError($res) || PEAR::isError($res)) {
153  return $res;
154  }
155  }
156  if ($this->options['auto_quote'] && $this->db->dsn['phptype'] != 'sqlite') {
157  if (strpos('.', $this->options['table']) === false) {
158  $this->options['final_table'] = $this->db->quoteIdentifier($this->options['table']);
159  } else {
160  $t = explode('.', $this->options['table']);
161  for ($i = 0, $count = count($t); $i < $count; $i++)
162  $t[$i] = $this->db->quoteIdentifier($t[$i]);
163  $this->options['final_table'] = implode('.', $t);
164  }
165  $this->options['final_usernamecol'] = $this->db->quoteIdentifier($this->options['usernamecol']);
166  $this->options['final_passwordcol'] = $this->db->quoteIdentifier($this->options['passwordcol']);
167  } else {
168  $this->options['final_table'] = $this->options['table'];
169  $this->options['final_usernamecol'] = $this->options['usernamecol'];
170  $this->options['final_passwordcol'] = $this->options['passwordcol'];
171  }
172  return true;
173  }
174 
175  // }}}
176  // {{{ query()
177 
190  function query($query)
191  {
192  $err = $this->_prepare();
193  if ($err !== true) {
194  return $err;
195  }
196  return $this->db->query($query);
197  }
198 
199  // }}}
200  // {{{ _setDefaults()
201 
208  function _setDefaults()
209  {
210  $this->options['table'] = 'auth';
211  $this->options['usernamecol'] = 'username';
212  $this->options['passwordcol'] = 'password';
213  $this->options['dsn'] = '';
214  $this->options['db_fields'] = '';
215  $this->options['cryptType'] = 'md5';
216  $this->options['db_options'] = array();
217  $this->options['db_where'] = '';
218  $this->options['auto_quote'] = true;
219  }
220 
221  // }}}
222  // {{{ _parseOptions()
223 
230  function _parseOptions($array)
231  {
232  foreach ($array as $key => $value) {
233  if (isset($this->options[$key])) {
234  $this->options[$key] = $value;
235  }
236  }
237  }
238 
239  // }}}
240  // {{{ _quoteDBFields()
241 
249  function _quoteDBFields()
250  {
251  if (isset($this->options['db_fields'])) {
252  if (is_array($this->options['db_fields'])) {
253  if ($this->options['auto_quote']) {
254  $fields = array();
255  foreach ($this->options['db_fields'] as $field) {
256  $fields[] = $this->db->quoteIdentifier($field);
257  }
258  return implode(', ', $fields);
259  } else {
260  return implode(', ', $this->options['db_fields']);
261  }
262  } else {
263  if (strlen($this->options['db_fields']) > 0) {
264  if ($this->options['auto_quote']) {
265  return $this->db->quoteIdentifier($this->options['db_fields']);
266  } else {
267  return $this->options['db_fields'];
268  }
269  }
270  }
271  }
272 
273  return '';
274  }
275 
276  // }}}
277  // {{{ fetchData()
278 
295  function fetchData($username, $password, $isChallengeResponse=false)
296  {
297  $this->log('Auth_Container_DB::fetchData() called.', AUTH_LOG_DEBUG);
298  // Prepare for a database query
299  $err = $this->_prepare();
300  if ($err !== true) {
301  return PEAR::raiseError($err->getMessage(), $err->getCode());
302  }
303 
304  // Find if db_fields contains a *, if so assume all columns are selected
305  if (is_string($this->options['db_fields'])
306  && strstr($this->options['db_fields'], '*')) {
307  $sql_from = "*";
308  } else {
309  $sql_from = $this->options['final_usernamecol'].
310  ", ".$this->options['final_passwordcol'];
311 
312  if (strlen($fields = $this->_quoteDBFields()) > 0) {
313  $sql_from .= ', '.$fields;
314  }
315  }
316 
317  $query = "SELECT ".$sql_from.
318  " FROM ".$this->options['final_table'].
319  " WHERE ".$this->options['final_usernamecol']." = ".$this->db->quoteSmart($username);
320 
321  // check if there is an optional parameter db_where
322  if ($this->options['db_where'] != '') {
323  // there is one, so add it to the query
324  $query .= " AND ".$this->options['db_where'];
325  }
326 
327  $this->log('Running SQL against DB: '.$query, AUTH_LOG_DEBUG);
328 
329  $res = $this->db->getRow($query, null, DB_FETCHMODE_ASSOC);
330 
331  if (DB::isError($res)) {
332  return PEAR::raiseError($res->getMessage(), $res->getCode());
333  }
334 
335  if (!is_array($res)) {
336  $this->activeUser = '';
337  return false;
338  }
339 
340  // Perform trimming here before the hashihg
341  $password = trim($password, "\r\n");
342  $res[$this->options['passwordcol']] = trim($res[$this->options['passwordcol']], "\r\n");
343 
344  // If using Challenge Response md5 the pass with the secret
345  if ($isChallengeResponse) {
346  $res[$this->options['passwordcol']] = md5($res[$this->options['passwordcol']]
347  .$this->_auth_obj->session['loginchallenege']);
348 
349  // UGLY cannot avoid without modifying verifyPassword
350  if ($this->options['cryptType'] == 'md5') {
351  $res[$this->options['passwordcol']] = md5($res[$this->options['passwordcol']]);
352  }
353 
354  //print " Hashed Password [{$res[$this->options['passwordcol']]}]<br/>\n";
355  }
356 
357  if ($this->verifyPassword($password,
358  $res[$this->options['passwordcol']],
359  $this->options['cryptType'])) {
360  // Store additional field values in the session
361  foreach ($res as $key => $value) {
362  if ($key == $this->options['passwordcol'] ||
363  $key == $this->options['usernamecol']) {
364  continue;
365  }
366 
367  $this->log('Storing additional field: '.$key, AUTH_LOG_DEBUG);
368 
369  // Use reference to the auth object if exists
370  // This is because the auth session variable can change so a
371  // static call to setAuthData does not make sence
372  $this->_auth_obj->setAuthData($key, $value);
373  }
374  return true;
375  }
376  $this->activeUser = $res[$this->options['usernamecol']];
377  return false;
378  }
379 
380  // }}}
381  // {{{ listUsers()
382 
389  function listUsers()
390  {
391  $this->log('Auth_Container_DB::listUsers() called.', AUTH_LOG_DEBUG);
392  $err = $this->_prepare();
393  if ($err !== true) {
394  return PEAR::raiseError($err->getMessage(), $err->getCode());
395  }
396 
397  $retVal = array();
398 
399  // Find if db_fields contains a *, if so assume all col are selected
400  if ( is_string($this->options['db_fields'])
401  && strstr($this->options['db_fields'], '*')) {
402  $sql_from = "*";
403  } else {
404  $sql_from = $this->options['final_usernamecol'].
405  ", ".$this->options['final_passwordcol'];
406 
407  if (strlen($fields = $this->_quoteDBFields()) > 0) {
408  $sql_from .= ', '.$fields;
409  }
410  }
411 
412  $query = sprintf("SELECT %s FROM %s",
413  $sql_from,
414  $this->options['final_table']
415  );
416 
417  // check if there is an optional parameter db_where
418  if ($this->options['db_where'] != '') {
419  // there is one, so add it to the query
420  $query .= " WHERE ".$this->options['db_where'];
421  }
422 
423  $this->log('Running SQL against DB: '.$query, AUTH_LOG_DEBUG);
424 
425  $res = $this->db->getAll($query, null, DB_FETCHMODE_ASSOC);
426 
427  if (DB::isError($res)) {
428  return PEAR::raiseError($res->getMessage(), $res->getCode());
429  } else {
430  foreach ($res as $user) {
431  $user['username'] = $user[$this->options['usernamecol']];
432  $retVal[] = $user;
433  }
434  }
435  $this->log('Found '.count($retVal).' users.', AUTH_LOG_DEBUG);
436  return $retVal;
437  }
438 
439  // }}}
440  // {{{ addUser()
441 
452  function addUser($username, $password, $additional = "")
453  {
454  $this->log('Auth_Container_DB::addUser() called.', AUTH_LOG_DEBUG);
455  $err = $this->_prepare();
456  if ($err !== true) {
457  return PEAR::raiseError($err->getMessage(), $err->getCode());
458  }
459 
460  if ( isset($this->options['cryptType'])
461  && $this->options['cryptType'] == 'none') {
462  $cryptFunction = 'strval';
463  } elseif ( isset($this->options['cryptType'])
464  && function_exists($this->options['cryptType'])) {
465  $cryptFunction = $this->options['cryptType'];
466  } else {
467  $cryptFunction = 'md5';
468  }
469 
470  $password = $cryptFunction($password);
471 
472  $additional_key = '';
473  $additional_value = '';
474 
475  if (is_array($additional)) {
476  foreach ($additional as $key => $value) {
477  if ($this->options['auto_quote']) {
478  $additional_key .= ', ' . $this->db->quoteIdentifier($key);
479  } else {
480  $additional_key .= ', ' . $key;
481  }
482  $additional_value .= ", " . $this->db->quoteSmart($value);
483  }
484  }
485 
486  $query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)",
487  $this->options['final_table'],
488  $this->options['final_usernamecol'],
489  $this->options['final_passwordcol'],
490  $additional_key,
491  $this->db->quoteSmart($username),
492  $this->db->quoteSmart($password),
493  $additional_value
494  );
495 
496  $this->log('Running SQL against DB: '.$query, AUTH_LOG_DEBUG);
497 
498  $res = $this->query($query);
499 
500  if (DB::isError($res)) {
501  return PEAR::raiseError($res->getMessage(), $res->getCode());
502  } else {
503  return true;
504  }
505  }
506 
507  // }}}
508  // {{{ removeUser()
509 
518  function removeUser($username)
519  {
520  $this->log('Auth_Container_DB::removeUser() called.', AUTH_LOG_DEBUG);
521 
522  $err = $this->_prepare();
523  if ($err !== true) {
524  return PEAR::raiseError($err->getMessage(), $err->getCode());
525  }
526 
527  // check if there is an optional parameter db_where
528  if ($this->options['db_where'] != '') {
529  // there is one, so add it to the query
530  $where = " AND ".$this->options['db_where'];
531  } else {
532  $where = '';
533  }
534 
535  $query = sprintf("DELETE FROM %s WHERE %s = %s %s",
536  $this->options['final_table'],
537  $this->options['final_usernamecol'],
538  $this->db->quoteSmart($username),
539  $where
540  );
541 
542  $this->log('Running SQL against DB: '.$query, AUTH_LOG_DEBUG);
543 
544  $res = $this->query($query);
545 
546  if (DB::isError($res)) {
547  return PEAR::raiseError($res->getMessage(), $res->getCode());
548  } else {
549  return true;
550  }
551  }
552 
553  // }}}
554  // {{{ changePassword()
555 
562  function changePassword($username, $password)
563  {
564  $this->log('Auth_Container_DB::changePassword() called.', AUTH_LOG_DEBUG);
565  $err = $this->_prepare();
566  if ($err !== true) {
567  return PEAR::raiseError($err->getMessage(), $err->getCode());
568  }
569 
570  if ( isset($this->options['cryptType'])
571  && $this->options['cryptType'] == 'none') {
572  $cryptFunction = 'strval';
573  } elseif ( isset($this->options['cryptType'])
574  && function_exists($this->options['cryptType'])) {
575  $cryptFunction = $this->options['cryptType'];
576  } else {
577  $cryptFunction = 'md5';
578  }
579 
580  $password = $cryptFunction($password);
581 
582  // check if there is an optional parameter db_where
583  if ($this->options['db_where'] != '') {
584  // there is one, so add it to the query
585  $where = " AND ".$this->options['db_where'];
586  } else {
587  $where = '';
588  }
589 
590  $query = sprintf("UPDATE %s SET %s = %s WHERE %s = %s %s",
591  $this->options['final_table'],
592  $this->options['final_passwordcol'],
593  $this->db->quoteSmart($password),
594  $this->options['final_usernamecol'],
595  $this->db->quoteSmart($username),
596  $where
597  );
598 
599  $this->log('Running SQL against DB: '.$query, AUTH_LOG_DEBUG);
600 
601  $res = $this->query($query);
602 
603  if (DB::isError($res)) {
604  return PEAR::raiseError($res->getMessage(), $res->getCode());
605  } else {
606  return true;
607  }
608  }
609 
610  // }}}
611  // {{{ supportsChallengeResponse()
612 
621  {
622  return in_array($this->options['cryptType'], array('md5', 'none', ''));
623  }
624 
625  // }}}
626  // {{{ getCryptType()
627 
631  function getCryptType()
632  {
633  return($this->options['cryptType']);
634  }
635 
636  // }}}
637 
638 }
639 ?>