I store data from an article in a .txt file.
A txt file looks like this:
id_20201010120010 // id of article
Sport // category of article
data/uploads/image-1602324010_resized.jpg // image of article
Champions League // title of article
Nunc porttitor ut augue sit amet maximus... // content of the article
2020-10-10 12:00 // date article
John // author of article
oPXWlZp+op7B0+/v5Y9khQ== // encrypted email of author
football,soccer // tags of article
true // boolean (SHOULD BE IGNORED WHEN SEARCHING)
false // boolean (SHOULD BE IGNORED WHEN SEARCHING)
For searching in articles, is use this code below:
$searchthis = strtolower('Nunc');
$searchmatches = [];
foreach($articles as $article) { // Loop through all the articles
$handle = #fopen($article, "r");
if ($handle) {
while (!feof($handle)) {
$buffer = fgets($handle);
if(strpos(strtolower($buffer), $searchthis) !== FALSE) { // strtolower; search word not case sensitive
$searchmatches[] = $article; // array of articles with search matches
}
}
fclose($handle);
}
}
//show results:
if(empty($searchmatches)) { // if empty array
echo 'no match found';
}
print_r($searchmatches);
This works all fine! But when searching on a word like true, he finds almost all articles because in all articles are the 2 booleans at the last lines. So how can i skip these 2 last lines of the txt file from searching?
One way to do this would be to use file to read the entire file into an array, then array_slice to strip the last two elements from the array. You can then iterate through the array looking for the search value. Note you can use stripos to do a case-insensitive search:
foreach ($articles as $article) {
$data = file($article);
if ($data === false) continue;
$data = array_slice($data, 0, -2);
$search = 'league';
foreach ($data as $value) {
if (stripos($value, $search) !== false) {
$searchmatches[] = $article;
}
}
}
To read your file, instead of using fopen, fgets, etc, like with some C code, just use the file() function. It will read all the file and put it inside an array of lines. Then select the lines where you want to do a search.
<?php
$article = file('article-20201010120010.txt');
// Access each information of the article you need directly.
$id = $article[0];
$category = $article[1];
// etc...
// Or do it like this with the list() operator of PHP:
list($id, $category, $image, $title, $content, $date, $author, $email_encrypted, $tags, $option_1, $option_2) = $article;
// Now do the insensitive seach in the desired fields.
$search = 'porttitor'; // or whatever typed.
if (($pos = stripos($content, $search)) !== false) {
print "Found $search at position $pos\n";
} else {
print "$search not found!\n";
}
Related
I'm attempting to make a search feature for my website using PHP. Right now, I have this code to create an array of all files in a directory, which works just fine, but I've hit a snag with my next step. I want it to now list all elements in that array that contain a certain word (the users search), this way I can do something with them later in HTML. My idea was to make a loop that runs strpos for each element and list only the ones it finds matches for. I've tried that, but it always gave me nothing. This is my honest attempt:
<?php
$search = "Pitfall";
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.')) as $filename)
{
if ($filename->isDir()) continue;
foreach ($filename as &$result)
{
$pos = strpos($result, $search);
if ($pos === true) {
echo "$result\n";
}
}
}
?>
Thank you for any help
I think your issue is with your conditional:
if ($pos === true)
strpos() does not return true. It returns the position of the string or false. See docs. You could instead use:
if ($pos !== false)
Edited:
The RecusiveIteratorIterator does not return a string. It returns an object. Here I am typecasting the object so that it gets the correct filename. From there, you don't need to iterate over again, as this is just a string at this point.
$search = "wp-config";
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.')) as $filename)
{
$filename = (string) $filename;
if (is_dir($filename)) continue;
$pos = strpos($filename, $search);
if ($pos !== false) {
echo "$filename <br />";
}
}
How do I search a file and return an array of the results so that I can use it in a collection in PHP?
So, for example, say I have a .txt file with something like:
hellohello
hihi
heywhats up
hello hey whats up
hello
And I want to search for all occurrences with hello and its line number, then return it as an array so I can use it in a data collector.
So, it would return the line number and line, like:
$results = array
(
array('1', 'hellohello'),
array('4', 'hello hey whats up'),
array('5', 'hello'),
);
My idea is to us file_get_contents.
So, for example..
$file = 'example.txt';
function get_file($file) {
$file = file_get_contents($file);
return $file;
}
function searchFile($search_str) {
$matches = preg_match('/$search_str/i', get_file($file);
return $matches;
}
As an alternative, you could also use file() function so it reads the entire file into an array. Then you could just loop, then search. Rough example:
$file = 'example.txt';
$search = 'hello';
$results = array();
$contents = file($file);
foreach($contents as $line => $text) {
if(stripos($text, $search) !== false) {
$results[] = array($line+1, $text);
}
}
print_r($results);
Sidenote: stripos() is just an example, you could still use your other way/preference to search the needle for that particular line.
How can I find a needle in a haystack, and show the entire line?
log.txt :
Log #5731: JohnDoe has arrested JaneDoe
Log #5732: DonDoe has arrested JaneDoe
I want to search for "JohnDoe" and display the whole lineLog #5731: JohnDoe has arrested JaneDoe.
Also, if there's several logs for one person I want to show them all
You could explode your text by newline.
Then search for what you want using array_search method and have the key of that element in the array.
Tho I wouldn't recommend that first solution, if your log is or becomes big (which should be the case for most logs), since the entire log has to be loaded and put into an array. That eats up a massive ammount of resources.
I'd rather do like
<?php
$logfilepath = 'path/to/log.txt';
function searchLog($logfilepath, $searchQuery) {
$fileresource = fopen($logfilepath, 'r');
while (($buffer = fgets($handle)) !== false) {
//now search in buffer
if(strpos($buffer, $searchQuery) !== false) {
return $buffer;
}
}
}
Edit: If you want to find all occurences:
<?php
$logfilepath = 'path/to/log.txt';
function searchLog($logfilepath, $searchQuery) {
$fileresource = fopen($logfilepath, 'r');
$occurences = array();
while (($buffer = fgets($handle)) !== false) {
//now search in buffer
if(strpos($buffer, $searchQuery) !== false) {
$occurences[] = $buffer;
}
}
return $occurences;
}
If the data source is a file and the definition of "entire line" is a newline delimiter, I would use file() to explode the data into an array and then loop through it:
function findLines($file_path, $needle) {
$file_lines = file($file_path);
foreach($file_lines as $line) {
if(strpos($line, $needle) !== false) {
$matching_lines[] = $line;
}
}
return $matching_lines;
}
$needle = 'JohnDoe';
$log_entries = findLines('/path/to/log.txt', $needle);
I have this textfile:
foo: bar
el: macho
bing: bong
cake color: blue berry
mayo: ello
And I what I'm trying to accomplish is that if I "look" for foo, it returns bar (if I look for bing, it should return bong). A way a tried to accomplish this is first search though the file, return the line with the result, put it in a string and remove everything before the ":" and display the string.
// What to look for
$search = 'bing';
// 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;
$new_str = substr($line, ($pos = strpos($line, ',')) !== false ? $pos + 1 : 0);
}
echo "<br>";
echo "bing should return bong:";
echo $new_str;
But it doesn't work. Up here is just one of the many things I've tried.
Sources:
Many stackoverflow links on and comparable searches:
https://www.google.com/search?client=opera&q=php+remove+everything+after
https://www.google.com/search?client=opera&q=php+search+text+file+return+line
I've asked a question before, but the answers are to "professional" for me, I really need a noob-proof solution/answer. I've been trying to figure it out all day but I just can't get this to work.
Edit:
It's solved! Thank you so much for your time & help, I hope this might be useful to someone else to!
This should work with what you are looking for, I tested it on my server and it seems to fit what you are looking for.
$lines_array = file("file.txt");
$search_string = "bing";
foreach($lines_array as $line) {
if(strpos($line, $search_string) !== false) {
list(, $new_str) = explode(":", $line);
// If you don't want the space before the word bong, uncomment the following line.
//$new_str = trim($new_str);
}
}
echo $new_str;
?>
I would do it this way:
foreach($lines as $line)
{
// explode the line into an array
$values = explode(':',$line);
// trim the whitspace from the value
if(trim($values[1]) == $search)
{
echo "found value for ".$search.": ".$values[1];
// exit the foreach if we found the needle
break;
}
}
$search = 'bing';
// Read from file
$lines = file('text.txt');
$linea='';
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) {
$liner=explode(': ',$line);
$linea.= $liner[1];
}
}
echo 'Search returned: '. $linea;
Explanation: - $linea var is created before loop, and it will contain search result. If value is found on line - explode string, and make array, get second var from array, put it in search results container variable.
As your data is almost YAML [see lint], you could use a parser in order to get the associated PHP array.
But if can go with your solution as well:
// What to look for
$search = 'bing';
// 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 array_pop(explode(":", $line));
}
}
Use fgetcsv:
$bits = array();
if (($handle = fopen('t.txt','r')) !== FALSE) {
while (($data = fgetcsv($handle, 0, ":")) !== FALSE) {
$bits[$data[0]] = $data[1];
}
}
# Now, you search
echo $bits['foo'];
$bits will have a key for each split part, which makes your ultimate goal quite simple. Here is what it looks like:
Array
(
[foo] => bar
[el] => macho
[bing] => bong
[cake color] => blue berry
[mayo] => ello
)
I want to record downloads in a text file
Someone comes to my site and downloads something, it will add a new row to the text file if it hasn't already or increment the current one.
I have tried
$filename = 'a.txt';
$lines = file($filename);
$linea = array();
foreach ($lines as $line)
{
$linea[] = explode("|",$line);
}
$linea[0][1] ++;
$a = $linea[0][0] . "|" . $linea[0][1];
file_put_contents($filename, $a);
but it always increments it by more than 1
The text file format is
name|download_count
You're doing your incrementing outside of the for loop, and only accessing the [0]th element so nothing is changing anywhere else.
This should probably look something like:
$filename = 'a.txt';
$lines = file($filename);
// $k = key, $v = value
foreach ($lines as $k=>$v) {
$exploded = explode("|", $v);
// Does this match the site name you're trying to increment?
if ($exploded[0] == "some_name_up_to_you") {
$exploded[1]++;
// To make changes to the source array,
// it must be referenced using the key.
// (If you just change $v, the source won't be updated.)
$lines[$k] = implode("|", $exploded);
}
}
// Write.
file_put_contents($filename, $lines);
You should probably be using a database for this, though. Check out PDO and MYSQL and you'll be on your way to awesomeness.
EDIT
To do what you mentioned in your comments, you can set a boolean flag, and trigger it as you walk through the array. This may warrant a break, too, if you're only looking for one thing:
...
$found = false;
foreach ($lines as $k=>$v) {
$exploded = explode("|", $v);
if ($exploded[0] == "some_name_up_to_you") {
$found = true;
$exploded[1]++;
$lines[$k] = implode("|", $exploded);
break; // ???
}
}
if (!$found) {
$lines[] = "THE_NEW_SITE|1";
}
...
one hand you are using a foreach loop, another hand you are write only the first line into your file after storing it in $a... it's making me confuse what do you have in your .txt file...
Try this below code... hope it will solve your problem...
$filename = 'a.txt';
// get file contents and split it...
$data = explode('|',file_get_contents($filename));
// increment the counting number...
$data[1]++;
// join the contents...
$data = implode('|',$data);
file_put_contents($filename, $data);
Instead of creating your own structure inside a text file, why not just use PHP arrays to keep track? You should also apply proper locking to prevent race conditions:
function recordDownload($download, $counter = 'default')
{
// open lock file and acquire exclusive lock
if (false === ($f = fopen("$counter.lock", "c"))) {
return;
}
flock($f, LOCK_EX);
// read counter data
if (file_exists("$counter.stats")) {
$stats = include "$counter.stats";
} else {
$stats = array();
}
if (isset($stats[$download])) {
$stats[$download]++;
} else {
$stats[$download] = 1;
}
// write back counter data
file_put_contents('counter.txt', '<?php return ' . var_export($stats, true) . '?>');
// release exclusive lock
fclose($f);
}
recordDownload('product1'); // will save in default.stats
recordDownload('product2', 'special'); // will save in special.stats
personally i suggest using a json blob as the content of the text file. then you can read the file into php, decode it (json_decode), manipulate the data, then resave it.