PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/php/Safe.php

http://github.com/clone1018/Shocky
PHP | 424 lines | 369 code | 35 blank | 20 comment | 29 complexity | 11904f29fd95dc06e237a7ca4f3c69af MD5 | raw file
Possible License(s): 0BSD, Apache-2.0
  1. <?php
  2. class Safe {
  3. private static $allowedCalls = array(
  4. 'function',
  5. // Mathematical functions
  6. 'ceil', // Round fractions up
  7. 'floor', // Round fractions down
  8. 'fmod', // Returns the floating point remainder (modulo) of the division of the arguments
  9. 'log', // Natural logarithm
  10. 'mt_rand', // Generate a better random value
  11. 'mt_srand', // Seed the better random number generator
  12. 'pow', // Exponential expression
  13. 'rand', // Generate a random integer
  14. 'sqrt', // Square root
  15. 'srand', // Seed the random number generator
  16. // Variable handling
  17. 'empty', // Determine whether a variable is empty
  18. 'floatval', // Get float value of a variable
  19. 'intval', // Get the integer value of a variable
  20. 'is_array', // Finds whether a variable is an array
  21. 'is_binary', // Finds whether a variable is a native binary string
  22. 'is_bool', // Finds out whether a variable is a boolean
  23. 'is_double', // Alias of is_float
  24. 'is_float', // Finds whether the type of a variable is float
  25. 'is_int', // Find whether the type of a variable is integer
  26. 'is_integer', // Alias of is_int
  27. 'is_long', // Alias of is_int
  28. 'is_null', // Finds whether a variable is NULL
  29. 'is_numeric', // Finds whether a variable is a number or a numeric string
  30. 'is_real', // Alias of is_float
  31. 'is_scalar', // Finds whether a variable is a scalar
  32. 'is_string', // Find whether the type of a variable is string
  33. 'is_unicode', // Finds whether a variable is a unicode string
  34. 'isset', // Determine whether a variable is set
  35. 'strval', // Get string value of a variable
  36. 'unset', // Unset a given variable
  37. // Array functions
  38. 'array_change_key_case',// Changes all keys in an array
  39. 'array_chunk', // Split an array into chunks
  40. 'array_combine', // Creates an array by using one array for keys and another for its values
  41. 'array_count_values', // Counts all the values of an array
  42. 'array_diff_assoc', // Computes the difference of arrays with additional index check
  43. 'array_diff_key', // Computes the difference of arrays using keys for comparison
  44. 'array_diff', // Computes the difference of arrays
  45. 'array_fill_keys', // Fill an array with values, specifying keys
  46. 'array_fill', // Fill an array with values
  47. 'array_flip', // Exchanges all keys with their associated values in an array
  48. 'array_intersect_assoc',// Computes the intersection of arrays with additional index check
  49. 'array_intersect_key', // Computes the intersection of arrays using keys for comparison
  50. 'array_intersect', // Computes the intersection of arrays
  51. 'array_key_exists', // Checks if the given key or index exists in the array
  52. 'array_keys', // Return all the keys of an array
  53. 'array_merge_recursive',// Merge two or more arrays recursively
  54. 'array_merge', // Merge one or more arrays
  55. 'array_multisort', // Sort multiple or multi-dimensional arrays
  56. 'array_pad', // Pad array to the specified length with a value
  57. 'array_pop', // Pop the element off the end of array
  58. 'array_product', // Calculate the product of values in an array
  59. 'array_push', // Push one or more elements onto the end of array
  60. 'array_rand', // Pick one or more random entries out of an array
  61. 'array_reverse', // Return an array with elements in reverse order
  62. 'array_search', // Searches the array for a given value and returns the corresponding key if successful
  63. 'array_shift', // Shift an element off the beginning of array
  64. 'array_slice', // Extract a slice of the array
  65. 'array_splice', // Remove a portion of the array and replace it with something else
  66. 'array_sum', // Calculate the sum of values in an array
  67. 'array_unique', // Removes duplicate values from an array
  68. 'array_unshift', // Prepend one or more elements to the beginning of an array
  69. 'array_values', // Return all the values of an array
  70. 'array', // Create an array
  71. 'arsort', // Sort an array in reverse order and maintain index association
  72. 'asort', // Sort an array and maintain index association
  73. 'compact', // Create array containing variables and their values
  74. 'count', // Count elements in an array, or properties in an object
  75. 'current', // Return the current element in an array
  76. 'each', // Return the current key and value pair from an array and advance the array cursor
  77. 'end', // Set the internal pointer of an array to its last element
  78. 'in_array', // Checks if a value exists in an array
  79. 'key', // Fetch a key from an associative array
  80. 'krsort', // Sort an array by key in reverse order
  81. 'ksort', // Sort an array by key
  82. 'natcasesort', // Sort an array using a case insensitive "natural order" algorithm
  83. 'natsort', // Sort an array using a "natural order" algorithm
  84. 'next', // Advance the internal array pointer of an array
  85. 'pos', // Alias of current
  86. 'prev', // Rewind the internal array pointer
  87. 'range', // Create an array containing a range of elements
  88. 'reset', // Set the internal pointer of an array to its first element
  89. 'rsort', // Sort an array in reverse order
  90. 'shuffle', // Shuffle an array
  91. 'sizeof', // Alias of count
  92. 'sort', // Sort an array
  93. // Strings Functions
  94. 'chop', // Alias of rtrim
  95. 'count_chars', // Return information about characters used in a string
  96. 'explode', // Split a string by string
  97. 'implode', // Join array elements with a string
  98. 'join', // Alias of implode
  99. 'levenshtein', // Calculate Levenshtein distance between two strings
  100. 'ltrim', // Strip whitespace (or other characters) from the beginning of a string
  101. 'metaphone', // Calculate the metaphone key of a string
  102. 'money_format', // Formats a number as a currency string
  103. 'number_format', // Format a number with grouped thousands
  104. 'rtrim', // Strip whitespace (or other characters) from the end of a string
  105. 'similar_text', // Calculate the similarity between two strings
  106. 'soundex', // Calculate the soundex key of a string
  107. 'str_getcsv', // Parse a CSV string into an array
  108. 'str_ireplace', // Case-insensitive version of str_replace.
  109. 'str_pad', // Pad a string to a certain length with another string
  110. 'str_repeat', // Repeat a string
  111. 'str_replace', // Replace all occurrences of the search string with the replacement string
  112. 'str_rot13', // Perform the rot13 transform on a string
  113. 'str_shuffle', // Randomly shuffles a string
  114. 'str_split', // Convert a string to an array
  115. 'str_word_count', // Return information about words used in a string
  116. 'strcasecmp', // Binary safe case-insensitive string comparison
  117. 'strchr', // Alias of strstr
  118. 'strcmp', // Binary safe string comparison
  119. 'strcspn', // Find length of initial segment not matching mask
  120. 'stripos', // Find position of first occurrence of a case-insensitive string
  121. 'stristr', // Case-insensitive strstr
  122. 'strlen', // Get string length
  123. 'strnatcasecmp', // Case insensitive string comparisons using a "natural order" algorithm
  124. 'strnatcmp', // String comparisons using a "natural order" algorithm
  125. 'strncasecmp', // Binary safe case-insensitive string comparison of the first n characters
  126. 'strncmp', // Binary safe string comparison of the first n characters
  127. 'strpbrk', // Search a string for any of a set of characters
  128. 'strpos', // Find position of first occurrence of a string
  129. 'strrchr', // Find the last occurrence of a character in a string
  130. 'strrev', // Reverse a string
  131. 'strripos', // Find position of last occurrence of a case-insensitive string in a string
  132. 'strrpos', // Find position of last occurrence of a char in a string
  133. 'strspn', // Find length of initial segment matching mask
  134. 'strstr', // Find first occurrence of a string
  135. 'strtolower', // Make a string lowercase
  136. 'strtoupper', // Make a string uppercase
  137. 'strtr', // Translate certain characters
  138. 'substr_compare', // Binary safe comparison of 2 strings from an offset, up to length characters
  139. 'substr_count', // Count the number of substring occurrences
  140. 'substr_replace', // Replace text within a portion of a string
  141. 'substr', // Return part of a string
  142. 'trim', // Strip whitespace (or other characters) from the beginning and end of a string
  143. 'ucfirst', // Make a string's first character uppercase
  144. 'ucwords', // Uppercase the first character of each word in a string
  145. 'wordwrap' // Wraps a string to a given number of characters
  146. );
  147. private static $allowedTokens = array(
  148. 'T_AND_EQUAL', // assignment operators
  149. 'T_ARRAY', // array(), array syntax
  150. 'T_ARRAY_CAST', // type-casting
  151. 'T_AS', // foreach
  152. 'T_BOOLEAN_AND', // logical operators
  153. 'T_BOOLEAN_OR', // logical operators
  154. 'T_BOOL_CAST', // type-casting
  155. 'T_BREAK', // break
  156. 'T_CASE', // switch
  157. 'T_CHARACTER', // ?
  158. 'T_COMMENT', // comments
  159. 'T_CONCAT_EQUAL', // assignment operators
  160. 'T_CONSTANT_ENCAPSED_STRING', // string syntax
  161. 'T_CONTINUE', //
  162. 'T_CURLY_OPEN', //
  163. 'T_DEC', // incrementing/decrementing operators
  164. 'T_DECLARE', // declare
  165. 'T_DEFAULT', // switch
  166. 'T_DIV_EQUAL', // assignment operators
  167. 'T_DNUMBER', // floating point numbers
  168. 'T_DO', // do..while
  169. 'T_DOUBLE_ARROW', // array syntax
  170. 'T_DOUBLE_CAST', // type-casting
  171. 'T_ECHO', //
  172. 'T_ELSE', // else
  173. 'T_ELSEIF', // elseif
  174. 'T_EMPTY', // empty()
  175. 'T_ENCAPSED_AND_WHITESPACE', // ?
  176. 'T_ENDDECLARE', // declare, alternative syntax
  177. 'T_ENDFOR', // for, alternative syntax
  178. 'T_ENDFOREACH', // foreach, alternative syntax
  179. 'T_ENDIF', // if, alternative syntax
  180. 'T_ENDSWITCH', // switch, alternative syntax
  181. 'T_FOR', // for
  182. 'T_FOREACH', // foreach
  183. 'T_IF', // if
  184. 'T_INC', // incrementing/decrementing operators
  185. 'T_INT_CAST', // type-casting
  186. 'T_ISSET', // isset()
  187. 'T_IS_EQUAL', // comparison operators
  188. 'T_IS_GREATER_OR_EQUAL', // comparison operators
  189. 'T_IS_IDENTICAL', // comparison operators
  190. 'T_IS_NOT_EQUAL', // comparison operators
  191. 'T_IS_NOT_IDENTICAL', // comparison operators
  192. 'T_IS_SMALLER_OR_EQUAL', // comparison operators
  193. 'T_LNUMBER', // integers
  194. 'T_LOGICAL_AND', // logical operators
  195. 'T_LOGICAL_OR', // logical operators
  196. 'T_LOGICAL_XOR', // logical operators
  197. 'T_MINUS_EQUAL', // assignment operators
  198. 'T_MOD_EQUAL', // assignment operators
  199. 'T_MUL_EQUAL', // assignment operators
  200. 'T_NUM_STRING', // ?
  201. 'T_OR_EQUAL', // assignment operators
  202. 'T_PLUS_EQUAL', // assignment operators
  203. 'T_RETURN', // returning values
  204. 'T_SL', // bitwise operators
  205. 'T_SL_EQUAL', // assignment operators
  206. 'T_SR', // bitwise operators
  207. 'T_SR_EQUAL', // assignment operators
  208. 'T_STRING', // ?
  209. 'T_STRING_CAST', // type-casting
  210. 'T_STRING_VARNAME', // ?
  211. 'T_SWITCH', // switch
  212. 'T_UNSET', // unset()
  213. 'T_UNSET_CAST', // (not documented; casts to NULL)
  214. 'T_VARIABLE', // variables
  215. 'T_WHILE', // while, do..while
  216. 'T_WHITESPACE', //
  217. 'T_XOR_EQUAL', // assignment operators
  218. 'T_PRINT',
  219. 'T_PRINT_R',
  220. 'T_FUNCTION',
  221. 'T_OBJECT_OPERATOR',
  222. 'T_DOUBLE_COLON',
  223. 'T_CLASS',
  224. 'T_CONST',
  225. 'T_EXTENDS',
  226. 'T_NEW',
  227. 'T_PRIVATE',
  228. 'T_PUBLIC',
  229. 'T_PROTECTED',
  230. 'T_CLASS_C',
  231. 'T_METHOD_C',
  232. 'T_LIST',
  233. 'T_STATIC',
  234. 'T_NAMESPACE',
  235. 'T_NS_SEPARATOR',
  236. 'T_NS_C',
  237. 'T_CLONE',
  238. 'T_EXIT',
  239. 'T_INCLUDE',
  240. 'T_INCLUDE_ONCE',
  241. 'T_REQUIRE',
  242. 'T_TRY',
  243. 'T_CATCH'
  244. );
  245. private static $disallowedExpressions = array(
  246. '/`/', // Shell execution operator: "`"
  247. // '/\$\W/', // Variable variables: any "$" which is not "$_" or "$alphanumeric"
  248. '/(\]|\})\s*\(/', // Variable functions: "] (" or "} ("
  249. '/\$\w\w*\s*\(/', // Variable functions: "$_ (" or "$alphanumeric"
  250. );
  251. private static $disabledFunctions = array("eval", "call_user_func_array","call_user_func","create_function","forward_static_call_array","forward_static_call","func_get_arg","func_get_args","func_num_args","function_exists","get_defined_functions","register_shutdown_function","register_tick_function","unregister_tick_function", "file_put_contents", "file", "ini_set", "ini_get", "mail", "phpinfo", "setenv", "getenv", "socket_create", "socket_bind", "socket_listen", "socket_create_listen", "socket_create_pair", "socket_accept", "pcntl_fork", "exec", "passthru", "shell_exec", "system", "proc_open", "popen", "parse_ini_file", "show_source", "glob", "opendir", "readdir", "set_time_limit", "unlink", "rmdir", "mkdir", "rename", "copy", "dir", "scandir", "ftp_connect", "ftp_ssl_connect", "openlog", "syslog", "fsockopen", "define_syslog_variables", "pfsockopen", "snmp2_get", "snmp3_get", "snmp2_walk", "snmp2_real_walk", "snmp2_getnext", "snmp3_walk", "snmp3_real_walk", "snmpget", "snmpwalk", "snmpgetnext", "snmprealwalk", "snmp3_getnext", "snmpwalkoid", "ssh2_connect", "ssh2_fetch_stream", "ssh2_tunnel", "yaz_connect", "yaz_wait", "disk_free_space", "disk_total_space", "flock", "link", "tempnam", "tmpfile", "touch", "symlink", "pcntl_exec", "posix_kill", "posix_mkfifo", "posix_mknod", "fopen", "stream_socket_server", "stream_socket_client", "stream_socket_pair", "gc_disable", "ob_end_flush", "flush", "ini_get_all", "get_loaded_extensions", "ini_alter", "chmod", "chgrp", "chown", "posix_access", "posix_ctermid", "posix_errno", "posix_get_last_error", "posix_getcwd", "posix_getegid", "posix_geteuid", "posix_getgid", "posix_getgrgid", "posix_getgrnam", "posix_getgroups", "posix_getlogin", "posix_getpgid", "posix_getpgrp", "posix_getpid", "posix_getppid", "posix_getpwnam", "posix_getpwuid", "posix_getrlimit", "posix_getsid", "posix_getuid", "posix_initgroups", "posix_isatty", "posix_kill", "posix_mkfifo", "posix_mknod", "posix_setegid", "posix_seteuid", "posix_setgid", "posix_setpgid", "posix_setsid", "posix_setuid", "posix_strerror", "posix_times", "posix_ttyname", "posix_uname", "chdir", "opendir", "readdir", "debug_backtrace", "debug_print_backtrace");
  252. public static function getSetting($setting) {
  253. return self::$$setting;
  254. }
  255. public function Safe() {
  256. }
  257. public function evalSyntax($code) { // Separate function for checking syntax without breaking the script
  258. ob_start(); // Catch potential parse error messages
  259. $code = eval('if(0){' . "\n" . $code . "\n" . '}'); // Put $code in a dead code sandbox to prevent its execution
  260. ob_end_clean();
  261. return $code !== false;
  262. }
  263. public function checkScript($code, $execute) {
  264. $this->execute = $execute;
  265. $this->code = $code;
  266. $this->tokens = token_get_all('<?php '.$this->code.' ?>');
  267. $this->errors = array();
  268. $this->braces = 0;
  269. // STEP 1: SYNTAX - Check if braces are balanced
  270. foreach ($this->tokens as $token) {
  271. if ($token == '{') $this->braces = $this->braces + 1;
  272. else if ($token == '}') $this->braces = $this->braces - 1;
  273. if ($this->braces < 0) { // Closing brace before one is open
  274. $this->errors[0]['name'] = 'Unbalanced braces.';
  275. break;
  276. }
  277. }
  278. if (empty($this->errors)) {
  279. if ($this->braces) $this->errors[0]['name'] = 'Unbalanced braces.';
  280. }
  281. // STEP 2: SYNTAX - Check if syntax is valid
  282. else if (!$this->evalSyntax($this->code)) {
  283. $this->errors[0]['name'] = 'Syntax error.';
  284. }
  285. // STEP 3: EXPRESSIONS - Check against various insecure elements
  286. if (empty($this->errors)) foreach ($this->getSetting('disallowedExpressions') as $disallowedExpression) {
  287. unset($matches);
  288. preg_match($disallowedExpression, $this->code, $matches);
  289. if($matches) {
  290. //$this->errors[0]['name'] = 'Execution operator / variable function name / variable variable name detected.';
  291. $this->errors[0]['name'] = 'Execution operator / variable function name';
  292. break;
  293. }
  294. }
  295. // STEP 4: TOKENS
  296. if(empty($this->errors)) {
  297. unset($this->tokens[0]);
  298. unset($this->tokens[0]);
  299. array_pop($this->tokens);
  300. array_pop($this->tokens);
  301. $i = 0;
  302. //var_dump($this->tokens);
  303. foreach ($this->tokens as $key => $token) {
  304. $i++;
  305. if (is_array($token)) {
  306. $id = token_name($token[0]);
  307. switch ($id) {
  308. case('T_STRING'):
  309. if (in_array($token[1], $this->getSetting('disabledFunctions')) === true) {
  310. $this->errors[$i]['name'] = 'Illegal function: ' . $token[1];
  311. $this->errors[$i]['line'] = $token[2];
  312. }
  313. if($token[1] == 'file_get_contents') {
  314. $this->tokens[$i][1] = '$this->safe_file_get_contents';
  315. }
  316. /*if($token[1] == 'preg_replace') {
  317. //&& strpos($token[2],'eval') !== false
  318. //print_r($this->tokens[$i]);
  319. $this->errors[$i]['name'] = 'Illegal Eval: ' . $token[1];
  320. $this->errors[$i]['line'] = $token[2];
  321. }*/
  322. break;
  323. default:
  324. if (in_array($id, $this->getSetting('allowedTokens')) === false) {
  325. $this->errors[$i]['name'] = 'Illegal token: ' . $token[1];
  326. $this->errors[$i]['line'] = $token[2];
  327. }
  328. break;
  329. }
  330. }
  331. }
  332. }
  333. $this->code = '';
  334. foreach($this->tokens as $key => $token) {
  335. if(is_array($token)) {
  336. $this->code .= $token[1];
  337. } else {
  338. $this->code .= $token;
  339. }
  340. }
  341. if(!empty($this->errors)) {
  342. return array('error' => true, 'errors' => $this->errors);
  343. } else if ($this->execute) {
  344. //$this->code = str_replace(array("\n","\r","\r\n"), "\r\n", $this->code);
  345. ob_start();
  346. //ini_set('open_basedir', '/srv/www/code.ignite.io/public_html/tmp/');
  347. eval($this->code);
  348. $output = ob_get_contents();
  349. ob_end_clean();
  350. //$output = str_replace(array("\\r\\n", "\\n"), "\r\n", $output);
  351. $end = array('output' => $output);
  352. if(isset($error)) $end['error'] = $error;
  353. return $end;
  354. }
  355. }
  356. public function htmlErrors ($errors = null) {
  357. if ($errors) {
  358. $this->errors = $errors;
  359. $this->errorsHTML = '<dl>';
  360. foreach ($this->errors as $error) {
  361. if (isset($error['line']) && $error['line']) {
  362. $this->errorsHTML .= '<dt>Line '.$error['line'].'</dt>';
  363. $error['line']++;
  364. }
  365. $this->errorsHTML .= '<dd>'.$error['name'].'</dd>';
  366. }
  367. $this->errorsHTML .= '</dl>';
  368. return($this->errorsHTML);
  369. }
  370. }
  371. public function textErrors($errors = null) {
  372. if($errors) {
  373. foreach($errors as $error) {
  374. $this->errorsText .= $error['name'];
  375. }
  376. return($this->errorsText);
  377. }
  378. }
  379. public function safe_file_get_contents($url) {
  380. $ch = curl_init();
  381. $timeout = 30;
  382. curl_setopt($ch,CURLOPT_URL,$url);
  383. curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
  384. curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
  385. $data = curl_exec($ch);
  386. curl_close($ch);
  387. return $data;
  388. }
  389. }