1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
#!/usr/bin/perl -w
# $Id: code-style.pl,v 1.14 2007/02/15 11:40:19 dries Exp $
use Pod::Usage;
use Getopt::Long qw(GetOptions);
Getopt::Long::Configure ("bundling");
my %opt = ( "help" => 0,
'debug' => 0,
);
if(!GetOptions(\%opt,
'help|?',
'debug',
)) {
pod2usage(-exitval => 1, 'verbose'=>0);
}
pod2usage(-exitval => 0, -verbose => 2) if($opt{'help'});
$debug = $opt{'debug'};
$comment = 0; #flag used to signal we're inside /* */
$program = 0; #flag used to signal we're inside <?php ?>
#read the file
while (<>) {
$org=$_;
s/\\["']//g;
# please don't use nested comments for now... thanks!
# handles comments // style, but don't mess with http://
s/\/\/[^:].*//;
# handles comments /**/ on a single line
s/\/\*.*\*\///g;
# handles comments /**/ over several lines
if ($comment == 1) {
if (s/.*\*\///) {
$comment = 0;
}
else {
next;
}
}
if (s/\/\*.*//) {
$comment = 1;
}
if (/^\s*#/) {
next;
}
if (s/<\?php//) {
$program = 1;
}
if (/\?>/) {
$program = 0;
}
# enforce "bar". foo() ."bar" syntax
if (/^("[^"]*"|[^"])*("[^"]*")\.[^ ]/ && $program) {
$msg = "'\".' -> '\". '";
}
elsif (/^("[^"]*"|[^"])*("[^"]*")\s+\./ && $program) {
$msg = "'\" .' -> '\".'";
}
# enforce "bar". foo() ."bar" syntax
elsif (/^("[^"]*"|[^"])*[^ "]\.("[^"]*")/ && $program) {
$msg = "'.\"' -> '.\"'";
}
elsif (/^("[^"]*"|[^"])*[^ "]\.\s+("[^"]*")/ && $program) {
$msg = "'. \"' -> '.\"'";
}
# XHTML requires closing tag
elsif (/<br>/i) {
$msg = "'<br>' -> '<br />'";
}
elsif (/\$REQUEST_URI/i) {
$msg = "the use of REQUEST_URI is prone to XSS exploits and does not work on IIS; use request_uri() instead";
}
elsif (/\"REQUEST_URI\"/i) {
$msg = "the use of REQUEST_URI is prone to XSS exploits and does not work on IIS; use request_uri() instead";
}
# XHTML compatibility mode suggests a blank before /
# i.e. <br />
elsif (/<[a-z][^>]*[^ >]\/>/i) {
$msg = "'<foo/".">' -> '<foo />'";
}
# we write '{' on the same line, not on the next
elsif (/^\s*{/ && $program) {
$msg = "take '{' to previous line";
}
elsif (/([a-z])([A-Z])/) {
$msg = "no mixed case function or variable names, use lower case and _";
}
elsif (/<[\/]*[A-Z]+[^>]*>/) {
$msg = "XHTML demands tags to be lowercase";
}
# trying to recognize splitted lines
# there are only a few valid last characters in programming mode,
# only sometimes it is ( if you use if/else with a single statement
# from here on we need no more strings
while (s/^([^"]*)"[^"]*"/$1#/) {};
while (s/^([^']*)'[^']*'/$1#/) {};
# it should be 'if (' all the time
if (/(^|[^a-zA-Z])(if|else|elseif|while|foreach|switch|return|for)\(/) {
$msg = "'(' -> ' ('";
}
#elsif (/[^;{}:\s\n]\s*\n*$/ && $program && !/^[\s}]*(if|else)/) {
# $msg = "don't split lines";
#}
elsif (/\}\s*else/) {
$msg = "'} else' -> '}\\nelse'";
}
elsif (/[^{\s\n]\s*\n*$/ && $program && /^\s*(if|else)/) {
$msg = "every if/else needs a { at eol";
}
elsif (/([\(\[]) / && $program) {
$msg = "'$1 ' -> '$1'";
}
elsif (/\S ([\)\]])/ && $program) {
$msg = "' $1' -> '$1'";
}
# but no brackets
elsif (/([a-z-A-Z_][a-zA-Z0-9_-]*)\s+\(/ && $program) {
if ($1 ne "switch" and $1 ne "if" and $1 ne "while" and $1 ne "foreach" and $1 ne "return" and $1 ne "for" and $1 ne "elseif") {
$msg = "'$1 (' -> '$1('";
}
}
# there should be a space before '{'
if (/[^ ]{/ && $program) {
$msg = "missing space before '{'";
}
# there should be a space after ','
elsif (/[,][^ \n\r]/ && $program) {
$msg = "missing space after ','";
}
# spaces before and after, only foreach may use $foo=>bar
elsif (/[^ =|\-|\+](\+|\-)[^ =>|\-|\+]/ && $program && !/foreach/) {
$msg = "'$1' -> ' $1 '";
}
elsif (/[^ =](\*|==|\.=|=>|=|\|\|)[^ =>]/ && $program && !/foreach/) {
$msg = "'$1' -> ' $1 '";
}
# ensure $bar["foo"] and $bar[$foo] and $bar[0]
elsif (/\[[^#][^\]]*\]/ && !/\[[0-9\$][^\]]*\]/ && !/\[\]/) {
$msg = "only [\"foo\"], [\$foo] or [0] is allowed";
}
# first try to find missing quotes after = in (X)HTML tags
elsif (/<[^>]*=[a-zA-Z0-9][^>]*>/) {
$msg = "=... -> =\"...\"";
}
if (defined $msg) {
if ($debug==0) {
print $ARGV .":". $. .": $msg : ". $org;
}
undef $msg;
}
elsif ($debug==1) {
print $org;
}
} continue {
close ARGV if eof;
}
__END__
=head1 NAME
code-style.pl - Review drupal code for style
=head1 SYNOPSIS
code-style.pl [options] <filename>
Options:
-? --help detailed help message
=head1 DESCRIPTION
Originally written for Drupal (http://drupal.org/) to ensure stylish
code. This program reviews PHP code, and tries to show as many code
improvements as possible with no false positives.
=head1 OPTIONS
--comment
=head1 EXAMPLES
./code-style.pl ../index.php
=cut
|