In case anyone's interested, I solved this myself using this (probably absolutely horrible) piece of PHP code.
class clsURL {
    static function checkURL() {
     // don't allow requests on old style URL's
     if (($_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING']) == $_SERVER['REQUEST_URI'] &&
       $_SERVER['REQUEST_METHOD'] != 'POST') {
      // redirect to new style URL
      $redirectTable = self::createReverseTable();
      $currentURL = $_SERVER['REQUEST_URI'];
      if (substr($currentURL, 0, 1) == "/")
       $currentURL = substr($currentURL, 1);
      $newURL = self::getReverseURL($currentURL, $redirectTable);
      if ($newURL) {
       header ('HTTP/1.1 301 Moved Permanently');
       header ('Location: /' . $newURL);
       exit;
      }
     }
    }
    static function getReverseURL($current, $reverseTable) {
     // filter out some common stuff
     $current = preg_replace("/&mid=[0-9]+/", "", $current);
     foreach ($reverseTable as $pair) {
      if (preg_match("|" . $pair['from'] . "|", $current)) {
       return preg_replace("|" . $pair['from'] . "|", $pair['to'], $current);
      }
     }
     // nothing found
     return false;
    }
    static function createReverseTable() {
     $file = fopen('.htaccess', 'r');
     $reverse = array();
     while ($line = fgets($file)) {
      if (stripos($line, 'RewriteRule') === 0) {
       $parts = preg_split("/[\\s\\t]/", $line, 3, PREG_SPLIT_NO_EMPTY);
       $regex = trim($parts[1]);
       $url = trim($parts[2]);
       $parts[2] = $url;
       $matches = array();
       if (preg_match_all("/\\$[0-9]/", $url, $matches)) {
        $matches = $matches[0]; // why? don't know.
        $from = str_replace('?', '\\?', $url);
        $to = $regex;
        foreach ($matches as $match) {
         $index = substr($match, 1);
         $bracket = 0;
         for ($i = 0; $i < strlen($regex); ++$i) {
          if (substr($regex, $i, 1) == "(") {
           $bracket++;
           if ($bracket == $index) {
            $pattern = "";
            $j = $i + 1;
            while (substr($regex, $j, 1) != ")") {
             $pattern .= substr($regex, $j, 1);
             $j++;
            }
            $from = str_replace('$' . $index, '(' . $pattern . ')', $from);
            $to = preg_replace('/\\(' . preg_quote($pattern, '/') . '\\)/', '\\$' . $index, $to, 1);
           }
          }
         }
        }
        // remove optional stuff that we don't use
        $to = str_replace('(-(.*))?', '', $to);
        // remove ^ and (/)?$
        $to = substr($to, 1);
        if (substr($to, -5) == '(/)?$')
         $to = substr($to, 0, strlen($to) - 5);
        $from = '^' . $from . '$';
        // index.php is optional
        $from = str_replace('index.php', '(?:index\\.php)?', $from);
        $reverse[] = array(
         'from' => $from,
         'to'   => $to
        );
       } else {
        $from = str_replace('?', '\\?', $url);
        $to = $regex;
        // remove ^ and (/)?$
        $to = substr($to, 1);
        if (substr($to, -5) == '(/)?$')
         $to = substr($to, 0, strlen($to) - 5);
        $from = '^' . $from . '$';
        // index.php is optional
        $from = str_replace('index.php', '(?:index\\.php)?', $from);
        $reverse[] = array(
         'from' => $from,
         'to'   => $to
        );
       }
      }
     }
     fclose($file);
     return $reverse;
    }
}