AbstractUriPart::toUriString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
namespace Subreality\Dilmun\Anshar\Http\UriParts;
3
4
use Subreality\Dilmun\Anshar\Utils\StringHelper;
5
6
/**
7
 * Class AbstractUriPart
8
 * @package Subreality\Dilmun\Anshar\Http\UriParts
9
 */
10
abstract class AbstractUriPart implements UriPartInterface
11
{
12
    protected static $unreserved_pattern  = '\w\-\.~';
13
    protected static $pct_encoded_pattern = '%[A-Fa-f0-9]{2}';
14
    protected static $sub_delims_pattern  = '\!\$&\'\(\)\*\+,;\=';
15
    protected static $pchar_pattern       = '\:@';
16
17
    protected static $unreserved_characters = array("_", "-", ".", "~");
18
    protected static $pchar_characters      = array(":", "@");
19
20
    protected static $sub_delims_characters = array(
21
        "!",
22
        "$",
23
        "&",
24
        "'",
25
        "(",
26
        ")",
27
        "*",
28
        "+",
29
        ",",
30
        ";",
31
        "=",
32
    );
33
34
    protected $data = "";
35
36
    protected static $part_pattern;
37
38
    /**
39
     * Provides a common composition of allowed characters for validation and encoding.
40
     *
41
     * @see AbstractUriPart::compileUnencodedCharacters()
42
     * @see AbstractUriPart::compileValidPattern()
43
     *
44
     * @var array
45
     */
46
    protected static $compositions = array(
47
        "unreserved_characters",
48
        "pchar_characters",
49
        "sub_delims_characters",
50
    );
51
52
    protected static $unencoded_characters = array();
53
54
    protected static $valid_pattern;
55
56
    /**
57
     * Constructor for URI parts.
58
     *
59
     * Note that, if overriding the abstract class's constructor, care should be taken to compile unencoded characters
60
     * prior to compiling the part's valid pattern, as the default behavior of the abstract class is to base the part's
61
     * validation pattern on compiled unencoded characters.
62
     *
63
     * @see AbstractUriPart::compileUnencodedCharacters()
64
     * @see AbstractUriPart::compileValidPattern()
65
     *
66
     * @param string $part_data The data used to construct a URI part
67
     * @param string $part_name The name of the URI part for exception reporting
68
     * @param string $part_type [optional] The expected type of the URI part
69
     */
70 224
    public function __construct($part_data, $part_name, $part_type = "string")
71
    {
72 224
        if (gettype($part_data) != $part_type) {
73 42
            throw new \InvalidArgumentException("{$part_name} must be a {$part_type}");
74 182
        } elseif (!static::isValid($part_data)) {
75 33
            $part_data = $this->encode($part_data);
76 33
        }
77
78 182
        $this->data = $part_data;
79 182
    }
80
81
    /**
82
     * Returns a string representation of the URI component
83
     *
84
     * @return string   A string representation of the URI component
85
     */
86 231
    public function __toString()
87
    {
88 231
        return (string) $this->data;
89
    }
90
91
    /**
92
     * Returns a string representing a valid pattern for the URI component
93
     *
94
     * @return string
95
     */
96 22
    public static function getValidPattern()
97
    {
98 22
        static::compileValidPattern();
99
100 22
        return static::$part_pattern;
101
    }
102
103
    /**
104
     * Determines whether a given string adheres to the RFC3986 specification for the extending URI part.
105
     *
106
     * Requires extending classes to define self::$valid_pattern.
107
     *
108
     * @see https://tools.ietf.org/html/rfc3986#appendix-A
109
     *
110
     * @param mixed $data   The data to check for validity
111
     *
112
     * @return bool         Returns true if the provided query matches the RFC3986 specification
113
     *                      Returns false otherwise
114
     */
115 276
    public static function isValid($data)
116
    {
117 276
        static::compileValidPattern();
118
119 276
        $pattern_found = preg_match(static::$valid_pattern, $data, $matches);
120
121 276
        return (bool) $pattern_found;
122
    }
123
124
    /**
125
     * @return string
126
     */
127 98
    public function toUriString()
128
    {
129 98
        return (string) $this;
130
    }
131
132
    /**
133
     * Percent-encodes invalid characters within a given string. Percent-encoding ignores valid as defined by the
134
     * component per RFC3986.
135
     *
136
     * @see https://tools.ietf.org/html/rfc3986#appendix-A
137
     *
138
     * @param string $string     The query string to be percent-encoded
139
     *
140
     * @return string            The query string with invalid characters percent-encoded
141
     */
142 33
    protected function encode($string)
143
    {
144 33
        $encoded_query = $string;
145
146 33
        if (!empty(static::$unencoded_characters)) {
147 33
            $string_helper = new StringHelper($string);
148
149 33
            $encoded_query = $string_helper->affectChunks("rawurlencode", ...static::$unencoded_characters);
150 33
        }
151
152 33
        return $encoded_query;
153
    }
154
155
    /**
156
     * Creates a validation pattern based upon a URI part's unencoded characters, allowing for empty strings (^$),
157
     * word characters (\w), and percent encoding by default.
158
     *
159
     * @see AbstractUriPart::compileUnencodedCharacters()
160
     *
161
     * @return void
162
     */
163 240
    protected static function compileValidPattern()
164
    {
165 240
        static::compileUnencodedCharacters();
166
167 240
        $valid_characters = implode(static::$unencoded_characters);
168
169 240
        if (empty(static::$part_pattern)) {
170
            static::$part_pattern = '([\w';   //start decoded group
171
172
            static::$part_pattern = static::$part_pattern . preg_quote($valid_characters, "/");
173
174
            static::$part_pattern = static::$part_pattern .
175
                ']|' .                          //predefined patterns or percent-encoding
176
                self::$pct_encoded_pattern .
177
                ')*';
178
        }
179
180 240
        static::$valid_pattern = '/^$|^' . //allows part to be empty
181 240
            static::$part_pattern .
182 240
            '$/';
183 240
    }
184
185
    /**
186
     * Compiles unencoded characters provided a URI part's composition, as defined by its compositions property.
187
     * Note that unencoded characters form the basis for the URI part's validation pattern.
188
     *
189
     * @see AbstractUriPart::compileValidPattern()
190
     *
191
     * @return void
192
     */
193 263
    protected static function compileUnencodedCharacters()
194
    {
195 263
        foreach (static::$compositions as $composition) {
196 263
            $composition_characters = self::${$composition};
197
198 263
            $delta = array_diff($composition_characters, static::$unencoded_characters);
199
200 263
            if (!empty($delta)) {
201
                static::$unencoded_characters = array_merge(static::$unencoded_characters, self::${$composition});
202
            }
203 263
        }
204 263
    }
205
}
206