首先,我是PHP的新手,所以我不知道如何实现这一目标。我有一个文件夹,不断创建txt
文件,大小和文本不等。我试图创建一些"搜索引擎"在用PHP编写的Linux系统上。到目前为止,我正在使用下面的代码。
if ( $_SERVER['REQUEST_METHOD'] == 'POST'){
$path = '/example/files';
$findThisString = $_POST['text_box'];
$dir = dir($path);
while (false !== ($file = $dir->read())){
if ($file != '.' && $file != '..'){
if (is_file($path . '/' . $file)){
$data = file_get_contents($path . '/' . $file);
if (stripos($data, $findThisString) !== false){
echo '<p></p><font style="color:white; font-family:Arial">Found Match - <a href="http://test.example.com/files/'. $file .'">'. $file .'</a> <br>';
}
}
}
}
}
$dir->close();
现在这段代码很棒!但有一个问题,一旦文件夹获得大约40,000个文件,搜索需要花费大量时间来提取任何结果。现在我无法使用任何命令,例如greb
。它必须用纯PHP编写,就像上面的代码一样。
是否有优化上述代码才能更快地运行?或者,我可以在PHP中使用更好的搜索功能吗?
答案 0 :(得分:1)
脚本速度如此之慢的原因有很多,而且为了减少所需的时间,您需要做的就是完全取决于代码的确切部分会导致速度减慢。
这意味着您需要通过分析器放置代码,然后调整它报告的代码部分是原因。没有分析器,我们所能做的就是猜测。不一定正确。
正如您对问题的评论所述,使用已经制作的搜索引擎将是更好的解决方案。特别是为此类目的而制作的东西,因为它会大大缩短的时间。
即使是用于Linux shell的内置grep
命令也是一种改进。
那就是说,我怀疑你的代码速度太慢的原因是因为你正在阅读和搜索PHP中所有文件的内容。 stripos()
在这里特别容易受到怀疑,因为这是一个相当慢的搜索
另一个因素可能是循环中的read()
调用,因为我相信它们会在每次调用时执行IO操作。此外,在脚本中对echo
进行大量调用可能会导致速度变慢,具体取决于您拥有的数量。几百个不是很明显,但有几千个。
考虑到这些最后几点,以及我建议您更容易维护代码的一些其他常规更改,我对您的代码进行了以下更改。
<?php
if (isset ($_POST['text_box'])) {
$path = '/example/files';
$result = search_files ($_POST['text_box'], $path);
}
/**
* Searches through the files in the given path, for the search term.
*
* @param string $term The term to search for, only "word characters" as defined by RegExp allowed.
* @param string $path The path which contains the files to be searched.
*
* @return string Either a list of links to the files, or an error message.
*/
function search_files ($term, $path) {
// Ensuring that we have a closing slash at the end of the path, so that
// we can add a file-descriptor for glob() to use.
if (substr ($path, -1) != '/') {
$path .= '/';
}
// If we don't have a valid/readable path we ened to throw an error now.
// This only happens if the code itself is wrong, as it's not user-supplied,
// thus an exception is thrown.
if (!is_dir ($path) || !is_readable ($path)) {
throw new InvalidArgumentException ("Not a valid search path!");
}
// This should be validated to ensure you get sane input,
// in order to avoid erroneous responses to the user and
// possible attacks.
// Addded a simple test to ensure we only accept "word characters".
if (!preg_match ('/^\w+\\z/', $term)) {
// Invalid input. Show warning to user.
return 'Not a valid search string.';
}
// Using glob so that we retrieve a list of all files in one operation.
$contents = glob ($path.'*');
// Using a holding variable, as this many echo statements take
// noticable longer time than just concatenating strings and
// echoing it out once.
$output = '';
// Using printf() templates to make the code easier to reach.
// Ideally the HTML-code shouldn't be in this string either, but adding
// a templating system is far beyond the reach of this Q&A.
$outTemplate = '<p class="found">Found Match - <a href="http://test.example.com/files/%1$s">%2$s</a></p>';
foreach ($contents as $file) {
// Skip the hardlinks for parent and current folder.
if ($file == '.' || $file == '..') {
continue;
}
// Skip if the path isn't a file.
if (!is_file ($path . '/' . $file)) {
continue;
}
// This one is the big issue. Reading all of the files one by one will take time!
$data = file_get_contents ($path . '/' . $file);
// Same with running a case-insensitive search!
if (stripos ($data, $term) !== false) {
// Added output escaping to prevent issues with possible meta-characters.
// (A problem also known as XSS attacks)
$output .= sprintf ($outTemplate, htmlspecialchars (rawurlencode($file)), htmlspecialchars($file));
}
}
// Lastly, if the output string is empty we haven't found anything.
if (empty($output)) {
return "Term not found";
}
return $output;
}
答案 1 :(得分:0)
如果你有两种方法,你不能使用linux命令: 1)它是在数据库中保存文件,之后,当你需要找到你从数据库调用查询搜索文件时。 2)它创建一个索引文件(将保存在他列表文件中的文件)
1种和2种方式可以帮助您节省执行脚本的时间。对于更新文件,您可以编写Cron任务,该任务将开始导入数据库或文件中的新文件。