├── perl
├── 0.a
│ ├── .htaccess
│ └── 1.a
│ │ ├── .htaccess
│ │ └── 2.a
│ │ ├── .htaccess
│ │ └── 3.a
│ │ └── .htaccess
├── 0.b
│ ├── .htaccess
│ └── 1.d
│ │ ├── .htaccess
│ │ └── 2.b
│ │ └── .htaccess
├── 0.c
│ ├── .htaccess
│ └── 1.g
│ │ └── .htaccess
├── htconf.php
├── htconf.pl
├── htcrawler.php
├── htcrawler.pl
└── diffplphp.diff
├── README
└── htaccess.php
/perl/0.a/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.b/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.c/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.a/1.a/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.b/1.d/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.c/1.g/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.a/1.a/2.a/.htaccess:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/perl/0.a/1.a/2.a/3.a/.htaccess:
--------------------------------------------------------------------------------
1 | ApacheParam 1
2 | ApacheParam 2
3 |
--------------------------------------------------------------------------------
/perl/0.b/1.d/2.b/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | ##Comment line!
3 | ##
4 | RedirectBase blalbh
5 | SomethingElse
6 | ApacheParam3 doo
7 | RedirectBase Again!
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This script recursively searches from the present working directory for .htaccess files. It converts the directives found within the .htaccess files into the apropriate format for addition within the httpd.conf configuration file.
2 |
3 | This is useful as .htaccess files are incredibly easy to work with during development, but a major performance issue in production. Get the best of both worlds, let your devs work on the fly, then merge as part of your deployment process
4 |
5 |
6 |
--------------------------------------------------------------------------------
/perl/htconf.php:
--------------------------------------------------------------------------------
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 | ##Comment line!
32 | ##
33 | RedirectBase blalbh
34 | # WARNING The above line contains RedirectBase which may not convert directly to a conf file. Please check manually
35 | SomethingElse
36 | ApacheParam3 doo
37 | RedirectBase Again!
38 | # WARNING The above line contains RedirectBase which may not convert directly to a conf file. Please check manually
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | ApacheParam 1
52 | ApacheParam 2
53 |
54 |
55 | # A total of 2 warnings were encountered. Please read through the file and correct any noted problems
56 | # Please test before going live, no guarantees!
57 |
--------------------------------------------------------------------------------
/perl/htconf.pl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ##Comment line!
19 | ##
20 |
21 | ####WARNING! RedirectBase' does't convert correctly. Check manually!
22 | RedirectBase blalbh
23 | SomethingElse
24 |
25 | ####WARNING! Apache params not supported. ;-)
26 | ApacheParam3 doo
27 |
28 | ####WARNING! RedirectBase' does't convert correctly. Check manually!
29 | RedirectBase Again!
30 |
31 |
32 |
33 | ####WARNING! Apache params not supported. ;-)
34 | ApacheParam 1
35 |
36 | ####WARNING! Apache params not supported. ;-)
37 | ApacheParam 2
38 |
39 |
40 | ######################################################
41 | #Total Warnings: 5
42 | #%ErrorTypeFound = (
43 | # 'RedirectBase' => 2,
44 | # 'OtherParamLabel' => 3
45 | # );
46 | ######################################################
47 |
48 | ######################################################
49 | ## Total Files processed: 10
50 | ######################################################
51 |
52 | ## Please test before going live, no guarantees!
53 |
--------------------------------------------------------------------------------
/perl/htcrawler.php:
--------------------------------------------------------------------------------
1 | php htaccess.php > ~/htaccess.conf
12 | * Filtering to exclude (substring match)
13 | * /var/www/domain.com> php htaccess.php evilDirectory > ~/htaccess.conf
14 | */
15 |
16 | //Start from the present working directory, recurse from here. Using the real path avoids a bug where .htaccess files in the PWD are omitted from results on some systems
17 | $startPath = realpath("./");
18 | $ite= new RecursiveDirectoryIterator($startPath);
19 |
20 | //Lets give people a hand, skip these directories. Especially helpful when run on dev systems
21 | $filters = array(".svn", ".cvs");
22 |
23 | //Merge base set of filters with any from the command line
24 | if(count($argv) > 0)
25 | {
26 | unset($argv[0]);
27 | $filters = array_merge($filters, $argv);
28 | }
29 |
30 | //Iterate recursively through everything from here on in, of course filtering out stuff from the filter list
31 | foreach (new fileFilter(new RecursiveIteratorIterator($ite), $filters) as $filename=>$cur)
32 | {
33 | $htaccessFiles[] = $filename;
34 | }
35 |
36 | //No files? Quit now!
37 | if (count($htaccessFiles) == 0)
38 | {
39 | die("No .htaccess files found");
40 | }
41 |
42 | //Sort the list, place least depth first. This is important to allow overrides from sub-directories to occur correctly
43 | usort($htaccessFiles, 'sorter');
44 |
45 | //Warnings encountered
46 | $flags = 0;
47 |
48 | //Iterate over found files (sorted now) and read them in.
49 | foreach($htaccessFiles as $file)
50 | {
51 | //Grab the file and print out the bit
52 | $path = realpath(pathinfo($file, PATHINFO_DIRNAME));
53 | echo "\n";
54 | $lines = file($file);
55 | if(count($lines) > 0)
56 | {
57 | //Tab the file in, check for RedirectBase which may cause problems
58 | foreach($lines as $line)
59 | {
60 | echo "\t$line";
61 | if(stripos($line, "RedirectBase") !== FALSE)
62 | {
63 | //Not tabbed! See what happens there?
64 | echo "# WARNING The above line contains RedirectBase which may not convert directly to a conf file. Please check manually\n";
65 | $flags++;
66 | }
67 | }
68 |
69 | //Handle issues where files don't end with a newline
70 | if (in_array(substr($line, -1), array("\n", "\r")))
71 | {
72 | echo "\n\n";
73 | }else
74 | {
75 | echo "\n\n\n";
76 | }
77 | }else{
78 | //File was empty, leave the stub in
79 | echo "\n\n\n";
80 | }
81 | }
82 |
83 | //Check for warnings
84 | if ($flags > 0)
85 | {
86 | echo "# A total of $flags warnings were encountered. Please read through the file and correct any noted problems\n";
87 | }else
88 | {
89 | echo "# No warnings detected \n";
90 | }
91 |
92 | echo "# Please test before going live, no guarantees! \n";
93 |
94 |
95 |
96 |
97 | //Sort by the number of path segments, least first
98 | function sorter($a, $b)
99 | {
100 | $a = count(explode("/", $a));
101 | $b = count(explode("/", $b));
102 | if($a == $b)
103 | {
104 | return 0;
105 | }
106 | if($a > $b)
107 | {
108 | return 1;
109 | }
110 | return -1;
111 | }
112 |
113 |
114 |
115 | //Filter out specified files.
116 | class fileFilter extends FilterIterator
117 | {
118 | private $filters;
119 | public function __construct(Iterator $iterator, $filters)
120 | {
121 | parent::__construct($iterator);
122 | $this->filters = $filters;
123 | }
124 |
125 | public function accept()
126 | {
127 | $dir = $this->getInnerIterator()->current();
128 | foreach($this->filters as $filter)
129 | {
130 | if(strpos($dir, $filter) !== false)
131 | {
132 | return false;
133 | }
134 | }
135 |
136 | if (strpos($dir, ".htaccess") !== false)
137 | {
138 | return true;
139 | }
140 | //echo "Skipping $dir\n";
141 | return false;
142 | }
143 | }
144 |
145 |
--------------------------------------------------------------------------------
/htaccess.php:
--------------------------------------------------------------------------------
1 | php htaccess.php > ~/htaccess.conf
20 | * Filtering to exclude (substring match)
21 | * /var/www/domain.com> php htaccess.php evilDirectory > ~/htaccess.conf
22 | */
23 |
24 | //Start from the present working directory, recurse from here. Using the real path avoids a bug where .htaccess files in the PWD are omitted from results on some systems
25 | $startPath = realpath("./");
26 | $ite= new RecursiveDirectoryIterator($startPath);
27 |
28 | //Lets give people a hand, skip these directories. Especially helpful when run on dev systems
29 | $filters = array(".svn", ".cvs", ".git");
30 |
31 | //Merge base set of filters with any from the command line
32 | if(count($argv) > 0)
33 | {
34 | unset($argv[0]);
35 | $filters = array_merge($filters, $argv);
36 | }
37 |
38 | //Iterate recursively through everything from here on in, of course filtering out stuff from the filter list
39 | foreach (new fileFilter(new RecursiveIteratorIterator($ite), $filters) as $filename=>$cur)
40 | {
41 | $htaccessFiles[] = $filename;
42 | }
43 |
44 | //No files? Quit now!
45 | if (count($htaccessFiles) == 0)
46 | {
47 | die("No .htaccess files found");
48 | }
49 |
50 | //Sort the list, place least depth first. This is important to allow overrides from sub-directories to occur correctly
51 | usort($htaccessFiles, 'sorter');
52 |
53 | //Warnings encountered
54 | $flags = 0;
55 |
56 | //Iterate over found files (sorted now) and read them in.
57 | foreach($htaccessFiles as $file)
58 | {
59 | //Grab the file and print out the bit
60 | $path = realpath(pathinfo($file, PATHINFO_DIRNAME));
61 | echo "\n";
62 | $lines = file($file);
63 | if(count($lines) > 0)
64 | {
65 | //Tab the file in, check for RedirectBase which may cause problems
66 | foreach($lines as $line)
67 | {
68 | echo "\t$line";
69 | if(stripos($line, "RedirectBase") !== FALSE)
70 | {
71 | //Not tabbed! See what happens there?
72 | echo "# WARNING The above line contains RedirectBase which may not convert directly to a conf file. Please check manually\n";
73 | $flags++;
74 | }
75 | }
76 |
77 | //Handle issues where files don't end with a newline
78 | if (in_array(substr($line, -1), array("\n", "\r")))
79 | {
80 | echo "\n\n";
81 | }else
82 | {
83 | echo "\n\n\n";
84 | }
85 | }else{
86 | //File was empty, leave the stub in
87 | echo "\n\n\n";
88 | }
89 | }
90 |
91 | //Check for warnings
92 | if ($flags > 0)
93 | {
94 | echo "# A total of $flags warnings were encountered. Please read through the file and correct any noted problems\n";
95 | }else
96 | {
97 | echo "# No warnings detected \n";
98 | }
99 |
100 | echo "# Please test before going live, no guarantees! \n";
101 |
102 |
103 |
104 |
105 | //Sort by the number of path segments, least first
106 | function sorter($a, $b)
107 | {
108 | $a = count(explode("/", $a));
109 | $b = count(explode("/", $b));
110 | if($a == $b)
111 | {
112 | return 0;
113 | }
114 | if($a > $b)
115 | {
116 | return 1;
117 | }
118 | return -1;
119 | }
120 |
121 |
122 |
123 | //Filter out specified files.
124 | class fileFilter extends FilterIterator
125 | {
126 | private $filters;
127 | public function __construct(Iterator $iterator, $filters)
128 | {
129 | parent::__construct($iterator);
130 | $this->filters = $filters;
131 | }
132 |
133 | public function accept()
134 | {
135 | $dir = $this->getInnerIterator()->current();
136 | foreach($this->filters as $filter)
137 | {
138 | if(strpos($dir, $filter) !== false)
139 | {
140 | return false;
141 | }
142 | }
143 |
144 | $filename = DIRECTORY_SEPARATOR . '.htaccess';
145 | if (substr($dir, - strlen($filename), strlen($filename)) == $filename)
146 | {
147 | return true;
148 | }
149 | //echo "Skipping $dir\n";
150 | return false;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/perl/htcrawler.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | ##
3 | # 2009 Kurt P. Hundeck (whereiskurt@gmail.com)
4 | #
5 | # Recursively search through '--path' for files that match '--match' regex,
6 | # slurp those files up, and output them as descendents of apache conf
7 | # '$slurped htaccess.conf
11 | # or
12 | # perl htcrawler.pl --path=./ --match='\.htaccess$' > htaccess.conf
13 | # or
14 | # ./htcrawler.pl --path=/var/www/somesite.com/ > somesite.com.conf
15 | #
16 | # NOTE: It's the 'AccessFileName .htaccess' (default), it *could* be something
17 | # else, use '--match' to override.
18 | #
19 | use strict;
20 | use warnings;
21 |
22 | use English;
23 | use Data::Dumper;
24 | use Getopt::Long qw(GetOptions);
25 | use File::Find qw(find);
26 | use File::Spec::Functions qw(rel2abs splitdir);
27 | use File::Basename qw(dirname);
28 |
29 | ##Set some reasonable defaults
30 | my %argv = (
31 | 'startpath' => dirname(rel2abs($0)), ## Real fullpath of script, default.
32 | 'match' => qr{\.htaccess$}, ## Regex for ".htaccess" files
33 | 'skip' => qr{^((.cvs)|(.svn))$},
34 | );
35 |
36 | ##Parse commandline
37 | GetOptions ( 'startpath|path=s' => \$argv{'startpath'} ,
38 | 'match=s' => \$argv{'match'} ,
39 | 'skip=s' => \$argv{'skip'} ,
40 | ) or die "Can't parse commandline (!)";
41 |
42 | my @matches; ##Holds the fullnames of matching files (/dir1/dir2/.htaccess)
43 |
44 | ##Find files that match our criteria.
45 | File::Find::find({ 'preprocess' => \&skiprcs , #Filter hook
46 | 'wanted' => \&wanted , } #Check match hook
47 | , $argv{'startpath'});
48 |
49 | sub skiprcs {
50 | ## 'grep' through the arglist (@_) and return things that
51 | ## don't match .cvs|.svn
52 | return grep { !/$argv{'skip'}/ } @_;
53 | };
54 |
55 | sub wanted {
56 | ##Add *fullpath* filename to matches, if we matched.
57 | if ($File::Find::name =~ m/$argv{'match'}/i) {
58 | push @matches, $File::Find::name;
59 | }
60 | }
61 |
62 | if (not @matches ) {
63 | die "No files matched '$argv{'match'}' in path '$argv{'startpath'}'.\n";
64 | }
65 |
66 | ##Sort by shortest path depth (ie. '/folder' before '/folder/subfolder')
67 | ##by comparying the length of arrays returned by 'splitdir'
68 | @matches = sort { splitdir($a) <=> splitdir($b) } @matches;
69 |
70 | my (%errflag, $errcount);
71 |
72 | ## Hash lookup to support different failures for conversion. Certain
73 | ## pragmas won't convert 1-to-1 (like "RedirectBase"), these are the rules.
74 | my %error_lkp = (
75 | 'RedirectBase' => {
76 | 're'=>qr/RedirectBase/ix,
77 | 'msg'=>"##WARNING! RedirectBase' does't convert correctly. Check manually!",
78 | },
79 | 'OtherParamLabel' => {
80 | 're'=>qr/ApacheParam*/ix,
81 | 'msg'=>"##WARNING! Apache params not supported. ;-)"
82 | },
83 | );
84 |
85 | foreach my $file (@matches) {
86 | ##Perl5 'slurp' $file idiom
87 | my $text = do { local( @ARGV, $RS ) = $file ; <> } ;
88 |
89 | if ($text) {
90 | ##Cleanup leading/trailing whitespace
91 | $text =~ s/^(.+?)\s*$/$1/gmix; #ltrim()
92 | $text =~ s/^\s*(.+?)$/$1/gmix; #rtrim()
93 |
94 | # Use the error lookup to see if the text contains things that don't
95 | # convert from .htaccess (like RedirectBase..)
96 | while( my ($key, $value) = each(%error_lkp)) {
97 | my $re = $value->{'re'}; #Each error has it's own match pattern
98 | my $msg = $value->{'msg'}; #and error message.
99 |
100 | ##If the text matched the error regex, insert a warning $msg
101 | ## and track/count it.
102 | if (my $count = $text =~ s/^(.*?$re.*?)$/$RS##$msg$RS$1/gmix) {
103 | $errflag{$key}+=$count;
104 | $errcount +=$count;
105 | }
106 | }
107 |
108 | ##Add a "tab" infront of each line
109 | $text =~ s/^(.+?)$/\t$1/gmix;
110 | ##Add a newline, back.
111 | $text .= $RS;
112 | }
113 | else {
114 | $text = ""; ##NOTE: $text is undef until we make it an "empty string"
115 | }
116 |
117 | my $dir = dirname($file);
118 | print "$RS";
119 | print $text;
120 | print "$RS";
121 |
122 | }
123 |
124 | ## Output a commented block (Apache style) with any erros we found.
125 | if ($errcount > 0) {
126 | ##Convert our %errflag to a nicely Dump'd output.
127 | my $errors = Data::Dumper->Dump( [ \%errflag ], [ qw(*ErrorTypeFound) ] );
128 |
129 | ##Append '#' infront of each line of $errors.
130 | $errors =~ s/^(.+?)$/#$1/gmix;
131 |
132 | print $RS;
133 | print "######################################################$RS";
134 | print "#Total Warnings: $errcount $RS";
135 | print $errors;
136 | print "######################################################$RS";
137 | print $RS;
138 | }
139 |
140 | print "######################################################$RS";
141 | print "## Total Files processed: " . scalar @matches . $RS;
142 | print "######################################################$RS";
143 | print $RS;
144 | print "## Please test before going live, no guarantees! $RS";
145 |
--------------------------------------------------------------------------------
/perl/diffplphp.diff:
--------------------------------------------------------------------------------
1 | 1,144c1,144
2 | < php htaccess.php > ~/htaccess.conf
13 | < * Filtering to exclude (substring match)
14 | < * /var/www/domain.com> php htaccess.php evilDirectory > ~/htaccess.conf
15 | < */
16 | <
17 | < //Start from the present working directory, recurse from here. Using the real path avoids a bug where .htaccess files in the PWD are omitted from results on some systems
18 | < $startPath = realpath("./");
19 | < $ite= new RecursiveDirectoryIterator($startPath);
20 | <
21 | < //Lets give people a hand, skip these directories. Especially helpful when run on dev systems
22 | < $filters = array(".svn", ".cvs");
23 | <
24 | < //Merge base set of filters with any from the command line
25 | < if(count($argv) > 0)
26 | < {
27 | < unset($argv[0]);
28 | < $filters = array_merge($filters, $argv);
29 | < }
30 | <
31 | < //Iterate recursively through everything from here on in, of course filtering out stuff from the filter list
32 | < foreach (new fileFilter(new RecursiveIteratorIterator($ite), $filters) as $filename=>$cur)
33 | < {
34 | < $htaccessFiles[] = $filename;
35 | < }
36 | <
37 | < //No files? Quit now!
38 | < if (count($htaccessFiles) == 0)
39 | < {
40 | < die("No .htaccess files found");
41 | < }
42 | <
43 | < //Sort the list, place least depth first. This is important to allow overrides from sub-directories to occur correctly
44 | < usort($htaccessFiles, 'sorter');
45 | <
46 | < //Warnings encountered
47 | < $flags = 0;
48 | <
49 | < //Iterate over found files (sorted now) and read them in.
50 | < foreach($htaccessFiles as $file)
51 | < {
52 | < //Grab the file and print out the bit
53 | < $path = realpath(pathinfo($file, PATHINFO_DIRNAME));
54 | < echo "\n";
55 | < $lines = file($file);
56 | < if(count($lines) > 0)
57 | < {
58 | < //Tab the file in, check for RedirectBase which may cause problems
59 | < foreach($lines as $line)
60 | < {
61 | < echo "\t$line";
62 | < if(stripos($line, "RedirectBase") !== FALSE)
63 | < {
64 | < //Not tabbed! See what happens there?
65 | < echo "# WARNING The above line contains RedirectBase which may not convert directly to a conf file. Please check manually\n";
66 | < $flags++;
67 | < }
68 | < }
69 | <
70 | < //Handle issues where files don't end with a newline
71 | < if (in_array(substr($line, -1), array("\n", "\r")))
72 | < {
73 | < echo "\n\n";
74 | < }else
75 | < {
76 | < echo "\n\n\n";
77 | < }
78 | < }else{
79 | < //File was empty, leave the stub in
80 | < echo "\n\n\n";
81 | < }
82 | < }
83 | <
84 | < //Check for warnings
85 | < if ($flags > 0)
86 | < {
87 | < echo "# A total of $flags warnings were encountered. Please read through the file and correct any noted problems\n";
88 | < }else
89 | < {
90 | < echo "# No warnings detected \n";
91 | < }
92 | <
93 | < echo "# Please test before going live, no guarantees! \n";
94 | <
95 | <
96 | <
97 | <
98 | < //Sort by the number of path segments, least first
99 | < function sorter($a, $b)
100 | < {
101 | < $a = count(explode("/", $a));
102 | < $b = count(explode("/", $b));
103 | < if($a == $b)
104 | < {
105 | < return 0;
106 | < }
107 | < if($a > $b)
108 | < {
109 | < return 1;
110 | < }
111 | < return -1;
112 | < }
113 | <
114 | <
115 | <
116 | < //Filter out specified files.
117 | < class fileFilter extends FilterIterator
118 | < {
119 | < private $filters;
120 | < public function __construct(Iterator $iterator, $filters)
121 | < {
122 | < parent::__construct($iterator);
123 | < $this->filters = $filters;
124 | < }
125 | <
126 | < public function accept()
127 | < {
128 | < $dir = $this->getInnerIterator()->current();
129 | < foreach($this->filters as $filter)
130 | < {
131 | < if(strpos($dir, $filter) !== false)
132 | < {
133 | < return false;
134 | < }
135 | < }
136 | <
137 | < if (strpos($dir, ".htaccess") !== false)
138 | < {
139 | < return true;
140 | < }
141 | < //echo "Skipping $dir\n";
142 | < return false;
143 | < }
144 | < }
145 | <
146 | ---
147 | > #!/usr/bin/perl
148 | > ##
149 | > # 2009 Kurt P. Hundeck (whereiskurt@gmail.com)
150 | > #
151 | > # Recursively search through '--path' for files that match '--match' regex,
152 | > # slurp those files up, and output them as descendents of apache conf
153 | > # '$slurped #
155 | > # Usage:
156 | > # perl htcrawler.pl > htaccess.conf
157 | > # or
158 | > # perl htcrawler.pl --path=./ --match='\.htaccess$' > htaccess.conf
159 | > # or
160 | > # ./htcrawler.pl --path=/var/www/somesite.com/ > somesite.com.conf
161 | > #
162 | > # NOTE: It's the 'AccessFileName .htaccess' (default), it *could* be something
163 | > # else, use '--match' to override.
164 | > #
165 | > use strict;
166 | > use warnings;
167 | >
168 | > use English;
169 | > use Data::Dumper;
170 | > use Getopt::Long qw(GetOptions);
171 | > use File::Find qw(find);
172 | > use File::Spec::Functions qw(rel2abs splitdir);
173 | > use File::Basename qw(dirname);
174 | >
175 | > ##Set some reasonable defaults
176 | > my %argv = (
177 | > 'startpath' => dirname(rel2abs($0)), ## Real fullpath of script, default.
178 | > 'match' => qr{\.htaccess$}, ## Regex for ".htaccess" files
179 | > 'skip' => qr{^((.cvs)|(.svn))$},
180 | > );
181 | >
182 | > ##Parse commandline
183 | > GetOptions ( 'startpath|path=s' => \$argv{'startpath'} ,
184 | > 'match=s' => \$argv{'match'} ,
185 | > 'skip=s' => \$argv{'skip'} ,
186 | > ) or die "Can't parse commandline (!)";
187 | >
188 | > my @matches; ##Holds the fullnames of matching files (/dir1/dir2/.htaccess)
189 | >
190 | > ##Find files that match our criteria.
191 | > File::Find::find({ 'preprocess' => \&skiprcs , #Filter hook
192 | > 'wanted' => \&wanted , } #Check match hook
193 | > , $argv{'startpath'});
194 | >
195 | > sub skiprcs {
196 | > ## 'grep' through the arglist (@_) and return things that
197 | > ## don't match .cvs|.svn
198 | > return grep { !/$argv{'skip'}/ } @_;
199 | > };
200 | >
201 | > sub wanted {
202 | > ##Add *fullpath* filename to matches, if we matched.
203 | > if ($File::Find::name =~ m/$argv{'match'}/i) {
204 | > push @matches, $File::Find::name;
205 | > }
206 | > }
207 | >
208 | > if (not @matches ) {
209 | > die "No files matched '$argv{'match'}' in path '$argv{'startpath'}'.\n";
210 | > }
211 | >
212 | > ##Sort by shortest path depth (ie. '/folder' before '/folder/subfolder')
213 | > ##by comparying the length of arrays returned by 'splitdir'
214 | > @matches = sort { splitdir($a) <=> splitdir($b) } @matches;
215 | >
216 | > my (%errflag, $errcount);
217 | >
218 | > ## Hash lookup to support different failures for conversion. Certain
219 | > ## pragmas won't convert 1-to-1 (like "RedirectBase"), these are the rules.
220 | > my %error_lkp = (
221 | > 'RedirectBase' => {
222 | > 're'=>qr/RedirectBase/ix,
223 | > 'msg'=>"##WARNING! RedirectBase' does't convert correctly. Check manually!",
224 | > },
225 | > 'OtherParamLabel' => {
226 | > 're'=>qr/ApacheParam*/ix,
227 | > 'msg'=>"##WARNING! Apache params not supported. ;-)"
228 | > },
229 | > );
230 | >
231 | > foreach my $file (@matches) {
232 | > ##Perl5 'slurp' $file idiom
233 | > my $text = do { local( @ARGV, $RS ) = $file ; <> } ;
234 | >
235 | > if ($text) {
236 | > ##Cleanup leading/trailing whitespace
237 | > $text =~ s/^(.+?)\s*$/$1/gmix; #ltrim()
238 | > $text =~ s/^\s*(.+?)$/$1/gmix; #rtrim()
239 | >
240 | > # Use the error lookup to see if the text contains things that don't
241 | > # convert from .htaccess (like RedirectBase..)
242 | > while( my ($key, $value) = each(%error_lkp)) {
243 | > my $re = $value->{'re'}; #Each error has it's own match pattern
244 | > my $msg = $value->{'msg'}; #and error message.
245 | >
246 | > ##If the text matched the error regex, insert a warning $msg
247 | > ## and track/count it.
248 | > if (my $count = $text =~ s/^(.*?$re.*?)$/$RS##$msg$RS$1/gmix) {
249 | > $errflag{$key}+=$count;
250 | > $errcount +=$count;
251 | > }
252 | > }
253 | >
254 | > ##Add a "tab" infront of each line
255 | > $text =~ s/^(.+?)$/\t$1/gmix;
256 | > ##Add a newline, back.
257 | > $text .= $RS;
258 | > }
259 | > else {
260 | > $text = ""; ##NOTE: $text is undef until we make it an "empty string"
261 | > }
262 | >
263 | > my $dir = dirname($file);
264 | > print "$RS";
265 | > print $text;
266 | > print "$RS";
267 | >
268 | > }
269 | >
270 | > ## Output a commented block (Apache style) with any erros we found.
271 | > if ($errcount > 0) {
272 | > ##Convert our %errflag to a nicely Dump'd output.
273 | > my $errors = Data::Dumper->Dump( [ \%errflag ], [ qw(*ErrorTypeFound) ] );
274 | >
275 | > ##Append '#' infront of each line of $errors.
276 | > $errors =~ s/^(.+?)$/#$1/gmix;
277 | >
278 | > print $RS;
279 | > print "######################################################$RS";
280 | > print "#Total Warnings: $errcount $RS";
281 | > print $errors;
282 | > print "######################################################$RS";
283 | > print $RS;
284 | > }
285 | >
286 | > print "######################################################$RS";
287 | > print "## Total Files processed: " . scalar @matches . $RS;
288 | > print "######################################################$RS";
289 | > print $RS;
290 | > print "## Please test before going live, no guarantees! $RS";
291 |
--------------------------------------------------------------------------------