2
0
forked from Wavyzz/dolibarr

More explicit reporting for NOT IN sql forge notices

This commit is contained in:
MDW
2025-02-22 15:54:53 +01:00
parent 6257c892bf
commit edfb385fd7

View File

@@ -1,7 +1,7 @@
<?php <?php
/* Copyright (C) 2013 Laurent Destailleur <eldy@users.sourceforge.net> /* Copyright (C) 2013 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com> * Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com> * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr> * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -497,36 +497,40 @@ class CodingPhpTest extends CommonClassTest
// Checks with IN // Checks with IN
// Check string ' IN (".xxx' or ' IN (\'.xxx' with xxx that is not '$this->db->sanitize' and not '$db->sanitize'. It means we forget a db->sanitize when forging sql request. // Check string ' IN (".xxx' or ' IN (\'.xxx' with xxx that is not '$this->db->sanitize' and not '$db->sanitize'. It means we forgot a db->sanitize when forging a sql request.
$ok = true; $ok = true;
$lines = array();
$matches = array(); $matches = array();
preg_match_all('/\s+IN\s*\([\'"]\s*\.\s*(.........)/i', $filecontent, $matches, PREG_SET_ORDER); preg_match_all('/\s+IN\s*\([\'"]\s*\.\s*(.........)(.*)/i', $filecontent, $matches, PREG_SET_ORDER);
foreach ($matches as $key => $val) { foreach ($matches as $key => $val) {
//var_dump($val); //var_dump($val);
if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) { if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) {
$lines[] = self::reportAndGetLine($val[1].$val[2], $filecontent, $report_filepath, "NotSanitizedString in IN/NOT IN sql query `{$val[1]}{$val[2]}...`)");
$ok = false; $ok = false;
break; // break; // Not breaking, report all lines
} }
//if ($reg[0] != 'db') $ok=false; //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"; //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
$this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad.'); $this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad. Lines:'.implode(',', $lines));
//exit; //exit;
// Check string ' IN (\'".xxx' with xxx that is not '$this->db->sanitize' and not '$db->sanitize'. It means we forget a db->sanitize when forging sql request. // Check string ' IN (\'".xxx' with xxx that is not '$this->db->sanitize' and not '$db->sanitize'. It means we forgot a db->sanitize when forging a sql request.
$ok = true; $ok = true;
$lines = array();
$matches = array(); $matches = array();
preg_match_all('/\s+IN\s*\(\'"\s*\.\s*(.........)/i', $filecontent, $matches, PREG_SET_ORDER); preg_match_all('/\s+IN\s*\(\'"\s*\.\s*(.........)(.*)/i', $filecontent, $matches, PREG_SET_ORDER);
foreach ($matches as $key => $val) { foreach ($matches as $key => $val) {
//var_dump($val); //var_dump($val);
if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) { if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) {
$lines[] = self::reportAndGetLine($val[1].$val[2], $filecontent, $report_filepath, "NotSanitizedString in IN/NOT IN sql query `{$val[1]}{$val[2]}...`)");
$ok = false; $ok = false;
break; // break; // Not breaking, report all lines
} }
//if ($reg[0] != 'db') $ok=false; //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"; //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
$this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad.'); $this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad. Lines:'.implode(',', $lines));
//exit; //exit;
// Test that output of $_SERVER\[\'QUERY_STRING\'\] is escaped. // Test that output of $_SERVER\[\'QUERY_STRING\'\] is escaped.
@@ -915,4 +919,36 @@ class CodingPhpTest extends CommonClassTest
$this->assertEquals($expected, $this->removePhpComments($source), "Comments not removed as expected"); $this->assertEquals($expected, $this->removePhpComments($source), "Comments not removed as expected");
} }
/**
* Helper function to generate a notice after determining the line number.
*
* The notice is generated in a way that can be picked up in CI so that a useful annotation
* is made on the file.
*
* Note: if the string occurs multiple times in a file, only the first occurrence is reported
* and it might be for the wrong line. In most cases it should be ok.
*
* @param string $needle The exact string to be found, no escaping needed.
* @param string $subject The filecontents in which this string is located.
* @param string $filename The filename that should be reported
* @param string $errMessage The error message to report
*
* @return int The line that `$needle` occurs on, or 0 if not found
*/
public static function reportAndGetLine($needle, $subject, $filename, $errMessage)
{
static $already_reported = array();
$linenbr = 0;
if (preg_match("/^(?<lines>.*)\\Q$needle\\E/s", $subject, $linematches)) {
$linenbr = substr_count($linematches['lines'], "\n");
}
$msg = PHP_EOL."$filename:$linenbr: $errMessage".PHP_EOL;
if (!array_key_exists($msg, $already_reported)) {
$already_reported[$msg] = 1;
print $msg;
}
return $linenbr;
}
} }