55

Using php, I'm trying to create a script which will search within a text file and grab that entire line and echo it.

I have a text file (.txt) titled "numorder.txt" and within that text file, there are several lines of data, with new lines coming in every 5 minutes (using cron job). The data looks similar to:

2 aullah1
7 name
12 username

How would I go about creating a php script which will search for the data "aullah1" and then grab the entire line and echo it? (Once echoed, it should display "2 aullah1" (without quotations).

If I didn't explain anything clearly and/or you'd like me to explain in more detail, please comment.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124
aullah
  • 1,334
  • 3
  • 20
  • 28
  • 1
    “new lines coming in every 5 minutes” – That sounds like a lot of data. Maybe you should rethink whatever you are doing and use some database instead to store the values. Otherwise php will have big problems with the growing size of that file. – poke Sep 10 '10 at 16:16
  • Hey poke, thank you for your reply and concern. ;) The file won't really be too large, infact I think at the moment it's only approximately 150 lines. Although it does update every 5 minutes, it may only be 1 line or up to 20 lines at time. On certain occasions I may delete the lines in order to reset the data. The only reason I mentioned that the lines update, is so that when searching within the text file, I don't get an answer which is based upon lines. Again, I really do appreciate your response and thank you. ;) – aullah Sep 10 '10 at 16:30
  • possible duplicate of [PHP script to grab entire line](http://stackoverflow.com/questions/3539004/php-script-to-grab-entire-line) – Gordon Apr 14 '11 at 12:27
  • https://github.com/skfaisal93/AnyWhereInFiles – Faisal Shaikh Dec 31 '15 at 15:20

7 Answers7

89

And a PHP example, multiple matching lines will be displayed:

<?php
$file = 'somefile.txt';
$searchfor = 'name';

// the following line prevents the browser from parsing this as HTML.
header('Content-Type: text/plain');

// get the file contents, assuming the file to be readable (and exist)
$contents = file_get_contents($file);

// escape special characters in the query
$pattern = preg_quote($searchfor, '/');

// finalise the regular expression, matching the whole line
$pattern = "/^.*$pattern.*\$/m";

// search, and store all matching occurences in $matches
if (preg_match_all($pattern, $contents, $matches))
{
   echo "Found matches:\n";
   echo implode("\n", $matches[0]);
}
else
{
   echo "No matches found";
}
Avatar
  • 14,622
  • 9
  • 119
  • 198
Lekensteyn
  • 64,486
  • 22
  • 159
  • 192
  • 3
    Did you mean `preg_match_all`? – poke Sep 10 '10 at 16:13
  • 2
    Yes I did, I'm used to JS 'g' flag: using one function :o – Lekensteyn Sep 10 '10 at 16:26
  • 1
    Hi Lekensteyn, I am extremely grateful of your response and fond of your coding. I'd love to use this script, however, every time I replace the text "name" within the $searchfor variable, I always get the error "No matches found". Of course, that's probably just me. There can be a lot of problems which cause this, and I'll try and find out whatever it is, but do you think it could be the coding? Again, apologies if I'm causing any hassle and I do extremely appreciate your response and efforts. Thank you. ;) – aullah Sep 10 '10 at 16:38
  • Added `m` flag and changed `implode("\n", $matches)` to `implode("\n", $matches[0])`. Tested it, and it works now. Try it again :) – Lekensteyn Sep 10 '10 at 19:46
  • `^*.` is not a valid regex... it is not an error so I have rolled back that change. – Lekensteyn Dec 10 '15 at 11:31
61

Do it like this. This approach lets you search a file of any size (big size won't crash the script) and will return ALL lines that match the string you want.

<?php
$searchthis = "mystring";
$matches = array();

$handle = @fopen("path/to/inputfile.txt", "r");
if ($handle)
{
    while (!feof($handle))
    {
        $buffer = fgets($handle);
        if(strpos($buffer, $searchthis) !== FALSE)
            $matches[] = $buffer;
    }
    fclose($handle);
}

//show results:
print_r($matches);
?>

Note the way strpos is used with !== operator.

shamittomar
  • 46,210
  • 12
  • 74
  • 78
  • 2
    The only beef I would have is suppressing the error. *In my opinion*, it is better to turn display_errors off when on production, but at least this way you see any errors and can fix them while under development. +1 for a good answer though. – Jim Sep 10 '10 at 16:41
  • Hi shamittomar, thank you for your response. I extremely appreciate it and your coding! Thank you. ;) One thing though, I don't really like the idea of how the result is displayed within an array as I need the result to displayed to the end-user eventually. :( Of course, I do appreciate your response as well as your coding. Thank you. ;) – aullah Sep 10 '10 at 16:43
  • @AUllah. You're welcome. I have just printed the array of result. It is upto you to show the array in any way you want. Do a `foreach` loop of the `$matches` and echo the results with your style and choice. – shamittomar Sep 10 '10 at 17:17
  • @premiso, yes I agree with that practice completely. However, the `if($handle)` can have an `else` with stating that the file did not open correctly. I like this approach better. Just a matter of choice. – shamittomar Sep 10 '10 at 17:18
  • Yea, the else would be good for user-friendly errors. But it is nice having the actual error too while you are developing. – Jim Sep 10 '10 at 17:38
  • If you are using fgets() without a length (second param), then your script still might stop due to memory limit. This is because fgets() reads a line. But if you have a binary file (or a text file which is just extremely long) then the function might read until the end of the file! It does not guarantee you to read the entire file. Just add a length, e. g. 262144 (256 KiB). – StanE Jan 19 '16 at 23:44
