325 lines
8.7 KiB
PHP
325 lines
8.7 KiB
PHP
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
|
|
/**
|
|
* This class takes care of searching within LDAP
|
|
*
|
|
* @package Kohana/Database
|
|
* @category Query
|
|
* @author Deon George
|
|
* @copyright (c) 2013 phpLDAPadmin Development Team
|
|
* @license http://dev.phpldapadmin.org/license.html
|
|
*/
|
|
abstract class Kohana_Database_LDAP_Search {
|
|
private $_db; // Our LDAP Server to query
|
|
|
|
private $_attrs = array('*','+'); // LDAP Attributes to Return
|
|
private $_base = array(); // LDAP Search Base
|
|
private $_deref = LDAP_DEREF_NEVER; // LDAP Search Default DEREF
|
|
private $_filter = '(objectclass=*)'; // LDAP Search Filter
|
|
private $_size_limit = '500'; // LDAP Search Size Limit
|
|
private $_scope = 'base'; // LDAP Search Scope
|
|
private $_time_limit = '60'; // LDAP Search Time Limit
|
|
private $_db_pending = array(); // LDAP Query Filter to compile
|
|
|
|
// Execute the query during a cache hit
|
|
protected $_force_execute = FALSE;
|
|
|
|
// Cache lifetime
|
|
protected $_lifetime = NULL;
|
|
|
|
// Parameters for __construct when using object results
|
|
protected $_object_params = array();
|
|
|
|
// Return results as associative arrays or objects
|
|
protected $_as_object = FALSE;
|
|
|
|
/**
|
|
* Callable database methods
|
|
* @var array
|
|
*/
|
|
protected static $_db_methods = array(
|
|
'where', 'and_where', 'or_where', 'where_open', 'and_where_open', 'or_where_open', 'where_close',
|
|
'and_where_close', 'or_where_close',
|
|
'limit','scope',
|
|
);
|
|
|
|
/**
|
|
* ORM methods that are called, but dont do anything in LDAP
|
|
*/
|
|
protected static $_orm_ignore_methods = array(
|
|
'from',
|
|
);
|
|
|
|
/**
|
|
* Members that have access methods
|
|
* @var array
|
|
*/
|
|
protected static $_properties = array(
|
|
);
|
|
|
|
public function __construct(Database_LDAP $db,$base=array()) {
|
|
$this->_db = $db;
|
|
|
|
$this->_base = is_null($base) ? $this->base() : $base;
|
|
}
|
|
|
|
/**
|
|
* Handles pass-through to database methods. Calls to query methods
|
|
* (query, get, insert, update) are not allowed. Query builder methods
|
|
* are chainable.
|
|
*
|
|
* @param string $method Method name
|
|
* @param array $args Method arguments
|
|
* @return mixed
|
|
*/
|
|
public function __call($method,array $args) {
|
|
if (in_array($method,Database_LDAP_Search::$_properties)) {
|
|
/*
|
|
// @todo To Implement
|
|
if ($method === 'validation')
|
|
{
|
|
if ( ! isset($this->_validation))
|
|
{
|
|
// Initialize the validation object
|
|
$this->_validation();
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Return the property
|
|
return $this->{'_'.$method};
|
|
|
|
} elseif (in_array($method,Database_LDAP_Search::$_db_methods)) {
|
|
// Add pending database call which is executed after query type is determined
|
|
$this->_db_pending[] = array('name' => $method,'args' => $args);
|
|
|
|
return $this;
|
|
|
|
} elseif (in_array($method,Database_LDAP_Search::$_orm_ignore_methods)) {
|
|
return $this;
|
|
|
|
} else {
|
|
throw new Kohana_Exception('Invalid method :method called in :class (:args)',
|
|
array(':method' => $method,':class' => get_class($this),':args'=>print_r($args,TRUE)));
|
|
}
|
|
}
|
|
|
|
private function _build() {
|
|
$search = new Database_LDAP_Search_Builder_Query();
|
|
|
|
// Process pending database method calls
|
|
foreach ($this->_db_pending as $method) {
|
|
$name = $method['name'];
|
|
$args = $method['args'];
|
|
|
|
$this->_db_applied[$name] = $name;
|
|
|
|
switch ($name) {
|
|
case 'limit':
|
|
$this->_size_limit = $args[0];
|
|
break;
|
|
|
|
default:
|
|
call_user_func_array(array($search,$name),$args);
|
|
}
|
|
}
|
|
|
|
return $search;
|
|
}
|
|
|
|
public function as_assoc() {
|
|
$this->_as_object = FALSE;
|
|
|
|
$this->_object_params = array();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns results as objects
|
|
*
|
|
* @param string $class classname or TRUE for stdClass
|
|
* @param array $params
|
|
* @return $this
|
|
*/
|
|
public function as_object($class = TRUE, array $params = NULL) {
|
|
$this->_as_object = $class;
|
|
|
|
// Add object parameters
|
|
if ($params)
|
|
$this->_object_params = $params;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Figure out the bases
|
|
*/
|
|
public function base(array $base=NULL) {
|
|
if (! is_null($base))
|
|
$this->_base = $base;
|
|
|
|
if ($this->_base)
|
|
return $this->_base;
|
|
|
|
// If the base is set in the configuration file, then just return that.
|
|
if (! is_null($x=Kohana::$config->load('database.default.connection.database')))
|
|
return $x;
|
|
|
|
$x = LDAP::factory('auth');
|
|
|
|
$u = $x->search(array(''))
|
|
->scope('base')
|
|
->execute();
|
|
|
|
// Quick validation
|
|
if ($u['']->count() > 1)
|
|
throw HTTP_Exception::factory(501,'We got more than 1 null DN?');
|
|
|
|
return isset($u['']['']['namingcontexts']) ? $u['']['']['namingcontexts'] : array();
|
|
}
|
|
|
|
/**
|
|
* Enables the query to be cached for a specified amount of time.
|
|
*
|
|
* @param integer $lifetime number of seconds to cache, 0 deletes it from the cache
|
|
* @param boolean whether or not to execute the query during a cache hit
|
|
* @return $this
|
|
* @uses Kohana::$cache_life
|
|
*/
|
|
public function cached($lifetime=NULL,$force=FALSE) {
|
|
// Use the global setting
|
|
if ($lifetime === NULL)
|
|
$lifetime = Kohana::$cache_life;
|
|
|
|
// Global is caching enabled.
|
|
if (! Kohana::$caching)
|
|
$lifetime = NULL;
|
|
|
|
$this->_force_execute = $force;
|
|
$this->_lifetime = $lifetime;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function deref($val) {
|
|
$this->_deref = $val;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Search the LDAP database
|
|
*/
|
|
public function execute($db=NULL,$as_object=NULL,$object_params=NULL) {
|
|
$query = array();
|
|
|
|
if (! is_object($this->_db))
|
|
throw new Kohana_Exception('db must be an object');
|
|
|
|
// We'll override the DB if we have been given one
|
|
if (is_object($db))
|
|
$this->_db = $db;
|
|
|
|
if ($as_object === NULL)
|
|
$as_object = $this->_as_object;
|
|
|
|
if ($object_params === NULL)
|
|
$object_params = $this->_object_params;
|
|
|
|
// Query Defaults
|
|
$attrs_only = 0;
|
|
|
|
// Compile our query
|
|
if ($this->_db_pending)
|
|
$this->_filter = $this->_build();
|
|
|
|
// Validation that we are connected, no point contining if we are not.
|
|
$this->_db->connect();
|
|
|
|
if (! $this->_db->connection())
|
|
throw HTTP_Exception::factory(501,'Cant run a search without a connection (:type,:filter)',array(':type'=>$this->_db,':filter'=>$this->_filter));
|
|
|
|
$result = new Database_LDAP_Search_Result;
|
|
|
|
foreach ($this->_base as $base) {
|
|
if (($this->_lifetime !== NULL AND $this->_db->caching()) OR (Kohana::$caching AND $this->_db->caching() AND $this->cached())) {
|
|
// Set the cache key based on the database instance name and SQL
|
|
$cache_key = 'Database::query("'.$this->_db.'","'.$base.'","'.$this->_scope.'","'.$this->_filter.'")';
|
|
|
|
// Read the cache first to delete a possible hit with lifetime <= 0
|
|
if (($search = Kohana::cache($cache_key, NULL, $this->_lifetime)) !== NULL AND ! $this->_force_execute) {
|
|
// Return a cached result
|
|
$result[$base] = new Database_LDAP_Result_Cached($search, array('b'=>$base,'s'=>$this->_scope,'f'=>$this->_filter), $as_object);
|
|
$result[$base]->cache_key($cache_key);
|
|
}
|
|
}
|
|
|
|
if (Kohana::$profiling)
|
|
$benchmark = Profiler::start("Database LDAP ({$this->_db})",$this->_scope.':'.$base.':'.$this->_filter);
|
|
|
|
// Search is not cached, OR caching is disabled, so we'll query
|
|
if (! isset($result[$base])) {
|
|
try {
|
|
switch ($this->_scope) {
|
|
case 'base':
|
|
$search = ldap_read($this->_db->connection(),$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
|
|
break;
|
|
|
|
case 'one':
|
|
$search = ldap_list($this->_db->connection(),$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
|
|
break;
|
|
|
|
case 'sub':
|
|
default:
|
|
$search = ldap_search($this->_db->connection(),$base,$this->_filter,$this->_attrs,$attrs_only,$this->_size_limit,$this->_time_limit,$this->_deref);
|
|
break;
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
throw HTTP_Exception::factory(501,'Error running a query (SCOPE::scope,BASE::base,TYPE::type,FILTER::filter,ATTRS::attrs) [:error]',
|
|
array(':base'=>$base,':scope'=>$this->_scope,':type'=>$this->_db,':filter'=>$this->_filter,':attrs'=>join('|',$this->_attrs),':error'=>$e->getMessage()));
|
|
}
|
|
|
|
$result[$base] = new Database_LDAP_Result(array('l'=>$this->_db->connection(),'r'=>$search),array('b'=>$base,'s'=>$this->_scope,'f'=>$this->_filter),$as_object,$object_params);
|
|
|
|
// Cache the result array
|
|
if (isset($cache_key) AND $this->_lifetime > 0)
|
|
Kohana::cache($cache_key,$result[$base]->as_array(),$this->_lifetime);
|
|
}
|
|
|
|
if (isset($benchmark))
|
|
Profiler::stop($benchmark);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function size_limit($val) {
|
|
$this->_size_limit = $val;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function scope($val) {
|
|
switch ($val) {
|
|
case 'base':
|
|
case 'sub':
|
|
case 'one': $this->_scope = $val;
|
|
break;
|
|
|
|
default:
|
|
throw new Kohana_Exception('Unknown search scope :scope',array(':scope',$val));
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function time_limit($val) {
|
|
$this->_time_limit = $val;
|
|
|
|
return $this;
|
|
}
|
|
}
|
|
?>
|