You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

191 lines
4.3 KiB

  1. <?php
  2. /**
  3. * eval source code in PHP or JSON format
  4. *
  5. */
  6. class VarEval {
  7. /**
  8. * Source to run
  9. *
  10. * @var string
  11. */
  12. private $_source;
  13. /**
  14. * Source Format
  15. *
  16. * @var string
  17. */
  18. private $_format;
  19. /**
  20. * current MongoDB
  21. *
  22. * @var MongoDB
  23. */
  24. private $_db;
  25. function __construct($source, $format = "array", MongoDB $db = null) {
  26. $this->_source = $source;
  27. $this->_format = $format;
  28. if (!$this->_format) {
  29. $this->_format = "array";
  30. }
  31. $this->_db = $db;
  32. }
  33. /**
  34. * execute the code
  35. *
  36. * @return mixed
  37. */
  38. function execute() {
  39. if ($this->_format == "array") {
  40. return $this->_runPHP();
  41. }
  42. else if ($this->_format == "json") {
  43. return $this->_runJson();
  44. }
  45. }
  46. private function _runPHP() {
  47. $this->_source = "return " . $this->_source . ";";
  48. if (function_exists("token_get_all")) {//tokenizer extension may be disabled
  49. $php = "<?php\n" . $this->_source . "\n?>";
  50. $tokens = token_get_all($php);
  51. foreach ($tokens as $token) {
  52. $type = $token[0];
  53. if (is_long($type)) {
  54. if (in_array($type, array(
  55. T_OPEN_TAG,
  56. T_RETURN,
  57. T_WHITESPACE,
  58. T_ARRAY,
  59. T_LNUMBER,
  60. T_DNUMBER,
  61. T_CONSTANT_ENCAPSED_STRING,
  62. T_DOUBLE_ARROW,
  63. T_CLOSE_TAG,
  64. T_NEW,
  65. T_DOUBLE_COLON
  66. ))) {
  67. continue;
  68. }
  69. if ($type == T_STRING) {
  70. $func = strtolower($token[1]);
  71. if (in_array($func, array(
  72. //keywords allowed
  73. "mongoid",
  74. "mongocode",
  75. "mongodate",
  76. "mongoregex",
  77. "mongobindata",
  78. "mongoint32",
  79. "mongoint64",
  80. "mongodbref",
  81. "mongominkey",
  82. "mongomaxkey",
  83. "mongotimestamp",
  84. "true",
  85. "false",
  86. "null",
  87. "__set_state",
  88. "stdclass"
  89. ))) {
  90. continue;
  91. }
  92. }
  93. exit("For your security, we stoped data parsing at '(" . token_name($type) . ") " . $token[1] . "'.");
  94. }
  95. }
  96. }
  97. return eval($this->_source);
  98. }
  99. private function _runJson() {
  100. $timezone = @date_default_timezone_get();
  101. date_default_timezone_set("UTC");
  102. $ret = $this->_db->execute('function () {
  103. if (typeof(ISODate) == "undefined") {
  104. function ISODate (isoDateStr) {
  105. if (!isoDateStr) {
  106. return new Date;
  107. }
  108. var isoDateRegex = /(\d{4})-?(\d{2})-?(\d{2})([T ](\d{2})(:?(\d{2})(:?(\d{2}(\.\d+)?))?)?(Z|([+-])(\d{2}):?(\d{2})?)?)?/;
  109. var res = isoDateRegex.exec(isoDateStr);
  110. if (!res) {
  111. throw "invalid ISO date";
  112. }
  113. var year = parseInt(res[1], 10) || 1970;
  114. var month = (parseInt(res[2], 10) || 1) - 1;
  115. var date = parseInt(res[3], 10) || 0;
  116. var hour = parseInt(res[5], 10) || 0;
  117. var min = parseInt(res[7], 10) || 0;
  118. var sec = parseFloat(res[9]) || 0;
  119. var ms = Math.round(sec % 1 * 1000);
  120. sec -= ms / 1000;
  121. var time = Date.UTC(year, month, date, hour, min, sec, ms);
  122. if (res[11] && res[11] != "Z") {
  123. var ofs = 0;
  124. ofs += (parseInt(res[13], 10) || 0) * 60 * 60 * 1000;
  125. ofs += (parseInt(res[14], 10) || 0) * 60 * 1000;
  126. if (res[12] == "+") {
  127. ofs *= -1;
  128. }
  129. time += ofs;
  130. }
  131. return new Date(time);
  132. };
  133. };
  134. function r_util_convert_empty_object_to_string(obj) {
  135. if (r_util_is_empty(obj)) {
  136. return "__EMPTYOBJECT__";
  137. }
  138. if (typeof(obj) == "object") {
  139. for (var k in obj) {
  140. obj[k] = r_util_convert_empty_object_to_string(obj[k]);
  141. }
  142. }
  143. return obj;
  144. };
  145. function r_util_is_empty(obj) {
  146. if (obj == null || typeof(obj) != "object" || (obj.constructor != Object)) {
  147. return false;
  148. }
  149. for(var k in obj) {
  150. if(obj.hasOwnProperty(k)) {
  151. return false;
  152. }
  153. }
  154. return true;
  155. };
  156. var o = ' . $this->_source . '; return r_util_convert_empty_object_to_string(o); }'
  157. );
  158. $this->_fixEmptyObject($ret);
  159. date_default_timezone_set($timezone);
  160. if ($ret["ok"]) {
  161. return $ret["retval"];
  162. }
  163. return json_decode($this->_source, true);
  164. }
  165. private function _fixEmptyObject(&$object) {
  166. if (is_array($object)) {
  167. foreach ($object as &$v) {
  168. $this->_fixEmptyObject($v);
  169. }
  170. }
  171. else if (is_string($object) && $object === "__EMPTYOBJECT__") {
  172. $object = new stdClass();
  173. }
  174. }
  175. }
  176. ?>