Escaping line break in csv php - php

I have a .csv template I'd wish for people to fill up, save it and upload it.
The problem is this, assuming some users would insert hidden line breaks in a row, when using fgetcsv() it would output the row broken by the hidden line breaks.
How can I escape the line break or sanitize my data?
Possible solution:
assume first row is correct, $count = count the number of delimiters until line break, the rebuild the text into an array as long as $count;
but i think the're better options available.
LATER EDIT
Here's the input *IMPORTANT[ ! ] : the data inside the excel file is "fine", it isn't broken, it's a single row!!! saving it as a csv file and opening it in notepad shows the following
asd;"asd
asd
asd";asd;asd
Here's the code
$handle = fopen("file.csv","r");
$data = fgetcsv($handle,";");
while($data = fgetcsv($handle)) {
$array = explode(";",$data[0]);
print_r($array);
}
fclose($handle);
Here's the echoed data
Array ( [0] => asd [1] => "asd ) Array ( [0] => asd ) Array ( [0] => asd" [1] => asd [2] => asd [3] => )
Thanks

it is very easy to test your case and see that there are no broken rows, if fields being properly quoted.
So, a CSV line like this
1,"joe
""Big Coyote""
Hopkins",598600
will be read with not a single problem.

Related

PHP - Converting String to Array that is already formated as an array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
For clarification purposes I am using 2 separate files. So I am trying to check if a value exist within my array that is generated in my 2nd file. The first file stores the input below...
//mytxtfile.txt previous content stored in a text file using file_put_content and print_r...
Array
(
[0] => Bill
[1] => Bob
[2] => Joe
[3] => Frank
[4] => Mark
)
My 2nd file I try to call file_get_content but now realize that it stores my input as a string. Is there any way to convert this string back to an array in my new file? I have tried json_decode but it says it is null... Or if this is too much of a hassle I am also willing to change the format on how it is stored in the 1st file that generates the content.
<?php
$input = "Array
(
[0] => Bill
[1] => Bob
[2] => Joe
[3] => Frank
[4] => Mark
)";
$pattern = '/\[(?<keys>\w+)\]\s=>\s(?<values>\S+)/';
preg_match_all($pattern, $input, $matches);
$values = $matches['values'];
$keys = $matches['keys'];
$result = array_combine($keys, $values);
print_r($result);
?>
I'll explain the solution in details , but first let me post the code:
<?php //php 7.0.8
$input = "Array
(
[0] => Bill
[1] => Bob
[2] => Joe
[3] => Frank
[4] => Mark
)";
$lines = explode("\n", $input);
$values = array();
for ($i = 2; $i < count($lines) - 1; $i++) {
$value = explode("=>", $lines[$i])[1];
$value = trim($value);
array_push($values, $value);
}
print_r($values);
?>
So the file contains the formatted array as a text , we will split the content of the file into lines , this can be done using explode() function , now the $lines array contains the text rows of the file.
Now we will loop to extract the values , notice that the loop starts from $i = 2 , this because we're ignoring the first line (which contains Array) and the second line (which contains () , and the loop ends right before the last line , because we're ignoring the last line (which contains )).
We initialize an empty array $values to store the values of the array , to do this we again need to split each line using explode() function , but having in mind that the separator is => , this will return an array similar to ("[0]", " Bill") , since we want the string " Bill" we use the index 1.
Next (this step is optional) , we get rid of the whitespace before the value using the trim() function.
Finally , we push the resultant $value into the empty array.
When the loop ends you will get the extracted values.
For the sake of reference , here's the documentation of the used functions:
trim() http://php.net/manual/en/function.trim.php
explode() http://php.net/manual/en/function.explode.php
array_push() http://php.net/manual/en/function.array-push.php

PHP - is_file says file does not exists but it does

I'm trying to get 3 pdf files attached to an email, the problem I have is that is_file gives a false on the first two files but the third file it works. The files come from a textbox and are exploded like this:
$pdfs = explode("\n", $string);
And I put it in a foreach loop to attach to an email like this:
foreach($pdfs as $pdf) {
if (is_file(JPATH_ROOT . $pdf)) {
$mail['attachment'][] =
array('name' => basename($pdf), 'file' => JPATH_ROOT . $pdf);
}
}
When I run this code I only get the third pdf file attached, however if I remove the is_file() they are in the array but won't attach to the sent email.
So the results then are:
[attachment] => Array
(
[0] => Array
(
[name] => pdf_file_1.pdf
[file] => /home/psinke/domains/*****/public_html/pdf_file_1.pdf
)
[1] => Array
(
[name] => pdf_file_2.pdf
[file] => /home/psinke/domains/*****/public_html/pdf_file_2.pdf
)
[2] => Array
(
[name] => pdf_file_3.pdf
[file] => /home/psinke/domains/*****/public_html/pdf_file_3.pdf
)
)
But the first two files do not attach to the sent email.
Likely the line break that separates those entries in your input data is not just \n ... so you might have left a \r at the end of the first two, which of course makes PHP not find those files.
The third file won’t have this problem, because likely after that line there is no more line break.
The files come from a textbox
Assuming you mean an HTML textarea element - all modern browsers send \r\n for a line break in a textarea - so if you only get your content from there, exploding at "\r\n" should work. If you are not sure about the exact line break format used beforehand, you can also use a preg_split solution as shown here, https://stackoverflow.com/a/36851287/1427878

