19
19
#include "php.h"
20
20
#include "info.h"
21
21
22
+ #include "zend_exceptions.h"
23
+
22
24
#include "php_random.h"
23
25
#include "php_random_class.h"
24
26
#include "random_class_arginfo.h"
25
27
26
- #include "zend_exceptions.h"
28
+ PHPAPI zend_class_entry * php_random_class_ce_RandomNumberGenerator ;
29
+ PHPAPI zend_class_entry * php_random_class_ce_Random ;
27
30
28
31
static zend_array php_random_class_algos ;
29
- static zend_class_entry * php_random_class_ce ;
30
32
static zend_object_handlers php_random_class_object_handlers ;
31
33
34
+ /* stolen from: mt_rand.c */
32
35
static uint32_t range32 (php_random_class * random_class , uint32_t umax ) {
33
36
uint32_t result , limit ;
34
37
@@ -59,6 +62,7 @@ static uint32_t range32(php_random_class *random_class, uint32_t umax) {
59
62
}
60
63
61
64
#if ZEND_ULONG_MAX > UINT32_MAX
65
+ /* stolen from: mt_rand.c */
62
66
static uint64_t range64 (php_random_class * random_class , uint64_t umax ) {
63
67
uint64_t result , limit ;
64
68
@@ -134,24 +138,32 @@ const php_random_class_algo* php_random_class_algo_find(const zend_string *ident
134
138
135
139
/* {{{ */
136
140
uint64_t php_random_class_next (php_random_class * random_class )
137
- {
138
- zend_long ret ;
139
- zend_function * function ;
140
- zval function_name , retval ;
141
-
141
+ {
142
142
if (random_class -> algo ) {
143
143
return random_class -> algo -> next (random_class -> state );
144
144
}
145
145
146
- /* call user implementation. */
147
- ZVAL_STRING (& function_name , "next" );
148
- function = zend_hash_find_ptr (& random_class -> std .ce -> function_table , Z_STR (function_name ));
149
- zval_ptr_dtor (& function_name );
146
+ zval retval , rv ;
147
+ zval * zrng = zend_read_property (random_class -> std .ce , & random_class -> std , "rng" , sizeof ("rng" ) - 1 , 0 , & rv );
148
+ if (Z_ISNULL_P (zrng )) {
149
+ return 0 ;
150
+ }
151
+
152
+ zend_object * obj = Z_OBJ_P (zrng );
153
+ if (!obj ) {
154
+ return 0 ;
155
+ }
156
+
157
+ zend_string * method_name_generate = zend_string_init ("generate" , sizeof ("generate" ) - 1 , 0 );
158
+ zend_function * func = zend_hash_find_ptr (& obj -> ce -> function_table , method_name_generate );
159
+ zend_string_release (method_name_generate );
160
+ if (!func ) {
161
+ return 0 ;
162
+ }
150
163
151
- zend_call_known_instance_method_with_0_params (function , & random_class -> std , & retval );
152
- ret = Z_LVAL (retval );
164
+ zend_call_known_instance_method_with_0_params (func , obj , & retval );
153
165
154
- return (uint64_t ) ret ;
166
+ return (uint64_t ) Z_LVAL ( retval ) ;
155
167
}
156
168
/* }}} */
157
169
@@ -284,9 +296,13 @@ static zend_object *php_random_class_new(zend_class_entry *ce) {
284
296
return & random_class -> std ;
285
297
}
286
298
287
- static void php_random_class_state_initialize (php_random_class * random_class ) {
288
- if (random_class -> algo && random_class -> algo -> state_size > 0 ) {
289
- random_class -> state = ecalloc (1 , random_class -> algo -> state_size );
299
+ static void php_random_class_state_initialize (php_random_class * random_class , const php_random_class_algo * algo ) {
300
+ if (!algo ) {
301
+ return ;
302
+ }
303
+
304
+ if (algo -> state_size > 0 ) {
305
+ random_class -> state = ecalloc (1 , algo -> state_size );
290
306
}
291
307
}
292
308
@@ -311,7 +327,7 @@ static zend_object *php_random_class_clone_obj(zend_object *object) {
311
327
312
328
if (old -> algo ) {
313
329
new -> algo = old -> algo ;
314
- php_random_class_state_initialize (new );
330
+ php_random_class_state_initialize (new , new -> algo );
315
331
memcpy (new -> state , old -> state , old -> algo -> state_size );
316
332
}
317
333
@@ -523,10 +539,6 @@ const php_random_class_algo php_random_class_algo_secure = {
523
539
};
524
540
/* secure END */
525
541
526
- /* user BEGIN */
527
- #define PHP_RANDOM_CLASS_ALGO_USER_DEFINED "user"
528
- /* user END */
529
-
530
542
/* {{{ PHP_INI */
531
543
PHP_INI_BEGIN ()
532
544
STD_PHP_INI_BOOLEAN ("random.ignore_generated_size_exceeded" , "0" , PHP_INI_ALL , OnUpdateBool , random_class_ignore_generated_size_exceeded , php_core_globals , core_globals )
@@ -572,47 +584,61 @@ PHP_METHOD(Random, getAlgoInfo)
572
584
/* {{{ */
573
585
PHP_METHOD (Random , __construct )
574
586
{
587
+ php_random_class * random_class = Z_RANDOM_CLASS_P (ZEND_THIS );
575
588
zend_string * algo_str = NULL ;
589
+ zend_object * rng = NULL ;
576
590
zend_long seed ;
577
591
bool seed_is_null = 1 ;
578
- const php_random_class_algo * algo ;
579
592
580
593
ZEND_PARSE_PARAMETERS_START (0 , 2 )
581
594
Z_PARAM_OPTIONAL
582
- Z_PARAM_STR ( algo_str )
595
+ Z_PARAM_OBJ_OF_CLASS_OR_STR ( rng , php_random_class_ce_RandomNumberGenerator , algo_str )
583
596
Z_PARAM_LONG_OR_NULL (seed , seed_is_null )
584
597
ZEND_PARSE_PARAMETERS_END ();
585
598
586
- algo =
587
- algo_str == NULL
588
- ? & php_random_class_algo_xorshift128plus
589
- : php_random_class_algo_find (algo_str );
590
-
591
- if (algo ) {
592
- php_random_class * random_class = Z_RANDOM_CLASS_P (ZEND_THIS );
593
- random_class -> algo = algo ;
594
-
595
- if (!algo -> seed && !seed_is_null ) {
596
- zend_argument_value_error (2 , "algorithm does not support seed with value" );
599
+ if (rng ) {
600
+ zval property_rng_value ;
601
+
602
+ if (!seed_is_null ) {
603
+ zend_argument_value_error (2 , "RandomNumberGenerator does not support seed with value" );
597
604
RETURN_THROWS ();
598
605
}
599
606
600
- php_random_class_state_initialize (random_class );
601
- if (algo -> seed ) {
602
- if (seed_is_null ) {
603
- seed = php_random_bytes_silent (& seed , sizeof (zend_long ));
604
- }
607
+ ZVAL_OBJ (& property_rng_value , rng );
608
+ zend_string * property_rng_name = zend_string_init ("rng" , sizeof ("rng" ) - 1 , 0 );
609
+ zend_std_write_property (& random_class -> std , property_rng_name , & property_rng_value , NULL );
610
+ zend_string_release (property_rng_name );
611
+
612
+ return ;
613
+ }
605
614
606
- algo -> seed (random_class -> state , seed );
607
- }
615
+ const php_random_class_algo * algo ;
608
616
609
- } else if (! zend_string_equals_literal (algo_str , PHP_RANDOM_CLASS_ALGO_USER_DEFINED )) {
617
+ algo = algo_str == NULL
618
+ ? & php_random_class_algo_xorshift128plus
619
+ : php_random_class_algo_find (algo_str );
620
+
621
+ if (!algo ) {
610
622
zend_argument_value_error (1 , "must be a valid random number generator algorithm" );
611
623
RETURN_THROWS ();
612
- } else if (Z_OBJCE_P (ZEND_THIS )-> type == ZEND_INTERNAL_CLASS ) {
613
- zend_throw_exception (NULL , "User defined algorithm must be inherited" , 0 );
624
+ }
625
+
626
+ random_class -> algo = algo ;
627
+
628
+ if (!algo -> seed && !seed_is_null ) {
629
+ zend_argument_value_error (2 , "algorithm does not support seed with value" );
614
630
RETURN_THROWS ();
615
631
}
632
+
633
+ php_random_class_state_initialize (random_class , algo );
634
+
635
+ if (algo -> seed ) {
636
+ if (seed_is_null ) {
637
+ seed = php_random_bytes_silent (& seed , sizeof (zend_long ));
638
+ }
639
+
640
+ algo -> seed (random_class -> state , seed );
641
+ }
616
642
}
617
643
/* }}} */
618
644
@@ -744,11 +770,6 @@ PHP_METHOD(Random, __serialize)
744
770
745
771
ZEND_PARSE_PARAMETERS_NONE ();
746
772
747
- if (Z_OBJCE_P (ZEND_THIS )-> ce_flags & ZEND_ACC_ANON_CLASS ) {
748
- zend_throw_exception (NULL , "Anonymous class serialization is not allowed" , 0 );
749
- RETURN_THROWS ();
750
- }
751
-
752
773
if (intern -> algo && (!intern -> algo -> serialize || !intern -> algo -> unserialize )) {
753
774
zend_throw_exception (NULL , "Algorithm does not support serialization" , 0 );
754
775
RETURN_THROWS ();
@@ -762,7 +783,11 @@ PHP_METHOD(Random, __serialize)
762
783
zend_hash_next_index_insert (Z_ARRVAL_P (return_value ), & tmp );
763
784
764
785
/* algo */
765
- ZVAL_STRING (& tmp , intern -> algo ? intern -> algo -> ident : PHP_RANDOM_CLASS_ALGO_USER_DEFINED );
786
+ if (intern -> algo ) {
787
+ ZVAL_STRING (& tmp , intern -> algo -> ident );
788
+ } else {
789
+ ZVAL_NULL (& tmp );
790
+ }
766
791
zend_hash_next_index_insert (Z_ARRVAL_P (return_value ), & tmp );
767
792
768
793
/* state */
@@ -776,7 +801,6 @@ PHP_METHOD(Random, __serialize)
776
801
PHP_METHOD (Random , __unserialize )
777
802
{
778
803
php_random_class * intern = Z_RANDOM_CLASS_P (ZEND_THIS );
779
- const php_random_class_algo * algo ;
780
804
HashTable * data ;
781
805
zval * tmp , * members_zv ;
782
806
@@ -794,15 +818,17 @@ PHP_METHOD(Random, __unserialize)
794
818
795
819
/* state */
796
820
tmp = zend_hash_index_find (data , 1 );
797
- if (! zend_string_equals_literal (Z_STR_P (tmp ), PHP_RANDOM_CLASS_ALGO_USER_DEFINED )) {
821
+ if (!Z_ISNULL_P (tmp )) {
822
+ const php_random_class_algo * algo ;
823
+
798
824
algo = php_random_class_algo_find (Z_STR_P (tmp ));
799
825
if (!algo ) {
800
826
zend_throw_exception (NULL , "Algorithm does not registered" , 0 );
801
827
RETURN_THROWS ();
802
828
}
803
829
intern -> algo = algo ;
804
830
805
- php_random_class_state_initialize (intern );
831
+ php_random_class_state_initialize (intern , algo );
806
832
807
833
if (!algo -> serialize || !algo -> unserialize ) {
808
834
zend_throw_exception (NULL , "Algorithm does not support serialization" , 0 );
@@ -817,40 +843,31 @@ PHP_METHOD(Random, __unserialize)
817
843
}
818
844
/* }}} */
819
845
820
- /* {{{ */
821
- PHP_METHOD (Random , next )
822
- {
823
- zend_throw_exception (NULL , "Must be override the method next(): int" , 0 );
824
- RETURN_THROWS ();
825
- }
826
- /* }}} */
827
-
828
846
PHP_MINIT_FUNCTION (random_class )
829
847
{
830
- zend_class_entry ce ;
831
-
832
848
REGISTER_INI_ENTRIES ();
833
849
834
850
zend_hash_init (& php_random_class_algos , 1 , NULL , ZVAL_PTR_DTOR , 1 );
835
851
836
- /* XorShift128+ */
852
+ /* algo: XorShift128+ */
837
853
if (FAILURE == php_random_class_algo_register (& php_random_class_algo_xorshift128plus )) { return FAILURE ; }
838
854
REGISTER_STRING_CONSTANT ("RANDOM_XORSHIFT128PLUS" , php_random_class_algo_xorshift128plus .ident , CONST_CS | CONST_PERSISTENT );
839
855
840
- /* MT19937 */
856
+ /* algo: MT19937 */
841
857
if (FAILURE == php_random_class_algo_register (& php_random_class_algo_mt19937 )) { return FAILURE ; }
842
858
REGISTER_STRING_CONSTANT ("RANDOM_MT19937" , php_random_class_algo_mt19937 .ident , CONST_CS | CONST_PERSISTENT );
843
859
844
- /* secure */
860
+ /* algo: secure */
845
861
if (FAILURE == php_random_class_algo_register (& php_random_class_algo_secure )) { return FAILURE ; }
846
862
REGISTER_STRING_CONSTANT ("RANDOM_SECURE" , php_random_class_algo_secure .ident , CONST_CS | CONST_PERSISTENT );
847
863
848
- /* user */
849
- REGISTER_STRING_CONSTANT ("RANDOM_USER" , PHP_RANDOM_CLASS_ALGO_USER_DEFINED , CONST_CS | CONST_PERSISTENT );
864
+ /* interface: RandomNumberGenerator */
865
+ php_random_class_ce_RandomNumberGenerator = register_class_RandomNumberGenerator ();
866
+
867
+ /* class:Random */
868
+ php_random_class_ce_Random = register_class_Random ();
850
869
851
- INIT_CLASS_ENTRY (ce , "Random" , class_Random_methods );
852
- php_random_class_ce = zend_register_internal_class (& ce );
853
- php_random_class_ce -> create_object = php_random_class_new ;
870
+ php_random_class_ce_Random -> create_object = php_random_class_new ;
854
871
memcpy (& php_random_class_object_handlers , zend_get_std_object_handlers (), sizeof (zend_object_handlers ));
855
872
php_random_class_object_handlers .offset = XtOffsetOf (php_random_class , std );
856
873
php_random_class_object_handlers .free_obj = php_random_class_free_obj ;
0 commit comments