first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,452 @@
<?php
use PhpOffice\PhpSpreadsheet\IOFactory;
/**
* AutomaticImportTransform.
*
* @author Petr Knap <knap@wpj.cz>
*
* @category Import
*/
class AutomaticImportTransform
{
private $pathToFile;
private $typeOfFile;
private $rootElementName = 'xml';
private $headElementName = 'head';
private $itemElementName = 'item';
private $colNames = [];
private $encoding;
/**
* Zkouška existence souboru na disku.
*
* @param string $iPathToFile cesta k souboru na pevném disku
*
* @return bool
*/
private static function TestFile($iPathToFile)
{
return file_exists($iPathToFile);
}
/**
* Konstruktor třídy.
*
* @param string $iPathToFile cesta k souboru na pevném disku
* @param string|null $iTypeOfFile typ souboru (null = automatická detekce)
*/
public function __construct($iPathToFile, $iTypeOfFile = null)
{
if (self::TestFile($iPathToFile)) {
$this->pathToFile = $iPathToFile;
if ($iTypeOfFile === null) {
$this->typeOfFile = IOFactory::identify($this->pathToFile);
} else {
$this->typeOfFile = $iTypeOfFile;
}
}
}
/**
* Setter pro $rootElementName.
*
* @param string $iName název XML root tagu
*
* @return bool
*/
public function setRootElementName($iName)
{
if (is_string($iName) && !preg_match('/[^A-Za-z0-9]/', $iName)) {
$this->rootElementName = $iName;
return true;
}
return false;
}
/**
* Setter pro $headElementName.
*
* @param string $iName název XML head tagu
*
* @return bool
*/
public function setHeadElementName($iName)
{
if (is_string($iName) && !preg_match('/[^A-Za-z0-9]/', $iName)) {
$this->headElementName = $iName;
return true;
}
return false;
}
/**
* Setter pro $itemElementName.
*
* @param string $iName název XML item tagu
*
* @return bool
*/
public function setItemElementName($iName)
{
if (is_string($iName) && !preg_match('/[^A-Za-z0-9]/', $iName)) {
$this->itemElementName = $iName;
return true;
}
return false;
}
/**
* Setter pro $colNames.
*
* @param array(string) $iNames Pole stringů obsahující názvy XML subitem tagy. Pole je ve tvaru $index => $nazev, např. array(0 => 'id', 1 => 'name',...).
*
* @return bool
*/
public function setColNames($iNames)
{
if (is_array($iNames)) {
foreach ($iNames as $name) {
if (!is_string($name) || preg_match('/[^A-Za-z0-9_]/', $name)) {
return false;
}
}
$this->colNames = $iNames;
return true;
}
return false;
}
public function setEncoding($encoding)
{
if (empty($encoding)) {
return;
}
switch ($this->typeOfFile) {
case 'HTML':
case 'Csv':
ob_start(); // start output buffering
readfile($this->pathToFile);
// save buffer in a file
$buffer = ob_get_clean();
@ob_end_clean();
$buffer = iconv($encoding, 'UTF-8', $buffer);
if ($buffer !== false) {
$this->pathToFile = "{$this->pathToFile}.utf8";
file_put_contents($this->pathToFile, $buffer);
}
break;
case 'dbf':
$this->encoding = $encoding;
break;
}
}
/**
* Metoda pro načtení binárního tabulkového souboru (XLS, XLSX, ODS, atd.) do 3D pole.
*
* @return array|null
*/
public function LoadBinfileAsArray()
{
if (!self::TestFile($this->pathToFile)) {
return null;
}
$output = [];
$objReader = IOFactory::createReader($this->typeOfFile);
$objReader->setLoadAllSheets();
$objPHPExcel = $objReader->load($this->pathToFile);
$loadedSheetNames = $objPHPExcel->getSheetNames();
foreach ($loadedSheetNames as $sheetIndex => $loadedSheetName) {
$objPHPExcel->setActiveSheetIndex($sheetIndex);
$output[$loadedSheetName] = $objPHPExcel->getActiveSheet()->rangeToArray($objPHPExcel->getActiveSheet()->calculateWorksheetDataDimension(), null, true, true, true);
}
return $output;
}
/**
* Metoda pro načtení CSV tabulkového souboru do 2D pole.
*
* @param string|null $iItemSeparator oddělovač položek v řádku
* @param string|null $iLineSeparator oddělovač řádků
*
* @return array|null
*/
public function LoadCsvfileAsArray($iItemSeparator = null, $iLineSeparator = null)
{
if (!self::TestFile($this->pathToFile)) {
return null;
}
$output = [];
if ($iItemSeparator === null) {
$ItemSeparator = ';';
} else {
$ItemSeparator = $iItemSeparator;
}
if ($iLineSeparator === null) {
$LineSeparator = "\n";
} else {
$LineSeparator = $iLineSeparator;
}
$handle = fopen($this->pathToFile, 'r');
while (($row = fgetcsv($handle, null, $ItemSeparator, '"')) != false) {
$output[] = $row;
}
fclose($handle);
return $output;
}
/**
* Metoda pro převod tabulkového souboru na XML.
*
* Základní XML struktura je následující:
* <xml>
* <head>
* <col>...</col>
* ...
* <col>...</col>
* </head>
* <item>
* <col>...</col>
* ...
* <col>...</col>
* </item>
* ...
* <item>...</item>
* </xml>
* Tuto strukturu lze modifikovat pomocí metod setRootElementName, setHeadElementName, setItemElementName a setColNames.
*
* @param int $iFirstDataLine index prvního datového řádku (číslováno od 1)
* @param string|null $iSheetName_iItemSeparator název sešitu nebo znak oddělující položky na řádku
* @param array $params další parametry s případnou konfigurací pro načtení souboru
*
* @return string|null
*/
public function GetXml($iHeaderLine = 0, $iFirstDataLine = 1, $iSheetName_iItemSeparator = null, array $params = [])
{
if (!self::TestFile($this->pathToFile)) {
return null;
}
$output = new SimpleXMLElement("<?xml version='1.0' encoding='UTF-8'?><{$this->rootElementName}/>");
switch ($this->typeOfFile) {
case 'Xls':
case 'Xml':
case 'Xlsx':
case 'Ods':
$data = self::LoadBinfileAsArray();
if ($iSheetName_iItemSeparator === null) {
$values = array_values($data);
$data = array_shift($values);
} else {
$data = $data[$iSheetName_iItemSeparator];
}
break;
case 'json':
$data = json_decode(file_get_contents($this->pathToFile), true);
break;
case 'dbf':
$data = $this->LoadDBFDatabase();
break;
default: // CSV
$data = self::LoadCsvfileAsArray($iSheetName_iItemSeparator);
$iFirstDataLine--;
$iHeaderLine--;
break;
}
if ($data === null) {
return null;
}
// vložení hlavičky
if ($iHeaderLine > 0 || ($params['forceHeaderLine'] ?? null) !== null) {
$i = 0;
$heads = $data[$params['forceHeaderLine'] ?? $iHeaderLine];
$head = $output->addChild($this->headElementName);
if (count($heads) == 1 && strpos($heads[0], 'columns:') === 0) { // Úprava pro WinShop
$heads = explode(
';',
trim(
str_replace('columns:', '', $heads[0])
)
);
}
foreach ($heads as $name) {
if (empty($this->colNames[$i])) {
$this->colNames[$i] = empty($name) ? 'col' : createScriptURL_Text($name);
}
$head->addChild($this->colNames[$i], $name);
$i++;
}
}
// odtržení úvodní části
for ($i = 1; $i < $iFirstDataLine; $i++) {
array_shift($data);
}
// sestavení datové části
foreach ($data as $A => $B) {
$item = $output->addChild($this->itemElementName);
$this->addItemChildren($item, $B);
}
return $output;
}
public function addItemChildren($parent, $data)
{
$i = 0;
foreach ($data as $key => $item) {
if (empty($this->colNames[$i])) {
$this->colNames[$i] = 'col';
}
$colName = $this->colNames[$i];
if ($this->typeOfFile == 'json') {
$colName = $key;
if (is_numeric($key)) {
$colName = $this->itemElementName;
}
}
if (is_array($item)) {
$newParent = @$parent->addChild($colName);
$this->addItemChildren($newParent, $item);
} else {
@$parent->addChild($colName, strtr($item, ['&' => '&amp;', '>' => '&gt;', '<' => '&lt;']));
}
$i++;
}
}
/**
* Metoda pro převod XML souboru za využití XSL.
*
* @param DomDocument $xsl xSL šablona
* @param DomDocument $xml_doc XML dokument
*
* @return DomDocument|void|null
*/
public static function TransformXml($xsl, $xml_doc)
{
$xp = new XSLTProcessor();
$xp->registerPHPFunctions(['xsl_replace', 'count_same']);
$xp->importStylesheet($xsl);
if ($output = $xp->transformToDoc($xml_doc)) {
return $output;
} else {
trigger_error('XSL transformation failed.', E_USER_ERROR);
}
}
public static function LoadXMLFromFile($fileName)
{
if (!self::TestFile($fileName)) {
trigger_error('Cannot load XML file {$fileName}.', E_USER_ERROR);
return null;
}
$xml = new DOMDocument();
@$xml->load($fileName);
return $xml;
}
public function LoadDBFDatabase()
{
$table = new XBase\Table($this->pathToFile);
$columns = [];
foreach ($table->getColumns() as $name => $column) {
$columns[] = preg_replace('/[^[:print:]\p{L}]/u', '', $name);
}
if (count($columns) <= 0) {
throw new Exception('Empty DBF file');
}
$this->setColNames($columns);
$data = [];
while ($record = $table->nextRecord()/* && $i++ < 1000 */) {
$row = [];
foreach ($table->getColumns() as $name => $column) {
if ($this->encoding && $column->getType() == XBase\Record::DBFFIELD_TYPE_CHAR) {
$row[] = preg_replace('/[^[:print:]\p{L}]/u', '', iconv($this->encoding, 'UTF-8', $record->getString($name) ?? ''));
} else {
$row[] = $record->getString($name);
}
}
$data[] = $row;
}
return $data;
}
}
/**
* Replace all occurrences of the search string with the replacement string.
*
* @param mixed $search The value being searched for, otherwise known as the needle. An array may be used to designate multiple needles.
* @param mixed $replace The replacement value that replaces found search values. An array may be used to designate multiple replacements.
* @param mixed $subject the string, DOM element or array being searched and replaced on, otherwise known as the haystack
* @param int $count if passed, this will be set to the number of replacements performed
*
* @return mixed this function returns a string with the replaced values
*/
function xsl_replace($search, $replace, $subject, &$count = null)
{
if (is_array($subject)) {
$subject = $subject[0];
}
if (!is_string($subject)) {
$subject = $subject->textContent;
}
return str_replace($search, $replace, $subject, $count);
}
/**
* @param DOMElement $node
*/
function count_same($node, $attr)
{
if (is_array($node)) {
$node = $node[0];
}
var_dump($node->firstChild->textContent);
exit;
$next = $node;
$value = $node->getAttribute($attr);
var_dump([$value, $attr]);
$count = 1;
while ($next && $next->getAttribute($attr) == $value) {
var_dump([$count, $next->getAttribute($attr)]);
$count++;
$next = $next->nextSibling;
}
exit(var_dump($count));
}