1 | 1 | simandl | <?php |
2 | | | // WebSVN - Subversion repository viewing via the web using PHP |
3 | | | // Copyright (C) 2004-2006 Tim Armes |
4 | | | // |
5 | | | // This program is free software; you can redistribute it and/or modify |
6 | | | // it under the terms of the GNU General Public License as published by |
7 | | | // the Free Software Foundation; either version 2 of the License, or |
8 | | | // (at your option) any later version. |
9 | | | // |
10 | | | // This program is distributed in the hope that it will be useful, |
11 | | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | | // GNU General Public License for more details. |
14 | | | // |
15 | | | // You should have received a copy of the GNU General Public License |
16 | | | // along with this program; if not, write to the Free Software |
17 | | | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | | | // |
19 | | | // -- |
20 | | | // |
21 | | | // log.php |
22 | | | // |
23 | | | // Show the logs for the given path |
24 | | | |
25 | | | require_once("include/setup.php"); |
26 | | | require_once("include/svnlook.php"); |
27 | | | require_once("include/utils.php"); |
28 | | | require_once("include/template.php"); |
29 | | | require_once("include/bugtraq.php"); |
30 | | | |
31 | | | $page = (int)@$_REQUEST["page"]; |
32 | | | $all = (@$_REQUEST["all"] == 1)?1:0; |
33 | | | $isDir = (@$_REQUEST["isdir"] == 1)?1:0; |
34 | | | $dosearch = (@$_REQUEST["logsearch"] == 1)?1:0; |
35 | | | $search = trim(@$_REQUEST["search"]); |
36 | | | $words = preg_split('#\s+#', $search); |
37 | | | $fromRev = (int)@$_REQUEST["fr"]; |
38 | | | $startrev = strtoupper(trim(@$_REQUEST["sr"])); |
39 | | | $endrev = strtoupper(trim(@$_REQUEST["er"])); |
40 | | | $max = isset($_REQUEST['max']) ? (int)$_REQUEST['max'] : false; |
41 | | | |
42 | | | // Max number of results to find at a time |
43 | | | $numSearchResults = 15; |
44 | | | |
45 | | | if ($search == "") { |
46 | | | $dosearch = false; |
47 | | | } |
48 | | | |
49 | | | // removeAccents |
50 | | | // |
51 | | | // Remove all the accents from a string. This function doesn't seem |
52 | | | // ideal, but expecting everyone to install 'unac' seems a little |
53 | | | // excessive as well... |
54 | | | |
55 | | | function removeAccents($string) { |
56 | | | $string = htmlentities($string, ENT_QUOTES, 'ISO-8859-1'); |
57 | | | $string = preg_replace('/&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron);/','$1',$string); |
58 | | | $string = preg_replace('/&([A-Z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron);/','$1',$string); |
59 | | | |
60 | | | return $string; |
61 | | | } |
62 | | | |
63 | | | // Normalise the search words |
64 | | | foreach ($words as $index => $word) { |
65 | | | $words[$index] = strtolower(removeAccents($word)); |
66 | | | |
67 | | | // Remove empty string introduced by multiple spaces |
68 | | | if (empty($words[$index])) unset($words[$index]); |
69 | | | } |
70 | | | |
71 | | | if (empty($page)) $page = 1; |
72 | | | |
73 | | | // If searching, display all the results |
74 | | | if ($dosearch) $all = true; |
75 | | | |
76 | | | $maxperpage = 20; |
77 | | | |
78 | | | // Make sure that we have a repository |
79 | | | if (!isset($rep)) { |
80 | | | echo $lang["NOREP"]; |
81 | | | exit; |
82 | | | } |
83 | | | |
84 | | | $svnrep = new SVNRepository($rep); |
85 | | | |
86 | | | $passrev = $rev; |
87 | | | |
88 | | | // If there's no revision info, go to the lastest revision for this path |
89 | 3 | simandl | $history = $svnrep->getLog($path, $startrev, $endrev, true); |
90 | | | if (is_string($history)) { |
91 | | | echo $history; |
92 | | | exit; |
93 | | | } |
94 | 1 | simandl | $youngest = isset($history->entries[0]) ? $history->entries[0]->rev : 0; |
95 | | | |
96 | | | if (empty($rev)) { |
97 | | | $rev = $youngest; |
98 | | | } |
99 | | | |
100 | | | // make sure path is prefixed by a / |
101 | | | $ppath = $path; |
102 | | | if ($path == "" || $path{0} != "/") { |
103 | | | $ppath = "/".$path; |
104 | | | } |
105 | | | |
106 | | | $vars["action"] = $lang["LOG"]; |
107 | | | $vars["repname"] = htmlentities($rep->getDisplayName(), ENT_QUOTES, 'UTF-8'); |
108 | | | $vars["rev"] = $rev; |
109 | | | $vars["path"] = htmlentities($ppath, ENT_QUOTES, 'UTF-8'); |
110 | | | |
111 | | | createDirLinks($rep, $ppath, $passrev); |
112 | | | |
113 | | | $vars['indexurl'] = $config->getURL($rep, '', 'index'); |
114 | | | $vars['repurl'] = $config->getURL($rep, '', 'dir'); |
115 | | | |
116 | | | if (!$isDir) { |
117 | | | $url = $config->getURL($rep, $path, "file"); |
118 | | | $vars["filedetaillink"] = "<a href=\"${url}rev=$rev&isdir=0\">${lang["FILEDETAIL"]}</a>"; |
119 | | | |
120 | | | $url = $config->getURL($rep, $path, "diff"); |
121 | | | $vars["prevdifflink"] = "<a href=\"${url}rev=$rev\">${lang["DIFFPREV"]}</a>"; |
122 | | | |
123 | | | $url = $config->getURL($rep, $path, "blame"); |
124 | | | $vars["blamelink"] = "<a href=\"${url}rev=$passrev\">${lang["BLAME"]}</a>"; |
125 | | | } |
126 | | | |
127 | | | $logurl = $config->getURL($rep, $path, "log"); |
128 | | | |
129 | | | if ($rev != $youngest) { |
130 | | | $vars["goyoungestlink"] = "<a href=\"${logurl}isdir=$isDir\">${lang["GOYOUNGEST"]}</a>"; |
131 | | | } else { |
132 | | | $vars["goyoungestlink"] = ""; |
133 | | | } |
134 | | | |
135 | | | // We get the bugtraq variable just once based on the HEAD |
136 | | | $bugtraq = new Bugtraq($rep, $svnrep, $ppath); |
137 | | | |
138 | | | if ($startrev != "HEAD" && $startrev != "BASE" && $startrev != "PREV" && $startrev != "COMMITTED") $startrev = (int)$startrev; |
139 | | | if ($endrev != "HEAD" && $endrev != "BASE" && $endrev != "PREV" && $endrev != "COMMITTED") $endrev = (int)$endrev; |
140 | | | if (empty($startrev)) $startrev = $rev; |
141 | | | if (empty($endrev)) $endrev = 1; |
142 | | | |
143 | | | if ($max === false) { |
144 | | | $max = $dosearch ? 0 : 30; |
145 | | | } else { |
146 | | | if ($max < 0) $max = 30; |
147 | | | } |
148 | | | |
149 | | | $history = $svnrep->getLog($path, $startrev, $endrev, true, $max); |
150 | 3 | simandl | if (is_string($history)) { |
151 | | | echo $history; |
152 | | | exit; |
153 | | | } |
154 | 1 | simandl | $vars["logsearch_moreresultslink"] = ""; |
155 | | | $vars["pagelinks"] = ""; |
156 | | | $vars["showalllink"] = ""; |
157 | | | $listing = array(); |
158 | | | |
159 | | | if (!empty($history)) { |
160 | | | // Get the number of separate revisions |
161 | | | $revisions = count($history->entries); |
162 | | | |
163 | | | if ($all) { |
164 | | | $firstrevindex = 0; |
165 | | | $lastrevindex = $revisions - 1; |
166 | | | $pages = 1; |
167 | | | } else { |
168 | | | // Calculate the number of pages |
169 | | | $pages = floor($revisions / $maxperpage); |
170 | | | if (($revisions % $maxperpage) > 0) $pages++; |
171 | | | |
172 | | | if ($page > $pages) $page = $pages; |
173 | | | |
174 | | | // Word out where to start and stop |
175 | | | $firstrevindex = ($page - 1) * $maxperpage; |
176 | | | $lastrevindex = $firstrevindex + $maxperpage - 1; |
177 | | | if ($lastrevindex > $revisions - 1) $lastrevindex = $revisions - 1; |
178 | | | } |
179 | | | |
180 | | | $brev = isset($history->entries[$firstrevindex ]) ? $history->entries[$firstrevindex ]->rev : false; |
181 | | | $erev = isset($history->entries[$lastrevindex]) ? $history->entries[$lastrevindex]->rev : false; |
182 | | | |
183 | | | $entries = array(); |
184 | | | if ($brev && $erev) { |
185 | | | $history = $svnrep->getLog($path, $brev, $erev, false, 0); |
186 | 3 | simandl | if (is_string($history)) { |
187 | | | echo $history; |
188 | | | exit; |
189 | | | } |
190 | 1 | simandl | $entries = $history->entries; |
191 | | | } |
192 | | | |
193 | | | $row = 0; |
194 | | | $index = 0; |
195 | | | $listing = array(); |
196 | | | $found = false; |
197 | | | |
198 | | | foreach ($entries as $r) { |
199 | | | // Assume a good match |
200 | | | $match = true; |
201 | | | $thisrev = $r->rev; |
202 | | | |
203 | | | // Check the log for the search words, if searching |
204 | | | if ($dosearch) { |
205 | | | if ((empty($fromRev) || $fromRev > $thisrev)) { |
206 | | | // Turn all the HTML entities into real characters. |
207 | | | |
208 | | | // Make sure that each word in the search in also in the log |
209 | | | foreach ($words as $word) { |
210 | | | if (strpos(strtolower(removeAccents($r->msg)), $word) === false && strpos(strtolower(removeAccents($r->author)), $word) === false) { |
211 | | | $match = false; |
212 | | | break; |
213 | | | } |
214 | | | } |
215 | | | |
216 | | | if ($match) { |
217 | | | $numSearchResults--; |
218 | | | $found = true; |
219 | | | } |
220 | | | } else { |
221 | | | $match = false; |
222 | | | } |
223 | | | } |
224 | | | |
225 | | | if ($match) |
226 | | | { |
227 | | | // Add the trailing slash if we need to (svnlook history doesn't return trailing slashes!) |
228 | | | $rpath = $r->path; |
229 | | | |
230 | | | if (empty($rpath)) { |
231 | | | $rpath = "/"; |
232 | | | } else if ($isDir && $rpath{strlen($rpath) - 1} != "/") { |
233 | | | $rpath .= "/"; |
234 | | | } |
235 | | | |
236 | | | // Find the parent path (or the whole path if it's already a directory) |
237 | | | $pos = strrpos($rpath, "/"); |
238 | | | $parent = substr($rpath, 0, $pos + 1); |
239 | | | |
240 | | | $url = $config->getURL($rep, $parent, "revision"); |
241 | | | $listing[$index]["revlink"] = "<a href=\"${url}rev=$thisrev\">$thisrev</a>"; |
242 | | | |
243 | | | if ($isDir) { |
244 | | | $listing[$index]["compare_box"] = "<input type=\"checkbox\" name=\"compare[]\" value=\"$parent@$thisrev\" onclick=\"checkCB(this)\" />"; |
245 | | | $url = $config->getURL($rep, $rpath, "dir"); |
246 | | | $listing[$index]["revpathlink"] = "<a href=\"${url}rev=$thisrev\">$rpath</a>"; |
247 | | | } else { |
248 | | | $listing[$index]["compare_box"] = "<input type=\"checkbox\" name=\"compare[]\" value=\"$rpath@$thisrev\" onclick=\"checkCB(this)\" />"; |
249 | | | $url = $config->getURL($rep, $rpath, "file"); |
250 | | | $listing[$index]["revpathlink"] = "<a href=\"${url}rev=$thisrev\">$rpath</a>"; |
251 | | | } |
252 | | | |
253 | | | $listing[$index]["revauthor"] = $r->author; |
254 | 3 | simandl | $listing[$index]["date"] = $r->date; |
255 | 1 | simandl | $listing[$index]["revage"] = $r->age; |
256 | | | $listing[$index]["revlog"] = nl2br($bugtraq->replaceIDs(create_anchors($r->msg))); |
257 | | | $listing[$index]["rowparity"] = $row; |
258 | | | |
259 | | | $row = 1 - $row; |
260 | | | $index++; |
261 | | | } |
262 | | | |
263 | | | // If we've reached the search limit, stop here... |
264 | | | if (!$numSearchResults) { |
265 | | | $url = $config->getURL($rep, $path, "log"); |
266 | | | $vars["logsearch_moreresultslink"] = "<a href=\"${url}rev=$rev&isdir=$isDir&logsearch=1&search=$search&fr=$thisrev\">${lang["MORERESULTS"]}</a>"; |
267 | | | break; |
268 | | | } |
269 | | | } |
270 | | | |
271 | | | $vars["logsearch_resultsfound"] = true; |
272 | | | |
273 | | | if ($dosearch && !$found) { |
274 | | | if ($fromRev == 0) { |
275 | | | $vars["logsearch_nomatches"] = true; |
276 | | | $vars["logsearch_resultsfound"] = false; |
277 | | | } else { |
278 | | | $vars["logsearch_nomorematches"] = true; |
279 | | | } |
280 | | | } else if ($dosearch && $numSearchResults > 0) { |
281 | | | $vars["logsearch_nomorematches"] = true; |
282 | | | } |
283 | | | |
284 | | | // Work out the paging options |
285 | | | |
286 | | | if ($pages > 1) { |
287 | | | $prev = $page - 1; |
288 | | | $next = $page + 1; |
289 | | | |
290 | | | if ($page > 1) $vars["pagelinks"] .= "<a href=\"${logurl}rev=$rev&sr=$startrev&er=$endrev&max=$max&page=$prev\">< ${lang["PREV"]}</a> "; |
291 | | | for ($p = 1; $p <= $pages; $p++) { |
292 | | | if ($p != $page) { |
293 | | | $vars["pagelinks"].= "<a href=\"${logurl}rev=$rev&sr=$startrev&er=$endrev&isdir=$isDir&max=$max&page=$p\">$p</a> "; |
294 | | | } else { |
295 | | | $vars["pagelinks"] .= "<b>$p </b>"; |
296 | | | } |
297 | | | } |
298 | | | if ($page < $pages) $vars["pagelinks"] .=" <a href=\"${logurl}rev=$rev&sr=$startrev&er=$endrev&isdir=$isDir&max=$max&page=$next\">${lang["NEXT"]} ></a>"; |
299 | | | |
300 | | | $vars["showalllink"] = "<a href=\"${logurl}rev=$rev&sr=$startrev&er=$endrev&isdir=$isDir&all=1&max=$max\">${lang["SHOWALL"]}</a>"; |
301 | | | } |
302 | | | } |
303 | | | |
304 | | | // Create the project change combo box |
305 | | | |
306 | | | $url = $config->getURL($rep, $path, "log"); |
307 | | | // XXX: forms don't have the name attribute, but _everything_ has the id attribute, |
308 | | | // so what you're trying to do (if anything?) should be done via that ~J |
309 | | | $vars["logsearch_form"] = "<form action=\"$url\" method=\"post\">"; |
310 | | | |
311 | | | $vars["logsearch_startbox"] = "<input name=\"sr\" size=\"5\" value=\"$startrev\" />"; |
312 | | | $vars["logsearch_endbox" ] = "<input name=\"er\" size=\"5\" value=\"$endrev\" />"; |
313 | | | $vars["logsearch_maxbox" ] = "<input name=\"max\" size=\"5\" value=\"".($max==0?"":$max)."\" />"; |
314 | | | $vars["logsearch_inputbox"] = "<input name=\"search\" value=\"".htmlentities($search, ENT_QUOTES, 'UTF-8')."\" />"; |
315 | 3 | simandl | $vars["logsearch_showall"] = '<input type="checkbox" name="all" value="1"'.($all ? ' checked="checked"' : '').' />'; |
316 | 1 | simandl | |
317 | | | $vars["logsearch_submit"] = "<input type=\"submit\" value=\"${lang["GO"]}\" />"; |
318 | | | $vars["logsearch_hidden"] = "<input type=\"hidden\" name=\"logsearch\" value=\"1\" />". |
319 | | | "<input type=\"hidden\" name=\"op\" value=\"log\" />". |
320 | | | "<input type=\"hidden\" name=\"rev\" value=\"$rev\" />". |
321 | | | "<input type=\"hidden\" name=\"isdir\" value=\"$isDir\" />"; |
322 | | | $vars["logsearch_endform"] = "</form>"; |
323 | | | |
324 | 3 | simandl | if ($page !== 1 || $all || $dosearch || $fromRev || $startrev !== $rev || $endrev !== 1 || $max !== 30) { |
325 | | | $url = $config->getURL($rep, $path, "log"); |
326 | | | $vars["logsearch_clearloglink"] = "<a href=\"${url}rev=$rev&isdir=$isDir\">${lang["CLEARLOG"]}</a>"; |
327 | | | } |
328 | 1 | simandl | |
329 | | | $url = $config->getURL($rep, "/", "comp"); |
330 | | | $vars["compare_form"] = "<form action=\"$url\" method=\"post\">"; |
331 | | | $vars["compare_submit"] = "<input name=\"comparesubmit\" type=\"submit\" value=\"${lang["COMPAREREVS"]}\" />"; |
332 | | | $vars["compare_hidden"] = "<input type=\"hidden\" name=\"op\" value=\"comp\" />"; |
333 | | | $vars["compare_endform"] = "</form>"; |
334 | | | |
335 | 3 | simandl | $vars['showageinsteadofdate'] = $config->showAgeInsteadOfDate; |
336 | | | |
337 | 1 | simandl | $vars["version"] = $version; |
338 | | | |
339 | | | if (!$rep->hasReadAccess($path, false)) { |
340 | | | $vars["noaccess"] = true; |
341 | | | } |
342 | | | |
343 | | | parseTemplate($rep->getTemplatePath()."header.tmpl", $vars, $listing); |
344 | | | parseTemplate($rep->getTemplatePath()."log.tmpl", $vars, $listing); |
345 | | | parseTemplate($rep->getTemplatePath()."footer.tmpl", $vars, $listing); |