Rev 172 Rev 185
1 <?php 1 <?php
2 # vim:et:ts=3:sts=3:sw=3:fdm=marker: 2 # vim:et:ts=3:sts=3:sw=3:fdm=marker:
3   3  
4 // WebSVN - Subversion repository viewing via the web using PHP 4 // WebSVN - Subversion repository viewing via the web using PHP
5 // Copyright © 2004-2006 Tim Armes, Matt Sicker 5 // Copyright © 2004-2006 Tim Armes, Matt Sicker
6 // 6 //
7 // This program is free software; you can redistribute it and/or modify 7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by 8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or 9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version. 10 // (at your option) any later version.
11 // 11 //
12 // This program is distributed in the hope that it will be useful, 12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details. 15 // GNU General Public License for more details.
16 // 16 //
17 // You should have received a copy of the GNU General Public License 17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software 18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // 20 //
21 // -- 21 // --
22 // 22 //
23 // comp.php 23 // comp.php
24 // 24 //
25 // Compare two paths using "svn diff" 25 // Compare two paths using "svn diff"
26 // 26 //
27   27  
28 require_once("include/setup.inc"); 28 require_once("include/setup.inc");
29 require_once("include/svnlook.inc"); 29 require_once("include/svnlook.inc");
30 require_once("include/utils.inc"); 30 require_once("include/utils.inc");
31 require_once("include/template.inc"); 31 require_once("include/template.inc");
32   32  
33 $svnrep = new SVNRepository($rep); 33 $svnrep = new SVNRepository($rep);
34   34  
35 function checkRevision($rev) 35 function checkRevision($rev)
36 { 36 {
37 if (is_numeric($rev) && ((int)$rev > 0)) 37 if (is_numeric($rev) && ((int)$rev > 0))
38 return $rev; 38 return $rev;
39 39
40 $rev = strtoupper($rev); 40 $rev = strtoupper($rev);
41 41
42 switch($rev) 42 switch($rev)
43 { 43 {
44 case "HEAD": 44 case "HEAD":
45 case "PREV": 45 case "PREV":
46 case "COMMITTED": 46 case "COMMITTED":
47 return $rev; 47 return $rev;
48 } 48 }
49 49
50 return "HEAD"; 50 return "HEAD";
51 } 51 }
52   52  
53 $svnrep = new SVNRepository($rep); 53 $svnrep = new SVNRepository($rep);
54   54  
55 // Retrieve the request information 55 // Retrieve the request information
56 $path1 = @$_REQUEST["compare"][0]; 56 $path1 = @$_REQUEST["compare"][0];
57 $path2 = @$_REQUEST["compare"][1]; 57 $path2 = @$_REQUEST["compare"][1];
58 $rev1 = @$_REQUEST["compare_rev"][0]; 58 $rev1 = @$_REQUEST["compare_rev"][0];
59 $rev2 = @$_REQUEST["compare_rev"][1]; 59 $rev2 = @$_REQUEST["compare_rev"][1];
60   60  
61 // Some page links put the revision with the path... 61 // Some page links put the revision with the path...
62 if (strpos($path1, "@")) list($path1, $rev1) = explode("@", $path1); 62 if (strpos($path1, "@")) list($path1, $rev1) = explode("@", $path1);
63 if (strpos($path2, "@")) list($path2, $rev2) = explode("@", $path2); 63 if (strpos($path2, "@")) list($path2, $rev2) = explode("@", $path2);
64   64  
65 $rev1 = checkRevision($rev1); 65 $rev1 = checkRevision($rev1);
66 $rev2 = checkRevision($rev2); 66 $rev2 = checkRevision($rev2);
67   67  
68 // Choose a sensible comparison order unless told not to 68 // Choose a sensible comparison order unless told not to
69 if (!@$_REQUEST["manualorder"] && is_numeric($rev1) && is_numeric($rev2)) 69 if (!@$_REQUEST["manualorder"] && is_numeric($rev1) && is_numeric($rev2))
70 { 70 {
71 if ($rev1 > $rev2) 71 if ($rev1 > $rev2)
72 { 72 {
73 $temppath = $path1; 73 $temppath = $path1;
74 $temprev = $rev1; 74 $temprev = $rev1;
75 75
76 $path1 = $path2; 76 $path1 = $path2;
77 $rev1 = $rev2; 77 $rev1 = $rev2;
78 78
79 $path2 = $temppath; 79 $path2 = $temppath;
80 $rev2 = $temprev; 80 $rev2 = $temprev;
81 } 81 }
82 } 82 }
83   83  
84 $url = $config->getURL($rep, "/", "comp"); 84 $url = $config->getURL($rep, "/", "comp");
85 $vars["revlink"] = "<a href=\"${url}compare%5B%5D=".urlencode($path2)."@$rev2&amp;compare%5B%5D=".urlencode($path1)."@$rev1&manualorder=1\">${lang["REVCOMP"]}</a>"; 85 $vars["revlink"] = "<a href=\"${url}compare%5B%5D=".urlencode($path2)."@$rev2&amp;compare%5B%5D=".urlencode($path1)."@$rev1&manualorder=1\">${lang["REVCOMP"]}</a>";
86   86  
87 if ($rev1 == 0) $rev1 = "HEAD"; 87 if ($rev1 == 0) $rev1 = "HEAD";
88 if ($rev2 == 0) $rev2 = "HEAD"; 88 if ($rev2 == 0) $rev2 = "HEAD";
89   89  
90 $vars["repname"] = $rep->getDisplayName(); 90 $vars["repname"] = $rep->getDisplayName();
91 $vars["action"] = $lang["PATHCOMPARISON"]; 91 $vars["action"] = $lang["PATHCOMPARISON"];
92 $vars["compare_form"] = "<form action=\"$url\" method=\"post\" name=\"compareform\">"; 92 $vars["compare_form"] = "<form action=\"$url\" method=\"post\" name=\"compareform\">";
93 $vars["compare_path1input"] = "<input type=\"text\" size=\"40\" name=\"compare[0]\" value=\"$path1\" />"; 93 $vars["compare_path1input"] = "<input type=\"text\" size=\"40\" name=\"compare[0]\" value=\"$path1\" />";
94 $vars["compare_rev1input"] = "<input type=\"text\" size=\"5\" name=\"compare_rev[0]\" value=\"$rev1\" />"; 94 $vars["compare_rev1input"] = "<input type=\"text\" size=\"5\" name=\"compare_rev[0]\" value=\"$rev1\" />";
95 $vars["compare_path2input"] = "<input type=\"text\" size=\"40\" name=\"compare[1]\" value=\"$path2\" />"; 95 $vars["compare_path2input"] = "<input type=\"text\" size=\"40\" name=\"compare[1]\" value=\"$path2\" />";
96 $vars["compare_rev2input"] = "<input type=\"text\" size=\"5\" name=\"compare_rev[1]\" value=\"$rev2\" />"; 96 $vars["compare_rev2input"] = "<input type=\"text\" size=\"5\" name=\"compare_rev[1]\" value=\"$rev2\" />";
97 $vars["compare_submit"] = "<input name=\"comparesubmit\" type=\"submit\" value=\"${lang["COMPAREPATHS"]}\" />"; 97 $vars["compare_submit"] = "<input name=\"comparesubmit\" type=\"submit\" value=\"${lang["COMPAREPATHS"]}\" />";
98 $vars["compare_endform"] = "<input type=\"hidden\" name=\"op\" value=\"comp\" /><input type=\"hidden\" name=\"manualorder\" value=\"1\" /><input type=\"hidden\" name=\"sc\" value=\"$showchanged\" /></form>"; 98 $vars["compare_endform"] = "<input type=\"hidden\" name=\"op\" value=\"comp\" /><input type=\"hidden\" name=\"manualorder\" value=\"1\" /><input type=\"hidden\" name=\"sc\" value=\"$showchanged\" /></form>";
99   99  
100 # safe paths are a hack for fixing XSS sploit 100 # safe paths are a hack for fixing XSS sploit
101 $vars["path1"] = $path1; 101 $vars["path1"] = $path1;
102 $vars['safepath1'] = htmlentities($path1); 102 $vars['safepath1'] = htmlentities($path1);
103 $vars["path2"] = $path2; 103 $vars["path2"] = $path2;
104 $vars['safepath2'] = htmlentities($path2); 104 $vars['safepath2'] = htmlentities($path2);
105   105  
106 $vars["rev1"] = $rev1; 106 $vars["rev1"] = $rev1;
107 $vars["rev2"] = $rev2; 107 $vars["rev2"] = $rev2;
108   108  
109 $noinput = empty($path1) || empty($path2); 109 $noinput = empty($path1) || empty($path2);
110 $listing = array(); 110 $listing = array();
111   111  
112 // Generate the diff listing 112 // Generate the diff listing
113 $path1 = encodepath(str_replace(DIRECTORY_SEPARATOR, "/", $svnrep->repConfig->path.$path1)); 113 $path1 = encodepath(str_replace(DIRECTORY_SEPARATOR, "/", $svnrep->repConfig->path.$path1));
114 $path2 = encodepath(str_replace(DIRECTORY_SEPARATOR, "/", $svnrep->repConfig->path.$path2)); 114 $path2 = encodepath(str_replace(DIRECTORY_SEPARATOR, "/", $svnrep->repConfig->path.$path2));
115   115  
116 $debug = false; 116 $debug = false;
117   117  
118 if (!$noinput) 118 if (!$noinput)
119 { 119 {
120 $rawcmd = $config->svn." diff ".$rep->svnParams().quote($path1."@".$rev1)." ".quote($path2."@".$rev2); 120 $rawcmd = $config->svn." diff ".$rep->svnParams().quote($path1."@".$rev1)." ".quote($path2."@".$rev2);
121 $cmd = quoteCommand($rawcmd, true); 121 $cmd = quoteCommand($rawcmd, true);
122 if ($debug) echo "$cmd\n"; 122 if ($debug) echo "$cmd\n";
123 } 123 }
124   124  
125 function clearVars() 125 function clearVars()
126 { 126 {
127 global $listing, $index; 127 global $listing, $index;
128 128
129 $listing[$index]["newpath"] = null; 129 $listing[$index]["newpath"] = null;
130 $listing[$index]["endpath"] = null; 130 $listing[$index]["endpath"] = null;
131 $listing[$index]["info"] = null; 131 $listing[$index]["info"] = null;
132 $listing[$index]["diffclass"] = null; 132 $listing[$index]["diffclass"] = null;
133 $listing[$index]["difflines"] = null; 133 $listing[$index]["difflines"] = null;
134 $listing[$index]["enddifflines"] = null; 134 $listing[$index]["enddifflines"] = null;
135 $listing[$index]["properties"] = null; 135 $listing[$index]["properties"] = null;
136 } 136 }
137   137  
138 $vars["success"] = false; 138 $vars["success"] = false;
139   139  
140 if (!$noinput) 140 if (!$noinput)
141 { 141 {
142 if ($diff = popen($cmd, "r")) 142 if ($diff = popen($cmd, "r"))
143 { 143 {
144 $index = 0; 144 $index = 0;
145 $indiff = false; 145 $indiff = false;
146 $indiffproper = false; 146 $indiffproper = false;
147 $getLine = true; 147 $getLine = true;
148 $node = null; 148 $node = null;
149 149
150 $vars["success"] = true; 150 $vars["success"] = true;
151 151
152 while (!feof($diff)) 152 while (!feof($diff))
153 { 153 {
154 if ($getLine) 154 if ($getLine)
155 $line = fgets($diff); 155 $line = fgets($diff);
156 156
157 clearVars(); 157 clearVars();
158 $getLine = true; 158 $getLine = true;
159 if ($debug) print "Line = '$line'<br />" ; 159 if ($debug) print "Line = '$line'<br />" ;
160 if ($indiff) 160 if ($indiff)
161 { 161 {
162 // If we're in a diff proper, just set up the line 162 // If we're in a diff proper, just set up the line
163 if ($indiffproper) 163 if ($indiffproper)
164 { 164 {
165 if ($line[0] == " " || $line[0] == "+" || $line[0] == "-") 165 if ($line[0] == " " || $line[0] == "+" || $line[0] == "-")
166 { 166 {
167 switch ($line[0]) 167 switch ($line[0])
168 { 168 {
169 case " ": 169 case " ":
170 $listing[$index]["diffclass"] = "diff"; 170 $listing[$index]["diffclass"] = "diff";
171 $subline = hardspace(replaceEntities(rtrim(substr($line, 1)), $rep)); 171 $subline = hardspace(replaceEntities(rtrim(substr($line, 1)), $rep));
172 if (empty($subline)) $subline = "&nbsp;"; 172 if (empty($subline)) $subline = "&nbsp;";
173 $listing[$index++]["line"] = $subline; 173 $listing[$index++]["line"] = $subline;
174 if ($debug) print "Including as diff: $subline<br />"; 174 if ($debug) print "Including as diff: $subline<br />";
175 break; 175 break;
176 176
177 case "+": 177 case "+":
178 $listing[$index]["diffclass"] = "diffadded"; 178 $listing[$index]["diffclass"] = "diffadded";
179 $subline = hardspace(replaceEntities(rtrim(substr($line, 1)), $rep)); 179 $subline = hardspace(replaceEntities(rtrim(substr($line, 1)), $rep));
180 if (empty($subline)) $subline = "&nbsp;"; 180 if (empty($subline)) $subline = "&nbsp;";
181 $listing[$index++]["line"] = $subline; 181 $listing[$index++]["line"] = $subline;
182 if ($debug) print "Including as added: $subline<br />"; 182 if ($debug) print "Including as added: $subline<br />";
183 break; 183 break;
184 184
185 case "-": 185 case "-":
186 $listing[$index]["diffclass"] = "diffdeleted"; 186 $listing[$index]["diffclass"] = "diffdeleted";
187 $subline = hardspace(replaceEntities(rtrim(substr($line, 1)), $rep)); 187 $subline = hardspace(replaceEntities(rtrim(substr($line, 1)), $rep));
188 if (empty($subline)) $subline = "&nbsp;"; 188 if (empty($subline)) $subline = "&nbsp;";
189 $listing[$index++]["line"] = $subline; 189 $listing[$index++]["line"] = $subline;
190 if ($debug) print "Including as removed: $subline<br />"; 190 if ($debug) print "Including as removed: $subline<br />";
191 break; 191 break;
192 } 192 }
193 193
194 continue; 194 continue;
195 } 195 }
196 else 196 else
197 { 197 {
198 $indiffproper = false; 198 $indiffproper = false;
199 $listing[$index++]["enddifflines"] = true; 199 $listing[$index++]["enddifflines"] = true;
200 $getLine = false; 200 $getLine = false;
201 if ($debug) print "Ending lines<br />"; 201 if ($debug) print "Ending lines<br />";
202 continue; 202 continue;
203 } 203 }
204 } 204 }
205 205
206 // Check for the start of a new diff area 206 // Check for the start of a new diff area
207 if (!strncmp($line, "@@", 2)) 207 if (!strncmp($line, "@@", 2))
208 { 208 {
209 $pos = strpos($line, "+"); 209 $pos = strpos($line, "+");
210 $posline = substr($line, $pos); 210 $posline = substr($line, $pos);
211 sscanf($posline, "+%d,%d", $sline, $eline); 211 sscanf($posline, "+%d,%d", $sline, $eline);
212 if ($debug) print "sline = '$sline', eline = '$eline'<br />"; 212 if ($debug) print "sline = '$sline', eline = '$eline'<br />";
213 // Check that this isn't a file deletion 213 // Check that this isn't a file deletion
214 if ($sline == 0 && $eline == 0) 214 if ($sline == 0 && $eline == 0)
215 { 215 {
216 $line = fgets($diff); 216 $line = fgets($diff);
217 if ($debug) print "Ignoring: $line<br />" ; 217 if ($debug) print "Ignoring: $line<br />" ;
218 while ($line[0] == " " || $line[0] == "+" || $line[0] == "-") 218 while ($line[0] == " " || $line[0] == "+" || $line[0] == "-")
219 { 219 {
220 $line = fgets($diff); 220 $line = fgets($diff);
221 if ($debug) print "Ignoring: $line<br />" ; 221 if ($debug) print "Ignoring: $line<br />" ;
222 } 222 }
223 223
224 $getLine = false; 224 $getLine = false;
225 if ($debug) print "Unignoring previous - marking as deleted<b>"; 225 if ($debug) print "Unignoring previous - marking as deleted<b>";
226 $listing[$index++]["info"] = $lang["FILEDELETED"]; 226 $listing[$index++]["info"] = $lang["FILEDELETED"];
227 } 227 }
228 else 228 else
229 { 229 {
230 $listing[$index++]["difflines"] = $line; 230 $listing[$index++]["difflines"] = $line;
231 $indiffproper = true; 231 $indiffproper = true;
232 } 232 }
233 233
234 continue; 234 continue;
235 } 235 }
236 else 236 else
237 { 237 {
238 $indiff = false; 238 $indiff = false;
239 if ($debug) print "Ending diff"; 239 if ($debug) print "Ending diff";
240 } 240 }
241 } 241 }
242 242
243 // Check for a new node entry 243 // Check for a new node entry
244 if (strncmp(trim($line), "Index: ", 7) == 0) 244 if (strncmp(trim($line), "Index: ", 7) == 0)
245 { 245 {
246 // End the current node 246 // End the current node
247 if ($node) 247 if ($node)
248 { 248 {
249 $listing[$index++]["endpath"] = true; 249 $listing[$index++]["endpath"] = true;
250 clearVars(); 250 clearVars();
251 } 251 }
252 252
253 $node = trim($line); 253 $node = trim($line);
254 $node = substr($node, 7); 254 $node = substr($node, 7);
255 255
256 $listing[$index]["newpath"] = $node; 256 $listing[$index]["newpath"] = $node;
257 if ($debug) echo "Creating node $node<br />"; 257 if ($debug) echo "Creating node $node<br />";
258 258
259 // Skip past the line of ='s 259 // Skip past the line of ='s
260 $line = fgets($diff); 260 $line = fgets($diff);
261 if ($debug) print "Skipping: $line<br />" ; 261 if ($debug) print "Skipping: $line<br />" ;
262 262
263 // Check for a file addition 263 // Check for a file addition
264 $line = fgets($diff); 264 $line = fgets($diff);
265 if ($debug) print "Examining: $line<br />" ; 265 if ($debug) print "Examining: $line<br />" ;
266 if (strpos($line, "(revision 0)")) 266 if (strpos($line, "(revision 0)"))
267 $listing[$index]["info"] = $lang["FILEADDED"]; 267 $listing[$index]["info"] = $lang["FILEADDED"];
268 268
269 if (strncmp(trim($line), "Cannot display:", 15) == 0) 269 if (strncmp(trim($line), "Cannot display:", 15) == 0)
270 { 270 {
271 $index++; 271 $index++;
272 clearVars(); 272 clearVars();
273 $listing[$index++]["info"] = $line; 273 $listing[$index++]["info"] = $line;
274 continue; 274 continue;
275 } 275 }
276 276
277 // Skip second file info 277 // Skip second file info
278 $line = fgets($diff); 278 $line = fgets($diff);
279 if ($debug) print "Skipping: $line<br />" ; 279 if ($debug) print "Skipping: $line<br />" ;
280 280
281 $indiff = true; 281 $indiff = true;
282 $index++; 282 $index++;
283 283
284 continue; 284 continue;
285 } 285 }
286 286
287 if (strncmp(trim($line), "Property changes on: ", 21) == 0) 287 if (strncmp(trim($line), "Property changes on: ", 21) == 0)
288 { 288 {
289 $propnode = trim($line); 289 $propnode = trim($line);
290 $propnode = substr($propnode, 21); 290 $propnode = substr($propnode, 21);
291 291
292 if ($debug) print "Properties on $propnode (cur node $ $node)"; 292 if ($debug) print "Properties on $propnode (cur node $ $node)";
293 if ($propnode != $node) 293 if ($propnode != $node)
294 { 294 {
295 if ($node) 295 if ($node)
296 { 296 {
297 $listing[$index++]["endpath"] = true; 297 $listing[$index++]["endpath"] = true;
298 clearVars(); 298 clearVars();
299 } 299 }
300 300
301 $node = $propnode; 301 $node = $propnode;
302 302
303 $listing[$index++]["newpath"] = $node; 303 $listing[$index++]["newpath"] = $node;
304 clearVars(); 304 clearVars();
305 } 305 }
306 306
307 $listing[$index++]["properties"] = true; 307 $listing[$index++]["properties"] = true;
308 clearVars(); 308 clearVars();
309 if ($debug) echo "Creating node $node<br />"; 309 if ($debug) echo "Creating node $node<br />";
310 310
311 // Skip the row of underscores 311 // Skip the row of underscores
312 $line = fgets($diff); 312 $line = fgets($diff);
313 if ($debug) print "Skipping: $line<br />" ; 313 if ($debug) print "Skipping: $line<br />" ;
314 314
315 while ($line = trim(fgets($diff))) 315 while ($line = trim(fgets($diff)))
316 { 316 {
317 $listing[$index++]["info"] = $line; 317 $listing[$index++]["info"] = $line;
318 clearVars(); 318 clearVars();
319 } 319 }
320 320
321 continue; 321 continue;
322 } 322 }
323 323
324 // Check for error messages 324 // Check for error messages
325 if (strncmp(trim($line), "svn: ", 5) == 0) 325 if (strncmp(trim($line), "svn: ", 5) == 0)
326 { 326 {
327 $listing[$index++]["info"] = urldecode($line); 327 $listing[$index++]["info"] = urldecode($line);
328 $vars["success"] = false; 328 $vars["success"] = false;
329 continue; 329 continue;
330 } 330 }
331 331
332 $listing[$index++]["info"] = $line; 332 $listing[$index++]["info"] = $line;
333 333
334 } 334 }
335 335
336 if ($node) 336 if ($node)
337 { 337 {
338 clearVars(); 338 clearVars();
339 $listing[$index++]["endpath"] = true; 339 $listing[$index++]["endpath"] = true;
340 } 340 }
341 341
342 if ($debug) print_r($listing); 342 if ($debug) print_r($listing);
343 } 343 }
344 } 344 }
345   345  
346 $vars["version"] = $version; 346 $vars["version"] = $version;
347   347  
348 if (!$rep->hasUnrestrictedReadAccess($path1) || !$rep->hasUnrestrictedReadAccess($path2, false)) 348 if (!$rep->hasUnrestrictedReadAccess($path1) || !$rep->hasUnrestrictedReadAccess($path2, false))
349 $vars["noaccess"] = true; 349 $vars["noaccess"] = true;
350   350  
351 parseTemplate($rep->getTemplatePath()."header.tmpl", $vars, $listing); 351 parseTemplate($rep->getTemplatePath()."header.tmpl", $vars, $listing);
352 parseTemplate($rep->getTemplatePath()."compare.tmpl", $vars, $listing); 352 parseTemplate($rep->getTemplatePath()."compare.tmpl", $vars, $listing);
353 parseTemplate($rep->getTemplatePath()."footer.tmpl", $vars, $listing); 353 parseTemplate($rep->getTemplatePath()."footer.tmpl", $vars, $listing);
354 354
355 ?> 355 ?>