PHP recursive function not allowing page to load - php

I am trying to display the total number in each line of a file that does not contain a path to another file as well as the filename,
but if it has a path to another file loop through that file and sum all the number it has and the loop goes on and on as long as there exists a path to a file in the current file.
here is my code
function fileProcessor($value){
if(file_exists(trim($value))){
$total = 0;
$files = file($value, FILE_SKIP_EMPTY_LINES);
foreach($files as $data) {
if(!preg_match("/.txt/i", $data)){
$num = floatval($data);
$total += $num;
} else {
fileProcessor(trim($data));
}
}
echo $value. ' - ' .($total);
} else {
echo 'File does not exist';
}
fileProcessor('text_files/first.txt');
}
I have 3 .txt files I'm working with, inside those files I have something like this
first.txt
1
3
3
second.txt
second.txt
2
3
third.txt
third.txt
1
2
The output I am looking for
first.txt - 15
second.txt - 8
third.txt - 3
I will really appreciate it if someone can point me in the right direction, I don't know if I'm doing it right.

There are two problems with your code:
You're not including the directory for the source file in the path to subsidiary files, so those files are never found.
You're not returning the total from the function so that higher level invocations can add the total for subsidiary files
Correcting those issues, and renaming the variables to something meaningful gives this code:
function fileProcessor($filename){
if(file_exists(trim($filename))){
$total = 0;
$rows = file($filename, FILE_SKIP_EMPTY_LINES);
foreach($rows as $data) {
if(!preg_match("/.txt/i", $data)){
$num = floatval($data);
$total += $num;
}else {
$total += fileProcessor(dirname($filename)."/".trim($data));
}
}
echo $filename. ' - ' .($total)."<br>\n";
}else{
echo "File does not exist<br>\n";
}
return $total;
}
fileProcessor('text_files/first.txt');
Output:
text_files/third.txt - 3
text_files/second.txt - 8
text_files/first.txt - 15
This lists the files in the order in which the totals are finally accumulated, so the lowest levels appear first.
[Edit]
I spotted a problem with the order of results if two or more filenames appear in a file. Here's a reworked version that deals with that.
To list the files in the order in which they are encountered requires reversing the natural order. In the new version below I've placed the filenames in a $fileList array which is passed down by reference. Each new invocation of the function adds its results to the end of that array. Once processing is complete the array is displayed.
function fileProcessor( &$fileList){
// Get the last filename in the array
end($fileList);
$filename = key($fileList);
if(file_exists(trim($filename))){
// Accumulate the values
$fileList[$filename] = 0;
$rows = file($filename, FILE_SKIP_EMPTY_LINES);
foreach($rows as $data) {
if(!preg_match("/.txt/i", $data)){
$num = floatval($data);
$fileList[$filename] += $num;
}else {
// Recursive call. Add the next filename to the array
$fileList[dirname($filename)."/".trim($data)]=0;
$fileList[$filename] += fileProcessor($fileList);
}
}
} else {
$fileList[$filename]= "File does not exist: $filename";
}
// return the total for the file to add to the accumulator for the file above.
return $fileList[$filename];
}
// Place the initial file in the array
$results = ['text_files/first.txt' => 0];
// run the function
fileProcessor($results);
// display the results
foreach($results as $filename=>$total) {
echo $filename.' - '.$total."<br>\n";
}
Output:
text_files/first.txt - 15
text_files/second.txt - 8
text_files/third.txt - 3

You could use the static var:
<?php
function fileProcessor($value) {
static $results = [];
if (file_exists(trim($value))) {
$results[$value] = 0;
$files = file($value, FILE_SKIP_EMPTY_LINES);
foreach($files as $data) {
if (!preg_match("/.txt/i", $data)) {
$num = floatval($data);
$results[$value] += $num;
} else {
fileProcessor(trim($data));
}
}
} else {
echo 'File does not exist';
}
reset($results);
if (key($results) != $value) {
return;
}
foreach($results as $key => $value) {
echo $key. ' - ' .$value."\n";
}
}
fileProcessor('text_files/first.txt');
Output:
text_files/first.txt - 7
text_files/second.txt - 5
text_files/third.txt - 3

Related

