(http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/08/logo_qscope_b NULL.png)Ceci est une nouvelle version de la bibliothèque PHP que j’avais précédemment publié (http://xv4y NULL.radioclub NULL.asia/2013/10/15/bibliotheque-php-de-traitement-de-fichiers-logs-adif-v2/). Elle accepte maintenant conforme à la norme ADIF v3 et accepte de manière transparente les fichiers au format traditionnels ADI ou au nouveau format ADX (XML). C’est la librairie que j’utilise pour mon site d’analyse de log en ligne QScope.org.
Ce code ne gagnerait pas un concours de beauté, mais il fonctionne. J’avoue que les tests avec le format XML ont été limités à l’exemple donné avec la norme ADIF v3, car je n’ai pas de logiciel capable de générer de tels fichiers. Aucune comparaison de performance n’a été faite entre les deux formats, mais je soupçonne que le format traditionnel est un peu plus rapide à importer, même si la limite viendra plus rapidement de la base de données que du parsing.
<?php /* === ADIF v3 Parser library v2.00 (2015-03-10) === This Library his based on work by Jason Harris KJ4IWX but has been simplified and improved for better ADIF compatiblity by Yannick DEVOS XV4Y Version 2.00 introduces transparent support for ADX (XML) file format coming with ADIF v3 specifications Copyright 2011-2013 Jason Harris KJ4IWX (Apache v2.00 License) Copyright 2015 Yannick DEVOS XV4Y (GNU GPL v3.00 License) Any commercial use is subject to authorization from the respective authors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. --- This PHP library is designed to work with the Jelix 1.5 PHP Framework and PHP 5.4. However, it can simply be called by any PHP program. Usage for ADI and ADX files (with Jelix): $ADIFParser = jClasses::createInstance('yourmodule~ADIFParser'); $ADIFParser->initialize($complete_path_to_the_file); echo ($ADIFParser->get_header('adif_ver')); // Will display the ADIF version $all_headers_array = $ADIFParser->get_header(); // Will return the whole headers in an array while(($record = $ADIFParser->get_record())!=-1) { // Check for end of file if ($record!=false) { // If line is empty we skip if(count($record) == 0) { break; }; echo ($record['call']); echo ($record['qso_date']); echo ($record['mode']); // Do whatever you like with the ADIF fields... }; }; Fore more infos find contacts at: http://xv4y.radioclub.asia/ http://www.qscope.org/ */ class ADIFParser { var $is_adx = false; // default to ADI file (traditionnal format) var $data; // the adif data var $i; // the iterator var $headers = array(); public function initialize($file) //this function parses the header { // We read the first line and check if it is XML (ADX) or not $this->file_handler = fopen($file,'r'); $firstline = fgets($this->file_handler); if (stripos($firstline, "<?xml")!==false) $this->is_adx = true; fclose($this->file_handler); if (!$this->is_adx) { // This is an old fashion ADI file format $eoh=$eof=false; $this->data=''; // And we start from the begining $this->file_handler = fopen($file,'r'); while (!$eoh && !$eof) { // We will try to locate the <EOH> tag $newdata = fgets($this->file_handler); // $this->file_handler contains a handler in the case of ADI files if (!$newdata) { $eof = true; } else { if (stripos($newdata, "<eoh>")===false) { $this->data .= $newdata; } else { $eoh = true; } }; } if($eoh == false) //did we find the end of headers? { // If this ADIF file has no header (like FT5ZM), we need to re-open the file because we already went to the end fclose($this->file_handler); $this->file_handler = fopen($file,'r'); return 0; }; //get headers $this->i = 0; $in_tag = false; $tag = ""; $value_length = ""; $value = ""; $pos = strlen($this->data)-1; while($this->i < $pos) { //skip comments if($this->data[$this->i] == "#") { while($this->i < $pos) { if($this->data[$this->i] == "\n") { break; } $this->i++; } }else{ //find the beginning of a tag if($this->data[$this->i] == "<") { $this->i++; //record the key while($this->data[$this->i] < $pos && $this->data[$this->i] != ':') { $tag = $tag.$this->data[$this->i]; $this->i++; } $this->i++; //iterate past the : //find out how long the value is while($this->data[$this->i] < $pos && $this->data[$this->i] != '>') { $value_length = $value_length.$this->data[$this->i]; $this->i++; } $this->i++; //iterate past the > $len = (int)$value_length; //copy the value into the buffer while($len > 0 && $this->i < $pos) { $value = $value.$this->data[$this->i]; $len--; $this->i++; }; $this->headers[strtolower(trim($tag))] = $value; //convert it to lowercase and trim it in case of \r //clear all of our variables $tag = ""; $value_length = ""; $value = ""; } } $this->i++; }; return 1; } else { // This is the new ADX (XML) file format $this->is_adx = true; $this->xml_reader = new XMLReader; $this->xml_reader->open($file); // In this case, $file contains a file path if (!$this->xml_reader) return -1; // Not able to open the file while ($this->xml_reader->read() && $this->xml_reader->name != 'HEADER'); // Looking for the header if ($this->xml_reader->name == 'HEADER') { // Load the current xml element into simplexml $xml = simplexml_load_string($this->xml_reader->readOuterXML()); $this->headers = array_change_key_case(json_decode(json_encode($xml),TRUE),CASE_LOWER); } else { return 0; // No header, this should mean invalid file for ADX } while ($this->xml_reader->read() && $this->xml_reader->name != 'RECORD'); // Now we go to the first RECORD if ($this->xml_reader->name != 'RECORD') { $this->xml_reader->close(); return -2; // This is an empty or invalid ADX file } return 1; // All is normal } } //the following function does the processing of the array into its key and value pairs public function record_to_array(&$record) { $return = array(); for($a = 0; $a < strlen($record); $a++) { if($record[$a] == '<') //find the start of the tag { $tag_name = ""; $value = ""; $len_str = ""; $len = 0; $a++; //go past the < while($record[$a] != ':') //get the tag { $tag_name = $tag_name.$record[$a]; //append this char to the tag name $a++; }; $a++; //iterate past the colon while($record[$a] != '>' && $record[$a] != ':') { $len_str = $len_str.$record[$a]; $a++; }; if($record[$a] == ':') { while($record[$a] != '>') { $a++; }; }; $len = (int)$len_str; while($len > 0) { $a++; $value = $value.$record[$a]; $len--; }; $return[strtolower($tag_name)] = $value; }; //skip comments if($record[$a] == "#") { while($a < strlen($record)) { if($record[$a] == "\n") { break; } $a++; } } }; return $return; } //finds the next record in the file public function get_record() { if (!$this->is_adx) { $record =''; $out_condition = false; while (!$out_condition) { $newdata = fgets($this->file_handler); if ($newdata===false) { $out_condition = true; fclose($this->file_handler); return -1; // This is the end of file } else { $end = stripos($newdata , "<eor>"); if($end !== false) { //we got a full line $record .= substr($newdata, 0, $end); $out_condition = true; return $this->record_to_array($record); //process and return output } else { $record .= $newdata; // The line is not complete and we need to fetch a new string } } } } else { // Loop through the Records if ($this->xml_reader->name == 'RECORD') { // Load the current xml element into simplexml and we’re off and running! $xml = simplexml_load_string($this->xml_reader->readOuterXML()); $this->xml_reader->next('RECORD'); $array = array_change_key_case(json_decode(json_encode($xml),TRUE),CASE_LOWER); return $array; } else { $this->xml_reader->close(); return -1; } } } public function get_header($key='') // Changed to return the whole array if no key provided { if(array_key_exists(strtolower($key), $this->headers)) { return $this->headers[strtolower($key)]; } else if (empty($key)) { return $this->headers; } else { return NULL; } } } ?>