Incrementing number inside bloc string using fwrite - php

im creating file retrieving data from mysql database.
$fo = fopen($newName, 'w')or die("can't open file")
After querying db, lets start writing.
<?php fwrite($fo, $row['entetequestionmonochoix']. PHP_EOL);?>
Correspondance to 'entetequestionmultichoix' is the following:
\begin{question}{01}\scoring{b=1,e=0,m=0,V=0}
im facing a small obstacle when generating file.
The while loop allow me to read and then insert but inside the correspondance i need to increment {01} after each loop.
\begin{question} **{01}**\scoring{b=1,e=0,m=0,V=0}

Use str_replace() to replace {01} with a string containing an incrementing variable.
$i = 1;
while ($row = $results->fetch_assoc()) {
$line = str_replace('{01}', sprintf('{%02d}', $i++), $row['entetequestionmonochoix']);
fwrite($fo, $line . PHP_EOL);
}

Related

PHP How to handle/parse csv files that have missing columns

I have many csv files generated by a third party, for which I have no say or control.
So each day I must import these csv data to mysql.
Some tables have correct matching number of columns to header.
Others do not.
Even when I did a prepared statement, it still did not import.
I tried to create a repair csv function, to add extra columns to each row, if their count of columns was less than the count of header columns.
As part of this project I am using the composer package league csv.
https://csv.thephpleague.com/
But here is my function code:
public function repaircsv(string $filepath) {
// make sure incoming file exists
if (!file_exists($filepath)) {
// return nothing
return;
}
// setup variables
$tempfile = pathinfo($filepath,PATHINFO_DIRNAME).'temp.csv';
$counter = 0;
$colcount = 0;
$myline = '';
// check if temp file exists if it does delete it
if (file_exists($tempfile)) {
// delete the temp file
unlink($tempfile);
}
// C:\Users\admin\vendor\league\csv
require('C:\Users\admin\vendor\league\csv\autoload.php');
// step one get header column count
$csv = Reader::createFromPath($filepath);
// set the header offset
$csv->setHeaderOffset(0);
//returns the CSV header record
$header = $csv->getHeader();
// get the header column count
$header_count = count($header);
// check if greater than zero and not null
if ($header_count < 1 || empty($header_count)) {
// return nothing
return $header_count;
}
// loop thru csv file
// now read file line by line skipping line 1
$file = fopen($filepath, 'r');
$temp = fopen($tempfile, 'w');
// loop thru each line
while (($line = fgetcsv($file)) !== FALSE) {
// if first row just straight append
if ($counter = 0) {
// append line to temp file
fputcsv($temp, $line);
}
// if all other rows compare column count to header column count
if ($counter > 0) {
// get column count for normal rows
$colcount = count($line);
// compare to header column count
$coldif = $header_count - $colcount;
// loop til difference is zero
while ($colcount != $header_count) {
// add to line extra comma
$line .= ',';
// get new column count
$colcount = count($line);
}
// append to temp file
fputcsv($temp, $line);
// show each line
$myline .= 'Line: ['.$line.']<br/><br/>';
}
// increment counter
$counter++;
}
// check file size of temp file
$fs = filesize($tempfile);
// if below 200 ignore and do not copy
if ($fs > 200) {
// copy temp to original filename
copy($tempfile,$filepath);
}
return $myline;
}
The logic is to copy the original csv file to a new temp csv file and add extra commas to rows of data that have missing columns.
Thank you for any help.
Edit: So the various csv's contain private data, so I can not share them.
But let us for example say i download multiple csvs for different data daily.
Each csv has a header row, and data.
If the number of columns in each row isn't 100% the same number of columns as in the header, it errors out.
If there are any special characters, it errors out.
There are 1000's of rows of data.
The code above is my first attempt to try to fix rows that have missing columns.
Here is an example
FirstName, LastName, Email
Steve,Jobs
,Johnson,sj#johns.com
Just a very small example.
I have no control of how the csvs are created, I do control the download process and import process.
Which then i use the csv data to update mysql tables.
I have tried the load data infile but that errors out too.
So I need to fix the csv files after they are downloaded.
Any ideas?
Do not mix array and string, instead of
$line .= ',';
do
$Line[]= '';
Also fix:
$myline .= 'Line: ['.implode(',', $line).']<br/><br/>';
Suggestion, you can replace your while loop with:
$line = array_pad($line, $header_count, ''); // append missing items
$line = array_slice($line, 0, $header_count); // remove eventual excess items

PHP read from file line by line, declare as variable, then use in MySQL query as WHERE column_name equals variable

