1: <?php
2: App::import('Core', 'ConnectionManager');
3: /**
4: * Washes strings from unwanted noise.
5: *
6: * Helpful methods to make unsafe strings usable.
7: *
8: * PHP versions 4 and 5
9: *
10: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
11: * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
12: *
13: * Licensed under The MIT License
14: * Redistributions of files must retain the above copyright notice.
15: *
16: * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
17: * @link http://cakephp.org CakePHP(tm) Project
18: * @package cake
19: * @subpackage cake.cake.libs
20: * @since CakePHP(tm) v 0.10.0.1076
21: * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
22: */
23:
24: /**
25: * Data Sanitization.
26: *
27: * Removal of alpahnumeric characters, SQL-safe slash-added strings, HTML-friendly strings,
28: * and all of the above on arrays.
29: *
30: * @package cake
31: * @subpackage cake.cake.libs
32: */
33: class Sanitize {
34:
35: /**
36: * Removes any non-alphanumeric characters.
37: *
38: * @param string $string String to sanitize
39: * @param array $allowed An array of additional characters that are not to be removed.
40: * @return string Sanitized string
41: * @access public
42: * @static
43: */
44: function paranoid($string, $allowed = array()) {
45: $allow = null;
46: if (!empty($allowed)) {
47: foreach ($allowed as $value) {
48: $allow .= "\\$value";
49: }
50: }
51:
52: if (is_array($string)) {
53: $cleaned = array();
54: foreach ($string as $key => $clean) {
55: $cleaned[$key] = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $clean);
56: }
57: } else {
58: $cleaned = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $string);
59: }
60: return $cleaned;
61: }
62:
63: /**
64: * Makes a string SQL-safe.
65: *
66: * @param string $string String to sanitize
67: * @param string $connection Database connection being used
68: * @return string SQL safe string
69: * @access public
70: * @static
71: */
72: function escape($string, $connection = 'default') {
73: $db =& ConnectionManager::getDataSource($connection);
74: if (is_numeric($string) || $string === null || is_bool($string)) {
75: return $string;
76: }
77: $string = substr($db->value($string), 1);
78: $string = substr($string, 0, -1);
79: return $string;
80: }
81:
82: /**
83: * Returns given string safe for display as HTML. Renders entities.
84: *
85: * strip_tags() does not validating HTML syntax or structure, so it might strip whole passages
86: * with broken HTML.
87: *
88: * ### Options:
89: *
90: * - remove (boolean) if true strips all HTML tags before encoding
91: * - charset (string) the charset used to encode the string
92: * - quotes (int) see http://php.net/manual/en/function.htmlentities.php
93: *
94: * @param string $string String from where to strip tags
95: * @param array $options Array of options to use.
96: * @return string Sanitized string
97: * @access public
98: * @static
99: */
100: function html($string, $options = array()) {
101: static $defaultCharset = false;
102: if ($defaultCharset === false) {
103: $defaultCharset = Configure::read('App.encoding');
104: if ($defaultCharset === null) {
105: $defaultCharset = 'UTF-8';
106: }
107: }
108: $default = array(
109: 'remove' => false,
110: 'charset' => $defaultCharset,
111: 'quotes' => ENT_QUOTES
112: );
113:
114: $options = array_merge($default, $options);
115:
116: if ($options['remove']) {
117: $string = strip_tags($string);
118: }
119:
120: return htmlentities($string, $options['quotes'], $options['charset']);
121: }
122:
123: /**
124: * Strips extra whitespace from output
125: *
126: * @param string $str String to sanitize
127: * @return string whitespace sanitized string
128: * @access public
129: * @static
130: */
131: function stripWhitespace($str) {
132: $r = preg_replace('/[\n\r\t]+/', '', $str);
133: return preg_replace('/\s{2,}/u', ' ', $r);
134: }
135:
136: /**
137: * Strips image tags from output
138: *
139: * @param string $str String to sanitize
140: * @return string Sting with images stripped.
141: * @access public
142: * @static
143: */
144: function stripImages($str) {
145: $str = preg_replace('/(<a[^>]*>)(<img[^>]+alt=")([^"]*)("[^>]*>)(<\/a>)/i', '$1$3$5<br />', $str);
146: $str = preg_replace('/(<img[^>]+alt=")([^"]*)("[^>]*>)/i', '$2<br />', $str);
147: $str = preg_replace('/<img[^>]*>/i', '', $str);
148: return $str;
149: }
150:
151: /**
152: * Strips scripts and stylesheets from output
153: *
154: * @param string $str String to sanitize
155: * @return string String with <script>, <style>, <link>, <img> elements removed.
156: * @access public
157: * @static
158: */
159: function stripScripts($str) {
160: return preg_replace('/(<link[^>]+rel="[^"]*stylesheet"[^>]*>|<img[^>]*>|style="[^"]*")|<script[^>]*>.*?<\/script>|<style[^>]*>.*?<\/style>|<!--.*?-->/is', '', $str);
161: }
162:
163: /**
164: * Strips extra whitespace, images, scripts and stylesheets from output
165: *
166: * @param string $str String to sanitize
167: * @return string sanitized string
168: * @access public
169: */
170: function stripAll($str) {
171: $str = Sanitize::stripWhitespace($str);
172: $str = Sanitize::stripImages($str);
173: $str = Sanitize::stripScripts($str);
174: return $str;
175: }
176:
177: /**
178: * Strips the specified tags from output. First parameter is string from
179: * where to remove tags. All subsequent parameters are tags.
180: *
181: * Ex.`$clean = Sanitize::stripTags($dirty, 'b', 'p', 'div');`
182: *
183: * Will remove all `<b>`, `<p>`, and `<div>` tags from the $dirty string.
184: *
185: * @param string $str String to sanitize
186: * @param string $tag Tag to remove (add more parameters as needed)
187: * @return string sanitized String
188: * @access public
189: * @static
190: */
191: function stripTags() {
192: $params = params(func_get_args());
193: $str = $params[0];
194:
195: for ($i = 1, $count = count($params); $i < $count; $i++) {
196: $str = preg_replace('/<' . $params[$i] . '\b[^>]*>/i', '', $str);
197: $str = preg_replace('/<\/' . $params[$i] . '[^>]*>/i', '', $str);
198: }
199: return $str;
200: }
201:
202: /**
203: * Sanitizes given array or value for safe input. Use the options to specify
204: * the connection to use, and what filters should be applied (with a boolean
205: * value). Valid filters:
206: *
207: * - odd_spaces - removes any non space whitespace characters
208: * - encode - Encode any html entities. Encode must be true for the `remove_html` to work.
209: * - dollar - Escape `$` with `\$`
210: * - carriage - Remove `\r`
211: * - unicode -
212: * - escape - Should the string be SQL escaped.
213: * - backslash -
214: * - remove_html - Strip HTML with strip_tags. `encode` must be true for this option to work.
215: *
216: * @param mixed $data Data to sanitize
217: * @param mixed $options If string, DB connection being used, otherwise set of options
218: * @return mixed Sanitized data
219: * @access public
220: * @static
221: */
222: function clean($data, $options = array()) {
223: if (empty($data)) {
224: return $data;
225: }
226:
227: if (is_string($options)) {
228: $options = array('connection' => $options);
229: } else if (!is_array($options)) {
230: $options = array();
231: }
232:
233: $options = array_merge(array(
234: 'connection' => 'default',
235: 'odd_spaces' => true,
236: 'remove_html' => false,
237: 'encode' => true,
238: 'dollar' => true,
239: 'carriage' => true,
240: 'unicode' => true,
241: 'escape' => true,
242: 'backslash' => true
243: ), $options);
244:
245: if (is_array($data)) {
246: foreach ($data as $key => $val) {
247: $data[$key] = Sanitize::clean($val, $options);
248: }
249: return $data;
250: } else {
251: if ($options['odd_spaces']) {
252: $data = str_replace(chr(0xCA), '', $data);
253: }
254: if ($options['encode']) {
255: $data = Sanitize::html($data, array('remove' => $options['remove_html']));
256: }
257: if ($options['dollar']) {
258: $data = str_replace("\\\$", "$", $data);
259: }
260: if ($options['carriage']) {
261: $data = str_replace("\r", "", $data);
262: }
263: if ($options['unicode']) {
264: $data = preg_replace("/&#([0-9]+);/s", "&#\\1;", $data);
265: }
266: if ($options['escape']) {
267: $data = Sanitize::escape($data, $options['connection']);
268: }
269: if ($options['backslash']) {
270: $data = preg_replace("/\\\(?!&#|\?#)/", "\\", $data);
271: }
272: return $data;
273: }
274: }
275:
276: /**
277: * Formats column data from definition in DBO's $columns array
278: *
279: * @param Model $model The model containing the data to be formatted
280: * @access public
281: * @static
282: */
283: function formatColumns(&$model) {
284: foreach ($model->data as $name => $values) {
285: if ($name == $model->alias) {
286: $curModel =& $model;
287: } elseif (isset($model->{$name}) && is_object($model->{$name}) && is_subclass_of($model->{$name}, 'Model')) {
288: $curModel =& $model->{$name};
289: } else {
290: $curModel = null;
291: }
292:
293: if ($curModel != null) {
294: foreach ($values as $column => $data) {
295: $colType = $curModel->getColumnType($column);
296:
297: if ($colType != null) {
298: $db =& ConnectionManager::getDataSource($curModel->useDbConfig);
299: $colData = $db->columns[$colType];
300:
301: if (isset($colData['limit']) && strlen(strval($data)) > $colData['limit']) {
302: $data = substr(strval($data), 0, $colData['limit']);
303: }
304:
305: if (isset($colData['formatter']) || isset($colData['format'])) {
306:
307: switch (strtolower($colData['formatter'])) {
308: case 'date':
309: $data = date($colData['format'], strtotime($data));
310: break;
311: case 'sprintf':
312: $data = sprintf($colData['format'], $data);
313: break;
314: case 'intval':
315: $data = intval($data);
316: break;
317: case 'floatval':
318: $data = floatval($data);
319: break;
320: }
321: }
322: $model->data[$name][$column]=$data;
323: /*
324: switch ($colType) {
325: case 'integer':
326: case 'int':
327: return $data;
328: break;
329: case 'string':
330: case 'text':
331: case 'binary':
332: case 'date':
333: case 'time':
334: case 'datetime':
335: case 'timestamp':
336: case 'date':
337: return "'" . $data . "'";
338: break;
339: }
340: */
341: }
342: }
343: }
344: }
345: }
346: }
347: