ILIAS  Release_4_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
MDB.php
Go to the documentation of this file.
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
3 
29 require_once 'Auth/Container.php';
33 require_once 'MDB.php';
34 
52 {
53 
54  // {{{ properties
55 
60  var $options = array();
61 
66  var $db = null;
67  var $dsn = '';
68 
73  var $activeUser = '';
74 
75  // }}}
76  // {{{ Auth_Container_MDB() [constructor]
77 
87  {
88  $this->_setDefaults();
89 
90  if (is_array($dsn)) {
91  $this->_parseOptions($dsn);
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_MDB::_connect() called.', AUTH_LOG_DEBUG);
113  if (is_string($dsn) || is_array($dsn)) {
114  $this->db =& MDB::connect($dsn, $this->options['db_options']);
115  } elseif (is_subclass_of($dsn, 'mdb_common')) {
116  $this->db = $dsn;
117  } elseif (is_object($dsn) && MDB::isError($dsn)) {
118  return PEAR::raiseError($dsn->getMessage(), $dsn->code);
119  } else {
120  return PEAR::raiseError('The given dsn was not valid in file ' . __FILE__ . ' at line ' . __LINE__,
121  41,
123  null,
124  null
125  );
126 
127  }
128 
129  if (MDB::isError($this->db) || PEAR::isError($this->db)) {
130  return PEAR::raiseError($this->db->getMessage(), $this->db->code);
131  }
132 
133  if ($this->options['auto_quote']) {
134  if (strpos('.', $this->options['table']) === false) {
135  $this->options['final_table'] = $this->db->quoteIdentifier($this->options['table']);
136  } else {
137  $t = explode('.', $this->options['table']);
138  for ($i = 0, $count = count($t); $i < $count; $i++)
139  $t[$i] = $this->db->quoteIdentifier($t[$i]);
140  $this->options['final_table'] = implode('.', $t);
141  }
142  $this->options['final_usernamecol'] = $this->db->quoteIdentifier($this->options['usernamecol']);
143  $this->options['final_passwordcol'] = $this->db->quoteIdentifier($this->options['passwordcol']);
144  } else {
145  $this->options['final_table'] = $this->options['table'];
146  $this->options['final_usernamecol'] = $this->options['usernamecol'];
147  $this->options['final_passwordcol'] = $this->options['passwordcol'];
148  }
149 
150  return true;
151  }
152 
153  // }}}
154  // {{{ _prepare()
155 
165  function _prepare()
166  {
167  if (is_subclass_of($this->db, 'mdb_common')) {
168  return true;
169  }
170  return $this->_connect($this->options['dsn']);
171  }
172 
173  // }}}
174  // {{{ query()
175 
188  function query($query)
189  {
190  $this->log('Auth_Container_MDB::query() called.', AUTH_LOG_DEBUG);
191  $err = $this->_prepare();
192  if ($err !== true) {
193  return $err;
194  }
195  return $this->db->query($query);
196  }
197 
198  // }}}
199  // {{{ _setDefaults()
200 
207  function _setDefaults()
208  {
209  $this->options['table'] = 'auth';
210  $this->options['usernamecol'] = 'username';
211  $this->options['passwordcol'] = 'password';
212  $this->options['dsn'] = '';
213  $this->options['db_fields'] = '';
214  $this->options['cryptType'] = 'md5';
215  $this->options['db_options'] = array();
216  $this->options['db_where'] = '';
217  $this->options['auto_quote'] = true;
218  }
219 
220  // }}}
221  // {{{ _parseOptions()
222 
229  function _parseOptions($array)
230  {
231  foreach ($array as $key => $value) {
232  if (isset($this->options[$key])) {
233  $this->options[$key] = $value;
234  }
235  }
236  }
237 
238  // }}}
239  // {{{ _quoteDBFields()
240 
248  function _quoteDBFields()
249  {
250  if (isset($this->options['db_fields'])) {
251  if (is_array($this->options['db_fields'])) {
252  if ($this->options['auto_quote']) {
253  $fields = array();
254  foreach ($this->options['db_fields'] as $field) {
255  $fields[] = $this->db->quoteIdentifier($field);
256  }
257  return implode(', ', $fields);
258  } else {
259  return implode(', ', $this->options['db_fields']);
260  }
261  } else {
262  if (strlen($this->options['db_fields']) > 0) {
263  if ($this->options['auto_quote']) {
264  return $this->db->quoteIdentifier($this->options['db_fields']);
265  } else {
266  return $this->options['db_fields'];
267  }
268  }
269  }
270  }
271 
272  return '';
273  }
274 
275  // }}}
276  // {{{ fetchData()
277 
294  function fetchData($username, $password, $isChallengeResponse=false)
295  {
296  $this->log('Auth_Container_MDB::fetchData() called.', AUTH_LOG_DEBUG);
297  // Prepare for a database query
298  $err = $this->_prepare();
299  if ($err !== true) {
300  return PEAR::raiseError($err->getMessage(), $err->getCode());
301  }
302 
303  //Check if db_fields contains a *, if so assume all columns are selected
304  if (is_string($this->options['db_fields'])
305  && strstr($this->options['db_fields'], '*')) {
306  $sql_from = '*';
307  } else {
308  $sql_from = $this->options['final_usernamecol'].
309  ", ".$this->options['final_passwordcol'];
310 
311  if (strlen($fields = $this->_quoteDBFields()) > 0) {
312  $sql_from .= ', '.$fields;
313  }
314  }
315 
316  $query = sprintf("SELECT %s FROM %s WHERE %s = %s",
317  $sql_from,
318  $this->options['final_table'],
319  $this->options['final_usernamecol'],
320  $this->db->getTextValue($username)
321  );
322 
323  // check if there is an optional parameter db_where
324  if ($this->options['db_where'] != '') {
325  // there is one, so add it to the query
326  $query .= " AND ".$this->options['db_where'];
327  }
328 
329  $this->log('Running SQL against MDB: '.$query, AUTH_LOG_DEBUG);
330 
331  $res = $this->db->getRow($query, null, null, null, MDB_FETCHMODE_ASSOC);
332 
333  if (MDB::isError($res) || PEAR::isError($res)) {
334  return PEAR::raiseError($res->getMessage(), $res->getCode());
335  }
336  if (!is_array($res)) {
337  $this->activeUser = '';
338  return false;
339  }
340 
341  // Perform trimming here before the hashing
342  $password = trim($password, "\r\n");
343  $res[$this->options['passwordcol']] = trim($res[$this->options['passwordcol']], "\r\n");
344 
345  // If using Challenge Response md5 the pass with the secret
346  if ($isChallengeResponse) {
347  $res[$this->options['passwordcol']] =
348  md5($res[$this->options['passwordcol']].$this->_auth_obj->session['loginchallenege']);
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 
355  if ($this->verifyPassword($password,
356  $res[$this->options['passwordcol']],
357  $this->options['cryptType'])) {
358  // Store additional field values in the session
359  foreach ($res as $key => $value) {
360  if ($key == $this->options['passwordcol'] ||
361  $key == $this->options['usernamecol']) {
362  continue;
363  }
364 
365  $this->log('Storing additional field: '.$key, AUTH_LOG_DEBUG);
366  // Use reference to the auth object if exists
367  // This is because the auth session variable can change so a static
368  // call to setAuthData does not make sense
369  $this->_auth_obj->setAuthData($key, $value);
370  }
371  return true;
372  }
373 
374  $this->activeUser = $res[$this->options['usernamecol']];
375  return false;
376  }
377 
378  // }}}
379  // {{{ listUsers()
380 
387  function listUsers()
388  {
389  $this->log('Auth_Container_MDB::listUsers() called.', AUTH_LOG_DEBUG);
390  $err = $this->_prepare();
391  if ($err !== true) {
392  return PEAR::raiseError($err->getMessage(), $err->getCode());
393  }
394 
395  $retVal = array();
396 
397  //Check if db_fields contains a *, if so assume all columns are selected
398  if ( is_string($this->options['db_fields'])
399  && strstr($this->options['db_fields'], '*')) {
400  $sql_from = '*';
401  } else {
402  $sql_from = $this->options['final_usernamecol']
403  .', '.$this->options['final_passwordcol'];
404 
405  if (strlen($fields = $this->_quoteDBFields()) > 0) {
406  $sql_from .= ', '.$fields;
407  }
408  }
409 
410  $query = sprintf('SELECT %s FROM %s',
411  $sql_from,
412  $this->options['final_table']
413  );
414 
415  // check if there is an optional parameter db_where
416  if ($this->options['db_where'] != '') {
417  // there is one, so add it to the query
418  $query .= " WHERE ".$this->options['db_where'];
419  }
420 
421  $this->log('Running SQL against MDB: '.$query, AUTH_LOG_DEBUG);
422 
423  $res = $this->db->getAll($query, null, null, null, MDB_FETCHMODE_ASSOC);
424 
425  if (MDB::isError($res)) {
426  return PEAR::raiseError($res->getMessage(), $res->getCode());
427  } else {
428  foreach ($res as $user) {
429  $user['username'] = $user[$this->options['usernamecol']];
430  $retVal[] = $user;
431  }
432  }
433  $this->log('Found '.count($retVal).' users.', AUTH_LOG_DEBUG);
434  return $retVal;
435  }
436 
437  // }}}
438  // {{{ addUser()
439 
450  function addUser($username, $password, $additional = "")
451  {
452  $this->log('Auth_Container_MDB::addUser() called.', AUTH_LOG_DEBUG);
453  $err = $this->_prepare();
454  if ($err !== true) {
455  return PEAR::raiseError($err->getMessage(), $err->getCode());
456  }
457 
458  if (isset($this->options['cryptType']) && $this->options['cryptType'] == 'none') {
459  $cryptFunction = 'strval';
460  } elseif (isset($this->options['cryptType']) && function_exists($this->options['cryptType'])) {
461  $cryptFunction = $this->options['cryptType'];
462  } else {
463  $cryptFunction = 'md5';
464  }
465 
466  $password = $cryptFunction($password);
467 
468  $additional_key = '';
469  $additional_value = '';
470 
471  if (is_array($additional)) {
472  foreach ($additional as $key => $value) {
473  if ($this->options['auto_quote']) {
474  $additional_key .= ', ' . $this->db->quoteIdentifier($key);
475  } else {
476  $additional_key .= ', ' . $key;
477  }
478  $additional_value .= ', ' . $this->db->getTextValue($value);
479  }
480  }
481 
482  $query = sprintf("INSERT INTO %s (%s, %s%s) VALUES (%s, %s%s)",
483  $this->options['final_table'],
484  $this->options['final_usernamecol'],
485  $this->options['final_passwordcol'],
486  $additional_key,
487  $this->db->getTextValue($username),
488  $this->db->getTextValue($password),
489  $additional_value
490  );
491 
492  $this->log('Running SQL against MDB: '.$query, AUTH_LOG_DEBUG);
493 
494  $res = $this->query($query);
495 
496  if (MDB::isError($res)) {
497  return PEAR::raiseError($res->getMessage(), $res->code);
498  }
499  return true;
500  }
501 
502  // }}}
503  // {{{ removeUser()
504 
513  function removeUser($username)
514  {
515  $this->log('Auth_Container_MDB::removeUser() called.', AUTH_LOG_DEBUG);
516  $err = $this->_prepare();
517  if ($err !== true) {
518  return PEAR::raiseError($err->getMessage(), $err->getCode());
519  }
520 
521  $query = sprintf("DELETE FROM %s WHERE %s = %s",
522  $this->options['final_table'],
523  $this->options['final_usernamecol'],
524  $this->db->getTextValue($username)
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  $query .= " AND ".$this->options['db_where'];
531  }
532 
533  $this->log('Running SQL against MDB: '.$query, AUTH_LOG_DEBUG);
534 
535  $res = $this->query($query);
536 
537  if (MDB::isError($res)) {
538  return PEAR::raiseError($res->getMessage(), $res->code);
539  }
540  return true;
541  }
542 
543  // }}}
544  // {{{ changePassword()
545 
552  function changePassword($username, $password)
553  {
554  $this->log('Auth_Container_MDB::changePassword() called.', AUTH_LOG_DEBUG);
555  $err = $this->_prepare();
556  if ($err !== true) {
557  return PEAR::raiseError($err->getMessage(), $err->getCode());
558  }
559 
560  if (isset($this->options['cryptType']) && $this->options['cryptType'] == 'none') {
561  $cryptFunction = 'strval';
562  } elseif (isset($this->options['cryptType']) && function_exists($this->options['cryptType'])) {
563  $cryptFunction = $this->options['cryptType'];
564  } else {
565  $cryptFunction = 'md5';
566  }
567 
568  $password = $cryptFunction($password);
569 
570  $query = sprintf("UPDATE %s SET %s = %s WHERE %s = %s",
571  $this->options['final_table'],
572  $this->options['final_passwordcol'],
573  $this->db->getTextValue($password),
574  $this->options['final_usernamecol'],
575  $this->db->getTextValue($username)
576  );
577 
578  // check if there is an optional parameter db_where
579  if ($this->options['db_where'] != '') {
580  // there is one, so add it to the query
581  $query .= " AND ".$this->options['db_where'];
582  }
583 
584  $this->log('Running SQL against MDB: '.$query, AUTH_LOG_DEBUG);
585 
586  $res = $this->query($query);
587 
588  if (MDB::isError($res)) {
589  return PEAR::raiseError($res->getMessage(), $res->code);
590  }
591  return true;
592  }
593 
594  // }}}
595  // {{{ supportsChallengeResponse()
596 
605  {
606  return in_array($this->options['cryptType'], array('md5', 'none', ''));
607  }
608 
609  // }}}
610  // {{{ getCryptType()
611 
617  function getCryptType()
618  {
619  return $this->options['cryptType'];
620  }
621 
622  // }}}
623 
624 }
625 ?>