I am trying to create a .csv file from a php script (that get the data from a database). My problem is that special characters are not displayed correctly.
$content[] = All field content at here.
echo "<pre>";
print_r($content);
$title = array("Category", "ProductName", "ProductSKU", "Price", "ProductURL", "ManufacturerSKU", "ManufacturerName","EAN","Description"
,"imageURL","StockStatus","DeliveryTime","Shippingcost");
$output = fopen('csv.csv', 'w+');
fputcsv($output, $title);
foreach ($content as $con) {
fputcsv($output, $con);
}
fclose($output);
echo "CSV created."
When i print $content, it is displaying properly special characters, But when i open csc.csv, It is not displaying properly.
Related
I have some json data that I need to email to my users as a .csv file.
The following code works as expected for Hällowörld, however, once I put a space in there, Hällo wörld, the .csv file reads ÔªøH√§llo w√∂rld when opened in Excel (for Mac).
$temp = fopen('php://temp/maxmemory:10485760', 'w');
$rows = json_decode('[["Hällowörld"]]'); // -> Hällowörld
//$rows = json_decode('[["Hällo wörld"]]'); // -> ÔªøH√§llo w√∂rld
foreach($rows as $row) {
$row = array_map(function($cell) {
return chr(239).chr(187).chr(191).$cell;
}, $row);
fputcsv($temp, $row, ';');
}
rewind($temp);
$csv = stream_get_contents($temp);
fclose($temp);
$csv = base64_encode($csv);
// -> post $csv to my email provider's API
A few notes:
My code is in UTF-8
If I open the file with Apple's numbers or textedit, the content is displayed as expected.
If I don't do the mapping with chr(239).chr(187).chr(191).$cell, I get Hällowörld.
If instead, I use mb_convert_encoding($cell, 'UTF-16LE', 'UTF-8') or mb_convert_encoding($cell, 'Windows-1252', 'UTF-8'), as is often suggested, I get H‰llowˆrld.
The final base64_encode() is necessary, because my email provider needs the attachment to be base_64-encoded.
I found the solution! :) Replace the above foreach loop with the following:
array_unshift($rows, [chr(239).chr(187).chr(191)]);
foreach($rows as $row) {
fputcsv($f, $row, ',');
}
I'm working on a PHP script that creates a .csv file from some data.
Unfortunately, in Excel Umlauts are not displayed properly: Löl becomes L√∂l (this is just in Excel, in Apple's Numbers, Atom and Textedit everything looks fine).
I have tried hundreds of functions to try and get the encoding right (see the commented functions below). Could someone please tell me what I'm doing wrong?
$rows = json_decode('[["Löl"]]');
foreach($rows as $key_row => $row) {
foreach($row as $key_cell => $cell) {
// $rows[$key_row][$key_cell] = utf8_decode($cell);
// $rows[$key_row][$key_cell] = iconv('UTF-8', 'Windows-1252', $cell);
// $rows[$key_row][$key_cell] = mb_convert_encoding($cell, 'UTF-16LE', 'UTF-8');
// iconv('UTF-8', 'Windows-1252', $rows[$key_row][$key_cell]);
// mb_convert_encoding($rows[$key_row][$key_cell], 'UTF-16LE', 'UTF-8');
}
}
$temp = fopen('php://memory', 'w');
foreach($rows as $row) {
fputcsv($temp, $row, ';');
}
fseek($temp, 0);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="test.csv";');
fpassthru($temp);
The following conversion to UTF-8 BOM worked:
foreach($rows as $key_row => $row) {
foreach($row as $key_cell => $cell) {
$rows[$key_row][$key_cell] = chr(239) . chr(187) . chr(191) . $cell;
}
}
Thanks for everybody who chimed in :)
I have this piece of PHP code that's intended to retrieve data from a mySQL database, and export it to a CSV file that has to be automatically downloaded after it was created.
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
// fetch mysql table rows
$sql = "select * from users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
$fp = fopen('users.csv', 'w');
while($row = mysqli_fetch_assoc($result)) {
fputcsv($fp, $row);
}
fclose($fp);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
mysqli_close($connection);
The problem here is that it:
Retrieves the data.
Retrieves the CSV file on the server in the same directory of the export.php file with the data on it.
Downloads the file with the same name BUT it's EMPTY
Thanks.
You're writing it to a file called users.csv, but the file you are forcing the user to download is the output of the page.
As long as your query is correct, once the PHP script has run, there should be a file called users.csv in the same directory as the PHP file that contains the correct data.
You need to output the data to the browser for it to be attributed to the file you're downloading.
Try this:
//Connect to database
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
//Fetch mysql table rows
$sql = "select * from users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
//Close connection
mysqli_close($connection);
//Set $output
$output = "";
//Set header values
$headers = array("Header 1", "Header 2", "Header 3");
//Insert header values to $output
foreach($headers as $h){
$output .= fieldCheck($h) . ",";
}
$output = rtrim($output, ","). "\n";
//Iterate through results
while($row = mysqli_fetch_assoc($result)) {
foreach($row as $cell){
//Comma-separate each value
$output .= fieldCheck($cell).",";
}
//Remove last comma of each line and add newline
$output = rtrim($output, ",") . "\n";
}
//Set headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
//Output
echo $output;
exit;
//Function in case of comma in field
function fieldCheck($string){
if(strpos($string, ",") !== false){
$string = '"'.$string.'"';
}
return $string;
}
I have seen this question come up quite a few times and here the user is sending the data to "users.csv" as shown below:
$fp = fopen('users.csv', 'w');
The issue is that unless the file "users.csv" is already created there is nothing to write the data to, so the CSV is blank. The "fopen" does not create the file it only opens an existing file and the "w" directive then instructs "fputcsv" to put it into the file "users.csv" which may not exist and if the file does exist it writes over the existing file.
Here is an explainer PHP script that will send the output (CSV) to a filename of your choice for downloading:
//Connect to database
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
//Get the data
//The order and number of elements must match the header below or the data
//will appear in the wrong columns.
$sql = "SELECT FirstName,LastName,Address,City,State,Zip FROM users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
//Close connection
mysqli_close($connection);
//Name of the file you want the user to download can be any name but
//use the .CSV file extension so it will be recognized
//as a CSV when downloaded.
$NameOfCSVFileToDownload = "MyCSVFile.csv";
//set headers tells the page what to do
header("Content-Type: application/csv; charset=utf-8");
header("Content-Disposition: attachment;filename=\"$NameOfCSVFileToDownload\"");
//Where to send the data -
//there are several option but sending it to output will insert
//the data into "$NameOfCSVFileToDownload" when complete, your output.
//Output is a way to access I/O streams
$output = fopen("php://output", 'w');
//Add the header or 1st row for your data
//-notice we are sending it to "$output" you can add any names you want
//for this header row but make sure that the number of columns in the header
//matches the number of columns you are retrieving from the database or they
//will not line up when you open up the CSV and things will look scrambled.
fputcsv($output, array('FirstName','LastName','Address','City','State','Zip'));
//Loop through the data and insert the data into "$output"
while($rows = $result->fetch_assoc()){
fputcsv($output, $rows);
}
//Close the "$output" file to complete the write.
fclose($output);
That's all, call the page and it will prompt to open or download the CSV that contains data. If it is still blank make sure your SQL statement is actually pulling data.
You can also review the PHP manual on streams to better understand.
PHP Manual
Combining a few ideas mentioned in the comments:
Output directly to stdout (rather than a users.csv file). This prevents concurrent processes from clashing with the same output file. No need to buffer temporary results in a variable, either.
Use fputcsv()'s 3rd argument to specify ';' as the field separator. No need to rewrite special code for that.
Use array_map() and a custom filter to add quotes around all the fields.
// Helper function to surround a string with double quotes
function pad_with_quotes($s) {
return '"' . $s . '"';
}
// Helper function to output a row to $fp:
function output_row($fp, $row) {
// Separate fields with ';':
fputcsv($fp, array_map('pad_with_quotes', $row), ';');
}
// Send HTTP headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
// Open a pointer to stdout:
$fp = fopen('php://output', 'w'); // TO DO: check for fopen() failure
// Output headers (padded with quotes):
output_row($fp, ['foo', 'bar']); // TO DO: change headers
// DB connection/query goes here; omitted for brevity
// Loop through DB results:
while($row = mysqli_fetch_assoc($result)) {
// Output a row of results:
output_row($fp, row);
}
I am having a few problems with this code, one is that the proxies are not being displayed on a new line for each one.
Two is that instead of the "" being displayed these weird chinese characters are being displayed 䈼㹒
<?php
$data = file_get_contents("http://proxylists.connectionincognito.com/proxies_657.txt");
//var_dump($data);
$lines = explode("/n", $data);
foreach($lines as $line)
{
echo $line;
echo "<BR>";
}
?>
Try to explode by "\n" instead of "/n".
The Chinese charakters are there because the file is encoded in UTF-16, so you need to do this:
$data = mb_convert_encoding($data,'UTF-8','UTF-16');
before you start to work with the data. I made a working example here:
http://www.servisio.com/test.html
It contains these four lines:
$data = file_get_contents("http://proxylists.connectionincognito.com/proxies_657.txt");
$data = mb_convert_encoding($data,'UTF-8','UTF-16');
$lines = explode("\n", $data);
foreach($lines as $line) echo $line.'<br>';
I have a CSV file and we know excel does its thing with commas in a field by enclosing them in double quotation marks for instance i have a file
Product Name,Product Code
Product 1,AAA
"Prod,A,B",BBB
How can I use RegExp to replace the quotation marks with "." instead but only within quotation marks so i get
Product Name,Product Code
Product 1,AAA
Prod.A.B,BBB
as output
CSV handling functions (fgetcsv(), fputcsv()) are much better for this - they will handle edge cases and will likely be far more reliable than any regex you can come up with.
// Open the file
$fp = fopen($pathToCsvFile, 'r+');
// Create an array of modified data
$tmp = array();
while (($row = fgetcsv($fp, 8192)) !== FALSE) {
foreach ($row as &$field) $field = str_replace(',', '.', $field);
$tmp[] = $row;
}
// Truncate the file and put the pointer at the beginning
ftruncate($fp, 0);
rewind($fp);
// Write the modified data back and close the file
foreach ($tmp as $row) {
fputcsv($fp, $row);
}
fclose($fp);
EDIT Following your comment about not wanting to read from/write to disk, you can do this:
// Lets say the raw CSV data is held in this variable as a string
$rawCsvData = 'Product Name,Product Code
Product 1,AAA
"Prod,A,B",BBB';
// Open a virtual file pointer to memory and fill it with your data
$fp = fopen('php://memory', 'w+');
fwrite($fp, $rawCsvData);
// Start from the beginning of the pointer
rewind($fp);
// ... INSERT CODE FROM ABOVE HERE (minus the fopen()/fclose())
$modifiedCsvData = stream_get_contents($fp);
fclose($fp);
This will do multiple replaces, and remove the quotes.
<?php
$data = 'Product Name,Product Code
Product 1,AAA
"Prod,A,B",BBB';
$rgx = '/"(.+?)"/';
preg_match_all($rgx, $data, $matches);
$x = 0; $max = count($matches[0]);
while($x < $max){
$replace = str_replace(",", ".", $matches[1][$x]);
$data = str_replace($matches[0][$x], $replace, $data);
$x++;
}
echo $data;
?>