: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
elseif (($value & 0xF8) === 0xF0)
$character = ($value & 0x07) << 18;
if ($position + $length <= $strlen)
for ($position++; $remaining; $position++)
$value = ord($string[$position]);
// Check that the byte is valid, then add it to the character:
if (($value & 0xC0) === 0x80)
$character |= ($value & 0x3F) << (--$remaining * 6);
// If it is invalid, count the sequence as invalid and reprocess the current byte:
// Percent encode anything invalid or not in ucschar
// Non-shortest form sequences are invalid
|| $length > 1 && $character <= 0x7F
|| $length > 2 && $character <= 0x7FF
|| $length > 3 && $character <= 0xFFFF
// Outside of range of ucschar codepoints
|| ($character & 0xFFFE) === 0xFFFE
|| $character >= 0xFDD0 && $character <= 0xFDEF
// Everything else not in ucschar
$character > 0xD7FF && $character < 0xF900
// Everything not in iprivate, if it applies
// If we were a character, pretend we weren't, but rather an error.
for ($j = $start; $j <= $position; $j++)
$string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
* Callback function for preg_replace_callback.
* Removes sequences of percent encoded bytes that represent UTF-8
* encoded characters in iunreserved
* @param array $match PCRE match
* @return string Replacement
protected function remove_iunreserved_percent_encoded($match)
// As we just have valid percent encoded sequences we can just explode
// and ignore the first member of the returned array (an empty string).
$bytes = explode('%', $match[0]);
// Initialize the new string (this is what will be returned) and that
// there are no bytes remaining in the current sequence (unsurprising
// Loop over each and every byte, and set $value to its value
for ($i = 1, $len = count($bytes); $i < $len; $i++)
$value = hexdec($bytes[$i]);
// If we're the first byte of sequence:
// By default we are valid
elseif (($value & 0xE0) === 0xC0)
$character = ($value & 0x1F) << 6;
elseif (($value & 0xF0) === 0xE0)
$character = ($value & 0x0F) << 12;
elseif (($value & 0xF8) === 0xF0)
$character = ($value & 0x07) << 18;
// Check that the byte is valid, then add it to the character:
if (($value & 0xC0) === 0x80)
$character |= ($value & 0x3F) << ($remaining * 6);
// If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
// If we've reached the end of the current byte sequence, append it to Unicode::$data
// Percent encode anything invalid or not in iunreserved
// Non-shortest form sequences are invalid
|| $length > 1 && $character <= 0x7F
|| $length > 2 && $character <= 0x7FF
|| $length > 3 && $character <= 0xFFFF
// Outside of range of iunreserved codepoints
|| ($character & 0xFFFE) === 0xFFFE
|| $character >= 0xFDD0 && $character <= 0xFDEF
// Everything else not in iunreserved (this is all BMP)
|| $character > 0x39 && $character < 0x41
|| $character > 0x5A && $character < 0x61
|| $character > 0x7A && $character < 0x7E
|| $character > 0x7E && $character < 0xA0
|| $character > 0xD7FF && $character < 0xF900
for ($j = $start; $j <= $i; $j++)
$string .= '%' . strtoupper($bytes[$j]);
for ($j = $start; $j <= $i; $j++)
$string .= chr(hexdec($bytes[$j]));
// If we have any bytes left over they are invalid (i.e., we are
// mid-way through a multi-byte sequence)
for ($j = $start; $j < $len; $j++)
$string .= '%' . strtoupper($bytes[$j]);
protected function scheme_normalization()
if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
* Check if the object represents a valid IRI. This needs to be done on each
* call as some things change depending on another part of the IRI.
public function is_valid()
if ($this->ipath === '') return true;
$isauthority = $this->iuserinfo !== null || $this->ihost !== null ||
if ($isauthority && $this->ipath[0] === '/') return true;
if (!$isauthority && (substr($this->ipath, 0, 2) === '//')) return false;
// Relative urls cannot have a colon in the first path segment (and the
// slashes themselves are not included so skip the first character).
if (!$this->scheme && !$isauthority &&
strpos($this->ipath, ':') !== false &&
strpos($this->ipath, '/', 1) !== false &&
strpos($this->ipath, ':') < strpos($this->ipath, '/', 1)) return false;
* Set the entire IRI. Returns true on success, false on failure (if there
* are any invalid characters).
public function set_iri($iri, $clear_cache = false)
elseif (isset($cache[$iri]))
$parsed = $this->parse_iri((string) $iri);
$return = $this->set_scheme($parsed['scheme'])
&& $this->set_authority($parsed['authority'])
&& $this->set_path($parsed['path'])
&& $this->set_query($parsed['query'])
&& $this->set_fragment($parsed['fragment']);
$cache[$iri] = array($this->scheme,
* Set the scheme. Returns true on success, false on failure (if there are
* any invalid characters).
public function set_scheme($scheme)
elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
$this->scheme = strtolower($scheme);
* Set the authority. Returns true on success, false on failure (if there are
* any invalid characters).
* @param string $authority
public function set_authority($authority, $clear_cache = false)
elseif (isset($cache[$authority]))
$return) = $cache[$authority];
if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
$iuserinfo = substr($remaining, 0, $iuserinfo_end);
$remaining = substr($remaining, $iuserinfo_end + 1);
if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
if (($port = substr($remaining, $port_start + 1)) === false)
$remaining = substr($remaining, 0, $port_start);
$return = $this->set_userinfo($iuserinfo) &&
$this->set_host($remaining) &&
$cache[$authority] = array($this->iuserinfo,
* @param string $iuserinfo
public function set_userinfo($iuserinfo)
$this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
$this->scheme_normalization();
* Set the ihost. Returns true on success, false on failure (if there are
* any invalid characters).
public function set_host($ihost)
elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
$this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
$ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
// Lowercase, but ignore pct-encoded sections (as they should
// remain uppercase). This must be done after the previous step
// as that can add unescaped characters.
$strlen = strlen($ihost);
while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
if ($ihost[$position] === '%')