PageRenderTime 80ms CodeModel.GetById 40ms RepoModel.GetById 0ms app.codeStats 0ms

/sputnik/Form.php

https://github.com/voov/Sputnik-Framework
PHP | 202 lines | 138 code | 42 blank | 22 comment | 23 complexity | 75f68b2033910581391ad5c4651122cf MD5 | raw file
  1. <?php
  2. require_once "FormValidator.php";
  3. require_once "FormEvent.php";
  4. class Form {
  5. private $notsafe_vars = array();
  6. private static $instance = false;
  7. private static $own_data = array();
  8. function __construct() {
  9. $this->notsafe_vars = $_POST;
  10. // Clean POST
  11. foreach ($_POST as $post_key => $post_value) {
  12. if (!preg_match("/^[a-z0-9:_\/-]+$/i", $post_key))
  13. trigger_error("Not safe var key ('$post_key')!");
  14. $_POST[$post_key . ":unsafe"] = $post_value;
  15. $_POST[$post_key] = $this->XSS_Clean($post_value);
  16. }
  17. }
  18. public static function GetInstance() {
  19. if(self::$instance == false) self::$instance = new Form();
  20. return self::$instance;
  21. }
  22. public static function GI() {
  23. return self::GetInstance();
  24. }
  25. private function GetFileExt($filename) {
  26. return substr(strrchr($filename, '.'), 1);
  27. }
  28. private function GetUniqueFilename($filename) {
  29. $ext = $this->GetFileExt($filename);
  30. // explode the IP of the remote client into four parts
  31. $ipbits = explode(".", $_SERVER["REMOTE_ADDR"]);
  32. // Get both seconds and microseconds parts of the time
  33. list($usec, $sec) = explode(" ", microtime());
  34. // Fudge the time we just got to create two 16 bit words
  35. $usec = (integer) ($usec * 65536);
  36. $sec = ((integer) $sec) & 0xFFFF;
  37. // Fun bit - convert the remote client's IP into a 32 bit
  38. // hex number then tag on the time.
  39. // Result of this operation looks like this xxxxxxxx-xxxx-xxxx
  40. $uid = sprintf("%08x%04x%04x.%s", ($ipbits[0] << 24)
  41. | ($ipbits[1] << 16)
  42. | ($ipbits[2] << 8)
  43. | $ipbits[3], $sec, $usec, $ext);
  44. return $uid;
  45. }
  46. private function UploadArray($array, $upload_dir, $use_unique) {
  47. $buffer = array();
  48. foreach($array as $arr) {
  49. if($arr["error"] != UPLOAD_ERR_OK) return false;
  50. $filename = $use_unique ? $this->GetUniqueFilename($_FILES[$name]["name"]) : $_FILES[$name]["name"];
  51. $fulldir = $upload_dir ."/". $filename;
  52. $buffer[] = $fulldir;
  53. move_uploaded_file($arr["tmp_name"], $fulldir);
  54. }
  55. return $buffer;
  56. }
  57. public function UploadData($name, $upload_dir, $use_unique=false) {
  58. ini_set("upload_max_filesize", 12328960);
  59. ini_set("post_max_size", 12328960);
  60. if(!isset($_FILES[$name])) return false;
  61. if(isset($_FILES[$name][0]["name"])) return $this->UploadArray($_FILES[$name], $upload_dir, $use_unique);
  62. if($_FILES[$name]["error"] != UPLOAD_ERR_OK) {
  63. return false;
  64. }
  65. $filename = $use_unique ? $this->GetUniqueFilename($_FILES[$name]["name"]) : $_FILES[$name]["name"];
  66. $fulldir = $upload_dir ."/". $filename;
  67. if(!move_uploaded_file($_FILES[$name]["tmp_name"],$fulldir)) {
  68. trigger_error("Cannot upload file");
  69. }
  70. return $fulldir;
  71. }
  72. public function ClearAll() {
  73. // Clear all data sent from the browser
  74. //$_POST = array(); $_GET = array(); $_FILES = array();
  75. }
  76. public function GetNotSafe($name) {
  77. return $this->notsafe_vars[$name];
  78. }
  79. public function GetField($name, $use_regex) {
  80. $field_buffer = array();
  81. $wildcards = array("*" => "(?:.*?)", "?" => "(?:.{1})", "+" => "(?:.+?)");
  82. // we don't want to use regular expressions by default
  83. $field_final = $name;
  84. if ($use_regex == false)
  85. $field_final = strtr($name, $wildcards);
  86. foreach ($_POST as $key => $value) {
  87. if (preg_match("/^$field_final$/i", $key)) $field_buffer[$key] = $_POST[$key];
  88. }
  89. if(count($field_buffer) == 1) return $field_buffer[0];
  90. return $field_buffer;
  91. }
  92. public function __get($name) {
  93. return $_POST[$name];
  94. }
  95. public static function StartForm($name, $action, $method="post", $enctype="application/x-www-form-urlencoded") {
  96. $form = Form::Factory();
  97. //$action = URI::MakeURL($action);
  98. return "<form action='$action' method='$method' name='$name' id='$name' enctype='$enctype'>" .
  99. HtmlBuilder::HtmlBuilder("input")->type("hidden")->name(":input_token")->value(Sessions::GetInstance()->input_token) .
  100. HtmlBuilder::HtmlBuilder("input")->type("hidden")->name(":input_name")->value($name);
  101. }
  102. public static function EndForm() {
  103. return "</form>";
  104. }
  105. public static function Factory() {
  106. return self::GetInstance();
  107. }
  108. public static function GetValidator() {
  109. return new FormValidator();
  110. }
  111. public static function GenerateInputToken() {
  112. if(Sessions::GetInstance()->input_token == false) {
  113. $token = uniqid();
  114. Sessions::GetInstance()->input_token = $token;
  115. }
  116. }
  117. public static function OnSubmit($name, $func) {
  118. if($_POST[":input_name"] != $name || $_POST[":input_token"] != Sessions::GetInstance()->input_token) {
  119. return;
  120. }
  121. call_user_func($func, $_POST);
  122. }
  123. private function XSS_Clean($data) {
  124. if(is_array($data)) {
  125. return $data;
  126. /*foreach($data as $value) {
  127. $this->XSS_Clean($value);
  128. }*/
  129. }
  130. $data = urldecode($data);
  131. // Fix &entity\n;
  132. $data = str_replace(array('&amp;', '&lt;', '&gt;'), array('&amp;amp;', '&amp;lt;', '&amp;gt;'), $data);
  133. $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
  134. $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
  135. $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
  136. // Remove any attribute starting with "on" or xmlns
  137. $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
  138. // Remove javascript: and vbscript: protocols
  139. $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
  140. $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
  141. $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
  142. // Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
  143. $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
  144. $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
  145. $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
  146. // Remove namespaced elements (we do not need them)
  147. $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
  148. do
  149. {
  150. // Remove really unwanted tags
  151. $old_data = $data;
  152. $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
  153. //$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
  154. }
  155. while ($old_data !== $data);
  156. // we are done...
  157. return $data;
  158. }
  159. }
  160. ?>