1: <?php
2: /**
3: * Magento
4: *
5: * NOTICE OF LICENSE
6: *
7: * This source file is subject to the Open Software License (OSL 3.0)
8: * that is bundled with this package in the file LICENSE.txt.
9: * It is also available through the world-wide-web at this URL:
10: * http://opensource.org/licenses/osl-3.0.php
11: * If you did not receive a copy of the license and are unable to
12: * obtain it through the world-wide-web, please send an email
13: * to license@magentocommerce.com so we can send you a copy immediately.
14: *
15: * DISCLAIMER
16: *
17: * Do not edit or add to this file if you wish to upgrade Magento to newer
18: * versions in the future. If you wish to customize Magento for your
19: * needs please refer to http://www.magentocommerce.com for more information.
20: *
21: * @category Mage
22: * @package Mage_Core
23: * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24: * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25: */
26:
27: /**
28: * Filter data collector
29: *
30: * Model for multi-filtering all data which set to models
31: * Example:
32: * <code>
33: * /** @var $filter Mage_Core_Model_Input_Filter {@*}
34: * $filter = Mage::getModel('core/input_filter');
35: * $filter->setFilters(array(
36: * 'list_values' => array(
37: * 'children_filters' => array( //filters will applied to all children
38: * array(
39: * 'zend' => 'StringToUpper',
40: * 'args' => array('encoding' => 'utf-8')),
41: * array('zend' => 'StripTags')
42: * )
43: * ),
44: * 'list_values_with_name' => array(
45: * 'children_filters' => array(
46: * 'item1' => array(
47: * array(
48: * 'zend' => 'StringToUpper',
49: * 'args' => array('encoding' => 'utf-8'))),
50: * 'item2' => array(
51: * array('model' => 'core/input_filter_maliciousCode')
52: * ),
53: * 'item3' => array(
54: * array(
55: * 'helper' => 'core',
56: * 'method' => 'stripTags',
57: * 'args' => array('<p> <div>', true))
58: * )
59: * )
60: * )
61: * ));
62: * $filter->addFilter('name2', new Zend_Filter_Alnum());
63: * $filter->addFilter('name1',
64: * array(
65: * 'zend' => 'StringToUpper',
66: * 'args' => array('encoding' => 'utf-8')));
67: * $filter->addFilter('name1', array('zend' => 'StripTags'), Zend_Filter::CHAIN_PREPEND);
68: * $filter->addFilters(protected $_filtersToAdd = array(
69: * 'list_values_with_name' => array(
70: * 'children_filters' => array(
71: * 'deep_list' => array(
72: * 'children_filters' => array(
73: * 'sub1' => array(
74: * array(
75: * 'zend' => 'StringToLower',
76: * 'args' => array('encoding' => 'utf-8'))),
77: * 'sub2' => array(array('zend' => 'Int'))
78: * )
79: * )
80: * )
81: * )
82: * ));
83: * $filter->filter(array(
84: * 'name1' => 'some <b>string</b>',
85: * 'name2' => '888 555',
86: * 'list_values' => array(
87: * 'some <b>string2</b>',
88: * 'some <p>string3</p>',
89: * ),
90: * 'list_values_with_name' => array(
91: * 'item1' => 'some <b onclick="alert(\'2\')">string4</b>',
92: * 'item2' => 'some <b onclick="alert(\'1\')">string5</b>',
93: * 'item3' => 'some <p>string5</p> <b>bold</b> <div>div</div>',
94: * 'deep_list' => array(
95: * 'sub1' => 'toLowString',
96: * 'sub2' => '5 TO INT',
97: * )
98: * )
99: * ));
100: * </code>
101: *
102: * @see Mage_Core_Model_Input_FilterTest See this class for manual
103: * @category Mage
104: * @package Mage_Core
105: * @author Magento Api Team <api-team@magento.com>
106: */
107: class Mage_Core_Model_Input_Filter implements Zend_Filter_Interface
108: {
109: /**
110: * Filters data collectors
111: *
112: * @var array
113: */
114: protected $_filters = array();
115:
116: /**
117: * Add filter
118: *
119: * @param string $name
120: * @param array|Zend_Filter_Interface $filter
121: * @param string $placement
122: * @return Mage_Core_Model_Input_Filter
123: */
124: public function addFilter($name, $filter, $placement = Zend_Filter::CHAIN_APPEND)
125: {
126: if ($placement == Zend_Filter::CHAIN_PREPEND) {
127: array_unshift($this->_filters[$name], $filter);
128: } else {
129: $this->_filters[$name][] = $filter;
130: }
131: return $this;
132: }
133:
134: /**
135: * Add a filter to the end of the chain
136: *
137: * @param array|Zend_Filter_Interface $filter
138: * @return Mage_Core_Model_Input_Filter
139: */
140: public function appendFilter(Zend_Filter_Interface $filter)
141: {
142: return $this->addFilter($filter, Zend_Filter::CHAIN_APPEND);
143: }
144:
145: /**
146: * Add a filter to the start of the chain
147: *
148: * @param array|Zend_Filter_Interface $filter
149: * @return Mage_Core_Model_Input_Filter
150: */
151: public function prependFilter($filter)
152: {
153: return $this->addFilter($filter, Zend_Filter::CHAIN_PREPEND);
154: }
155:
156: /**
157: * Add filters
158: *
159: * Filters data must be has view as
160: * array(
161: * 'key1' => $filters,
162: * 'key2' => array( ... ), //array filters data
163: * 'key2' => $filters
164: * )
165: *
166: * @param array $filters
167: * @return Mage_Core_Model_Input_Filter
168: */
169: public function addFilters(array $filters)
170: {
171: $this->_filters = array_merge_recursive($this->_filters, $filters);
172: return $this;
173: }
174:
175: /**
176: * Set filters
177: *
178: * @param array $filters
179: * @return Mage_Core_Model_Input_Filter
180: */
181: public function setFilters(array $filters)
182: {
183: $this->_filters = $filters;
184: return $this;
185: }
186:
187: /**
188: * Get filters
189: *
190: * @param string|null $name Get filter for selected name
191: * @return array
192: */
193: public function getFilters($name = null)
194: {
195: if (null === $name) {
196: return $this->_filters;
197: } else {
198: return isset($this->_filters[$name]) ? $this->_filters[$name] : null;
199: }
200: }
201:
202: /**
203: * Filter data
204: *
205: * @param array $data
206: * @return array Return filtered data
207: */
208: public function filter($data)
209: {
210: return $this->_filter($data);
211: }
212:
213: /**
214: * Recursive filtering
215: *
216: * @param array $data
217: * @param array|null $filters
218: * @param bool $isFilterListSimple
219: * @return array
220: * @throws Exception Exception when filter is not found or not instance of defined instances
221: */
222: protected function _filter(array $data, &$filters = null, $isFilterListSimple = false)
223: {
224: if (null === $filters) {
225: $filters = &$this->_filters;
226: }
227: foreach ($data as $key => $value) {
228: if (!$isFilterListSimple && !empty($filters[$key])) {
229: $itemFilters = $filters[$key];
230: } elseif ($isFilterListSimple && !empty($filters)) {
231: $itemFilters = $filters;
232: } else {
233: continue;
234: }
235:
236: if (!$isFilterListSimple && is_array($value) && isset($filters[$key]['children_filters'])) {
237: $isChildrenFilterListSimple = is_numeric(implode('', array_keys($filters[$key]['children_filters'])));
238: $value = $this->_filter($value, $filters[$key]['children_filters'], $isChildrenFilterListSimple);
239: } else {
240: foreach ($itemFilters as $filterData) {
241: if ($zendFilter = $this->_getZendFilter($filterData)) {
242: $value = $zendFilter->filter($value);
243: } elseif ($filtrationHelper = $this->_getFiltrationHelper($filterData)) {
244: $value = $this->_applyFiltrationWithHelper($value, $filtrationHelper, $filterData);
245: }
246: }
247: }
248: $data[$key] = $value;
249: }
250: return $data;
251: }
252:
253: /**
254: * Call specified helper method for $value filtration
255: *
256: * @param mixed $value
257: * @param Mage_Core_Helper_Abstract $helper
258: * @param array $filterData
259: * @return mixed
260: */
261: protected function _applyFiltrationWithHelper($value, Mage_Core_Helper_Abstract $helper, array $filterData)
262: {
263: if (!isset($filterData['method']) || empty($filterData['method'])) {
264: throw new Exception("Helper filtration method is not set");
265: }
266: if (!isset($filterData['args']) || empty($filterData['args'])) {
267: $filterData['args'] = array();
268: }
269: $filterData['args'] = array(-100 => $value) + $filterData['args'];
270: // apply filter
271: $value = call_user_func_array(array($helper, $filterData['method']), $filterData['args']);
272: return $value;
273: }
274:
275: /**
276: * Try to create Magento helper for filtration based on $filterData. Return false on failure
277: *
278: * @param $filterData
279: * @return bool|Mage_Core_Helper_Abstract
280: * @throws Exception
281: */
282: protected function _getFiltrationHelper($filterData)
283: {
284: $helper = false;
285: if (isset($filterData['helper'])) {
286: $helper = $filterData['helper'];
287: if (is_string($helper)) {
288: $helper = Mage::helper($helper);
289: }
290: if (!($helper instanceof Mage_Core_Helper_Abstract)) {
291: throw new Exception("Filter '{$filterData['helper']}' not found");
292: }
293: }
294: return $helper;
295: }
296:
297: /**
298: * Try to create Zend filter based on $filterData. Return false on failure
299: *
300: * @param $filterData
301: * @return bool|Zend_Filter_Interface
302: */
303: protected function _getZendFilter($filterData)
304: {
305: $zendFilter = false;
306: if (is_object($filterData) && $filterData instanceof Zend_Filter_Interface) {
307: /** @var $zendFilter Zend_Filter_Interface */
308: $zendFilter = $filterData;
309: } elseif (isset($filterData['model'])) {
310: $zendFilter = $this->_createCustomZendFilter($filterData);
311: } elseif (isset($filterData['zend'])) {
312: $zendFilter = $this->_createNativeZendFilter($filterData);
313: }
314: return $zendFilter;
315: }
316:
317: /**
318: * Get Magento filters
319: *
320: * @param $filterData
321: * @return Zend_Filter_Interface
322: * @throws Exception
323: */
324: protected function _createCustomZendFilter($filterData)
325: {
326: $filter = $filterData['model'];
327: if (!isset($filterData['args'])) {
328: $filterData['args'] = null;
329: } else {
330: //use only first element because Mage factory cannot get more
331: $filterData['args'] = $filterData['args'][0];
332: }
333: if (is_string($filterData['model'])) {
334: $filter = Mage::getModel($filterData['model'], $filterData['args']);
335: }
336: if (!($filter instanceof Zend_Filter_Interface)) {
337: throw new Exception('Filter is not instance of Zend_Filter_Interface');
338: }
339: return $filter;
340: }
341:
342: /**
343: * Get native Zend_Filter
344: *
345: * @param $filterData
346: * @return Zend_Filter_Interface
347: * @throws Exception
348: */
349: protected function _createNativeZendFilter($filterData)
350: {
351: $filter = $filterData['zend'];
352: if (is_string($filter)) {
353: $class = new ReflectionClass('Zend_Filter_' . $filter);
354: if ($class->implementsInterface('Zend_Filter_Interface')) {
355: if (isset($filterData['args']) && $class->hasMethod('__construct')) {
356: $filter = $class->newInstanceArgs($filterData['args']);
357: } else {
358: $filter = $class->newInstance();
359: }
360: } else {
361: throw new Exception('Filter is not instance of Zend_Filter_Interface');
362: }
363: }
364: return $filter;
365: }
366: }
367: