Invalid argument supplied for foreach() + Logic of Script - php

I posted a similar question earlier today, however I recently downloaded xampp and can now get syntax errors. I'm very new to all of this.
Please see this example to see the current state of my .php file: http://rich2233.comoj.com/file2.php
I can get the .txt file to extract and display the content from the .txt file, but any attempt of modifying the .txt file does not happen.
When I ran this on xampp, I got this error: Invalid argument supplied for foreach() in file2.php on line 30

After your most recent update of the code: The answer to the error message in the question title is:
The code is missing the line $users = file("test.txt");

Here's a quick tip: keep track of your iterator. Confusing? Think of each row number as unique offset in the file. You need to iterate (foreach) and increment it by +1 each time. When you're editing a row later on, you just need to submit the offset number, iterate again and check if $i == $_POST['iterator'].
// Iterator example
$users = file('text.txt');
$hours_taken = array();
foreach ($users as $user) {
list($time, $name) = explode('|', $user);
array_push($hours_taken, $time);
}
// Assuming same order of rows in users.txt
$hours = array('8:00 am', '9:00 am', '10:00 am'); // ...5:00 pm
$i = 1;
echo '<select name="time"><option selected>-- Select time --</option>';
foreach ($hours as $hour) {
if (in_array($hour, $hours_taken)) {
echo '<option disabled=disabled>'. $hour .'</option>';
}
else {
echo '<option value='. $i .'>'. $hour .'</option>';
}
$i++;
}

Edited as that last function wouldn't have worked
function editTxt(){
$find_name = $_POST['name'];
$find_time = $_POST['time'];
$filename = getcwd() . "/test.txt";
$lines = file( $filename , FILE_IGNORE_NEW_LINES );
foreach($lines as $key => $line)
{
list($time, $name) = explode('|', $line);
if($time == $find_time && $name == "Available")
{
$lines[$key] = $time."|".$find_name;
file_put_contents( $filename , $lines );
break;
}
}
}
If you are planning to use this for something other than just an exercise I suggest using a database.

Try:
$users = file($filename);
I suspect $users === false as you aren't using the same "calculated" file name.

Related

Fatal error: Uncaught Error: Call to a member function format() on bool on line 58

