i have 2 files:
text1.txt and text2.txt
how can i do this: if found a row in text1.txt that match to a row from text2.txt, delete it (or display the unique)?
this is what i have so far:
$a = file('text1.txt');
$b = file('text2.txt');
$contents = '';
foreach($b as $line2) {
foreach($a as $line1) {
if(!strstr($line1, $line2)) {
$contents .= $line1;
}
}
}
file_put_contents('unique.txt', $contents);
That will be:
file_put_contents('unique.txt', array_diff(file('text1.txt'), file('text2.txt')));
-since you're loading your files into RAM entirely, I suppose it's acceptable solution.
Also you may want to define your own function to determine if strings are equal. Logic then will be the same, but array_udiff() should be used
Related
I'm trying to get 2 random results from an array of files in the "related" directory. I've managed to pull two results randomly from the directory but I need to avoid certain results depending on a variable relating to a specific file name.
My code so far is:
$foo = "bar.php";
function random_file($dir) {
$files = opendir($dir . '/*.php');
$rand_files = array_rand($files, 2);
return array(include $files[$rand_files[0]], include $files[$rand_files[1]]);
}
list($file_1,$file_2) = random_file("related");
I'm trying to pull two random results but avoid the file: bar.php. Does anyone know of a way to omit certain results from the array as I can't find anything online even close?
You can use glob function with a specific regex to only select names that are a match for you. This will limit your initial $files variable to results that do satisfy your condition and you can continue and do the random sampling without modifications.
// entries containing foo will not be included
function random_file($dir) {
$files = glob("^(?!bar.php)*");
$rand_files = array_rand($files, 2);
return array(include $files[$rand_files[0]], include $files[$rand_files[1]]);
}
list($file_1,$file_2) = random_file("related");
You also need to consider directories such as '.' and '..'. I think a switch statement and an unset() for those values in your overall array would work. Then once you have an array with files not including what you don't want. You can then pull two randoms and return that array.
This code may not be 100% perfect but should get you in the right direction.
function random_file($dir) {
$fileArray = array();
if (is_dir($dir)) {
if ($dh = opendir($dir . '/*.php')) {
while (($file = readdir($dh)) !== false) {
$fileArray = array_push($fileArray, $file)
}
for( $i = 0; $i < count($fileArray); $i++ ) {
switch($fileArray) {
case '.':
unset($array[$i]);
break;
case '..':
unset($array[$i]);
break;
case 'bar.php':
unset($array[$i]);
break;
}
}
}
closedir($dh);
}
$rand_files_keys = array_rand($fileArray, 2);
$rand_files = $fileArray[$rand_files_keys[0]];
$rand_files = $fileArray[$rand_files_keys[1]];
return $rand_files;
try this. It will keep randomizing your array until it selects two records excluding the bar.php
$rand_files = array_rand($files, 2);
while(in_array("bar.php",$rand_files))
{
$rand_files = array_rand($files, 2);
}
I've been given a list of data and I need to split it and move it into different text files. I've tried a few things so far but cant seem to get it to work.
<?php
/*
*order the file based on surname (col 2)
*create two new text files - class A and B
*split the source text into two equal lists
*format them: ID, firstname, lastname. all words must be first letter caps
*move each list to a new file.
*close files
*/
//This function converts every attribute/variable passed to it into a sentence case
function Uppercase($convert) {
return ucwords($convert);
}
//This function compares two items to see which one is higher
//src: http://php.net/manual/en/function.usort.php
function cmp($a, $b) {
$compResult = strcmp($a[1], $b[1]);
if ($compResult == 0) {
return strcmp($a[2], $b[2]);
}else {
return $compResult;
}
}
//This function gets rid of the whitespace that is not needed
function cut($c) {
return trim($c, " \n\r\0");
}
//open file
$myfile = fopen("students.csv", "r");
echo "A";
//initialise the array, giving them 'headers'
$array = array();
echo "B";
//sort through the data, moving it to a multidimentional array and setting the first letter in each item to uppercase
$i=0;
while(!feof($myfile)){
$line = fgets($myfile);
$pieces = explode(",", $line);
$array[$i][0] = $pieces[0];
$array[$i][1] = cut(Uppercase($pieces[2]));
$array[$i][2] = cut(Uppercase($pieces[1]));
$i++;
}
echo "C";
//sort the file by the second item in the array
usort($array, "cmp");
echo array_shift($array)."<br>";
echo "D";
//create class files
$fileA = fopen("Class 1.txt", "w");
$fileB = fopen("Class 2.txt", "w");
echo "E";
//get size of array
$arraylength = count($array);
//half the array length(
$half = ceil($arraylength /= 2);
//echo $half;
//echo $arraylength."</br>";
echo "F";
echo "<pre>";
print_r($array);
echo "</br>";
//move the first class into a text file
$k = 0;
foreach ($array as $key){
echo $key[0];
if ($k < $half) {
$current = file_get_contents($fileA);
$current .= $key;
}
}
echo "G";
fclose($fileA);
fclose($fileB);
fclose($myfile);
echo "H";
When this runs, I get the following line recurring for each item in the array
Warning: file_get_contents() expects parameter 1 to be a valid path, resource given in C:\xampp\htdocs\PHPLabs\EE1600Assignment.php on line 93
The document itself has 25 items that look like this:
123, billy, bobs
Any help is appreciated. Thank you
file_get_contents expects a file path, but you are providing a file handler. You probably want instead fgets($fileA).
Alternatively, if you want to read the complete file (it's not entirely clear from your code), you can use fread($fileA).
According to the documentation, file_get_contents requires a path to the file you want to open (as per the error message you're getting - file_get_contents() expects parameter 1 to be a valid path).
You're passing in $fileA - which you created earlier using an fopen call
fopen("Class 1.txt", "w");
I have two files with same format where one has new updates and the other has older updates. There is no particular unique id column.
How can I extract the new updated lines only (with unix, PHP, AWK)?
You want to "byte" compare all lines against the other lines, so i would do:
$lines1 = file('file1.txt');
$lines2 = file('file2.txt');
$lookup = array();
foreach($lines1 as $line) {
$key = crc32($line);
if (!isset($lookup[$key])) $lookup[$key] = array();
$lookup[$key][] = $line;
}
foreach($lines2 as $line) {
$key = crc32($line);
$found = false;
if (isset($lookup[$key])) {
foreach($lookup[$key] as $lookupLine) {
if (strcmp($lookupLine, $line) == 0) {
$found = true;
break;
}
}
}
// check if not found
if (!$found) {
// output to file or do something
}
}
Note that if the files are very large this will consume quite some memory and you need to use some other mechanism, but the idea stays the same
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.
Suppose there are 2 directories on my server:
/xyz/public_html/a/
/xyz/public_html/b/
And both of them consist of many files. How do i detect the files that are common to both the folders in terms of their name and file_extension. This program is to be implemented in PHP. Any suggestions?
Using FileSystemIterator, you might do something like this...
<?
$it = new FilesystemIterator('/xyz/public_html/a/');
$commonFiles = array();
foreach ($it as $file) {
if ($file->isDot() || $file->isDir()) continue;
if (file_exists('/xyz/public_html/b/' . $file->getFilename())) {
$commonFiles[] = $file->getFilename();
}
}
Basically, you have to loop through all the files in one directory, and see if any identically-named files exist in the other directory. Remember that the file name includes the extension.
If it’s just two directories, you could use an algorithm similar to the merge algorithm of merge sort where you have two lists of already sorted items and walk them simultaneously while comparing the current items:
$iter1 = new FilesystemIterator('/xyz/public_html/a/');
$iter2 = new FilesystemIterator('/xyz/public_html/b/');
while ($iter1->valid() && $iter2->valid()) {
$diff = strcmp($iter1->current()->getFilename(), $iter2->current()->getFilename());
if ($diff === 0) {
// duplicate found
} else if ($diff < 0) {
$iter1->next();
} else {
$iter2->next();
}
}
Another solution would be to use the uniqueness of array keys so that you put each directory item into an array as key and then check for each item of the other directory if such a key exists:
$arr = array();
$iter1 = new FilesystemIterator('/xyz/public_html/a/');
foreach ($iter1 as $item) {
$arr[$item->getFilename()] = true;
}
$iter2 = new FilesystemIterator('/xyz/public_html/a/');
foreach ($iter2 as $item) {
if (array_key_exists($item->getFilename(), $arr)) {
// duplicate found
}
}
If you just want to find out which are in common, you can easily use scandir twice and find what's in common, for example:
//Remove first two elements, which will be the constant . and .. Not a very sexy solution
$filesInA = array_shift(array_shift(scandir('/xyz/publichtml/a/')));
$filesInB = array_shift(array_shift(scandir('/xyz/publichtml/b/')));
$filesInCommon = array_intersect($filesInA, $filesInB);