str_getcsv doesn't enclose first column in double quotation marks in multi-line CSV

I noticed that str_getcsv doesn't seem to enclose the first value it receives in double quotation marks, even when the string data is passed this way.
In the example below, the first value in the 3rd row is "Small Box, But Smaller", but after running it through str_getcsv it becomes Small Box, But Smaller (without double quotation marks). Like this:
// multi-line csv string
$csvString = <<<'CSV'
"Title","Description",Quantity
"Small Box","For storing magic beans.",2
"Small Box, But Smaller","Not sure why we need this.",0
CSV;
// split string into rows (don't use explode in case multi-line values exist)
$csvRows = str_getcsv($csvString, "\n"); // parse rows
echo '<pre>';
print_r($csvRows);
echo '</pre>';
Outputs:
Array
(
[0] => Title,"Description",Quantity
[1] => Small Box,"For storing magic beans.",2
[2] => Small Box, But Smaller,"Not sure why we need this.",0
)
The problem this causes is that now if each row is parsed using str_getcsv, a comma in the first value makes it split into two rows. If it keeps running this:
foreach($csvRows as &$csvRow) {
$csvRow = str_getcsv($csvRow); // parse each row into values and save over original array value
}
unset($csvRow); // clean up
// output
echo '<pre>';
print_r($csvRows);
echo '</pre>';
Outputs:
Array
(
[0] => Array
(
[0] => Title
[1] => Description
[2] => Quantity
)
[1] => Array
(
[0] => Small Box
[1] => For storing magic beans.
[2] => 2
)
[2] => Array
(
[0] => Small Box
[1] => But Smaller
[2] => Not sure why we need this.
[3] => 0
)
)
The problem is in the last array value, which is an array of 4 keys instead of 3. It's split on the comma of the value "Small Box, But Smaller".
On the other hand, parsing just one row string works:
$csvRowData = '"Small Box, But Smaller","Not sure why we need this.",0';
$csvValues = str_getcsv($csvRowData);
echo '<pre>';
print_r($csvValues);
echo '</pre>';
Outputs:
Array
(
[0] => Small Box, But Smaller
[1] => Not sure why we need this.
[2] => 0
)
Why is this happening and how do I solve the problem with multi-line CSV data? Is there a best practice for working with multi-line CSV data when it is a string and is not read directly from a file? Also, I need to handle multi-line values, such as "foo \n bar" so I can't just use explode() instead of the first str_getcsv().
After much headache I think I understand the problem now. According to the PHP folks, "str_getcsv() is designed to parse a single CSV record into fields" (see https://bugs.php.net/bug.php?id=55763). I discovered that using str_getcsv() for multiple rows causes these not-so-well documented problems:
Double quotation marks are not maintained (as I demontrate above).
Line breaks in values cause it to think a new row has begun. This can have many unintended consequences.
I solved the issue by creating a temporary file and writing the CSV content to it. Then I read the file using fgetcsv(), which did not result in the 2 issues I described above. Example code:
// multi-line csv string
$csvString = <<<'CSV'
"Title","Description",Quantity
"Small Box","For storing magic beans.",2
"Small Box, But Smaller","This value
contains
multiple
lines.",0
CSV;
// ^ notice the multiple lines in the last row's value
// create a temporary file
$tempFile = tmpfile();
// write the CSV to the file
fwrite($tempFile, $csvString);
// go to first character
fseek($tempFile, 0);
// track CSV rows
$csvRows = array();
// read the CSV temp file line by line
while (($csvColumns = fgetcsv($tempFile)) !== false) {
$csvRows[] = $csvColumns; // push columns to array (really it would be more memory-efficient to process the data here and not append to an array)
}
// Close and delete the temp file
fclose($tempFile);
// output
echo '<pre>';
print_r($csvRows);
echo '</pre>';
Results in:
Array
(
[0] => Array
(
[0] => Title
[1] => Description
[2] => Quantity
)
[1] => Array
(
[0] => Small Box
[1] => For storing magic beans.
[2] => 2
)
[2] => Array
(
[0] => Small Box, But Smaller
[1] => This value
contains
multiple
lines.
[2] => 0
)
)
I'll also add that I found some options on GitHub, and 2 major projects for PHP 5.4+ and PHP 5.5+. However, I am still using PHP 5.3 and only saw options with limited activity. Furthermore, some of those processed CSV strings by writing to files and reading them out also.
I should also note that the documentation for PHP has some comments about str_getcsv() not being RFC-compliant: http://php.net/manual/en/function.str-getcsv.php. The same seems to be true for fgetcsv() yet the latter did meet my needs, at least in this case.
I don't know why you PHP_EOL is not working correctly as it does on my server however I did encounter this problem before.
The approach I took goes as follows.
Firstly I like to make sure all my fields are surrounded by double quotes regardless of the value in the field so to use your example text (with some slight modifications):
// multi-line csv string
$csvString = <<<CSV
"Title","Description","Quantity"
"Small Box","For storing magic beans.","2"
"Small Box, But Smaller","Not sure why we need this.","0"
"a","\n","b","c"
CSV;
$csvString .= '"a","' . "\n" . '","' . PHP_EOL . '","c"';
Secondly I target solo PHP_EOL that may be lingering in values so I can replace any "PHP_EOL" strings with "\r\n"
// Clear any solo end of line characters that are within values
$csvString = str_replace('","' . PHP_EOL . '"', '",""',$csvString);
$csvString = str_replace('"' . PHP_EOL . '","', '"","',$csvString);
$csvString = str_replace('"' . PHP_EOL . '"', '"'. "\r\n" . '"',$csvString);
and then finally this allows me to use the php explode function and display output:
$csvArr = explode("\r\n",$csvString);
foreach($csvArr as &$csvRow) {
$csvRow = str_getcsv($csvRow); // parse each row into values and save over original array value
}
unset($csvRow); // clean up
// output
echo '<pre>';
print_r($csvArr);
echo '</pre>';
Which outputs:
Array
(
[0] => Array
(
[0] => Title
[1] => Description
[2] => Quantity
)
[1] => Array
(
[0] => Small Box
[1] => For storing magic beans.
[2] => 2
)
[2] => Array
(
[0] => Small Box, But Smaller
[1] => Not sure why we need this.
[2] => 0
)
[3] => Array
(
[0] => a
[1] =>
[2] => b
[3] => c
)
[4] => Array
(
[0] => a
[1] =>
[2] =>
[3] => c
)
)
As you can see from the output the new line characters are not targeted, just the PHP_EOL.

Export an array to CSV failure: string given

I can't solve a problem occurring when I try to export an array to a CSV file. I have used this function several times without problem but here I do not see where my mistake is.
I set an array:
$mytags= array();
I populate it by a loop. When I print the content through print_r($mytags);
it seems to be OK, here some examples of my output:
Array ( [0] => [1] => air-travel [2] => airports [3] => security-airport [4] => city-airport ... )
After that I try to export the result to CSV by fputcsv:
$fp = fopen('file.csv', 'w');
foreach ($mytags as $fields) {
fputcsv($fp, $fields);
}
But I get this error:
Warning: fputcsv() expects parameter 2 to be array, string given in
C:\wamp\www\tests\capturetags.php on line 55
Could the problem be that there is only one field?
Alternatively, I tried to replace $fields by $mytags to write the CSV, and in this case I get a 4GB files, so it's not the
Does someone see how to record thhis unique field in a CSV file?
The error is very clear, $fields is not an array, it is a string. You need an array.
fputcsv($fp, $mytags);
Without a foreach loop will do the job.

Save items from array on mysql with php

Hi i have one situation and i dont know what exactly i need to do.
This is a multiple file upload so im doing this
$files = $_POST["files-temp"];
this return ( iten1.jpg;iten2.jpg;iten3.jpg;) there is a semicolon on last iten
then i did
$array = preg_split('/;/',$files);
then i got
Array ( [0] => iten1.jpg [1] => iten2.jpg [2] => iten3.jpg [3] => )
So there is a iten 4 that not exists, so i need to find a better way to do this then count and execut the query to save on mysql.
thanks for any help.
If $files contains a string and want to remove that last extra array location:
Try:
$files = 'iten1.jpg;iten2.jpg;iten3.jpg;';
$result = explode(";", rtrim($files,';'));
print_r( $result );
Test Here

Categories