Your IP : 3.136.23.84


Current Path : /home/bitrix/ext_www/ballu.in.ua/bitrix/modules/translate/lib/
Upload File :
Current File : /home/bitrix/ext_www/ballu.in.ua/bitrix/modules/translate/lib/csvfile.php

<?php
namespace Bitrix\Translate;

use Bitrix\Main\Text\BinaryString;
use Bitrix\Main;

class CsvFile extends File
{
	// fields type with delimiter,
	const FIELDS_TYPE_FIXED_WIDTH = 'F';
	// fields type fixed width
	const FIELDS_TYPE_WITH_DELIMITER = 'R';

	/**
	 * fields type
	 * @var string
	 */
	protected $fieldsType = self::FIELDS_TYPE_WITH_DELIMITER;

	// field delimiter
	const DELIMITER_TAB = "\t";
	const DELIMITER_ZPT = ',';
	const DELIMITER_SPS = ' ';
	const DELIMITER_TZP = ';';

	/**
	 * field delimiter
	 * @var string
	 */
	protected $fieldDelimiter = self::DELIMITER_TZP;

	// UTF-8 Byte-Order Mark
	const BOM_TYPE_UTF8 = "\xEF\xBB\xBF";

	/**
	 * UTF Byte-Order Mark.
	 * @var string
	 */
	protected $bomMark = self::BOM_TYPE_UTF8;

	/**
	 * First bites is file are the Byte-Order Mark.
	 * @var bool
	 */
	protected $hasBom = false;

	const LINE_DELIMITER_WIN = "\r\n";
	const LINE_DELIMITER_UNIX = "\r";

	/**
	 * line delimiter
	 * @var string
	 */
	protected $rowDelimiter = self::LINE_DELIMITER_WIN;

	/**
	 * array of delimiters positions in fixed width case
	 * @var array
	 */
	protected $widthMap = array();

	/**
	 * The first row is columns titles.
	 * @var bool
	 */
	protected $firstHeader = false;


	/**
	 * File length.
	 * @var string
	 */
	private $fileSize;
	/**
	 * Current file position for fetch.
	 * @var int
	 */
	private $currentPosition = 0;
	/** @var string  */
	private $buffer = '';
	/** @var int  */
	private $bufferPosition = 0;
	/** @var int  */
	private $bufferSize = 0;



	/**
	 * Opens file for reading.
	 *
	 *
	 * @return bool
	 */
	public function openLoad()
	{
		if (parent::openLoad())
		{
			$this->fileSize = $this->getSize();
			$this->checkUtf8Bom();
		}

		return $this->isExists() && $this->isReadable();
	}

	/**
	 * Opens file for writing.
	 *
	 * @return bool
	 */
	public function openWrite()
	{
		if (parent::openWrite())
		{
			$this->fileSize = 0;
			if ($this->hasBom)
			{
				$this->fileSize = $this->write($this->bomMark);
			}

			return true;
		}

		return false;
	}

	/**
	 * Sets UTF Byte-Order Mark.
	 *
	 * @param string $mark BOM mark.
	 * @return self
	 */
	public function setUtf8Bom($mark = self::BOM_TYPE_UTF8)
	{
		$this->bomMark = $mark;

		return $this;
	}

	/**
	 * Tells true if UTF Byte-Order Mark exists in the file.
	 *
	 * @return bool
	 */
	public function hasUtf8Bom()
	{
		return $this->hasBom;
	}

	/**
	 * Sets if UTF-8 Byte-Order Mark exists.
	 *
	 * @param bool $exists Flag value to setup.
	 *
	 * @return self
	 */
	public function prefaceWithUtf8Bom($exists = true)
	{
		$this->hasBom = $exists;

		return $this;
	}

	/**
	 * Check UTF-8 Byte-Order Mark
	 * @return bool
	 */
	public function checkUtf8Bom()
	{
		$this->seek(0);
		$bom = $this->read(BinaryString::getLength($this->bomMark));
		if($bom === $this->bomMark)
		{
			$this->hasBom = true;
		}

		if ($this->hasBom)
		{
			$this->seek(BinaryString::getLength($this->bomMark));
		}
		else
		{
			$this->seek(0);
		}

		return $this->hasBom;
	}