I must retrieve data from a CSV file and to show the month and year from a date written in string format.I run the code and it shows the A non well formed numeric value encountered error.I also tried other ways to convert the date and I get the year 1900 for each date.
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
require('php_library/spreadsheet-reader-master/php-excel-reader/excel_reader2.php');
require('php_library/spreadsheet-reader-master/SpreadsheetReader.php');
if(isset($_FILES["filename"]))
{
$file = $_FILES["filename"]["tmp_name"];
$file_open = fopen($file,"r");
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$spreadsheet = $reader->load($file);
$sheetData = $spreadsheet->getActiveSheet()->toArray();
foreach ($sheetData as $i=>$Row)
{
foreach($Row as $j=>$column)
{
// echo $Row[$j].", ";
if($i == 0)
{
if($Row[$j] == "Codice cliente")
$column1 = $j;
if($Row[$j] == "Data emissione")
{
$column2 = $j;
// echo $j;
}
}
}
}
foreach ($sheetData as $i=>$row)
{
if($i!=0){
json_encode(\PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($row[$column2])->format('Y'));
}
I guess this is the offending line in your code; it's the only line using a ->format() method.
json_encode(\PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($row[$column2])->format('Y'));
Let's try breaking it into multiple lines so it's readable.
$excelDatestamp = $row[$column2];
$dto = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject( $excelDatestamp );
$year = $dto->format( 'Y' );
json_encode( $year );
It seems likely to me that the $excelDatestamp generated by this refactoring of your code is malformed. That makes ::excelToDateTimeObject() return false, letting you know you have an error. Then you try to invoke the format method like this (false)->format( 'Y' ). That's why php threw the error message you showed us.
And, you don't do anything with the output of json_encode() so even if everything worked it would get lost.

looping through txt file to use specific part of a string

I am new to Php and can't seem to figure this out no matter how much I've googled.
So I've opened the txt file (which consists of multiple lines of this type of string unique Identifier IMEI in bold:
Rx:00:39:54 06/09/2015:+RESP:GTEPS,210101,863286020022449,,8296,01,1,3,0.0,0,1031.1,29.367950,-30.799161,20150906003710,,,,,,2857.9,20150906003710,8038$) There are different strings with different IMEIs but i only want to use a specific one.
My question is, how do I extract/only use the string with the same Unique identifier and then loop through those to use in another function?
My function has different cases and each case has different calculations, so I'll need to loop through the txt file (with e.g. 863286020022449 as Identifier, ignoring other identifiers/IMEIs) in order to use the string in my function as below:
This is my starter function:
function GetParam($unknownFunction, $numberCommas) {
$returnString = "";
$foundSting = 0;
$numberFound = 0;
$len = strlen($unknownFunction);
for ($i = 0; $i < $len; ++$i) {
if ($Rawline[$i] == ",") {
++$numberFound;
if ($numberFound > $numberCommas)
break;
if ($numberFound == $numberCommas)
$foundSting = 1;
}
else if ($foundSting == 1) {
$returnString .= $unknownFunction[$i];
}
}
return $returnString;
echo $returnString;
}
$i = strpos($unknownFunction, ":GT");
$p = substr($unknownFunction, $i+3,3);
$Protocol = GetParam($unknownFunction, 1);
//this switch reads the differences in the message types (e.g. HBD- in this case is a heartbeat message type and would thus have a different amount of commas in the string and has different definitions of the characters within the commas)
switch ($p) {
case 'HBD':
//+ACK:GTHBD,220100,135790246811220,,20100214093254,11F0$
//This is an example of an HBD message
$result2["Type"] = 'Heart beat';
$IMEI = GetParam($unknownFunction, 2);
$mDate = GetParam($unknownFunction, 4);
$mDate = substr($mDate,0,4).'-'.substr($mDate,4,2).'-
'.substr($mDate,6,2).'
'.substr($mDate,8,2).':'.substr($mDate,10,2).':'.substr($mDate,12,2);
break;
This is the biggest problem I am facing at the moment and when I print the different lines, it indicates the correct IMEI but it does not loop through the whole file to use each string that belongs to that IMEI.
Your assistance would be greatly appreciated.
Thank you so much.
Example of input file:
Rx:00:00:00 28/02/2018:+RESP:GTFRI,3C0103,862045030241360,,14067,11,1,1,29.7,320,151.1,30.949307,-29.819685,20180227235959,0655,0001,013A,87B6,00,35484.1,01500:51:31,,,100,220101,,,,20180228000000,3461$
Rx:00:00:01 28/02/2018:+RESP:GTERI,380201,869606020047340,gv65,00000002,14076,10,1,1,119.0,119,24.3,18.668516,-34.016808,20180227235955,0655,0001,00F7,2DC9,00,98912.0,02235:20:25,0,100,220101,0,0,20180227235958,FF20$
Rx:00:00:03 28/02/2018:+RESP:GTERI,380201,869606020162990,,00000002,12912,10,1,1,0.0,230,1127.3,30.846671,-27.674206,20180227235956,0655,0001,013E,88B0,00,106651.1,03546:44:42,0,100,210101,0,0,20180227235959,6190$
Rx:00:00:03 28/02/2018:+ACK:GTHBD,450102,865084030005340,gb100,20180228000003,CC61$
Rx:00:00:03 28/02/2018:+RESP:GTERI,380201,869606020115980,,00000002,13640,10,1,1,12.1,353,1663.1,28.580726,-28.162208,20180227235957,,,,,,37599.6,02422:07:24,0,100,220101,0,0,20180228000000,1937$
Rx:00:00:04 28/02/2018:+RESP:GTERI,380502,869606020276840,gv65,00000002,12723,10,1,1,0.0,106,1232.8,22.878013,-27.951762,20180227235952,0655,0001,0204,63C5,00,13808.9,00778:32:20,0,100,210100,0,0,20180228000002,2C50$
Rx:00:00:04 28/02/2018:+RESP:GTERI,380502,869606020274530,gv65,00000002,12683,10,1,1,0.0,91,1213.7,24.863444,-28.174319,20180227235956,0655,0001,0203,69F1,00,9753.2,00673:49:21,0,100,210100,0,0,20180228000003,8AC7$
Rx:00:00:05 28/02/2018:+ACK:GTHBD,380201,863286023083810,,20180228000003,0D87$
Rx:00:00:06 28/02/2018:+RESP:GTFRI,3C0103,862045030241360,,14086,10,1,1,34.0,327,152.0,30.949152,-29.819501,20180228000002,0655,0001,013A,87B6,00,35484.1,01500:51:36,,,100,220101,,,,20180228000005,3462$
Rx:00:00:06 28/02/2018:+ACK:GTHBD,060228,862894021626380,,20180228000007,F9A5$
Rx:00:00:07 28/02/2018:+RESP:GTERI,380201,869606020019430,,00000002,12653,10,1,1,0.0,219,1338.7,26.882063,-28.138099,20180228000002,,,,,,86473.7,05645:48:34,0,93,210101,0,0,20180228000003,0FA5$
Rx:00:00:09 28/02/2018:+ACK:GTHBD,380502,869606020233940,gv65,20180228000008,7416$
Rx:00:00:10 28/02/2018:+RESP:GTAIS,380201,869606020171710,,11,11,1,1,0.0,95,281.2,30.855164,-29.896575,20180228000009,0655,0001,0156,9A9F,00,156073.7,20180228000008,F9A4$
Each GT message means something which is why i need to extract only one specific IMEI and use the result in my function as a breakdown of what every set of numbers between the commas actually mean. The end result needs to be populated in an excel spreadsheet but that's a different issue.
Nested foreach, keeping tracking of the IMEIs you've already gone through. Or something like this.
<?php
$filename = 'info.txt';
$contents = file($filename);
foreach ($contents as $line) {
$doneAlreadyArray = array();
$IMEI = GetParam($line, 2);
foreach ($contents as $IMEIline){
$thisIMEI = GetParam($IMEIline,2);
//check if already done the IMEI previously
if (!in_array($thisIMEI, $doneAlreadyArray)){
//matching IMEIs?
if ($thisIMEI == $IMEI){
//run new function with entire $IMEIline
new_function($IMEIline);
}
}
}
//add IMEI to doneAlreadyArray
array_push($doneAlreadyArray,$IMEI);
}
?>
If I've understood your question right and you want to extract the string(line) with the same Unique identifier, this may be useful for your needs as a strating point.
The example is very basic, and use data from your question:
<?php
// Read the file.
$filename = 'input.txt';
$file = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// Each item of $output will contain an array of lines:
$output = array();
foreach ($file as $row) {
$a = explode(',', $row);
$imei = $a[2];
if (!array_key_exists($imei, $output)) {
$output[$imei] = array();
}
$output[$imei][] = $row;
}
// Then do what you want ...
foreach ($output as $key=>$value) {
echo 'IMEI: '.$key.'</br>';
foreach($value as $row) {
// Here you can call your functions. I just echo the row:
echo $row.'</br>';
}
}
?>
thank you for the feedback.
Ryan Dewberry ended up helping me.
The fix was simpler than I thought too :)
//Unknownfunction is now $line
function GetParam($line, $numberCommas) {
$returnString = "";
$foundSting = 0;
$numberFound = 0;
$len = strlen($line);
for ($i = 0; $i < $len; ++$i) {
if ($line[$i] == ",") {
++$numberFound;
if ($numberFound > $numberCommas)
break;
if ($numberFound == $numberCommas)
$foundSting = 1;
}
else if ($foundSting == 1) {
$returnString .= $line[$i];
}
}
return $returnString;
// print $returnString;
}
//this is new - makes sure I use the correct IMEI
$contents = file($fileName);
foreach ($contents as $line){
$haveData = 0;
$IMEI = GetParam($line, 2);
if ($IMEI == $gprsid){
$i = strpos($line, ":GT");
$p = substr($line, $i+3,3);
$Protocol = GetParam($line, 1);
//this is the part I struggled with as well - This is an array of all of my
//calculation
//results and in printing it out I can see that everything is working
$superResult = array();
array_push($superResult,$result2);
print_r($superResult);
}
}
Much appreciated. Thank you!

SplFileObject + LimitIterator + offset

I have data file with two lines (two lines just for my example, in real, that file can contain millions of lines) and I use SplFileObject and LimitIterator with offseting. But this combination have strange behaviour in some cases:
$offset = 0;
$file = new \SplFileObject($filePath);
$fileIterator = new \LimitIterator($file, $offset, 100);
foreach ($fileIterator as $key => $line) {
echo $key;
}
Output is: 01
But with $offset set to 1, output is blank (foreach doesn't iterate any line).
My data file contain this:
{"generatedAt":1434665322,"numRecords":"1}
{"id":"215255","code":"NB000110"}
What I'm doing wrong?
Thanks
Required:
Use SplFileObject to process a number of records from:
a given start record number
for a given number of records or until EOF.
The issue is that SplFileObject gets confused as regards the last record in the file. This prevents it working correctly in foreach loops.
This code uses the SplFileObject and 'skip records' and 'processes records'. Alas, It cannot use foreach loops.
Skip a number of records from the start of the file ($offset).
Process a given number of records or unit the end of file ($recordsToProccess)
The code:
<?php
$filePath = __DIR__ . '/Q30932555.txt';
// $filePath = __DIR__ . '/Q30932555_1.txt';
$offset = 1;
$recordsToProcess = 100;
$file = new \SplFileObject($filePath);
// skip the records
$file->seek($offset);
$recordsProcessed = 0;
while ( ($file->valid() || strlen($file->current()) > 0)
&& $recordsProcessed < $recordsToProcess
) {
$recordsProcessed++;
echo '<br />', 'current: ', $file->key(), ' ', $file->current();
$file->next();
}
Reading the related PHP bug 65601 suggests adding the READ_AHEAD flag will fix this. Tested and works as you expected it to.
$offset = 0;
$file = new \SplFileObject($filePath);
$file->setFlags(SplFileObject::READ_AHEAD);
$fileIterator = new \LimitIterator($file, $offset, 100);
foreach ($fileIterator as $key => $line) {
echo $key;
}

PHP - search and replace then sort and echo

I've managed (well, stackoverflow has shown me how) to search a directory on my server and echo and image. The trouble is the images in the folder are named by an IP camera yy_mm_dd_hh_mm where dd (and other date digits) have either one or two digits. I need them to have a preceeding zero so that I don't end up with, for example, an image taken at 9:50am being treated as a higher value than the photo taken more recently, at 10:05am. (I want it to treat it as 09_50 and 10_05 to fix the issue).
I've looked at search and replace but cannot get this to work within my current code:
function webcam_image () {
foreach (glob( "../camera/IPC_IPCamera*.jpg") as $f ) {
$list[] = $f;
}
sort($list);
echo array_pop($list);
}
example file = IPC_IPCamera_13_7_24_9_57_45.jpg
any help would be much appreciated!
Thanks
Ali
I would ignore the file name altogether and use a DirectoryIterator, fetching the files actual modified date. Something like this might work.
$files = array();
$iterator = new \DirectoryIterator('/path/to/dir');
foreach ($iterator as $file) {
if(! $file->isDot()) $files[$file->getMTime()] = $file->getFilename();
}
ksort($files);
print_r($files);
Take a look here for more information: http://php.net/manual/en/class.directoryiterator.php
If I have understood you correctly, you could handle this by preg_replaceing the files.
So you could loop through your files and do the following
$newFilename = preg_replace('/_([0-9])_/', '_0$1_', $oldFilename);
rename($oldFilename, $newFilename);
You can try something like:
function webcam_image () {
foreach (glob( "../camera/IPC_IPCamera*.jpg") as $f ) {
$digits = explode('_', substr(substr($f, 13), 0, -4));
foreach($digits as &$digit){
$digit = sprintf("%02d", $digit);
}
unset($digit);
$list[] = 'IPC_IPCamera_' . implode('_', $digits) . '.jpg';
}
sort($list);
echo array_pop($list);
}
You can use sprintf()
$list[] = $f;
with the following
$list[] = sprintf("%02s", $f);

Getting a Simple PHP function to run [duplicate]

I posted a similar question earlier today, however I recently downloaded xampp and can now get syntax errors. I'm very new to all of this.
Please see this example to see the current state of my .php file: http://rich2233.comoj.com/file2.php
I can get the .txt file to extract and display the content from the .txt file, but any attempt of modifying the .txt file does not happen.
When I ran this on xampp, I got this error: Invalid argument supplied for foreach() in file2.php on line 30
After your most recent update of the code: The answer to the error message in the question title is:
The code is missing the line $users = file("test.txt");
Here's a quick tip: keep track of your iterator. Confusing? Think of each row number as unique offset in the file. You need to iterate (foreach) and increment it by +1 each time. When you're editing a row later on, you just need to submit the offset number, iterate again and check if $i == $_POST['iterator'].
// Iterator example
$users = file('text.txt');
$hours_taken = array();
foreach ($users as $user) {
list($time, $name) = explode('|', $user);
array_push($hours_taken, $time);
}
// Assuming same order of rows in users.txt
$hours = array('8:00 am', '9:00 am', '10:00 am'); // ...5:00 pm
$i = 1;
echo '<select name="time"><option selected>-- Select time --</option>';
foreach ($hours as $hour) {
if (in_array($hour, $hours_taken)) {
echo '<option disabled=disabled>'. $hour .'</option>';
}
else {
echo '<option value='. $i .'>'. $hour .'</option>';
}
$i++;
}
Edited as that last function wouldn't have worked
function editTxt(){
$find_name = $_POST['name'];
$find_time = $_POST['time'];
$filename = getcwd() . "/test.txt";
$lines = file( $filename , FILE_IGNORE_NEW_LINES );
foreach($lines as $key => $line)
{
list($time, $name) = explode('|', $line);
if($time == $find_time && $name == "Available")
{
$lines[$key] = $time."|".$find_name;
file_put_contents( $filename , $lines );
break;
}
}
}
If you are planning to use this for something other than just an exercise I suggest using a database.
Try:
$users = file($filename);
I suspect $users === false as you aren't using the same "calculated" file name.

Categories