1<?php if (!defined('BASEPATH')) { 2 exit('No direct script access allowed'); 3} 4/* 5 * LimeSurvey 6 * Copyright (C) 2007-2011 The LimeSurvey Project Team / Carsten Schmitz 7 * All rights reserved. 8 * License: GNU/GPL License v2 or later, see LICENSE.php 9 * LimeSurvey is free software. This version may have been modified pursuant 10 * to the GNU General Public License, and as distributed it includes or 11 * is derivative of works licensed under the GNU General Public License or 12 * other free or open source software licenses. 13 * See COPYRIGHT.php for copyright notices and details. 14 * 15 */ 16/* 17 * 18 * Copyright (c) 2002,2003 Free Software Foundation 19 * developed under the custody of the 20 * Open Web Application Security Project 21 * (http://www.owasp.org) 22 * 23 * This file is part of the PHP Filters. 24 * PHP Filters is free software; you can redistribute it and/or modify it 25 * under the terms of the GNU General Public License as published by 26 * the Free Software Foundation; either version 2 of the License, or 27 * (at your option) any later version. 28 * 29 * PHP Filters is distributed in the hope that it will be useful, 30 * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 32 * See the GNU General Public License for more details. 33 * 34 * If you are not able to view the LICENSE, which should 35 * always be possible within a valid and working PHP Filters release, 36 * please write to the Free Software Foundation, Inc., 37 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 38 * to get a copy of the GNU General Public License or to report a 39 * possible license violation. 40 */ 41/////////////////////////////////////// 42// sanitize.inc.php 43// Sanitization functions for PHP 44// by: Gavin Zuchlinski, Jamie Pratt, Hokkaido 45// webpage: http://libox.net 46// Last modified: December 21, 2003 47// 48// Many thanks to those on the webappsec list for helping me improve these functions 49/////////////////////////////////////// 50// Function list: 51// sanitize_paranoid_string($string) -- input string, returns string stripped of all non 52// alphanumeric 53// sanitize_system_string($string) -- input string, returns string stripped of special 54// characters 55// sanitize_html_string($string) -- input string, returns string with html replacements 56// for special characters 57// sanitize_int($integer) -- input integer, returns ONLY the integer (no extraneous 58// characters 59// sanitize_float($float) -- input float, returns ONLY the float (no extraneous 60// characters) 61// sanitize($input, $flags) -- input any variable, performs sanitization 62// functions specified in flags. flags can be bitwise 63// combination of PARANOID, SQL, SYSTEM, HTML, INT, FLOAT, LDAP, 64// UTF8 65// sanitize_user($string) -- total length check (and more ??) 66// sanitize_userfullname($string) -- total length check (and more ??) 67// 68// 69/////////////////////////////////////// 70// 71// 20031121 jp - added defines for magic_quotes and register_globals, added ; to replacements 72// in sanitize_sql_string() function, created rudimentary testing pages 73// 20031221 gz - added nice_addslashes and changed sanitize_sql_string to use it 74// 20070213 lemeur - marked sanitize_sql_string as obsolete, should use db_quote instead 75// 20071032 lemeur - added sanitize_user and sanitize_userfullname 76// 77///////////////////////////////////////// 78 79define("PARANOID", 1); 80//define("SQL", 2); 81define("SYSTEM", 4); 82define("HTML", 8); 83define("INT", 16); 84define("FLOAT", 32); 85define("LDAP", 64); 86define("UTF8", 128); 87 88// get magic_quotes_gpc ini setting - jp 89$magic_quotes = (bool) @ini_get('magic_quotes_gpc'); 90if ($magic_quotes == true) { define("MAGIC_QUOTES", 1); } else { define("MAGIC_QUOTES", 0); } 91 92// addslashes wrapper to check for gpc_magic_quotes - gz 93function nice_addslashes($string) 94{ 95 // if magic quotes is on the string is already quoted, just return it 96 if (MAGIC_QUOTES) { 97 return $string; 98 } else { 99 return addslashes($string); 100 } 101 } 102 103 104/** 105 * Function: sanitize_filename 106 * Returns a sanitized string, typically for URLs. 107 * 108 * Parameters: 109 * $string - The string to sanitize. 110 * $force_lowercase - Force the string to lowercase? 111 * $alphanumeric - If set to *true*, will remove all non-alphanumeric characters. 112 */ 113function sanitize_filename($filename, $force_lowercase = true, $alphanumeric = false, $beautify = true) 114{ 115 // sanitize filename 116 $filename = preg_replace( 117 '~ 118 [<>:"/\\|?*]| 119 [\x00-\x1F]| 120 [\x7F\xA0\xAD]| 121 [#\[\]@!$&\'()+,;=]| 122 [{}^\~`] 123 ~x', 124 '-', $filename); 125 // Removes smart quotes 126 $filename = str_replace(array("\xe2\x80\x98", "\xe2\x80\x99", "\xe2\x80\x9c", "\xe2\x80\x9d", "\xe2\x80\x93", "\xe2\x80\x94", "\xe2\x80\xa6"), array('','', '', '', '-', '--','...'), $filename); 127 // avoids ".", ".." or ".hiddenFiles" 128 $filename = ltrim($filename, '.-'); 129 // optional beautification 130 if ($beautify) { 131 $filename = beautify_filename($filename); 132 } 133 // maximise filename length to 255 bytes http://serverfault.com/a/9548/44086 134 $ext = pathinfo($filename, PATHINFO_EXTENSION); 135 $filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)).($ext ? '.'.$ext : ''); 136 $filename = ($alphanumeric) ? preg_replace("/[^a-zA-Z0-9]/", "", $filename) : $filename; 137 138 if ($force_lowercase) { 139 $filename=mb_strtolower($filename, 'UTF-8'); 140 } 141 // At the end of the process there are sometimes question marks left from non-UTF-8 characters 142 $filename = str_replace('?', '', $filename); 143 return $filename; 144} 145 146/** 147 * @param string $filename 148 */ 149function beautify_filename($filename) 150{ 151 // reduce consecutive characters 152 $filename = preg_replace(array( 153 // "file name.zip" becomes "file-name.zip" 154 '/ +/', 155 // "file___name.zip" becomes "file-name.zip" 156 '/_+/', 157 // "file---name.zip" becomes "file-name.zip" 158 '/-+/' 159 ), '-', $filename); 160 $filename = preg_replace(array( 161 // "file--.--.-.--name.zip" becomes "file.name.zip" 162 '/-*\.-*/', 163 // "file...name..zip" becomes "file.name.zip" 164 '/\.{2,}/' 165 ), '.', $filename); 166 // lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 167 $filename = mb_strtolower($filename, mb_detect_encoding($filename)); 168 // ".file-name.-" becomes "file-name" 169 $filename = trim($filename, '.-'); 170 return $filename; 171} 172 173 174 175/** 176 * Function: sanitize_dirname 177 * sanitizes a string that will be used as a directory name 178 * 179 * Parameters: 180 * $string - The string to sanitize. 181 * $force_lowercase - Force the string to lowercase? 182 * $alphanumeric - If set to *true*, will remove all non-alphanumeric characters. 183 */ 184 185function sanitize_dirname($string, $force_lowercase = false, $alphanumeric = false) 186{ 187 $string = str_replace(".", "", $string); 188 return sanitize_filename($string, $force_lowercase, $alphanumeric, false); 189} 190 191 192// paranoid sanitization -- only let the alphanumeric set through 193function sanitize_paranoid_string($string, $min = '', $max = '') 194{ 195 if (isset($string)) { 196 $string = preg_replace("/[^_.a-zA-Z0-9]/", "", $string); 197 $len = strlen($string); 198 if ((($min != '') && ($len < $min)) || (($max != '') && ($len > $max))) { 199 return false; 200 } 201 return $string; 202 } 203} 204 205function sanitize_cquestions($string, $min = '', $max = '') 206{ 207 if (isset($string)) { 208 $string = preg_replace("/[^_.a-zA-Z0-9+#]/", "", $string); 209 $len = strlen($string); 210 if ((($min != '') && ($len < $min)) || (($max != '') && ($len > $max))) { 211 return false; 212 } 213 return $string; 214 } 215} 216 217// sanitize a string in prep for passing a single argument to system() (or similar) 218function sanitize_system_string($string, $min = '', $max = '') 219{ 220 if (isset($string)) { 221 $pattern = '/(;|\||`|>|<|&|^|"|'."\n|\r|'".'|{|}|[|]|\)|\()/i'; // no piping, passing possible environment variables ($), 222 // separate commands, nested execution, file redirection, 223 // background processing, special commands (backspace, etc.), quotes 224 // newlines, or some other special characters 225 $string = preg_replace($pattern, '', $string); 226 $string = '"'.preg_replace('/\$/', '\\\$', $string).'"'; //make sure this is only interpretted as ONE argument 227 $len = strlen($string); 228 if ((($min != '') && ($len < $min)) || (($max != '') && ($len > $max))) { 229 return false; 230 } 231 return $string; 232 } 233} 234 235function sanitize_xss_string($string) 236{ 237 if (isset($string)) { 238 $bad = array('*', '^', '&', ';', '\"', '(', ')', '%', '$', '?'); 239 return str_replace($bad, '', $string); 240 } 241} 242 243 244 245// sanitize a string for SQL input (simple slash out quotes and slashes) 246function sanitize_sql_db_tablename($string) 247{ 248 $bad = array('*', '^', '&', '\'', '-', ';', '\"', '(', ')', '%', '$', '?'); 249 return str_replace($bad, "", $string); 250} 251 252// sanitize a string for SQL input (simple slash out quotes and slashes) 253function sanitize_ldap_string($string, $min = '', $max = '') 254{ 255 $pattern = '/(\)|\(|\||&)/'; 256 $len = strlen($string); 257 if ((($min != '') && ($len < $min)) || (($max != '') && ($len > $max))) { 258 return false; 259 } 260 return preg_replace($pattern, '', $string); 261} 262 263 264// sanitize a string for HTML (make sure nothing gets interpretted!) 265function sanitize_html_string($string) 266{ 267 $pattern[0] = '/\&/'; 268 $pattern[1] = '/</'; 269 $pattern[2] = "/>/"; 270 $pattern[3] = '/\n/'; 271 $pattern[4] = '/"/'; 272 $pattern[5] = "/'/"; 273 $pattern[6] = "/%/"; 274 $pattern[7] = '/\(/'; 275 $pattern[8] = '/\)/'; 276 $pattern[9] = '/\+/'; 277 $pattern[10] = '/-/'; 278 $replacement[0] = '&'; 279 $replacement[1] = '<'; 280 $replacement[2] = '>'; 281 $replacement[3] = '<br />'; 282 $replacement[4] = '"'; 283 $replacement[5] = '''; 284 $replacement[6] = '%'; 285 $replacement[7] = '('; 286 $replacement[8] = ')'; 287 $replacement[9] = '+'; 288 $replacement[10] = '-'; 289 return preg_replace($pattern, $replacement, $string); 290} 291 292// make int int! 293function sanitize_int($integer, $min = '', $max = '') 294{ 295 $int = preg_replace("#[^0-9]#", "", $integer); 296 if ((($min != '') && ($int < $min)) || (($max != '') && ($int > $max))) { 297 return false; 298 } 299 if ($int == '') { 300 return null; 301 } 302 return $int; 303} 304 305// sanitize a username 306// TODO: define the exact format of the username 307// allow for instance 0-9a-zA-Z@_-. 308/** 309 * @param string $string 310 */ 311function sanitize_user($string) 312{ 313 $username_length = 64; 314 $string = mb_substr($string, 0, $username_length); 315 return $string; 316} 317 318// sanitize a username 319// TODO: define the exact format of the username 320// allow for instance 0-9a-zA-Z@_-. 321function sanitize_userfullname($string) 322{ 323 $username_length = 50; 324 $string = mb_substr($string, 0, $username_length); 325 return $string; 326} 327 328function sanitize_labelname($string) 329{ 330 $labelname_length = 100; 331 $string = mb_substr($string, 0, $labelname_length); 332 return $string; 333} 334 335// make float float! 336function sanitize_float($float, $min = '', $max = '') 337{ 338 $float = str_replace(',', '.', $float); 339 // GMP library allows for high precision and high value numbers 340 if (function_exists('gmp_init') && defined('GMP_VERSION') && version_compare(GMP_VERSION, '4.3.2') == 1) { 341 $gNumber = gmp_init($float); 342 if (($min != '' && gmp_cmp($gNumber, $min) < 0) || ($max != '' && gmp_cmp($gNumber, $max) > 0)) { 343 return false; 344 } else { 345 return gmp_strval($gNumber); 346 } 347 } else { 348 $fNumber = str_replace(',', '.', $float); 349 $fNumber = floatval($fNumber); 350 if ((($min != '') && ($fNumber < $min)) || (($max != '') && ($fNumber > $max))) { 351 return false; 352 } 353 return $fNumber; 354 } 355} 356 357 358// glue together all the other functions 359function sanitize($input, $flags, $min = '', $max = '') 360{ 361 if ($flags & PARANOID) { 362 $input = sanitize_paranoid_string($input, $min, $max); 363 } 364 if ($flags & INT) { 365 $input = sanitize_int($input, $min, $max); 366 } 367 if ($flags & FLOAT) { 368 $input = sanitize_float($input, $min, $max); 369 } 370 if ($flags & HTML) { 371 $input = sanitize_html_string($input); 372 } 373 if ($flags & LDAP) { 374 $input = sanitize_ldap_string($input, $min, $max); 375 } 376 if ($flags & SYSTEM) { 377 $input = sanitize_system_string($input, $min, $max); 378 } 379 return $input; 380} 381 382function check_paranoid_string($input, $min = '', $max = '') 383{ 384 if ($input != sanitize_paranoid_string($input, $min, $max)) { 385 return false; 386 } 387 return true; 388} 389 390function check_int($input, $min = '', $max = '') 391{ 392 if ($input != sanitize_int($input, $min, $max)) { 393 return false; 394 } 395 return true; 396} 397 398function check_float($input, $min = '', $max = '') 399{ 400 if ($input != sanitize_float($input, $min, $max)) { 401 return false; 402 } 403 return true; 404} 405 406function check_html_string($input, $min = '', $max = '') 407{ 408 if ($input != sanitize_html_string($input)) { 409 return false; 410 } 411 return true; 412} 413 414 415function check_ldap_string($input, $min = '', $max = '') 416{ 417 if ($input != sanitize_string($input, $min, $max)) { 418 return false; 419 } 420 return true; 421} 422 423function check_system_string($input, $min = '', $max = '') 424{ 425 if ($input != sanitize_system_string($input, $min, $max)) { 426 return false; 427 } 428 return true; 429} 430 431// glue together all the other functions 432function check($input, $flags, $min = '', $max = '') 433{ 434 $oldput = $input; 435 if ($flags & UTF8) { 436 $input = my_utf8_decode($input); 437 } 438 if ($flags & PARANOID) { 439 $input = sanitize_paranoid_string($input, $min, $max); 440 } 441 if ($flags & INT) { 442 $input = sanitize_int($input, $min, $max); 443 } 444 if ($flags & FLOAT) { 445 $input = sanitize_float($input, $min, $max); 446 } 447 if ($flags & HTML) { 448 $input = sanitize_html_string($input); 449 } 450 if ($flags & LDAP) { 451 $input = sanitize_ldap_string($input, $min, $max); 452 } 453 if ($flags & SYSTEM) { 454 $input = sanitize_system_string($input, $min, $max); 455 } 456 if ($input != $oldput) { 457 return false; 458 } 459 return true; 460} 461 462function sanitize_languagecode($codetosanitize) 463{ 464 return preg_replace('/[^a-z0-9-]/i', '', $codetosanitize); 465} 466 467/** 468 * @param string $codestringtosanitize 469 */ 470function sanitize_languagecodeS($codestringtosanitize) 471{ 472 $codearray = explode(" ", trim($codestringtosanitize)); 473 $codearray = array_map("sanitize_languagecode", $codearray); 474 return implode(" ", $codearray); 475} 476 477 478function sanitize_signedint($integer, $min = '', $max = '') 479{ 480 $int = (int) $integer; 481 482 if ((($min != '') && ($int < $min)) || (($max != '') && ($int > $max))) { 483 return false; // Oops! Outside limits. 484 } 485 486 return $int; 487}; 488