	/**
	 * Set fields type.
	 *
	 * @param string $fieldsType Type.
	 * @return self
	 */
	public function setFieldsType($fieldsType = self::FIELDS_TYPE_WITH_DELIMITER)
	{
		$this->fieldsType =
			($fieldsType == self::FIELDS_TYPE_FIXED_WIDTH ? self::FIELDS_TYPE_FIXED_WIDTH : self::FIELDS_TYPE_WITH_DELIMITER);

		return $this;
	}

	/**
	 * Sets up delimiter character.
	 *
	 * @param string $fieldDelimiter Char.
	 *
	 * @return self
	 */
	public function setFieldDelimiter($fieldDelimiter = self::DELIMITER_TZP)
	{
		$this->fieldDelimiter = (strlen($fieldDelimiter) > 1 ? substr($fieldDelimiter, 0, 1) : $fieldDelimiter);

		return $this;
	}

	/**
	 * Sets up row delimiter character.
	 *
	 * @param string $rowDelimiter Char.
	 *
	 * @return self
	 */
	public function setRowDelimiter($rowDelimiter = self::LINE_DELIMITER_WIN)
	{
		$this->rowDelimiter = $rowDelimiter;

		return $this;
	}

	/**
	 * Sets first row as a header.
	 *
	 * @param bool $firstHeader Flag.
	 * @return self
	 */
	public function setFirstHeader($firstHeader = false)
	{
		$this->firstHeader = $firstHeader;

		return $this;
	}

	/**
	 * Tells true if first row is a header.
	 *
	 * @return bool
	 */
	public function getFirstHeader()
	{
		return $this->firstHeader;
	}

	/**
	 * Sets up fields widths.
	 *
	 * @param int[] $mapFields Fields widths.
	 * @return self
	 */
	public function setWidthMap($mapFields)
	{
		$this->widthMap = array();
		for ($i = 0, $n = count($mapFields); $i < $n; $i++)
		{
			$this->widthMap[$i] = (int)$mapFields[$i];
		}

		return $this;
	}

	/**
	 * Fetches data row as delimited columns.
	 *
	 * @return array|bool
	 */
	protected function fetchDelimiter()
	{
		$isInside = false;
		$str = '';
		$result = array();
		while ($this->currentPosition < $this->fileSize)
		{
			$ch = $this->buffer[$this->bufferPosition];
			if ($ch == "\r" || $ch == "\n")
			{
				if (!$isInside)
				{
					while ($this->currentPosition < $this->fileSize)
					{
						$this->incrementCurrentPosition();
						$ch = $this->buffer[$this->bufferPosition];
						if ($ch != "\r" && $ch != "\n")
						{
							break;
						}
					}
					if ($this->firstHeader)
					{
						$this->firstHeader = false;
						$result = array();
						$str = '';
						continue;
					}

					$result[] = $str;
					return $result;
				}
			}
			elseif ($ch == "\"")
			{
				if (!$isInside)
				{
					$isInside = true;
					$this->incrementCurrentPosition();
					continue;
				}

				$this->incrementCurrentPosition();
				if ($this->buffer[$this->bufferPosition] != "\"")
				{
					$isInside = false;
					continue;
				}
			}
			elseif ($ch == $this->fieldDelimiter)
			{
				if (!$isInside)
				{
					$result[] = $str;
					$str = '';
					$this->incrementCurrentPosition();
					continue;
				}
			}

			//inline "call"
			$this->currentPosition ++;
			$this->bufferPosition ++;
			if ($this->bufferPosition >= $this->bufferSize)
			{
				$this->buffer = $this->read(1024 * 1024);
				$this->bufferSize = BinaryString::getLength($this->buffer);
				$this->bufferPosition = 0;
			}

			$str .= $ch;
		}

		if ($str <> '')
		{
			$result[] = $str;
		}

		if(empty($result))
		{
			return false;
		}

		return $result;
	}

