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