25
25
#include "util_metrics.h"
26
26
#include "util_number_converter.h"
27
27
#include "util_strings.h"
28
+ #include "util_syscalls.h"
28
29
#include "util_url.h"
29
30
#include "util_url.h"
30
31
#include "util_metrics.h"
@@ -476,7 +477,6 @@ typedef struct _nr_library_table_t {
476
477
const char * library_name ;
477
478
const char * file_to_check ;
478
479
size_t file_to_check_len ;
479
- nr_composer_special_fn_t special ;
480
480
nr_library_enable_fn_t enable ;
481
481
} nr_library_table_t ;
482
482
@@ -486,97 +486,98 @@ typedef struct _nr_library_table_t {
486
486
// clang-format: off
487
487
static nr_library_table_t libraries [] = {
488
488
/* AWS-SDK-PHP 3 */
489
- {"AWS-SDK-PHP" , NR_PSTR ("aws-sdk-php/src/awsclient.php" ), 0 , nr_aws_sdk_php_enable },
489
+ {"AWS-SDK-PHP" , NR_PSTR ("aws-sdk-php/src/awsclient.php" ), nr_aws_sdk_php_enable },
490
490
491
491
/* Doctrine < 2.18 */
492
- {"Doctrine 2" , NR_PSTR ("doctrine/orm/query.php" ), 0 , nr_doctrine2_enable },
492
+ {"Doctrine 2" , NR_PSTR ("doctrine/orm/query.php" ), nr_doctrine2_enable },
493
493
/* Doctrine 2.18 reworked the directory structure */
494
- {"Doctrine 2" , NR_PSTR ("doctrine/orm/src/query.php" ), 0 , nr_doctrine2_enable },
494
+ {"Doctrine 2" , NR_PSTR ("doctrine/orm/src/query.php" ), nr_doctrine2_enable },
495
495
496
- {"Guzzle 3" , NR_PSTR ("guzzle/http/client.php" ), 0 , nr_guzzle3_enable },
497
- {"Guzzle 4-5" , NR_PSTR ("hasemitterinterface.php" ), 0 , nr_guzzle4_enable },
498
- {"Guzzle 6" , NR_PSTR ("guzzle/src/functions_include.php" ), 0 , nr_guzzle6_enable },
496
+ {"Guzzle 3" , NR_PSTR ("guzzle/http/client.php" ), nr_guzzle3_enable },
497
+ {"Guzzle 4-5" , NR_PSTR ("hasemitterinterface.php" ), nr_guzzle4_enable },
498
+ {"Guzzle 6" , NR_PSTR ("guzzle/src/functions_include.php" ), nr_guzzle6_enable },
499
499
500
- {"MongoDB" , NR_PSTR ("mongodb/src/client.php" ), 0 , nr_mongodb_enable },
500
+ {"MongoDB" , NR_PSTR ("mongodb/src/client.php" ), nr_mongodb_enable },
501
501
502
502
/*
503
503
* The first path is for Composer installs, the second is for
504
504
* /usr/local/bin.
505
505
*/
506
- {"PHPUnit" , NR_PSTR ("phpunit/src/framework/test.php" ), 0 , nr_phpunit_enable },
507
- {"PHPUnit" , NR_PSTR ("phpunit/framework/test.php" ), 0 , nr_phpunit_enable },
506
+ {"PHPUnit" , NR_PSTR ("phpunit/src/framework/test.php" ), nr_phpunit_enable },
507
+ {"PHPUnit" , NR_PSTR ("phpunit/framework/test.php" ), nr_phpunit_enable },
508
508
509
- {"Predis" , NR_PSTR ("predis/src/client.php" ), 0 , nr_predis_enable },
510
- {"Predis" , NR_PSTR ("predis/client.php" ), 0 , nr_predis_enable },
509
+ {"Predis" , NR_PSTR ("predis/src/client.php" ), nr_predis_enable },
510
+ {"Predis" , NR_PSTR ("predis/client.php" ), nr_predis_enable },
511
+ {"PHP_Package" , NR_PSTR ("vendor/autoload.php" ), nr_composer_detected },
511
512
512
513
/*
513
514
* Allow Zend Framework 1.x to be detected as a library as well as a
514
515
* framework. This allows Zend_Http_Client to be instrumented when used
515
516
* with other frameworks or even without a framework at all. This is
516
517
* necessary for Magento in particular, which is built on ZF1.
517
518
*/
518
- {"Zend_Http" , NR_PSTR ("zend/http/client.php" ), 0 , nr_zend_http_enable },
519
+ {"Zend_Http" , NR_PSTR ("zend/http/client.php" ), nr_zend_http_enable },
519
520
520
521
/*
521
522
* Allow Laminas Framework 3.x to be detected as a library as well as a
522
523
* framework. This allows Laminas_Http_Client to be instrumented when used
523
524
* with other frameworks or even without a framework at all.
524
525
*/
525
- {"Laminas_Http" , NR_PSTR ("laminas-http/src/client.php" ), 0 , nr_laminas_http_enable },
526
+ {"Laminas_Http" , NR_PSTR ("laminas-http/src/client.php" ), nr_laminas_http_enable },
526
527
527
528
/*
528
529
* Other frameworks, detected only, but not specifically
529
530
* instrumented. We detect these as libraries so that we don't prevent
530
531
* detection of a supported framework or library later (since a transaction
531
532
* can only have one framework).
532
533
*/
533
- {"Aura1" , NR_PSTR ("aura/framework/system.php" ), 0 , NULL },
534
- {"Aura2" , NR_PSTR ("aura/di/src/containerinterface.php" ), 0 , NULL },
535
- {"Aura3" , NR_PSTR ("aura/di/src/containerconfiginterface.php" ), 0 , NULL },
536
- {"CakePHP3" , NR_PSTR ("cakephp/src/core/functions.php" ), 0 , NULL },
537
- {"Fuel" , NR_PSTR ("fuel/core/classes/fuel.php" ), 0 , NULL },
538
- {"Lithium" , NR_PSTR ("lithium/core/libraries.php" ), 0 , NULL },
539
- {"Phpbb" , NR_PSTR ("phpbb/request/request.php" ), 0 , NULL },
540
- {"Phpixie2" , NR_PSTR ("phpixie/core/classes/phpixie/pixie.php" ), 0 , NULL },
541
- {"Phpixie3" , NR_PSTR ("phpixie/framework.php" ), 0 , NULL },
542
- {"React" , NR_PSTR ("react/event-loop/src/loopinterface.php" ), 0 , NULL },
543
- {"SilverStripe" , NR_PSTR ("injector/silverstripeinjectioncreator.php" ), 0 , NULL },
544
- {"SilverStripe4" , NR_PSTR ("silverstripeserviceconfigurationlocator.php" ), 0 , NULL },
545
- {"Typo3" , NR_PSTR ("classes/typo3/flow/core/bootstrap.php" ), 0 , NULL },
546
- {"Typo3" , NR_PSTR ("typo3/sysext/core/classes/core/bootstrap.php" ), 0 , NULL },
534
+ {"Aura1" , NR_PSTR ("aura/framework/system.php" ), NULL },
535
+ {"Aura2" , NR_PSTR ("aura/di/src/containerinterface.php" ), NULL },
536
+ {"Aura3" , NR_PSTR ("aura/di/src/containerconfiginterface.php" ), NULL },
537
+ {"CakePHP3" , NR_PSTR ("cakephp/src/core/functions.php" ), NULL },
538
+ {"Fuel" , NR_PSTR ("fuel/core/classes/fuel.php" ), NULL },
539
+ {"Lithium" , NR_PSTR ("lithium/core/libraries.php" ), NULL },
540
+ {"Phpbb" , NR_PSTR ("phpbb/request/request.php" ), NULL },
541
+ {"Phpixie2" , NR_PSTR ("phpixie/core/classes/phpixie/pixie.php" ), NULL },
542
+ {"Phpixie3" , NR_PSTR ("phpixie/framework.php" ), NULL },
543
+ {"React" , NR_PSTR ("react/event-loop/src/loopinterface.php" ), NULL },
544
+ {"SilverStripe" , NR_PSTR ("injector/silverstripeinjectioncreator.php" ), NULL },
545
+ {"SilverStripe4" , NR_PSTR ("silverstripeserviceconfigurationlocator.php" ), NULL },
546
+ {"Typo3" , NR_PSTR ("classes/typo3/flow/core/bootstrap.php" ), NULL },
547
+ {"Typo3" , NR_PSTR ("typo3/sysext/core/classes/core/bootstrap.php" ), NULL },
547
548
548
549
/*
549
550
* Other CMS (content management systems), detected only, but
550
551
* not specifically instrumented.
551
552
*/
552
- {"Moodle" , NR_PSTR ("moodlelib.php" ), 0 , NULL },
553
+ {"Moodle" , NR_PSTR ("moodlelib.php" ), NULL },
553
554
/*
554
555
* It is likely that this will never be found, since the CodeIgniter.php
555
556
* will get loaded first, and as such mark this transaction as belonging to
556
557
* CodeIgniter, and not Expession Engine.
557
558
*/
558
- {"ExpressionEngine" , NR_PSTR ("system/expressionengine/config/config.php" ), 0 , NULL },
559
+ {"ExpressionEngine" , NR_PSTR ("system/expressionengine/config/config.php" ), NULL },
559
560
/*
560
561
* ExpressionEngine 5, however, has a very obvious file we can look for.
561
562
*/
562
- {"ExpressionEngine5" , NR_PSTR ("expressionengine/boot/boot.php" ), 0 , NULL },
563
+ {"ExpressionEngine5" , NR_PSTR ("expressionengine/boot/boot.php" ), NULL },
563
564
/*
564
565
* DokuWiki uses doku.php as an entry point, but has other files that are
565
566
* loaded directly that this won't pick up. That's probably OK for
566
567
* supportability metrics, but we'll add the most common name for the
567
568
* configuration file as well just in case.
568
569
*/
569
- {"DokuWiki" , NR_PSTR ("doku.php" ), 0 , NULL },
570
- {"DokuWiki" , NR_PSTR ("conf/dokuwiki.php" ), 0 , NULL },
570
+ {"DokuWiki" , NR_PSTR ("doku.php" ), NULL },
571
+ {"DokuWiki" , NR_PSTR ("conf/dokuwiki.php" ), NULL },
571
572
572
573
/*
573
574
* SugarCRM no longer has a community edition, so this likely only works
574
575
* with older versions.
575
576
*/
576
- {"SugarCRM" , NR_PSTR ("sugarobjects/sugarconfig.php" ), 0 , NULL },
577
+ {"SugarCRM" , NR_PSTR ("sugarobjects/sugarconfig.php" ), NULL },
577
578
578
- {"Xoops" , NR_PSTR ("class/xoopsload.php" ), 0 , NULL },
579
- {"E107" , NR_PSTR ("e107_handlers/e107_class.php" ), 0 , NULL },
579
+ {"Xoops" , NR_PSTR ("class/xoopsload.php" ), NULL },
580
+ {"E107" , NR_PSTR ("e107_handlers/e107_class.php" ), NULL },
580
581
};
581
582
// clang-format: on
582
583
@@ -585,15 +586,15 @@ static size_t num_libraries = sizeof(libraries) / sizeof(nr_library_table_t);
585
586
// clang-format: off
586
587
static nr_library_table_t logging_frameworks [] = {
587
588
/* Monolog - Logging for PHP */
588
- {"Monolog" , NR_PSTR ("monolog/logger.php" ), 0 , nr_monolog_enable },
589
+ {"Monolog" , NR_PSTR ("monolog/logger.php" ), nr_monolog_enable },
589
590
/* Consolidation/Log - Logging for PHP */
590
- {"Consolidation/Log" , NR_PSTR ("consolidation/log/src/logger.php" ), 0 , NULL },
591
+ {"Consolidation/Log" , NR_PSTR ("consolidation/log/src/logger.php" ), NULL },
591
592
/* laminas-log - Logging for PHP */
592
- {"laminas-log" , NR_PSTR ("laminas-log/src/logger.php" ), 0 , NULL },
593
+ {"laminas-log" , NR_PSTR ("laminas-log/src/logger.php" ), NULL },
593
594
/* cakephp-log - Logging for PHP */
594
- {"cakephp-log" , NR_PSTR ("cakephp/log/log.php" ), 0 , NULL },
595
+ {"cakephp-log" , NR_PSTR ("cakephp/log/log.php" ), NULL },
595
596
/* Analog - Logging for PHP */
596
- {"Analog" , NR_PSTR ("analog/analog.php" ), 0 , NULL },
597
+ {"Analog" , NR_PSTR ("analog/analog.php" ), NULL },
597
598
};
598
599
// clang-format: on
599
600
@@ -932,24 +933,137 @@ static void nr_execute_handle_library(const char* filename,
932
933
}
933
934
}
934
935
935
- static void nr_execute_handle_composer (const char * filename ,
936
- const size_t filename_len TSRMLS_DC ) {
937
- size_t i ;
936
+ void nr_composer_detected () {
937
+ if (NULL != NRPRG (txn ) && !NRPRG (txn )-> detection_status .composer_detected ) {
938
+ const char * magic_file_1
939
+ = "vendor/composer/autoload_real.php" ;
940
+ const char * composer_file = "vendor/composer/installed.php" ;
941
+ // the below should be using the absolute path
942
+ if (0 == nr_access (magic_file_1 , F_OK | R_OK )) {
943
+ if (0 == nr_access (composer_file , F_OK | R_OK )) {
944
+ NRPRG (txn )-> detection_status .composer_detected = 1 ;
945
+ NRPRG (txn )-> detection_status .file_exists = 1 ;
946
+ NRPRG (txn )-> detection_status .api_called = 0 ;
947
+ NRPRG (txn )-> detection_status .inside_eval_string = 0 ;
948
+ }
949
+ }
950
+ }
951
+ }
938
952
939
- for (i = 0 ; i < num_libraries ; i ++ ) {
940
- if (nr_striendswith (STR_AND_LEN (filename ),
941
- STR_AND_LEN (libraries [i ].file_to_check ))) {
942
- if (libraries [i ].special ) {
943
- nr_composer_classification_t special
944
- = libraries [i ].special (filename TSRMLS_CC );
945
- if (FILE_EXISTS == special ) {
946
- nr_fw_support_add_library_supportability_metric (
947
- NRPRG (txn ), libraries [i ].library_name );
948
- if (NULL != libraries [i ].enable ) {
949
- libraries [i ].enable (TSRMLS_C );
953
+ static void nr_get_composer_package_information () {
954
+ zval retval ;
955
+ int result = -1 ;
956
+
957
+ if (NRPRG (txn )-> detection_status .inside_eval_string ) {
958
+ return ;
959
+ }
960
+
961
+ char * check
962
+ = ""
963
+ "(function() {"
964
+ " try {"
965
+ " if (class_exists('Composer\\InstalledVersions')) {"
966
+ " if (method_exists('Composer\\InstalledVersions', "
967
+ " 'getInstalledPackages') && method_exists('Composer\\InstalledVersions', "
968
+ " 'getVersion')) {"
969
+ " return true;"
970
+ " } else {"
971
+ " return false;"
972
+ " }"
973
+ " } else {"
974
+ " return false;"
975
+ " }"
976
+ " } catch (Exception $e) {"
977
+ " return NULL;"
978
+ " }"
979
+ "})();" ;
980
+
981
+ char * getpackagename =
982
+ ""
983
+ "(function() {"
984
+ " try {"
985
+ " return Composer\\InstalledVersions::getInstalledPackages();"
986
+ " } catch (Exception $e) {"
987
+ " return NULL;"
988
+ " }"
989
+ "})();" ;
990
+
991
+ char * getversion =
992
+ ""
993
+ "(function() {"
994
+ " try {"
995
+ " return Composer\\InstalledVersions::getVersion(\"%s\");"
996
+ " } catch (Exception $e) {"
997
+ " return NULL;"
998
+ " }"
999
+ "})();" ;
1000
+
1001
+ NRPRG (txn )-> detection_status .inside_eval_string = 1 ;
1002
+ result = zend_eval_string (check , & retval , "check if class and methods exist" TSRMLS_CC );
1003
+ NRPRG (txn )-> detection_status .inside_eval_string = 0 ;
1004
+
1005
+ if (result == SUCCESS ) {
1006
+ if (Z_TYPE (retval ) == IS_NULL ) {
1007
+ if (NULL != NRPRG (txn )) {
1008
+ NRPRG (txn )-> detection_status .api_called = 1 ;
1009
+ }
1010
+ nrl_verbosedebug (NRL_TXN , "IS_NULL" );
1011
+ return ;
1012
+ } else if (Z_TYPE (retval ) == IS_FALSE ) {
1013
+ nrl_verbosedebug (NRL_TXN , "IS_FALSE" );
1014
+ return ;
1015
+ } else if (Z_TYPE (retval ) != IS_TRUE ) {
1016
+ nrl_verbosedebug (NRL_TXN , "NOT_TRUE" );
1017
+ return ;
1018
+ }
1019
+ }
1020
+ zval_dtor (& retval );
1021
+ NRPRG (txn )-> detection_status .inside_eval_string = 1 ;
1022
+ result = zend_eval_string (getpackagename , & retval ,
1023
+ "get installed packages by name" TSRMLS_CC );
1024
+ NRPRG (txn )-> detection_status .inside_eval_string = 0 ;
1025
+ if (result == SUCCESS ) {
1026
+ if (Z_TYPE (retval ) == IS_ARRAY ) {
1027
+ zval * value ;
1028
+ char * buf ;
1029
+ int result2 ;
1030
+ zval retval2 ;
1031
+ char * version = NULL ;
1032
+ (void )version ;
1033
+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL (retval ), value ) {
1034
+ if (Z_TYPE_P (value ) == IS_STRING ) {
1035
+ buf = nr_formatf (getversion , Z_STRVAL_P (value ));
1036
+ NRPRG (txn )-> detection_status .inside_eval_string = 1 ;
1037
+ result2 = zend_eval_string (buf , & retval2 , "retrieve version for packages" );
1038
+ NRPRG (txn )-> detection_status .inside_eval_string = 0 ;
1039
+ nr_free (buf );
1040
+ if (SUCCESS == result2 ) {
1041
+ if (nr_php_is_zval_valid_string (& retval2 )) {
1042
+ version = Z_STRVAL (retval2 );
1043
+ }
950
1044
}
951
1045
}
1046
+ zval_dtor (& retval2 );
1047
+ nrl_verbosedebug (NRL_TXN , "package %s, version %s" ,
1048
+ NRSAFESTR (Z_STRVAL_P (value )), NRSAFESTR (version ));
952
1049
}
1050
+ ZEND_HASH_FOREACH_END ();
1051
+ } else {
1052
+ if (NULL != NRPRG (txn )) {
1053
+ NRPRG (txn )-> detection_status .api_called = 1 ;
1054
+ }
1055
+ zval_dtor (& retval );
1056
+ return ;
1057
+ }
1058
+ zval_dtor (& retval );
1059
+ NRPRG (txn )-> detection_status .api_called = 1 ;
1060
+ }
1061
+ }
1062
+
1063
+ static void nr_execute_handle_composer () {
1064
+ if (NRPRG (txn )-> detection_status .file_exists ) {
1065
+ if (!NRPRG (txn )-> detection_status .api_called ) {
1066
+ nr_get_composer_package_information ();
953
1067
}
954
1068
}
955
1069
}
@@ -1060,6 +1174,10 @@ static void nr_php_execute_file(const zend_op_array* op_array,
1060
1174
}
1061
1175
1062
1176
nr_php_add_user_instrumentation (TSRMLS_C );
1177
+
1178
+ if (NRPRG (txn )-> detection_status .composer_detected && !NRPRG (txn )-> detection_status .api_called ) {
1179
+ nr_execute_handle_composer (filename , filename_len );
1180
+ }
1063
1181
}
1064
1182
1065
1183
/*
0 commit comments