2222 * In a normal course of events, the following line will always work
2323 * zend_eval_string("Aws\\Sdk::VERSION;", &retval, "Get AWS Version")
2424 * By the time we have detected the existence of the aws-sdk-php and with
25- * default composer profject settings, it callable even from
25+ * default composer project settings, it is callable even from
2626 * nr_aws_sdk_php_enable which will automatically load the class if it isn't
27- * loaded yet and then evaluate the string. However, in the rare case that files
27+ * loaded yet and then evaluate the string. In the rare case that files
2828 * are not loaded via autoloader and/or have non-default composer classload
29- * settings, if the class is not found, PHP 8.2+ will generate a fatal
30- * unrecoverable uncatchable error error whenever it cannot find a class. While
31- * calling this from nr_aws_sdk_php_enable would have been great and would allow
32- * the sdk version value to be set only once, to avoid the very unlikely but not
33- * impossible fatal error, this will be called from the
34- * "Aws\\ClientResolver::_apply_user_agent" wrapper which GUARANTEES that
35- * aws/sdk exists and is already loaded.
36- *
37- *
38- * Additionally given that aws-sdk-php is currently detected from the
39- * AwsClient.php file, this method will always be called when a client is
40- * created unlike Sdk::construct which doesn't show with PHP 8.2+.
41- *
42- * Using Aws/Sdk::__construct for version is currently nonviable as it is
43- * unreliable as a version determiner.
44- * Having separate functionality to extract from Aws/Sdk::__construct
45- * is both not required and is redundant and causes additional overhead and
46- * so only one function is needed to extract version.
47- *
48- * Aws\\ClientResolver::_apply_user_agent a reliable function as it is
49- * always called on client initialization since it is key to populating
50- * the request headers, and it loads Sdk by default.
51- *
52- * Concerns about future/past proofing to the checking prioritized the following
53- * implementation vs using the eval method.
29+ * settings, if the class is not found, PHP 8.2+ will generate an
30+ * error whenever it cannot find a class which must be caught. Calling this
31+ * from nr_aws_sdk_php_enable would allow the sdk version value to be set only
32+ * once. To avoid the VERY unlikely but not impossible fatal error, we need to
33+ * wrap the call in a try/catch block and make it a lambda so that we avoid
34+ * fatal errors.
5435 */
5536void nr_lib_aws_sdk_php_handle_version () {
56- zval * zval_version = NULL ;
57- zend_class_entry * class_entry = NULL ;
5837 char * version = NULL ;
59-
60- class_entry = nr_php_find_class ("aws\\sdk" );
61- if (NULL != class_entry ) {
62- zval_version = nr_php_get_class_constant (class_entry , "VERSION" );
63-
64- if (nr_php_is_zval_non_empty_string (zval_version )) {
65- version = Z_STRVAL_P (zval_version );
38+ zval retval ;
39+ int result = FAILURE ;
40+
41+ result = zend_eval_string (
42+ "(function() {"
43+ " $nr_aws_sdk_version = '';"
44+ " try {"
45+ " $nr_aws_sdk_version = Aws\\Sdk::VERSION;"
46+ " } catch (Throwable $e) {"
47+ " }"
48+ " return $nr_aws_sdk_version;"
49+ "})();" ,
50+ & retval , "Get nr_aws_sdk_version" );
51+
52+ /* See if we got a non-empty/non-null string for version. */
53+ if (SUCCESS == result ) {
54+ if (nr_php_is_zval_non_empty_string (& retval )) {
55+ version = Z_STRVAL (retval );
6656 }
6757 }
58+
6859 if (NRINI (vulnerability_management_package_detection_enabled )) {
6960 /* Add php package to transaction */
7061 nr_txn_add_php_package (NRPRG (txn ), PHP_PACKAGE_NAME , version );
@@ -73,7 +64,7 @@ void nr_lib_aws_sdk_php_handle_version() {
7364 nr_txn_suggest_package_supportability_metric (NRPRG (txn ), PHP_PACKAGE_NAME ,
7465 version );
7566
76- nr_php_zval_free ( & zval_version );
67+ zval_dtor ( & retval );
7768}
7869
7970void nr_lib_aws_sdk_php_add_supportability_service_metric (
@@ -96,13 +87,6 @@ void nr_lib_aws_sdk_php_add_supportability_service_metric(
9687 nrm_force_add (NRPRG (txn ) ? NRTXN (unscoped_metrics ) : 0 , buf , 0 );
9788}
9889
99- NR_PHP_WRAPPER (nr_create_aws_sdk_version_metrics ) {
100- (void )wraprec ;
101- NR_PHP_WRAPPER_CALL ;
102- nr_lib_aws_sdk_php_handle_version ();
103- }
104- NR_PHP_WRAPPER_END
105-
10690/*
10791 * AwsClient::parseClass
10892 * This is called from the base AwsClient class for every client associated
@@ -144,7 +128,7 @@ NR_PHP_WRAPPER_END
144128 * optimizable library. Small overhead incurred when encountering an autoload
145129 * file, but detects aws-sdk-php immediately before any sdk code executes
146130 * (changes needed for this are detailed in the original PR)
147- * 2. use a file that gets called later and only when AwsClient.php file file is
131+ * 2. use a file that gets called later and only when AwsClient.php file is
148132 * called. It's called later and we'll miss some instrumentation, but if we're
149133 * only ever going to be interested in Client calls anyway, maybe that's ok?
150134 * Doesn't detect Sdk.php (optimized out) so when customers only use that or
@@ -158,22 +142,24 @@ NR_PHP_WRAPPER_END
158142 * to wrap, this will add overhead to every hash map lookup. Currently
159143 * implemented option is 2, use the AwsClient.php as this is our main focus.
160144 * This means until a call to an Aws/AwsClient function,
161- * all calls including aws\sdk calls are ignored. Version detection will be
162- * tied to Aws/ClientResolver::_apply_user_agent which is ALWAYS called when
163- * dealing with aws clients. It will not be computed from
164- * Aws/Sdk::__constructor which would at best be duplicate info and worst would
165- * never be ignored until a client is called.
145+ * all calls including aws\sdk calls are ignored.
146+ *
147+ * Version detection will be called directly from Aws\Sdk.php
166148 */
167149void nr_aws_sdk_php_enable () {
168- /* This will be used to extract the version. */
169- nr_php_wrap_user_function (NR_PSTR ("Aws\\ClientResolver::_apply_user_agent" ),
170- nr_create_aws_sdk_version_metrics );
171- /* Called when initializing all other Clients */
172- nr_php_wrap_user_function (NR_PSTR ("Aws\\AwsClient::parseClass" ),
173- nr_create_aws_service_metric );
174-
150+ /*
151+ * Set the UNKNOWN package first, so it doesn't overwrite what we find with
152+ * nr_lib_aws_sdk_php_handle_version.
153+ */
175154 if (NRINI (vulnerability_management_package_detection_enabled )) {
176155 nr_txn_add_php_package (NRPRG (txn ), PHP_PACKAGE_NAME ,
177156 PHP_PACKAGE_VERSION_UNKNOWN );
178157 }
158+
159+ /* Extract the version for aws-sdk 3+ */
160+ nr_lib_aws_sdk_php_handle_version ();
161+
162+ /* Called when initializing all Clients */
163+ nr_php_wrap_user_function (NR_PSTR ("Aws\\AwsClient::parseClass" ),
164+ nr_create_aws_service_metric );
179165}
0 commit comments