Good day,
My aim with the script (overview) is to let PHP read from text file line by line then declare the line as variable that will be used in a MySQL statement as a where clause into an array, then ultimately writing to another text file.
CODE:
$lines = file('/root/prcode');
foreach($lines as $line) {
$query = "select * from $db_table where code=$line";
$result = mysqli_query($conn,$query);
while($row = mysqli_fetch_array($result, MYSQLI_NUM)) {
$out = "$row[0],$row[1],$row[2],$row[3],$row[4],$row[5],$row[6],$row[7],
$row[8],$row[9],$row[10],$row[11],$row[12],\n";
//file_put_contents($outfile, $out);
//$fp = fopen($outfile, 'w');
//fwrite($fp, $out);
//fclose($fp);
echo $out;
//echo $line;
//echo $query;
//echo $result;
//echo $row;
};
}
File prcode's first 10 lines:
60025909170
*
.05005140160
0000000000000000
0000000000000001
0000000000000004
0000000000000005
0000000000000007
0000000000000010
0000000000000011
OUTPUT when script is run from Linux shell:
0010,0000,60025909170,01,,,,,,,,,,
0010,0000,60025909170,02,,,,,,,,,,
0010,0000,60025909170,03,,,,,,,,,,
0010,0000,60025909170,04,,,,,,,,,,
0010,0000,60025909170,05,,,,,,,,,,
0010,0000,60025909170,06,,,,,,,,,,
0010,0000,60025909170,07,4.000,36.960,-4.000,-36.960,,,,,,
0010,0000,60025909170,08,4.000,36.960,,,,,,,,
0010,0000,60025909170,09,4.000,36.960,,,,,,,,
0010,0000,60025909170,10,4.000,36.960,,,,,,,,
0010,0000,60025909170,11,4.000,36.960,,,,,,,,
0010,0000,0000060025909170,01,,,,,,,,,,
0010,0000,0000060025909170,02,,,,,,,,,,
0010,0000,0000060025909170,03,,,,,,,,,,
0010,0000,0000060025909170,04,,,,,,,,,,
0010,0000,0000060025909170,05,,,,,,,,,,
0010,0000,0000060025909170,06,,,,,,,,,,
0010,0000,0000060025909170,07,,,,,,,,,,
0010,0000,0000060025909170,08,,,,,,,,,,
0010,0000,0000060025909170,09,,,,,,,,,,
0010,0000,0000060025909170,10,-4.000,-.040,4.000,.040,,,,,,
0010,0000,0000060025909170,11,-4.000,-.040,,,,,,,,
0010,0000,60025909170,12,4.000,36.960,,,,,,,,
0010,0000,0000060025909170,12,-4.000,-.040,,,,,,,,
From the output, it can be established that the order of the text file is not being followed as 60025909170 and 0000060025909170 are 2 different products and 0000060025909170 is at about line 32000 <- my first problem. To try to rectify this and cater for following the order, the special characters and spaces I tried:
$query = "select * from $db_table where code='$line'"; \\causes empty output
$query = "select * from $db_table where code=\"$line\""; \\causes empty output
$query = "select * from $db_table where code=\'$line\'"; \\empty output
The echos below were just to test to see which variables are set or not to try to further troubleshoot:
echo $out;
//echo $line;
//echo $query;
//echo $result;
//echo $row;
The second problem is, none of the attempts to write to file worked, it would either write just a single line and nothing more or would not write at all.
Any advise or guidance on how to possibly fix my 2 issues?
1st issue: Likely, your file is being read in order, but your query is finding all of those rows. You can see if this is happening by adding the line number to your output. Try changing your foreach to foreach($lines as $lineNum => $line) { and your output to $out = $lineNum.implode(',', $row)."\n"; If you have the same lineNum for 60025909170 and 0000060025909170, then you know that the query is matching both.
2nd issue: You just need to add a flag of FILE_APPEND to the file_put_contents. Like this: file_put_contents($outfile, $out, FILE_APPEND);

Compare and display using Php

I am working on a code where i am having a file.txt which is used like a database and i want to search the content on file.txt in any txt file or json file. But the problem is whenever it searches it skips the 1st line.
Below is my code.
<?php
$gameaudiof = fopen("gameaudio.txt", "a");
$lines1 = file("file.txt");
$data2 = $_FILES['data2']['tmp_name'] or exit("Please select the file");
$data3 = file_get_contents($data2);
foreach($lines1 as $line1){
$line1 = trim($line1);
if(strpos($data3, $line1)){
echo $line1;
echo "\n<br>";
fwrite($gameaudiof, $line1);
fwrite($gameaudiof,"".PHP_EOL);}}fclose($gameaudiof); ?>

Importing CSV to mysql table and add date to each row using PHP execution time

I did php code that do all the work of finding CSV files in a given directory and importing each csv file to the right table. The problem is I a csv file that contains 1M rows! Yes 1M rows :/ So it takes more than 15 mins to import it. This is the ISSUE. How can I improve the execution time?
$csv = new SplFileObject($file, 'r');
$csv->setFlags(SplFileObject::READ_CSV);
// get columns name
$tableColumns = $db->getColumns('daily_transaction');
print_r($tableColumns);
// get line fro csv file without the first one
foreach(new LimitIterator($csv, 1) as $line){
$i = 0;
$data = array();
foreach ($tableColumns as $Columns) {
// print($line[$i]."<br>");
$data[$Columns] = $line[$i];
$i++;
}
$data['file_name'] = $infoNAME;
$data['file_date'] = $file_date;
$insert_id = $db->arrayToInsert('daily_transaction', $data);
}
}

