diff --git a/dev/tools/phan/config.php b/dev/tools/phan/config.php index 9821b5049b7..1dc71344d2d 100644 --- a/dev/tools/phan/config.php +++ b/dev/tools/phan/config.php @@ -83,6 +83,7 @@ return [ // 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') 'plugins' => [ + __DIR__.'/plugins/NoVarDumpPlugin.php', // checks if a function, closure or method unconditionally returns. // can also be written as 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php' //'DeprecateAliasPlugin', @@ -149,9 +150,13 @@ return [ 'PhanPluginShortArray', 'PhanPluginNumericalComparison', 'PhanPluginUnknownObjectMethodCall', - 'PhanPluginCanUseParamType', 'PhanPluginNonBoolInLogicalArith', - 'PhanPluginCanUseReturnType', + // 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 + // 'PhanPluginNotFullyQualifiedFunctionCall', 'PhanPluginConstantVariableScalar', // 'PhanPluginNoCommentOnPublicProperty', @@ -166,7 +171,6 @@ return [ 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgumentInternal', 'PhanPluginDuplicateAdjacentStatement', - 'PhanPluginCanUseNullableParamType', 'PhanTypeInvalidLeftOperandOfNumericOp', 'PhanTypeMismatchProperty', // 'PhanPluginNoCommentOnPublicMethod', @@ -190,7 +194,6 @@ return [ 'PhanTypeInvalidLeftOperandOfAdd', // 'PhanPluginNoCommentOnPrivateProperty', // 'PhanPluginNoCommentOnFunction', - 'PhanPluginCanUseNullableReturnType', 'PhanPluginUnknownArrayFunctionParamType', // 'PhanPluginDescriptionlessCommentOnPublicProperty', 'PhanPluginUnknownFunctionParamType', diff --git a/dev/tools/phan/config_extended.php b/dev/tools/phan/config_extended.php index 2e748430fe2..9a721355daf 100644 --- a/dev/tools/phan/config_extended.php +++ b/dev/tools/phan/config_extended.php @@ -83,6 +83,7 @@ return [ // 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') 'plugins' => [ + __DIR__.'/plugins/NoVarDumpPlugin.php', 'DeprecateAliasPlugin', //'EmptyMethodAndFunctionPlugin', 'InvalidVariableIssetPlugin', @@ -102,7 +103,7 @@ return [ 'NonBoolBranchPlugin', // Requires test on bool, nont on ints 'NonBoolInLogicalArithPlugin', 'NumericalComparisonPlugin', - 'PHPDocToRealTypesPlugin', + // 'PHPDocToRealTypesPlugin', // Report/Add types to function definitions 'PHPDocInWrongCommentPlugin', // Missing /** (/* was used) //'ShortArrayPlugin', // Checks that [] is used //'StrictLiteralComparisonPlugin', @@ -138,10 +139,11 @@ return [ 'PhanPluginCanUsePHP71Void', // Dolibarr is maintaining 7.0 compatibility 'PhanPluginShortArray', // Dolibarr uses array() 'PhanPluginShortArrayList', // Dolibarr uses array() - // The following may require that --quick is not used - 'PhanPluginCanUseParamType', // Does not seem useful: is reporting types already in PHPDoc? - 'PhanPluginCanUseReturnType', // Does not seem useful: is reporting types already in PHPDoc? - 'PhanPluginCanUseNullableParamType', // Does not seem useful: is reporting types already in PHPDoc? + // 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 diff --git a/dev/tools/phan/plugins/NoVarDumpPlugin.php b/dev/tools/phan/plugins/NoVarDumpPlugin.php new file mode 100644 index 00000000000..b2b093922f7 --- /dev/null +++ b/dev/tools/phan/plugins/NoVarDumpPlugin.php @@ -0,0 +1,81 @@ + + */ + +declare(strict_types=1); + +use ast\Node; +use Phan\PluginV3; +use Phan\PluginV3\PluginAwarePostAnalysisVisitor; +use Phan\PluginV3\PostAnalyzeNodeCapability; + +/** + * NoVarDumpPlugin hooks into one event: + * + * - getPostAnalyzeNodeVisitorClassName + * This method returns a visitor that is called on every AST node from every + * file being analyzed + * + * A plugin file must + * + * - Contain a class that inherits from \Phan\PluginV3 + * + * - End by returning an instance of that class. + * + * It is assumed without being checked that plugins aren't + * mangling state within the passed code base or context. + * + * Note: When adding new plugins, + * add them to the corresponding section of README.md + */ +class NoVarDumpPlugin extends PluginV3 implements PostAnalyzeNodeCapability +{ + /** + * @return string - name of PluginAwarePostAnalysisVisitor subclass + */ + public static function getPostAnalyzeNodeVisitorClassName(): string + { + return NoVarDumpVisitor::class; + } +} + +/** + * When __invoke on this class is called with a node, a method + * will be dispatched based on the `kind` of the given node. + * + * Visitors such as this are useful for defining lots of different + * checks on a node based on its kind. + */ +class NoVarDumpVisitor extends PluginAwarePostAnalysisVisitor +{ + // A plugin's visitors should not override visit() unless they need to. + + /** + * @param Node $node A node to analyze + * + * @return void + * + * @override + */ + public function visitCall(Node $node): void + { + $name = $node->children['expr']->children['name'] ?? null; + if (!is_string($name)) { + return; + } + if (strcasecmp($name, 'var_dump') !== 0) { + return; + } + $this->emitPluginIssue( + $this->code_base, + $this->context, + 'NoVarDumpPlugin', + 'var_dump() should be commented in submitted code', + [] + ); + } +} + +// Every plugin needs to return an instance of itself at the +// end of the file in which it's defined. +return new NoVarDumpPlugin(); diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index d6981147691..9eb4626c3bc 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -106,13 +106,14 @@ if (($action == 'update' && !GETPOST("cancel", 'alpha')) $db->begin(); - dolibarr_set_const($db, "MAIN_INFO_SOCIETE_NOM", GETPOST("nom", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_INFO_SOCIETE_NOM", GETPOST("name", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_ADDRESS", GETPOST("MAIN_INFO_SOCIETE_ADDRESS", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_TOWN", GETPOST("MAIN_INFO_SOCIETE_TOWN", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_ZIP", GETPOST("MAIN_INFO_SOCIETE_ZIP", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_REGION", GETPOST("region_code", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_MONNAIE", GETPOST("currency", 'aZ09'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_INFO_SOCIETE_TEL", GETPOST("tel", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_INFO_SOCIETE_TEL", GETPOST("phone", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_INFO_SOCIETE_MOBILE", GETPOST("phone_mobile", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_FAX", GETPOST("fax", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_MAIL", GETPOST("mail", 'alphanohtml'), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_INFO_SOCIETE_WEB", GETPOST("web", 'alphanohtml'), 'chaine', 0, '', $conf->entity); @@ -440,18 +441,18 @@ print ''.$langs-> // Name print ''; -print ''."\n"; +print ''."\n"; // Address print ''; -print ''."\n"; +print ''."\n"; // Zip print ''; -print ''."\n"; +print ''."\n"; print ''; -print ''."\n"; +print ''."\n"; // Country print ''; @@ -481,13 +482,19 @@ print ''."\n"; // Phone print ''; print img_picto('', 'object_phoning', '', false, 0, 0, '', 'pictofixedwidth'); -print ''; +print ''; +print ''."\n"; + +// Phone mobile +print ''; +print img_picto('', 'object_phoning_mobile', '', false, 0, 0, '', 'pictofixedwidth'); +print ''; print ''."\n"; // Fax print ''; print img_picto('', 'object_phoning_fax', '', false, 0, 0, '', 'pictofixedwidth'); -print ''; +print ''; print ''."\n"; // Email diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 9fb167e4e46..0037dc520cf 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -10,7 +10,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2016 Charlie Benke - * Copyright (C) 2018-2023 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2023 Benjamin Falière * * This program is free software; you can redistribute it and/or modify @@ -1707,7 +1707,7 @@ class Categorie extends CommonObject * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking * @return string Chaine avec URL */ - public function getNomUrl($withpicto = 0, $option = '', $maxlength = 0, $moreparam = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = '') + public function getNomUrl($withpicto = 0, $option = '', $maxlength = 0, $moreparam = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = 0) { global $conf, $langs, $hookmanager; diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index d471e9d7ca4..de9e0bd9892 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -2727,7 +2727,7 @@ while ($i < $imaxinloop) { // Billed if (!empty($arrayfields['c.facture']['checked'])) { - print ''.yn($obj->billed).''; + print ''.yn($obj->billed, 4).''; if (!$i) { $totalarray['nbfield']++; } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index eb113f1ddb9..bc316e5b80f 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -2660,14 +2660,14 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } } // Fix modulepart for backward compatibility - if ($modulepart == 'users') { + if ($modulepart == 'facture') { + $modulepart = 'invoice'; + } elseif ($modulepart == 'users') { $modulepart = 'user'; - } - if ($modulepart == 'tva') { + } elseif ($modulepart == 'tva') { $modulepart = 'tax-vat'; - } - // Fix modulepart delivery - if ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) { + } elseif ($modulepart == 'expedition' && strpos($original_file, 'receipt/') === 0) { + // Fix modulepart delivery $modulepart = 'delivery'; } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 779359719e5..391dbe2e0b4 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -7236,6 +7236,9 @@ function yn($yesno, $case = 1, $color = 0) if ($case == 3) { $result = ' '.$result; } + if ($case == 4) { + $result = img_picto('check', 'check'); + } $classname = 'ok'; } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') { @@ -7249,6 +7252,9 @@ function yn($yesno, $case = 1, $color = 0) if ($case == 3) { $result = ' '.$result; } + if ($case == 4) { + $result = img_picto('uncheck', 'uncheck'); + } if ($color == 2) { $classname = 'ok'; diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index df55b335132..27b78638c33 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -1912,7 +1912,7 @@ function getListOfModels($db, $type, $maxfilenamelength = 0) } if (is_dir($tmpdir)) { // all type of template is allowed - $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '', '', 'name', SORT_ASC, 0); + $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '', null, 'name', SORT_ASC, 0); if (count($tmpfiles)) { $listoffiles = array_merge($listoffiles, $tmpfiles); } diff --git a/htdocs/delivery/class/delivery.class.php b/htdocs/delivery/class/delivery.class.php index 26cea82e0d7..1dfc406a9b9 100644 --- a/htdocs/delivery/class/delivery.class.php +++ b/htdocs/delivery/class/delivery.class.php @@ -6,7 +6,7 @@ * Copyright (C) 2011-2023 Philippe Grand * Copyright (C) 2013 Florian Henry * Copyright (C) 2014-2015 Marcos García - * Copyright (C) 2023 Frédéric France + * Copyright (C) 2023-2024 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -599,10 +599,10 @@ class Delivery extends CommonObject * Update a livraison line (only extrafields) * * @param int $id Id of line (livraison line) - * @param array $array_options extrafields array + * @param array $array_options extrafields array * @return int Return integer <0 if KO, >0 if OK */ - public function update_line($id, $array_options = 0) + public function update_line($id, $array_options = []) { // phpcs:enable global $conf; diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 8c004650de0..5216aa24d81 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -250,55 +250,55 @@ class FactureFournisseur extends CommonInvoice public $fk_fac_rec_source; public $fields = array( - 'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10), - 'ref' =>array('type'=>'varchar(255)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15), - 'ref_supplier' =>array('type'=>'varchar(255)', 'label'=>'RefSupplier', 'enabled'=>1, 'visible'=>-1, 'position'=>20), - 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>25, 'index'=>1), - 'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>30), - 'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35), - 'subtype' =>array('type'=>'smallint(6)', 'label'=>'InvoiceSubtype', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>36), - 'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>-1, 'notnull'=>1, 'position'=>40), - 'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>45), - 'datef' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>-1, 'position'=>50), - 'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>55), - 'libelle' =>array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'position'=>60), - 'paye' =>array('type'=>'smallint(6)', 'label'=>'Paye', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>65), - 'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70), - 'remise' =>array('type'=>'double(24,8)', 'label'=>'Discount', 'enabled'=>1, 'visible'=>-1, 'position'=>75), - 'close_code' =>array('type'=>'varchar(16)', 'label'=>'CloseCode', 'enabled'=>1, 'visible'=>-1, 'position'=>80), - 'close_note' =>array('type'=>'varchar(128)', 'label'=>'CloseNote', 'enabled'=>1, 'visible'=>-1, 'position'=>85), - 'tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>90), - 'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>95), - 'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>100), - 'total_ht' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>105), - 'total_tva' =>array('type'=>'double(24,8)', 'label'=>'TotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>110), - 'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>115), - 'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>125), - 'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>130), - 'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>135), - 'fk_facture_source' =>array('type'=>'integer', 'label'=>'Fk facture source', 'enabled'=>1, 'visible'=>-1, 'position'=>140), - 'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>"isModEnabled('project')", 'visible'=>-1, 'position'=>145), - 'fk_account' =>array('type'=>'integer', 'label'=>'Account', 'enabled'=>'isModEnabled("banque")', 'visible'=>-1, 'position'=>150), - 'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>155), - 'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>160), - 'date_lim_reglement' =>array('type'=>'date', 'label'=>'DateLimReglement', 'enabled'=>1, 'visible'=>-1, 'position'=>165), - 'note_private' =>array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>170), - 'note_public' =>array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>175), - 'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPdf', 'enabled'=>1, 'visible'=>0, 'position'=>180), - 'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>190), - 'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermCode', 'enabled'=>1, 'visible'=>-1, 'position'=>195), - 'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermLocation', 'enabled'=>1, 'visible'=>-1, 'position'=>200), - 'fk_multicurrency' =>array('type'=>'integer', 'label'=>'MulticurrencyId', 'enabled'=>1, 'visible'=>-1, 'position'=>205), - 'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCode', 'enabled'=>1, 'visible'=>-1, 'position'=>210), - 'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>1, 'visible'=>-1, 'position'=>215), - 'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>220), - 'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>225), - 'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyTotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>230), - 'date_pointoftax' =>array('type'=>'date', 'label'=>'Date pointoftax', 'enabled'=>1, 'visible'=>-1, 'position'=>235), - 'date_valid' =>array('type'=>'date', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>240), - 'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'Last main doc', 'enabled'=>1, 'visible'=>-1, 'position'=>245), - 'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500), - 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900), + 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10), + 'ref' => array('type' => 'varchar(255)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 15), + 'ref_supplier' => array('type' => 'varchar(255)', 'label' => 'RefSupplier', 'enabled' => 1, 'visible' => -1, 'position' => 20), + 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => 1, 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 25, 'index' => 1), + 'ref_ext' => array('type' => 'varchar(255)', 'label' => 'RefExt', 'enabled' => 1, 'visible' => 0, 'position' => 30), + 'type' => array('type' => 'smallint(6)', 'label' => 'Type', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 35), + 'subtype' => array('type' => 'smallint(6)', 'label' => 'InvoiceSubtype', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 36), + 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 40), + 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 45), + 'datef' => array('type' => 'date', 'label' => 'Date', 'enabled' => 1, 'visible' => -1, 'position' => 50), + 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 55), + 'libelle' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => -1, 'position' => 60), + 'paye' => array('type' => 'smallint(6)', 'label' => 'Paye', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 65), + 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 70), + 'remise' => array('type' => 'double(24,8)', 'label' => 'Discount', 'enabled' => 1, 'visible' => -1, 'position' => 75), + 'close_code' => array('type' => 'varchar(16)', 'label' => 'CloseCode', 'enabled' => 1, 'visible' => -1, 'position' => 80), + 'close_note' => array('type' => 'varchar(128)', 'label' => 'CloseNote', 'enabled' => 1, 'visible' => -1, 'position' => 85), + 'tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 90), + 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 95), + 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 100), + 'total_ht' => array('type' => 'double(24,8)', 'label' => 'TotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 105), + 'total_tva' => array('type' => 'double(24,8)', 'label' => 'TotalVAT', 'enabled' => 1, 'visible' => -1, 'position' => 110), + 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'TotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 115), + 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'position' => 125), + 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 130), + 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 135), + 'fk_facture_source' => array('type' => 'integer', 'label' => 'Fk facture source', 'enabled' => 1, 'visible' => -1, 'position' => 140), + 'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label' => 'Project', 'enabled' => "isModEnabled('project')", 'visible' => -1, 'position' => 145), + 'fk_account' => array('type' => 'integer', 'label' => 'Account', 'enabled' => 'isModEnabled("banque")', 'visible' => -1, 'position' => 150), + 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'PaymentTerm', 'enabled' => 1, 'visible' => -1, 'position' => 155), + 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'PaymentMode', 'enabled' => 1, 'visible' => -1, 'position' => 160), + 'date_lim_reglement' => array('type' => 'date', 'label' => 'DateLimReglement', 'enabled' => 1, 'visible' => -1, 'position' => 165), + 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 170), + 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 175), + 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'ModelPdf', 'enabled' => 1, 'visible' => 0, 'position' => 180), + 'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 190), + 'fk_incoterms' => array('type' => 'integer', 'label' => 'IncotermCode', 'enabled' => 1, 'visible' => -1, 'position' => 195), + 'location_incoterms' => array('type' => 'varchar(255)', 'label' => 'IncotermLocation', 'enabled' => 1, 'visible' => -1, 'position' => 200), + 'fk_multicurrency' => array('type' => 'integer', 'label' => 'MulticurrencyId', 'enabled' => 1, 'visible' => -1, 'position' => 205), + 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'MulticurrencyCode', 'enabled' => 1, 'visible' => -1, 'position' => 210), + 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyRate', 'enabled' => 1, 'visible' => -1, 'position' => 215), + 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalHT', 'enabled' => 1, 'visible' => -1, 'position' => 220), + 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalVAT', 'enabled' => 1, 'visible' => -1, 'position' => 225), + 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'MulticurrencyTotalTTC', 'enabled' => 1, 'visible' => -1, 'position' => 230), + 'date_pointoftax' => array('type' => 'date', 'label' => 'Date pointoftax', 'enabled' => 1, 'visible' => -1, 'position' => 235), + 'date_valid' => array('type' => 'date', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -1, 'position' => 240), + 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'Last main doc', 'enabled' => 1, 'visible' => -1, 'position' => 245), + 'fk_statut' => array('type' => 'smallint(6)', 'label' => 'Status', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500), + 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 900), ); @@ -1350,7 +1350,7 @@ class FactureFournisseur extends CommonInvoice $facligne->rang = 1; $linecount = count($this->lines); for ($ii = 1; $ii <= $linecount; $ii++) { - $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii+1); + $this->updateRangOfLine($this->lines[$ii - 1]->id, $ii + 1); } } @@ -2658,7 +2658,7 @@ class FactureFournisseur extends CommonInvoice } if ($qualified) { $paymentornot = ($obj->fk_paiementfourn ? 1 : 0); - $return[$obj->rowid] = array('ref'=>$obj->ref, 'status'=>$obj->fk_statut, 'type'=>$obj->type, 'paye'=>$obj->paye, 'paymentornot'=>$paymentornot); + $return[$obj->rowid] = array('ref' => $obj->ref, 'status' => $obj->fk_statut, 'type' => $obj->type, 'paye' => $obj->paye, 'paymentornot' => $paymentornot); } } @@ -2922,7 +2922,7 @@ class FactureFournisseur extends CommonInvoice } global $action; $hookmanager->initHooks(array($this->element . 'dao')); - $parameters = array('id'=>$this->id, 'getnomurl' => &$result); + $parameters = array('id' => $this->id, 'getnomurl' => &$result); $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks if ($reshook > 0) { $result = $hookmanager->resPrint; @@ -3689,7 +3689,7 @@ class FactureFournisseur extends CommonInvoice return 0; } else { - $this->error = 'Nb of emails sent : '.$nbMailSend.', '.(!empty($errorsMsg)) ? join(', ', $errorsMsg) : $error; + $this->error = 'Nb of emails sent : '.$nbMailSend.', '.(!empty($errorsMsg)) ? implode(', ', $errorsMsg) : $error; dol_syslog(__METHOD__." end - ".$this->error, LOG_INFO); diff --git a/htdocs/product/stats/commande.php b/htdocs/product/stats/commande.php index 3532afb8116..eedd1cb47c8 100644 --- a/htdocs/product/stats/commande.php +++ b/htdocs/product/stats/commande.php @@ -69,7 +69,7 @@ if (!$sortfield) { $search_month = GETPOST('search_month', 'int'); $search_year = GETPOST('search_year', 'int'); if (GETPOSTISARRAY('search_status')) { - $search_status = join(',', GETPOST('search_status', 'array:intcomma')); + $search_status = implode(',', GETPOST('search_status', 'array:intcomma')); } else { $search_status = (GETPOST('search_status', 'intcomma') != '' ? GETPOST('search_status', 'intcomma') : GETPOST('statut', 'intcomma')); } @@ -100,7 +100,7 @@ if ($id > 0 || !empty($ref)) { $object = $product; - $parameters = array('id'=>$id); + $parameters = array('id' => $id); $reshook = $hookmanager->executeHooks('doActions', $parameters, $product, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); diff --git a/htdocs/product/stats/commande_fournisseur.php b/htdocs/product/stats/commande_fournisseur.php index a76c572af19..44e35990683 100644 --- a/htdocs/product/stats/commande_fournisseur.php +++ b/htdocs/product/stats/commande_fournisseur.php @@ -69,7 +69,7 @@ if (!$sortfield) { $search_month = GETPOST('search_month', 'int'); $search_year = GETPOST('search_year', 'int'); if (GETPOSTISARRAY('search_status')) { - $search_status = join(',', GETPOST('search_status', 'array:intcomma')); + $search_status = implode(',', GETPOST('search_status', 'array:intcomma')); } else { $search_status = (GETPOST('search_status', 'intcomma') != '' ? GETPOST('search_status', 'intcomma') : GETPOST('statut', 'intcomma')); } diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index ff079efe387..265f218fc53 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -2,7 +2,7 @@ /* Copyright (C) 2008-2014 Laurent Destailleur * Copyright (C) 2010-2012 Regis Houssin * Copyright (C) 2014 Marcos García - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2020 Juanjo Menent * Copyright (C) 2022 Charlene Benke * Copyright (C) 2023 Gauthier VERDOL @@ -903,14 +903,14 @@ class Task extends CommonObjectLine { $this->id = 0; - $this->fk_project = ''; + $this->fk_project = 0; $this->ref = 'TK01'; - $this->fk_task_parent = null; + $this->fk_task_parent = 0; $this->label = 'Specimen task TK01'; $this->duration_effective = ''; - $this->fk_user_creat = null; + $this->fk_user_creat = 1; $this->progress = '25'; - $this->status = null; + $this->status = 0; $this->note = 'This is a specimen task not'; } diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php index 44ff7c4a6fb..ee2587cc04e 100644 --- a/htdocs/reception/class/reception.class.php +++ b/htdocs/reception/class/reception.class.php @@ -937,7 +937,7 @@ class Reception extends CommonObject $this->fk_user_valid = trim($this->fk_user_valid); } if (isset($this->shipping_method_id)) { - $this->shipping_method_id = trim($this->shipping_method_id); + $this->shipping_method_id = (int) $this->shipping_method_id; } if (isset($this->tracking_number)) { $this->tracking_number = trim($this->tracking_number); diff --git a/htdocs/resource/class/html.formresource.class.php b/htdocs/resource/class/html.formresource.class.php index 0241e62a8fc..425ee481964 100644 --- a/htdocs/resource/class/html.formresource.class.php +++ b/htdocs/resource/class/html.formresource.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2019 Frédéric France + * Copyright (C) 2019-2024 Frédéric France * Copyright (C) 2022 Ferran Marcet * Copyright (C) 2023 William Mead * @@ -80,7 +80,7 @@ class FormResource * @param bool $multiple add [] in the name of element and add 'multiple' attribute * @return string|array HTML string with */ - public function select_resource_list($selected = 0, $htmlname = 'fk_resource', array $filter = [], $showempty = 0, $showtype = 0, $forcecombo = 0, $event = [], $filterkey = '', $outputmode = 0, $limit = 20, $morecss = '', $multiple = false) + public function select_resource_list($selected = 0, $htmlname = 'fk_resource', array $filter = [], $showempty = 0, $showtype = 0, $forcecombo = 0, $event = [], $filterkey = [], $outputmode = 0, $limit = 20, $morecss = '', $multiple = false) { // phpcs:enable global $conf, $user, $langs; diff --git a/test/phpunit/CodingPhpTest.php b/test/phpunit/CodingPhpTest.php index 7e134b07bbb..5dd8a43257a 100644 --- a/test/phpunit/CodingPhpTest.php +++ b/test/phpunit/CodingPhpTest.php @@ -131,14 +131,20 @@ class CodingPhpTest extends CommonClassTest //print 'Check php file '.$file['relativename']."\n"; $filecontent = file_get_contents($file['fullname']); - $this->verifyIsModuleEnabledOk($filecontent, "htdocs/{$file['relativename']}"); + // We are not interested in the comments + $filecontent = $this->removePhpComments(file_get_contents($file['fullname'])); + + // File path for reports + $report_filepath = "htdocs/{$file['relativename']}"; + + $this->verifyIsModuleEnabledOk($filecontent, $report_filepath); if (preg_match('/\.class\.php/', $file['relativename']) || preg_match('/boxes\/box_/', $file['relativename']) || preg_match('/modules\/.*\/doc\/(doc|pdf)_/', $file['relativename']) || preg_match('/modules\/(import|mailings|printing)\//', $file['relativename']) || in_array($file['name'], array('modules_boxes.php', 'TraceableDB.php'))) { - // Check into Class files + // Check Class files if (! in_array($file['name'], array( 'api.class.php', 'commonobject.class.php', @@ -152,18 +158,18 @@ class CodingPhpTest extends CommonClassTest // Must not find $db-> $ok = true; $matches = array(); - // Check string $db-> inside a class.php file (it should be $this->db-> into such classes) + // Check string $db-> inside a class.php file (it should be $this->db-> in such classes) preg_match_all('/'.preg_quote('$db->', '/').'/', $filecontent, $matches, PREG_SET_ORDER); foreach ($matches as $key => $val) { $ok = false; break; } //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Found string $db-> into a .class.php file in '.$file['relativename'].'. Inside a .class file, you should use $this->db-> instead.'); + $this->assertTrue($ok, 'Found string $db-> in a .class.php file in '.$file['relativename'].'. Inside a .class file, you should use $this->db-> instead.'); //exit; } - if (preg_match('/\.class\.php/', $file['relativename']) && ! in_array($file['relativename'], array( + if (preg_match('/\.class\.php$/', $file['relativename']) && ! in_array($file['relativename'], array( 'adherents/canvas/actions_adherentcard_common.class.php', 'contact/canvas/actions_contactcard_common.class.php', 'compta/facture/class/facture.class.php', @@ -191,7 +197,7 @@ class CodingPhpTest extends CommonClassTest // Must not find GETPOST $ok = true; $matches = array(); - // Check string GETPOSTFLOAT a class.php file (should not be found into classes) + // Check string GETPOSTFLOAT a class.php file (should not be found in classes) preg_match_all('/GETPOST\(["\'](....)/', $filecontent, $matches, PREG_SET_ORDER); foreach ($matches as $key => $val) { if (in_array($val[1], array('lang', 'forc', 'mass', 'conf'))) { @@ -201,11 +207,10 @@ class CodingPhpTest extends CommonClassTest $ok = false; break; } - //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Found string GETPOST into a .class.php file in '.$file['relativename'].'.'); + $this->assertTrue($ok, 'Found string GETPOST in a .class.php file in '.$file['relativename'].'.'); } } else { - // Check into Include files + // Check Include files if (! in_array($file['name'], array( 'objectline_view.tpl.php', 'extrafieldsinexport.inc.php', @@ -216,7 +221,7 @@ class CodingPhpTest extends CommonClassTest // Must not found $this->db-> $ok = true; $matches = array(); - // Check string $this->db-> into a non class.php file (it should be $db-> into such classes) + // Check string $this->db-> in a non class.php file (it should be $db-> in such classes) preg_match_all('/'.preg_quote('$this->db->', '/').'/', $filecontent, $matches, PREG_SET_ORDER); foreach ($matches as $key => $val) { $ok = false; @@ -228,9 +233,9 @@ class CodingPhpTest extends CommonClassTest } } - // Check we don't miss top_httphead() into any ajax pages + // Check we don't miss top_httphead() in any ajax pages if (preg_match('/ajax\//', $file['relativename'])) { - print "Analyze ajax page ".$file['relativename']."\n"; + //print "Analyze ajax page ".$file['relativename']."\n"; $ok = true; $matches = array(); preg_match_all('/top_httphead/', $filecontent, $matches, PREG_SET_ORDER); @@ -238,28 +243,13 @@ class CodingPhpTest extends CommonClassTest $ok = false; } //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Did not find top_httphead into the ajax page '.$file['relativename']); + $this->assertTrue($ok, 'Did not find top_httphead in the ajax page '.$file['relativename']); //exit; } - // Check if a var_dump has been forgotten + // Check for unauthorised vardumps if (!preg_match('/test\/phpunit/', $file['fullname'])) { - if (! in_array($file['name'], array('class.nusoap_base.php'))) { - $ok = true; - $matches = array(); - preg_match_all('/(.)\s*var_dump\(/', $filecontent, $matches, PREG_SET_ORDER); - //var_dump($matches); - foreach ($matches as $key => $val) { - if ($val[1] != '/' && $val[1] != '*') { - $ok = false; - break; - } - break; - } - //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Found string var_dump that is not just after /* or // in '.$file['relativename']); - //exit; - } + $this->verifyNoActiveVardump($filecontent, $report_filepath); } // Check get_class followed by __METHOD__ @@ -311,7 +301,7 @@ class CodingPhpTest extends CommonClassTest break; } //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Found non quoted or not casted var into sql request '.$file['relativename'].' - Bad.'); + $this->assertTrue($ok, 'Found non quoted or not casted var in sql request '.$file['relativename'].' - Bad.'); //exit; // Check that forged sql string is using ' instead of " as string PHP quotes @@ -327,7 +317,7 @@ class CodingPhpTest extends CommonClassTest //if ($reg[0] != 'db') $ok=false; } //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Found a forged SQL string that mix on same line the use of \' for PHP string and PHP variables into file '.$file['relativename'].' Use " to forge PHP string like this: $sql = "SELECT ".$myvar...'); + $this->assertTrue($ok, 'Found a forged SQL string that mix on same line the use of \' for PHP string and PHP variables in file '.$file['relativename'].' Use " to forge PHP string like this: $sql = "SELECT ".$myvar...'); //exit; // Check that forged sql string is using ' instead of " as string PHP quotes @@ -339,7 +329,7 @@ class CodingPhpTest extends CommonClassTest $ok = false; break; } - $this->assertTrue($ok, 'Found a forged SQL string that mix on same line the use of \' for PHP string and PHP variables into file '.$file['relativename'].' Use " to forge PHP string like this: $sql = "SELECT ".$myvar...'); + $this->assertTrue($ok, 'Found a forged SQL string that mix on same line the use of \' for PHP string and PHP variables in file '.$file['relativename'].' Use " to forge PHP string like this: $sql = "SELECT ".$myvar...'); // Check sql string VALUES ... , ".$xxx // with xxx that is not 'db-' (for $db->escape). It means we forget a ' if string, or an (int) if int, when forging sql request. @@ -358,7 +348,7 @@ class CodingPhpTest extends CommonClassTest break; } //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n"; - $this->assertTrue($ok, 'Found non quoted or not casted var into sql request '.$file['relativename'].' - Bad.'); + $this->assertTrue($ok, 'Found non quoted or not casted var in sql request '.$file['relativename'].' - Bad.'); //exit; // Check '".$xxx non escaped @@ -514,7 +504,7 @@ class CodingPhpTest extends CommonClassTest break; } } - $this->assertTrue($ok, 'Found a forbidden string sequence into '.$file['relativename'].' : name="token" value="\'.$_SESSION[..., you must use a newToken() instead of $_SESSION[\'newtoken\'].'); + $this->assertTrue($ok, 'Found a forbidden string sequence in '.$file['relativename'].' : name="token" value="\'.$_SESSION[..., you must use a newToken() instead of $_SESSION[\'newtoken\'].'); // Test we don't have preg_grep with a param without preg_quote @@ -589,10 +579,93 @@ class CodingPhpTest extends CommonClassTest $ok = false; break; } - $this->assertTrue($ok, 'Found a CURDATE\(\) into code. Do not use this SQL method in file '.$file['relativename'].'. You must use the PHP function dol_now() instead.'); + $this->assertTrue($ok, 'Found a CURDATE\(\) in code. Do not use this SQL method in file '.$file['relativename'].'. You must use the PHP function dol_now() instead.'); } + /** + * Verify that no active var_dump was left over in the code + * + * @param string $filecontent Contents to check for php code that uses a module name + * @param string $filename File name for the contents (used for reporting) + * + * @return void + */ + private function verifyNoActiveVardump(&$filecontent, $filename) + { + $ok = true; + $matches = array(); + // Match!: + // - Line-start, whitespace, var_dump + // - Line-start, no-comment-leader, var_dump + // no-commen-leader= + // - Any character not / or * + // - Any / not preceded with / and not followed by / or * + // - Any * not preceded with / + preg_match_all('{^(?:^|^(?:[ \t]*|(?:(?:[^*/]|(? $val) { + if (!isset($val[1]) || $val[1] != '/' && $val[1] != '*') { + $ok = false; + $failing_string = $val[0]; + break; + } + } + $this->assertTrue($ok, "Found string var_dump that is not just after /* or // in '$filename': $failing_string"); + } + + + /** + * Provide test data for testing the method detecting var_dump presence. + * + * @return array Test sets + */ + public function vardumpTesterProvider() + { + return [ + 'var_dump at start of file' => ["var_dump(\$help)\n", true], + 'var_dump at start of line' => ["\nvar_dump(\$help)\n", true], + 'var_dump after comment next line' => ["/* Hello */\nvar_dump(\$help)\n", true], + 'var_dump with space' => [" var_dump(\$help)\n", true], + 'var_dump after comment' => [" // var_dump(\$help)\n", false], + '2 var_dumps after comment' => [" // var_dump(\$help); var_dump(\$help)\n", false], + 'var_dump before and after comment' => [" var_dump(\$help); // var_dump(\$help)\n", true], + ]; + } + + /** + * Test that verifyNoActiveVardump generates a notification + * + * @param string $filecontent Fake file content + * @param bool $hasVardump When true, expect var_dump detection + * + * @return void + * + * @dataProvider vardumpTesterProvider + */ + public function testVerifyNoActiveVardump(&$filecontent, $hasVardump) + { + $this->nbLinesToShow = 1; + // Create some dummy file content + $filename = $this->getName(false); + + $notification = false; + ob_start(); // Do not disturb the output with tests that are meant to fail. + try { + $this->verifyNoActiveVardump($filecontent, $filename); + } catch (Throwable $e) { + $notification = (string) $e; + } + $output = ob_get_clean(); + + // Assert that a notification was generated + if ($hasVardump) { + $this->assertStringContainsString("Found string var_dump", $notification ?? '', "Expected notification not found."); + } else { + $this->assertFalse($notification, "Unexpection detection of var_dump"); + } + } + /** * Verify that only known modules are used * @@ -635,4 +708,72 @@ class CodingPhpTest extends CommonClassTest ); } } + + + /** + * Remove php comments from source string + * + * @param string $string The string from which the PHP comments are removed + * + * @return string The string without the comments + */ + private function removePhpComments($string) + { + return preg_replace_callback( + '{(//.*?$)|(/\*.*?\*/)}ms', + static function ($match) { + if (isset($match[2])) { + // Count the number of newline characters in the comment + $num_newlines = substr_count($match[0], "\n"); + // Generate whitespace equivalent to the number of newlines + if ($num_newlines == 0) { + // /* Comment on single line -> space + return " "; + } else { + // /* Comment on multiple lines -> new lines + return str_repeat("\n", $num_newlines); + } + } else { + // Double slash comment, just remove + return ""; + } + }, + $string + ); + } + + /** + * Provide test data for testing the comments remover + * + * @return array Test sets + */ + public function commentRemovalTestProvider() + { + return [ + 'complete line 1' => ["/*Comment complete line*/", " "], + 'complete line 2' => ["// Comment complete line", ""], + 'partial line 1' => ["a/*Comment complete line*/b", "a b"], + 'partial line 2' => ["a// Comment complete line", "a"], + 'multi line full 1' => ["/*Comment\ncomplete line*/", "\n"], + 'multi line full 2' => ["/*Comment\ncomplete line*/\n", "\n\n"], + 'multi line partials 1' => ["a/*Comment\ncomplete line*/b", "a\nb"], + ]; + } + + /** + * Test that comments are properly removed + * + * @param string $source Fake file content + * @param bool $expected When true, expect var_dump detection + * + * @return void + * + * @dataProvider commentRemovalTestProvider + */ + public function testRemovePhpComments(&$source, &$expected) + { + $this->nbLinesToShow = 0; + + $this->assertEquals($expected, $this->removePhpComments($source), "Comments not removed as expected"); + } }