escape semicolon character when writing to csv file - php

I want to write something like
=HYPERLINK("http://example.com"; "Example")
to a comma-separated CSV file, but Excel parses the semicolon and puts "Example") part in another cell. I tried escaping the semicolon with backslash and wrapping everything in double quotes without any luck.
Any help?

The wrapping with double quotes was already the correct idea, but you have to make sure you do it correctly. You can put a column within double quotes, then everything inside is considered as a single value. Quotes itself have to be escaped by writing two of them ("").
See for example this:
Column A;Column B;Column C
Column A;"Column B; with semicolon";Column C
Column A;"Column B"";"" with semicolon and quotes";Column C
Column A;"=HYPERLINK(""http://example.com""; ""Example"")";Column C

I also had a very wild time tring to figure the whole picture out, then is how I've got all my csv ready to open into excel in php ( which includes utf8 encoding as well ) :
$sep='";"';//note the separator is double quoted
while($t=mysql_fetch_assoc(mysql_query('select ..')){
#replaces the caracters who are breaking csv display
$t=array_map(function($x){return str_replace(array("\n","\r",'"'),array('\\n',"\\r",'""'),$x);},$t);
$csv.="\n\"".implode($sep,$t)."\"";
}
$charset='utf-8';
header('Content-Type: application/csv;charset='.$charset);
header('Content-Disposition: attachment; filename="filename.csv"');
$bom=chr(239).chr(187).chr(191);#this tells excel document is utf8 encoded
die($bom.$csv);

I use this function for each CSV value to pass it correctly. It quotes a value only if it contain new line symbols, double quotes or separator. Actually, the only value to escape is double quotes symbol. All other cell content gets into it and displayed correctly in Excel.
Checked with various versions of Excel and ODBC CSV parsers in Cyrillic locale under Windows.
/**
* This function escapes single CSV value if it contains new line symbols, quotes or separator symbol and encodes it into specified $encoding.
*
* #param string $source - origin string
* #param string $sep - CSV separator
* #param string $source_encoding - origin string encoding
* #param string $encoding - destination encoding
*
* #return string - escaped string, ready to be added to CSV
*
* #example echo escapeStringCSV("Hello\r\n\"World\"!");
* will output
* "Hello
* ""World""!"
*/
function escapeStringCSV($source, $sep=';', $source_encoding='utf-8', $encoding="windows-1251//TRANSLIT"){
$str = ($source_encoding!=$encoding ? iconv($source_encoding, $encoding, $source) : $source);
if(preg_match('/[\r\n"'.preg_quote($sep, '/').']/', $str)){
return '"'.str_replace('"', '""', $str).'"';
} else
return $str;
}
So usage can be like this:
while($row = mysql_fetch_assoc($res)){
foreach($row as $val){
$csv .= escapeStringCSV($val).';';
}
$csv .= "\r\n";
}

Yes, agreed with the solution
I applied below and it fixed the issue
Representing= tdOPP[2].text.replace(';', '"";""')
odata_row = [b_yr, b_no, full_nameOPP, f_nameOPP, l_nameOPP, tdOPP[1].text.strip(),Representing, witness_positionOPP]

Related

PHP convert double quoted string to single quoted string

I know this question asked here many times.But That solutions are not useful for me. I am facing this problem very badly today.
// Case 1
$str = 'Test \300'; // Single Quoted String
echo json_encode(utf8_encode($str)) // output: Test \\300
// Case 2
$str = "Test \300"; // Double Quoted String
echo json_encode(utf8_encode($str)) // output: Test \u00c0
I want case 2's output and I have single quoted $str variable. This variable is filled from XML string parsing . And that XML string is saved in txt file.
(Here \300 is encoding of À (latin Charactor) character and I can't control it.)
Please Don't give me solution for above static string
Thanks in advance
This'll do:
$string = '\300';
$string = preg_replace_callback('/\\\\\d{1,3}/', function (array $match) {
return pack('C', octdec($match[0]));
}, $string);
It matches any sequence of a backslash followed by up to three numbers and converts that number from an octal number to a binary string. Which has the same result as what "\300" does.
Note that this will not work exactly the same for escaped escapes; i.e. "\\300" will result in a literal \300 while the above code will convert it.
If you want all the possible rules of double quoted strings followed without reimplementing them by hand, your best bet is to simply eval("return \"$string\""), but that has a number of caveats too.
May You are looking for this
$str = 'Test \300'; // Single Quoted String
echo json_encode(stripslashes($str)); // output: Test \\300

Character encoding issue when importing CSV from Excel?

I have a PHP script which exports a CSV file. My users then edit the file in Excel, save it, and re-upload it.
If they type a euro symbol into a field, when the file is uploaded, the euro symbol, and everything afterwards is missing. I'm using the str_getcsv function.
If I try to convert the encoding (say to UTF-8), the euro symbol disappears, and I get a missing character marker (usually represented by a blank square or a question mark in a diamond).
How to I convert the encoding to UTF-8, but also keep the euro symbol (and other non-standard characters)?
Edit:
Here is my code:
/**
* Decodes html entity encoded characters back to their original
*
* #access public
* #param String The element of the array to process
* #param Mixed The key of the current element of the array
* #return void
*/
public function decodeArray(&$indexValue, $key)
{
$indexValue = html_entity_decode($indexValue, ENT_NOQUOTES, 'Windows-1252');
}
/**
* Parses the contents of a CSV file into a two dimensional array
*
* #access public
* #param String The contents of the uploaded CSV file
* #return Array Two dimensional-array.
*/
public function parseCsv($contents)
{
$changes = array();
$lines = split("[\n|\r]", $contents);
foreach ($lines as $line) {
$line = utf8_encode($line);
$line = htmlentities($line, ENT_NOQUOTES);
$lineValues = str_getcsv($line);
array_walk($lineValues, 'decodeArray');
$changes[] = $lineValues;
}
return $changes;
I have also tried the following instead of the utf8_encode function:
iconv("Windows-1252", "UTF-8//TRANSLIT", $line);
And also just:
$line = htmlentities($line, ENT_NOQUOTES, 'Windows-1252');
With the utf8_encode function, the offending character is removed from the string. With any other method, the character and everything after the character is missing.
Example:
The field value : "Promo € Mobile"
is interpreted as : "Promo Mobile"
Add these to the beginning of your CSV file
chr(239) . chr(187) . chr(191)

How to prevent character conversion to integer in data export in PHP

I have a link on a page that, when clicked, exports an array of data to csv using fputcsv. When Excel displays the data, there is a column that looks like an integer, but it's not, and Excel is converting it to scientific notation. How do I export the data so that this column is displayed as characters (not a scientific number) ?
The code I'm using for export is from Alain Tiemblo's answer here:
Link to Code
function array2csv(array &$array)
{
if (count($array) == 0) {
return null;
}
ob_start();
$df = fopen("php://output", 'w');
fputcsv($df, array_keys(reset($array)));
foreach ($array as $row) {
fputcsv($df, $row);
}
fclose($df);
return ob_get_clean();
}
Not sure about Excel, but LibreOffice and OpenOffice will import fields as strings if the CSV field is quoted. For example, you want your CSV to be something like:
foo,bar,"12345",baz
(You may also have to check "Quoted field as text" option in the file open dialog.)
Edit: PHP's fputcsv() function will only use quote wrappers if it needs to, so you'll likely have to manually force quotes around the actual field value yourself:
$field = 12345;
$quoted_field = '"' . $field . '"';
Edit 2: If you don't need to worry about escaping, this might work for you instead of fputcsv():
fwrite($fp, '"' . implode($fields, '","') . '"' . "\n");
Try to force your int into a string before your fputcsv.
For example
$foo = "$foo";
http://php.net/manual/en/language.types.type-juggling.php
But then again Excel might make up its own mind when converting your CSV to an Excel format...
Also this question might help: Excel CSV - Number cell format
You could cast the value to string using strval.
converting integer to string using :-
string, strval or enclosing value in double/single quotes , or even concat space with the variable does not work because CSV doesn't hold field type information.
The only way I found is to add some character or symbol to forcefully make it string but that will show in output too.

What is the best way to convert special characters to the corresponding HTML Codes with PHP?

I want to convert everything like spaces, single/double quotes, line break, etc.
Here is a sample input (Thanks som_nangia) :
Escape Check < "escape these" > <“and these”> <html><tr><td></td></tr></html> 'these will need escaping too' ‘ so will these’ <script> </script>
Here are the options I am considering:
<pre>Escape Check < "escape these" > <“and these”> <html><tr><td></td></tr></html> 'these will need escaping too' ‘ so will these’ <script> </script></pre>
/**
* Encoding html special characters, including nl2br
* #param string $original
* #return string
*/
function encode_html_sp_chars($original) {
$table = get_html_translation_table(HTML_ENTITIES);
$table[' '] = ' ';
$encoded = strtr($original, $table);
return nl2br($encoded);
}
I have tried both htmlspecialchars and htmlentities, but none of them encodes spaces.
Use htmlspecialchars.
echo htmlspecialchars($string);
In your case, please pass two parameters this way:
echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
Thanks to zerkms and Phil.
Explanation
Certain characters have special significance in HTML, and should be represented by HTML entities if they are to preserve their meanings. This function returns a string with these conversions made. If you require all input substrings that have associated named entities to be translated, use htmlentities() instead.
If the input string passed to this function and the final document share the same character set, this function is sufficient to prepare input for inclusion in most contexts of an HTML document. If, however, the input can represent characters that are not coded in the final document character set and you wish to retain those characters (as numeric or named entities), both this function and htmlentities() (which only encodes substrings that have named entity equivalents) may be insufficient. You may have to use mb_encode_numericentity() instead.
This best way is probably
Example:
function encode_html_sp_chars($original) {
$encoded = htmlentities($original, ENT_QUOTES, "UTF-8");
$encoded = str_replace(' ', ' ', $encoded);
return nl2br($encoded);
}

Forcing fputcsv to Use Enclosure For *all* Fields

When I use fputcsv to write out a line to an open file handle, PHP will add an enclosing character to any column that it believes needs it, but will leave other columns without the enclosures.
For example, you might end up with a line like this
11,"Bob ",Jenkins,"200 main st. USA ",etc
Short of appending a bogus space to the end of every field, is there any way to force fputcsv to always enclose columns with the enclosure (defaults to a ") character?
No, fputcsv() only encloses the field under the following conditions
/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (FPUTCSV_FLD_CHK(delimiter) ||
FPUTCSV_FLD_CHK(enclosure) ||
FPUTCSV_FLD_CHK(escape_char) ||
FPUTCSV_FLD_CHK('\n') ||
FPUTCSV_FLD_CHK('\r') ||
FPUTCSV_FLD_CHK('\t') ||
FPUTCSV_FLD_CHK(' ')
)
There is no "always enclose" option.
Not happy with this solution but it is what I did and worked. The idea is to set an empty char as enclosure character on fputcsv and add some quotes on every element of your array.
function encodeFunc($value) {
return "\"$value\"";
}
fputcsv($handler, array_map(encodeFunc, $array), ',', chr(0));
Building on Martin's answer, if you want to avoid inserting any characters that don't stem from the source array (Chr(127), Chr(0), etc), you can replace the fputcsv() line with the following instead:
fputs($fp, implode(",", array_map("encodeFunc", $row))."\r\n");
Granted, fputs() is slower than fputcsv(), but it's a cleaner output. The complete code is thus:
/***
* #param $value array
* #return string array values enclosed in quotes every time.
*/
function encodeFunc($value) {
///remove any ESCAPED double quotes within string.
$value = str_replace('\\"','"',$value);
//then force escape these same double quotes And Any UNESCAPED Ones.
$value = str_replace('"','\"',$value);
//force wrap value in quotes and return
return '"'.$value.'"';
}
$fp = fopen("filename.csv", 'w');
foreach($table as $row){
fputs($fp, implode(",", array_map("encodeFunc", $row))."\r\n");
}
fclose($fp);
After a lot of scrafffing around and some somewhat tedious character checking, I have a version of the above referenced codes by Diego and Mahn that will correctly strip out encasings and replace with double quotes on all fields in fputcsv. and then output the file to the browser to download.
I also had a secondary issue of not being able to be sure that double quotes were always / never escaped.
Specifically for when outputting directly to browser using the php://input stream as referenced by Diego. Chr(127) is a space character so the CSV file has a few more spaces than otherwise but I believe this sidesteps the issue of chr(0) NULL characters in UTF-8.
/***
* #param $value array
* #return string array values enclosed in quotes every time.
*/
function encodeFunc($value) {
///remove any ESCAPED double quotes within string.
$value = str_replace('\\"','"',$value);
//then force escape these same double quotes And Any UNESCAPED Ones.
$value = str_replace('"','\"',$value);
//force wrap value in quotes and return
return '"'.$value.'"';
}
$result = $array_Set_Of_DataBase_Results;
$fp = fopen('php://output', 'w');
if ($fp && $result) {
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export-'.date("d-m-Y").'.csv"');
foreach($result as $row) {
fputcsv($fp, array_map("encodeFunc", $row), ',', chr(127));
}
unset($result,$row);
die;
}
I hope this is useful for some one.
A "quick and dirty" solution is to add ' ' at the end of all of your fields, if it's acceptable for you:
function addspace($v) {
return $v.' ';
}
fputcsv($handle, array_map('addspace', $fields));
PS: why it's working? see Volkerk answer ;)

Categories