Find Phrase
Some time ago, I made a quick script to search log files for specific phrases. I don't recall exactly why I was doing the searches, but it probably was related to seeing how much traffic was experienced at certain web pages.
That script has been updated for broader use for this article. I call it Find Phrase.
Most people have search functions on their phones and computers for searching files stored there. Find Phrase is for searching files on their server. Any files available to browsers can be searched — logs, web pages, images, CSS and JavaScript files, and so forth.
The Find Phrase script itself is copy and paste. No customization required. The source code is below. Upload it to your server as findphrase.php
or other *.php file name. When findphrase.php
is uploaded, make a note of its URL.
<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Find Phrase</title> <style type="text/css"> * { box-sizing:border-box; } html { font-family:sans-serif; font-size:100%; } a { text-decoration:none; } code { font-size:125%; padding-left:2px; padding-right:1px; } input[type="text"], input[type="submit"] { width:100%; font-size:1rem; font-family:sans-serif; } input[type="text"] { border:1px solid #ccc; border-radius:5px; padding:5px; } </style> </head> <body> <div style="text-align:center;"> <h1><a href="https://www.willmaster.com/"><img src="https://www.willmaster.com/images/wmlogo_icon.gif"></a><br>Find Phrase</h1> </div> <?php /* Search Files In Directory for Phrase Version 1.1 Integrated with web page form October 30, 2023 Version 1.0, Original, June 21, 2022 Will Bontrager Software LLC https://www.willmaster.com/ */ $Notices = array(); if( count($_POST) ) { TrimAndStripSlashes($_POST); if( empty($_POST['word']) ) { $Notices[] = 'A word or phrase needs to be provided.'; } } if( count($_POST) and (!count($Notices)) ) { echo '<h3>Scanning...</h3>'; $dir = __DIR__; $_POST['dir'] = preg_replace('!/$!','',$_POST['dir']); if( ! empty($_POST['dir']) ) { if( preg_match('!^/!',$_POST['dir']) ) { $dir = preg_replace('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','',$_POST['dir']); $dir = "{$_SERVER['DOCUMENT_ROOT']}$dir"; } else { $dir .= "/{$_POST['dir']}"; } } $word = $_POST['word']; $case = (isset($_POST['case']) and $_POST['case']=='yes') ? true : false; $OmitExt = array(); foreach( preg_split('/[^0-9a-zA-Z]+/',$_POST['ext']) as $ext ) { if( preg_match('/\w/',$ext) ) { $OmitExt[strtolower($ext)]=true; } } $matchword = '/'.preg_quote($_POST['word'],'/').'/'; if( ! $case ) { $matchword .= 'i'; } $filesCount = 0; foreach( glob("$dir/*") as $f ) { if( ! is_file($f) ) { continue; } $match = array(); preg_match('/\.([^\.]+)$/i',$f,$match); $ext = strtolower($match[1]); if( isset($OmitExt[$ext]) ) { continue; } echo "\n<br>Scanning file: <b>$f</b>\n<br>"; $F = fopen($f,'r'); if( ! $F ) { echo "(unable to open the file)\n<br>"; continue; } $filesCount++; $linenumber = 0; $hasmatches = false; while( ($line=fgets($F))!==false ) { $linenumber++; if( preg_match($matchword,$line) ) { $hasmatches = true; echo "<br>Match at line $linenumber:<br>" . htmlspecialchars($line) . '<br>'; } } if( ! $hasmatches ) { echo "— no matches —\n<br>"; } } if( ! $filesCount ) { echo '<h4>No files scanned.</h4>'; } } function TrimAndStripSlashes(&$arr) { array_walk_recursive($arr, 'TrimAndStripSlashesFromArrayItems'); } function TrimAndStripSlashesFromArrayItems(&$item, $key) { $item = trim(stripslashes($item)); } ?> <div style="max-width:550px; margin:.5in auto;"> <form action="<?php echo($_SERVER['PHP_SELF']) ?>" method="post" accept-charset="utf-8"> <?php if(count($Notices)): ?> <div style="border:1px solid blue; padding:1em; border-radius:1em;"> • <?php echo implode('<br>• ',$Notices); ?> </div> <?php endif; ?> <p> Directory to search (blank for current directory): <br><input type="text" name="dir"> </p> <p> Word or phrase to search for: <br><input type="text" name="word"> <br><label><input type="checkbox" name="case" value="yes">Case sensitive.</label> </p> <p> File name extensions to omit from search: <br><input type="text" name="ext"> </p> <p> <input type="submit" value="Find Matches"> </form> <p> Copyright 2023 <a href="https://www.willmaster.com/">Will Bontrager Software LLC</a> </p> </div> </body> </html>
After the script is uploaded to your server, type Find Phrase's URL into your browser. You'll see something similar to this screenshot;
Let's talk about each field of the screenshot.
Directory to search
To search the same directory as where findphrase.php
is installed, this can be left blank. Otherwise, specify the directory to search.
When a directory is specified with a leading /
character, it is assumed to be relative to document root (the directory where the domain's home or index file is located). Without the leading /
character, it is assumed to be relative to where findphrase.php
is installed.
Word or phrase to search for
Here, type in the word or phrase you want to find within the files located in the directory you specified.
Case sensitive
If the search should be case-sensitive, check the "Case sensitive" checkbox. When it is checked, then searching for "Word" would match "Word" but not "word". If unchecked, both "Word" and "word" would match.
File name extensions to omit from search
If the directory might have files with file name extensions you do not want searched, specify the extensions here. If you don't want images searched, for example, you might specify .png .jpg .jpeg .gif
(the period/dot is optional).
Tap the "Find Matches" button and the search commences.
The page will reload and the results of the search will display above the search form.
Find Phrase will search the content of all files in the directory with a file name extension you have not listed. The search will publish the names of files being searched. Below the file name will be the approximate line number and the entire line of every match.
The Find Phrase script can be quite handy, especially for log files and files that contain site visitor-provided content. It does the search on the server.
(This content first appeared in Possibilities newsletter.)
Will Bontrager