add a few more arguments
[civicrm-core.git] / tools / scripts / tpl-lint
CommitLineData
b63f5679
TO
1#!/usr/bin/env php
2<?php
3
4// FIXME: Make this a proper app with unit-tests
5
6$civi_pkgs_dir = dirname( dirname( dirname( __FILE__ ) ) ) . DIRECTORY_SEPARATOR . 'packages';
7require_once $civi_pkgs_dir . DIRECTORY_SEPARATOR . 'simple_html_dom.php';
8exit(main($argv));
9
10/**
11 * Scan a series of files for suspicious code
12 *
13 * example: find templates -name '*.tpl' | xargs php tools/scripts/tpl-lint
14 *
15 * @param array $argv
16 * @return int
17 */
18function main($argv) {
19 $files = $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);
24 });
25 }
26 return 0;
27}
28
29/**
30 * Scan a file for suspicious code
31 *
32 * @param string $file
33 * @param callable $reporter
34 * @return void
35 */
36function check_tpl($file, $reporter) {
37 $html = file_get_html($file);
38 foreach ($html->find('a') as $a) {
39 check_a($a, $reporter);
40 }
41}
42
43/**
44 * Scan an <A> tag
45 *
46 * @param object $a
47 * @param callable $reporter
48 * @return void
49 */
50function check_a($a, $reporter) {
51 if (!$a->hasAttribute('href')) {
52 // anchor, don't care
53 return;
54 }
55
56 $href = trim($a->getAttribute('href'));
57 if (preg_match('/javascript:/', $href)) {
58 $reporter('javascript-url', "<a> has javascript url: $href");
59 return;
60 }
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");
65 return;
66 }
67 }
68 if ($href != '#' && $a->hasAttribute('onclick')) {
69 $onclick = $a->getAttribute('onclick');
70 $reporter('a-double-action', "<a> has both URL ($href) and onclick ($onclick)");
71 return;
72 }
73}
74
75/**
76 * Determine if snippet of JS returns strictly false
d7c8cf03
EM
77 * @param $js
78 * @return bool
b63f5679
TO
79 */
80function js_returns_false($js) {
81 return
82 // last in a series of statements
83 preg_match('/; *return +false *; *$/', $js)
84 ||
85 // only statement
86 preg_match('/^ *return +false *;? *$/', $js);
87}
88
89/**
90 * Determine if snippet of JS returns a function call
d7c8cf03
EM
91 * @param $js
92 * @return int
b63f5679
TO
93 */
94function js_returns_func($js) {
95 return preg_match('/^ *return +[a-zA-Z0-9\._$]+\(/', $js);
96}