26

Using file() and strpos():

<?php
// What to look for
$search = 'foo';
// Read from file
$lines = file('file.txt');
foreach($lines as $line)
{
  // Check if the line contains the string we're looking for, and print if it does
  if(strpos($line, $search) !== false)
    echo $line;
}

When tested on this file:

foozah
barzah
abczah

It outputs:

foozah


Update:
To show text if the text is not found, use something like this:

<?php
$search = 'foo';
$lines = file('file.txt');
// Store true when the text is found
$found = false;
foreach($lines as $line)
{
  if(strpos($line, $search) !== false)
  {
    $found = true;
    echo $line;
  }
}
// If the text was not found, show a message
if(!$found)
{
  echo 'No match found';
}

Here I'm using the $found variable to find out if a match was found.

Frxstrem
  • 38,761
  • 9
  • 79
  • 119
  • Hi Frxstrem, thank you for your response. I'm extremely fond of it and I do appreciate your reply. The code seems to work fabulously, if possible do you think there is a possibility to add an "else" line against that "if". Something on the lines as "Not found"? Again, apologies if I'm asking for too much, just the way it is, is fine. I do appreciate your response and thank you very much! ;) – aullah Sep 10 '10 at 16:49
  • @AUllah1: It's pretty easy to do, so I have updated my answer with that – Frxstrem Sep 10 '10 at 19:26
  • What about exact match? Let say I have 1.2.3.4 and 1.1.2.45 then searching 1.2.3.4 also will output 1.1.2.45 – MaXi32 Nov 12 '20 at 09:35
10
$searchfor = $_GET['keyword'];
$file = 'users.txt';

$contents = file_get_contents($file);
$pattern = preg_quote($searchfor, '/');
$pattern = "/^.*$pattern.*\$/m";

if (preg_match_all($pattern, $contents, $matches)) {
    echo "Found matches:<br />";
    echo implode("<br />", $matches[0]);
} else {
    echo "No matches found";
    fclose ($file); 
}
zessx
  • 68,042
  • 28
  • 135
  • 158
4

looks like you're better off systeming out to system("grep \"$QUERY\"") since that script won't be particularly high performance either way. Otherwise http://php.net/manual/en/function.file.php shows you how to loop over lines and you can use http://php.net/manual/en/function.strstr.php for finding matches.

Novikov
  • 4,399
  • 3
  • 28
  • 36
  • Hi Novikov, thank you for your response, I extremely appreciate it, as well as your efforts. I'll try and see if I can make heads and tails from the links you've provided. ;) The reason I can't use the system approach is that, I will eventually turn the script into a search. Of course, apologies that I didn't state this clearly. It's my fault. Sorry, and thank you for your response. ;) – aullah Sep 10 '10 at 16:34
  • 1
    You really don't want to pass anything to system(), shell_exec(), exec(), etc without using escapeshellarg() ... it often creates a big security issue :-) – Craig Francis Jan 03 '18 at 14:53
3

one way...

$needle = "blah";
$content = file_get_contents('file.txt');
preg_match('~^(.*'.$needle.'.*)$~',$content,$line);
echo $line[1];

though it would probably be better to read it line by line with fopen() and fread() and use strpos()

CrayonViolent
  • 32,111
  • 5
  • 56
  • 79
  • Hi Crayon Violent, thank you for your response. It is extremely appreciated, however, whenever I attempt to run this code, I always end up with a blank page within my browser. I'm currently running php 5.3.2, if that where the problem lies? Again, I appreciate your response and efforts. Thank you! ;) – aullah Sep 10 '10 at 16:41
  • Could be any number of things, like wrong path/to/file, etc..can't really help w/out seeing what you actually did with it.. but something like this is really only good for short files. Overall as I mentioned it would be better to read it line by line, which shamittomar's answer details, so stick with that one. – CrayonViolent Sep 10 '10 at 18:53
0

Slightly modified approach of the Upvoted answer to support multiple directories and variable keywords through a GET variable (if you wish to do it that way)

if (isset($_GET["keyword"])){

   foreach(glob('*.php') as $file) { 

      $searchfor = $_GET["keyword"];
      
      // the following line prevents the browser from parsing this as HTML.
      header('Content-Type: text/plain');
      
      // get the file contents, assuming the file to be readable (and exist)
      $contents = file_get_contents($file);
      // escape special characters in the query
      $pattern = preg_quote($searchfor, '/');
      // finalise the regular expression, matching the whole line
      $pattern = "/^.*$pattern.*\$/m";
      // search, and store all matching occurences in $matches
      if(preg_match_all($pattern, $contents, $matches)){
         echo "Found matches:\n";
         echo $file. "\n";
         echo implode("\n", $matches[0]);
         echo "\n\n";
      }
      else{
      //  echo "No matches found";
      }
   }
}
Pearce
  • 320
  • 4
  • 10