%PDF- %PDF-
Direktori : /home/lightco1/upgrade.lightco.com.au/administrator/components/com_csvi/models/ |
Current File : /home/lightco1/upgrade.lightco.com.au/administrator/components/com_csvi/models/analyzers.php |
<?php /** * @package CSVI * @subpackage Analyzer * * @author Roland Dalmulder <contact@csvimproved.com> * @copyright Copyright (C) 2006 - 2016 RolandD Cyber Produksi. All rights reserved. * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html * @link http://www.csvimproved.com */ defined('_JEXEC') or die; /** * Analyzer model. * * @package CSVI * @subpackage Analyzer * @since 6.0 */ class CsviModelAnalyzers extends FOFModel { /** * The file to analyze * * @var string * @since 5.3.3 */ private $filename = null; /** * The real filename of the file to analyze * * @var string * @since 6.0 */ private $realname = null; /** * Number of lines to check * * @var int * @since 5.3.3 */ private $lines = 3; /** * Set if file has column headers * * @var bool * @since 5.3.3 */ private $columnheader = true; /** * Set if file has a BOM * * @var bool * @since 5.3.3 */ private $bom = false; /** * List of errors encountered after checking the CSV file * * @var array * @since 5.3.3 */ private $csverrors = array(); /** * List of messages to show * * @var array * @since 5.3.3 */ private $messages = array(); /** * List of recommendations * * @var array * @since 5.3.3 */ private $recommend = array(); /** * The data from the CSV file * * @var string * @since 5.3.3 */ private $data = ''; /** * Text enclosure found * * @var string * @since 5.3.3 */ private $textEnclosure = '"'; /** * Field delimiter found * * @var string * @since 5.3.3 */ private $fieldDelimiter = null; /** * The fields found in the CSV file * * @var array * @since 5.3.3 */ private $fields = array(); /** * The CSV data * * @var array * @since 5.3.3 */ private $csvdata = array(); /** * The XML record to process * * @var string * @since 6.0 */ private $recordname = array(); /** * Analyze the uploaded file. * * @return object List of analyzer results. * * @since 5.3.3 */ public function analyze() { // Prepare if ($this->prepare()) { // Check the type of file to analyze $extension = JFile::getExt($this->realname); switch ($extension) { case 'xml': $this->analyzeXml(); $this->fields = $this->csvdata[0]; break; default: $this->analyzeCsv(); break; } } // Combine the data for showing $items = new stdClass; $items->csverrors = $this->csverrors; $items->messages = $this->messages; $items->fields = $this->fields; $items->csvdata = $this->csvdata; $items->recommend = $this->recommend; return $items; } /** * Prepare the file for analyzes. * * @return bool True if file can be analyzed | False if file cannot be analyzed. * * @since 6.0 */ private function prepare() { $jinput = JFactory::getApplication()->input; $filename = $jinput->files->get('filename'); // Assign the local values if ($filename['error'] > 0) { $this->csverrors[] = JText::_('COM_CSVI_ANALYZER_NO_FILE'); return false; } $this->filename = $filename['tmp_name']; $this->realname = $filename['name']; $this->columnheader = $jinput->get('columnheader', false, 'bool'); $this->lines = $jinput->get('lines', 3, 'int'); $this->recordname = $jinput->get('recordname'); return true; } /** * Analyze a CSV file. * * @return void. * * @since 6.0 */ private function analyzeCsv() { // Read the file $handle = fopen($this->filename, "r"); if ($handle) { // Get the first line $this->data = fread($handle, 4096); // Check for Mac line-ending if ($this->checkMac()) { // Reload the file fclose($handle); $handle = fopen($this->filename, "r"); $this->data = fread($handle, 4096); } // Check for BOM $this->checkBom(); // Find delimiters $this->findDelimiters(); // Find fields $this->findFields($handle); // Find data for ($i = 0; $i < $this->lines; $i++) { $this->findData($handle); } fclose($handle); } } /** * Check if the file has Mac line-endings. * * @return bool True if it has | False if it doesn't. * * @since 6.0 */ private function checkMac() { $matches = array(); // Check Windows first $total = preg_match('/\r\n/', $this->data, $matches); if (!$total) { preg_match('/\r/', $this->data, $matches); if (!empty($matches)) { $this->csverrors['MACLINE'] = JText::_('COM_CSVI_ANALYZER_MAC_LINE'); $this->recommend[] = JText::_('COM_CSVI_ANALYZER_MAC_LINE_RECOMMEND'); // Set auto detect to handle the rest of the file ini_set('auto_detect_line_endings', true); return true; } } return false; } /** * Check if the file has a Byte Order Mark. * * @return void. * * @since 6.0 */ private function checkBom() { if (strlen($this->data) > 3) { if (ord($this->data{0}) == 239 && ord($this->data{1}) == 187 && ord($this->data{2}) == 191) { $this->csverrors['BOM'] = JText::_('COM_CSVI_ANALYZER_BOM_FOUND'); $this->bom = true; $this->data = substr($this->data, 3, strlen($this->data)); } } } /** * Find the delimiters used. * * @return void. * * @since 6.0 */ private function findDelimiters() { // 1. Is the user using text enclosures $first_char = substr($this->data, 0, 1); $pattern = '/[a-zA-Z0-9_ ]/'; $matches = array(); preg_match($pattern, $first_char, $matches); if (count($matches) == 0) { // User is using text delimiter $this->textEnclosure = $first_char; $this->messages[] = JText::sprintf('COM_CSVI_ANALYZER_TEXT_ENCLOSURE', $first_char); // 2. What field delimiter is being used $match_next_char = strpos($this->data, $this->textEnclosure, 1); $second_char = substr($this->data, $match_next_char + 1, 1); if ($first_char == $second_char) { $this->csverrors['NOFIELD'] = JText::_('COM_CSVI_ANALYZER_FIELD_DELIMITER_NOT_FOUND'); } else { $this->fieldDelimiter = $second_char; $this->messages[] = JText::sprintf('COM_CSVI_ANALYZER_FIELD_DELIMITER', $second_char); } } else { // Check for tabs $tabs = preg_match('/\t/', $this->data, $matches); if ($tabs) { $this->fieldDelimiter = "\t"; $this->messages[] = JText::sprintf('COM_CSVI_ANALYZER_FIELD_DELIMITER', JText::_('COM_CSVI_ANALYZER_TAB')); } else { $totalchars = strlen($this->data); // 2. What field delimiter is being used for ($i = 0;$i <= $totalchars; $i++) { $current_char = substr($this->data, $i, 1); preg_match($pattern, $current_char, $matches); if (count($matches) == 0) { $this->fieldDelimiter = $current_char; $this->messages[] = JText::sprintf('COM_CSVI_ANALYZER_FIELD_DELIMITER', $current_char); $i = $totalchars; } } } if (is_null($this->fieldDelimiter)) { $this->csverrors['NOFIELD'] = JText::_('COM_CSVI_ANALYZER_FIELD_DELIMITER_NOT_FOUND'); } } } /** * Find the fields used in the CSV file. * * @param resource $handle The file handle. * * @return void. * * @since 6.0 */ private function findFields($handle) { rewind($handle); $data = fgetcsv($handle, 1000, $this->fieldDelimiter, $this->textEnclosure); if ($this->columnheader) { if ($data !== false) { if ($this->bom) { $data[0] = substr($data[0], 3, strlen($data[0])); } $this->fields = $data; // Check the fields for any _id fields foreach ($this->fields as $field) { if (substr($field, -3) == '_id') { $this->recommend[] = JText::sprintf('COM_CSVI_ANALYZER_FIELD_RECOMMEND', $field); } } } else { $this->csverrors['NOREAD'] = JText::_('COM_CSVI_ANALYZER_NO_READ'); } } } /** * Read the data from the CSV file. * * @param resource $handle The file handle. * * @return void. * * @since 6.0 */ private function findData($handle) { $data = fgetcsv($handle, 4096, $this->fieldDelimiter, $this->textEnclosure); if ($data !== false) { if ($this->columnheader) { if (count($this->fields) > count($data)) { $this->csverrors['NODATA'] = JText::_('COM_CSVI_ANALYZER_MORE_FIELDS'); $this->recommend[] = JText::_('COM_CSVI_ANALYZER_MORE_FIELDS_RECOMMEND'); } elseif (count($this->fields) < count($data)) { $this->csverrors['NODATA'] = JText::_('COM_CSVI_ANALYZER_LESS_FIELDS'); $this->recommend[] = JText::_('COM_CSVI_ANALYZER_LESS_FIELDS_RECOMMEND'); } } $this->csvdata[] = $data; } else { if (!feof($handle)) { $this->csverrors['NOREAD'] = JText::_('COM_CSVI_ANALYZER_NO_READ'); } } } /** * Analyze an XML file. * * @return void. * * @since 6.0 */ private function analyzeXml() { if ($this->recordname) { // Use a streaming approach to support large files $this->data = new XMLReader; $handle = $this->data->open($this->filename); $row = 1; if ($handle) { $parent = array(); $header = array(); $record = array(); // Start reading the XML file while ($this->data->read()) { // Only read the chosen records if ($this->data->nodeType == XMLREADER::ELEMENT && $this->data->name == $this->recordname) { // Check for attributes on the opening node if ($this->data->hasAttributes) { // Get the attributes while ($this->data->moveToNextAttribute()) { // The attribute name if (empty($parent)) { $field_name = $this->data->name; } else { $field_name = implode('/', $parent) . '/' . $this->data->name; } // The attribute value $field_value = $this->data->value; $header[] = $field_name; $record[] = $field_value; } } // Start reading the record while ($this->data->read()) { switch ($this->data->nodeType) { case (XMLREADER::ELEMENT): // Check if it has attributes if ($this->data->hasAttributes) { $clearParent = false; if ($this->data->isEmptyElement) { $clearParent = true; } $parent[] = $this->data->name; // Get the attributes while ($this->data->moveToNextAttribute()) { // The attribute name if (empty($parent)) { $field_name = $this->data->name; } else { $field_name = implode('/', $parent) . '/' . $this->data->name; } // The attribute value $field_value = $this->data->value; $header[] = $field_name; $record[] = $field_value; } if ($clearParent) { array_pop($parent); } } else { if (!$this->data->isEmptyElement) { $parent[] = $this->data->name; } } break; case (XMLREADER::END_ELEMENT) : array_pop($parent); if ($this->data->name == $this->recordname) { if ($record) { if ($row == 1) { $this->csvdata[] = $header; } $this->csvdata[] = $record; $record = array(); } // Check the number of rows if ($this->lines == $row) { return; } $row++; } break; case XMLReader::TEXT: case XMLReader::CDATA: // The field name if (empty($parent)) { $field_name = $this->data->name; } else { $field_name = implode('/', $parent); } // The field value $field_value = $this->data->value; // Add it to the data array $header[] = $field_name; $record[] = $field_value; break; } } } } } } } }