* Copyright (C) 2024 Frédéric France */ define('DOL_PROJECT_ROOT', __DIR__.'/../../..'); define('DOL_DOCUMENT_ROOT', DOL_PROJECT_ROOT.'/htdocs'); define('PHAN_DIR', __DIR__); $sanitizeRegex = '/^(array:)?(?:'.implode( '|', array( // Documented: 'none', 'password', 'array', 'int', 'intcomma', 'alpha', 'alphawithlgt', 'alphanohtml', 'MS', 'aZ', 'aZ09', 'aZ09arobase', 'aZ09comma', 'email', 'san_alpha', 'restricthtml', 'nohtml', 'custom', // Not documented: 'restricthtmlallowclass', 'restricthtmlallowunvalid', 'restricthtmlnolink', 'restricthtmlallowlinkscript' ) ).')*$/'; /** * Map deprecated module names to new module names */ $DEPRECATED_MODULE_MAPPING = array( 'actioncomm' => 'agenda', 'adherent' => 'member', 'adherent_type' => 'member_type', 'banque' => 'bank', 'categorie' => 'category', 'commande' => 'order', 'contrat' => 'contract', 'entrepot' => 'stock', 'expedition' => 'shipping', 'facture' => 'invoice', 'ficheinter' => 'intervention', 'product_fournisseur_price' => 'productsupplierprice', 'product_price' => 'productprice', 'projet' => 'project', 'propale' => 'propal', 'socpeople' => 'contact', ); /** * Map module names to the 'class' name (the class is: mod) * Value is null when the module is not internal to the default * Dolibarr setup. */ $VALID_MODULE_MAPPING = array( 'accounting' => 'Accounting', 'agenda' => 'Agenda', 'ai' => 'Ai', 'anothermodule' => null, 'api' => 'Api', 'asset' => 'Asset', 'bank' => 'Banque', 'barcode' => 'Barcode', 'blockedlog' => 'BlockedLog', 'bom' => 'Bom', 'bookcal' => 'BookCal', 'bookmark' => 'Bookmark', 'cashdesk' => null, // TODO: fill in proper class 'category' => 'Categorie', 'clicktodial' => 'ClickToDial', 'collab' => 'Collab', 'comptabilite' => 'Comptabilite', 'contact' => null, // TODO: fill in proper class 'contract' => 'Contrat', 'cron' => 'Cron', 'datapolicy' => 'DataPolicy', 'dav' => 'Dav', 'debugbar' => 'DebugBar', 'shipping' => 'Expedition', 'deplacement' => 'Deplacement', "documentgeneration" => 'DocumentGeneration', 'don' => 'Don', 'dynamicprices' => 'DynamicPrices', 'ecm' => 'ECM', 'ecotax' => null, // TODO: External module ? 'emailcollector' => 'EmailCollector', 'eventorganization' => 'EventOrganization', 'expensereport' => 'ExpenseReport', 'export' => 'Export', 'externalrss' => 'ExternalRss', 'externalsite' => 'ExternalSite', 'fckeditor' => 'Fckeditor', 'fournisseur' => 'Fournisseur', 'ftp' => 'FTP', 'geoipmaxmind' => 'GeoIPMaxmind', 'google' => null, // External ? 'gravatar' => 'Gravatar', 'holiday' => 'Holiday', 'hrm' => 'HRM', 'import' => 'Import', 'incoterm' => 'Incoterm', 'intervention' => 'Ficheinter', 'intracommreport' => 'Intracommreport', 'invoice' => 'Facture', 'knowledgemanagement' => 'KnowledgeManagement', 'label' => 'Label', 'ldap' => 'Ldap', 'loan' => 'Loan', 'mailing' => 'Mailing', 'mailman' => null, // Same module as mailmanspip -> MailmanSpip ?? 'mailmanspip' => 'MailmanSpip', 'margin' => 'Margin', 'member' => 'Adherent', 'memcached' => null, // TODO: External module? 'modulebuilder' => 'ModuleBuilder', 'mrp' => 'Mrp', 'multicompany' => null, // Not provided by default, no module tests 'multicurrency' => 'MultiCurrency', 'mymodule' => null, // modMyModule - Name used in module builder (avoid false positives) 'notification' => 'Notification', 'numberwords' => null, // Not provided by default, no module tests 'oauth' => 'OAuth', 'openstreetmap' => null, // External module? 'opensurvey' => 'OpenSurvey', 'order' => 'Commande', 'partnership' => 'Partnership', 'paybox' => 'Paybox', 'paymentbybanktransfer' => 'PaymentByBankTransfer', 'paypal' => 'Paypal', 'paypalplus' => null, 'prelevement' => 'Prelevement', 'printing' => 'Printing', 'product' => 'Product', 'productbatch' => 'ProductBatch', 'productprice' => null, 'productsupplierprice' => null, 'project' => 'Projet', 'propal' => 'Propale', 'receiptprinter' => 'ReceiptPrinter', 'reception' => 'Reception', 'recruitment' => 'Recruitment', 'resource' => 'Resource', 'salaries' => 'Salaries', 'service' => 'Service', 'socialnetworks' => 'SocialNetworks', 'societe' => 'Societe', 'stock' => 'Stock', 'stocktransfer' => 'StockTransfer', 'stripe' => 'Stripe', 'supplier_invoice' => null, // Special case, uses invoice 'supplier_order' => null, // Special case, uses invoice 'supplier_proposal' => 'SupplierProposal', 'syslog' => 'Syslog', 'takepos' => 'TakePos', 'tax' => 'Tax', 'theme_datacolor' => 'array{0:array{0:int,1:int,2:int},1:array{0:int,1:int,2:int},2:array{0:int,1:int,2:int},3:array{0:int,1:int,2:int}}', 'ticket' => 'Ticket', 'user' => 'User', 'variants' => 'Variants', 'webhook' => 'Webhook', 'webportal' => 'WebPortal', 'webservices' => 'WebServices', 'webservicesclient' => 'WebServicesClient', 'website' => 'Website', 'workflow' => 'Workflow', 'workstation' => 'Workstation', 'zapier' => 'Zapier', ); // From ExtraFields class $EXTRAFIELDS_TYPE2LABEL = array( 'varchar' => 'String1Line', 'text' => 'TextLongNLines', 'html' => 'HtmlText', 'int' => 'Int', 'double' => 'Float', 'date' => 'Date', 'datetime' => 'DateAndTime', //'datetimegmt'=>'DateAndTimeUTC', 'boolean' => 'Boolean', // Remove as test 'price' => 'ExtrafieldPrice', 'pricecy' => 'ExtrafieldPriceWithCurrency', 'phone' => 'ExtrafieldPhone', 'mail' => 'ExtrafieldMail', 'url' => 'ExtrafieldUrl', 'ip' => 'ExtrafieldIP', 'icon' => 'Icon', 'password' => 'ExtrafieldPassword', 'select' => 'ExtrafieldSelect', 'sellist' => 'ExtrafieldSelectList', 'radio' => 'ExtrafieldRadio', 'checkbox' => 'ExtrafieldCheckBox', 'chkbxlst' => 'ExtrafieldCheckBoxFromList', 'link' => 'ExtrafieldLink', 'separate' => 'ExtrafieldSeparator', ); $moduleNameRegex = '/^(?:'.implode('|', array_merge(array_keys($DEPRECATED_MODULE_MAPPING), array_keys($VALID_MODULE_MAPPING), array('\$modulename'))).')$/'; $deprecatedModuleNameRegex = '/^(?!(?:'.implode('|', array_keys($DEPRECATED_MODULE_MAPPING)).')$).*/'; $extraFieldTypeRegex = '/^(?:'.implode('|', array_keys($EXTRAFIELDS_TYPE2LABEL)).')$/'; /** * This configuration will be read and overlaid on top of the * default configuration. Command line arguments will be applied * after this file is read. */ return [ // 'processes' => 6, 'backward_compatibility_checks' => false, 'simplify_ast' => true, 'analyzed_file_extensions' => ['php','inc'], 'globals_type_map' => [ 'action' => 'string', 'actioncode' => 'string', 'badgeStatus0' => 'string', 'badgeStatus1' => 'string', 'badgeStatus11' => 'string', 'badgeStatus3' => 'string', 'badgeStatus4' => 'string', 'badgeStatus6' => 'string', 'badgeStatus8' => 'string', 'badgeStatus9' => 'string', 'classname' => 'string', 'conf' => '\Conf', 'conffile' => 'string', 'conffiletoshow' => 'string', 'conffiletoshowshort' => 'string', 'dateSelector' => 'int<0,1>', 'db' => '\DoliDB', 'disableedit' => 'int<0,1>', 'disablemove' => 'int<0,1>', 'disableremove' => 'int<0,1>', 'dolibarr_main_authentication' => 'string', 'dolibarr_main_data_root' => 'string', 'dolibarr_main_data_root' => 'string', 'dolibarr_main_db_encrypted_pass' => 'string', 'dolibarr_main_db_host' => 'string', 'dolibarr_main_db_pass' => 'string', 'dolibarr_main_demo' => 'string', 'dolibarr_main_document_root' => 'string', 'dolibarr_main_url_root' => 'string', 'errormsg' => 'string', 'extrafields' => '\ExtraFields', 'filter' => 'string', 'filtert' => 'int', 'forceall' => 'int<0,1>', 'form' => '\Form', 'formcompany' => '\FormCompany', 'hookmanager' => '\HookManager', 'inputalsopricewithtax' => 'int<0,1>', 'langs' => '\Translate', 'leftmenu' => 'string', 'linkedObjectBlock' => '\CommonObject[]', // See htdocs/core/class/html.form.class.php 'mainmenu' => 'string', 'menumanager' => '\MenuManager', 'mysoc' => '\Societe', 'nblines' => '\int', 'objectoffield' => '\CommonObject', 'objsoc' => '\Societe', 'senderissupplier' => 'int<0,2>', 'user' => '\User', 'website' => 'string', // See discussion https://github.com/Dolibarr/dolibarr/pull/28891#issuecomment-2002268334 // Disable because Phan infers Website type 'websitepage' => '\WebSitePage', 'websitepagefile' => 'string', // 'object' => '\CommonObject', // Deprecated, not enabled because conflicts with $object assignments ], // Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`, `null`. // If this is set to `null`, // then Phan assumes the PHP version which is closest to the minor version // of the php executable used to execute Phan. //"target_php_version" => null, "target_php_version" => '8.2', //"target_php_version" => '7.3', //"target_php_version" => '5.6', // A list of directories that should be parsed for class and // method information. After excluding the directories // defined in exclude_analysis_directory_list, the remaining // files will be statically analyzed for errors. // // Thus, both first-party and third-party code being used by // your application should be included in this list. 'directory_list' => [ 'htdocs', PHAN_DIR . '/stubs/', ], // A directory list that defines files that will be excluded // from static analysis, but whose class and method // information should be included. // // Generally, you'll want to include the directories for // third-party code (such as "vendor/") in this list. // // n.b.: If you'd like to parse but not analyze 3rd // party code, directories containing that code // should be added to the `directory_list` as // to `exclude_analysis_directory_list`. "exclude_analysis_directory_list" => [ 'htdocs/includes/', 'htdocs/install/doctemplates/websites/', 'htdocs/core/class/lessc.class.php', // External library PHAN_DIR . '/stubs/', ], //'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', 'exclude_file_regex' => '@^(' // @phpstan-ignore-line .'dummy' // @phpstan-ignore-line // mymodule seen in cti, but not in git. .'|htdocs/custom/mymodule/.*' // @phpstan-ignore-line .'|htdocs/.*/canvas/.*/tpl/.*.tpl.php' // @phpstan-ignore-line //.'|htdocs/modulebuilder/template/.*' // @phpstan-ignore-line // Included as stub (better analysis) .'|htdocs/includes/nusoap/.*' // @phpstan-ignore-line // Included as stub (old version + incompatible typing hints) .'|htdocs/includes/restler/.*' // @phpstan-ignore-line // Included as stub (did not seem properly analyzed by phan without it) .'|htdocs/includes/stripe/.*' // @phpstan-ignore-line .'|htdocs/conf/conf.php' // @phpstan-ignore-line // .'|htdocs/[^h].*/.*' // For testing @phpstan-ignore-line .')@', // @phpstan-ignore-line // A list of plugin files to execute. // Plugins which are bundled with Phan can be added here by providing their name // (e.g. 'AlwaysReturnPlugin') // // Documentation about available bundled plugins can be found // at https://github.com/phan/phan/tree/master/.phan/plugins // // Alternately, you can pass in the full path to a PHP file // with the plugin's implementation (e.g. 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php') 'ParamMatchRegexPlugin' => [ '/^GETPOST$/' => [1, $sanitizeRegex, 'GetPostUnknownSanitizeType'], '/^isModEnabled$/' => [0, $moduleNameRegex, 'UnknownModuleName'], // Note: trick to have different key for same regex: '/^isModEnable[d]$/' => [0, $deprecatedModuleNameRegex, "DeprecatedModuleName"], '/^sanitizeVal$/' => [1, $sanitizeRegex,"UnknownSanitizeType"], '/^checkVal$/' => [1, $sanitizeRegex,"UnknownCheckValSanitizeType"], '/^\\\\ExtraFields::addExtraField$/' => [2, $extraFieldTypeRegex,"UnknownExtrafieldTypeBack"], '/^dol_now$/' => [0, '{^(?:auto|gmt|tz(?:server|ref|user(?:rel)?))$}',"InvalidDolNowArgument"], '/^dol_mktime$/' => [6, '{^(?:|0|1|auto|gmt|tz(?:server|ref|user(?:rel)?|,[+a-zA-Z-/]+))$}',"InvalidDolMktimeArgument"], // '', 0, 1 match bool and int values '/^dol_print_date$/' => [2, '{^(?:|0|1|auto|gmt|tz(?:server|user(?:rel)?))$}',"InvalidDolMktimeArgument"], // '', 0, 1 match bool and int values '/^GETPOSTFLOAT$/' => [1, '{^(?:|M[UTS]|C[UT]|\d+)$}',"InvalidGetPostFloatRounding"], '/^price2num$/' => [1, '{^(?:|M[UTS]|C[UT]|\d+)$}',"InvalidPrice2NumRounding"], ], 'plugins' => [ __DIR__.'/plugins/NoVarDumpPlugin.php', __DIR__.'/plugins/ParamMatchRegexPlugin.php', // checks if a function, closure or method unconditionally returns. // can also be written as 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php' 'DeprecateAliasPlugin', //'EmptyMethodAndFunctionPlugin', // 'InvalidVariableIssetPlugin', //'MoreSpecificElementTypePlugin', 'NoAssertPlugin', 'NotFullyQualifiedUsagePlugin', //'PHPDocRedundantPlugin', 'PHPUnitNotDeadCodePlugin', //'PossiblyStaticMethodPlugin', 'PreferNamespaceUsePlugin', 'PrintfCheckerPlugin', 'RedundantAssignmentPlugin', 'ConstantVariablePlugin', // Warns about values that are actually constant //'HasPHPDocPlugin', // Requires PHPDoc // 'InlineHTMLPlugin', // html in PHP file, or at end of file //'NonBoolBranchPlugin', // Requires test on bool, nont on ints //'NonBoolInLogicalArithPlugin', 'NumericalComparisonPlugin', //'PHPDocToRealTypesPlugin', 'PHPDocInWrongCommentPlugin', // Missing /** (/* was used) //'ShortArrayPlugin', // Checks that [] is used //'StrictLiteralComparisonPlugin', 'UnknownClassElementAccessPlugin', 'UnknownElementTypePlugin', 'WhitespacePlugin', //'RemoveDebugStatementPlugin', // Reports echo, print, ... 'SimplifyExpressionPlugin', //'StrictComparisonPlugin', // Expects === 'SuspiciousParamOrderPlugin', 'UnsafeCodePlugin', //'UnusedSuppressionPlugin', 'AlwaysReturnPlugin', //'DollarDollarPlugin', 'DuplicateArrayKeyPlugin', 'DuplicateExpressionPlugin', 'PregRegexCheckerPlugin', 'PrintfCheckerPlugin', 'SleepCheckerPlugin', // Checks for syntactically unreachable statements in // the global scope or function bodies. 'UnreachableCodePlugin', 'UseReturnValuePlugin', 'EmptyStatementListPlugin', 'LoopVariableReusePlugin', ], // Add any issue types (such as 'PhanUndeclaredMethod') // here to inhibit them from being reported 'suppress_issue_types' => [ // Dolibarr uses a lot of internal deprecated stuff, not reporting 'PhanDeprecatedProperty', 'PhanCompatibleNegativeStringOffset', // return false positive 'PhanPluginConstantVariableBool', // a lot of false positive, in most cases, we want to keep the code as it is // 'PhanPluginUnknownArrayPropertyType', // this option costs more time to be supported than it solves time 'PhanTypeArraySuspiciousNullable', // this option costs more time to be supported than it solves time 'PhanTypeInvalidDimOffset', // this option costs more time to be supported than it solves time 'PhanTypeObjectUnsetDeclaredProperty', 'PhanTypePossiblyInvalidDimOffset', // a lot of false positive, in most cases, we want to keep the code as it is // 'PhanPluginUnknownArrayFunctionReturnType', // a lot of false positive, in most cases, we want to keep the code as it is 'PhanPluginWhitespaceTab', // Dolibarr used tabs 'PhanPluginCanUsePHP71Void', // Dolibarr is maintaining 7.0 compatibility 'PhanPluginShortArray', // Dolibarr uses array() 'PhanPluginShortArrayList', // Dolibarr uses array() // Fixers From PHPDocToRealTypesPlugin: 'PhanPluginCanUseParamType', // Fixer - Report/Add types in the function definition (function abc(string $var) (adds string) 'PhanPluginCanUseReturnType', // Fixer - Report/Add return types in the function definition (function abc(string $var) (adds string) 'PhanPluginCanUseNullableParamType', // Fixer - Report/Add nullable parameter types in the function definition 'PhanPluginCanUseNullableReturnType', // Fixer - Report/Add nullable return types in the function definition 'PhanPluginNonBoolBranch', // Not essential - 31240+ occurrences 'PhanPluginNumericalComparison', // Not essential - 19870+ occurrences 'PhanTypeMismatchArgument', // Not essential - 12300+ occurrences 'PhanPluginNonBoolInLogicalArith', // Not essential - 11040+ occurrences 'PhanPluginConstantVariableScalar', // Not essential - 5180+ occurrences 'PhanPluginDuplicateAdjacentStatement', 'PhanPluginDuplicateConditionalTernaryDuplication', // 2750+ occurrences 'PhanPluginDuplicateConditionalNullCoalescing', // Not essential - 990+ occurrences 'PhanPluginRedundantAssignmentInGlobalScope', // Not essential, a lot of false warning 'PhanPluginRedundantAssignment', // Not essential, useless 'PhanPluginDuplicateCatchStatementBody', // Requires PHP7.1 - 50+ occurrences // 'PhanPluginUnknownArrayMethodParamType', // Too many troubles to manage. Is enabled in config_extended only. // 'PhanPluginUnknownArrayMethodReturnType', // Too many troubles to manage. Is enabled in config_extended only. 'PhanUndeclaredGlobalVariable', // Too many false positives on .tpl.php files. Is enabled into config_extended only. // 'PhanPluginUnknownObjectMethodCall', // False positive for some class. Is enabled in config_extended only. ], // You can put relative paths to internal stubs in this config option. // Phan will continue using its detailed type annotations, // but load the constants, classes, functions, and classes (and their Reflection types) // from these stub files (doubling as valid php files). // Use a different extension from php (and preferably a separate folder) // to avoid accidentally parsing these as PHP (includes projects depending on this). // The 'mkstubs' script can be used to generate your own stubs (compatible with php 7.0+ right now) // Note: The array key must be the same as the extension name reported by `php -m`, // so that phan can skip loading the stubs if the extension is actually available. 'autoload_internal_extension_signatures' => [ // Stubs may be available at https://github.com/JetBrains/phpstorm-stubs/tree/master // Xdebug stubs are bundled with Phan 0.10.1+/0.8.9+ for usage, // because Phan disables xdebug by default. //'xdebug' => 'vendor/phan/phan/.phan/internal_stubs/xdebug.phan_php', //'memcached' => PHAN_DIR . '/your_internal_stubs_folder_name/memcached.phan_php', //'PDO' => PHAN_DIR . '/stubs/PDO.phan_php', 'brotli' => PHAN_DIR . '/stubs/brotli.phan_php', 'curl' => PHAN_DIR . '/stubs/curl.phan_php', 'calendar' => PHAN_DIR . '/stubs/calendar.phan_php', 'fileinfo' => PHAN_DIR . '/stubs/fileinfo.phan_php', 'ftp' => PHAN_DIR . '/stubs/ftp.phan_php', 'gd' => PHAN_DIR . '/stubs/gd.phan_php', 'geoip' => PHAN_DIR . '/stubs/geoip.phan_php', 'imagick' => PHAN_DIR . '/stubs/imagick.phan_php', 'imap' => PHAN_DIR . '/stubs/imap.phan_php', 'intl' => PHAN_DIR . '/stubs/intl.phan_php', 'ldap' => PHAN_DIR . '/stubs/ldap.phan_php', 'mcrypt' => PHAN_DIR . '/stubs/mcrypt.phan_php', 'memcache' => PHAN_DIR . '/stubs/memcache.phan_php', 'memcached' => PHAN_DIR . '/stubs/memcached.phan_php', 'mysqli' => PHAN_DIR . '/stubs/mysqli.phan_php', 'pdo_cubrid' => PHAN_DIR . '/stubs/pdo_cubrid.phan_php', 'pdo_mysql' => PHAN_DIR . '/stubs/pdo_mysql.phan_php', 'pdo_pgsql' => PHAN_DIR . '/stubs/pdo_pgsql.phan_php', 'pdo_sqlite' => PHAN_DIR . '/stubs/pdo_sqlite.phan_php', 'pgsql' => PHAN_DIR . '/stubs/pgsql.phan_php', 'session' => PHAN_DIR . '/stubs/session.phan_php', 'simplexml' => PHAN_DIR . '/stubs/SimpleXML.phan_php', 'soap' => PHAN_DIR . '/stubs/soap.phan_php', 'sockets' => PHAN_DIR . '/stubs/sockets.phan_php', 'tidy' => PHAN_DIR . '/stubs/tidy.phan_php', 'zip' => PHAN_DIR . '/stubs/zip.phan_php', ], ];