Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
Intensity
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
5 / 5
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fetch
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
4
 fetchFromLocalPath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 fetchFromUrl
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2namespace Shakemaps\Webservice;
3
4use ArrayIterator;
5use IteratorAggregate;
6use Traversable;
7
8use Fdsn\DataStructure\LatLon as DS_LatLon;
9
10/**
11 * Fetch grid.xml intensity file from Shakemaps portal 
12 * 
13 * @param string $eventId Id quake to scan for data (not in FDSN format to support shakemapseu portal idevent format)
14 * @param string $shakemapsServer (nullable) Server FQDN to connect to (default is shakemaps.rm.ingv.it)
15 * @param string $localFileFullPath (nullable) path to fetch local file  (if exists AND is readable)
16 */
17class Intensity implements IteratorAggregate {
18    private const dataFile = 'grid.xml';
19
20    private string $server;
21    private string $eventId;
22    
23    private ?string $localFileFullPath = null;
24
25    private string $curlErrInfo;
26    private int $curlErrNum;
27    private array $places = array();
28
29    function __construct ( string $eventId, ?string $shakemapsServer = Settings::defaultShakemapsServer, ?string $localFileFullPath = null ) {
30
31        $this->eventId = $eventId;
32        $this->server = empty($shakemapsServer) ? Settings::defaultShakemapsServer : $shakemapsServer;
33
34        if ( is_null($localFileFullPath) )
35            return;
36        
37                $this->localFileFullPath = $localFileFullPath;
38    }
39
40        /**
41         * get all places intensity
42         * 
43         * @return array locality intensity (array of associative arrays[DS_LatLon, mmi, pga, pgv, psa03, psa10, psa30, svel])
44         */
45        public function getIterator():Traversable{ return new ArrayIterator($this->places); }
46 
47        /**
48         * Fetch data (remote or local - if $localFileFullPath is set in __construct)
49         * 
50         * @return int number of data found
51         * 
52         * @internal DOMDocument::load(): <grid_data> contains a HUGE CSV text and xmlSAX2Characters crash
53         *         so i must parse it like an array
54         */
55    public function fetch():int{
56        $xmlString = is_null($this->localFileFullPath) ? $this->fetchFromUrl() : $this->fetchFromLocalPath();
57
58        $xmlAsArray = preg_split("/\n/", $xmlString);
59        foreach($xmlAsArray as $line){
60            if( ! preg_match('/^[0-9]/', $line) ) 
61                continue;
62
63            list($lon, $lat, $mmi, $pga, $pgv, $psa03, $psa10, $psa30, $svel) = preg_split('[\s]', trim($line) );
64            $this->places[] = array(
65                'point' => new DS_LatLon($lat, $lon),
66                'mmi' => $mmi, 
67                'pga' => $pga, 
68                'pgv' => $pgv, 
69                'psa03' => $psa03, 
70                'psa10' => $psa10, 
71                'psa30' => $psa30, 
72                'svel' => $svel
73            );
74        }
75
76        return count($this->places);
77    }
78
79
80        /**
81         * fetch data from local path - if $localFileFullPath is set in __construct()
82         * 
83         * @return string Datafile read in a string or, on missing/unreadable file a RuntimeException is thrown
84         */
85    function fetchFromLocalPath():string { 
86                if ( ! file_exists($this->localFileFullPath) || ! is_readable($this->localFileFullPath) )
87                        throw new \RuntimeException(sprintf("[%s] file %s not exists or is not readable", __METHOD__, $this->localFileFullPath));
88
89        return file_get_contents( $this->localFileFullPath); 
90    }
91
92        /**
93         * fetch data from url  (remote or local - if $localFileFullPath is set in __construct)
94         * 
95         * @return int number of data found
96         */
97    private function fetchFromUrl():string{
98        $curlSession = curl_init();
99        curl_setopt_array($curlSession, array(
100            CURLOPT_URL             => sprintf(Settings::basePath, 
101                $this->server, $this->eventId, self::dataFile),
102            CURLOPT_HEADER          => false,
103            CURLOPT_CUSTOMREQUEST   => 'GET',
104            CURLOPT_RETURNTRANSFER  => 1,
105            CURLOPT_TIMEOUT         => 60
106            )
107        );
108
109        $response = curl_exec($curlSession);
110        $this->curlErrNum = curl_errno($curlSession);
111        $this->curlErrInfo = curl_error($curlSession);
112        curl_close($curlSession);
113
114        if(CURLE_OK != $this->curlErrNum)
115            throw new \RuntimeException( sprintf("[%s] [CurlErr: %d] %s", __METHOD__, $this->curlErrNum, $this->curlErrInfo));
116
117        return $response;
118    }
119}
120?>