I want to create a CSV file in php, encoded in UTF-8, all caracters are well rendered (even accents, cause I am french), except quotes, that are rendered as "'".
Can anyone help me?
Here is an example of my code, in Symfony2
$response = new Response();
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-disposition', 'attachment; filename="'.$name.'.csv"');
$response->setContent(utf8_decode($csv));
$response->setStatusCode(200);
Thank's a lot
Some pointers for you:
utf8_decode produces ISO-8859-1 content. Therefore your output is not UTF-8.
' is the same in UTF-8, ASCII, Windows-1252 and ISO-8859-1
I suspect ' is coming from your CSV source.
If you're building the source, ensure you use UTF-8 chars. Then you don't need to convert. If you're reading from disk, make sure you know the original character set. Don't convert character sets unless you know the original character set.
I am using Symfony 4.4.
These are the 2 solutions that worked for me :
1. First one:
// This import is used to inject a serializer object
use Symfony\Component\Serializer\SerializerInterface;
$content = $this->serializer->serialize($csv, 'csv', [
'csv_delimiter' => ';',
'output_utf8_bom' => true,
]);
$response = new Response($content);
$response->headers->set('Cache-Control', 'no-cache');
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition', $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT, "$name.csv"
));
2. Second one:
headers => contains your headers.
lines => contains your lines.
$response = new StreamedResponse();
$response->headers->set('Cache-Control', 'no-cache');
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition', $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
"$name.csv"
));
$response->setCallback(function () use ($headers, $lines) {
$handle = fopen('php://output', 'w+');
// Mandatory: Use bom + "Content-Type: application/force-download" => to allow to display special characters with excel
fwrite($handle, $bom = chr(hexdec('EF')).chr(hexdec('BB')).chr(hexdec('BF')));
// headers
fputcsv($handle, $headers, ';');
// data
foreach ($lines as $line) {
fputcsv($handle, $line, ';');
}
fclose($handle);
});
Related
I have some csv data that looks like this:
$data = 'email,score
john#do.com,3
test#test.com,4';
When I try to export this csv to a file like this:
$response = new StreamedResponse();
$response->setCallback(
static function () use ($data): void {
$fp = fopen('php://output', 'wb');
file_put_contents('exportk.csv', $data);
fclose($fp);
}
);
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', 'attachment; filename="export.csv"');
I get an empty file, what am I doing wrong here
From the Symfony docs:
https://symfony.com/doc/current/components/http_foundation.html#request
If you just created the file during this same request, the file may be sent without any content. This may be due to cached file stats that return zero for the size of the file. To fix this issue, call clearstatcache(true, $file) with the path to the binary file.
If that doesn't fix the issue, maybe try something like this:
use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
$data = <<<END
email,score
john#do.com,3
test#test.com,4
END;
// Just write the file here to save to the file system if you want...
$response = new Response($data);
$disposition = HeaderUtils::makeDisposition(
HeaderUtils::DISPOSITION_ATTACHMENT,
'export.csv'
);
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', $disposition);
$data = file_get_contents($path);
$data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data, 'UTF-8, ISO-8859-1', true));
$csv = Reader::createFromString($data);
$csv->setDelimiter(';');
$csv->setHeaderOffset(0);
$test = $csv->getContent();
return (new Statement)->process($csv);
When I debug and look at $test, all characters are displayed correctly (no lønn etc).
When I loop through the TabularDataReader object returned from this line:
return (new Statement)->process($csv);
the headers are displaying incorrectly e.g "Bil lønn" (should be "Bil lønn").
Do I have to set encoding on the Statement object as well? I looked through the class, but couldn't find any functions related to encoding.
I've had the same issue with league/csv and ISO-8859-1 encoding. Try this workaround:
$data = file_get_contents($path);
if (!mb_check_encoding($data, 'UTF-8')) {
$data = mb_convert_encoding($data, 'UTF-8');
}
$csv = Reader::createFromString($data);
$csv->setDelimiter(';');
$csv->setHeaderOffset(0);
$test = $csv->getContent();
return (new Statement)->process($csv);
I'm trying to create a csv file using laravel and php. The database used to create the csv contains Japanese characters which I want to appear exactly the same in the file.
Below is the code I've tried so far, but the japanese characters still appear as symbols.
$headers = array(
"Content-Encoding" => "sjis-win",
"Content-type" => "text/csv; charset=sjis-win",
"Content-Disposition" => "attachment; filename=User-List.csv",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
);
$users= $this->users->orderBy('created_at', 'desc')->get();
$columns = array('氏名', '氏名(ローマ字)');
$callback = function() use ($users, $columns)
{
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
foreach($users as $user) {
fputcsv($file, array($user->name, $user->name_alphabet));
}
fclose($file);
};
What am I missing? What needs to be changed to make the characters appear as Japanese automatically in the csv.
It working!
// You add $bom in when fputs file.
$headerColumns = [
'name',
'birthday',
'address',
];
$fileCSV = fopen($fileName, 'w');
fputs($fileCSV, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($fileCSV, $headerColumns);
foreach ($data as $myField ){
fputcsv($fileCSV, $myField);
}
fclose($fileCSV);
// Good luck!
As the data your retrieving from the database is encoded in UTF-8, you will need to re-encode that data to match the encoding of your CSV file (SJIS-win).
You can use php's mb_convert_encoding() function to achieve this.
mb_convert_encoding($dataVariable, "SJIS-win", "UTF-8");
In your case you would use it as follows:
foreach($users as $user) {
fputcsv($file, array(
mb_convert_encoding($user->name, "SJIS-win", "UTF-8"),
mb_convert_encoding($user->name_alphabet, "SJIS-win", "UTF-8")
));
}
You may also need to re-encode the strings in your $columns = array('氏名', '氏名(ローマ字)') array too.
I work with yii-powered application. My goal is write controller action what exporting some data from mongodb to csv file using Yii 1.1: csvexport and CHttpRequest::sendFile
My code:
public function actionCatalogDataExport( $catalog_id )
{
// prepare all needed variables here
$data = ..., $headers = ..., $filename = ...
Yii::import('ext.csv.ECSVExport');
$csv = new ECSVExport($data);
$output = $csv->setHeaders($headers)->setDelimiter(',')->toCSV();
Yii::app()->getRequest()->sendFile($filename, $output, "text/csv", true);
}
This script works properly, but if I open resulting file via Excel I see something like that:
There are some problems with file encoding... I opened notepad++ and changed encoding to UTF-8 without BOM, now file looks good (language: Ru):
Tested this fixes but no success results:
header('Content-type: text/csv; charset=UTF-8'); // no effect
Yii::app()->getRequest()->sendFile(
$filename,
$output,
"text/csv; charset=UTF-8", // no effect
true
);
How can I achieve this immediately after yii send file action?
Try to add the encode to begin of the csv file like this:
$encode = "\xEF\xBB\xBF"; // UTF-8 BOM
$content = $encode . $csv->toCSV();
//var_dump($content);
Yii::app()->getRequest()->sendFile($filename, $content, "text/csv; charset=UTF-8", false);
By default setup params, Excel for Windows opens csv files using windows-1251 encoding. If I need to make correct data values using this encoding I must use iconv
foreach( $data as $key => &$value ) {
$value = iconv('UTF-8', 'windows-1251', $value);
}
// send file to user...
// ...and it works as I need.
I just want to know if its possible to extract content encoded (in utf-8) from a html file without encoding header.
My specific case is this website:
http://www.metal-archives.com/band/discography/id/203/tab/all
I want to extract all the info but, as you can see, this word for example, looks bad:
Motörhead
I tried to use file_get_html, htmlentities, utf_decode, utf_encode and mix of them with different options but I cant find a solution...
Edit:
I just want to see the same website with correct format with this simple code:
$html_discos = file_get_html("http://www.metal-archives.com/band/discography/id/223/tab/all");
//some transform/decode here
print_r($html_discos);
I want the content in correct format in a string or DOM object to get some parts later.
Edit 2:
$file_get_html is a function of "simple html dom" library:
http://simplehtmldom.sourceforge.net/
That have this code:
function file_get_html($url, $use_include_path = false, $context=null, $offset = -1, $maxLen=-1, $lowercase = true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT, $defaultSpanText=DEFAULT_SPAN_TEXT)
{
// We DO force the tags to be terminated.
$dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $target_charset, $stripRN, $defaultBRText, $defaultSpanText);
// For sourceforge users: uncomment the next line and comment the retreive_url_contents line 2 lines down if it is not already done.
$contents = file_get_contents($url, $use_include_path, $context, $offset);
// Paperg - use our own mechanism for getting the contents as we want to control the timeout.
//$contents = retrieve_url_contents($url);
if (empty($contents) || strlen($contents) > MAX_FILE_SIZE)
{
return false;
}
// The second parameter can force the selectors to all be lowercase.
$dom->load($contents, $lowercase, $stripRN);
return $dom;
}
The Content-Type of the URL
http://www.metal-archives.com/band/discography/id/203/tab/all
is:
Content-Type: text/html
This will default to ISO-8859-1. But instead you want to use UTF-8. Change the Content-Type so this is correctly signaled:
Content-Type: text/html; charset=utf-8
See: Setting the HTTP charset parameter
header('Content-Type: text/html; charset=utf-8');
echo file_get_contents('http://www.metal-archives.com/band/discography/id/203/tab/all');
As long as you are emitting as UTF-8, the raw data will work properly.
Try using html_eneity_decode http://php.net/manual/en/function.html-entity-decode.php (the source of that page has encoded characters)