xref: /plugin/pureldap/vendor/freedsx/ldap/src/FreeDSx/Ldap/Entry/Rdn.php (revision dad993c57a70866aa1db59c43f043769c2eb7ed0)
10b3fd2d3SAndreas Gohr<?php
2*dad993c5SAndreas Gohr
30b3fd2d3SAndreas Gohr/**
40b3fd2d3SAndreas Gohr * This file is part of the FreeDSx LDAP package.
50b3fd2d3SAndreas Gohr *
60b3fd2d3SAndreas Gohr * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
70b3fd2d3SAndreas Gohr *
80b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE
90b3fd2d3SAndreas Gohr * file that was distributed with this source code.
100b3fd2d3SAndreas Gohr */
110b3fd2d3SAndreas Gohr
120b3fd2d3SAndreas Gohrnamespace FreeDSx\Ldap\Entry;
130b3fd2d3SAndreas Gohr
140b3fd2d3SAndreas Gohruse FreeDSx\Ldap\Exception\InvalidArgumentException;
15*dad993c5SAndreas Gohruse function array_keys;
16*dad993c5SAndreas Gohruse function array_values;
17*dad993c5SAndreas Gohruse function count;
18*dad993c5SAndreas Gohruse function explode;
19*dad993c5SAndreas Gohruse function preg_split;
20*dad993c5SAndreas Gohruse function str_replace;
21*dad993c5SAndreas Gohruse function substr;
22*dad993c5SAndreas Gohruse function substr_replace;
230b3fd2d3SAndreas Gohr
240b3fd2d3SAndreas Gohr/**
250b3fd2d3SAndreas Gohr * Represents a Relative Distinguished Name.
260b3fd2d3SAndreas Gohr *
270b3fd2d3SAndreas Gohr * @author Chad Sikorra <Chad.Sikorra@gmail.com>
280b3fd2d3SAndreas Gohr */
290b3fd2d3SAndreas Gohrclass Rdn
300b3fd2d3SAndreas Gohr{
310b3fd2d3SAndreas Gohr    use EscapeTrait;
320b3fd2d3SAndreas Gohr
330b3fd2d3SAndreas Gohr    public const ESCAPE_MAP = [
340b3fd2d3SAndreas Gohr        '\\' => '\\5c',
350b3fd2d3SAndreas Gohr        '"' => '\\22',
360b3fd2d3SAndreas Gohr        '+' => '\\2b',
370b3fd2d3SAndreas Gohr        ',' => '\\2c',
380b3fd2d3SAndreas Gohr        ';' => '\\3b',
390b3fd2d3SAndreas Gohr        '<' => '\\3c',
400b3fd2d3SAndreas Gohr        '>' => '\\3e',
410b3fd2d3SAndreas Gohr    ];
420b3fd2d3SAndreas Gohr
430b3fd2d3SAndreas Gohr    /**
440b3fd2d3SAndreas Gohr     * @var string
450b3fd2d3SAndreas Gohr     */
460b3fd2d3SAndreas Gohr    protected $name;
470b3fd2d3SAndreas Gohr
480b3fd2d3SAndreas Gohr    /**
490b3fd2d3SAndreas Gohr     * @var string
500b3fd2d3SAndreas Gohr     */
510b3fd2d3SAndreas Gohr    protected $value;
520b3fd2d3SAndreas Gohr
530b3fd2d3SAndreas Gohr    /**
540b3fd2d3SAndreas Gohr     * @var Rdn[]
550b3fd2d3SAndreas Gohr     */
560b3fd2d3SAndreas Gohr    protected $additional = [];
570b3fd2d3SAndreas Gohr
580b3fd2d3SAndreas Gohr    /**
590b3fd2d3SAndreas Gohr     * @param string $name
600b3fd2d3SAndreas Gohr     * @param string $value
610b3fd2d3SAndreas Gohr     */
620b3fd2d3SAndreas Gohr    public function __construct(string $name, string $value)
630b3fd2d3SAndreas Gohr    {
640b3fd2d3SAndreas Gohr        $this->name = $name;
650b3fd2d3SAndreas Gohr        $this->value = $value;
660b3fd2d3SAndreas Gohr    }
670b3fd2d3SAndreas Gohr
680b3fd2d3SAndreas Gohr    /**
690b3fd2d3SAndreas Gohr     * @return string
700b3fd2d3SAndreas Gohr     */
710b3fd2d3SAndreas Gohr    public function getName(): string
720b3fd2d3SAndreas Gohr    {
730b3fd2d3SAndreas Gohr        return $this->name;
740b3fd2d3SAndreas Gohr    }
750b3fd2d3SAndreas Gohr
760b3fd2d3SAndreas Gohr    /**
770b3fd2d3SAndreas Gohr     * @return string
780b3fd2d3SAndreas Gohr     */
790b3fd2d3SAndreas Gohr    public function getValue(): string
800b3fd2d3SAndreas Gohr    {
810b3fd2d3SAndreas Gohr        return $this->value;
820b3fd2d3SAndreas Gohr    }
830b3fd2d3SAndreas Gohr
840b3fd2d3SAndreas Gohr    /**
850b3fd2d3SAndreas Gohr     * @return bool
860b3fd2d3SAndreas Gohr     */
870b3fd2d3SAndreas Gohr    public function isMultivalued(): bool
880b3fd2d3SAndreas Gohr    {
89*dad993c5SAndreas Gohr        return count($this->additional) !== 0;
900b3fd2d3SAndreas Gohr    }
910b3fd2d3SAndreas Gohr
920b3fd2d3SAndreas Gohr    /**
930b3fd2d3SAndreas Gohr     * @return string
940b3fd2d3SAndreas Gohr     */
950b3fd2d3SAndreas Gohr    public function toString(): string
960b3fd2d3SAndreas Gohr    {
970b3fd2d3SAndreas Gohr        $rdn = $this->name . '=' . $this->value;
980b3fd2d3SAndreas Gohr
990b3fd2d3SAndreas Gohr        foreach ($this->additional as $additional) {
1000b3fd2d3SAndreas Gohr            $rdn .= '+' . $additional->getName() . '=' . $additional->getValue();
1010b3fd2d3SAndreas Gohr        }
1020b3fd2d3SAndreas Gohr
1030b3fd2d3SAndreas Gohr        return $rdn;
1040b3fd2d3SAndreas Gohr    }
1050b3fd2d3SAndreas Gohr
1060b3fd2d3SAndreas Gohr    /**
1070b3fd2d3SAndreas Gohr     * @return string
1080b3fd2d3SAndreas Gohr     */
1090b3fd2d3SAndreas Gohr    public function __toString()
1100b3fd2d3SAndreas Gohr    {
1110b3fd2d3SAndreas Gohr        return $this->toString();
1120b3fd2d3SAndreas Gohr    }
1130b3fd2d3SAndreas Gohr
1140b3fd2d3SAndreas Gohr    /**
1150b3fd2d3SAndreas Gohr     * @param string $rdn
1160b3fd2d3SAndreas Gohr     * @return Rdn
117*dad993c5SAndreas Gohr     * @throws InvalidArgumentException
1180b3fd2d3SAndreas Gohr     */
1190b3fd2d3SAndreas Gohr    public static function create(string $rdn): Rdn
1200b3fd2d3SAndreas Gohr    {
121*dad993c5SAndreas Gohr        $pieces = preg_split('/(?<!\\\\)\+/', $rdn);
1220b3fd2d3SAndreas Gohr        if ($pieces === false) {
1230b3fd2d3SAndreas Gohr            throw new InvalidArgumentException(sprintf('The RDN "%s" is invalid.', $rdn));
1240b3fd2d3SAndreas Gohr        }
1250b3fd2d3SAndreas Gohr
1260b3fd2d3SAndreas Gohr        // @todo Simplify this logic somehow?
1270b3fd2d3SAndreas Gohr        $obj = null;
1280b3fd2d3SAndreas Gohr        foreach ($pieces as $piece) {
129*dad993c5SAndreas Gohr            $parts = explode('=', $piece, 2);
130*dad993c5SAndreas Gohr            if (count($parts) !== 2) {
1310b3fd2d3SAndreas Gohr                throw new InvalidArgumentException(sprintf('The RDN "%s" is invalid.', $piece));
1320b3fd2d3SAndreas Gohr            }
1330b3fd2d3SAndreas Gohr            if ($obj === null) {
1340b3fd2d3SAndreas Gohr                $obj = new self($parts[0], $parts[1]);
1350b3fd2d3SAndreas Gohr            } else {
1360b3fd2d3SAndreas Gohr                /** @var Rdn $obj */
1370b3fd2d3SAndreas Gohr                $obj->additional[] = new self($parts[0], $parts[1]);
1380b3fd2d3SAndreas Gohr            }
1390b3fd2d3SAndreas Gohr        }
1400b3fd2d3SAndreas Gohr
1410b3fd2d3SAndreas Gohr        if ($obj === null) {
1420b3fd2d3SAndreas Gohr            throw new InvalidArgumentException(sprintf("The RDN '%s' is not valid.", $rdn));
1430b3fd2d3SAndreas Gohr        }
1440b3fd2d3SAndreas Gohr
1450b3fd2d3SAndreas Gohr        return $obj;
1460b3fd2d3SAndreas Gohr    }
1470b3fd2d3SAndreas Gohr
1480b3fd2d3SAndreas Gohr    /**
1490b3fd2d3SAndreas Gohr     * Escape an RDN value.
1500b3fd2d3SAndreas Gohr     *
1510b3fd2d3SAndreas Gohr     * @param string $value
1520b3fd2d3SAndreas Gohr     * @return string
1530b3fd2d3SAndreas Gohr     */
1540b3fd2d3SAndreas Gohr    public static function escape(string $value): string
1550b3fd2d3SAndreas Gohr    {
1560b3fd2d3SAndreas Gohr        if (self::shouldNotEscape($value)) {
1570b3fd2d3SAndreas Gohr            return $value;
1580b3fd2d3SAndreas Gohr        }
159*dad993c5SAndreas Gohr        $value = str_replace(array_keys(self::ESCAPE_MAP), array_values(self::ESCAPE_MAP), $value);
1600b3fd2d3SAndreas Gohr
1610b3fd2d3SAndreas Gohr        if ($value[0] === '#' || $value[0] === ' ') {
162*dad993c5SAndreas Gohr            $value = ($value[0] === '#' ? '\23' : '\20') . substr($value, 1);
1630b3fd2d3SAndreas Gohr        }
1640b3fd2d3SAndreas Gohr        if ($value[-1] === ' ') {
165*dad993c5SAndreas Gohr            $value = substr_replace($value, '\20', -1, 1);
1660b3fd2d3SAndreas Gohr        }
1670b3fd2d3SAndreas Gohr
1680b3fd2d3SAndreas Gohr        return self::escapeNonPrintable($value);
1690b3fd2d3SAndreas Gohr    }
1700b3fd2d3SAndreas Gohr}
171