Line data Source code
1 : /*
2 : +----------------------------------------------------------------------+
3 : | COLOPL PHP Backwards Compatibility Extension. |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) COLOPL, Inc. |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to the BSD-3-Clause license that is |
8 : | bundled with this package in the file LICENSE. |
9 : +----------------------------------------------------------------------+
10 : | Author: Go Kudo <g-kudo@colopl.co.jp> |
11 : +----------------------------------------------------------------------+
12 : */
13 :
14 : #ifdef HAVE_CONFIG_H
15 : # include "config.h"
16 : #endif
17 :
18 : #include "php_colopl_bc.h"
19 :
20 : #include "ext/date/php_date.h"
21 : #include "zend_bitset.h"
22 :
23 : #ifndef RAND_MAX
24 : # define RAND_MAX (1 << 15)
25 : #endif
26 :
27 : #if !defined(ZTS) && (defined(HAVE_LRAND48) || defined(HAVE_RANDOM))
28 : enum {
29 : COLOPL_BC_RAND_MAX_VALUE = 2147483647,
30 : COLOPL_BC_MT_M = 397,
31 : COLOPL_BC_MT_RAND_MAX_VALUE = 0x7FFFFFFF
32 : };
33 : #else
34 : enum {
35 : COLOPL_BC_RAND_MAX_VALUE = RAND_MAX,
36 : COLOPL_BC_MT_M = 397,
37 : COLOPL_BC_MT_RAND_MAX_VALUE = 0x7FFFFFFF
38 : };
39 : #endif
40 :
41 : /* Emulate gcc + amd64 undefined behavior results. */
42 6406256 : static inline zend_long php_colopl_bc_float_to_long_amd64(zend_long min, double value)
43 : {
44 6406256 : if (value > ((double) ZEND_LONG_MAX) || value < ((double) ZEND_LONG_MIN)) {
45 800766 : return 0;
46 : }
47 :
48 5605490 : return min + (zend_long) value;
49 : }
50 :
51 6406256 : static inline zend_long php_colopl_bc_rand_range(zend_long number, zend_long min, zend_long max, zend_long rand_max)
52 : {
53 12812512 : return php_colopl_bc_float_to_long_amd64(
54 : min,
55 6406256 : ((double) max - (double) min + 1.0) * ((double) number / ((double) rand_max + 1.0))
56 : );
57 : }
58 :
59 0 : static inline zend_long php_colopl_bc_generate_seed(void)
60 : {
61 : #ifdef PHP_WIN32
62 : return (((zend_long) (time(0) * GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg())));
63 : #else
64 0 : return (((zend_long) (time(0) * getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg())));
65 : #endif
66 : }
67 :
68 3217344 : static inline uint32_t php_colopl_bc_mt_hi_bit(uint32_t value)
69 : {
70 3217344 : return value & 0x80000000U;
71 : }
72 :
73 3217344 : static inline uint32_t php_colopl_bc_mt_lo_bit(uint32_t value)
74 : {
75 3217344 : return value & 0x00000001U;
76 : }
77 :
78 3217344 : static inline uint32_t php_colopl_bc_mt_lo_bits(uint32_t value)
79 : {
80 3217344 : return value & 0x7FFFFFFFU;
81 : }
82 :
83 3217344 : static inline uint32_t php_colopl_bc_mt_mix_bits(uint32_t left, uint32_t right)
84 : {
85 3217344 : return php_colopl_bc_mt_hi_bit(left) | php_colopl_bc_mt_lo_bits(right);
86 : }
87 :
88 3217344 : static inline uint32_t php_colopl_bc_mt_twist(uint32_t m, uint32_t u, uint32_t v)
89 : {
90 3217344 : return m ^ (php_colopl_bc_mt_mix_bits(u, v) >> 1) ^ ((uint32_t) (-(uint32_t) php_colopl_bc_mt_lo_bit(u)) & 0x9908b0dfU);
91 : }
92 :
93 : /* rand.c */
94 :
95 : #if defined(__clang__)
96 : __attribute__((no_sanitize("signed-integer-overflow")))
97 : #endif
98 48 : void php_colopl_bc_srand(zend_long seed)
99 : {
100 : #ifdef ZTS
101 22 : COLOPL_BC_G(rand_seed) = (uint32_t) seed;
102 : #else
103 26 : uint32_t s = (uint32_t) seed;
104 26 : int i = 0;
105 :
106 26 : if (s == 0) {
107 6 : s = 1;
108 : }
109 :
110 26 : COLOPL_BC_G(gnurandom_r)[0] = s;
111 806 : for (i = 1; i < 31; i++) {
112 780 : COLOPL_BC_G(gnurandom_r)[i] = (16807LL * COLOPL_BC_G(gnurandom_r)[i - 1]) % 2147483647;
113 780 : if (COLOPL_BC_G(gnurandom_r)[i] < 0) {
114 2 : COLOPL_BC_G(gnurandom_r)[i] += 2147483647;
115 : }
116 : }
117 104 : for (i = 31; i < 34; i++) {
118 78 : COLOPL_BC_G(gnurandom_r)[i] = COLOPL_BC_G(gnurandom_r)[i - 31];
119 : }
120 8086 : for (i = 34; i < 344; i++) {
121 8060 : COLOPL_BC_G(gnurandom_r)[i] = COLOPL_BC_G(gnurandom_r)[i - 31] + COLOPL_BC_G(gnurandom_r)[i - 3];
122 : }
123 :
124 26 : COLOPL_BC_G(gnurandom_next) = 0;
125 : #endif
126 48 : COLOPL_BC_G(rand_is_seeded) = 1;
127 48 : }
128 :
129 : #if defined(__clang__)
130 : __attribute__((no_sanitize("signed-integer-overflow")))
131 : #endif
132 3204234 : zend_long php_colopl_bc_rand(void)
133 : {
134 : zend_long ret;
135 :
136 3204234 : if (!COLOPL_BC_G(rand_is_seeded)) {
137 0 : php_colopl_bc_srand(php_colopl_bc_generate_seed());
138 : }
139 :
140 : #ifdef ZTS
141 1601096 : uint32_t next = COLOPL_BC_G(rand_seed);
142 :
143 1601096 : next = (next * 1103515245) + 12345;
144 1601096 : ret = (uint32_t) (next / 65536) % 2048;
145 :
146 1601096 : next = (next * 1103515245) + 12345;
147 1601096 : ret <<= 10;
148 1601096 : ret ^= (uint32_t) (next / 65536) % 1024;
149 :
150 1601096 : next = (next * 1103515245) + 12345;
151 1601096 : ret <<= 10;
152 1601096 : ret ^= (uint32_t) (next / 65536) % 1024;
153 :
154 1601096 : COLOPL_BC_G(rand_seed) = next;
155 : #else
156 1603138 : COLOPL_BC_G(gnurandom_r)[COLOPL_BC_G(gnurandom_next) % 344] = COLOPL_BC_G(gnurandom_r)[(COLOPL_BC_G(gnurandom_next) + 313) % 344] + COLOPL_BC_G(gnurandom_r)[(COLOPL_BC_G(gnurandom_next) + 341) % 344];
157 1603138 : ret = ((uint32_t) COLOPL_BC_G(gnurandom_r)[COLOPL_BC_G(gnurandom_next) % 344] >> 1);
158 1603138 : COLOPL_BC_G(gnurandom_next) = (COLOPL_BC_G(gnurandom_next) + 1) % 344;
159 : #endif
160 3204234 : return (zend_long) ret;
161 : }
162 :
163 48 : PHP_FUNCTION(Colopl_ColoplBc_Php70_srand)
164 : {
165 48 : zend_long seed = 0;
166 :
167 48 : ZEND_PARSE_PARAMETERS_START(0, 1)
168 48 : Z_PARAM_OPTIONAL
169 48 : Z_PARAM_LONG(seed)
170 48 : ZEND_PARSE_PARAMETERS_END();
171 :
172 48 : if (ZEND_NUM_ARGS() == 0) {
173 0 : seed = php_colopl_bc_generate_seed();
174 : }
175 :
176 48 : php_colopl_bc_srand(seed);
177 : }
178 :
179 3202044 : PHP_FUNCTION(Colopl_ColoplBc_Php70_rand)
180 : {
181 : zend_long min, max, number;
182 : int argc;
183 :
184 3202044 : number = php_colopl_bc_rand();
185 3202044 : argc = ZEND_NUM_ARGS();
186 :
187 3202044 : if (argc == 0) {
188 0 : RETURN_LONG(number);
189 : }
190 :
191 3202044 : ZEND_PARSE_PARAMETERS_START(2, 2)
192 3202044 : Z_PARAM_LONG(min)
193 3202044 : Z_PARAM_LONG(max)
194 3202044 : ZEND_PARSE_PARAMETERS_END();
195 :
196 3202044 : number = php_colopl_bc_rand_range(number, min, max, COLOPL_BC_RAND_MAX_VALUE);
197 3202044 : RETURN_LONG(number);
198 : }
199 :
200 0 : PHP_FUNCTION(Colopl_ColoplBc_Php70_getrandmax)
201 : {
202 0 : ZEND_PARSE_PARAMETERS_NONE();
203 :
204 0 : RETURN_LONG(COLOPL_BC_RAND_MAX_VALUE);
205 : }
206 :
207 : /* mt_rand.c */
208 :
209 36 : static inline void mt_initialize(uint32_t seed, uint32_t *state)
210 : {
211 36 : register uint32_t *s = state;
212 36 : register uint32_t *r = state;
213 36 : register int i = 1;
214 :
215 36 : *s++ = seed & 0xffffffffU;
216 22464 : for (; i < COLOPL_BC_MT_N; ++i) {
217 22428 : *s++ = ( 1812433253U * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffU;
218 22428 : r++;
219 : }
220 36 : }
221 :
222 5156 : static inline void mt_reload(void)
223 : {
224 5156 : register uint32_t *state = COLOPL_BC_G(mt_state);
225 5156 : register uint32_t *p = state;
226 : register int i;
227 :
228 1175568 : for (i = COLOPL_BC_MT_N - COLOPL_BC_MT_M; i--; ++p) {
229 1170412 : *p = php_colopl_bc_mt_twist(p[COLOPL_BC_MT_M], p[0], p[1]);
230 : }
231 2046932 : for (i = COLOPL_BC_MT_M; --i; ++p) {
232 2041776 : *p = php_colopl_bc_mt_twist(p[COLOPL_BC_MT_M - COLOPL_BC_MT_N], p[0], p[1]);
233 : }
234 5156 : *p = php_colopl_bc_mt_twist(p[COLOPL_BC_MT_M - COLOPL_BC_MT_N], p[0], state[0]);
235 5156 : COLOPL_BC_G(mt_left) = COLOPL_BC_MT_N;
236 5156 : COLOPL_BC_G(mt_next) = state;
237 5156 : }
238 :
239 36 : void php_colopl_bc_mt_srand(uint32_t seed)
240 : {
241 36 : mt_initialize(seed, COLOPL_BC_G(mt_state));
242 36 : mt_reload();
243 :
244 36 : COLOPL_BC_G(mt_rand_is_seeded) = 1;
245 36 : }
246 :
247 3202040 : uint32_t php_colopl_bc_mt_rand(void)
248 : {
249 : register uint32_t s1;
250 :
251 3202040 : if (COLOPL_BC_G(mt_left) == 0) {
252 5120 : mt_reload();
253 : }
254 3202040 : --COLOPL_BC_G(mt_left);
255 :
256 3202040 : s1 = *COLOPL_BC_G(mt_next)++;
257 3202040 : s1 ^= (s1 >> 11);
258 3202040 : s1 ^= (s1 << 7) & 0x9d2c5680U;
259 3202040 : s1 ^= (s1 << 15) & 0xefc60000U;
260 3202040 : return ( s1 ^ (s1 >> 18) );
261 : }
262 :
263 36 : PHP_FUNCTION(Colopl_ColoplBc_Php70_mt_srand)
264 : {
265 36 : zend_long seed = 0;
266 :
267 36 : ZEND_PARSE_PARAMETERS_START(0, 1)
268 36 : Z_PARAM_OPTIONAL
269 36 : Z_PARAM_LONG(seed)
270 36 : ZEND_PARSE_PARAMETERS_END();
271 :
272 36 : if (ZEND_NUM_ARGS() == 0) {
273 0 : seed = php_colopl_bc_generate_seed();
274 : }
275 :
276 36 : php_colopl_bc_mt_srand((uint32_t) seed);
277 : }
278 :
279 3202040 : PHP_FUNCTION(Colopl_ColoplBc_Php70_mt_rand)
280 : {
281 : zend_long min, max, number;
282 3202040 : int argc = ZEND_NUM_ARGS();
283 :
284 3202040 : if (argc == 0) {
285 0 : if (!COLOPL_BC_G(mt_rand_is_seeded)) {
286 0 : php_colopl_bc_mt_srand(php_colopl_bc_generate_seed());
287 : }
288 0 : RETURN_LONG(php_colopl_bc_mt_rand() >> 1);
289 : }
290 :
291 3202040 : ZEND_PARSE_PARAMETERS_START(2, 2)
292 3202040 : Z_PARAM_LONG(min)
293 3202040 : Z_PARAM_LONG(max)
294 3202040 : ZEND_PARSE_PARAMETERS_END();
295 :
296 3202040 : if (UNEXPECTED(max < min)) {
297 0 : zend_argument_value_error(2, "must be greater than or equal to argument #1 ($min)");
298 0 : RETURN_THROWS();
299 : }
300 :
301 3202040 : if (!COLOPL_BC_G(mt_rand_is_seeded)) {
302 0 : php_colopl_bc_mt_srand(php_colopl_bc_generate_seed());
303 : }
304 :
305 3202040 : number = (zend_long) (php_colopl_bc_mt_rand() >> 1);
306 3202040 : number = php_colopl_bc_rand_range(number, min, max, COLOPL_BC_MT_RAND_MAX_VALUE);
307 3202040 : RETURN_LONG(number);
308 : }
309 :
310 0 : PHP_FUNCTION(Colopl_ColoplBc_Php70_mt_getrandmax)
311 : {
312 0 : ZEND_PARSE_PARAMETERS_NONE();
313 :
314 0 : RETURN_LONG(COLOPL_BC_MT_RAND_MAX_VALUE);
315 : }
316 :
317 : /* array.c */
318 :
319 : #if PHP_VERSION_ID < 80200
320 : void php_colopl_bc_array_data_shuffle(zval *array)
321 : {
322 : uint32_t idx, j, n_elems;
323 : Bucket *p, temp;
324 : HashTable *hash;
325 : zend_long rnd_idx;
326 : uint32_t n_left;
327 :
328 : n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
329 :
330 : if (n_elems < 1) {
331 : return;
332 : }
333 :
334 : hash = Z_ARRVAL_P(array);
335 : n_left = n_elems;
336 :
337 : if (EXPECTED(hash->u.v.nIteratorsCount == 0)) {
338 : if (hash->nNumUsed != hash->nNumOfElements) {
339 : for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
340 : p = hash->arData + idx;
341 : if (Z_TYPE(p->val) == IS_UNDEF) continue;
342 : if (j != idx) {
343 : hash->arData[j] = *p;
344 : }
345 : j++;
346 : }
347 : }
348 : while (--n_left) {
349 : rnd_idx = php_colopl_bc_rand();
350 : rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
351 : if (rnd_idx != n_left) {
352 : temp = hash->arData[n_left];
353 : hash->arData[n_left] = hash->arData[rnd_idx];
354 : hash->arData[rnd_idx] = temp;
355 : }
356 : }
357 : } else {
358 : uint32_t iter_pos = zend_hash_iterators_lower_pos(hash, 0);
359 :
360 : if (hash->nNumUsed != hash->nNumOfElements) {
361 : for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
362 : p = hash->arData + idx;
363 : if (Z_TYPE(p->val) == IS_UNDEF) continue;
364 : if (j != idx) {
365 : hash->arData[j] = *p;
366 : if (idx == iter_pos) {
367 : zend_hash_iterators_update(hash, idx, j);
368 : iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
369 : }
370 : }
371 : j++;
372 : }
373 : }
374 : while (--n_left) {
375 : rnd_idx = php_colopl_bc_rand();
376 : rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
377 : if (rnd_idx != n_left) {
378 : temp = hash->arData[n_left];
379 : hash->arData[n_left] = hash->arData[rnd_idx];
380 : hash->arData[rnd_idx] = temp;
381 : zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
382 : }
383 : }
384 : }
385 : HANDLE_BLOCK_INTERRUPTIONS();
386 : hash->nNumUsed = n_elems;
387 : hash->nInternalPointer = 0;
388 :
389 : for (j = 0; j < n_elems; j++) {
390 : p = hash->arData + j;
391 : if (p->key) {
392 : zend_string_release(p->key);
393 : }
394 : p->h = j;
395 : p->key = NULL;
396 : }
397 : hash->nNextFreeElement = n_elems;
398 : if (!(hash->u.flags & HASH_FLAG_PACKED)) {
399 : zend_hash_to_packed(hash);
400 : }
401 : HANDLE_UNBLOCK_INTERRUPTIONS();
402 : }
403 : #else
404 4 : void php_colopl_bc_array_data_shuffle(zval *array)
405 : {
406 : int64_t idx, j, n_elems, rnd_idx, n_left;
407 : zval *zv, temp;
408 : HashTable *hash;
409 :
410 4 : n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
411 :
412 4 : if (n_elems < 1) {
413 0 : return;
414 : }
415 :
416 4 : hash = Z_ARRVAL_P(array);
417 4 : n_left = n_elems;
418 :
419 4 : if (!HT_IS_PACKED(hash)) {
420 0 : if (!HT_HAS_STATIC_KEYS_ONLY(hash)) {
421 0 : Bucket *p = hash->arData;
422 0 : zend_long i = hash->nNumUsed;
423 :
424 0 : for (; i > 0; p++, i--) {
425 0 : if (p->key) {
426 0 : zend_string_release(p->key);
427 0 : p->key = NULL;
428 : }
429 : }
430 : }
431 0 : zend_hash_to_packed(hash);
432 : }
433 :
434 4 : if (EXPECTED(!HT_HAS_ITERATORS(hash))) {
435 4 : if (hash->nNumUsed != hash->nNumOfElements) {
436 0 : for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
437 0 : zv = hash->arPacked + idx;
438 0 : if (Z_TYPE_P(zv) == IS_UNDEF) continue;
439 0 : if (j != idx) {
440 0 : ZVAL_COPY_VALUE(&hash->arPacked[j], zv);
441 : }
442 0 : j++;
443 : }
444 : }
445 400 : while (--n_left) {
446 396 : rnd_idx = php_colopl_bc_rand();
447 396 : rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
448 396 : if (rnd_idx != n_left) {
449 370 : ZVAL_COPY_VALUE(&temp, &hash->arPacked[n_left]);
450 370 : ZVAL_COPY_VALUE(&hash->arPacked[n_left], &hash->arPacked[rnd_idx]);
451 370 : ZVAL_COPY_VALUE(&hash->arPacked[rnd_idx], &temp);
452 : }
453 : }
454 : } else {
455 0 : zend_long iter_pos = zend_hash_iterators_lower_pos(hash, 0);
456 :
457 0 : if (hash->nNumUsed != hash->nNumOfElements) {
458 0 : for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
459 0 : zv = hash->arPacked + idx;
460 0 : if (Z_TYPE_P(zv) == IS_UNDEF) continue;
461 0 : if (j != idx) {
462 0 : ZVAL_COPY_VALUE(&hash->arPacked[j], zv);
463 0 : if (idx == iter_pos) {
464 0 : zend_hash_iterators_update(hash, idx, j);
465 0 : iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
466 : }
467 : }
468 0 : j++;
469 : }
470 : }
471 0 : while (--n_left) {
472 0 : rnd_idx = php_colopl_bc_rand();
473 0 : rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
474 0 : if (rnd_idx != n_left) {
475 0 : ZVAL_COPY_VALUE(&temp, &hash->arPacked[n_left]);
476 0 : ZVAL_COPY_VALUE(&hash->arPacked[n_left], &hash->arPacked[rnd_idx]);
477 0 : ZVAL_COPY_VALUE(&hash->arPacked[rnd_idx], &temp);
478 0 : zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
479 : }
480 : }
481 : }
482 4 : hash->nNumUsed = n_elems;
483 4 : hash->nInternalPointer = 0;
484 4 : hash->nNextFreeElement = n_elems;
485 : }
486 : #endif
487 :
488 4 : PHP_FUNCTION(Colopl_ColoplBc_Php70_shuffle)
489 : {
490 : zval *array;
491 :
492 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
493 4 : Z_PARAM_ARRAY_EX(array, 0, 1)
494 4 : ZEND_PARSE_PARAMETERS_END();
495 :
496 4 : php_colopl_bc_array_data_shuffle(array);
497 :
498 4 : RETURN_TRUE;
499 : }
500 :
501 4 : PHP_FUNCTION(Colopl_ColoplBc_Php70_array_rand)
502 : {
503 : zval *input;
504 4 : zend_long randval, num_req = 1;
505 : int num_avail;
506 : zend_string *string_key;
507 : zend_ulong num_key;
508 :
509 4 : ZEND_PARSE_PARAMETERS_START(1, 2)
510 4 : Z_PARAM_ARRAY(input)
511 4 : Z_PARAM_OPTIONAL
512 4 : Z_PARAM_LONG(num_req)
513 4 : ZEND_PARSE_PARAMETERS_END();
514 :
515 4 : num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));
516 :
517 4 : if (ZEND_NUM_ARGS() > 1) {
518 4 : if (num_req <= 0 || num_req > num_avail) {
519 0 : zend_argument_value_error(2, "must be between 1 and the number of elements in argument #1 ($array)");
520 0 : RETURN_THROWS();
521 : }
522 : }
523 :
524 : /* Make the return value an array only if we need to pass back more than one result. */
525 4 : if (num_req > 1) {
526 4 : array_init_size(return_value, (uint32_t)num_req);
527 : }
528 :
529 : /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
530 22 : ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(input), num_key, string_key) {
531 20 : if (!num_req) {
532 2 : break;
533 : }
534 :
535 18 : randval = php_colopl_bc_rand();
536 :
537 18 : if ((double) randval / ((double) COLOPL_BC_RAND_MAX_VALUE + 1.0) < (double) num_req / (double) num_avail) {
538 : /* If we are returning a single result, just do it. */
539 12 : if (Z_TYPE_P(return_value) != IS_ARRAY) {
540 0 : if (string_key) {
541 0 : RETURN_STR_COPY(string_key);
542 : } else {
543 0 : RETURN_LONG(num_key);
544 : }
545 : } else {
546 : /* Append the result to the return value. */
547 12 : if (string_key) {
548 0 : add_next_index_str(return_value, zend_string_copy(string_key));
549 : } else {
550 12 : add_next_index_long(return_value, num_key);
551 : }
552 : }
553 12 : num_req--;
554 : }
555 18 : num_avail--;
556 : } ZEND_HASH_FOREACH_END();
557 :
558 : }
559 :
560 : /* string.c */
561 4 : void php_colopl_bc_string_shuffle(char *str, zend_long len)
562 : {
563 : zend_long n_elems, rnd_idx, n_left;
564 : char temp;
565 :
566 4 : n_elems = len;
567 :
568 4 : if (n_elems <= 1) {
569 0 : return;
570 : }
571 :
572 4 : n_left = n_elems;
573 :
574 1780 : while (--n_left) {
575 1776 : rnd_idx = php_colopl_bc_rand();
576 1776 : rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
577 1776 : if (rnd_idx != n_left) {
578 1744 : temp = str[n_left];
579 1744 : str[n_left] = str[rnd_idx];
580 1744 : str[rnd_idx] = temp;
581 : }
582 : }
583 : }
584 :
585 4 : PHP_FUNCTION(Colopl_ColoplBc_Php70_str_shuffle)
586 : {
587 : zend_string *arg;
588 :
589 4 : ZEND_PARSE_PARAMETERS_START(1, 1)
590 4 : Z_PARAM_STR(arg)
591 4 : ZEND_PARSE_PARAMETERS_END();
592 :
593 4 : RETVAL_STRINGL(ZSTR_VAL(arg), ZSTR_LEN(arg));
594 4 : if (Z_STRLEN_P(return_value) > 1) {
595 4 : php_colopl_bc_string_shuffle(Z_STRVAL_P(return_value), (zend_long) Z_STRLEN_P(return_value));
596 : }
597 : }
598 :
599 4004 : PHP_FUNCTION(Colopl_ColoplBc_Php70_date_create)
600 : {
601 4004 : zval *timezone_object = NULL;
602 4004 : char *time_str = NULL;
603 4004 : size_t time_str_len = 0;
604 : php_date_obj *date;
605 :
606 4004 : ZEND_PARSE_PARAMETERS_START(0, 2)
607 4004 : Z_PARAM_OPTIONAL
608 4004 : Z_PARAM_STRING(time_str, time_str_len)
609 4 : Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, php_date_get_timezone_ce())
610 4008 : ZEND_PARSE_PARAMETERS_END();
611 :
612 4004 : php_date_instantiate(php_date_get_date_ce(), return_value);
613 4004 : if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) {
614 4 : zval_ptr_dtor(return_value);
615 4 : RETURN_FALSE;
616 : }
617 :
618 4000 : date = Z_PHPDATE_P(return_value);
619 4000 : date->time->us = 0;
620 : }
621 :
622 4004 : PHP_FUNCTION(Colopl_ColoplBc_Php70_date_create_immutable)
623 : {
624 4004 : zval *timezone_object = NULL;
625 4004 : char *time_str = NULL;
626 4004 : size_t time_str_len = 0;
627 : php_date_obj *date;
628 :
629 4004 : ZEND_PARSE_PARAMETERS_START(0, 2)
630 4004 : Z_PARAM_OPTIONAL
631 4004 : Z_PARAM_STRING(time_str, time_str_len)
632 4 : Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, php_date_get_timezone_ce())
633 4008 : ZEND_PARSE_PARAMETERS_END();
634 :
635 4004 : php_date_instantiate(php_date_get_immutable_ce(), return_value);
636 4004 : if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) {
637 4 : zval_ptr_dtor(return_value);
638 4 : RETURN_FALSE;
639 : }
640 :
641 4000 : date = Z_PHPDATE_P(return_value);
642 4000 : date->time->us = 0;
643 : }
|