PageRenderTime 37ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/ext/std/ext_std_variable.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 489 lines | 402 code | 57 blank | 30 comment | 82 complexity | cbf38aab837bf2eb3dc3a853eca2a032 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/std/ext_std_variable.h"
  18. #include <folly/Likely.h>
  19. #include "hphp/util/logger.h"
  20. #include "hphp/runtime/base/variable-serializer.h"
  21. #include "hphp/runtime/base/variable-unserializer.h"
  22. #include "hphp/runtime/base/builtin-functions.h"
  23. #include "hphp/runtime/base/zend-functions.h"
  24. #include "hphp/runtime/ext/xdebug/ext_xdebug.h"
  25. #include "hphp/runtime/vm/jit/translator-inline.h"
  26. #include "hphp/runtime/server/http-protocol.h"
  27. namespace HPHP {
  28. ///////////////////////////////////////////////////////////////////////////////
  29. const StaticString
  30. s_unknown_type("unknown type"),
  31. s_boolean("boolean"),
  32. s_bool("bool"),
  33. s_integer("integer"),
  34. s_int("int"),
  35. s_float("float"),
  36. s_double("double"),
  37. s_string("string"),
  38. s_object("object"),
  39. s_array("array"),
  40. s_null("null");
  41. String HHVM_FUNCTION(gettype, const Variant& v) {
  42. if (v.getType() == KindOfResource && v.getResourceData()->isInvalid()) {
  43. return s_unknown_type;
  44. }
  45. return getDataTypeString(v.getType());
  46. }
  47. String HHVM_FUNCTION(get_resource_type, const Resource& handle) {
  48. return handle->o_getResourceName();
  49. }
  50. bool HHVM_FUNCTION(boolval, const Variant& v) {
  51. return v.toBoolean();
  52. }
  53. int64_t HHVM_FUNCTION(intval, const Variant& v, int64_t base /* = 10 */) {
  54. return v.toInt64(base);
  55. }
  56. double HHVM_FUNCTION(floatval, const Variant& v) {
  57. return v.toDouble();
  58. }
  59. String HHVM_FUNCTION(strval, const Variant& v) {
  60. return v.toString();
  61. }
  62. bool HHVM_FUNCTION(settype, VRefParam var, const String& type) {
  63. if (type == s_boolean) var = var.toBoolean();
  64. else if (type == s_bool ) var = var.toBoolean();
  65. else if (type == s_integer) var = var.toInt64();
  66. else if (type == s_int ) var = var.toInt64();
  67. else if (type == s_float ) var = var.toDouble();
  68. else if (type == s_double ) var = var.toDouble();
  69. else if (type == s_string ) var = var.toString();
  70. else if (type == s_array ) var = var.toArray();
  71. else if (type == s_object ) var = var.toObject();
  72. else if (type == s_null ) var = uninit_null();
  73. else return false;
  74. return true;
  75. }
  76. bool HHVM_FUNCTION(is_null, const Variant& v) {
  77. return is_null(v);
  78. }
  79. bool HHVM_FUNCTION(is_bool, const Variant& v) {
  80. return is_bool(v);
  81. }
  82. bool HHVM_FUNCTION(is_int, const Variant& v) {
  83. return is_int(v);
  84. }
  85. bool HHVM_FUNCTION(is_float, const Variant& v) {
  86. return is_double(v);
  87. }
  88. bool HHVM_FUNCTION(is_numeric, const Variant& v) {
  89. return v.isNumeric(true);
  90. }
  91. bool HHVM_FUNCTION(is_string, const Variant& v) {
  92. return is_string(v);
  93. }
  94. bool HHVM_FUNCTION(is_scalar, const Variant& v) {
  95. return v.isScalar();
  96. }
  97. bool HHVM_FUNCTION(is_array, const Variant& v) {
  98. return is_array(v);
  99. }
  100. bool HHVM_FUNCTION(is_object, const Variant& v) {
  101. return is_object(v);
  102. }
  103. bool HHVM_FUNCTION(is_resource, const Variant& v) {
  104. return (v.getType() == KindOfResource && !v.getResourceData()->isInvalid());
  105. }
  106. ///////////////////////////////////////////////////////////////////////////////
  107. // input/output
  108. Variant HHVM_FUNCTION(print_r, const Variant& expression,
  109. bool ret /* = false */) {
  110. Variant res;
  111. try {
  112. VariableSerializer vs(VariableSerializer::Type::PrintR);
  113. if (ret) {
  114. res = vs.serialize(expression, ret);
  115. } else {
  116. vs.serialize(expression, ret);
  117. res = true;
  118. }
  119. } catch (StringBufferLimitException &e) {
  120. raise_notice("print_r() exceeded max bytes limit");
  121. res = e.m_result;
  122. }
  123. return res;
  124. }
  125. Variant HHVM_FUNCTION(var_export, const Variant& expression,
  126. bool ret /* = false */) {
  127. Variant res;
  128. try {
  129. VariableSerializer vs(VariableSerializer::Type::VarExport);
  130. if (ret) {
  131. res = vs.serialize(expression, ret);
  132. } else {
  133. vs.serialize(expression, ret);
  134. res = true;
  135. }
  136. } catch (StringBufferLimitException &e) {
  137. raise_notice("var_export() exceeded max bytes limit");
  138. }
  139. return res;
  140. }
  141. static ALWAYS_INLINE void do_var_dump(VariableSerializer vs,
  142. const Variant& expression) {
  143. // manipulate maxCount to match PHP behavior
  144. if (!expression.isObject()) {
  145. vs.incMaxCount();
  146. }
  147. vs.serialize(expression, false);
  148. }
  149. void HHVM_FUNCTION(var_dump, const Variant& expression,
  150. const Array& _argv /*=null_array */) {
  151. if (UNLIKELY(XDEBUG_GLOBAL(OverloadVarDump) &&
  152. XDEBUG_GLOBAL(DefaultEnable))) {
  153. HHVM_FN(xdebug_var_dump)(expression, _argv);
  154. return;
  155. }
  156. VariableSerializer vs(VariableSerializer::Type::VarDump, 0, 2);
  157. do_var_dump(vs, expression);
  158. auto sz = _argv.size();
  159. for (int i = 0; i < sz; i++) {
  160. do_var_dump(vs, _argv[i]);
  161. }
  162. }
  163. void HHVM_FUNCTION(debug_zval_dump, const Variant& variable) {
  164. VariableSerializer vs(VariableSerializer::Type::DebugDump);
  165. vs.serialize(variable, false);
  166. }
  167. const StaticString
  168. s_Null("N;"),
  169. s_True("b:1;"),
  170. s_False("b:0;"),
  171. s_Res("i:0;"),
  172. s_EmptyArray("a:0:{}");
  173. String HHVM_FUNCTION(serialize, const Variant& value) {
  174. switch (value.getType()) {
  175. case KindOfUninit:
  176. case KindOfNull:
  177. return s_Null;
  178. case KindOfBoolean:
  179. return value.getBoolean() ? s_True : s_False;
  180. case KindOfInt64: {
  181. StringBuffer sb;
  182. sb.append("i:");
  183. sb.append(value.getInt64());
  184. sb.append(';');
  185. return sb.detach();
  186. }
  187. case KindOfStaticString:
  188. case KindOfString: {
  189. StringData *str = value.getStringData();
  190. StringBuffer sb;
  191. sb.append("s:");
  192. sb.append(str->size());
  193. sb.append(":\"");
  194. sb.append(str->data(), str->size());
  195. sb.append("\";");
  196. return sb.detach();
  197. }
  198. case KindOfResource:
  199. return s_Res;
  200. case KindOfArray: {
  201. ArrayData *arr = value.getArrayData();
  202. if (arr->empty()) return s_EmptyArray;
  203. // fall-through
  204. }
  205. case KindOfDouble:
  206. case KindOfObject: {
  207. VariableSerializer vs(VariableSerializer::Type::Serialize);
  208. return vs.serialize(value, true);
  209. }
  210. case KindOfRef:
  211. case KindOfClass:
  212. break;
  213. }
  214. not_reached();
  215. }
  216. Variant HHVM_FUNCTION(unserialize, const String& str,
  217. const Array& class_whitelist /* =[] */) {
  218. return unserialize_from_string(str, class_whitelist);
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////
  221. // variable table
  222. ALWAYS_INLINE
  223. static Array get_defined_vars() {
  224. VarEnv* v = g_context->getOrCreateVarEnv();
  225. return v ? v->getDefinedVariables() : empty_array();
  226. }
  227. Array HHVM_FUNCTION(get_defined_vars) {
  228. raise_disallowed_dynamic_call("get_defined_vars should not be "
  229. "called dynamically");
  230. return get_defined_vars();
  231. }
  232. // accessible as __SystemLib\\get_defined_vars
  233. Array HHVM_FUNCTION(SystemLib_get_defined_vars) {
  234. return get_defined_vars();
  235. }
  236. const StaticString
  237. s_GLOBALS("GLOBALS"),
  238. s_this("this");
  239. static const Func* arGetContextFunc(const ActRec* ar) {
  240. if (ar == nullptr) {
  241. return nullptr;
  242. }
  243. if (ar->m_func->isPseudoMain() || ar->m_func->isBuiltin()) {
  244. // Pseudomains inherit the context of their caller
  245. auto const context = g_context.getNoCheck();
  246. ar = context->getPrevVMState(ar);
  247. while (ar != nullptr &&
  248. (ar->m_func->isPseudoMain() || ar->m_func->isBuiltin())) {
  249. ar = context->getPrevVMState(ar);
  250. }
  251. if (ar == nullptr) {
  252. return nullptr;
  253. }
  254. }
  255. return ar->m_func;
  256. }
  257. static bool modify_extract_name(VarEnv* v,
  258. String& name,
  259. int64_t extract_type,
  260. const String& prefix) {
  261. switch (extract_type) {
  262. case EXTR_SKIP:
  263. if (v->lookup(name.get()) != nullptr) {
  264. return false;
  265. }
  266. break;
  267. case EXTR_IF_EXISTS:
  268. if (v->lookup(name.get()) == nullptr) {
  269. return false;
  270. } else {
  271. goto namechecks;
  272. }
  273. break;
  274. case EXTR_PREFIX_SAME:
  275. if (v->lookup(name.get()) != nullptr) {
  276. name = prefix + "_" + name;
  277. } else {
  278. goto namechecks;
  279. }
  280. break;
  281. case EXTR_PREFIX_ALL:
  282. name = prefix + "_" + name;
  283. break;
  284. case EXTR_PREFIX_INVALID:
  285. if (!is_valid_var_name(name.get()->data(), name.size())) {
  286. name = prefix + "_" + name;
  287. } else {
  288. goto namechecks;
  289. }
  290. break;
  291. case EXTR_PREFIX_IF_EXISTS:
  292. if (v->lookup(name.get()) == nullptr) {
  293. return false;
  294. }
  295. name = prefix + "_" + name;
  296. break;
  297. case EXTR_OVERWRITE:
  298. namechecks:
  299. if (name == s_GLOBALS) {
  300. return false;
  301. }
  302. if (name == s_this) {
  303. // Only disallow $this when inside a non-static method, or a static method
  304. // that has defined $this (matches Zend)
  305. CallerFrame cf;
  306. const Func* func = arGetContextFunc(cf());
  307. if (func && func->isMethod() && v->lookup(s_this.get()) != nullptr) {
  308. return false;
  309. }
  310. }
  311. default:
  312. break;
  313. }
  314. // skip invalid variable names, as in PHP
  315. return is_valid_var_name(name.get()->data(), name.size());
  316. }
  317. ALWAYS_INLINE static
  318. int64_t extract_impl(VRefParam vref_array,
  319. int extract_type /* = EXTR_OVERWRITE */,
  320. const String& prefix /* = "" */) {
  321. bool reference = extract_type & EXTR_REFS;
  322. extract_type &= ~EXTR_REFS;
  323. if (!vref_array.wrapped().isArray()) {
  324. raise_warning("extract() expects parameter 1 to be array");
  325. return 0;
  326. }
  327. VMRegAnchor _;
  328. auto const varEnv = g_context->getOrCreateVarEnv();
  329. if (!varEnv) return 0;
  330. if (UNLIKELY(reference)) {
  331. auto& arr = vref_array.wrapped().toArrRef();
  332. int count = 0;
  333. for (ArrayIter iter(arr); iter; ++iter) {
  334. String name = iter.first();
  335. if (!modify_extract_name(varEnv, name, extract_type, prefix)) continue;
  336. g_context->bindVar(name.get(), arr.lvalAt(name).asTypedValue());
  337. ++count;
  338. }
  339. return count;
  340. }
  341. auto const var_array = vref_array.wrapped().toArray();
  342. int count = 0;
  343. for (ArrayIter iter(var_array); iter; ++iter) {
  344. String name = iter.first();
  345. if (!modify_extract_name(varEnv, name, extract_type, prefix)) continue;
  346. g_context->setVar(name.get(), iter.secondRef().asTypedValue());
  347. ++count;
  348. }
  349. return count;
  350. }
  351. int64_t HHVM_FUNCTION(extract, VRefParam vref_array,
  352. int64_t extract_type /* = EXTR_OVERWRITE */,
  353. const String& prefix /* = "" */) {
  354. raise_disallowed_dynamic_call("extract should not be called dynamically");
  355. return extract_impl(vref_array, extract_type, prefix);
  356. }
  357. int64_t HHVM_FUNCTION(SystemLib_extract,
  358. VRefParam vref_array,
  359. int64_t extract_type = EXTR_OVERWRITE,
  360. const String& prefix = "") {
  361. return extract_impl(vref_array, extract_type, prefix);
  362. }
  363. static void parse_str_impl(const String& str, VRefParam arr) {
  364. Array result = Array::Create();
  365. HttpProtocol::DecodeParameters(result, str.data(), str.size());
  366. if (!arr.isReferenced()) {
  367. HHVM_FN(SystemLib_extract)(result);
  368. return;
  369. }
  370. arr = result;
  371. }
  372. void HHVM_FUNCTION(parse_str,
  373. const String& str,
  374. VRefParam arr /* = null */) {
  375. raise_disallowed_dynamic_call("parse_str should not be called dynamically");
  376. parse_str_impl(str, arr);
  377. }
  378. void HHVM_FUNCTION(SystemLib_parse_str,
  379. const String& str,
  380. VRefParam arr /* = null */) {
  381. parse_str_impl(str, arr);
  382. }
  383. /////////////////////////////////////////////////////////////////////////////
  384. #define EXTR_CONST(v) Native::registerConstant<KindOfInt64> \
  385. (makeStaticString("EXTR_" #v), EXTR_##v);
  386. void StandardExtension::initVariable() {
  387. EXTR_CONST(IF_EXISTS);
  388. EXTR_CONST(OVERWRITE);
  389. EXTR_CONST(PREFIX_ALL);
  390. EXTR_CONST(PREFIX_IF_EXISTS);
  391. EXTR_CONST(PREFIX_INVALID);
  392. EXTR_CONST(PREFIX_SAME);
  393. EXTR_CONST(REFS);
  394. EXTR_CONST(SKIP);
  395. HHVM_FE(is_null);
  396. HHVM_FE(is_bool);
  397. HHVM_FE(is_int);
  398. HHVM_FALIAS(is_integer, is_int);
  399. HHVM_FALIAS(is_long, is_int);
  400. HHVM_FE(is_float);
  401. HHVM_FALIAS(is_double, is_float);
  402. HHVM_FALIAS(is_real, is_float);
  403. HHVM_FE(is_numeric);
  404. HHVM_FE(is_string);
  405. HHVM_FE(is_scalar);
  406. HHVM_FE(is_array);
  407. HHVM_FE(is_object);
  408. HHVM_FE(is_resource);
  409. HHVM_FE(boolval);
  410. HHVM_FE(intval);
  411. HHVM_FE(floatval);
  412. HHVM_FALIAS(doubleval, floatval);
  413. HHVM_FE(strval);
  414. HHVM_FE(gettype);
  415. HHVM_FE(get_resource_type);
  416. HHVM_FE(settype);
  417. HHVM_FE(print_r);
  418. HHVM_FE(var_export);
  419. HHVM_FE(debug_zval_dump);
  420. HHVM_FE(var_dump);
  421. HHVM_FE(serialize);
  422. HHVM_FE(unserialize);
  423. HHVM_FE(get_defined_vars);
  424. HHVM_FALIAS(__SystemLib\\get_defined_vars, SystemLib_get_defined_vars);
  425. HHVM_FE(extract);
  426. HHVM_FE(parse_str);
  427. HHVM_FALIAS(__SystemLib\\extract, SystemLib_extract);
  428. HHVM_FALIAS(__SystemLib\\parse_str, SystemLib_parse_str);
  429. loadSystemlib("std_variable");
  430. }
  431. ///////////////////////////////////////////////////////////////////////////////
  432. } // namespace HPHP