4 // FIXME: Make this a proper app with unit-tests
6 $civi_pkgs_dir = dirname(dirname(dirname(__FILE__
))) . DIRECTORY_SEPARATOR
. 'packages';
7 require_once $civi_pkgs_dir . DIRECTORY_SEPARATOR
. 'simple_html_dom.php';
11 * Scan a series of files for suspicious code
13 * example: find templates -name '*.tpl' | xargs php tools/scripts/tpl-lint
18 function main($argv) {
20 array_shift($files); // skip program name
21 foreach ($files as $file) {
22 check_tpl($file, function ($code, $message) use ($file) {
23 printf("[%s] %s\n", $file, $message);
30 * Scan a file for suspicious code
33 * @param callable $reporter
36 function check_tpl($file, $reporter) {
37 $html = file_get_html($file);
38 foreach ($html->find('a') as $a) {
39 check_a($a, $reporter);
47 * @param callable $reporter
50 function check_a($a, $reporter) {
51 if (!$a->hasAttribute('href')) {
56 $href = trim($a->getAttribute('href'));
57 if (preg_match('/javascript:/', $href)) {
58 $reporter('javascript-url', "<a> has javascript url: $href");
61 if ($href == '#' && $a->hasAttribute('onclick')) {
62 $onclick = $a->getAttribute('onclick');
63 if (!js_returns_false($onclick) && !js_returns_func($onclick)) {
64 $reporter('a-no-return', "<a> has href=# but handler fails to return false: $onclick");
68 if ($href != '#' && $a->hasAttribute('onclick')) {
69 $onclick = $a->getAttribute('onclick');
70 $reporter('a-double-action', "<a> has both URL ($href) and onclick ($onclick)");
76 * Determine if snippet of JS returns strictly false
80 function js_returns_false($js) {
82 // last in a series of statements
83 preg_match('/; *return +false *; *$/', $js)
86 preg_match('/^ *return +false *;? *$/', $js);
90 * Determine if snippet of JS returns a function call
94 function js_returns_func($js) {
95 return preg_match('/^ *return +[a-zA-Z0-9\._$]+\(/', $js);