true, PDO::ATTR_EMULATE_PREPARES => true] ); } catch (PDOException $e) { return find_manual_page_slow($lang, $keyword); } } } } if (!$dbh) { return find_manual_page_slow($lang, $keyword); } $kw = $keyword; // Try the preferred language first, then the // English one in case no page is found $langs = ($lang != 'en') ? [$lang, 'en'] : ['en']; // Reformat keyword, drop anything in parenthesis --- except a search for the underscore only. (Bug #63490) if ($keyword != '_') { $keyword = str_replace('_', '-', $keyword); } if (strpos($keyword, '(') !== false) { $keyword = preg_replace("!\\(.*\\)!", "-", $keyword); } // No keyword to search for if (strlen($keyword) == 0) { return ""; } // If there is a dot in the $keyword, then a prefix // is specfied, so we need to carry that on into the SQL // search [eg. function.echo or function.mysql-close] // Check for all the languages foreach ($langs as $lang) { // @todo consider alternative schemas for this data // @todo utilize phd to generate this data, instead of the current systems/gen-phpweb-sqlite-db.php /* Example data: lang = en name = /manual/en/function.str-replace.php keyword = str-replace prefix = function. prio = 2 Therefore, the query below matches: str-replace, function.str-replace and function.str-replace.php This also applies to other sections like book.foo, language.foo, example.foo, etc. Note: $keyword replaces _ with - above, so _ variants also work */ if (strpos($keyword, ".") > 0) { $SQL = "SELECT name from fs WHERE lang = ? AND (name = ? OR keyword = ?) ORDER BY prio LIMIT 1"; $_keyword = $keyword; if (pathinfo($keyword, PATHINFO_EXTENSION) !== 'php') { $_keyword .= '.php'; } $stm = $dbh->prepare($SQL); if (!$stm) { return find_manual_page_slow($lang, $keyword); } $stm->execute([$lang, "/manual/{$lang}/{$_keyword}", $keyword]); // Some partially specified URL is used } else { // List a few variations, plus a metaphone version // FIXME: metaphone causes too many false positives, disable for now // the similar_text() search fallback works fine (see quickref.php) // if this change remains, adjust the gen-phpweb-sqlite script accordingly $SQL = "SELECT name, prio FROM fs WHERE lang = :lang AND keyword IN (?, ?, ?, ?, ?) ORDER BY keyword = ? DESC, prio LIMIT 1"; $stm = $dbh->prepare($SQL); if ($stm) { $stm->execute([$lang, $keyword, str_replace('\\', '-', $keyword), str_replace(' ', '', $keyword), str_replace(' ', '-', $keyword), str_replace('-', '', $keyword), $keyword]); } } // Successful query if ($stm) { $r = $stm->fetch(PDO::FETCH_NUM); if (isset($r[0])) { if (isset($r[1]) && $r[1] > 10 && strlen($keyword) < 4) { // "Match" found, but the keyword is so short // its probably bogus. Skip it continue; } // Match found // But does the file really exist? // @todo consider redirecting here, instead of including content within the 404 // @todo considering the file path is generated from the manual build, we can probably remove this file_exists() check if (file_exists($_SERVER["DOCUMENT_ROOT"] . $r[0])) { return $r[0]; } } } else { error_noservice(); } } // No match found // @todo refactor. find_manual_page_slow() performs many of the same searches already performed above, // but uses file_exists() instead of sqlite. In other words, if sqlite was used, don't perform // all of the slow and unnecessary checks. return find_manual_page_slow($langs[0], $kw); }