PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

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

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