|| ($attrFound && !$this->attrMethod)) { // Does the attribute have a value? if (empty($attrSubSet[1]) === false) { $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[1] . '"'; } elseif ($attrSubSet[1] === '0') { // Special Case // Is the value 0? $newSet[] = $attrSubSet[0] . '="0"'; } else { // Leave empty attributes alone $newSet[] = $attrSubSet[0] . '=""'; } } } return $newSet; } /** * Try to convert to plaintext * * @param string $source The source string. * * @return string Plaintext string * * @since 1.0 * @deprecated This method will be removed once support for PHP 5.3 is discontinued. */ protected function decode($source) { return html_entity_decode($source, \ENT_QUOTES, 'UTF-8'); } /** * Escape < > and " inside attribute values * * @param string $source The source string. * * @return string Filtered string * * @since 1.0 */ protected function escapeAttributeValues($source) { $alreadyFiltered = ''; $remainder = $source; $badChars = array('<', '"', '>'); $escapedChars = array('<', '"', '>'); // Process each portion based on presence of =" and ", "/>, or "> // See if there are any more attributes to process while (preg_match('#<[^>]*?=\s*?(\"|\')#s', $remainder, $matches, \PREG_OFFSET_CAPTURE)) { // We have found a tag with an attribute, convert its byte position to a UTF-8 string length, using non-multibyte substr() $stringBeforeTag = substr($remainder, 0, $matches[0][1]); $tagPosition = StringHelper::strlen($stringBeforeTag); // Get the character length before the attribute value $nextBefore = $tagPosition + StringHelper::strlen($matches[0][0]); // Figure out if we have a single or double quote and look for the matching closing quote // Closing quote should be "/>, ">, ", or " at the end of the string $quote = StringHelper::substr($matches[0][0], -1); $pregMatch = ($quote == '"') ? '#(\"\s*/\s*>|\"\s*>|\"\s+|\"$)#' : "#(\'\s*/\s*>|\'\s*>|\'\s+|\'$)#"; // Get the portion after attribute value $attributeValueRemainder = StringHelper::substr($remainder, $nextBefore); if (preg_match($pregMatch, $attributeValueRemainder, $matches, \PREG_OFFSET_CAPTURE)) { // We have a closing quote, convert its byte position to a UTF-8 string length, using non-multibyte substr() $stringBeforeQuote = substr($attributeValueRemainder, 0, $matches[0][1]); $closeQuoteChars = StringHelper::strlen($stringBeforeQuote); $nextAfter = $nextBefore + $matches[0][1]; } else { // No closing quote $nextAfter = StringHelper::strlen($remainder); } // Get the actual attribute value $attributeValue = StringHelper::substr($remainder, $nextBefore, $nextAfter - $nextBefore); // Escape bad chars $attributeValue = str_replace($badChars, $escapedChars, $attributeValue); $attributeValue = $this->stripCssExpressions($attributeValue); $alreadyFiltered .= StringHelper::substr($remainder, 0, $nextBefore) . $attributeValue . $quote; $remainder = StringHelper::substr($remainder, $nextAfter + 1); } // At this point, we just have to return the $alreadyFiltered and the $remainder return $alreadyFiltered . $remainder; } /** * Remove CSS Expressions in the form of :expression(...) * * @param string $source The source string. * * @return string Filtered string * * @since 1.0 */ protected function stripCssExpressions($source) { // Strip any comments out (in the form of /*...*/) $test = preg_replace('#\/\*.*\*\/#U', '', $source); // Test for :expression if (!stripos($test, ':expression')) { // Not found, so we are done return $source; } // At this point, we have stripped out the comments and have found :expression // Test stripped string for :expression followed by a '(' if (preg_match_all('#:expression\s*\(#', $test, $matches)) { // If found, remove :expression return str_ireplace(':expression', '', $test); } return $source; } /** * Integer filter * * @param string $source The string to be filtered * * @return integer The filtered value */ private function cleanInt($source) { $pattern = '/[-+]?[0-9]+/'; preg_match($pattern, $source, $matches); return isset($matches[0]) ? (int) $matches[0] : 0; } /** * Alias for cleanInt() * * @param string $source The string to be filtered * * @return integer The filtered value */ private function cleanInteger($source) { return $this->cleanInt($source); } /** * Unsigned integer filter * * @param string $source The string to be filtered * * @return integer The filtered value */ private function cleanUint($source) { $pattern = '/[-+]?[0-9]+/'; preg_match($pattern, $source, $matches); return isset($matches[0]) ? abs((int) $matches[0]) : 0; } /** * Float filter * * @param string $source The string to be filtered * * @return float The filtered value */ private function cleanFloat($source) { $pattern = '/[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?/'; preg_match($pattern, $source, $matches); return isset($matches[0]) ? (float) $matches[0] : 0.0; } /** * Alias for cleanFloat() * * @param string $source The string to be filtered * * @return float The filtered value */ private function cleanDouble($source) { return $this->cleanFloat($source); } /** * Boolean filter * * @param string $source The string to be filtered * * @return boolean The filtered value */ private function cleanBool($source) { return (bool) $source; } /** * Alias for cleanBool() * * @param string $source The string to be filtered * * @return boolean The filtered value */ private function cleanBoolean($source) { return $this->cleanBool($source); } /** * Word filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanWord($source) { $pattern = '/[^A-Z_]/i'; return preg_replace($pattern, '', $source); } /** * Alphanumerical filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanAlnum($source) { $pattern = '/[^A-Z0-9]/i'; return preg_replace($pattern, '', $source); } /** * Command filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanCmd($source) { $pattern = '/[^A-Z0-9_\.-]/i'; $result = preg_replace($pattern, '', $source); $result = ltrim($result, '.'); return $result; } /** * Base64 filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanBase64($source) { $pattern = '/[^A-Z0-9\/+=]/i'; return preg_replace($pattern, '', $source); } /** * String filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanString($source) { return $this->remove($this->decode($source)); } /** * HTML filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanHtml($source) { return $this->remove($source); } /** * Path filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanPath($source) { // Linux and other Unixoids $filePattern = '(?:[^\x00\/:*?]{1,255})'; $pathSeparatorPattern = '(?:\/+)'; $rootPattern = '(?:\/)'; if ($this->pathMatches($source, $rootPattern, $pathSeparatorPattern, $filePattern, '/')) { return $source; } // Windows $filePattern = '(?:[^\x00\\\\\/:*"?<>|]{1,255})'; $pathSeparatorPattern = '(?:[\\\\\/])'; $rootPattern = '(?:[A-Za-z]:(\\\\|\/))'; if ($this->pathMatches($source, $rootPattern, $pathSeparatorPattern, $filePattern, '\\')) { return $source; } return ''; } /** * Fix a path, if and only if it matches the provided patterns. * * If a path matches but is longer than 4095 bytes, it is cleared. * * @param string $source The path as provided; it gets cleaned in place, if possible. * @param string $rootPattern The pattern to identify an absolute path (e.g., '/' on Linux, 'C:\' on Windows), * @param string $pathSeparatorPattern The pattern for valid path separators * @param string $filePattern The pattern for valid file and directory names * @param string $pathSeparator The native path separator * * @return boolean */ private function pathMatches(&$source, $rootPattern, $pathSeparatorPattern, $filePattern, $pathSeparator) { $pathPattern = "/^{$rootPattern}?(?:{$filePattern}{$pathSeparatorPattern})*{$filePattern}?$/u"; if (preg_match($pathPattern, $source)) { $source = preg_replace("/{$pathSeparatorPattern}/", $pathSeparator, $source); if (strlen($source) > 4095) { // Path is too long $source = ''; } return true; } return false; } /** * Trim filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanTrim($source) { $result = trim($source); $result = StringHelper::trim($result, \chr(0xE3) . \chr(0x80) . \chr(0x80)); $result = StringHelper::trim($result, \chr(0xC2) . \chr(0xA0)); return $result; } /** * Username filter * * @param string $source The string to be filtered * * @return string The filtered string */ private function cleanUsername($source) { $pattern = '/[\x00-\x1F\x7F<>"\'%&]/'; return preg_replace($pattern, '', $source); } } Error