From c53d8d026021f97075fb2f4940ba22793c38fb6e Mon Sep 17 00:00:00 2001 From: davehauenstein Date: Wed, 15 Apr 2009 22:06:42 +0000 Subject: added toolbar; functionality includes refresh button to get back to original page, print article, email a link to the article with a personal note git-svn-id: http://arc90labs-readability.googlecode.com/svn/trunk@31 d4e419ec-0920-11de-bbfd-a7c1bc4c261e --- lib/Zend/Filter/Alnum.php | 115 +++ lib/Zend/Filter/Alpha.php | 115 +++ lib/Zend/Filter/BaseName.php | 50 ++ lib/Zend/Filter/Digits.php | 82 +++ lib/Zend/Filter/Dir.php | 50 ++ lib/Zend/Filter/Exception.php | 37 + lib/Zend/Filter/File/LowerCase.php | 84 +++ lib/Zend/Filter/File/Rename.php | 282 ++++++++ lib/Zend/Filter/File/UpperCase.php | 84 +++ lib/Zend/Filter/HtmlEntities.php | 122 ++++ lib/Zend/Filter/Inflector.php | 497 +++++++++++++ lib/Zend/Filter/Input.php | 926 +++++++++++++++++++++++++ lib/Zend/Filter/Int.php | 50 ++ lib/Zend/Filter/Interface.php | 40 ++ lib/Zend/Filter/PregReplace.php | 156 +++++ lib/Zend/Filter/RealPath.php | 50 ++ lib/Zend/Filter/StringToLower.php | 76 ++ lib/Zend/Filter/StringToUpper.php | 76 ++ lib/Zend/Filter/StringTrim.php | 97 +++ lib/Zend/Filter/StripNewlines.php | 48 ++ lib/Zend/Filter/StripTags.php | 294 ++++++++ lib/Zend/Filter/Word/CamelCaseToDash.php | 44 ++ lib/Zend/Filter/Word/CamelCaseToSeparator.php | 49 ++ lib/Zend/Filter/Word/CamelCaseToUnderscore.php | 44 ++ lib/Zend/Filter/Word/DashToCamelCase.php | 44 ++ lib/Zend/Filter/Word/DashToSeparator.php | 42 ++ lib/Zend/Filter/Word/DashToUnderscore.php | 45 ++ lib/Zend/Filter/Word/Separator/Abstract.php | 76 ++ lib/Zend/Filter/Word/SeparatorToCamelCase.php | 52 ++ lib/Zend/Filter/Word/SeparatorToDash.php | 46 ++ lib/Zend/Filter/Word/SeparatorToSeparator.php | 129 ++++ lib/Zend/Filter/Word/UnderscoreToCamelCase.php | 44 ++ lib/Zend/Filter/Word/UnderscoreToDash.php | 45 ++ lib/Zend/Filter/Word/UnderscoreToSeparator.php | 45 ++ 34 files changed, 4036 insertions(+) create mode 100644 lib/Zend/Filter/Alnum.php create mode 100644 lib/Zend/Filter/Alpha.php create mode 100644 lib/Zend/Filter/BaseName.php create mode 100644 lib/Zend/Filter/Digits.php create mode 100644 lib/Zend/Filter/Dir.php create mode 100644 lib/Zend/Filter/Exception.php create mode 100644 lib/Zend/Filter/File/LowerCase.php create mode 100644 lib/Zend/Filter/File/Rename.php create mode 100644 lib/Zend/Filter/File/UpperCase.php create mode 100644 lib/Zend/Filter/HtmlEntities.php create mode 100644 lib/Zend/Filter/Inflector.php create mode 100644 lib/Zend/Filter/Input.php create mode 100644 lib/Zend/Filter/Int.php create mode 100644 lib/Zend/Filter/Interface.php create mode 100644 lib/Zend/Filter/PregReplace.php create mode 100644 lib/Zend/Filter/RealPath.php create mode 100644 lib/Zend/Filter/StringToLower.php create mode 100644 lib/Zend/Filter/StringToUpper.php create mode 100644 lib/Zend/Filter/StringTrim.php create mode 100644 lib/Zend/Filter/StripNewlines.php create mode 100644 lib/Zend/Filter/StripTags.php create mode 100644 lib/Zend/Filter/Word/CamelCaseToDash.php create mode 100644 lib/Zend/Filter/Word/CamelCaseToSeparator.php create mode 100644 lib/Zend/Filter/Word/CamelCaseToUnderscore.php create mode 100644 lib/Zend/Filter/Word/DashToCamelCase.php create mode 100644 lib/Zend/Filter/Word/DashToSeparator.php create mode 100644 lib/Zend/Filter/Word/DashToUnderscore.php create mode 100644 lib/Zend/Filter/Word/Separator/Abstract.php create mode 100644 lib/Zend/Filter/Word/SeparatorToCamelCase.php create mode 100644 lib/Zend/Filter/Word/SeparatorToDash.php create mode 100644 lib/Zend/Filter/Word/SeparatorToSeparator.php create mode 100644 lib/Zend/Filter/Word/UnderscoreToCamelCase.php create mode 100644 lib/Zend/Filter/Word/UnderscoreToDash.php create mode 100644 lib/Zend/Filter/Word/UnderscoreToSeparator.php (limited to 'lib/Zend/Filter') diff --git a/lib/Zend/Filter/Alnum.php b/lib/Zend/Filter/Alnum.php new file mode 100644 index 0000000..a50cddd --- /dev/null +++ b/lib/Zend/Filter/Alnum.php @@ -0,0 +1,115 @@ +allowWhiteSpace = (boolean) $allowWhiteSpace; + if (null === self::$_unicodeEnabled) { + self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; + } + + if (null === self::$_meansEnglishAlphabet) { + $this->_locale = new Zend_Locale('auto'); + self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), + array('ja', 'ko', 'zh') + ); + } + + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, removing all but alphabetic and digit characters + * + * @param string $value + * @return string + */ + public function filter($value) + { + $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; + if (!self::$_unicodeEnabled) { + // POSIX named classes are not supported, use alternative a-zA-Z0-9 match + $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/'; + } else if (self::$_meansEnglishAlphabet) { + //The Alphabet means english alphabet. + $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/u'; + } else { + //The Alphabet means each language's alphabet. + $pattern = '/[^\p{L}\p{N}' . $whiteSpace . ']/u'; + } + + return preg_replace($pattern, '', (string) $value); + } +} diff --git a/lib/Zend/Filter/Alpha.php b/lib/Zend/Filter/Alpha.php new file mode 100644 index 0000000..adfaafe --- /dev/null +++ b/lib/Zend/Filter/Alpha.php @@ -0,0 +1,115 @@ +allowWhiteSpace = (boolean) $allowWhiteSpace; + if (null === self::$_unicodeEnabled) { + self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; + } + + if (null === self::$_meansEnglishAlphabet) { + $this->_locale = new Zend_Locale('auto'); + self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), + array('ja', 'ko', 'zh') + ); + } + + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, removing all but alphabetic characters + * + * @param string $value + * @return string + */ + public function filter($value) + { + $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; + if (!self::$_unicodeEnabled) { + // POSIX named classes are not supported, use alternative a-zA-Z match + $pattern = '/[^a-zA-Z' . $whiteSpace . ']/'; + } else if (self::$_meansEnglishAlphabet) { + //The Alphabet means english alphabet. + $pattern = '/[^a-zA-Z' . $whiteSpace . ']/u'; + } else { + //The Alphabet means each language's alphabet. + $pattern = '/[^\p{L}' . $whiteSpace . ']/u'; + } + + return preg_replace($pattern, '', (string) $value); + } +} diff --git a/lib/Zend/Filter/BaseName.php b/lib/Zend/Filter/BaseName.php new file mode 100644 index 0000000..a0652ab --- /dev/null +++ b/lib/Zend/Filter/BaseName.php @@ -0,0 +1,50 @@ +setEncoding($options); + } + } + + /** + * Defined by Zend_Filter_Interface + * + * Does a lowercase on the content of the given file + * + * @param string $value Full path of file to change + * @return string The given $value + * @throws Zend_Filter_Exception + */ + public function filter($value) + { + if (!file_exists($value)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!is_writable($value)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("File '$value' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $content = parent::filter($content); + $result = file_put_contents($value, $content); + + if (!$result) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Problem while writing file '$value'"); + } + + return $value; + } +} diff --git a/lib/Zend/Filter/File/Rename.php b/lib/Zend/Filter/File/Rename.php new file mode 100644 index 0000000..718443f --- /dev/null +++ b/lib/Zend/Filter/File/Rename.php @@ -0,0 +1,282 @@ + Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Target file or directory to be renamed + * @param string $target Source filename or directory (deprecated) + * @param bool $overwrite Should existing files be overwritten (deprecated) + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options)) { + $options = array('target' => $options); + } elseif (!is_array($options)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + if (1 < func_num_args()) { + trigger_error('Support for multiple arguments is deprecated in favor of a single options array', E_USER_NOTICE); + $argv = func_get_args(); + array_shift($argv); + $source = array_shift($argv); + $overwrite = false; + if (!empty($argv)) { + $overwrite = array_shift($argv); + } + $options['source'] = $source; + $options['overwrite'] = $overwrite; + } + + $this->setFile($options); + } + + /** + * Returns the files to rename and their new name and location + * + * @return array + */ + public function getFile() + { + return $this->_files; + } + + /** + * Sets a new file or directory as target, deleting existing ones + * + * Array accepts the following keys: + * 'source' => Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Old file or directory to be rewritten + * @return Zend_Filter_File_Rename + */ + public function setFile($options) + { + $this->_files = array(); + $this->addFile($options); + + return $this; + } + + /** + * Adds a new file or directory as target to the existing ones + * + * Array accepts the following keys: + * 'source' => Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Old file or directory to be rewritten + * @return Zend_Filter_File_Rename + */ + public function addFile($options) + { + if (is_string($options)) { + $options = array('target' => $options); + } elseif (!is_array($options)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception ('Invalid options to rename filter provided'); + } + + $this->_convertOptions($options); + + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Renames the file $value to the new name set before + * Returns the file $value, removing all but digit characters + * + * @param string $value Full path of file to change + * @return string The new filename which has been set, or false when there were errors + */ + public function filter($value) + { + $file = $this->_getFileName($value); + if ($file['source'] == $file['target']) { + return $value; + } + + if (!file_exists($file['source'])) { + return $value; + } + + if (($file['overwrite'] == true) and (file_exists($file['target']))) { + unlink($file['target']); + } + + if (file_exists($file['target'])) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. It already exists.", $value)); + } + + $result = rename($file['source'], $file['target']); + + if ($result === true) { + return $file['target']; + } + + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. An error occured while processing the file.", $value)); + } + + /** + * Internal method for creating the file array + * Supports single and nested arrays + * + * @param array $options + * @return array + */ + protected function _convertOptions($options) { + $files = array(); + foreach ($options as $key => $value) { + if (is_array($value)) { + $this->_convertOptions($value); + continue; + } + + switch ($key) { + case "source": + $files['source'] = (string) $value; + break; + + case 'target' : + $files['target'] = (string) $value; + break; + + case 'overwrite' : + $files['overwrite'] = (boolean) $value; + break; + + default: + break; + } + } + + if (empty($files)) { + return $this; + } + + if (empty($files['source'])) { + $files['source'] = '*'; + } + + if (empty($files['target'])) { + $files['target'] = '*'; + } + + if (empty($files['overwrite'])) { + $files['overwrite'] = false; + } + + $found = false; + foreach ($this->_files as $key => $value) { + if ($value['source'] == $files['source']) { + $this->_files[$key] = $files; + $found = true; + } + } + + if (!$found) { + $count = count($this->_files); + $this->_files[$count] = $files; + } + + return $this; + } + + /** + * Internal method to resolve the requested source + * and return all other related parameters + * + * @param string $file Filename to get the informations for + * @return array + */ + protected function _getFileName($file) + { + $rename = array(); + foreach ($this->_files as $value) { + if ($value['source'] == '*') { + if (!isset($rename['source'])) { + $rename = $value; + $rename['source'] = $file; + } + } + + if ($value['source'] == $file) { + $rename = $value; + } + } + + if (!isset($rename['source'])) { + return $file; + } + + if (!isset($rename['target']) or ($rename['target'] == '*')) { + $rename['target'] = $rename['source']; + } + + if (is_dir($rename['target'])) { + $name = basename($rename['source']); + $last = $rename['target'][strlen($rename['target']) - 1]; + if (($last != '/') and ($last != '\\')) { + $rename['target'] .= DIRECTORY_SEPARATOR; + } + + $rename['target'] .= $name; + } + + return $rename; + } +} diff --git a/lib/Zend/Filter/File/UpperCase.php b/lib/Zend/Filter/File/UpperCase.php new file mode 100644 index 0000000..9501e9e --- /dev/null +++ b/lib/Zend/Filter/File/UpperCase.php @@ -0,0 +1,84 @@ +setEncoding($options); + } + } + + /** + * Defined by Zend_Filter_Interface + * + * Does a lowercase on the content of the given file + * + * @param string $value Full path of file to change + * @return string The given $value + * @throws Zend_Filter_Exception + */ + public function filter($value) + { + if (!file_exists($value)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!is_writable($value)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("File '$value' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $content = parent::filter($content); + $result = file_put_contents($value, $content); + + if (!$result) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Problem while writing file '$value'"); + } + + return $value; + } +} diff --git a/lib/Zend/Filter/HtmlEntities.php b/lib/Zend/Filter/HtmlEntities.php new file mode 100644 index 0000000..e9887a2 --- /dev/null +++ b/lib/Zend/Filter/HtmlEntities.php @@ -0,0 +1,122 @@ +_quoteStyle = $quoteStyle; + $this->_charSet = $charSet; + } + + /** + * Returns the quoteStyle option + * + * @return integer + */ + public function getQuoteStyle() + { + return $this->_quoteStyle; + } + + /** + * Sets the quoteStyle option + * + * @param integer $quoteStyle + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setQuoteStyle($quoteStyle) + { + $this->_quoteStyle = $quoteStyle; + return $this; + } + + /** + * Returns the charSet option + * + * @return string + */ + public function getCharSet() + { + return $this->_charSet; + } + + /** + * Sets the charSet option + * + * @param string $charSet + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setCharSet($charSet) + { + $this->_charSet = $charSet; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to their corresponding HTML entity + * equivalents where they exist + * + * @param string $value + * @return string + */ + public function filter($value) + { + return htmlentities((string) $value, $this->_quoteStyle, $this->_charSet); + } +} diff --git a/lib/Zend/Filter/Inflector.php b/lib/Zend/Filter/Inflector.php new file mode 100644 index 0000000..4e7e493 --- /dev/null +++ b/lib/Zend/Filter/Inflector.php @@ -0,0 +1,497 @@ +setConfig($target); + } else { + if ((null !== $target) && is_string($target)) { + $this->setTarget($target); + } + + if (null !== $rules) { + $this->addRules($rules); + } + + if ($throwTargetExceptionsOn !== null) { + $this->setThrowTargetExceptionsOn($throwTargetExceptionsOn); + } + + if ($targetReplacementIdentifer != '') { + $this->setTargetReplacementIdentifier($targetReplacementIdentifer); + } + } + } + + /** + * Retreive PluginLoader + * + * @return Zend_Loader_PluginLoader_Interface + */ + public function getPluginLoader() + { + if (!$this->_pluginLoader instanceof Zend_Loader_PluginLoader_Interface) { + $this->_pluginLoader = new Zend_Loader_PluginLoader(array('Zend_Filter_' => 'Zend/Filter/'), __CLASS__); + } + + return $this->_pluginLoader; + } + + /** + * Set PluginLoader + * + * @param Zend_Loader_PluginLoader_Interface $pluginLoader + * @return Zend_Filter_Inflector + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $pluginLoader) + { + $this->_pluginLoader = $pluginLoader; + return $this; + } + + /** + * Use Zend_Config object to set object state + * + * @param Zend_Config $config + * @return Zend_Filter_Inflector + */ + public function setConfig(Zend_Config $config) + { + foreach ($config as $key => $value) { + switch ($key) { + case 'target': + $this->setTarget($value); + break; + case 'filterPrefixPath': + if (is_scalar($value)) { + break; + } + $paths = $value->toArray(); + foreach ($paths as $prefix => $path) { + $this->addFilterPrefixPath($prefix, $path); + } + break; + case 'throwTargetExceptionsOn': + $this->setThrowTargetExceptionsOn($value); + break; + case 'targetReplacementIdentifier': + $this->setTargetReplacementIdentifier($value); + break; + case 'rules': + $this->addRules($value->toArray()); + break; + default: + break; + } + } + return $this; + } + + /** + * Convienence method to add prefix and path to PluginLoader + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Inflector + */ + public function addFilterPrefixPath($prefix, $path) + { + $this->getPluginLoader()->addPrefixPath($prefix, $path); + return $this; + } + + /** + * Set Whether or not the inflector should throw an exception when a replacement + * identifier is still found within an inflected target. + * + * @param bool $throwTargetExceptions + * @return Zend_Filter_Inflector + */ + public function setThrowTargetExceptionsOn($throwTargetExceptionsOn) + { + $this->_throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false; + return $this; + } + + /** + * Will exceptions be thrown? + * + * @return bool + */ + public function isThrowTargetExceptionsOn() + { + return $this->_throwTargetExceptionsOn; + } + + /** + * Set the Target Replacement Identifier, by default ':' + * + * @param string $targetReplacementIdentifier + * @return Zend_Filter_Inflector + */ + public function setTargetReplacementIdentifier($targetReplacementIdentifier) + { + $this->_targetReplacementIdentifier = (string) $targetReplacementIdentifier; + return $this; + } + + /** + * Get Target Replacement Identifier + * + * @return string + */ + public function getTargetReplacementIdentifier() + { + return $this->_targetReplacementIdentifier; + } + + /** + * Set a Target + * ex: 'scripts/:controller/:action.:suffix' + * + * @param string + * @return Zend_Filter_Inflector + */ + public function setTarget($target) + { + $this->_target = (string) $target; + return $this; + } + + /** + * Retrieve target + * + * @return string + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Set Target Reference + * + * @param reference $target + * @return Zend_Filter_Inflector + */ + public function setTargetReference(&$target) + { + $this->_target =& $target; + return $this; + } + + /** + * SetRules() is the same as calling addRules() with the exception that it + * clears the rules before adding them. + * + * @param array $rules + * @return Zend_Filter_Inflector + */ + public function setRules(Array $rules) + { + $this->clearRules(); + $this->addRules($rules); + return $this; + } + + /** + * AddRules(): multi-call to setting filter rules. + * + * If prefixed with a ":" (colon), a filter rule will be added. If not + * prefixed, a static replacement will be added. + * + * ex: + * array( + * ':controller' => array('CamelCaseToUnderscore','StringToLower'), + * ':action' => array('CamelCaseToUnderscore','StringToLower'), + * 'suffix' => 'phtml' + * ); + * + * @param array + * @return Zend_Filter_Inflector + */ + public function addRules(Array $rules) + { + $keys = array_keys($rules); + foreach ($keys as $spec) { + if ($spec[0] == ':') { + $this->addFilterRule($spec, $rules[$spec]); + } else { + $this->setStaticRule($spec, $rules[$spec]); + } + } + + return $this; + } + + /** + * Get rules + * + * By default, returns all rules. If a $spec is provided, will return those + * rules if found, false otherwise. + * + * @param string $spec + * @return array|false + */ + public function getRules($spec = null) + { + if (null !== $spec) { + $spec = $this->_normalizeSpec($spec); + if (isset($this->_rules[$spec])) { + return $this->_rules[$spec]; + } + return false; + } + + return $this->_rules; + } + + /** + * getRule() returns a rule set by setFilterRule(), a numeric index must be provided + * + * @param string $spec + * @param int $index + * @return Zend_Filter_Interface|false + */ + public function getRule($spec, $index) + { + $spec = $this->_normalizeSpec($spec); + if (isset($this->_rules[$spec]) && is_array($this->_rules[$spec])) { + if (isset($this->_rules[$spec][$index])) { + return $this->_rules[$spec][$index]; + } + } + return false; + } + + /** + * ClearRules() clears the rules currently in the inflector + * + * @return Zend_Filter_Inflector + */ + public function clearRules() + { + $this->_rules = array(); + return $this; + } + + /** + * Set a filtering rule for a spec. $ruleSet can be a string, Filter object + * or an array of strings or filter objects. + * + * @param string $spec + * @param array|string|Zend_Filter_Interface $ruleSet + * @return Zend_Filter_Inflector + */ + public function setFilterRule($spec, $ruleSet) + { + $spec = $this->_normalizeSpec($spec); + $this->_rules[$spec] = array(); + return $this->addFilterRule($spec, $ruleSet); + } + + /** + * Add a filter rule for a spec + * + * @param mixed $spec + * @param mixed $ruleSet + * @return void + */ + public function addFilterRule($spec, $ruleSet) + { + $spec = $this->_normalizeSpec($spec); + if (!isset($this->_rules[$spec])) { + $this->_rules[$spec] = array(); + } + if (!is_array($ruleSet)) { + $ruleSet = array($ruleSet); + } + foreach ($ruleSet as $rule) { + $this->_rules[$spec][] = $this->_getRule($rule); + } + return $this; + } + + /** + * Set a static rule for a spec. This is a single string value + * + * @param string $name + * @param string $value + * @return Zend_Filter_Inflector + */ + public function setStaticRule($name, $value) + { + $name = $this->_normalizeSpec($name); + $this->_rules[$name] = (string) $value; + return $this; + } + + /** + * Set Static Rule Reference. + * + * This allows a consuming class to pass a property or variable + * in to be referenced when its time to build the output string from the + * target. + * + * @param string $name + * @param mixed $reference + * @return Zend_Filter_Inflector + */ + public function setStaticRuleReference($name, &$reference) + { + $name = $this->_normalizeSpec($name); + $this->_rules[$name] =& $reference; + return $this; + } + + /** + * Inflect + * + * @param string|array $source + * @return string + */ + public function filter($source) + { + // clean source + foreach ( (array) $source as $sourceName => $sourceValue) { + $source[ltrim($sourceName, ':')] = $sourceValue; + } + + $pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#'); + $processedParts = array(); + + foreach ($this->_rules as $ruleName => $ruleValue) { + if (isset($source[$ruleName])) { + if (is_string($ruleValue)) { + // overriding the set rule + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]); + } elseif (is_array($ruleValue)) { + $processedPart = $source[$ruleName]; + foreach ($ruleValue as $ruleFilter) { + $processedPart = $ruleFilter->filter($processedPart); + } + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart); + } + } elseif (is_string($ruleValue)) { + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue); + } + } + + // all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences + $inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target); + + if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception('A replacement identifier ' . $this->_targetReplacementIdentifier . ' was found inside the inflected target, perhaps a rule was not satisfied with a target source? Unsatisfied inflected target: ' . $inflectedTarget); + } + + return $inflectedTarget; + } + + /** + * Normalize spec string + * + * @param string $spec + * @return string + */ + protected function _normalizeSpec($spec) + { + return ltrim((string) $spec, ':&'); + } + + /** + * Resolve named filters and convert them to filter objects. + * + * @param string $rule + * @return Zend_Filter_Interface + */ + protected function _getRule($rule) + { + if ($rule instanceof Zend_Filter_Interface) { + return $rule; + } + + $rule = (string) $rule; + + $className = $this->getPluginLoader()->load($rule); + $ruleObject = new $className(); + if (!$ruleObject instanceof Zend_Filter_Interface) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception('No class named ' . $rule . ' implementing Zend_Filter_Interface could be found'); + } + + return $ruleObject; + } + +} diff --git a/lib/Zend/Filter/Input.php b/lib/Zend/Filter/Input.php new file mode 100644 index 0000000..a6782a3 --- /dev/null +++ b/lib/Zend/Filter/Input.php @@ -0,0 +1,926 @@ + false, + self::BREAK_CHAIN => false, + self::ESCAPE_FILTER => 'HtmlEntities', + self::MISSING_MESSAGE => "Field '%field%' is required by rule '%rule%', but the field is missing", + self::NOT_EMPTY_MESSAGE => "You must give a non-empty value for field '%field%'", + self::PRESENCE => self::PRESENCE_OPTIONAL + ); + + /** + * @var boolean Set to False initially, this is set to True after the + * input data have been processed. Reset to False in setData() method. + */ + protected $_processed = false; + + /** + * @param array $filterRules + * @param array $validatorRules + * @param array $data OPTIONAL + * @param array $options OPTIONAL + */ + public function __construct($filterRules, $validatorRules, array $data = null, array $options = null) + { + if ($options) { + $this->setOptions($options); + } + + $this->_filterRules = (array) $filterRules; + $this->_validatorRules = (array) $validatorRules; + + if ($data) { + $this->setData($data); + } + } + + /** + * @param mixed $namespaces + * @return Zend_Filter_Input + * @deprecated since 1.5.0RC1 - use addFilterPrefixPath() or addValidatorPrefixPath instead. + */ + public function addNamespace($namespaces) + { + if (!is_array($namespaces)) { + $namespaces = array($namespaces); + } + + foreach ($namespaces as $namespace) { + $prefix = $namespace; + $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix); + $this->addFilterPrefixPath($prefix, $path); + $this->addValidatorPrefixPath($prefix, $path); + } + + return $this; + } + + /** + * Add prefix path for all elements + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Input + */ + public function addFilterPrefixPath($prefix, $path) + { + $this->getPluginLoader(self::FILTER)->addPrefixPath($prefix, $path); + + return $this; + } + + /** + * Add prefix path for all elements + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Input + */ + public function addValidatorPrefixPath($prefix, $path) + { + $this->getPluginLoader(self::VALIDATE)->addPrefixPath($prefix, $path); + + return $this; + } + + /** + * Set plugin loaders for use with decorators and elements + * + * @param Zend_Loader_PluginLoader_Interface $loader + * @param string $type 'filter' or 'validate' + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception on invalid type + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) + { + $type = strtolower($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $this->_loaders[$type] = $loader; + return $this; + default: + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); + } + + return $this; + } + + /** + * Retrieve plugin loader for given type + * + * $type may be one of: + * - filter + * - validator + * + * If a plugin loader does not exist for the given type, defaults are + * created. + * + * @param string $type 'filter' or 'validate' + * @return Zend_Loader_PluginLoader_Interface + * @throws Zend_Filter_Exception on invalid type + */ + public function getPluginLoader($type) + { + $type = strtolower($type); + if (!isset($this->_loaders[$type])) { + switch ($type) { + case self::FILTER: + $prefixSegment = 'Zend_Filter_'; + $pathSegment = 'Zend/Filter/'; + break; + case self::VALIDATE: + $prefixSegment = 'Zend_Validate_'; + $pathSegment = 'Zend/Validate/'; + break; + default: + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + + require_once 'Zend/Loader/PluginLoader.php'; + $this->_loaders[$type] = new Zend_Loader_PluginLoader( + array($prefixSegment => $pathSegment) + ); + } + + return $this->_loaders[$type]; + } + + /** + * @return array + */ + public function getMessages() + { + $this->_process(); + return array_merge($this->_invalidMessages, $this->_missingFields); + } + + /** + * @return array + */ + public function getErrors() + { + $this->_process(); + return $this->_invalidErrors; + } + + /** + * @return array + */ + public function getInvalid() + { + $this->_process(); + return $this->_invalidMessages; + } + + /** + * @return array + */ + public function getMissing() + { + $this->_process(); + return $this->_missingFields; + } + + /** + * @return array + */ + public function getUnknown() + { + $this->_process(); + return $this->_unknownFields; + } + + /** + * @param string $fieldName OPTIONAL + * @return mixed + */ + public function getEscaped($fieldName = null) + { + $this->_process(); + $this->_getDefaultEscapeFilter(); + + if ($fieldName === null) { + return $this->_escapeRecursive($this->_validFields); + } + if (array_key_exists($fieldName, $this->_validFields)) { + return $this->_escapeRecursive($this->_validFields[$fieldName]); + } + return null; + } + + /** + * @param mixed $value + * @return mixed + */ + protected function _escapeRecursive($data) + { + if (!is_array($data)) { + return $this->_getDefaultEscapeFilter()->filter($data); + } + foreach ($data as &$element) { + $element = $this->_escapeRecursive($element); + } + return $data; + } + + /** + * @param string $fieldName OPTIONAL + * @return mixed + */ + public function getUnescaped($fieldName = null) + { + $this->_process(); + if ($fieldName === null) { + return $this->_validFields; + } + if (array_key_exists($fieldName, $this->_validFields)) { + return $this->_validFields[$fieldName]; + } + return null; + } + + /** + * @param string $fieldName + * @return mixed + */ + public function __get($fieldName) + { + return $this->getEscaped($fieldName); + } + + /** + * @return boolean + */ + public function hasInvalid() + { + $this->_process(); + return !(empty($this->_invalidMessages)); + } + + /** + * @return boolean + */ + public function hasMissing() + { + $this->_process(); + return !(empty($this->_missingFields)); + } + + /** + * @return boolean + */ + public function hasUnknown() + { + $this->_process(); + return !(empty($this->_unknownFields)); + } + + /** + * @return boolean + */ + public function hasValid() + { + $this->_process(); + return !(empty($this->_validFields)); + } + + /** + * @param string $fieldName + * @return boolean + */ + public function isValid($fieldName = null) + { + $this->_process(); + if ($fieldName === null) { + return !($this->hasMissing() || $this->hasInvalid()); + } + return array_key_exists($fieldName, $this->_validFields); + } + + /** + * @param string $fieldName + * @return boolean + */ + public function __isset($fieldName) + { + $this->_process(); + return isset($this->_validFields[$fieldName]); + } + + /** + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception + */ + public function process() + { + $this->_process(); + if ($this->hasInvalid()) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Input has invalid fields"); + } + if ($this->hasMissing()) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Input has missing fields"); + } + + return $this; + } + + /** + * @param array $data + * @return Zend_Filter_Input + */ + public function setData(array $data) + { + $this->_data = $data; + + /** + * Reset to initial state + */ + $this->_validFields = array(); + $this->_invalidMessages = array(); + $this->_invalidErrors = array(); + $this->_missingFields = array(); + $this->_unknownFields = array(); + + $this->_processed = false; + + return $this; + } + + /** + * @param mixed $escapeFilter + * @return Zend_Filter_Interface + */ + public function setDefaultEscapeFilter($escapeFilter) + { + if (is_string($escapeFilter) || is_array($escapeFilter)) { + $escapeFilter = $this->_getFilter($escapeFilter); + } + if (!$escapeFilter instanceof Zend_Filter_Interface) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception('Escape filter specified does not implement Zend_Filter_Interface'); + } + $this->_defaultEscapeFilter = $escapeFilter; + return $escapeFilter; + } + + /** + * @param array $options + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception if an unknown option is given + */ + public function setOptions(array $options) + { + foreach ($options as $option => $value) { + switch ($option) { + case self::ESCAPE_FILTER: + $this->setDefaultEscapeFilter($value); + break; + case self::INPUT_NAMESPACE: + $this->addNamespace($value); + break; + case self::ALLOW_EMPTY: + case self::BREAK_CHAIN: + case self::MISSING_MESSAGE: + case self::NOT_EMPTY_MESSAGE: + case self::PRESENCE: + $this->_defaults[$option] = $value; + break; + default: + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Unknown option '$option'"); + break; + } + } + + return $this; + } + + /* + * Protected methods + */ + + /** + * @return void + */ + protected function _filter() + { + foreach ($this->_filterRules as $ruleName => &$filterRule) { + /** + * Make sure we have an array representing this filter chain. + * Don't typecast to (array) because it might be a Zend_Filter object + */ + if (!is_array($filterRule)) { + $filterRule = array($filterRule); + } + + /** + * Filters are indexed by integer, metacommands are indexed by string. + * Pick out the filters. + */ + $filterList = array(); + foreach ($filterRule as $key => $value) { + if (is_int($key)) { + $filterList[] = $value; + } + } + + /** + * Use defaults for filter metacommands. + */ + $filterRule[self::RULE] = $ruleName; + if (!isset($filterRule[self::FIELDS])) { + $filterRule[self::FIELDS] = $ruleName; + } + + /** + * Load all the filter classes and add them to the chain. + */ + if (!isset($filterRule[self::FILTER_CHAIN])) { + $filterRule[self::FILTER_CHAIN] = new Zend_Filter(); + foreach ($filterList as $filter) { + if (is_string($filter) || is_array($filter)) { + $filter = $this->_getFilter($filter); + } + $filterRule[self::FILTER_CHAIN]->addFilter($filter); + } + } + + /** + * If the ruleName is the special wildcard rule, + * then apply the filter chain to all input data. + * Else just process the field named by the rule. + */ + if ($ruleName == self::RULE_WILDCARD) { + foreach (array_keys($this->_data) as $field) { + $this->_filterRule(array_merge($filterRule, array(self::FIELDS => $field))); + } + } else { + $this->_filterRule($filterRule); + } + } + } + + /** + * @param array $filterRule + * @return void + */ + protected function _filterRule(array $filterRule) + { + $field = $filterRule[self::FIELDS]; + if (!array_key_exists($field, $this->_data)) { + return; + } + if (is_array($this->_data[$field])) { + foreach ($this->_data[$field] as $key => $value) { + $this->_data[$field][$key] = $filterRule[self::FILTER_CHAIN]->filter($value); + } + } else { + $this->_data[$field] = + $filterRule[self::FILTER_CHAIN]->filter($this->_data[$field]); + } + } + + /** + * @return Zend_Filter_Interface + */ + protected function _getDefaultEscapeFilter() + { + if ($this->_defaultEscapeFilter !== null) { + return $this->_defaultEscapeFilter; + } + return $this->setDefaultEscapeFilter($this->_defaults[self::ESCAPE_FILTER]); + } + + /** + * @param string $rule + * @param string $field + * @return string + */ + protected function _getMissingMessage($rule, $field) + { + $message = $this->_defaults[self::MISSING_MESSAGE]; + $message = str_replace('%rule%', $rule, $message); + $message = str_replace('%field%', $field, $message); + return $message; + } + + /** + * @return string + */ + protected function _getNotEmptyMessage($rule, $field) + { + $message = $this->_defaults[self::NOT_EMPTY_MESSAGE]; + $message = str_replace('%rule%', $rule, $message); + $message = str_replace('%field%', $field, $message); + return $message; + } + + /** + * @return void + */ + protected function _process() + { + if ($this->_processed === false) { + $this->_filter(); + $this->_validate(); + $this->_processed = true; + } + } + + /** + * @return void + */ + protected function _validate() + { + /** + * Special case: if there are no validators, treat all fields as valid. + */ + if (!$this->_validatorRules) { + $this->_validFields = $this->_data; + $this->_data = array(); + return; + } + + foreach ($this->_validatorRules as $ruleName => &$validatorRule) { + /** + * Make sure we have an array representing this validator chain. + * Don't typecast to (array) because it might be a Zend_Validate object + */ + if (!is_array($validatorRule)) { + $validatorRule = array($validatorRule); + } + + /** + * Validators are indexed by integer, metacommands are indexed by string. + * Pick out the validators. + */ + $validatorList = array(); + foreach ($validatorRule as $key => $value) { + if (is_int($key)) { + $validatorList[] = $value; + } + } + + /** + * Use defaults for validation metacommands. + */ + $validatorRule[self::RULE] = $ruleName; + if (!isset($validatorRule[self::FIELDS])) { + $validatorRule[self::FIELDS] = $ruleName; + } + if (!isset($validatorRule[self::BREAK_CHAIN])) { + $validatorRule[self::BREAK_CHAIN] = $this->_defaults[self::BREAK_CHAIN]; + } + if (!isset($validatorRule[self::PRESENCE])) { + $validatorRule[self::PRESENCE] = $this->_defaults[self::PRESENCE]; + } + if (!isset($validatorRule[self::ALLOW_EMPTY])) { + $validatorRule[self::ALLOW_EMPTY] = $this->_defaults[self::ALLOW_EMPTY]; + } + if (!isset($validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array(); + } else if (!is_array($validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]); + } else if (!array_intersect_key($validatorList, $validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]); + } + + /** + * Load all the validator classes and add them to the chain. + */ + if (!isset($validatorRule[self::VALIDATOR_CHAIN])) { + $validatorRule[self::VALIDATOR_CHAIN] = new Zend_Validate(); + $i = 0; + foreach ($validatorList as $validator) { + + if (is_string($validator) || is_array($validator)) { + $validator = $this->_getValidator($validator); + } + if (isset($validatorRule[self::MESSAGES][$i])) { + $value = $validatorRule[self::MESSAGES][$i]; + if (is_array($value)) { + $validator->setMessages($value); + } else { + $validator->setMessage($value); + } + } + + $validatorRule[self::VALIDATOR_CHAIN]->addValidator($validator, $validatorRule[self::BREAK_CHAIN]); + ++$i; + } + $validatorRule[self::VALIDATOR_CHAIN_COUNT] = $i; + } + + /** + * If the ruleName is the special wildcard rule, + * then apply the validator chain to all input data. + * Else just process the field named by the rule. + */ + if ($ruleName == self::RULE_WILDCARD) { + foreach (array_keys($this->_data) as $field) { + $this->_validateRule(array_merge($validatorRule, array(self::FIELDS => $field))); + } + } else { + $this->_validateRule($validatorRule); + } + } + + /** + * Unset fields in $_data that have been added to other arrays. + * We have to wait until all rules have been processed because + * a given field may be referenced by multiple rules. + */ + foreach (array_merge(array_keys($this->_missingFields), array_keys($this->_invalidMessages)) as $rule) { + foreach ((array) $this->_validatorRules[$rule][self::FIELDS] as $field) { + unset($this->_data[$field]); + } + } + foreach ($this->_validFields as $field => $value) { + unset($this->_data[$field]); + } + + /** + * Anything left over in $_data is an unknown field. + */ + $this->_unknownFields = $this->_data; + } + + /** + * @param array $validatorRule + * @return void + */ + protected function _validateRule(array $validatorRule) + { + /** + * Get one or more data values from input, and check for missing fields. + * Apply defaults if fields are missing. + */ + $data = array(); + foreach ((array) $validatorRule[self::FIELDS] as $field) { + if (array_key_exists($field, $this->_data)) { + $data[$field] = $this->_data[$field]; + } else + if (array_key_exists(self::DEFAULT_VALUE, $validatorRule)) { + if (is_array($validatorRule[self::DEFAULT_VALUE])) { + $key = array_search($field, (array) $validatorRule[self::FIELDS]); + if (array_key_exists($key, $validatorRule[self::DEFAULT_VALUE])) { + $data[$field] = $validatorRule[self::DEFAULT_VALUE][$key]; + } + } else { + $data[$field] = $validatorRule[self::DEFAULT_VALUE]; + } + } else + if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) { + $this->_missingFields[$validatorRule[self::RULE]][] = + $this->_getMissingMessage($validatorRule[self::RULE], $field); + } + } + + /** + * If any required fields are missing, break the loop. + */ + if (isset($this->_missingFields[$validatorRule[self::RULE]]) && count($this->_missingFields[$validatorRule[self::RULE]]) > 0) { + return; + } + + /** + * Evaluate the inputs against the validator chain. + */ + if (count((array) $validatorRule[self::FIELDS]) > 1) { + if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($data)) { + $this->_invalidMessages[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getMessages(); + $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getErrors(); + return; + } + } else { + $failed = false; + foreach ($data as $fieldKey => $field) { + if (!is_array($field)) { + $field = array($field); + } + foreach ($field as $value) { + if (empty($value)) { + if ($validatorRule[self::ALLOW_EMPTY] == true) { + continue; + } + if ($validatorRule[self::VALIDATOR_CHAIN_COUNT] == 0) { + $notEmptyValidator = $this->_getValidator('NotEmpty'); + $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldKey)); + $validatorRule[self::VALIDATOR_CHAIN]->addValidator($notEmptyValidator); + } + } + if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($value)) { + $this->_invalidMessages[$validatorRule[self::RULE]] = + $validatorRule[self::VALIDATOR_CHAIN]->getMessages(); + $this->_invalidErrors[$validatorRule[self::RULE]] = + $validatorRule[self::VALIDATOR_CHAIN]->getErrors(); + unset($this->_validFields[$fieldKey]); + $failed = true; + if ($validatorRule[self::BREAK_CHAIN]) { + return; + } + } + } + } + if ($failed) { + return; + } + } + + /** + * If we got this far, the inputs for this rule pass validation. + */ + foreach ((array) $validatorRule[self::FIELDS] as $field) { + if (array_key_exists($field, $data)) { + $this->_validFields[$field] = $data[$field]; + } + } + } + + /** + * @param mixed $classBaseName + * @return Zend_Filter_Interface + */ + protected function _getFilter($classBaseName) + { + return $this->_getFilterOrValidator(self::FILTER, $classBaseName); + } + + /** + * @param mixed $classBaseName + * @return Zend_Validate_Interface + */ + protected function _getValidator($classBaseName) + { + return $this->_getFilterOrValidator(self::VALIDATE, $classBaseName); + } + + /** + * @param string $type + * @param mixed $classBaseName + * @return Zend_Filter_Interface|Zend_Validate_Interface + * @throws Zend_Filter_Exception + */ + protected function _getFilterOrValidator($type, $classBaseName) + { + $args = array(); + + if (is_array($classBaseName)) { + $args = $classBaseName; + $classBaseName = array_shift($args); + } + + $interfaceName = 'Zend_' . ucfirst($type) . '_Interface'; + $className = $this->getPluginLoader($type)->load(ucfirst($classBaseName)); + + $class = new ReflectionClass($className); + + if (!$class->implementsInterface($interfaceName)) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception("Class based on basename '$classBaseName' must implement the '$interfaceName' interface"); + } + + if ($class->hasMethod('__construct')) { + $object = $class->newInstanceArgs($args); + } else { + $object = $class->newInstance(); + } + + return $object; + } + +} diff --git a/lib/Zend/Filter/Int.php b/lib/Zend/Filter/Int.php new file mode 100644 index 0000000..39c3d6d --- /dev/null +++ b/lib/Zend/Filter/Int.php @@ -0,0 +1,50 @@ +setMatchPattern($matchPattern); + } + + if ($replacement) { + $this->setReplacement($replacement); + } + } + + /** + * Set the match pattern for the regex being called within filter() + * + * @param mixed $match - same as the first argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setMatchPattern($match) + { + $this->_matchPattern = $match; + return $this; + } + + /** + * Get currently set match pattern + * + * @return string + */ + public function getMatchPattern() + { + return $this->_matchPattern; + } + + /** + * Set the Replacement pattern/string for the preg_replace called in filter + * + * @param mixed $replacement - same as the second argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setReplacement($replacement) + { + $this->_replacement = $replacement; + return $this; + } + + /** + * Get currently set replacement value + * + * @return string + */ + public function getReplacement() + { + return $this->_replacement; + } + + /** + * Perform regexp replacement as filter + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_matchPattern == null) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.'); + } + + return preg_replace($this->_matchPattern, $this->_replacement, $value); + } + +} diff --git a/lib/Zend/Filter/RealPath.php b/lib/Zend/Filter/RealPath.php new file mode 100644 index 0000000..f94de32 --- /dev/null +++ b/lib/Zend/Filter/RealPath.php @@ -0,0 +1,50 @@ +_encoding = $encoding; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to lowercase as necessary + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_encoding) { + return mb_strtolower((string) $value, $this->_encoding); + } + + return strtolower((string) $value); + } +} diff --git a/lib/Zend/Filter/StringToUpper.php b/lib/Zend/Filter/StringToUpper.php new file mode 100644 index 0000000..bd68aae --- /dev/null +++ b/lib/Zend/Filter/StringToUpper.php @@ -0,0 +1,76 @@ +_encoding = $encoding; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to uppercase as necessary + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_encoding) { + return mb_strtoupper((string) $value, $this->_encoding); + } + + return strtoupper((string) $value); + } +} diff --git a/lib/Zend/Filter/StringTrim.php b/lib/Zend/Filter/StringTrim.php new file mode 100644 index 0000000..af22900 --- /dev/null +++ b/lib/Zend/Filter/StringTrim.php @@ -0,0 +1,97 @@ +_charList = $charList; + } + + /** + * Returns the charList option + * + * @return string|null + */ + public function getCharList() + { + return $this->_charList; + } + + /** + * Sets the charList option + * + * @param string|null $charList + * @return Zend_Filter_StringTrim Provides a fluent interface + */ + public function setCharList($charList) + { + $this->_charList = $charList; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value with characters stripped from the beginning and end + * + * @param string $value + * @return string + */ + public function filter($value) + { + if (null === $this->_charList) { + return trim((string) $value); + } else { + return trim((string) $value, $this->_charList); + } + } +} diff --git a/lib/Zend/Filter/StripNewlines.php b/lib/Zend/Filter/StripNewlines.php new file mode 100644 index 0000000..b2dd042 --- /dev/null +++ b/lib/Zend/Filter/StripNewlines.php @@ -0,0 +1,48 @@ +setTagsAllowed($tagsAllowed); + $this->setAttributesAllowed($attributesAllowed); + $this->commentsAllowed = (boolean) $commentsAllowed; + } + + /** + * Returns the tagsAllowed option + * + * @return array + */ + public function getTagsAllowed() + { + return $this->_tagsAllowed; + } + + /** + * Sets the tagsAllowed option + * + * @param array|string $tagsAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setTagsAllowed($tagsAllowed) + { + if (!is_array($tagsAllowed)) { + $tagsAllowed = array($tagsAllowed); + } + + foreach ($tagsAllowed as $index => $element) { + // If the tag was provided without attributes + if (is_int($index) && is_string($element)) { + // Canonicalize the tag name + $tagName = strtolower($element); + // Store the tag as allowed with no attributes + $this->_tagsAllowed[$tagName] = array(); + } + // Otherwise, if a tag was provided with attributes + else if (is_string($index) && (is_array($element) || is_string($element))) { + // Canonicalize the tag name + $tagName = strtolower($index); + // Canonicalize the attributes + if (is_string($element)) { + $element = array($element); + } + // Store the tag as allowed with the provided attributes + $this->_tagsAllowed[$tagName] = array(); + foreach ($element as $attribute) { + if (is_string($attribute)) { + // Canonicalize the attribute name + $attributeName = strtolower($attribute); + $this->_tagsAllowed[$tagName][$attributeName] = null; + } + } + } + } + + return $this; + } + + /** + * Returns the attributesAllowed option + * + * @return array + */ + public function getAttributesAllowed() + { + return $this->_attributesAllowed; + } + + /** + * Sets the attributesAllowed option + * + * @param array|string $attributesAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setAttributesAllowed($attributesAllowed) + { + if (!is_array($attributesAllowed)) { + $attributesAllowed = array($attributesAllowed); + } + + // Store each attribute as allowed + foreach ($attributesAllowed as $attribute) { + if (is_string($attribute)) { + // Canonicalize the attribute name + $attributeName = strtolower($attribute); + $this->_attributesAllowed[$attributeName] = null; + } + } + + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * @todo improve docblock descriptions + * + * @param string $value + * @return string + */ + public function filter($value) + { + $valueCopy = (string) $value; + + // If comments are allowed, then replace them with unique identifiers + if ($this->commentsAllowed) { + preg_match_all('/<\!--.*?--\s*>/s' , (string) $valueCopy, $matches); + $comments = array_unique($matches[0]); + foreach ($comments as $k => $v) { + $valueCopy = str_replace($v, self::UNIQUE_ID_PREFIX . $k, $valueCopy); + } + } + + // Initialize accumulator for filtered data + $dataFiltered = ''; + // Parse the input data iteratively as regular pre-tag text followed by a + // tag; either may be empty strings + preg_match_all('/([^<]*)(]*>?)/', (string) $valueCopy, $matches); + // Iterate over each set of matches + foreach ($matches[1] as $index => $preTag) { + // If the pre-tag text is non-empty, strip any ">" characters from it + if (strlen($preTag)) { + $preTag = str_replace('>', '', $preTag); + } + // If a tag exists in this match, then filter the tag + $tag = $matches[2][$index]; + if (strlen($tag)) { + $tagFiltered = $this->_filterTag($tag); + } else { + $tagFiltered = ''; + } + // Add the filtered pre-tag text and filtered tag to the data buffer + $dataFiltered .= $preTag . $tagFiltered; + } + + // If comments are allowed, then replace the unique identifiers with the corresponding comments + if ($this->commentsAllowed) { + foreach ($comments as $k => $v) { + $dataFiltered = str_replace(self::UNIQUE_ID_PREFIX . $k, $v, $dataFiltered); + } + } + + // Return the filtered data + return $dataFiltered; + } + + /** + * Filters a single tag against the current option settings + * + * @param string $tag + * @return string + */ + protected function _filterTag($tag) + { + // Parse the tag into: + // 1. a starting delimiter (mandatory) + // 2. a tag name (if available) + // 3. a string of attributes (if available) + // 4. an ending delimiter (if available) + $isMatch = preg_match('~()|[^/>])*)(/?>)~', $tag, $matches); + + // If the tag does not match, then strip the tag entirely + if (!$isMatch) { + return ''; + } + + // Save the matches to more meaningfully named variables + $tagStart = $matches[1]; + $tagName = strtolower($matches[2]); + $tagAttributes = $matches[3]; + $tagEnd = $matches[5]; + + // If the tag is not an allowed tag, then remove the tag entirely + if (!isset($this->_tagsAllowed[$tagName])) { + return ''; + } + + // Trim the attribute string of whitespace at the ends + $tagAttributes = trim($tagAttributes); + + // If there are non-whitespace characters in the attribute string + if (strlen($tagAttributes)) { + // Parse iteratively for well-formed attributes + preg_match_all('/(\w+)\s*=\s*(?:(")(.*?)"|(\')(.*?)\')/s', $tagAttributes, $matches); + + // Initialize valid attribute accumulator + $tagAttributes = ''; + + // Iterate over each matched attribute + foreach ($matches[1] as $index => $attributeName) { + $attributeName = strtolower($attributeName); + $attributeDelimiter = $matches[2][$index]; + $attributeValue = $matches[3][$index]; + + // If the attribute is not allowed, then remove it entirely + if (!array_key_exists($attributeName, $this->_tagsAllowed[$tagName]) + && !array_key_exists($attributeName, $this->_attributesAllowed)) { + continue; + } + // Add the attribute to the accumulator + $tagAttributes .= " $attributeName=" . $attributeDelimiter + . $attributeValue . $attributeDelimiter; + } + } + + // Reconstruct tags ending with "/>" as backwards-compatible XHTML tag + if (strpos($tagEnd, '/') !== false) { + $tagEnd = " $tagEnd"; + } + + // Return the filtered tag + return $tagStart . $tagName . $tagAttributes . $tagEnd; + } +} diff --git a/lib/Zend/Filter/Word/CamelCaseToDash.php b/lib/Zend/Filter/Word/CamelCaseToDash.php new file mode 100644 index 0000000..c4717f2 --- /dev/null +++ b/lib/Zend/Filter/Word/CamelCaseToDash.php @@ -0,0 +1,44 @@ +_separator . '\1', $this->_separator . '\1')); + } else { + parent::setMatchPattern(array('#(?<=(?:[A-Z]))([A-Z]+)([A-Z][A-z])#', '#(?<=(?:[a-z]))([A-Z])#')); + parent::setReplacement(array('\1' . $this->_separator . '\2', $this->_separator . '\1')); + } + + return parent::filter($value); + } + +} diff --git a/lib/Zend/Filter/Word/CamelCaseToUnderscore.php b/lib/Zend/Filter/Word/CamelCaseToUnderscore.php new file mode 100644 index 0000000..659dfb4 --- /dev/null +++ b/lib/Zend/Filter/Word/CamelCaseToUnderscore.php @@ -0,0 +1,44 @@ +setMatchPattern('#-#'); + $this->setReplacement($this->_separator); + return parent::filter($value); + } +} diff --git a/lib/Zend/Filter/Word/DashToUnderscore.php b/lib/Zend/Filter/Word/DashToUnderscore.php new file mode 100644 index 0000000..404598a --- /dev/null +++ b/lib/Zend/Filter/Word/DashToUnderscore.php @@ -0,0 +1,45 @@ +setSeparator($separator); + } + + /** + * Sets a new seperator + * + * @param string $separator Seperator + * @return $this + */ + public function setSeparator($separator) + { + if ($separator == null) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception('"' . $separator . '" is not a valid separator.'); + } + $this->_separator = $separator; + return $this; + } + + /** + * Returns the actual set seperator + * + * @return string + */ + public function getSeparator() + { + return $this->_separator; + } + +} \ No newline at end of file diff --git a/lib/Zend/Filter/Word/SeparatorToCamelCase.php b/lib/Zend/Filter/Word/SeparatorToCamelCase.php new file mode 100644 index 0000000..853ec1b --- /dev/null +++ b/lib/Zend/Filter/Word/SeparatorToCamelCase.php @@ -0,0 +1,52 @@ +_separator, '#'); + + if (self::isUnicodeSupportEnabled()) { + parent::setMatchPattern(array('#('.$pregQuotedSeparator.')(\p{L}{1})#e','#(^\p{Ll}{1})#e')); + parent::setReplacement(array("strtoupper('\\2')","strtoupper('\\1')")); + } else { + parent::setMatchPattern(array('#('.$pregQuotedSeparator.')([A-Z]{1})#e','#(^[a-z]{1})#e')); + parent::setReplacement(array("strtoupper('\\2')","strtoupper('\\1')")); + } + + return parent::filter($value); + } + +} diff --git a/lib/Zend/Filter/Word/SeparatorToDash.php b/lib/Zend/Filter/Word/SeparatorToDash.php new file mode 100644 index 0000000..d5eab06 --- /dev/null +++ b/lib/Zend/Filter/Word/SeparatorToDash.php @@ -0,0 +1,46 @@ +setSearchSeparator($searchSeparator); + $this->setReplacementSeparator($replacementSeparator); + } + + /** + * Sets a new seperator to search for + * + * @param string $separator Seperator to search for + * @return $this + */ + public function setSearchSeparator($separator) + { + $this->_searchSeparator = $separator; + return $this; + } + + /** + * Returns the actual set seperator to search for + * + * @return string + */ + public function getSearchSeparator() + { + return $this->_searchSeparator; + } + + /** + * Sets a new seperator which replaces the searched one + * + * @param string $separator Seperator which replaces the searched one + * @return $this + */ + public function setReplacementSeparator($separator) + { + $this->_replacementSeparator = $separator; + return $this; + } + + /** + * Returns the actual set seperator which replaces the searched one + * + * @return string + */ + public function getReplacementSeparator() + { + return $this->_replacementSeparator; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, replacing the searched seperators with the defined ones + * + * @param string $value + * @return string + */ + public function filter($value) + { + return $this->_separatorToSeparatorFilter($value); + } + + /** + * Do the real work, replaces the seperator to search for with the replacement seperator + * + * Returns the replaced string + * + * @param string $value + * @return string + */ + protected function _separatorToSeparatorFilter($value) + { + if ($this->_searchSeparator == null) { + require_once 'Zend/Filter/Exception.php'; + throw new Zend_Filter_Exception('You must provide a search separator for this filter to work.'); + } + + $this->setMatchPattern('#' . preg_quote($this->_searchSeparator, '#') . '#'); + $this->setReplacement($this->_replacementSeparator); + return parent::filter($value); + } + +} \ No newline at end of file diff --git a/lib/Zend/Filter/Word/UnderscoreToCamelCase.php b/lib/Zend/Filter/Word/UnderscoreToCamelCase.php new file mode 100644 index 0000000..aabbba9 --- /dev/null +++ b/lib/Zend/Filter/Word/UnderscoreToCamelCase.php @@ -0,0 +1,44 @@ +