Converting csv to array causing "Tokenization is skipped for long lines for performance reasons."

After uploading a CSV, I am trying to convert the first column (a list of domains) to an array and add the array items to a txt file.
So the CSV shows:
test.com
test2.net
test3.org
And the txt file should show them like this:
test.com, test2.net, test3.org
Everything works, except the first row (test.com) doesn't seem to be converting as text properly. All of the other rows work fine. When I look at the txt file, the content is there and doesn't seem to show an issue, but in my IDE it shows an error before the first item: Tokenization is skipped for long lines for performance reasons.
Screenshot of my txt file in VS Code:
I need to check each domain in the txt file before adding new domains to prevent duplicates, and it's not recognizing test.com as being there already.
So I ran a test to compare the array to a manually written array with the same values, and sure enough test.com and test.com do not equal each other. The other domains do.
// Converting a CSV UTF-8 (Comma delimited) to array
function csv_to_array( $filepath ) {
// Get the rows
$rows = array_map('str_getcsv', file( $filepath ));
// Store the items here
$csv = [];
// Grab the items
foreach($rows as $row) {
$csv[] = $row[0];
}
// Return the array
return $csv;
}
Running my test:
$csv_url = 'test.csv';
$csv_domains = csv_to_array( $csv_url );
print_r($csv_domains);
$csv_domains_string = implode(', ', $csv_domains);
print_r('<br>'.$csv_domains_string);
echo '<br><hr><br>';
$compare_domains = ['test.com', 'test2.net', 'test3.org'];
print_r($compare_domains);
$compare_domains_string = implode(', ', $compare_domains);
print_r('<br>'.$compare_domains_string);
echo '<br><hr><br>';
if ($csv_domains[0] === $compare_domains[0]) {
echo '<br>true: ';
echo '$csv_domains[0] ('.$csv_domains[0].') = $compare_domains[0] ('.$compare_domains[0].')';
} else {
echo '<br>false: ';
echo '$csv_domains[0] ('.$csv_domains[0].') != $compare_domains[0] ('.$compare_domains[0].')';
}
echo '<br><hr><br>';
if ($csv_domains[1] === $compare_domains[1]) {
echo '<br>true: ';
echo '$csv_domains[1] ('.$csv_domains[1].') = $compare_domains[1] ('.$compare_domains[1].')';
} else {
echo '<br>false: ';
echo '$csv_domains[1] ('.$csv_domains[1].') != $compare_domains[1] ('.$compare_domains[1].')';
}
echo '<br><hr><br>';
if ($csv_domains[2] === $compare_domains[2]) {
echo '<br>true: ';
echo '$csv_domains[2] ('.$csv_domains[2].') = $compare_domains[0] ('.$compare_domains[2].')';
} else {
echo '<br>false: ';
echo '$csv_domains[2] ('.$csv_domains[2].') != $compare_domains[0] ('.$compare_domains[2].')';
}
Result:
So how do I fix this?
EDIT: var_dump returns two different values:
var_dump($csv_domains[0]); // string(11) "test.com"
var_dump($compare_domains[0]); // string(8) "test.com"
Thanks to #ChrisHaas, I was able to fix it by changing the for loop and removing the BOM from the first cell:
$count = 0;
foreach($rows as $row) {
if ($count == 0) {
$new_row = str_replace("\xEF\xBB\xBF",'', $row[0]);
} else {
$new_row = $row[0];
}
$csv[] = $new_row;
$count++;
}

PHP Moving an array into different text files?

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");

Array intersect inside a while loop

