CodingPhpTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. <?php
  2. /* Copyright (C) 2013 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. * or see https://www.gnu.org/
  18. */
  19. /**
  20. * \file test/phpunit/CodingPhpTest.php
  21. * \ingroup test
  22. * \brief PHPUnit test
  23. * \remarks To run this script as CLI: phpunit filename.php
  24. */
  25. global $conf,$user,$langs,$db;
  26. //define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver
  27. //require_once 'PHPUnit/Autoload.php';
  28. require_once dirname(__FILE__).'/../../htdocs/master.inc.php';
  29. require_once dirname(__FILE__).'/../../htdocs/core/lib/security.lib.php';
  30. require_once dirname(__FILE__).'/../../htdocs/core/lib/security2.lib.php';
  31. if (! defined('NOREQUIREUSER')) {
  32. define('NOREQUIREUSER', '1');
  33. }
  34. if (! defined('NOREQUIREDB')) {
  35. define('NOREQUIREDB', '1');
  36. }
  37. if (! defined('NOREQUIRESOC')) {
  38. define('NOREQUIRESOC', '1');
  39. }
  40. if (! defined('NOREQUIRETRAN')) {
  41. define('NOREQUIRETRAN', '1');
  42. }
  43. if (! defined('NOCSRFCHECK')) {
  44. define('NOCSRFCHECK', '1');
  45. }
  46. if (! defined('NOTOKENRENEWAL')) {
  47. define('NOTOKENRENEWAL', '1');
  48. }
  49. if (! defined('NOREQUIREMENU')) {
  50. define('NOREQUIREMENU', '1'); // If there is no menu to show
  51. }
  52. if (! defined('NOREQUIREHTML')) {
  53. define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php
  54. }
  55. if (! defined('NOREQUIREAJAX')) {
  56. define('NOREQUIREAJAX', '1');
  57. }
  58. if (! defined("NOLOGIN")) {
  59. define("NOLOGIN", '1'); // If this page is public (can be called outside logged session)
  60. }
  61. if (empty($user->id)) {
  62. print "Load permissions for admin user nb 1\n";
  63. $user->fetch(1);
  64. $user->getrights();
  65. }
  66. $conf->global->MAIN_DISABLE_ALL_MAILS=1;
  67. /**
  68. * Class for PHPUnit tests
  69. *
  70. * @backupGlobals disabled
  71. * @backupStaticAttributes enabled
  72. * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased.
  73. */
  74. class CodingPhpTest extends PHPUnit\Framework\TestCase
  75. {
  76. protected $savconf;
  77. protected $savuser;
  78. protected $savlangs;
  79. protected $savdb;
  80. /**
  81. * Constructor
  82. * We save global variables into local variables
  83. *
  84. * @param string $name Name
  85. * @return SecurityTest
  86. */
  87. public function __construct($name = '')
  88. {
  89. parent::__construct($name);
  90. //$this->sharedFixture
  91. global $conf,$user,$langs,$db;
  92. $this->savconf=$conf;
  93. $this->savuser=$user;
  94. $this->savlangs=$langs;
  95. $this->savdb=$db;
  96. print __METHOD__." db->type=".$db->type." user->id=".$user->id;
  97. //print " - db ".$db->db;
  98. print "\n";
  99. }
  100. /**
  101. * setUpBeforeClass
  102. *
  103. * @return void
  104. */
  105. public static function setUpBeforeClass(): void
  106. {
  107. global $conf,$user,$langs,$db;
  108. $db->begin(); // This is to have all actions inside a transaction even if test launched without suite.
  109. print __METHOD__."\n";
  110. }
  111. /**
  112. * tearDownAfterClass
  113. *
  114. * @return void
  115. */
  116. public static function tearDownAfterClass(): void
  117. {
  118. global $conf,$user,$langs,$db;
  119. $db->rollback();
  120. print __METHOD__."\n";
  121. }
  122. /**
  123. * Init phpunit tests
  124. *
  125. * @return void
  126. */
  127. protected function setUp(): void
  128. {
  129. global $conf,$user,$langs,$db;
  130. $conf=$this->savconf;
  131. $user=$this->savuser;
  132. $langs=$this->savlangs;
  133. $db=$this->savdb;
  134. print __METHOD__."\n";
  135. }
  136. /**
  137. * End phpunit tests
  138. *
  139. * @return void
  140. */
  141. protected function tearDown(): void
  142. {
  143. print __METHOD__."\n";
  144. }
  145. /**
  146. * testPHP
  147. *
  148. * @return string
  149. */
  150. public function testPHP()
  151. {
  152. global $conf,$user,$langs,$db;
  153. $conf=$this->savconf;
  154. $user=$this->savuser;
  155. $langs=$this->savlangs;
  156. $db=$this->savdb;
  157. include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  158. $filesarray = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, '\.php', null, 'fullname', SORT_ASC, 0, 1, '', 1);
  159. foreach ($filesarray as $key => $file) {
  160. if (preg_match('/\/(htdocs|html)\/includes\//', $file['fullname'])) {
  161. continue;
  162. }
  163. if (preg_match('/\/(htdocs|html)\/install\/doctemplates\/websites\//', $file['fullname'])) {
  164. continue;
  165. }
  166. if (preg_match('/\/(htdocs|html)\/custom\//', $file['fullname'])) {
  167. continue;
  168. }
  169. if (preg_match('/\/(htdocs|html)\/dolimed/', $file['fullname'])) {
  170. continue;
  171. }
  172. if (preg_match('/\/(htdocs|html)\/nltechno/', $file['fullname'])) {
  173. continue;
  174. }
  175. if (preg_match('/\/(htdocs|html)\/teclib/', $file['fullname'])) {
  176. continue;
  177. }
  178. //print 'Check php file '.$file['relativename']."\n";
  179. $filecontent=file_get_contents($file['fullname']);
  180. if (preg_match('/\.class\.php/', $file['relativename'])
  181. || preg_match('/boxes\/box_/', $file['relativename'])
  182. || preg_match('/modules\/.*\/doc\/(doc|pdf)_/', $file['relativename'])
  183. || preg_match('/modules\/(import|mailings|printing)\//', $file['relativename'])
  184. || in_array($file['name'], array('modules_boxes.php', 'TraceableDB.php'))) {
  185. // Check into Class files
  186. if (! in_array($file['name'], array(
  187. 'api.class.php',
  188. 'commonobject.class.php',
  189. 'conf.class.php',
  190. 'html.form.class.php',
  191. 'translate.class.php',
  192. 'utils.class.php',
  193. 'TraceableDB.php',
  194. 'multicurrency.class.php',
  195. 'infobox.class.php'
  196. ))) {
  197. // Must not find $db->
  198. $ok=true;
  199. $matches=array();
  200. // Check string $db-> inside a class.php file (it should be $this->db-> into such classes)
  201. preg_match_all('/'.preg_quote('$db->', '/').'/', $filecontent, $matches, PREG_SET_ORDER);
  202. foreach ($matches as $key => $val) {
  203. $ok=false;
  204. break;
  205. }
  206. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  207. $this->assertTrue($ok, 'Found string $db-> into a .class.php file in '.$file['relativename'].'. Inside a .class file, you should use $this->db-> instead.');
  208. //exit;
  209. }
  210. } else {
  211. // Check into Include files
  212. if (! in_array($file['name'], array(
  213. 'objectline_view.tpl.php',
  214. 'extrafieldsinexport.inc.php',
  215. 'extrafieldsinimport.inc.php',
  216. 'DolQueryCollector.php',
  217. 'DoliStorage.php'
  218. ))) {
  219. // Must not found $this->db->
  220. $ok=true;
  221. $matches=array();
  222. // Check string $this->db-> into a non class.php file (it shoud be $db-> into such classes)
  223. preg_match_all('/'.preg_quote('$this->db->', '/').'/', $filecontent, $matches, PREG_SET_ORDER);
  224. foreach ($matches as $key => $val) {
  225. $ok=false;
  226. break;
  227. }
  228. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  229. $this->assertTrue($ok, 'Found string "$this->db->" in '.$file['relativename']);
  230. //exit;
  231. }
  232. }
  233. // Check we don't miss top_httphead() into any ajax pages
  234. if (preg_match('/ajax\//', $file['relativename'])) {
  235. print "Analyze ajax page ".$file['relativename']."\n";
  236. $ok=true;
  237. $matches=array();
  238. preg_match_all('/top_httphead/', $filecontent, $matches, PREG_SET_ORDER);
  239. if (count($matches) == 0) {
  240. $ok=false;
  241. }
  242. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  243. $this->assertTrue($ok, 'Did not find top_httphead into the ajax page '.$file['relativename']);
  244. //exit;
  245. }
  246. // Check if a var_dump has been forgotten
  247. if (!preg_match('/test\/phpunit/', $file['fullname'])) {
  248. if (! in_array($file['name'], array('class.nusoap_base.php'))) {
  249. $ok=true;
  250. $matches=array();
  251. preg_match_all('/(.)\s*var_dump\(/', $filecontent, $matches, PREG_SET_ORDER);
  252. //var_dump($matches);
  253. foreach ($matches as $key => $val) {
  254. if ($val[1] != '/' && $val[1] != '*') {
  255. $ok=false;
  256. break;
  257. }
  258. break;
  259. }
  260. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  261. $this->assertTrue($ok, 'Found string var_dump that is not just after /* or // in '.$file['relativename']);
  262. //exit;
  263. }
  264. }
  265. // Check get_class followed by __METHOD__
  266. $ok=true;
  267. $matches=array();
  268. preg_match_all('/'.preg_quote('get_class($this)."::".__METHOD__', '/').'/', $filecontent, $matches, PREG_SET_ORDER);
  269. foreach ($matches as $key => $val) {
  270. $ok=false;
  271. break;
  272. }
  273. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  274. $this->assertTrue($ok, 'Found string get_class($this)."::".__METHOD__ that must be replaced with __METHOD__ only in '.$file['relativename']);
  275. //exit;
  276. // Check string $this->db->idate without quotes
  277. $ok=true;
  278. $matches=array();
  279. preg_match_all('/(..)\s*\.\s*\$this->db->idate\(/', $filecontent, $matches, PREG_SET_ORDER);
  280. foreach ($matches as $key => $val) {
  281. if ($val[1] != '\'"' && $val[1] != '\'\'') {
  282. $ok=false;
  283. break;
  284. }
  285. //if ($reg[0] != 'db') $ok=false;
  286. }
  287. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  288. $this->assertTrue($ok, 'Found a $this->db->idate to forge a sql request without quotes around this date field '.$file['relativename']);
  289. //exit;
  290. // Check sql string DELETE|OR|AND|WHERE|INSERT ... yyy = ".$xxx
  291. // with xxx that is not 'thi' (for $this->db->sanitize) and 'db-' (for $db->sanitize). It means we forget a ' if string, or an (int) if int, when forging sql request.
  292. $ok=true;
  293. $matches=array();
  294. preg_match_all('/(DELETE|OR|AND|WHERE|INSERT)\s.*([^\s][^\s][^\s])\s*=\s*(\'|")\s*\.\s*\$(...)/', $filecontent, $matches, PREG_SET_ORDER);
  295. foreach ($matches as $key => $val) {
  296. if ($val[2] == 'ity' && $val[4] == 'con') { // exclude entity = ".$conf->entity
  297. continue;
  298. }
  299. if ($val[2] == 'ame' && $val[4] == 'db-' && preg_match('/WHERE name/', $val[0])) { // exclude name = ".$db->encrypt(
  300. continue;
  301. }
  302. if ($val[2] == 'ame' && $val[4] == 'thi' && preg_match('/WHERE name/', $val[0])) { // exclude name = ".$this->db->encrypt(
  303. continue;
  304. }
  305. var_dump($matches);
  306. $ok=false;
  307. break;
  308. }
  309. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  310. $this->assertTrue($ok, 'Found non quoted or not casted var into sql request '.$file['relativename'].' - Bad.');
  311. //exit;
  312. // Check that forged sql string is using ' instead of " as string PHP quotes
  313. $ok=true;
  314. $matches=array();
  315. preg_match_all('/\$sql \.= \'\s*VALUES.*\$/', $filecontent, $matches, PREG_SET_ORDER);
  316. foreach ($matches as $key => $val) {
  317. //if ($val[1] != '\'"' && $val[1] != '\'\'') {
  318. var_dump($matches);
  319. $ok=false;
  320. break;
  321. //}
  322. //if ($reg[0] != 'db') $ok=false;
  323. }
  324. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  325. $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...');
  326. //exit;
  327. // Check that forged sql string is using ' instead of " as string PHP quotes
  328. $ok=true;
  329. $matches=array();
  330. preg_match_all('/\$sql \.?= \'SELECT.*\$/', $filecontent, $matches, PREG_SET_ORDER);
  331. foreach ($matches as $key => $val) {
  332. var_dump($matches);
  333. $ok=false;
  334. break;
  335. }
  336. $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...');
  337. // Check sql string VALUES ... , ".$xxx
  338. // 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.
  339. $ok=true;
  340. $matches=array();
  341. preg_match_all('/(VALUES).*,\s*"\s*\.\s*\$(...)/', $filecontent, $matches, PREG_SET_ORDER);
  342. foreach ($matches as $key => $val) {
  343. if ($val[1] == 'VALUES' && $val[2] == 'db-') { // exclude $db->escape(
  344. continue;
  345. }
  346. if ($val[1] == 'VALUES' && $val[2] == 'thi' && preg_match('/this->db->encrypt/', $val[0])) { // exclude ".$this->db->encrypt(
  347. continue;
  348. }
  349. var_dump($matches);
  350. $ok=false;
  351. break;
  352. }
  353. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  354. $this->assertTrue($ok, 'Found non quoted or not casted var into sql request '.$file['relativename'].' - Bad.');
  355. //exit;
  356. // Check '".$xxx non escaped
  357. // Check string ='".$this->xxx with xxx that is not 'escape'. It means we forget a db->escape when forging sql request.
  358. $ok=true;
  359. $matches=array();
  360. preg_match_all('/=\s*\'"\s*\.\s*\$this->(....)/', $filecontent, $matches, PREG_SET_ORDER);
  361. foreach ($matches as $key => $val) {
  362. if ($val[1] != 'db->' && $val[1] != 'esca') {
  363. $ok=false;
  364. break;
  365. }
  366. }
  367. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  368. $this->assertTrue($ok, 'Found non escaped string in building of a sql request (case 1) in '.$file['relativename'].' - Bad.');
  369. // Check string sql|set|WHERE|...'".$yyy->xxx with xxx that is not 'escape', 'idate', .... It means we forget a db->escape when forging sql request.
  370. $ok=true;
  371. $matches=array();
  372. preg_match_all('/(sql|SET|WHERE|INSERT|VALUES|LIKE).+\s*\'"\s*\.\s*\$(.......)/', $filecontent, $matches, PREG_SET_ORDER);
  373. foreach ($matches as $key => $val) {
  374. if (! in_array($val[2], array('this->d', 'this->e', 'db->esc', 'dbs->es', 'dbs->id', 'mydb->e', 'dbsessi', 'db->ida', 'escaped', 'exclude', 'include'))) {
  375. $ok=false; // This will generate error
  376. break;
  377. }
  378. //if ($reg[0] != 'db') $ok=false;
  379. }
  380. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  381. $this->assertTrue($ok, 'Found non escaped string in building of a sql request (case 2) in '.$file['relativename'].': '.$val[0].' - Bad.');
  382. //exit;
  383. // Check string sql|set...'.$yyy->xxx with xxx that is not 'escape', 'idate', .... It means we forget a db->escape when forging sql request.
  384. $ok=true;
  385. $matches=array();
  386. preg_match_all('/(\$sql|SET\s|WHERE\s|INSERT\s|VALUES\s|VALUES\().+\s*\'\s*\.\s*\$(.........)/', $filecontent, $matches, PREG_SET_ORDER);
  387. foreach ($matches as $key => $val) {
  388. if (! in_array($val[2], array('this->db-', 'db->prefi', 'db->sanit', 'dbs->pref', 'dbs->sani', 'conf->ent', 'key : \'\')', 'key])."\')', 'excludefi', 'regexstri', ''))) {
  389. $ok=false;
  390. var_dump($matches);
  391. break;
  392. }
  393. //if ($reg[0] != 'db') $ok=false;
  394. }
  395. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  396. $this->assertTrue($ok, 'Found non escaped string in building of a sql request (case 3) in '.$file['relativename'].': '.$val[0].' - Bad.');
  397. //exit;
  398. // Checks with IN
  399. // 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.
  400. $ok=true;
  401. $matches=array();
  402. preg_match_all('/\s+IN\s*\([\'"]\s*\.\s*(.........)/i', $filecontent, $matches, PREG_SET_ORDER);
  403. foreach ($matches as $key => $val) {
  404. //var_dump($val);
  405. if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) {
  406. $ok=false;
  407. break;
  408. }
  409. //if ($reg[0] != 'db') $ok=false;
  410. }
  411. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  412. $this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad.');
  413. //exit;
  414. // 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.
  415. $ok=true;
  416. $matches=array();
  417. preg_match_all('/\s+IN\s*\(\'"\s*\.\s*(.........)/i', $filecontent, $matches, PREG_SET_ORDER);
  418. foreach ($matches as $key => $val) {
  419. //var_dump($val);
  420. if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) {
  421. $ok=false;
  422. break;
  423. }
  424. //if ($reg[0] != 'db') $ok=false;
  425. }
  426. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  427. $this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad.');
  428. //exit;
  429. // Test that output of $_SERVER\[\'QUERY_STRING\'\] is escaped.
  430. $ok=true;
  431. $matches=array();
  432. preg_match_all('/(..............)\$_SERVER\[\'QUERY_STRING\'\]/', $filecontent, $matches, PREG_SET_ORDER);
  433. foreach ($matches as $key => $val) {
  434. if ($val[1] != 'scape_htmltag(' && $val[1] != 'ing_nohtmltag(' && $val[1] != 'dol_escape_js(') {
  435. $ok=false;
  436. break;
  437. }
  438. }
  439. $this->assertTrue($ok, 'Found a $_SERVER[\'QUERY_STRING\'] without dol_escape_htmltag neither dol_string_nohtmltag around it, in file '.$file['relativename'].'. Bad.');
  440. // Check GETPOST(... 'none');
  441. $ok=true;
  442. $matches=array();
  443. preg_match_all('/GETPOST\s*\(([^\)]+),\s*["\']none["\']/i', $filecontent, $matches, PREG_SET_ORDER);
  444. foreach ($matches as $key => $val) {
  445. //var_dump($val);
  446. if (!in_array($val[1], array(
  447. "'replacestring'", "'htmlheader'", "'WEBSITE_HTML_HEADER'", "'WEBSITE_CSS_INLINE'", "'WEBSITE_JS_INLINE'", "'WEBSITE_MANIFEST_JSON'", "'PAGE_CONTENT'", "'WEBSITE_README'", "'WEBSITE_LICENSE'",
  448. '"mysqldump"', '"postgresqldump"',
  449. "'db_pass_root'", "'db_pass'", '"pass"', '"pass1"', '"pass2"', '"password"', "'password'",
  450. '"MAIN_MAIL_SMTPS_PW"', '"MAIN_MAIL_SMTPS_PW_EMAILING"', '"MAIN_MAIL_SMTPS_PW_TICKET"'))) {
  451. $ok=false;
  452. break;
  453. }
  454. //if ($reg[0] != 'db') $ok=false;
  455. }
  456. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  457. $this->assertTrue($ok, 'Found a GETPOST that use \'none\' as a parameter in file '.$file['relativename'].' and param is not an allowed parameter for using none - Bad.');
  458. //exit;
  459. // Test that first param of print_liste_field_titre is a translation key and not the translated value
  460. $ok=true;
  461. $matches=array();
  462. // Check string ='print_liste_field_titre\(\$langs'.
  463. preg_match_all('/print_liste_field_titre\(\$langs/', $filecontent, $matches, PREG_SET_ORDER);
  464. foreach ($matches as $key => $val) {
  465. $ok=false;
  466. break;
  467. }
  468. $this->assertTrue($ok, 'Found a use of print_liste_field_titre with first parameter that is a translated value instead of just the translation key in file '.$file['relativename'].'. Bad.');
  469. // Test we don't have <br />
  470. $ok=true;
  471. $matches=array();
  472. preg_match_all('/<br\s+\/>/', $filecontent, $matches, PREG_SET_ORDER);
  473. foreach ($matches as $key => $val) {
  474. if ($file['name'] != 'functions.lib.php') {
  475. $ok=false;
  476. break;
  477. }
  478. }
  479. $this->assertTrue($ok, 'Found a tag <br /> that is for xml in file '.$file['relativename'].'. You must use html syntax <br> instead.');
  480. // Test we don't have name="token" value="'.$_SESSION['newtoken'], we must use name="token" value="'.newToken() instead.
  481. $ok=true;
  482. $matches=array();
  483. preg_match_all('/name="token" value="\'\s*\.\s*\$_SESSION/', $filecontent, $matches, PREG_SET_ORDER);
  484. foreach ($matches as $key => $val) {
  485. if ($file['name'] != 'excludefile.php') {
  486. $ok=false;
  487. break;
  488. }
  489. }
  490. $this->assertTrue($ok, 'Found a forbidden string sequence into '.$file['relativename'].' : name="token" value="\'.$_SESSION[..., you must use a newToken() instead of $_SESSION[\'newtoken\'].');
  491. // Test we don't have preg_grep with a param without preg_quote
  492. $ok=true;
  493. $matches=array();
  494. preg_match_all('/preg_grep\(.*\$/', $filecontent, $matches, PREG_SET_ORDER);
  495. foreach ($matches as $key => $val) {
  496. if (strpos($val[0], 'preg_quote') === false) {
  497. $ok=false;
  498. break;
  499. }
  500. }
  501. $this->assertTrue($ok, 'Found a preg_grep with a param that is a $var but without preg_quote in file '.$file['relativename'].'.');
  502. // Test we don't have "if ($resql >"
  503. $ok=true;
  504. $matches=array();
  505. preg_match_all('/if \(\$resql >/', $filecontent, $matches, PREG_SET_ORDER);
  506. foreach ($matches as $key => $val) {
  507. $ok=false;
  508. break;
  509. }
  510. $this->assertTrue($ok, 'Found a if $resql with a > operator (when $resql is a boolean or resource) in file '.$file['relativename'].'. Please remove the > ... part.');
  511. // Test we don't have empty($user->hasRight
  512. $ok=true;
  513. $matches=array();
  514. preg_match_all('/empty\(\$user->hasRight/', $filecontent, $matches, PREG_SET_ORDER);
  515. foreach ($matches as $key => $val) {
  516. $ok=false;
  517. break;
  518. }
  519. $this->assertTrue($ok, 'Found code empty($user->hasRight in file '.$file['relativename'].'. empty() must not be used on a var not on a function.');
  520. // Test we don't have empty(DolibarrApiAccess::$user->hasRight
  521. $ok=true;
  522. $matches=array();
  523. preg_match_all('/empty\(DolibarrApiAccess::\$user->hasRight/', $filecontent, $matches, PREG_SET_ORDER);
  524. foreach ($matches as $key => $val) {
  525. $ok=false;
  526. break;
  527. }
  528. $this->assertTrue($ok, 'Found code empty(DolibarrApiAccess::$user->hasRight in file '.$file['relativename'].'. empty() must not be used on a var not on a function.');
  529. // Test we don't have empty($user->hasRight
  530. $ok=true;
  531. $matches=array();
  532. preg_match_all('/empty\(getDolGlobal/', $filecontent, $matches, PREG_SET_ORDER);
  533. foreach ($matches as $key => $val) {
  534. $ok=false;
  535. break;
  536. }
  537. $this->assertTrue($ok, 'Found code empty(getDolGlobal... in file '.$file['relativename'].'. empty() must be used on a var not on a function.');
  538. // Test we don't have @var array(
  539. $ok=true;
  540. $matches=array();
  541. preg_match_all('/@var\s+array\(/', $filecontent, $matches, PREG_SET_ORDER);
  542. foreach ($matches as $key => $val) {
  543. $ok=false;
  544. break;
  545. }
  546. $this->assertTrue($ok, 'Found a declaration @var array() instead of @var array in file '.$file['relativename'].'.');
  547. // Test we don't have CURDATE()
  548. $ok=true;
  549. $matches=array();
  550. preg_match_all('/CURDATE\(\)/', $filecontent, $matches, PREG_SET_ORDER);
  551. foreach ($matches as $key => $val) {
  552. $ok=false;
  553. break;
  554. }
  555. $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.');
  556. }
  557. return;
  558. }
  559. }