PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/standard/array.c

http://github.com/php/php-src
C | 6360 lines | 5077 code | 710 blank | 573 comment | 1527 complexity | 1050632557f69c6cefadd35cb7616cef MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Andi Gutmans <andi@php.net> |
  14. | Zeev Suraski <zeev@php.net> |
  15. | Rasmus Lerdorf <rasmus@php.net> |
  16. | Andrei Zmievski <andrei@php.net> |
  17. | Stig Venaas <venaas@php.net> |
  18. | Jason Greene <jason@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "php.h"
  22. #include "php_ini.h"
  23. #include <stdarg.h>
  24. #include <stdlib.h>
  25. #include <math.h>
  26. #include <time.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #ifdef PHP_WIN32
  30. #include "win32/unistd.h"
  31. #endif
  32. #include "zend_globals.h"
  33. #include "zend_interfaces.h"
  34. #include "php_globals.h"
  35. #include "php_array.h"
  36. #include "basic_functions.h"
  37. #include "php_string.h"
  38. #include "php_rand.h"
  39. #include "php_math.h"
  40. #include "zend_smart_str.h"
  41. #include "zend_bitset.h"
  42. #include "zend_exceptions.h"
  43. #include "ext/spl/spl_array.h"
  44. /* {{{ defines */
  45. #define EXTR_OVERWRITE 0
  46. #define EXTR_SKIP 1
  47. #define EXTR_PREFIX_SAME 2
  48. #define EXTR_PREFIX_ALL 3
  49. #define EXTR_PREFIX_INVALID 4
  50. #define EXTR_PREFIX_IF_EXISTS 5
  51. #define EXTR_IF_EXISTS 6
  52. #define EXTR_REFS 0x100
  53. #define CASE_LOWER 0
  54. #define CASE_UPPER 1
  55. #define DIFF_NORMAL 1
  56. #define DIFF_KEY 2
  57. #define DIFF_ASSOC 6
  58. #define DIFF_COMP_DATA_NONE -1
  59. #define DIFF_COMP_DATA_INTERNAL 0
  60. #define DIFF_COMP_DATA_USER 1
  61. #define DIFF_COMP_KEY_INTERNAL 0
  62. #define DIFF_COMP_KEY_USER 1
  63. #define INTERSECT_NORMAL 1
  64. #define INTERSECT_KEY 2
  65. #define INTERSECT_ASSOC 6
  66. #define INTERSECT_COMP_DATA_NONE -1
  67. #define INTERSECT_COMP_DATA_INTERNAL 0
  68. #define INTERSECT_COMP_DATA_USER 1
  69. #define INTERSECT_COMP_KEY_INTERNAL 0
  70. #define INTERSECT_COMP_KEY_USER 1
  71. /* }}} */
  72. ZEND_DECLARE_MODULE_GLOBALS(array)
  73. /* {{{ php_array_init_globals
  74. */
  75. static void php_array_init_globals(zend_array_globals *array_globals)
  76. {
  77. memset(array_globals, 0, sizeof(zend_array_globals));
  78. }
  79. /* }}} */
  80. PHP_MINIT_FUNCTION(array) /* {{{ */
  81. {
  82. ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
  83. REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
  84. REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
  85. REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
  86. REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
  87. REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
  88. REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
  89. REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
  90. REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
  91. REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
  92. REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
  93. REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
  94. REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
  95. REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
  96. REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
  97. REGISTER_LONG_CONSTANT("SORT_NATURAL", PHP_SORT_NATURAL, CONST_CS | CONST_PERSISTENT);
  98. REGISTER_LONG_CONSTANT("SORT_FLAG_CASE", PHP_SORT_FLAG_CASE, CONST_CS | CONST_PERSISTENT);
  99. REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
  100. REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
  101. REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
  102. REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
  103. REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
  104. REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
  105. return SUCCESS;
  106. }
  107. /* }}} */
  108. PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
  109. {
  110. #ifdef ZTS
  111. ts_free_id(array_globals_id);
  112. #endif
  113. return SUCCESS;
  114. }
  115. /* }}} */
  116. static int php_array_key_compare(Bucket *f, Bucket *s) /* {{{ */
  117. {
  118. zend_uchar t;
  119. zend_long l1, l2;
  120. double d;
  121. if (f->key == NULL) {
  122. if (s->key == NULL) {
  123. return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
  124. } else {
  125. l1 = (zend_long)f->h;
  126. t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
  127. if (t == IS_LONG) {
  128. /* pass */
  129. } else if (t == IS_DOUBLE) {
  130. return ZEND_NORMALIZE_BOOL((double)l1 - d);
  131. } else {
  132. l2 = 0;
  133. }
  134. }
  135. } else {
  136. if (s->key) {
  137. return zendi_smart_strcmp(f->key, s->key);
  138. } else {
  139. l2 = (zend_long)s->h;
  140. t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
  141. if (t == IS_LONG) {
  142. /* pass */
  143. } else if (t == IS_DOUBLE) {
  144. return ZEND_NORMALIZE_BOOL(d - (double)l2);
  145. } else {
  146. l1 = 0;
  147. }
  148. }
  149. }
  150. return ZEND_NORMALIZE_BOOL(l1 - l2);
  151. }
  152. /* }}} */
  153. static int php_array_reverse_key_compare(Bucket *a, Bucket *b) /* {{{ */
  154. {
  155. return php_array_key_compare(b, a);
  156. }
  157. /* }}} */
  158. static int php_array_key_compare_numeric(Bucket *f, Bucket *s) /* {{{ */
  159. {
  160. if (f->key == NULL && s->key == NULL) {
  161. return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
  162. } else {
  163. double d1, d2;
  164. if (f->key) {
  165. d1 = zend_strtod(f->key->val, NULL);
  166. } else {
  167. d1 = (double)(zend_long)f->h;
  168. }
  169. if (s->key) {
  170. d2 = zend_strtod(s->key->val, NULL);
  171. } else {
  172. d2 = (double)(zend_long)s->h;
  173. }
  174. return ZEND_NORMALIZE_BOOL(d1 - d2);
  175. }
  176. }
  177. /* }}} */
  178. static int php_array_reverse_key_compare_numeric(Bucket *a, Bucket *b) /* {{{ */
  179. {
  180. return php_array_key_compare_numeric(b, a);
  181. }
  182. /* }}} */
  183. static int php_array_key_compare_string_case(Bucket *f, Bucket *s) /* {{{ */
  184. {
  185. const char *s1, *s2;
  186. size_t l1, l2;
  187. char buf1[MAX_LENGTH_OF_LONG + 1];
  188. char buf2[MAX_LENGTH_OF_LONG + 1];
  189. if (f->key) {
  190. s1 = f->key->val;
  191. l1 = f->key->len;
  192. } else {
  193. s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
  194. l1 = buf1 + sizeof(buf1) - 1 - s1;
  195. }
  196. if (s->key) {
  197. s2 = s->key->val;
  198. l2 = s->key->len;
  199. } else {
  200. s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
  201. l2 = buf2 + sizeof(buf2) - 1 - s1;
  202. }
  203. return zend_binary_strcasecmp_l(s1, l1, s2, l2);
  204. }
  205. /* }}} */
  206. static int php_array_reverse_key_compare_string_case(Bucket *a, Bucket *b) /* {{{ */
  207. {
  208. return php_array_key_compare_string_case(b, a);
  209. }
  210. /* }}} */
  211. static int php_array_key_compare_string(Bucket *f, Bucket *s) /* {{{ */
  212. {
  213. const char *s1, *s2;
  214. size_t l1, l2;
  215. char buf1[MAX_LENGTH_OF_LONG + 1];
  216. char buf2[MAX_LENGTH_OF_LONG + 1];
  217. if (f->key) {
  218. s1 = f->key->val;
  219. l1 = f->key->len;
  220. } else {
  221. s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
  222. l1 = buf1 + sizeof(buf1) - 1 - s1;
  223. }
  224. if (s->key) {
  225. s2 = s->key->val;
  226. l2 = s->key->len;
  227. } else {
  228. s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
  229. l2 = buf2 + sizeof(buf2) - 1 - s2;
  230. }
  231. return zend_binary_strcmp(s1, l1, s2, l2);
  232. }
  233. /* }}} */
  234. static int php_array_reverse_key_compare_string(Bucket *a, Bucket *b) /* {{{ */
  235. {
  236. return php_array_key_compare_string(b, a);
  237. }
  238. /* }}} */
  239. static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case) /* {{{ */
  240. {
  241. const char *s1, *s2;
  242. size_t l1, l2;
  243. char buf1[MAX_LENGTH_OF_LONG + 1];
  244. char buf2[MAX_LENGTH_OF_LONG + 1];
  245. if (f->key) {
  246. s1 = f->key->val;
  247. l1 = f->key->len;
  248. } else {
  249. s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
  250. l1 = buf1 + sizeof(buf1) - 1 - s1;
  251. }
  252. if (s->key) {
  253. s2 = s->key->val;
  254. l2 = s->key->len;
  255. } else {
  256. s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
  257. l2 = buf2 + sizeof(buf2) - 1 - s1;
  258. }
  259. return strnatcmp_ex(s1, l1, s2, l2, fold_case);
  260. }
  261. /* }}} */
  262. static int php_array_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
  263. {
  264. return php_array_key_compare_string_natural_general(a, b, 1);
  265. }
  266. /* }}} */
  267. static int php_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */
  268. {
  269. return php_array_key_compare_string_natural_general(b, a, 1);
  270. }
  271. /* }}} */
  272. static int php_array_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
  273. {
  274. return php_array_key_compare_string_natural_general(a, b, 0);
  275. }
  276. /* }}} */
  277. static int php_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */
  278. {
  279. return php_array_key_compare_string_natural_general(b, a, 0);
  280. }
  281. /* }}} */
  282. static int php_array_key_compare_string_locale(Bucket *f, Bucket *s) /* {{{ */
  283. {
  284. const char *s1, *s2;
  285. char buf1[MAX_LENGTH_OF_LONG + 1];
  286. char buf2[MAX_LENGTH_OF_LONG + 1];
  287. if (f->key) {
  288. s1 = f->key->val;
  289. } else {
  290. s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
  291. }
  292. if (s->key) {
  293. s2 = s->key->val;
  294. } else {
  295. s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
  296. }
  297. return strcoll(s1, s2);
  298. }
  299. /* }}} */
  300. static int php_array_reverse_key_compare_string_locale(Bucket *a, Bucket *b) /* {{{ */
  301. {
  302. return php_array_key_compare_string_locale(b, a);
  303. }
  304. /* }}} */
  305. static int php_array_data_compare(Bucket *f, Bucket *s) /* {{{ */
  306. {
  307. zval *first = &f->val;
  308. zval *second = &s->val;
  309. if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
  310. first = Z_INDIRECT_P(first);
  311. }
  312. if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
  313. second = Z_INDIRECT_P(second);
  314. }
  315. return zend_compare(first, second);
  316. }
  317. /* }}} */
  318. static int php_array_reverse_data_compare(Bucket *a, Bucket *b) /* {{{ */
  319. {
  320. return php_array_data_compare(a, b) * -1;
  321. }
  322. /* }}} */
  323. static int php_array_data_compare_numeric(Bucket *f, Bucket *s) /* {{{ */
  324. {
  325. zval *first = &f->val;
  326. zval *second = &s->val;
  327. if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
  328. first = Z_INDIRECT_P(first);
  329. }
  330. if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
  331. second = Z_INDIRECT_P(second);
  332. }
  333. return numeric_compare_function(first, second);
  334. }
  335. /* }}} */
  336. static int php_array_reverse_data_compare_numeric(Bucket *a, Bucket *b) /* {{{ */
  337. {
  338. return php_array_data_compare_numeric(b, a);
  339. }
  340. /* }}} */
  341. static int php_array_data_compare_string_case(Bucket *f, Bucket *s) /* {{{ */
  342. {
  343. zval *first = &f->val;
  344. zval *second = &s->val;
  345. if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
  346. first = Z_INDIRECT_P(first);
  347. }
  348. if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
  349. second = Z_INDIRECT_P(second);
  350. }
  351. return string_case_compare_function(first, second);
  352. }
  353. /* }}} */
  354. static int php_array_reverse_data_compare_string_case(Bucket *a, Bucket *b) /* {{{ */
  355. {
  356. return php_array_data_compare_string_case(b, a);
  357. }
  358. /* }}} */
  359. static int php_array_data_compare_string(Bucket *f, Bucket *s) /* {{{ */
  360. {
  361. zval *first = &f->val;
  362. zval *second = &s->val;
  363. if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
  364. first = Z_INDIRECT_P(first);
  365. }
  366. if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
  367. second = Z_INDIRECT_P(second);
  368. }
  369. return string_compare_function(first, second);
  370. }
  371. /* }}} */
  372. static int php_array_reverse_data_compare_string(Bucket *a, Bucket *b) /* {{{ */
  373. {
  374. return php_array_data_compare_string(b, a);
  375. }
  376. /* }}} */
  377. static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case) /* {{{ */
  378. {
  379. zend_string *tmp_str1, *tmp_str2;
  380. zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
  381. zend_string *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
  382. int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
  383. zend_tmp_string_release(tmp_str1);
  384. zend_tmp_string_release(tmp_str2);
  385. return result;
  386. }
  387. /* }}} */
  388. static int php_array_natural_compare(Bucket *a, Bucket *b) /* {{{ */
  389. {
  390. return php_array_natural_general_compare(a, b, 0);
  391. }
  392. /* }}} */
  393. static int php_array_reverse_natural_compare(Bucket *a, Bucket *b) /* {{{ */
  394. {
  395. return php_array_natural_general_compare(b, a, 0);
  396. }
  397. /* }}} */
  398. static int php_array_natural_case_compare(Bucket *a, Bucket *b) /* {{{ */
  399. {
  400. return php_array_natural_general_compare(a, b, 1);
  401. }
  402. /* }}} */
  403. static int php_array_reverse_natural_case_compare(Bucket *a, Bucket *b) /* {{{ */
  404. {
  405. return php_array_natural_general_compare(b, a, 1);
  406. }
  407. /* }}} */
  408. static int php_array_data_compare_string_locale(Bucket *f, Bucket *s) /* {{{ */
  409. {
  410. zval *first = &f->val;
  411. zval *second = &s->val;
  412. if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
  413. first = Z_INDIRECT_P(first);
  414. }
  415. if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
  416. second = Z_INDIRECT_P(second);
  417. }
  418. return string_locale_compare_function(first, second);
  419. }
  420. /* }}} */
  421. static int php_array_reverse_data_compare_string_locale(Bucket *a, Bucket *b) /* {{{ */
  422. {
  423. return php_array_data_compare_string_locale(b, a);
  424. }
  425. /* }}} */
  426. static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
  427. {
  428. switch (sort_type & ~PHP_SORT_FLAG_CASE) {
  429. case PHP_SORT_NUMERIC:
  430. if (reverse) {
  431. return php_array_reverse_key_compare_numeric;
  432. } else {
  433. return php_array_key_compare_numeric;
  434. }
  435. break;
  436. case PHP_SORT_STRING:
  437. if (sort_type & PHP_SORT_FLAG_CASE) {
  438. if (reverse) {
  439. return php_array_reverse_key_compare_string_case;
  440. } else {
  441. return php_array_key_compare_string_case;
  442. }
  443. } else {
  444. if (reverse) {
  445. return php_array_reverse_key_compare_string;
  446. } else {
  447. return php_array_key_compare_string;
  448. }
  449. }
  450. break;
  451. case PHP_SORT_NATURAL:
  452. if (sort_type & PHP_SORT_FLAG_CASE) {
  453. if (reverse) {
  454. return php_array_reverse_key_compare_string_natural_case;
  455. } else {
  456. return php_array_key_compare_string_natural_case;
  457. }
  458. } else {
  459. if (reverse) {
  460. return php_array_reverse_key_compare_string_natural;
  461. } else {
  462. return php_array_key_compare_string_natural;
  463. }
  464. }
  465. break;
  466. case PHP_SORT_LOCALE_STRING:
  467. if (reverse) {
  468. return php_array_reverse_key_compare_string_locale;
  469. } else {
  470. return php_array_key_compare_string_locale;
  471. }
  472. break;
  473. case PHP_SORT_REGULAR:
  474. default:
  475. if (reverse) {
  476. return php_array_reverse_key_compare;
  477. } else {
  478. return php_array_key_compare;
  479. }
  480. break;
  481. }
  482. return NULL;
  483. }
  484. /* }}} */
  485. static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
  486. {
  487. switch (sort_type & ~PHP_SORT_FLAG_CASE) {
  488. case PHP_SORT_NUMERIC:
  489. if (reverse) {
  490. return php_array_reverse_data_compare_numeric;
  491. } else {
  492. return php_array_data_compare_numeric;
  493. }
  494. break;
  495. case PHP_SORT_STRING:
  496. if (sort_type & PHP_SORT_FLAG_CASE) {
  497. if (reverse) {
  498. return php_array_reverse_data_compare_string_case;
  499. } else {
  500. return php_array_data_compare_string_case;
  501. }
  502. } else {
  503. if (reverse) {
  504. return php_array_reverse_data_compare_string;
  505. } else {
  506. return php_array_data_compare_string;
  507. }
  508. }
  509. break;
  510. case PHP_SORT_NATURAL:
  511. if (sort_type & PHP_SORT_FLAG_CASE) {
  512. if (reverse) {
  513. return php_array_reverse_natural_case_compare;
  514. } else {
  515. return php_array_natural_case_compare;
  516. }
  517. } else {
  518. if (reverse) {
  519. return php_array_reverse_natural_compare;
  520. } else {
  521. return php_array_natural_compare;
  522. }
  523. }
  524. break;
  525. case PHP_SORT_LOCALE_STRING:
  526. if (reverse) {
  527. return php_array_reverse_data_compare_string_locale;
  528. } else {
  529. return php_array_data_compare_string_locale;
  530. }
  531. break;
  532. case PHP_SORT_REGULAR:
  533. default:
  534. if (reverse) {
  535. return php_array_reverse_data_compare;
  536. } else {
  537. return php_array_data_compare;
  538. }
  539. break;
  540. }
  541. return NULL;
  542. }
  543. /* }}} */
  544. /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
  545. Sort an array by key value in reverse order */
  546. PHP_FUNCTION(krsort)
  547. {
  548. zval *array;
  549. zend_long sort_type = PHP_SORT_REGULAR;
  550. bucket_compare_func_t cmp;
  551. ZEND_PARSE_PARAMETERS_START(1, 2)
  552. Z_PARAM_ARRAY_EX(array, 0, 1)
  553. Z_PARAM_OPTIONAL
  554. Z_PARAM_LONG(sort_type)
  555. ZEND_PARSE_PARAMETERS_END();
  556. cmp = php_get_key_compare_func(sort_type, 1);
  557. zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
  558. RETURN_TRUE;
  559. }
  560. /* }}} */
  561. /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
  562. Sort an array by key */
  563. PHP_FUNCTION(ksort)
  564. {
  565. zval *array;
  566. zend_long sort_type = PHP_SORT_REGULAR;
  567. bucket_compare_func_t cmp;
  568. ZEND_PARSE_PARAMETERS_START(1, 2)
  569. Z_PARAM_ARRAY_EX(array, 0, 1)
  570. Z_PARAM_OPTIONAL
  571. Z_PARAM_LONG(sort_type)
  572. ZEND_PARSE_PARAMETERS_END();
  573. cmp = php_get_key_compare_func(sort_type, 0);
  574. zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
  575. RETURN_TRUE;
  576. }
  577. /* }}} */
  578. PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */
  579. {
  580. zend_long cnt = 0;
  581. zval *element;
  582. if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
  583. if (GC_IS_RECURSIVE(ht)) {
  584. php_error_docref(NULL, E_WARNING, "Recursion detected");
  585. return 0;
  586. }
  587. GC_PROTECT_RECURSION(ht);
  588. }
  589. cnt = zend_array_count(ht);
  590. ZEND_HASH_FOREACH_VAL(ht, element) {
  591. ZVAL_DEREF(element);
  592. if (Z_TYPE_P(element) == IS_ARRAY) {
  593. cnt += php_count_recursive(Z_ARRVAL_P(element));
  594. }
  595. } ZEND_HASH_FOREACH_END();
  596. if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
  597. GC_UNPROTECT_RECURSION(ht);
  598. }
  599. return cnt;
  600. }
  601. /* }}} */
  602. /* {{{ proto int count(mixed var [, int mode])
  603. Count the number of elements in a variable (usually an array) */
  604. PHP_FUNCTION(count)
  605. {
  606. zval *array;
  607. zend_long mode = COUNT_NORMAL;
  608. zend_long cnt;
  609. ZEND_PARSE_PARAMETERS_START(1, 2)
  610. Z_PARAM_ZVAL(array)
  611. Z_PARAM_OPTIONAL
  612. Z_PARAM_LONG(mode)
  613. ZEND_PARSE_PARAMETERS_END();
  614. if (mode != COUNT_NORMAL && mode != COUNT_RECURSIVE) {
  615. zend_argument_value_error(2, "must be either COUNT_NORMAL or COUNT_RECURSIVE");
  616. RETURN_THROWS();
  617. }
  618. switch (Z_TYPE_P(array)) {
  619. case IS_NULL:
  620. /* Intentionally not converted to an exception */
  621. php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
  622. RETURN_LONG(0);
  623. break;
  624. case IS_ARRAY:
  625. if (mode != COUNT_RECURSIVE) {
  626. cnt = zend_array_count(Z_ARRVAL_P(array));
  627. } else {
  628. cnt = php_count_recursive(Z_ARRVAL_P(array));
  629. }
  630. RETURN_LONG(cnt);
  631. break;
  632. case IS_OBJECT: {
  633. zval retval;
  634. /* first, we check if the handler is defined */
  635. if (Z_OBJ_HT_P(array)->count_elements) {
  636. RETVAL_LONG(1);
  637. if (SUCCESS == Z_OBJ_HT(*array)->count_elements(Z_OBJ_P(array), &Z_LVAL_P(return_value))) {
  638. return;
  639. }
  640. if (EG(exception)) {
  641. RETURN_THROWS();
  642. }
  643. }
  644. /* if not and the object implements Countable we call its count() method */
  645. if (instanceof_function(Z_OBJCE_P(array), zend_ce_countable)) {
  646. zend_call_method_with_0_params(Z_OBJ_P(array), NULL, NULL, "count", &retval);
  647. if (Z_TYPE(retval) != IS_UNDEF) {
  648. RETVAL_LONG(zval_get_long(&retval));
  649. zval_ptr_dtor(&retval);
  650. }
  651. return;
  652. }
  653. /* If There's no handler and it doesn't implement Countable then add a warning */
  654. /* Intentionally not converted to an exception */
  655. php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
  656. RETURN_LONG(1);
  657. break;
  658. }
  659. default:
  660. /* Intentionally not converted to an exception */
  661. php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");
  662. RETURN_LONG(1);
  663. break;
  664. }
  665. }
  666. /* }}} */
  667. static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
  668. {
  669. zval *array;
  670. ZEND_PARSE_PARAMETERS_START(1, 1)
  671. Z_PARAM_ARRAY_EX(array, 0, 1)
  672. ZEND_PARSE_PARAMETERS_END();
  673. if (fold_case) {
  674. zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0);
  675. } else {
  676. zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0);
  677. }
  678. RETURN_TRUE;
  679. }
  680. /* }}} */
  681. /* {{{ proto void natsort(array &array_arg)
  682. Sort an array using natural sort */
  683. PHP_FUNCTION(natsort)
  684. {
  685. php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  686. }
  687. /* }}} */
  688. /* {{{ proto void natcasesort(array &array_arg)
  689. Sort an array using case-insensitive natural sort */
  690. PHP_FUNCTION(natcasesort)
  691. {
  692. php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  693. }
  694. /* }}} */
  695. /* {{{ proto bool asort(array &array_arg [, int sort_flags])
  696. Sort an array and maintain index association */
  697. PHP_FUNCTION(asort)
  698. {
  699. zval *array;
  700. zend_long sort_type = PHP_SORT_REGULAR;
  701. bucket_compare_func_t cmp;
  702. ZEND_PARSE_PARAMETERS_START(1, 2)
  703. Z_PARAM_ARRAY_EX(array, 0, 1)
  704. Z_PARAM_OPTIONAL
  705. Z_PARAM_LONG(sort_type)
  706. ZEND_PARSE_PARAMETERS_END();
  707. cmp = php_get_data_compare_func(sort_type, 0);
  708. zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
  709. RETURN_TRUE;
  710. }
  711. /* }}} */
  712. /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
  713. Sort an array in reverse order and maintain index association */
  714. PHP_FUNCTION(arsort)
  715. {
  716. zval *array;
  717. zend_long sort_type = PHP_SORT_REGULAR;
  718. bucket_compare_func_t cmp;
  719. ZEND_PARSE_PARAMETERS_START(1, 2)
  720. Z_PARAM_ARRAY_EX(array, 0, 1)
  721. Z_PARAM_OPTIONAL
  722. Z_PARAM_LONG(sort_type)
  723. ZEND_PARSE_PARAMETERS_END();
  724. cmp = php_get_data_compare_func(sort_type, 1);
  725. zend_hash_sort(Z_ARRVAL_P(array), cmp, 0);
  726. RETURN_TRUE;
  727. }
  728. /* }}} */
  729. /* {{{ proto bool sort(array &array_arg [, int sort_flags])
  730. Sort an array */
  731. PHP_FUNCTION(sort)
  732. {
  733. zval *array;
  734. zend_long sort_type = PHP_SORT_REGULAR;
  735. bucket_compare_func_t cmp;
  736. ZEND_PARSE_PARAMETERS_START(1, 2)
  737. Z_PARAM_ARRAY_EX(array, 0, 1)
  738. Z_PARAM_OPTIONAL
  739. Z_PARAM_LONG(sort_type)
  740. ZEND_PARSE_PARAMETERS_END();
  741. cmp = php_get_data_compare_func(sort_type, 0);
  742. zend_hash_sort(Z_ARRVAL_P(array), cmp, 1);
  743. RETURN_TRUE;
  744. }
  745. /* }}} */
  746. /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
  747. Sort an array in reverse order */
  748. PHP_FUNCTION(rsort)
  749. {
  750. zval *array;
  751. zend_long sort_type = PHP_SORT_REGULAR;
  752. bucket_compare_func_t cmp;
  753. ZEND_PARSE_PARAMETERS_START(1, 2)
  754. Z_PARAM_ARRAY_EX(array, 0, 1)
  755. Z_PARAM_OPTIONAL
  756. Z_PARAM_LONG(sort_type)
  757. ZEND_PARSE_PARAMETERS_END();
  758. cmp = php_get_data_compare_func(sort_type, 1);
  759. zend_hash_sort(Z_ARRVAL_P(array), cmp, 1);
  760. RETURN_TRUE;
  761. }
  762. /* }}} */
  763. static int php_array_user_compare(Bucket *f, Bucket *s) /* {{{ */
  764. {
  765. zval args[2];
  766. zval retval;
  767. ZVAL_COPY(&args[0], &f->val);
  768. ZVAL_COPY(&args[1], &s->val);
  769. BG(user_compare_fci).param_count = 2;
  770. BG(user_compare_fci).params = args;
  771. BG(user_compare_fci).retval = &retval;
  772. BG(user_compare_fci).no_separation = 0;
  773. if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
  774. zend_long ret = zval_get_long(&retval);
  775. zval_ptr_dtor(&retval);
  776. zval_ptr_dtor(&args[1]);
  777. zval_ptr_dtor(&args[0]);
  778. return ZEND_NORMALIZE_BOOL(ret);
  779. } else {
  780. zval_ptr_dtor(&args[1]);
  781. zval_ptr_dtor(&args[0]);
  782. return 0;
  783. }
  784. }
  785. /* }}} */
  786. /* check if comparison function is valid */
  787. #define PHP_ARRAY_CMP_FUNC_CHECK(func_name) \
  788. if (!zend_is_callable(*func_name, 0, NULL)) { \
  789. php_error_docref(NULL, E_WARNING, "Invalid comparison function"); \
  790. BG(user_compare_fci) = old_user_compare_fci; \
  791. BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
  792. RETURN_FALSE; \
  793. } \
  794. /* Clear FCI cache otherwise : for example the same or other array with
  795. * (partly) the same key values has been sorted with uasort() or
  796. * other sorting function the comparison is cached, however the name
  797. * of the function for comparison is not respected. see bug #28739 AND #33295
  798. *
  799. * Following defines will assist in backup / restore values. */
  800. #define PHP_ARRAY_CMP_FUNC_VARS \
  801. zend_fcall_info old_user_compare_fci; \
  802. zend_fcall_info_cache old_user_compare_fci_cache \
  803. #define PHP_ARRAY_CMP_FUNC_BACKUP() \
  804. old_user_compare_fci = BG(user_compare_fci); \
  805. old_user_compare_fci_cache = BG(user_compare_fci_cache); \
  806. BG(user_compare_fci_cache) = empty_fcall_info_cache; \
  807. #define PHP_ARRAY_CMP_FUNC_RESTORE() \
  808. zend_release_fcall_info_cache(&BG(user_compare_fci_cache)); \
  809. BG(user_compare_fci) = old_user_compare_fci; \
  810. BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
  811. static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compare_func, zend_bool renumber) /* {{{ */
  812. {
  813. zval *array;
  814. zend_array *arr;
  815. PHP_ARRAY_CMP_FUNC_VARS;
  816. PHP_ARRAY_CMP_FUNC_BACKUP();
  817. ZEND_PARSE_PARAMETERS_START(2, 2)
  818. Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
  819. Z_PARAM_FUNC(BG(user_compare_fci), BG(user_compare_fci_cache))
  820. ZEND_PARSE_PARAMETERS_END_EX( PHP_ARRAY_CMP_FUNC_RESTORE(); return );
  821. arr = Z_ARR_P(array);
  822. if (zend_hash_num_elements(arr) == 0) {
  823. PHP_ARRAY_CMP_FUNC_RESTORE();
  824. RETURN_TRUE;
  825. }
  826. /* Copy array, so the in-place modifications will not be visible to the callback function */
  827. arr = zend_array_dup(arr);
  828. zend_hash_sort(arr, compare_func, renumber);
  829. zval_ptr_dtor(array);
  830. ZVAL_ARR(array, arr);
  831. PHP_ARRAY_CMP_FUNC_RESTORE();
  832. RETURN_TRUE;
  833. }
  834. /* }}} */
  835. /* {{{ proto bool usort(array array_arg, string cmp_function)
  836. Sort an array by values using a user-defined comparison function */
  837. PHP_FUNCTION(usort)
  838. {
  839. php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
  840. }
  841. /* }}} */
  842. /* {{{ proto bool uasort(array array_arg, string cmp_function)
  843. Sort an array with a user-defined comparison function and maintain index association */
  844. PHP_FUNCTION(uasort)
  845. {
  846. php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
  847. }
  848. /* }}} */
  849. static int php_array_user_key_compare(Bucket *f, Bucket *s) /* {{{ */
  850. {
  851. zval args[2];
  852. zval retval;
  853. zend_long result;
  854. if (f->key == NULL) {
  855. ZVAL_LONG(&args[0], f->h);
  856. } else {
  857. ZVAL_STR_COPY(&args[0], f->key);
  858. }
  859. if (s->key == NULL) {
  860. ZVAL_LONG(&args[1], s->h);
  861. } else {
  862. ZVAL_STR_COPY(&args[1], s->key);
  863. }
  864. BG(user_compare_fci).param_count = 2;
  865. BG(user_compare_fci).params = args;
  866. BG(user_compare_fci).retval = &retval;
  867. BG(user_compare_fci).no_separation = 0;
  868. if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
  869. result = zval_get_long(&retval);
  870. zval_ptr_dtor(&retval);
  871. } else {
  872. result = 0;
  873. }
  874. zval_ptr_dtor(&args[0]);
  875. zval_ptr_dtor(&args[1]);
  876. return ZEND_NORMALIZE_BOOL(result);
  877. }
  878. /* }}} */
  879. /* {{{ proto bool uksort(array array_arg, string cmp_function)
  880. Sort an array by keys using a user-defined comparison function */
  881. PHP_FUNCTION(uksort)
  882. {
  883. php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
  884. }
  885. /* }}} */
  886. /* {{{ proto mixed end(array array_arg)
  887. Advances array argument's internal pointer to the last element and return it */
  888. PHP_FUNCTION(end)
  889. {
  890. HashTable *array;
  891. zval *entry;
  892. ZEND_PARSE_PARAMETERS_START(1, 1)
  893. Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
  894. ZEND_PARSE_PARAMETERS_END();
  895. zend_hash_internal_pointer_end(array);
  896. if (USED_RET()) {
  897. if ((entry = zend_hash_get_current_data(array)) == NULL) {
  898. RETURN_FALSE;
  899. }
  900. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  901. entry = Z_INDIRECT_P(entry);
  902. }
  903. ZVAL_COPY_DEREF(return_value, entry);
  904. }
  905. }
  906. /* }}} */
  907. /* {{{ proto mixed prev(array array_arg)
  908. Move array argument's internal pointer to the previous element and return it */
  909. PHP_FUNCTION(prev)
  910. {
  911. HashTable *array;
  912. zval *entry;
  913. ZEND_PARSE_PARAMETERS_START(1, 1)
  914. Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
  915. ZEND_PARSE_PARAMETERS_END();
  916. zend_hash_move_backwards(array);
  917. if (USED_RET()) {
  918. if ((entry = zend_hash_get_current_data(array)) == NULL) {
  919. RETURN_FALSE;
  920. }
  921. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  922. entry = Z_INDIRECT_P(entry);
  923. }
  924. ZVAL_COPY_DEREF(return_value, entry);
  925. }
  926. }
  927. /* }}} */
  928. /* {{{ proto mixed next(array array_arg)
  929. Move array argument's internal pointer to the next element and return it */
  930. PHP_FUNCTION(next)
  931. {
  932. HashTable *array;
  933. zval *entry;
  934. ZEND_PARSE_PARAMETERS_START(1, 1)
  935. Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
  936. ZEND_PARSE_PARAMETERS_END();
  937. zend_hash_move_forward(array);
  938. if (USED_RET()) {
  939. if ((entry = zend_hash_get_current_data(array)) == NULL) {
  940. RETURN_FALSE;
  941. }
  942. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  943. entry = Z_INDIRECT_P(entry);
  944. }
  945. ZVAL_COPY_DEREF(return_value, entry);
  946. }
  947. }
  948. /* }}} */
  949. /* {{{ proto mixed reset(array array_arg)
  950. Set array argument's internal pointer to the first element and return it */
  951. PHP_FUNCTION(reset)
  952. {
  953. HashTable *array;
  954. zval *entry;
  955. ZEND_PARSE_PARAMETERS_START(1, 1)
  956. Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
  957. ZEND_PARSE_PARAMETERS_END();
  958. zend_hash_internal_pointer_reset(array);
  959. if (USED_RET()) {
  960. if ((entry = zend_hash_get_current_data(array)) == NULL) {
  961. RETURN_FALSE;
  962. }
  963. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  964. entry = Z_INDIRECT_P(entry);
  965. }
  966. ZVAL_COPY_DEREF(return_value, entry);
  967. }
  968. }
  969. /* }}} */
  970. /* {{{ proto mixed current(array array_arg)
  971. Return the element currently pointed to by the internal array pointer */
  972. PHP_FUNCTION(current)
  973. {
  974. HashTable *array;
  975. zval *entry;
  976. ZEND_PARSE_PARAMETERS_START(1, 1)
  977. Z_PARAM_ARRAY_OR_OBJECT_HT(array)
  978. ZEND_PARSE_PARAMETERS_END();
  979. if ((entry = zend_hash_get_current_data(array)) == NULL) {
  980. RETURN_FALSE;
  981. }
  982. if (Z_TYPE_P(entry) == IS_INDIRECT) {
  983. entry = Z_INDIRECT_P(entry);
  984. }
  985. ZVAL_COPY_DEREF(return_value, entry);
  986. }
  987. /* }}} */
  988. /* {{{ proto mixed key(array array_arg)
  989. Return the key of the element currently pointed to by the internal array pointer */
  990. PHP_FUNCTION(key)
  991. {
  992. HashTable *array;
  993. ZEND_PARSE_PARAMETERS_START(1, 1)
  994. Z_PARAM_ARRAY_OR_OBJECT_HT(array)
  995. ZEND_PARSE_PARAMETERS_END();
  996. zend_hash_get_current_key_zval(array, return_value);
  997. }
  998. /* }}} */
  999. /* {{{
  1000. * proto mixed min(array values)
  1001. * proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
  1002. Return the lowest value in an array or a series of arguments */
  1003. PHP_FUNCTION(min)
  1004. {
  1005. int argc;
  1006. zval *args = NULL;
  1007. ZEND_PARSE_PARAMETERS_START(1, -1)
  1008. Z_PARAM_VARIADIC('+', args, argc)
  1009. ZEND_PARSE_PARAMETERS_END();
  1010. /* mixed min ( array $values ) */
  1011. if (argc == 1) {
  1012. zval *result;
  1013. if (Z_TYPE(args[0]) != IS_ARRAY) {
  1014. zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0]));
  1015. RETURN_THROWS();
  1016. } else {
  1017. if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 0)) != NULL) {
  1018. ZVAL_COPY_DEREF(return_value, result);
  1019. } else {
  1020. zend_argument_value_error(1, "must contain at least one element");
  1021. RETURN_THROWS();
  1022. }
  1023. }
  1024. } else {
  1025. /* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
  1026. zval *min, result;
  1027. int i;
  1028. min = &args[0];
  1029. for (i = 1; i < argc; i++) {
  1030. is_smaller_function(&result, &args[i], min);
  1031. if (Z_TYPE(result) == IS_TRUE) {
  1032. min = &args[i];
  1033. }
  1034. }
  1035. ZVAL_COPY(return_value, min);
  1036. }
  1037. }
  1038. /* }}} */
  1039. /* {{{
  1040. * proto mixed max(array values)
  1041. * proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
  1042. Return the highest value in an array or a series of arguments */
  1043. PHP_FUNCTION(max)
  1044. {
  1045. zval *args = NULL;
  1046. int argc;
  1047. ZEND_PARSE_PARAMETERS_START(1, -1)
  1048. Z_PARAM_VARIADIC('+', args, argc)
  1049. ZEND_PARSE_PARAMETERS_END();
  1050. /* mixed max ( array $values ) */
  1051. if (argc == 1) {
  1052. zval *result;
  1053. if (Z_TYPE(args[0]) != IS_ARRAY) {
  1054. zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0]));
  1055. RETURN_THROWS();
  1056. } else {
  1057. if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 1)) != NULL) {
  1058. ZVAL_COPY_DEREF(return_value, result);
  1059. } else {
  1060. zend_argument_value_error(1, "must contain at least one element");
  1061. RETURN_THROWS();
  1062. }
  1063. }
  1064. } else {
  1065. /* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
  1066. zval *max, result;
  1067. int i;
  1068. max = &args[0];
  1069. for (i = 1; i < argc; i++) {
  1070. is_smaller_or_equal_function(&result, &args[i], max);
  1071. if (Z_TYPE(result) == IS_FALSE) {
  1072. max = &args[i];
  1073. }
  1074. }
  1075. ZVAL_COPY(return_value, max);
  1076. }
  1077. }
  1078. /* }}} */
  1079. static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
  1080. {
  1081. zval args[3], /* Arguments to userland function */
  1082. retval, /* Return value - unused */
  1083. *zv;
  1084. HashTable *target_hash = HASH_OF(array);
  1085. HashPosition pos;
  1086. uint32_t ht_iter;
  1087. int result = SUCCESS;
  1088. /* Set up known arguments */
  1089. ZVAL_UNDEF(&args[1]);
  1090. if (userdata) {
  1091. ZVAL_COPY(&args[2], userdata);
  1092. }
  1093. BG(array_walk_fci).retval = &retval;
  1094. BG(array_walk_fci).param_count = userdata ? 3 : 2;
  1095. BG(array_walk_fci).params = args;
  1096. BG(array_walk_fci).no_separation = 0;
  1097. zend_hash_internal_pointer_reset_ex(target_hash, &pos);
  1098. ht_iter = zend_hash_iterator_add(target_hash, pos);
  1099. /* Iterate through hash */
  1100. do {
  1101. /* Retrieve value */
  1102. zv = zend_hash_get_current_data_ex(target_hash, &pos);
  1103. if (zv == NULL) {
  1104. break;
  1105. }
  1106. /* Skip undefined indirect elements */
  1107. if (Z_TYPE_P(zv) == IS_INDIRECT) {
  1108. zv = Z_INDIRECT_P(zv);
  1109. if (Z_TYPE_P(zv) == IS_UNDEF) {
  1110. zend_hash_move_forward_ex(target_hash, &pos);
  1111. continue;
  1112. }
  1113. }
  1114. /* Ensure the value is a reference. Otherwise the location of the value may be freed. */
  1115. ZVAL_MAKE_REF(zv);
  1116. /* Retrieve key */
  1117. zend_hash_get_current_key_zval_ex(target_hash, &args[1], &pos);
  1118. /* Move to next element already now -- this mirrors the approach used by foreach
  1119. * and ensures proper behavior with regard to modifications. */
  1120. zend_hash_move_forward_ex(target_hash, &pos);
  1121. /* Back up hash position, as it may change */
  1122. EG(ht_iterators)[ht_iter].pos = pos;
  1123. if (recursive && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY) {
  1124. HashTable *thash;
  1125. zend_fcall_info orig_array_walk_fci;
  1126. zend_fcall_info_cache orig_array_walk_fci_cache;
  1127. zval ref;
  1128. ZVAL_COPY_VALUE(&ref, zv);
  1129. ZVAL_DEREF(zv);
  1130. SEPARATE_ARRAY(zv);
  1131. thash = Z_ARRVAL_P(zv);
  1132. if (GC_IS_RECURSIVE(thash)) {
  1133. zend_throw_error(NULL, "Recursion detected");
  1134. result = FAILURE;
  1135. break;
  1136. }
  1137. /* backup the fcall info and cache */
  1138. orig_array_walk_fci = BG(array_walk_fci);
  1139. orig_array_walk_fci_cache = BG(array_walk_fci_cache);
  1140. Z_ADDREF(ref);
  1141. GC_PROTECT_RECURSION(thash);
  1142. result = php_array_walk(zv, userdata, recursive);
  1143. if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
  1144. /* If the hashtable changed in the meantime, we'll "leak" this apply count
  1145. * increment -- our reference to thash is no longer valid. */
  1146. GC_UNPROTECT_RECURSION(thash);
  1147. }
  1148. zval_ptr_dtor(&ref);
  1149. /* restore the fcall info and cache */
  1150. BG(array_walk_fci) = orig_array_walk_fci;
  1151. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  1152. } else {
  1153. ZVAL_COPY(&args[0], zv);
  1154. /* Call the userland function */
  1155. result = zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache));
  1156. if (result == SUCCESS) {
  1157. zval_ptr_dtor(&retval);
  1158. }
  1159. zval_ptr_dtor(&args[0]);
  1160. }
  1161. if (Z_TYPE(args[1]) != IS_UNDEF) {
  1162. zval_ptr_dtor(&args[1]);
  1163. ZVAL_UNDEF(&args[1]);
  1164. }
  1165. if (result == FAILURE) {
  1166. break;
  1167. }
  1168. /* Reload array and position -- both may have changed */
  1169. if (Z_TYPE_P(array) == IS_ARRAY) {
  1170. pos = zend_hash_iterator_pos_ex(ht_iter, array);
  1171. target_hash = Z_ARRVAL_P(array);
  1172. } else if (Z_TYPE_P(array) == IS_OBJECT) {
  1173. target_hash = Z_OBJPROP_P(array);
  1174. pos = zend_hash_iterator_pos(ht_iter, target_hash);
  1175. } else {
  1176. zend_type_error("Iterated value is no longer an array or object");
  1177. result = FAILURE;
  1178. break;
  1179. }
  1180. } while (!EG(exception));
  1181. if (userdata) {
  1182. zval_ptr_dtor(&args[2]);
  1183. }
  1184. zend_hash_iterator_del(ht_iter);
  1185. return result;
  1186. }
  1187. /* }}} */
  1188. /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
  1189. Apply a user function to every member of an array */
  1190. PHP_FUNCTION(array_walk)
  1191. {
  1192. zval *array;
  1193. zval *userdata = NULL;
  1194. zend_fcall_info orig_array_walk_fci;
  1195. zend_fcall_info_cache orig_array_walk_fci_cache;
  1196. orig_array_walk_fci = BG(array_walk_fci);
  1197. orig_array_walk_fci_cache = BG(array_walk_fci_cache);
  1198. ZEND_PARSE_PARAMETERS_START(2, 3)
  1199. Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
  1200. Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
  1201. Z_PARAM_OPTIONAL
  1202. Z_PARAM_ZVAL(userdata)
  1203. ZEND_PARSE_PARAMETERS_END_EX(
  1204. BG(array_walk_fci) = orig_array_walk_fci;
  1205. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  1206. return
  1207. );
  1208. php_array_walk(array, userdata, 0);
  1209. zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
  1210. BG(array_walk_fci) = orig_array_walk_fci;
  1211. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  1212. RETURN_TRUE;
  1213. }
  1214. /* }}} */
  1215. /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
  1216. Apply a user function recursively to every member of an array */
  1217. PHP_FUNCTION(array_walk_recursive)
  1218. {
  1219. zval *array;
  1220. zval *userdata = NULL;
  1221. zend_fcall_info orig_array_walk_fci;
  1222. zend_fcall_info_cache orig_array_walk_fci_cache;
  1223. orig_array_walk_fci = BG(array_walk_fci);
  1224. orig_array_walk_fci_cache = BG(array_walk_fci_cache);
  1225. ZEND_PARSE_PARAMETERS_START(2, 3)
  1226. Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
  1227. Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
  1228. Z_PARAM_OPTIONAL
  1229. Z_PARAM_ZVAL(userdata)
  1230. ZEND_PARSE_PARAMETERS_END_EX(
  1231. BG(array_walk_fci) = orig_array_walk_fci;
  1232. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  1233. return
  1234. );
  1235. php_array_walk(array, userdata, 1);
  1236. zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
  1237. BG(array_walk_fci) = orig_array_walk_fci;
  1238. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  1239. RETURN_TRUE;
  1240. }
  1241. /* }}} */
  1242. /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
  1243. * 0 = return boolean
  1244. * 1 = return key
  1245. */
  1246. static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
  1247. {
  1248. zval *value, /* value to check for */
  1249. *array, /* array to check in */
  1250. *entry; /* pointer to array entry */
  1251. zend_ulong num_idx;
  1252. zend_string *str_idx;
  1253. zend_bool strict = 0; /* strict comparison or not */
  1254. ZEND_PARSE_PARAMETERS_START(2, 3)
  1255. Z_PARAM_ZVAL(value)
  1256. Z_PARAM_ARRAY(array)
  1257. Z_PARAM_OPTIONAL
  1258. Z_PARAM_BOOL(strict)
  1259. ZEND_PARSE_PARAMETERS_END();
  1260. if (strict) {
  1261. if (Z_TYPE_P(value) == IS_LONG) {
  1262. ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
  1263. ZVAL_DEREF(entry);
  1264. if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
  1265. if (behavior == 0) {
  1266. RETURN_TRUE;
  1267. } else {
  1268. if (str_idx) {
  1269. RETVAL_STR_COPY(str_idx);
  1270. } else {
  1271. RETVAL_LONG(num_idx);
  1272. }
  1273. return;
  1274. }
  1275. }
  1276. } ZEND_HASH_FOREACH_END();
  1277. } else {
  1278. ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
  1279. ZVAL_DEREF(entry);
  1280. if (fast_is_identical_function(value, entry)) {
  1281. if (behavior == 0) {
  1282. RETURN_TRUE;
  1283. } else {
  1284. if (str_idx) {
  1285. RETVAL_STR_COPY(str_idx);
  1286. } else {
  1287. RETVAL_LONG(num_idx);
  1288. }
  1289. return;
  1290. }
  1291. }
  1292. } ZEND_HASH_FOREACH_END();
  1293. }
  1294. } else {
  1295. if (Z_TYPE_P(value) == IS_LONG) {
  1296. ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
  1297. if (fast_equal_check_long(value, entry)) {
  1298. if (behavior == 0) {
  1299. RETURN_TRUE;
  1300. } else {
  1301. if (str_idx) {
  1302. RETVAL_STR_COPY(str_idx);
  1303. } else {
  1304. RETVAL_LONG(num_idx);
  1305. }
  1306. return;
  1307. }
  1308. }
  1309. } ZEND_HASH_FOREACH_END();
  1310. } else if (Z_TYPE_P(value) == IS_STRING) {
  1311. ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
  1312. if (fast_equal_check_string(value, entry)) {
  1313. if (behavior == 0) {
  1314. RETURN_TRUE;
  1315. } else {
  1316. if (str_idx) {
  1317. RETVAL_STR_COPY(str_idx);
  1318. } else {
  1319. RETVAL_LONG(num_idx);
  1320. }
  1321. return;
  1322. }
  1323. }
  1324. } ZEND_HASH_FOREACH_END();
  1325. } else {
  1326. ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
  1327. if (fast_equal_check_function(value, entry)) {
  1328. if (behavior == 0) {
  1329. RETURN_TRUE;
  1330. } else {
  1331. if (str_idx) {
  1332. RETVAL_STR_COPY(str_idx);
  1333. } else {
  1334. RETVAL_LONG(num_idx);
  1335. }
  1336. return;
  1337. }
  1338. }
  1339. } ZEND_HASH_FOREACH_END();
  1340. }
  1341. }
  1342. RETURN_FALSE;
  1343. }
  1344. /* }}} */
  1345. /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
  1346. Checks if the given value exists in the array */
  1347. PHP_FUNCTION(in_array)
  1348. {
  1349. php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  1350. }
  1351. /* }}} */
  1352. /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
  1353. Searches the array for a given value and returns the corresponding key if successful */
  1354. PHP_FUNCTION(array_search)
  1355. {
  1356. php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  1357. }
  1358. /* }}} */
  1359. static zend_always_inline int php_valid_var_name(const char *var_name, size_t var_name_len) /* {{{ */
  1360. {
  1361. #if 1
  1362. /* first 256 bits for first character, and second 256 bits for the next */
  1363. static const uint32_t charset[8] = {
  1364. /* 31 0 63 32 95 64 127 96 */
  1365. 0x00000000, 0x00000000, 0x87fffffe, 0x07fffffe,
  1366. 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
  1367. static const uint32_t charset2[8] = {
  1368. /* 31 0 63 32 95 64 127 96 */
  1369. 0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe,
  1370. 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
  1371. #endif
  1372. size_t i;
  1373. uint32_t ch;
  1374. if (UNEXPECTED(!var_name_len)) {
  1375. return 0;
  1376. }
  1377. /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
  1378. ch = (uint32_t)((unsigned char *)var_name)[0];
  1379. #if 1
  1380. if (UNEXPECTED(!ZEND_BIT_TEST(charset, ch))) {
  1381. #else
  1382. if (var_name[0] != '_' &&
  1383. (ch < 65 /* A */ || /* Z */ ch > 90) &&
  1384. (ch < 97 /* a */ || /* z */ ch > 122) &&
  1385. (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
  1386. ) {
  1387. #endif
  1388. return 0;
  1389. }
  1390. /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
  1391. if (var_name_len > 1) {
  1392. i = 1;
  1393. do {
  1394. ch = (uint32_t)((unsigned char *)var_name)[i];
  1395. #if 1
  1396. if (UNEXPECTED(!ZEND_BIT_TEST(charset2, ch))) {
  1397. #else
  1398. if (var_name[i] != '_' &&
  1399. (ch < 48 /* 0 */ || /* 9 */ ch > 57) &&
  1400. (ch < 65 /* A */ || /* Z */ ch > 90) &&
  1401. (ch < 97 /* a */ || /* z */ ch > 122) &&
  1402. (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
  1403. ) {
  1404. #endif
  1405. return 0;
  1406. }
  1407. } while (++i < var_name_len);
  1408. }
  1409. return 1;
  1410. }
  1411. /* }}} */
  1412. PHPAPI int php_prefix_varname(zval *result, zend_string *prefix, const char *var_name, size_t var_name_len, zend_bool add_underscore) /* {{{ */
  1413. {
  1414. ZVAL_NEW_STR(result, zend_string_alloc(ZSTR_LEN(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0));
  1415. memcpy(Z_STRVAL_P(result), ZSTR_VAL(prefix), ZSTR_LEN(prefix));
  1416. if (add_underscore) {
  1417. Z_STRVAL_P(result)[ZSTR_LEN(prefix)] = '_';
  1418. }
  1419. memcpy(Z_STRVAL_P(result) + ZSTR_LEN(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
  1420. return SUCCESS;
  1421. }
  1422. /* }}} */
  1423. static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
  1424. {
  1425. zend_long count = 0;
  1426. zend_string *var_name;
  1427. zval *entry, *orig_var;
  1428. ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
  1429. if (!var_name) {
  1430. continue;
  1431. }
  1432. orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
  1433. if (orig_var) {
  1434. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1435. orig_var = Z_INDIRECT_P(orig_var);
  1436. if (Z_TYPE_P(orig_var) == IS_UNDEF) {
  1437. continue;
  1438. }
  1439. }
  1440. if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
  1441. continue;
  1442. }
  1443. if (zend_string_equals_literal(var_name, "GLOBALS")) {
  1444. continue;
  1445. }
  1446. if (zend_string_equals_literal(var_name, "this")) {
  1447. zend_throw_error(NULL, "Cannot re-assign $this");
  1448. return -1;
  1449. }
  1450. if (Z_ISREF_P(entry)) {
  1451. Z_ADDREF_P(entry);
  1452. } else {
  1453. ZVAL_MAKE_REF_EX(entry, 2);
  1454. }
  1455. zval_ptr_dtor(orig_var);
  1456. ZVAL_REF(orig_var, Z_REF_P(entry));
  1457. count++;
  1458. }
  1459. } ZEND_HASH_FOREACH_END();
  1460. return count;
  1461. }
  1462. /* }}} */
  1463. static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */
  1464. {
  1465. zend_long count = 0;
  1466. zend_string *var_name;
  1467. zval *entry, *orig_var;
  1468. ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
  1469. if (!var_name) {
  1470. continue;
  1471. }
  1472. orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
  1473. if (orig_var) {
  1474. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1475. orig_var = Z_INDIRECT_P(orig_var);
  1476. if (Z_TYPE_P(orig_var) == IS_UNDEF) {
  1477. continue;
  1478. }
  1479. }
  1480. if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
  1481. continue;
  1482. }
  1483. if (zend_string_equals_literal(var_name, "GLOBALS")) {
  1484. continue;
  1485. }
  1486. if (zend_string_equals_literal(var_name, "this")) {
  1487. zend_throw_error(NULL, "Cannot re-assign $this");
  1488. return -1;
  1489. }
  1490. ZVAL_DEREF(entry);
  1491. ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
  1492. if (UNEXPECTED(EG(exception))) {
  1493. return -1;
  1494. }
  1495. count++;
  1496. }
  1497. } ZEND_HASH_FOREACH_END();
  1498. return count;
  1499. }
  1500. /* }}} */
  1501. static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
  1502. {
  1503. zend_long count = 0;
  1504. zend_string *var_name;
  1505. zval *entry, *orig_var;
  1506. ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
  1507. if (!var_name) {
  1508. continue;
  1509. }
  1510. if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
  1511. continue;
  1512. }
  1513. if (zend_string_equals_literal(var_name, "this")) {
  1514. zend_throw_error(NULL, "Cannot re-assign $this");
  1515. return -1;
  1516. }
  1517. orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
  1518. if (orig_var) {
  1519. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1520. orig_var = Z_INDIRECT_P(orig_var);
  1521. }
  1522. if (zend_string_equals_literal(var_name, "GLOBALS")) {
  1523. continue;
  1524. }
  1525. if (Z_ISREF_P(entry)) {
  1526. Z_ADDREF_P(entry);
  1527. } else {
  1528. ZVAL_MAKE_REF_EX(entry, 2);
  1529. }
  1530. zval_ptr_dtor(orig_var);
  1531. ZVAL_REF(orig_var, Z_REF_P(entry));
  1532. } else {
  1533. if (Z_ISREF_P(entry)) {
  1534. Z_ADDREF_P(entry);
  1535. } else {
  1536. ZVAL_MAKE_REF_EX(entry, 2);
  1537. }
  1538. zend_hash_add_new(symbol_table, var_name, entry);
  1539. }
  1540. count++;
  1541. } ZEND_HASH_FOREACH_END();
  1542. return count;
  1543. }
  1544. /* }}} */
  1545. static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */
  1546. {
  1547. zend_long count = 0;
  1548. zend_string *var_name;
  1549. zval *entry, *orig_var;
  1550. ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
  1551. if (!var_name) {
  1552. continue;
  1553. }
  1554. if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
  1555. continue;
  1556. }
  1557. if (zend_string_equals_literal(var_name, "this")) {
  1558. zend_throw_error(NULL, "Cannot re-assign $this");
  1559. return -1;
  1560. }
  1561. orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
  1562. if (orig_var) {
  1563. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1564. orig_var = Z_INDIRECT_P(orig_var);
  1565. }
  1566. if (zend_string_equals_literal(var_name, "GLOBALS")) {
  1567. continue;
  1568. }
  1569. ZVAL_DEREF(entry);
  1570. ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
  1571. if (UNEXPECTED(EG(exception))) {
  1572. return -1;
  1573. }
  1574. } else {
  1575. ZVAL_DEREF(entry);
  1576. Z_TRY_ADDREF_P(entry);
  1577. zend_hash_add_new(symbol_table, var_name, entry);
  1578. }
  1579. count++;
  1580. } ZEND_HASH_FOREACH_END();
  1581. return count;
  1582. }
  1583. /* }}} */
  1584. static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
  1585. {
  1586. zend_long count = 0;
  1587. zend_string *var_name;
  1588. zval *entry, *orig_var, final_name;
  1589. ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
  1590. if (!var_name) {
  1591. continue;
  1592. }
  1593. orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
  1594. if (orig_var) {
  1595. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1596. orig_var = Z_INDIRECT_P(orig_var);
  1597. if (Z_TYPE_P(orig_var) == IS_UNDEF) {
  1598. if (Z_ISREF_P(entry)) {
  1599. Z_ADDREF_P(entry);
  1600. } else {
  1601. ZVAL_MAKE_REF_EX(entry, 2);
  1602. }
  1603. ZVAL_REF(orig_var, Z_REF_P(entry));
  1604. count++;
  1605. continue;
  1606. }
  1607. }
  1608. php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
  1609. if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
  1610. if (zend_string_equals_literal(Z_STR(final_name), "this")) {
  1611. zend_throw_error(NULL, "Cannot re-assign $this");
  1612. return -1;
  1613. } else {
  1614. if (Z_ISREF_P(entry)) {
  1615. Z_ADDREF_P(entry);
  1616. } else {
  1617. ZVAL_MAKE_REF_EX(entry, 2);
  1618. }
  1619. if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
  1620. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1621. orig_var = Z_INDIRECT_P(orig_var);
  1622. }
  1623. zval_ptr_dtor(orig_var);
  1624. ZVAL_REF(orig_var, Z_REF_P(entry));
  1625. } else {
  1626. zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
  1627. }
  1628. count++;
  1629. }
  1630. }
  1631. zval_ptr_dtor_str(&final_name);
  1632. }
  1633. } ZEND_HASH_FOREACH_END();
  1634. return count;
  1635. }
  1636. /* }}} */
  1637. static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */
  1638. {
  1639. zend_long count = 0;
  1640. zend_string *var_name;
  1641. zval *entry, *orig_var, final_name;
  1642. ZEND_HASH_FOREACH_STR_KEY_VAL_IND(arr, var_name, entry) {
  1643. if (!var_name) {
  1644. continue;
  1645. }
  1646. orig_var = zend_hash_find_ex(symbol_table, var_name, 1);
  1647. if (orig_var) {
  1648. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1649. orig_var = Z_INDIRECT_P(orig_var);
  1650. if (Z_TYPE_P(orig_var) == IS_UNDEF) {
  1651. ZVAL_COPY_DEREF(orig_var, entry);
  1652. count++;
  1653. continue;
  1654. }
  1655. }
  1656. php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
  1657. if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
  1658. if (zend_string_equals_literal(Z_STR(final_name), "this")) {
  1659. zend_throw_error(NULL, "Cannot re-assign $this");
  1660. return -1;
  1661. } else {
  1662. ZVAL_DEREF(entry);
  1663. if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
  1664. if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
  1665. orig_var = Z_INDIRECT_P(orig_var);
  1666. }
  1667. ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
  1668. if (UNEXPECTED(EG(exception))) {
  1669. zend_string_release_ex(Z_STR(final_name), 0);
  1670. return -1;
  1671. }
  1672. } else {
  1673. Z_TRY_ADDREF

Large files files are truncated, but you can click here to view the full file