OpenXE/classes/Components/Exporter/Csv/CsvWriter.php
2021-05-21 08:49:41 +02:00

148 lines
3.7 KiB
PHP

<?php
namespace Xentral\Components\Exporter\Csv;
use Iterator;
use Xentral\Components\Exporter\Exception\InvalidResourceException;
use Xentral\Components\Exporter\Exception\PhpExtensionMissingException;
final class CsvWriter
{
/** @var resource $handle */
private $handle;
/** @var CsvConfig $config */
private $config;
/**
* @param resource $handle
* @param CsvConfig|null $config
*
* @throws InvalidResourceException If resource is not writable or invalid
* @throws PhpExtensionMissingException If mbstring is missing
*/
public function __construct($handle, CsvConfig $config = null)
{
if (!is_resource($handle)) {
throw new InvalidResourceException('First parameter is not a valid resource.');
}
if (!$this->isStreamWritable($handle)) {
throw new InvalidResourceException('Resource is not writable.');
}
if (!function_exists('mb_convert_encoding')) {
throw new PhpExtensionMissingException('Required PHP extension "mbstring" is missing.');
}
if ($config === null) {
$config = new CsvConfig();
}
$this->config = $config;
$this->handle = $handle;
}
/**
* @param array|Iterator $lines
*
* @return void
*/
public function writeLines($lines)
{
foreach ($lines as $line) {
$this->writeLine($line);
}
}
/**
* @param array $line
*
* @return void
*/
public function writeLine($line)
{
if ($this->config->isForceEnclosureEnabled()) {
$fields = $this->encloseAllValues($line);
fwrite(
$this->handle,
sprintf(
"%s\n",
implode($this->config->getDelimiter(), $this->convertCharset($fields))
)
);
return;
}
fputcsv(
$this->handle,
$this->convertCharset($line),
$this->config->getDelimiter(),
$this->config->getEnclosure(),
$this->config->getEscapeChar()
);
}
/***
* @param array $line
*
* @return array
*/
private function encloseAllValues($line)
{
$escapeChar = $this->config->getEscapeChar();
$enclosure = $this->config->getEnclosure();
$result = [];
foreach ($line as $key => $value) {
$value = str_replace($escapeChar . $enclosure, $enclosure, $value);
$value = str_replace($enclosure, $escapeChar . $enclosure, $value);
$result[$key] = sprintf('%1$s%2$s%1$s', $enclosure, $value);
}
return $result;
}
/**
* @param array $line
*
* @return array
*/
private function convertCharset($line)
{
if ($this->config->getSourceCharset() === $this->config->getTargetCharset()) {
return $line; // No conversion needed
}
$result = [];
foreach ($line as $key => $cellData) {
$result[$key] = mb_convert_encoding(
$cellData,
$this->config->getTargetCharset(),
$this->config->getSourceCharset()
);
}
return $result;
}
/**
* @param resource $handle
*
* @return bool
*/
private function isStreamWritable($handle)
{
$meta = stream_get_meta_data($handle);
$currentMode = $meta['mode'];
$writeModes = ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+'];
foreach ($writeModes as $writeMode) {
if (strpos($currentMode, $writeMode) !== false) {
return true;
}
}
return false;
}
}