	/**
	 * Fetches data row as fixed width columns.
	 *
	 * @return array|bool
	 */
	protected function fetchWidth()
	{
		$str = '';
		$ind = 1;
		$jnd = 0;
		$result = array();

		while ($this->currentPosition < $this->fileSize)
		{
			$ch = $this->buffer[$this->bufferPosition];
			if ($ch == "\r" || $ch == "\n")
			{
				while ($this->currentPosition < $this->fileSize)
				{
					$this->incrementCurrentPosition();
					$ch = $this->buffer[$this->bufferPosition];
					if ($ch != "\r" && $ch != "\n")
					{
						break;
					}
				}
				if ($this->firstHeader)
				{
					$this->firstHeader = false;
					$result = array();
					$ind = 1;
					$str = '';
					continue;
				}

				$result[] = $str;
				return $result;
			}
			if ($ind == $this->widthMap[$jnd])
			{
				$result[] = $str.$ch;
				$str = '';
				$this->incrementCurrentPosition();
				$ind++;
				$jnd++;
				continue;
			}

			//inline "call"
			$this->currentPosition ++;
			$this->bufferPosition ++;
			if($this->bufferPosition >= $this->bufferSize)
			{
				$this->buffer = $this->read( 1024 * 1024);
				$this->bufferSize = BinaryString::getLength($this->buffer);
				$this->bufferPosition = 0;
			}

			$ind ++;
			$str .= $ch;
		}

		if ($str <> '')
		{
			$result[] = $str;
		}

		if(empty($result))
		{
			return false;
		}

		return $result;
	}

	/**
	 * Fetch data row.
	 *
	 * @return array|bool
	 */
	public function fetch()
	{
		if ($this->fieldsType == self::FIELDS_TYPE_WITH_DELIMITER)
		{
			if ($this->fieldDelimiter == '')
			{
				return false;
			}

			return $this->fetchDelimiter();
		}

		if (empty($this->widthMap))
		{
			return false;
		}

		return $this->fetchWidth();
	}

	/**
	 * Moves reading position and reads file into buffer.
	 *
	 * @return void
	 */
	protected function incrementCurrentPosition()
	{
		$this->currentPosition ++;
		$this->bufferPosition ++;
		if ($this->bufferPosition >= $this->bufferSize)
		{
			$this->buffer = $this->read( 1024 * 1024);
			$this->bufferSize = BinaryString::getLength($this->buffer);
			$this->bufferPosition = 0;
		}
	}

	/**
	 * Moves reading position to the first byte.
	 *
	 * @return void
	 */
	protected function moveFirst()
	{
		$this->setPos(0);
	}

	/**
	 * Returns reading position.
	 *
	 * @return int
	 */
	protected function getPos()
	{
		return $this->currentPosition;
	}

	/**
	 * Sets new reading position.
	 *
	 * @param int $position Reading position.
	 *
	 * @return void
	 */
	protected function setPos($position = 0)
	{
		$position = intval($position);
		if ($position <= $this->fileSize)
		{
			$this->currentPosition = $position;
		}
		else
		{
			$this->currentPosition = $this->fileSize;
		}

		$pos = $this->currentPosition;
		if($this->hasBom)
		{
			$pos += 3;
		}
		$this->seek($pos);

		$this->buffer = $this->read(1024 * 1024);

		$this->bufferSize = BinaryString::getLength($this->buffer);
		$this->bufferPosition = 0;
	}

	/**
	 * Writes data fields into file as row.
	 *
	 * @param array $fields Data field.
	 * 
	 * @return bool
	 */
	public function put(array $fields)
	{
		$length = false;
		if ($this->fieldsType == self::FIELDS_TYPE_WITH_DELIMITER)
		{
			$content = '';
			for ($i = 0, $n = count($fields); $i < $n; $i++)
			{
				if ($i>0)
				{
					$content .= $this->fieldDelimiter;
				}
				$pos1 = strpos($fields[$i], $this->fieldDelimiter);
				$pos2 = $pos1 || strpos($fields[$i], "\"");
				$pos3 = $pos2 || strpos($fields[$i], "\n");
				$pos4 = $pos3 || strpos($fields[$i], "\r");
				if ($pos1 !== false || $pos2 !== false || $pos3 !== false || $pos4 !== false)
				{
					$fields[$i] = str_replace("\"", "\"\"", $fields[$i]);
					$fields[$i] = str_replace("\\", "\\\\", $fields[$i]);
				}
				$content .= "\"";
				$content .= $fields[$i];
				$content .= "\"";
			}
			if ($content <> '')
			{
				$content .= $this->rowDelimiter;

				$length = $this->write($content);
				if ($length !== false)
				{
					$this->fileSize += $length;
				}
			}
		}
		// todo: $this->fieldsType == self::FIELDS_TYPE_FIXED_WIDTH

		return ($length !== false);
	}
}