[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/symfony/ldap/Adapter/ExtLdap/ -> Query.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <[email protected]>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\Ldap\Adapter\ExtLdap;
  13  
  14  use LDAP\Connection as LDAPConnection;
  15  use LDAP\Result;
  16  use Symfony\Component\Ldap\Adapter\AbstractQuery;
  17  use Symfony\Component\Ldap\Exception\LdapException;
  18  use Symfony\Component\Ldap\Exception\NotBoundException;
  19  
  20  /**
  21   * @author Charles Sarrazin <[email protected]>
  22   * @author Bob van de Vijver <[email protected]>
  23   */
  24  class Query extends AbstractQuery
  25  {
  26      // As of PHP 7.2, we can use LDAP_CONTROL_PAGEDRESULTS instead of this
  27      public const PAGINATION_OID = '1.2.840.113556.1.4.319';
  28  
  29      /** @var Connection */
  30      protected $connection;
  31  
  32      /** @var resource[]|Result[] */
  33      private $results;
  34  
  35      /** @var array */
  36      private $serverctrls = [];
  37  
  38      public function __construct(Connection $connection, string $dn, string $query, array $options = [])
  39      {
  40          parent::__construct($connection, $dn, $query, $options);
  41      }
  42  
  43      /**
  44       * @return array
  45       */
  46      public function __sleep()
  47      {
  48          throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  49      }
  50  
  51      public function __wakeup()
  52      {
  53          throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  54      }
  55  
  56      public function __destruct()
  57      {
  58          $con = $this->connection->getResource();
  59          $this->connection = null;
  60  
  61          if (null === $this->results) {
  62              return;
  63          }
  64  
  65          foreach ($this->results as $result) {
  66              if (false === $result || null === $result) {
  67                  continue;
  68              }
  69              if (!ldap_free_result($result)) {
  70                  throw new LdapException('Could not free results: '.ldap_error($con));
  71              }
  72          }
  73          $this->results = null;
  74      }
  75  
  76      /**
  77       * {@inheritdoc}
  78       */
  79      public function execute()
  80      {
  81          if (null === $this->results) {
  82              // If the connection is not bound, throw an exception. Users should use an explicit bind call first.
  83              if (!$this->connection->isBound()) {
  84                  throw new NotBoundException('Query execution is not possible without binding the connection first.');
  85              }
  86  
  87              $this->results = [];
  88              $con = $this->connection->getResource();
  89  
  90              switch ($this->options['scope']) {
  91                  case static::SCOPE_BASE:
  92                      $func = 'ldap_read';
  93                      break;
  94                  case static::SCOPE_ONE:
  95                      $func = 'ldap_list';
  96                      break;
  97                  case static::SCOPE_SUB:
  98                      $func = 'ldap_search';
  99                      break;
 100                  default:
 101                      throw new LdapException(sprintf('Could not search in scope "%s".', $this->options['scope']));
 102              }
 103  
 104              $itemsLeft = $maxItems = $this->options['maxItems'];
 105              $pageSize = $this->options['pageSize'];
 106              // Deal with the logic to handle maxItems properly. If we can satisfy it in
 107              // one request based on pageSize, we don't need to bother sending page control
 108              // to the server so that it can determine what we already know.
 109              if (0 !== $maxItems && $pageSize > $maxItems) {
 110                  $pageSize = 0;
 111              } elseif (0 !== $maxItems) {
 112                  $pageSize = min($maxItems, $pageSize);
 113              }
 114              $pageControl = $this->options['scope'] != static::SCOPE_BASE && $pageSize > 0;
 115              $cookie = '';
 116              do {
 117                  if ($pageControl) {
 118                      $this->controlPagedResult($con, $pageSize, true, $cookie);
 119                  }
 120                  $sizeLimit = $itemsLeft;
 121                  if ($pageSize > 0 && $sizeLimit >= $pageSize) {
 122                      $sizeLimit = 0;
 123                  }
 124                  $search = $this->callSearchFunction($con, $func, $sizeLimit);
 125  
 126                  if (false === $search) {
 127                      $ldapError = '';
 128                      if ($errno = ldap_errno($con)) {
 129                          $ldapError = sprintf(' LDAP error was [%d] %s', $errno, ldap_error($con));
 130                      }
 131                      if ($pageControl) {
 132                          $this->resetPagination();
 133                      }
 134  
 135                      throw new LdapException(sprintf('Could not complete search with dn "%s", query "%s" and filters "%s".%s.', $this->dn, $this->query, implode(',', $this->options['filter']), $ldapError));
 136                  }
 137  
 138                  $this->results[] = $search;
 139                  $itemsLeft -= min($itemsLeft, $pageSize);
 140  
 141                  if (0 !== $maxItems && 0 === $itemsLeft) {
 142                      break;
 143                  }
 144                  if ($pageControl) {
 145                      $cookie = $this->controlPagedResultResponse($con, $search, $cookie);
 146                  }
 147              } while (null !== $cookie && '' !== $cookie);
 148  
 149              if ($pageControl) {
 150                  $this->resetPagination();
 151              }
 152          }
 153  
 154          return new Collection($this->connection, $this);
 155      }
 156  
 157      /**
 158       * Returns an LDAP search resource. If this query resulted in multiple searches, only the first
 159       * page will be returned.
 160       *
 161       * @return resource|Result|null
 162       *
 163       * @internal
 164       */
 165      public function getResource(int $idx = 0)
 166      {
 167          return $this->results[$idx] ?? null;
 168      }
 169  
 170      /**
 171       * Returns all LDAP search resources.
 172       *
 173       * @return resource[]|Result[]
 174       *
 175       * @internal
 176       */
 177      public function getResources(): array
 178      {
 179          return $this->results;
 180      }
 181  
 182      /**
 183       * Resets pagination on the current connection.
 184       */
 185      private function resetPagination()
 186      {
 187          $con = $this->connection->getResource();
 188          $this->controlPagedResult($con, 0, false, '');
 189          $this->serverctrls = [];
 190  
 191          // This is a workaround for a bit of a bug in the above invocation
 192          // of ldap_control_paged_result. Instead of indicating to extldap that
 193          // we no longer wish to page queries on this link, this invocation sets
 194          // the LDAP_CONTROL_PAGEDRESULTS OID with a page size of 0. This isn't
 195          // well defined by RFC 2696 if there is no cookie present, so some servers
 196          // will interpret it differently and do the wrong thing. Forcefully remove
 197          // the OID for now until a fix can make its way through the versions of PHP
 198          // the we support.
 199          //
 200          // This is not supported in PHP < 7.2, so these versions will remain broken.
 201          $ctl = [];
 202          ldap_get_option($con, \LDAP_OPT_SERVER_CONTROLS, $ctl);
 203          if (!empty($ctl)) {
 204              foreach ($ctl as $idx => $info) {
 205                  if (static::PAGINATION_OID == $info['oid']) {
 206                      unset($ctl[$idx]);
 207                  }
 208              }
 209              ldap_set_option($con, \LDAP_OPT_SERVER_CONTROLS, $ctl);
 210          }
 211      }
 212  
 213      /**
 214       * Sets LDAP pagination controls.
 215       *
 216       * @param resource|LDAPConnection $con
 217       */
 218      private function controlPagedResult($con, int $pageSize, bool $critical, string $cookie): bool
 219      {
 220          if (\PHP_VERSION_ID < 70300) {
 221              return ldap_control_paged_result($con, $pageSize, $critical, $cookie);
 222          }
 223          $this->serverctrls = [
 224              [
 225                  'oid' => \LDAP_CONTROL_PAGEDRESULTS,
 226                  'isCritical' => $critical,
 227                  'value' => [
 228                      'size' => $pageSize,
 229                      'cookie' => $cookie,
 230                  ],
 231              ],
 232          ];
 233  
 234          return true;
 235      }
 236  
 237      /**
 238       * Retrieve LDAP pagination cookie.
 239       *
 240       * @param resource|LDAPConnection $con
 241       * @param resource|Result         $result
 242       */
 243      private function controlPagedResultResponse($con, $result, string $cookie = ''): string
 244      {
 245          if (\PHP_VERSION_ID < 70300) {
 246              ldap_control_paged_result_response($con, $result, $cookie);
 247  
 248              return $cookie;
 249          }
 250          ldap_parse_result($con, $result, $errcode, $matcheddn, $errmsg, $referrals, $controls);
 251  
 252          return $controls[\LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? '';
 253      }
 254  
 255      /**
 256       * Calls actual LDAP search function with the prepared options and parameters.
 257       *
 258       * @param resource|LDAPConnection $con
 259       *
 260       * @return resource|Result|false
 261       */
 262      private function callSearchFunction($con, callable $func, int $sizeLimit)
 263      {
 264          if (\PHP_VERSION_ID < 70300) {
 265              return @$func($con, $this->dn, $this->query, $this->options['filter'], $this->options['attrsOnly'], $sizeLimit, $this->options['timeout'], $this->options['deref']);
 266          }
 267  
 268          return @$func($con, $this->dn, $this->query, $this->options['filter'], $this->options['attrsOnly'], $sizeLimit, $this->options['timeout'], $this->options['deref'], $this->serverctrls);
 269      }
 270  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer