CodingPhpTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  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\/includes\//', $file['fullname'])) {
  161. continue;
  162. }
  163. if (preg_match('/\/htdocs\/install\/doctemplates\/websites\//', $file['fullname'])) {
  164. continue;
  165. }
  166. if (preg_match('/\/htdocs\/custom\//', $file['fullname'])) {
  167. continue;
  168. }
  169. if (preg_match('/\/htdocs\/dolimed/', $file['fullname'])) {
  170. continue;
  171. }
  172. if (preg_match('/\/htdocs\/nltechno/', $file['fullname'])) {
  173. continue;
  174. }
  175. if (preg_match('/\/htdocs\/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. ))) {
  218. // Must not found $this->db->
  219. $ok=true;
  220. $matches=array();
  221. // Check string $this->db-> into a non class.php file (it shoud be $db-> into such classes)
  222. preg_match_all('/'.preg_quote('$this->db->', '/').'/', $filecontent, $matches, PREG_SET_ORDER);
  223. foreach ($matches as $key => $val) {
  224. $ok=false;
  225. break;
  226. }
  227. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  228. $this->assertTrue($ok, 'Found string "$this->db->" in '.$file['relativename']);
  229. //exit;
  230. }
  231. }
  232. // Check we don't miss top_httphead() into any ajax pages
  233. if (preg_match('/ajax\//', $file['relativename'])) {
  234. print "Analyze ajax page ".$file['relativename']."\n";
  235. $ok=true;
  236. $matches=array();
  237. preg_match_all('/top_httphead/', $filecontent, $matches, PREG_SET_ORDER);
  238. if (count($matches) == 0) {
  239. $ok=false;
  240. }
  241. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  242. $this->assertTrue($ok, 'Did not find top_httphead into the ajax page '.$file['relativename']);
  243. //exit;
  244. }
  245. // Check if a var_dump has been forgotten
  246. if (!preg_match('/test\/phpunit/', $file['fullname'])) {
  247. $ok=true;
  248. $matches=array();
  249. preg_match_all('/(.)\s*var_dump/', $filecontent, $matches, PREG_SET_ORDER);
  250. //var_dump($matches);
  251. foreach ($matches as $key => $val) {
  252. if ($val[1] != '/' && $val[1] != '*') {
  253. $ok=false;
  254. break;
  255. }
  256. break;
  257. }
  258. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  259. $this->assertTrue($ok, 'Found string var_dump that is not just after /* or // in '.$file['relativename']);
  260. //exit;
  261. }
  262. // Check get_class followed by __METHOD__
  263. $ok=true;
  264. $matches=array();
  265. preg_match_all('/'.preg_quote('get_class($this)."::".__METHOD__', '/').'/', $filecontent, $matches, PREG_SET_ORDER);
  266. foreach ($matches as $key => $val) {
  267. $ok=false;
  268. break;
  269. }
  270. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  271. $this->assertTrue($ok, 'Found string get_class($this)."::".__METHOD__ that must be replaced with __METHOD__ only in '.$file['relativename']);
  272. //exit;
  273. // Check string $this->db->idate without quotes
  274. $ok=true;
  275. $matches=array();
  276. preg_match_all('/(..)\s*\.\s*\$this->db->idate\(/', $filecontent, $matches, PREG_SET_ORDER);
  277. foreach ($matches as $key => $val) {
  278. if ($val[1] != '\'"' && $val[1] != '\'\'') {
  279. $ok=false;
  280. break;
  281. }
  282. //if ($reg[0] != 'db') $ok=false;
  283. }
  284. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  285. $this->assertTrue($ok, 'Found a $this->db->idate to forge a sql request without quotes around this date field '.$file['relativename']);
  286. //exit;
  287. // Check sql string DELETE|OR|AND|WHERE|INSERT ... yyy = ".$xxx
  288. // 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.
  289. $ok=true;
  290. $matches=array();
  291. preg_match_all('/(DELETE|OR|AND|WHERE|INSERT)\s.*([^\s][^\s][^\s])\s*=\s*(\'|")\s*\.\s*\$(...)/', $filecontent, $matches, PREG_SET_ORDER);
  292. foreach ($matches as $key => $val) {
  293. if ($val[2] == 'ity' && $val[4] == 'con') { // exclude entity = ".$conf->entity
  294. continue;
  295. }
  296. if ($val[2] == 'ame' && $val[4] == 'db-' && preg_match('/WHERE name/', $val[0])) { // exclude name = ".$db->encrypt(
  297. continue;
  298. }
  299. if ($val[2] == 'ame' && $val[4] == 'thi' && preg_match('/WHERE name/', $val[0])) { // exclude name = ".$this->db->encrypt(
  300. continue;
  301. }
  302. var_dump($matches);
  303. $ok=false;
  304. break;
  305. }
  306. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  307. $this->assertTrue($ok, 'Found non quoted or not casted var into sql request '.$file['relativename'].' - Bad.');
  308. //exit;
  309. // Check that forged sql string is using ' instead of " as string PHP quotes
  310. $ok=true;
  311. $matches=array();
  312. preg_match_all('/\$sql \.= \'\s*VALUES.*\$/', $filecontent, $matches, PREG_SET_ORDER);
  313. foreach ($matches as $key => $val) {
  314. //if ($val[1] != '\'"' && $val[1] != '\'\'') {
  315. var_dump($matches);
  316. $ok=false;
  317. break;
  318. //}
  319. //if ($reg[0] != 'db') $ok=false;
  320. }
  321. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  322. $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...');
  323. //exit;
  324. // Check that forged sql string is using ' instead of " as string PHP quotes
  325. $ok=true;
  326. $matches=array();
  327. preg_match_all('/\$sql \.?= \'SELECT.*\$/', $filecontent, $matches, PREG_SET_ORDER);
  328. foreach ($matches as $key => $val) {
  329. var_dump($matches);
  330. $ok=false;
  331. break;
  332. }
  333. $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...');
  334. // Check sql string VALUES ... , ".$xxx
  335. // 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.
  336. $ok=true;
  337. $matches=array();
  338. preg_match_all('/(VALUES).*,\s*"\s*\.\s*\$(...)/', $filecontent, $matches, PREG_SET_ORDER);
  339. foreach ($matches as $key => $val) {
  340. if ($val[1] == 'VALUES' && $val[2] == 'db-') { // exclude $db->escape(
  341. continue;
  342. }
  343. if ($val[1] == 'VALUES' && $val[2] == 'thi' && preg_match('/this->db->encrypt/', $val[0])) { // exclude ".$this->db->encrypt(
  344. continue;
  345. }
  346. var_dump($matches);
  347. $ok=false;
  348. break;
  349. }
  350. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  351. $this->assertTrue($ok, 'Found non quoted or not casted var into sql request '.$file['relativename'].' - Bad.');
  352. //exit;
  353. // Check '".$xxx non escaped
  354. // Check string ='".$this->xxx with xxx that is not 'escape'. It means we forget a db->escape when forging sql request.
  355. $ok=true;
  356. $matches=array();
  357. preg_match_all('/=\s*\'"\s*\.\s*\$this->(....)/', $filecontent, $matches, PREG_SET_ORDER);
  358. foreach ($matches as $key => $val) {
  359. if ($val[1] != 'db->' && $val[1] != 'esca') {
  360. $ok=false;
  361. break;
  362. }
  363. }
  364. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  365. $this->assertTrue($ok, 'Found non escaped string in building of a sql request (case 1) in '.$file['relativename'].' - Bad.');
  366. // 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.
  367. $ok=true;
  368. $matches=array();
  369. preg_match_all('/(sql|SET|WHERE|INSERT|VALUES|LIKE).+\s*\'"\s*\.\s*\$(.......)/', $filecontent, $matches, PREG_SET_ORDER);
  370. foreach ($matches as $key => $val) {
  371. if (! in_array($val[2], array('this->d', 'this->e', 'db->esc', 'dbs->es', 'dbs->id', 'mydb->e', 'dbsessi', 'db->ida', 'escaped', 'exclude', 'include'))) {
  372. $ok=false; // This will generate error
  373. break;
  374. }
  375. //if ($reg[0] != 'db') $ok=false;
  376. }
  377. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  378. $this->assertTrue($ok, 'Found non escaped string in building of a sql request (case 2) in '.$file['relativename'].': '.$val[0].' - Bad.');
  379. //exit;
  380. // Check string sql|set...'.$yyy->xxx with xxx that is not 'escape', 'idate', .... It means we forget a db->escape when forging sql request.
  381. $ok=true;
  382. $matches=array();
  383. preg_match_all('/(\$sql|SET\s|WHERE\s|INSERT\s|VALUES\s|VALUES\().+\s*\'\s*\.\s*\$(.........)/', $filecontent, $matches, PREG_SET_ORDER);
  384. foreach ($matches as $key => $val) {
  385. if (! in_array($val[2], array('this->db-', 'db->prefi', 'db->sanit', 'dbs->pref', 'dbs->sani', 'conf->ent', 'key : \'\')', 'key])."\')', 'excludefi', 'regexstri', ''))) {
  386. $ok=false;
  387. var_dump($matches);
  388. break;
  389. }
  390. //if ($reg[0] != 'db') $ok=false;
  391. }
  392. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  393. $this->assertTrue($ok, 'Found non escaped string in building of a sql request (case 3) in '.$file['relativename'].': '.$val[0].' - Bad.');
  394. //exit;
  395. // Checks with IN
  396. // 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.
  397. $ok=true;
  398. $matches=array();
  399. preg_match_all('/\s+IN\s*\([\'"]\s*\.\s*(.........)/i', $filecontent, $matches, PREG_SET_ORDER);
  400. foreach ($matches as $key => $val) {
  401. //var_dump($val);
  402. if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) {
  403. $ok=false;
  404. break;
  405. }
  406. //if ($reg[0] != 'db') $ok=false;
  407. }
  408. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  409. $this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad.');
  410. //exit;
  411. // 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.
  412. $ok=true;
  413. $matches=array();
  414. preg_match_all('/\s+IN\s*\(\'"\s*\.\s*(.........)/i', $filecontent, $matches, PREG_SET_ORDER);
  415. foreach ($matches as $key => $val) {
  416. //var_dump($val);
  417. if (!in_array($val[1], array('$db->sani', '$this->db', 'getEntity', 'WON\',\'L', 'self::STA', 'Commande:', 'CommandeF', 'Entrepot:', 'Facture::', 'FactureFo', 'ExpenseRe', 'Societe::', 'Ticket::S'))) {
  418. $ok=false;
  419. break;
  420. }
  421. //if ($reg[0] != 'db') $ok=false;
  422. }
  423. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  424. $this->assertTrue($ok, 'Found non sanitized string in building of a IN or NOT IN sql request '.$file['relativename'].' - Bad.');
  425. //exit;
  426. // Test that output of $_SERVER\[\'QUERY_STRING\'\] is escaped.
  427. $ok=true;
  428. $matches=array();
  429. preg_match_all('/(..............)\$_SERVER\[\'QUERY_STRING\'\]/', $filecontent, $matches, PREG_SET_ORDER);
  430. foreach ($matches as $key => $val) {
  431. if ($val[1] != 'scape_htmltag(' && $val[1] != 'ing_nohtmltag(' && $val[1] != 'dol_escape_js(') {
  432. $ok=false;
  433. break;
  434. }
  435. }
  436. $this->assertTrue($ok, 'Found a $_SERVER[\'QUERY_STRING\'] without dol_escape_htmltag neither dol_string_nohtmltag around it, in file '.$file['relativename'].'. Bad.');
  437. // Check GETPOST(... 'none');
  438. $ok=true;
  439. $matches=array();
  440. preg_match_all('/GETPOST\s*\(([^\)]+),\s*["\']none["\']/i', $filecontent, $matches, PREG_SET_ORDER);
  441. foreach ($matches as $key => $val) {
  442. //var_dump($val);
  443. if (!in_array($val[1], array(
  444. "'replacestring'", "'htmlheader'", "'WEBSITE_HTML_HEADER'", "'WEBSITE_CSS_INLINE'", "'WEBSITE_JS_INLINE'", "'WEBSITE_MANIFEST_JSON'", "'PAGE_CONTENT'", "'WEBSITE_README'", "'WEBSITE_LICENSE'",
  445. '"mysqldump"', '"postgresqldump"',
  446. "'db_pass_root'", "'db_pass'", '"pass"', '"pass1"', '"pass2"', '"password"', "'password'",
  447. '"MAIN_MAIL_SMTPS_PW"', '"MAIN_MAIL_SMTPS_PW_EMAILING"', '"MAIN_MAIL_SMTPS_PW_TICKET"'))) {
  448. $ok=false;
  449. break;
  450. }
  451. //if ($reg[0] != 'db') $ok=false;
  452. }
  453. //print __METHOD__." Result for checking we don't have non escaped string in sql requests for file ".$file."\n";
  454. $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.');
  455. //exit;
  456. // Test that first param of print_liste_field_titre is a translation key and not the translated value
  457. $ok=true;
  458. $matches=array();
  459. // Check string ='print_liste_field_titre\(\$langs'.
  460. preg_match_all('/print_liste_field_titre\(\$langs/', $filecontent, $matches, PREG_SET_ORDER);
  461. foreach ($matches as $key => $val) {
  462. $ok=false;
  463. break;
  464. }
  465. $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.');
  466. // Test we don't have <br />
  467. $ok=true;
  468. $matches=array();
  469. preg_match_all('/<br\s+\/>/', $filecontent, $matches, PREG_SET_ORDER);
  470. foreach ($matches as $key => $val) {
  471. if ($file['name'] != 'functions.lib.php') {
  472. $ok=false;
  473. break;
  474. }
  475. }
  476. $this->assertTrue($ok, 'Found a tag <br /> that is for xml in file '.$file['relativename'].'. You must use html syntax <br> instead.');
  477. // Test we don't have name="token" value="'.$_SESSION['newtoken'], we must use name="token" value="'.newToken() instead.
  478. $ok=true;
  479. $matches=array();
  480. preg_match_all('/name="token" value="\'\s*\.\s*\$_SESSION/', $filecontent, $matches, PREG_SET_ORDER);
  481. foreach ($matches as $key => $val) {
  482. if ($file['name'] != 'excludefile.php') {
  483. $ok=false;
  484. break;
  485. }
  486. }
  487. $this->assertTrue($ok, 'Found a forbidden string sequence into '.$file['relativename'].' : name="token" value="\'.$_SESSION[..., you must use a newToken() instead of $_SESSION[\'newtoken\'].');
  488. // Test we don't have preg_grep with a param without preg_quote
  489. $ok=true;
  490. $matches=array();
  491. preg_match_all('/preg_grep\(.*\$/', $filecontent, $matches, PREG_SET_ORDER);
  492. foreach ($matches as $key => $val) {
  493. if (strpos($val[0], 'preg_quote') === false) {
  494. $ok=false;
  495. break;
  496. }
  497. }
  498. $this->assertTrue($ok, 'Found a preg_grep with a param that is a $var but without preg_quote in file '.$file['relativename'].'.');
  499. // Test we don't have "if ($resql >"
  500. $ok=true;
  501. $matches=array();
  502. preg_match_all('/if \(\$resql >/', $filecontent, $matches, PREG_SET_ORDER);
  503. foreach ($matches as $key => $val) {
  504. $ok=false;
  505. break;
  506. }
  507. $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.');
  508. // Test we don't have empty($user->hasRight
  509. $ok=true;
  510. $matches=array();
  511. preg_match_all('/empty\(\$user->hasRight/', $filecontent, $matches, PREG_SET_ORDER);
  512. foreach ($matches as $key => $val) {
  513. $ok=false;
  514. break;
  515. }
  516. $this->assertTrue($ok, 'Found code empty($user->hasRight in file '.$file['relativename'].'. empty() must not be used with hasRight.');
  517. // Test we don't have empty(DolibarrApiAccess::$user->hasRight
  518. $ok=true;
  519. $matches=array();
  520. preg_match_all('/empty\(DolibarrApiAccess::\$user->hasRight/', $filecontent, $matches, PREG_SET_ORDER);
  521. foreach ($matches as $key => $val) {
  522. $ok=false;
  523. break;
  524. }
  525. $this->assertTrue($ok, 'Found code empty(DolibarrApiAccess::$user->hasRight in file '.$file['relativename'].'. empty() must not be used with hasRight.');
  526. // Test we don't have @var array(
  527. $ok=true;
  528. $matches=array();
  529. preg_match_all('/@var\s+array\(/', $filecontent, $matches, PREG_SET_ORDER);
  530. foreach ($matches as $key => $val) {
  531. $ok=false;
  532. break;
  533. }
  534. $this->assertTrue($ok, 'Found a declaration @var array() instead of @var array in file '.$file['relativename'].'.');
  535. // Test we don't have CURDATE()
  536. $ok=true;
  537. $matches=array();
  538. preg_match_all('/CURDATE\(\)/', $filecontent, $matches, PREG_SET_ORDER);
  539. foreach ($matches as $key => $val) {
  540. $ok=false;
  541. break;
  542. }
  543. $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.');
  544. }
  545. return;
  546. }
  547. }