encoding) { return 'binary '.$this->type; } if ('ASCII' === $this->encoding) { return $this->type; } return $this->encoding.' '.$this->type; } public function getValueShort(): ?string { if ($rep = $this->value) { return '"'.$rep->contents.'"'; } return null; } public function transplant(Value $old): void { parent::transplant($old); if ($old instanceof self) { $this->encoding = $old->encoding; } } /** * @psalm-param Encoding $encoding */ public static function strlen(string $string, $encoding = false): int { if (\function_exists('mb_strlen')) { if (false === $encoding) { $encoding = self::detectEncoding($string); } if ($encoding && 'ASCII' !== $encoding) { return \mb_strlen($string, $encoding); } } return \strlen($string); } /** * @psalm-param Encoding $encoding */ public static function substr(string $string, int $start, int $length = null, $encoding = false): string { if (\function_exists('mb_substr')) { if (false === $encoding) { $encoding = self::detectEncoding($string); } if ($encoding && 'ASCII' !== $encoding) { return \mb_substr($string, $start, $length, $encoding); } } // Special case for substr/mb_substr discrepancy if ('' === $string) { return ''; } return \substr($string, $start, $length ?? PHP_INT_MAX); } /** * @psalm-return Encoding */ public static function detectEncoding(string $string) { if (\function_exists('mb_detect_encoding')) { if ($ret = \mb_detect_encoding($string, self::$char_encodings, true)) { return $ret; } } // Pretty much every character encoding uses first 32 bytes as control // characters. If it's not a multi-byte format it's safe to say matching // any control character besides tab, nl, and cr means it's binary. if (\preg_match('/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/', $string)) { return false; } if (\function_exists('iconv')) { foreach (self::$legacy_encodings as $encoding) { // Iconv detection works by triggering // "Detected an illegal character in input string" warnings if (@\iconv($encoding, $encoding, $string) === $string) { return $encoding; } } } elseif (!\function_exists('mb_detect_encoding')) { // @codeCoverageIgnore // If a user has neither mb_detect_encoding, nor iconv, nor the // polyfills, there's not much we can do about it... // Pretend it's ASCII and pray the browser renders it properly. return 'ASCII'; // @codeCoverageIgnore } return false; } }