A few days ago, I did the database work to ignore case when browsing to a cat/port. Tonight, I did the website side.
database access
First, I altered the database function (in classes/element_record.php) to use the new stored procedure:
- function FetchByName($Name) { + function FetchByName($Name, $caseSensitive = true) { + $Debug = 0; + + if ($Debug) echo "looking for '$Name' and caseSensitive is '$caseSensitive'<br>"; if (IsSet($Name)) { $this->element_pathname = $Name; $this->id = ''; } - $sql = "select * from elementGet('" . pg_escape_string($Name) . "')"; - $result = pg_exec($this->dbh, $sql); + if ($caseSensitive) { + $sql = "select * from elementGet('" . pg_escape_string($Name) . "')"; + if ($Debug) echo "invoking $sql<br>"; + $result = pg_exec($this->dbh, $sql); + } else { + $result = pg_query_params($this->dbh, 'select * from elementGetCaseInsensitive($1)', array($Name)); + } + if ($result) { + if ($Debug) echo "we got a result<br>"; + $numrows = pg_numrows($result); + if ($Debug) echo "we have '$numrows' rows<br>"; if ($numrows == 1) { $myrow = pg_fetch_array ($result, 0); $this->PopulateValues($myrow);
On line one, I modify the function to pass in an optional parameter which preserves the original behavior.
Line 10 is the original code.
Lines 13-20 invokes the elementGetCaseInsensitive() stored procedure to work on a case insensitive solution.
Redirecting when finding a different match
When getting a result, we check to see if the path differs. If we get a result, we know it matches, but we need to know if it’s a different case. Here is that code (from rewrite/functions.php):
- if ($ElementRecord->FetchByName('/ports/head/' . $pathname)) { + if ($ElementRecord->FetchByName(FRESHPORTS_PORTS_TREE_PREFIX . PATH_NAME, 0)) { $IsElement = true; if ($Debug) echo 'we found an element for that<br>'; + if ($Debug) echo "we have: '$ElementRecord->element_pathname'<br>"; + if ($Debug) echo " we had: '" . FRESHPORTS_PORTS_TREE_PREFIX . PATH_NAME . "'<br>"; + if (PathnameDiffers($ElementRecord->element_pathname . '/', FRESHPORTS_PORTS_TREE_PREFIX . PATH_NAME)) { + # in a case insensitive search, we want to redirect if the case was wrong + if ($Debug) echo "we are redirecting to '" . $ElementRecord->element_pathname . "/'<br>"; + if ($Debug) echo 'which normalizes to ' . str_replace(FRESHPORTS_PORTS_TREE_PREFIX, '/', $ElementRecord->element_pathname . '/<br>'); + $https = ((!empty($_SERVER['HTTPS'])) && ($_SERVER['HTTPS'] != 'off')); + if ($https) { + $protocol = "https"; + } else { + $protocol = "http"; + } + + header("HTTP/1.1 301 Moved Permanently"); + header('Location: ' . $protocol . '://' . $_SERVER['HTTP_HOST'] . str_replace(FRESHPORTS_PORTS_TREE_PREFIX, '/', $ElementRecord->element_pathname . '/')); + exit; + } + } +
Line 7 invokes PathDiffers to do a comparison between the two strings. This is not a simple A != B operation. sysutils/bacula9-server is not the same as sysutils/bacula9-server/ despite them showing the same content on the website. The paths, or URIs, must first be ‘normalized’ (that’s my chosen terminology, not anything official).
If the user has included a trailing slash (/) on their URL, the code will strip that before looking for a matching entry in the element table.
The debugging information shows some of this:
the URI is '/sysutils/bacula9-SERVER/' the url parts are array(1) { ["path"]=> string(25) "/sysutils/bacula9-SERVER/" } The pathname is '/sysutils/bacula9-SERVER/' we found an element for that we have: '/ports/head/sysutils/bacula9-server' we had: '/ports/head/sysutils/bacula9-SERVER' we are redirecting to '/ports/head/sysutils/bacula9-server/' which normalizes to /sysutils/bacula9-server/
The function in question looks like this:
function PathnameDiffers($Path1, $Path2) { # if the two paths are different, we might want to redirect # if one path ends in a / and the other does not, adjust them if (substr($Path1, -1) == '/') { if (substr($Path2, -1) != '/') { $Path2 .= '/'; } } else { if (substr($Path2, -1) == '/') { $Path1 .= '/'; } } return $Path1 != $Path2; }
That redirect happens early enough in the code to handle all elements, not just ports (e.g. cat/ports/Makefile or distinfo or pkg-descr).