parent
2a60e34558
commit
a035acdc2c
|
|
@ -7,7 +7,7 @@ use Response;
|
|||
use Backend;
|
||||
use BackendAuth;
|
||||
use Backend\Classes\ControllerBehavior;
|
||||
use Backend\Classes\StreamFilterTranscode;
|
||||
use Backend\Behaviors\ImportExportController\TranscodeFilter;
|
||||
use League\Csv\Reader as CsvReader;
|
||||
use League\Csv\Writer as CsvWriter;
|
||||
use ApplicationException;
|
||||
|
|
@ -175,20 +175,14 @@ class ImportExportController extends ControllerBehavior
|
|||
try {
|
||||
$model = $this->importGetModel();
|
||||
$matches = post('column_match', []);
|
||||
$importOptions = [
|
||||
'sessionKey' => $this->importUploadFormWidget->getSessionKey()
|
||||
];
|
||||
|
||||
if ($optionData = post('ImportOptions')) {
|
||||
$model->fill($optionData);
|
||||
}
|
||||
|
||||
if (post('format_preset') == 'custom') {
|
||||
$importOptions['delimiter'] = post('format_delimiter');
|
||||
$importOptions['enclosure'] = post('format_enclosure');
|
||||
$importOptions['escape'] = post('format_escape');
|
||||
$importOptions['encoding'] = post('format_encoding');
|
||||
}
|
||||
$importOptions = $this->getFormatOptionsFromPost();
|
||||
$importOptions['sessionKey'] = $this->importUploadFormWidget->getSessionKey();
|
||||
$importOptions['firstRowTitles'] = post('first_row_titles', false);
|
||||
|
||||
$model->import($matches, $importOptions);
|
||||
|
||||
|
|
@ -226,7 +220,7 @@ class ImportExportController extends ControllerBehavior
|
|||
}
|
||||
|
||||
$path = $this->getImportFilePath();
|
||||
$reader = $this->createCsvReader($path);
|
||||
$reader = $this->createCsvReader($path);
|
||||
|
||||
if (post('first_row_titles')) {
|
||||
$reader->setOffset(1);
|
||||
|
|
@ -301,7 +295,7 @@ class ImportExportController extends ControllerBehavior
|
|||
return null;
|
||||
}
|
||||
|
||||
$reader = $this->createCsvReader($path);
|
||||
$reader = $this->createCsvReader($path);
|
||||
$firstRow = $reader->fetchOne(0);
|
||||
|
||||
if (!post('first_row_titles')) {
|
||||
|
|
@ -310,8 +304,10 @@ class ImportExportController extends ControllerBehavior
|
|||
});
|
||||
}
|
||||
|
||||
// Prevents unfriendly error to be thrown due to bad encoding at response time
|
||||
if (false === json_encode($firstRow)) {
|
||||
/*
|
||||
* Prevents unfriendly error to be thrown due to bad encoding at response time.
|
||||
*/
|
||||
if (json_encode($firstRow) === false) {
|
||||
throw new ApplicationException(Lang::get('backend::lang.import_export.encoding_not_supported_error'));
|
||||
}
|
||||
|
||||
|
|
@ -395,19 +391,13 @@ class ImportExportController extends ControllerBehavior
|
|||
try {
|
||||
$model = $this->exportGetModel();
|
||||
$columns = $this->processExportColumnsFromPost();
|
||||
$exportOptions = [
|
||||
'sessionKey' => $this->exportFormatFormWidget->getSessionKey()
|
||||
];
|
||||
|
||||
if ($optionData = post('ExportOptions')) {
|
||||
$model->fill($optionData);
|
||||
}
|
||||
|
||||
if (post('format_preset') == 'custom') {
|
||||
$exportOptions['delimiter'] = post('format_delimiter');
|
||||
$exportOptions['enclosure'] = post('format_enclosure');
|
||||
$exportOptions['escape'] = post('format_escape');
|
||||
}
|
||||
$exportOptions = $this->getFormatOptionsFromPost();
|
||||
$exportOptions['sessionKey'] = $this->exportFormatFormWidget->getSessionKey();
|
||||
|
||||
$reference = $model->export($columns, $exportOptions);
|
||||
$fileUrl = $this->controller->actionUrl(
|
||||
|
|
@ -705,7 +695,6 @@ class ImportExportController extends ControllerBehavior
|
|||
return $this->controller->actionUrl($type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new CSV reader with options selected by the user
|
||||
* @param string $path
|
||||
|
|
@ -715,39 +704,59 @@ class ImportExportController extends ControllerBehavior
|
|||
protected function createCsvReader($path)
|
||||
{
|
||||
$reader = CsvReader::createFromPath($path);
|
||||
$options = $this->getFormatOptionsFromPost();
|
||||
|
||||
if (post('format_preset') == 'custom') {
|
||||
$options = [
|
||||
'delimiter' => post('format_delimiter'),
|
||||
'enclosure' => post('format_enclosure'),
|
||||
'escape' => post('format_escape'),
|
||||
'encoding' => post('format_encoding')
|
||||
];
|
||||
if ($options['delimiter'] !== null) {
|
||||
$reader->setDelimiter($options['delimiter']);
|
||||
}
|
||||
|
||||
if ($options['delimiter'] !== null) {
|
||||
$reader->setDelimiter($options['delimiter']);
|
||||
}
|
||||
if ($options['enclosure'] !== null) {
|
||||
$reader->setEnclosure($options['enclosure']);
|
||||
}
|
||||
|
||||
if ($options['enclosure'] !== null) {
|
||||
$reader->setEnclosure($options['enclosure']);
|
||||
}
|
||||
if ($options['escape'] !== null) {
|
||||
$reader->setEscape($options['escape']);
|
||||
}
|
||||
|
||||
if ($options['escape'] !== null) {
|
||||
$reader->setEscape($options['escape']);
|
||||
}
|
||||
|
||||
if ($options['encoding'] !== null) {
|
||||
if ($reader->isActiveStreamFilter()) {
|
||||
$reader->appendStreamFilter(sprintf(
|
||||
'%s%s:%s',
|
||||
StreamFilterTranscode::FILTER_NAME,
|
||||
strtolower($options['encoding']),
|
||||
'utf-8'
|
||||
));
|
||||
}
|
||||
}
|
||||
if (
|
||||
$options['encoding'] !== null &&
|
||||
$reader->isActiveStreamFilter()
|
||||
) {
|
||||
$reader->appendStreamFilter(sprintf(
|
||||
'%s%s:%s',
|
||||
TranscodeFilter::FILTER_NAME,
|
||||
strtolower($options['encoding']),
|
||||
'utf-8'
|
||||
));
|
||||
}
|
||||
|
||||
return $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file format options from postback. This method
|
||||
* can be used to define presets.
|
||||
* @return array
|
||||
*/
|
||||
protected function getFormatOptionsFromPost()
|
||||
{
|
||||
$presetMode = post('format_preset');
|
||||
|
||||
$options = [
|
||||
'delimiter' => null,
|
||||
'enclosure' => null,
|
||||
'escape' => null,
|
||||
'encoding' => null
|
||||
];
|
||||
|
||||
if ($presetMode == 'custom') {
|
||||
$options['delimiter'] = post('format_delimiter');
|
||||
$options['enclosure'] = post('format_enclosure');
|
||||
$options['escape'] = post('format_escape');
|
||||
$options['encoding'] = post('format_encoding');
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?php namespace Backend\Behaviors\ImportExportController;
|
||||
|
||||
use php_user_filter;
|
||||
|
||||
stream_filter_register(StreamFilterTranscode::FILTER_NAME . "*", StreamFilterTranscode::class);
|
||||
|
||||
/**
|
||||
* Transcode stream filter.
|
||||
*
|
||||
* Convert CSV source files from one encoding to another.
|
||||
*/
|
||||
class TranscodeFilter extends php_user_filter
|
||||
{
|
||||
const FILTER_NAME = 'october.csv.transcode.';
|
||||
|
||||
protected $encodingFrom = 'auto';
|
||||
|
||||
protected $encodingTo;
|
||||
|
||||
public function filter($in, $out, &$consumed, $closing)
|
||||
{
|
||||
while ($resource = stream_bucket_make_writeable($in)) {
|
||||
$resource->data = @mb_convert_encoding(
|
||||
$resource->data,
|
||||
$this->encodingTo,
|
||||
$this->encodingFrom
|
||||
);
|
||||
|
||||
$consumed += $resource->datalen;
|
||||
|
||||
stream_bucket_append($out, $resource);
|
||||
}
|
||||
|
||||
return PSFS_PASS_ON;
|
||||
}
|
||||
|
||||
public function onCreate()
|
||||
{
|
||||
if (strpos($this->filtername, self::FILTER_NAME) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = substr($this->filtername, strlen(self::FILTER_NAME));
|
||||
if (!preg_match('/^([-\w]+)(:([-\w]+))?$/', $params, $matches)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($matches[1])) {
|
||||
$this->encodingFrom = $matches[1];
|
||||
}
|
||||
|
||||
$this->encodingTo = mb_internal_encoding();
|
||||
if (isset( $matches[3] )) {
|
||||
$this->encodingTo = $matches[3];
|
||||
}
|
||||
|
||||
$this->params['locale'] = setlocale(LC_CTYPE, '0');
|
||||
if (stripos($this->params['locale'], 'UTF-8') === false) {
|
||||
setlocale(LC_CTYPE, 'en_US.UTF-8');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onClose()
|
||||
{
|
||||
setlocale(LC_CTYPE, $this->params['locale']);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
<?php namespace Backend\Classes;
|
||||
|
||||
use php_user_filter;
|
||||
|
||||
// Register the class for it to be usable by the CSV Lib
|
||||
stream_filter_register(StreamFilterTranscode::FILTER_NAME . "*", StreamFilterTranscode::class);
|
||||
|
||||
/**
|
||||
* A universal transcode stream filter.
|
||||
* Used by the backend import model to convert source file from one encoding to another.
|
||||
* The system must support both source and target encoding encoding.
|
||||
*
|
||||
* @credits https://github.com/thephpleague/csv/blob/master/examples/lib/FilterTranscode.php
|
||||
* @package october\backend
|
||||
*/
|
||||
class StreamFilterTranscode extends php_user_filter
|
||||
{
|
||||
|
||||
const FILTER_NAME = 'convert.transcode.';
|
||||
|
||||
private $encoding_from = 'auto';
|
||||
|
||||
private $encoding_to;
|
||||
|
||||
|
||||
public function onCreate()
|
||||
{
|
||||
if (strpos($this->filtername, self::FILTER_NAME) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = substr($this->filtername, strlen(self::FILTER_NAME));
|
||||
if ( ! preg_match('/^([-\w]+)(:([-\w]+))?$/', $params, $matches)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset( $matches[1] )) {
|
||||
$this->encoding_from = $matches[1];
|
||||
}
|
||||
|
||||
$this->encoding_to = mb_internal_encoding();
|
||||
if (isset( $matches[3] )) {
|
||||
$this->encoding_to = $matches[3];
|
||||
}
|
||||
|
||||
$this->params['locale'] = setlocale(LC_CTYPE, '0');
|
||||
if (stripos($this->params['locale'], 'UTF-8') === false) {
|
||||
setlocale(LC_CTYPE, 'en_US.UTF-8');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function onClose()
|
||||
{
|
||||
setlocale(LC_CTYPE, $this->params['locale']);
|
||||
}
|
||||
|
||||
|
||||
public function filter($in, $out, &$consumed, $closing)
|
||||
{
|
||||
while ($res = stream_bucket_make_writeable($in)) {
|
||||
$res->data = @mb_convert_encoding($res->data, $this->encoding_to, $this->encoding_from);
|
||||
$consumed += $res->datalen;
|
||||
stream_bucket_append($out, $res);
|
||||
}
|
||||
|
||||
return PSFS_PASS_ON;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ use SplTempFileObject;
|
|||
*/
|
||||
abstract class ExportModel extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Called when data is being exported.
|
||||
* The return value should be an array in the format of:
|
||||
|
|
@ -202,5 +201,4 @@ abstract class ExportModel extends Model
|
|||
|
||||
return implode($delimeter, $newData);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?php namespace Backend\Models;
|
||||
|
||||
use Lang;
|
||||
use Model;
|
||||
use League\Csv\Reader as CsvReader;
|
||||
|
||||
|
|
@ -179,7 +180,8 @@ abstract class ImportModel extends Model
|
|||
$file = $this
|
||||
->import_file()
|
||||
->withDeferred($sessionKey)
|
||||
->first();
|
||||
->first()
|
||||
;
|
||||
|
||||
if (!$file) {
|
||||
return null;
|
||||
|
|
@ -195,7 +197,7 @@ abstract class ImportModel extends Model
|
|||
*/
|
||||
public function getFormatEncodingOptions()
|
||||
{
|
||||
return \Lang::get('backend::lang.import_export.encodings');
|
||||
return Lang::get('backend::lang.import_export.encodings');
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue