@@ -2511,6 +2511,66 @@ int php_phongo_set_monitoring_callbacks(mongoc_client_t* client)
25112511 return retval ;
25122512}
25132513
2514+ static zval * php_phongo_manager_prepare_manager_for_hash (zval * driverOptions , bool * free TSRMLS_DC )
2515+ {
2516+ php_phongo_manager_t * manager ;
2517+ zval * autoEncryptionOpts = NULL ;
2518+ zval * keyVaultClient = NULL ;
2519+ zval * driverOptionsClone = NULL ;
2520+ zval * autoEncryptionOptsClone = NULL ;
2521+ #if PHP_VERSION_ID >= 70000
2522+ zval stackAutoEncryptionOptsClone ;
2523+ #endif
2524+
2525+ * free = false;
2526+
2527+ if (!driverOptions ) {
2528+ return NULL ;
2529+ }
2530+
2531+ if (!php_array_existsc (driverOptions , "autoEncryption" )) {
2532+ goto ref ;
2533+ }
2534+
2535+ autoEncryptionOpts = php_array_fetchc (driverOptions , "autoEncryption" );
2536+ if (Z_TYPE_P (autoEncryptionOpts ) != IS_ARRAY ) {
2537+ goto ref ;
2538+ }
2539+
2540+ if (!php_array_existsc (autoEncryptionOpts , "keyVaultClient" )) {
2541+ goto ref ;
2542+ }
2543+
2544+ keyVaultClient = php_array_fetchc (autoEncryptionOpts , "keyVaultClient" );
2545+ if (Z_TYPE_P (keyVaultClient ) != IS_OBJECT || !instanceof_function (Z_OBJCE_P (keyVaultClient ), php_phongo_manager_ce TSRMLS_CC )) {
2546+ goto ref ;
2547+ }
2548+
2549+ * free = true;
2550+
2551+ manager = Z_MANAGER_OBJ_P (keyVaultClient );
2552+
2553+ #if PHP_VERSION_ID >= 70000
2554+ driverOptionsClone = ecalloc (sizeof (zval ), 1 );
2555+ autoEncryptionOptsClone = & stackAutoEncryptionOptsClone ;
2556+ #else
2557+ ALLOC_INIT_ZVAL (driverOptionsClone );
2558+ MAKE_STD_ZVAL (autoEncryptionOptsClone );
2559+ #endif
2560+
2561+ ZVAL_DUP (autoEncryptionOptsClone , autoEncryptionOpts );
2562+ ADD_ASSOC_STRINGL (autoEncryptionOptsClone , "keyVaultClient" , manager -> client_hash , manager -> client_hash_len );
2563+
2564+ ZVAL_DUP (driverOptionsClone , driverOptions );
2565+ ADD_ASSOC_ZVAL_EX (driverOptionsClone , "autoEncryption" , autoEncryptionOptsClone );
2566+
2567+ return driverOptionsClone ;
2568+
2569+ ref :
2570+ Z_ADDREF_P (driverOptions );
2571+ return driverOptions ;
2572+ }
2573+
25142574/* Creates a hash for a client by concatenating the URI string with serialized
25152575 * options arrays. On success, a persistent string is returned (i.e. pefree()
25162576 * should be used to free it) and hash_len will be set to the string's length.
@@ -2520,6 +2580,8 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25202580 char * hash = NULL ;
25212581 smart_str var_buf = { 0 };
25222582 php_serialize_data_t var_hash ;
2583+ zval * serializable_driver_options = NULL ;
2584+ bool free_driver_options = false;
25232585
25242586#if PHP_VERSION_ID >= 70000
25252587 zval args ;
@@ -2536,8 +2598,8 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25362598 }
25372599
25382600 if (driverOptions ) {
2539- ADD_ASSOC_ZVAL_EX ( & args , " driverOptions" , driverOptions );
2540- Z_ADDREF_P ( driverOptions );
2601+ serializable_driver_options = php_phongo_manager_prepare_manager_for_hash ( driverOptions , & free_driver_options TSRMLS_CC );
2602+ ADD_ASSOC_ZVAL_EX ( & args , " driverOptions" , serializable_driver_options );
25412603 } else {
25422604 ADD_ASSOC_NULL_EX (& args , "driverOptions" );
25432605 }
@@ -2548,10 +2610,15 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25482610
25492611 if (!EG (exception )) {
25502612 * hash_len = ZSTR_LEN (var_buf .s );
2551- hash = pestrndup (ZSTR_VAL (var_buf .s ), * hash_len , 1 );
2613+ hash = estrndup (ZSTR_VAL (var_buf .s ), * hash_len );
25522614 }
25532615
25542616 zval_ptr_dtor (& args );
2617+
2618+ if (free_driver_options ) {
2619+ efree (serializable_driver_options );
2620+ }
2621+
25552622#else
25562623 zval * args ;
25572624
@@ -2568,8 +2635,8 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25682635 }
25692636
25702637 if (driverOptions ) {
2571- ADD_ASSOC_ZVAL_EX ( args , " driverOptions" , driverOptions );
2572- Z_ADDREF_P ( driverOptions );
2638+ serializable_driver_options = php_phongo_manager_prepare_manager_for_hash ( driverOptions , & free_driver_options TSRMLS_CC );
2639+ ADD_ASSOC_ZVAL_EX ( args , " driverOptions" , serializable_driver_options );
25732640 } else {
25742641 ADD_ASSOC_NULL_EX (args , "driverOptions" );
25752642 }
@@ -2580,7 +2647,7 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25802647
25812648 if (!EG (exception )) {
25822649 * hash_len = var_buf .len ;
2583- hash = pestrndup (var_buf .c , * hash_len , 1 );
2650+ hash = estrndup (var_buf .c , * hash_len );
25842651 }
25852652
25862653 zval_ptr_dtor (& args );
@@ -2653,23 +2720,156 @@ static mongoc_client_t* php_phongo_find_client(const char* hash, size_t hash_len
26532720 return NULL ;
26542721}
26552722
2723+ #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
2724+ static bool phongo_manager_set_auto_encryption_opts (php_phongo_manager_t * manager , zval * driverOptions TSRMLS_DC ) /* {{{ */
2725+ {
2726+ zval * zAutoEncryptionOpts ;
2727+ bson_error_t error = { 0 };
2728+ mongoc_auto_encryption_opts_t * auto_encryption_opts = NULL ;
2729+ bool retval = false;
2730+
2731+ if (!driverOptions || !php_array_existsc (driverOptions , "autoEncryption" )) {
2732+ return true;
2733+ }
2734+
2735+ zAutoEncryptionOpts = php_array_fetch (driverOptions , "autoEncryption" );
2736+
2737+ if (Z_TYPE_P (zAutoEncryptionOpts ) != IS_ARRAY ) {
2738+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"autoEncryption\" driver option to be array, %s given" , PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P (zAutoEncryptionOpts ));
2739+ return false;
2740+ }
2741+
2742+ auto_encryption_opts = mongoc_auto_encryption_opts_new ();
2743+
2744+ if (php_array_existsc (zAutoEncryptionOpts , "keyVaultClient" )) {
2745+ zval * key_vault_client = php_array_fetch (zAutoEncryptionOpts , "keyVaultClient" );
2746+
2747+ if (Z_TYPE_P (key_vault_client ) != IS_OBJECT || !instanceof_function (Z_OBJCE_P (key_vault_client ), php_phongo_manager_ce TSRMLS_CC )) {
2748+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"keyVaultClient\" encryption option to be %s, %s given" , ZSTR_VAL (php_phongo_manager_ce -> name ), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P (key_vault_client ));
2749+ goto cleanup ;
2750+ }
2751+
2752+ mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts , Z_MANAGER_OBJ_P (key_vault_client )-> client );
2753+ }
2754+
2755+ if (php_array_existsc (zAutoEncryptionOpts , "keyVaultNamespace" )) {
2756+ char * key_vault_ns ;
2757+ char * db_name ;
2758+ char * coll_name ;
2759+ int plen ;
2760+ zend_bool pfree ;
2761+
2762+ key_vault_ns = php_array_fetch_string (zAutoEncryptionOpts , "keyVaultNamespace" , & plen , & pfree );
2763+
2764+ if (!phongo_split_namespace (key_vault_ns , & db_name , & coll_name )) {
2765+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"keyVaultNamespace\" encryption option to contain a full collection name" );
2766+
2767+ if (pfree ) {
2768+ str_efree (key_vault_ns );
2769+ }
2770+
2771+ goto cleanup ;
2772+ }
2773+
2774+ mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts , db_name , coll_name );
2775+
2776+ efree (db_name );
2777+ efree (coll_name );
2778+
2779+ if (pfree ) {
2780+ str_efree (key_vault_ns );
2781+ }
2782+ }
2783+
2784+ if (php_array_existsc (zAutoEncryptionOpts , "kmsProviders" )) {
2785+ zval * kms_providers = php_array_fetch (zAutoEncryptionOpts , "kmsProviders" );
2786+ bson_t bson_providers = BSON_INITIALIZER ;
2787+
2788+ php_phongo_zval_to_bson (kms_providers , PHONGO_BSON_NONE , & bson_providers , NULL TSRMLS_CC );
2789+ if (EG (exception )) {
2790+ goto cleanup ;
2791+ }
2792+
2793+ mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts , & bson_providers );
2794+
2795+ bson_destroy (& bson_providers );
2796+ }
2797+
2798+ if (php_array_existsc (zAutoEncryptionOpts , "schemaMap" )) {
2799+ zval * schema_map = php_array_fetch (zAutoEncryptionOpts , "schemaMap" );
2800+ bson_t bson_map = BSON_INITIALIZER ;
2801+
2802+ php_phongo_zval_to_bson (schema_map , PHONGO_BSON_NONE , & bson_map , NULL TSRMLS_CC );
2803+ if (EG (exception )) {
2804+ goto cleanup ;
2805+ }
2806+
2807+ mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts , & bson_map );
2808+
2809+ bson_destroy (& bson_map );
2810+ }
2811+
2812+ if (php_array_existsc (zAutoEncryptionOpts , "bypassAutoEncryption" )) {
2813+ zend_bool bypass_auto_encryption = php_array_fetch_bool (zAutoEncryptionOpts , "bypassAutoEncryption" );
2814+
2815+ mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts , bypass_auto_encryption );
2816+ }
2817+
2818+ if (php_array_existsc (zAutoEncryptionOpts , "extraOptions" )) {
2819+ zval * extra_options = php_array_fetch (zAutoEncryptionOpts , "extraOptions" );
2820+ bson_t bson_options = BSON_INITIALIZER ;
2821+
2822+ php_phongo_zval_to_bson (extra_options , PHONGO_BSON_NONE , & bson_options , NULL TSRMLS_CC );
2823+ if (EG (exception )) {
2824+ goto cleanup ;
2825+ }
2826+
2827+ mongoc_auto_encryption_opts_set_extra (auto_encryption_opts , & bson_options );
2828+
2829+ bson_destroy (& bson_options );
2830+ }
2831+
2832+ if (!mongoc_client_enable_auto_encryption (manager -> client , auto_encryption_opts , & error )) {
2833+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
2834+ goto cleanup ;
2835+ }
2836+
2837+ retval = true;
2838+
2839+ cleanup :
2840+ mongoc_auto_encryption_opts_destroy (auto_encryption_opts );
2841+ return retval ;
2842+ }
2843+ /* }}} */
2844+ #else /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */
2845+ static bool phongo_manager_set_auto_encryption_opts (php_phongo_manager_t * manager , zval * driverOptions TSRMLS_DC ) /* {{{ */
2846+ {
2847+ if (!driverOptions || !php_array_existsc (driverOptions , "autoEncryption" )) {
2848+ return true;
2849+ }
2850+
2851+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Cannot enable automatic field-level encryption. Please recompile with support for libmongocrypt using the with-mongodb-client-side-encryption configure switch." );
2852+
2853+ return false;
2854+ }
2855+ /* }}} */
2856+ #endif
2857+
26562858void phongo_manager_init (php_phongo_manager_t * manager , const char * uri_string , zval * options , zval * driverOptions TSRMLS_DC ) /* {{{ */
26572859{
2658- char * hash = NULL ;
2659- size_t hash_len = 0 ;
26602860 bson_t bson_options = BSON_INITIALIZER ;
26612861 mongoc_uri_t * uri = NULL ;
26622862#ifdef MONGOC_ENABLE_SSL
26632863 mongoc_ssl_opt_t * ssl_opt = NULL ;
26642864#endif
26652865
2666- if (!(hash = php_phongo_manager_make_client_hash (uri_string , options , driverOptions , & hash_len TSRMLS_CC ))) {
2866+ if (!(manager -> client_hash = php_phongo_manager_make_client_hash (uri_string , options , driverOptions , & manager -> client_hash_len TSRMLS_CC ))) {
26672867 /* Exception should already have been thrown and there is nothing to free */
26682868 return ;
26692869 }
26702870
2671- if ((manager -> client = php_phongo_find_client (hash , hash_len TSRMLS_CC ))) {
2672- MONGOC_DEBUG ("Found client for hash: %s\n" , hash );
2871+ if ((manager -> client = php_phongo_find_client (manager -> client_hash , manager -> client_hash_len TSRMLS_CC ))) {
2872+ MONGOC_DEBUG ("Found client for hash: %s\n" , manager -> client_hash );
26732873 goto cleanup ;
26742874 }
26752875
@@ -2733,14 +2933,15 @@ void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string,
27332933 }
27342934#endif
27352935
2736- MONGOC_DEBUG ("Created client hash: %s\n" , hash );
2737- php_phongo_persist_client (hash , hash_len , manager -> client TSRMLS_CC );
2738-
2739- cleanup :
2740- if (hash ) {
2741- pefree (hash , 1 );
2936+ if (!phongo_manager_set_auto_encryption_opts (manager , driverOptions TSRMLS_CC )) {
2937+ /* Exception should already have been thrown */
2938+ goto cleanup ;
27422939 }
27432940
2941+ MONGOC_DEBUG ("Created client hash: %s\n" , manager -> client_hash );
2942+ php_phongo_persist_client (manager -> client_hash , manager -> client_hash_len , manager -> client TSRMLS_CC );
2943+
2944+ cleanup :
27442945 bson_destroy (& bson_options );
27452946
27462947 if (uri ) {
0 commit comments