MySQL to MySQLi Query issue when joining arrays

I'm trying to convert some MYSQL querys to MYSQLI, but I'm having an issue, below is part of the script I am having issues with, the script turn a query into csv:
$columns = (($___mysqli_tmp = mysqli_num_fields($result)) ? $___mysqli_tmp : false);
// Build a header row using the mysql field names
$rowe = mysqli_fetch_assoc($result);
$acolumns = array_keys($rowe);
$csvstring = '"=""' . implode('""","=""', $acolumns) . '"""';
$header_row = $csvstring;
// Below was used for MySQL, Above was added for MySQLi
//$header_row = '';
//for ($i = 0; $i < $columns; $i++) {
// $column_title = $file["csv_contain"] . stripslashes(mysql_field_name($result, $i)) . $file["csv_contain"];
// $column_title .= ($i < $columns-1) ? $file["csv_separate"] : '';
// $header_row .= $column_title;
// }
$csv_file .= $header_row . $file["csv_end_row"]; // add header row to CSV file
// Build the data rows by walking through the results array one row at a time
$data_rows = '';
while ($row = mysqli_fetch_array($result)) {
for ($i = 0; $i < $columns; $i++) {
// clean up the data; strip slashes; replace double quotes with two single quotes
$data_rows .= $file["csv_contain"] .$file["csv_equ"] .$file["csv_contain"] .$file["csv_contain"] . preg_replace('/'.$file["csv_contain"].'/', $file["csv_contain"].$file["csv_contain"], stripslashes($row[$i])) . $file["csv_contain"] .$file["csv_contain"] .$file["csv_contain"];
$data_rows .= ($i < $columns-1) ? $file["csv_separate"] : '';
}
$data_rows .= $this->csv_end_row; // add data row to CSV file
}
$csv_file .= $data_rows; // add the data rows to CSV file
if ($this->debugFlag) {
echo "Step 4 (repeats for each attachment): CSV file built. \n\n";
}
// Return the completed file
return $csv_file;
The problem I am having is when building a header row for the column titles mysqli doesn't use field_names so I am fetching the column titles by using mysqli_fetch_assoc() and then implode() the array, adding the ,'s etc for the csv.
This works but when I produce the csv I am deleting the first data row when the header is active, when I remove my header part of the script and leave the header as null I get all data rows and a blank header (As expected).
So I must be missing something when joining my header to array to the $csv_file.
Can anyone point me in the right direction?
Many Thanks
Ben
A third alternative is to refactor the loop body as a function, then also call this function on the first row before entering the loop. You can use fputcsv as this function.
$csv_stream = fopen('php://temp', 'r+');
if ($row = $result->fetch_assoc()) {
fputcsv($csv_stream, array_keys($row));
fputcsv($csv_stream, $row);
while ($row = $result->fetch_row()) {
fputcsv($csv_stream, $row);
}
fseek($csv_stream, 0);
}
$csv_data = stream_get_contents($csv_stream);
if ($this->debugFlag) {
echo "Step 4 (repeats for each attachment): CSV file built. \n\n";
}
// Return the completed file
return $csv_data;
As this basically does the same thing as a do ... while loop, which would make more sense to use. I bring up this alternative to present the loop body refactoring technique, which can be used when a different kind of loop doesn't make sense.
Best of all would be to use both mysqli_result::fetch_fields and fputcsv
$csv_stream = fopen('php://temp', 'r+');
$fields = $result->fetch_fields();
foreach ($fields as &$field) {
$field = $field->name;
}
fputcsv($csv_stream, $fields);
while ($row = $result->fetch_row()) {
fputcsv($csv_stream, $row);
}
fseek($csv_stream, 0);
$csv_data = stream_get_contents($csv_stream);
if ($this->debugFlag) {
echo "Step 4 (repeats for each attachment): CSV file built. \n\n";
}
// Return the completed file
return $csv_data;
If you can require that PHP be at least version 5.3, you can replace the foreach that generates the header line with a call to array_map. There admittedly isn't much advantage to this, I just find the functional approach more interesting.
fputcsv($csv_stream,
array_map(function($field) {return $field->name},
$result->fetch_fields()));
As you observe, you're using the first row to obtain the field names but then not using the data from the row. Evidently, you need to change your code so that you get both of those things.
There are a number of ways you might do this. The most appropriate one is to use mysqli_fetch_fields() instead to get the field metadata from the result object.
http://www.php.net/manual/en/mysqli-result.fetch-fields.php
Alternatively, you could make the loop lower down in the code a do... while instead of a while.

Categories