I am trying to with array_intersect match variable sku to the csv file,
When running it it causes a white page
while (($result = fgetcsv($ocuk,1024,"\t")) !== false)
{
$csvfull[] = $result;
}
$count=count($csvfull);
$sku = array();
foreach ($csvfull as $row)
{
$sku[] = $row[1];
}
$csv = fgetcsv($ocuk);
while ($x <= $count)
{
array_intersect($sku[$x], $csv)
echo
'',$csv[1], //sku
'test<br>';
$x++;
}
All I require is for array_intersect to check for sku in the csv file and then display the information requested from the csv file
example
sku = fb706, the array intersect finds it in the csv file then displays column 1 in the csv files
Is your $csv variable just a one dimensional array of skus? Seems unlikely but if thats the case then use in_array
while ($x <= $count)
{
if(in_array($sku[$x], $csv){
//the sku is present in the array
}
$x++;
}

PHP CSVImporter

I had a script called CSVimporter V3 for PHP that I used to run on a website and it worked fine. A couple of years later I've now dug out the same script to use on another project, all works okay except the CSV files are being read as one long line, as opposed to header row and multiple lines.
Here is part of the script.
Any ideas why it would be being read as a long line?
<?php
// Reference session variable for short-hand
$f = &$_SESSION['csv_file'];
// Open file - fp = file pointer
if (!$fp = #fopen($f, 'r')) {
error(L_ERROR_PREVIEW_NO_FILE);
} else {
// Array to store each row to be inserted
$batch = array();
// Row counter
$rc = 0;
// Work out starting row
switch ($_SESSION['csv_first_row']) {
case 'data':
$start_row = 0;
break;
default:
$start_row = 1;
}
// Get contents, while below preview limit and there's data to be read
while ($data = fgetcsv($fp, 1024, delimiter_to_char($_SESSION['csv_delimiter']))) {
if ($rc < $start_row) {
// Incremement counter
$rc++;
// Go to next loop
continue;
} else {
// Array to store data to be inputted
$values = array();
// Loop data
for ($i = 0; $i < count($data); $i++) {
// If data is wanted, put data into array
if (array_key_exists($i, $column_index)) {
$values[$column_index[$i]] = $data[$i];
}
}
// Sort array into correct order by index
ksort($values);
// Join values together and store in array
$batch[] = '("' . implode('", "', str_replace('"', '\"', $values)) . '","'.$accti.'","'.$impt.'")';
}
}
}
// Close the file
fclose($fp);
I added this at the top of the code and it all works now!
ini_set('auto_detect_line_endings', true);

Find intersection/frequency of a word in multiple file

<?php
$wordFrequencyArray = array();
function countWordsfrequency($filename) {
global $wordFrequencyArray;
$contentoffile = (file_get_contents($filename));
$wordArray = preg_split('/[^a-zA-Z0-9]/', $contentoffile, -1, NO_EMPTY);
foreach (array_count_values($wordArray) as $word => $count) {
if (!isset($wordFrequencyArray[$word])) $wordFrequencyArray[$word] = 0;
$wordFrequencyArray[$word] += $count;
}
}
$filenames = array('file1.txt', 'file2.txt','file3.txt','file4.txt');
foreach ($filenames as $filename) {
countWordsfrequency($filename);
}
print_r($wordFrequencyArray);
?>
This is the my code to find the frequency of each word in multiple files and print them.Now what i want to do is check find intersection that which word occurs in which files .For example if there is a word "stack" i want to print in which files it occurs and its frequency which i think i have already calculated.
Final result should be like the frequency followed by in which files that word occurs.
How should i proceed with it? Should i check it in the for loop in the countWords function itself.
You will have to save a little more information. I am going to shy away from using classes because it seems like you do not need anything too robust.
<?php
$wordFrequencies = array();
function countWordsFrequency($filename) {
global $wordFrequencies;
$contentoffile = (file_get_contents($filename));
$wordArray = preg_split('/[^a-zA-Z0-9]/', $contentoffile, -1, NO_EMPTY);
foreach (array_count_values($wordArray) as $word => $count) {
$wordFreqInfo = $wordFrequencies[$word];
if (!isset($wordFreqInfo)) {
$wordFreqInfo = array();
$wordFreqInfo['total'] = 0;
$wordFreqInfo['files'] = array();
$wordFrequencies[$word] = $wordFreqInfo;
}
// If this is the first occurence of this word in the file, start a count.
if (!isset($wordFreqInfo['files'][$filename]))
$wordFreqInfo['files'][$filename] = 0;
}
// Increment counts for both the total and the file.
$wordFreqInfo['total'] += $count;
$wordFreqInfo['files'][$filename] += $count;
}
}
$filenames = array('file1.txt', 'file2.txt','file3.txt','file4.txt');
foreach ($filenames as $filename) {
countWordsFrequency($filename);
}
print_r($wordFrequencies);
?>

Categories