Send wind even if it hasn't changed
[dweather.git] / yr.php
1 <?php\r
2 /*\r
3  yr.php  -  YR.no forecast on YOUR page!\r
4  \r
5  This script was downloaded from http://www.yr.no/verdata/1.5542682\r
6  Please read the tips on that page on how you would/should use this script\r
7 \r
8  You need a webserver with PHP version 5 or later to run this script.\r
9  A lot of comments are in Norwegian only. We will be translating to english whenever we have the opportunity.\r
10  For feedback / bug repports / feature requests, please contact:  Lennart André Rolland <lennart.andre.rolland@nrk.no>\r
11 \r
12  ###### Changelog\r
13 \r
14  Versjon: 2.6 - Lennart André Rolland (lennart.andre.rolland@nrk.no) / NRK - 2008.11.11 11:48\r
15  * Added option to remove banner ($yr_use_banner)\r
16  * Added option to allow any target for yr.no urls ($yr_link_target)\r
17 \r
18  Versjon: 2.5 - Lennart André Rolland (lennart.andre.rolland@nrk.no) / NRK - 2008.09.25 09:24\r
19  * Cache will now update on parameter changes (cache file is prefixed with md5 digest of all relevant parameters)\r
20    This change will in the future make it easier to use the script for multiple locations in one go.   \r
21  * Most relevant comments translated to english\r
22 \r
23  Versjon 2.4 - Sven-Ove Bjerkan (sven-ove@smart-media.no) / Smart-Media AS - 2008.10.22 12:14\r
24  * Endret funksjonalitet ifbm med visning av PHP-feil (fjernet blant annet alle "@", dette styres av error_reporting())\r
25  * Ved feilmelding så ble denne lagret i lokal cache slik at man fikk opp feilmld hver gang inntil "$yr_maxage" inntreffer og den forsøker å laste på nytt - den cacher nå ikke hvis det oppstår en feil\r
26  * $yr_use_text, $yr_use_links og $yr_use_table ble overstyrt til "true" uavhengig av brukerens innstilling - rettet!\r
27 \r
28  Versjon: 2.3 - Lennart André Rolland (lennart.andre.rolland@nrk.no) / NRK - 2008.09.25 09:24\r
29  * File permissions updated\r
30  * Caching is stored in HTML isntead of XML for security\r
31  * Other security and efficiency improvements\r
32 \r
33 \r
34 \r
35  ###### INSTRUCTIONS:\r
36 \r
37  1. Only edit this script in editors with ISO-8859-1 or ISO-8859-15 character set.\r
38  2. Edit the settings below\r
39  3. Transfer the script to a folder in your webroot.\r
40  4. Make sure that the webserver has write access to the folder where thsi script is placed. It will create a folder called yr-cache and place cached HTML data in that directory.\r
41 \r
42  */\r
43 \r
44 ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  /\r
45 ///  ///  ///  ///  ///  Settings  ///  ///  ///  ///  ///  ///  ///  ///  //\r
46 //  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///\r
47 \r
48 // 1. Lenke: Lenke til stedet på yr.no (Uten siste skråstrek. Bruk vanlig æøå i lenka )\r
49 //    Link: Link to the url for the location on yr.no (Without the last Slash.)\r
50 $yr_url='http://www.yr.no/sted/Norge/Vest-Agder/Lyngdal/Kvås';\r
51 $yr_url='http://www.yr.no/stad/Sverige/Jämtland/Lofsdalen';\r
52 \r
53 // 2. Stedsnavnet: Skriv inn navnet på stedet. La stå tom for å falle tilbake til navnet i lenken\r
54 //    Location: The name of the location. Leave empty to fallback to the location in the url.\r
55 $yr_name='';\r
56 \r
57 // 3. Bruk header og footer: Velg om du vil ha med header og/eller  footer\r
58 //    Use Header and footers: Select to have HTML headers/footers wrapping the content (useful for debugging)\r
59 //PS: Header for HTML dokumentet er XHTML 1.0 Strict\r
60 //    Skrus som regel av når du inlemmer i eksisterende dokument!\r
61 //\r
62 $yr_use_header=$yr_use_footer=true;\r
63 \r
64 // 4. Deler: Velg delene av varselet du vil ta med!\r
65 //    Parts: Choose which parts of the forecast to include\r
66 $yr_use_banner=true; //yr.no Banner\r
67 $yr_use_text=false;   //Tekstvarsel\r
68 $yr_use_links=true;  //Lenker til varsel på yr.no\r
69 $yr_use_table=true;  //Tabellen med varselet\r
70 \r
71 // 5. Mellomlagringstid: Antall sekunder før nytt varsel hentes fra yr.no.\r
72 //    Cachetime: Number of seconds to keep forecast in local cache\r
73 //    Den anbefalt verdien på 1200 vil oppdatere siden hver 20. minutt.\r
74 //\r
75 //    PS: Vi ønsker at du setter 20 minutters mellomlagringstid fordi\r
76 //    det vil gi høyere ytelse, både for yr.no og deg! MEN for å få til dette\r
77 //    vil vi opprette en mappe og lagre en fil i denne mappen. Vi har gått\r
78 //    gjennom scriptet veldig nøye for å forsikre oss om at det er feilfritt.\r
79 //    Likevel er dette ikke helt uproblematisk i forhold til sikkerhet.\r
80 //    Hvis du har problemer med dette kan du sette $yr_maxage til 0 for å skru\r
81 //    av mellomlagringen helt!\r
82 $yr_maxage=1200;\r
83 \r
84 // 6. Utløpstid: Denne instillingen lar deg velge hvor lenge yr.no har på å\r
85 //    levere varselet i sekunder.\r
86 //    Timeout: How long before this script gives up fetching data from yr.no\r
87 //\r
88 //    Hvis yr.no skulle være nede eller det er\r
89 //    forstyrrelser i båndbredden ellers, vil varselet erstattes med en\r
90 //    feilmelding til situasjonen er bedret igjen. PS: gjelder kun når nytt\r
91 //    varsel hentes! Påvirker ikke varsel mens siden viser varsel fra\r
92 //    mellomlageret. Den anbefalte verdien på 10 sekunder fungerer bra.\r
93 $yr_timeout=10;\r
94 \r
95 // 7. Mellomlagrinsmappe: Velg navn på mappen til mellomlagret data.\r
96 //    Cachefolder: Where to put cache data\r
97 //\r
98 //Dette scriptet vil forsøke å opprette mappen om den ikke finnes.\r
99 $yr_datadir='yr_cache';\r
100 \r
101 \r
102 // 8. Lenke mål: Velg hvilken target som skal brukes på lenker til yr.no\r
103 //    Link target: Choose which target to use for links to yr.no\r
104 $yr_link_target='_top';\r
105 \r
106 // 9. Vis feilmeldinger: Sett til "true" hvis du vil ha feilmeldinger.\r
107 //    Show errors: Useful while debugging.\r
108 //\r
109 //greit ved feilsøking, men bør ikke være aktivert i drift.\r
110 $yr_vis_php_feilmeldinger=true;\r
111 \r
112 \r
113 \r
114 \r
115 \r
116 \r
117 \r
118 \r
119 \r
120 \r
121 \r
122 \r
123 \r
124 \r
125 \r
126 ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  /\r
127 ///  ///  ///  ///  ///  Code ///  ///  ///  ///  ///  ///  ///  ///  ///  //\r
128 //  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///\r
129 // Skru på feilmeldinger i starten\r
130 if($yr_vis_php_feilmeldinger) {\r
131         error_reporting(E_ALL);\r
132         ini_set('display_errors', true);\r
133 }\r
134 else {\r
135         error_reporting(0);\r
136         ini_set('display_errors', false);\r
137 }\r
138 \r
139 //Opprett en komunikasjon med yr\r
140 $yr_xmlparse = &new YRComms();\r
141 //Opprett en presentasjon\r
142 $yr_xmldisplay = &new YRDisplay();\r
143 \r
144 $yr_try_curl=true;\r
145 \r
146 //Gjenomfør oppdraget basta bom.\r
147 die($yr_xmldisplay->generateHTMLCached($yr_url, $yr_name, $yr_xmlparse, $yr_url, $yr_try_curl, $yr_use_header, $yr_use_footer, $yr_use_banner, $yr_use_text, $yr_use_links, $yr_use_table, $yr_maxage, $yr_timeout, $yr_link_target));\r
148 \r
149 \r
150 ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  /\r
151 ///  ///  ///  ///  ///  Hjelpekode starter her   ///  ///  ///  ///  ///  //\r
152 //  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///  ///\r
153 \r
154 \r
155 function retar($array, $html = false, $level = 0) {\r
156         if(is_array($array)){\r
157                 $space = $html ? "&nbsp;" : " ";\r
158                 $newline = $html ? "<br />" : "\n";\r
159                 $spaces='';\r
160                 for ($i = 1; $i <= 3; $i++)$spaces .= $space;\r
161                 $tabs=$spaces;\r
162                 for ($i = 1; $i <= $level; $i++)$tabs .= $spaces;\r
163                 $output = "Array(" . $newline . $newline;\r
164                 $cnt=sizeof($array);\r
165                 $j=0;\r
166                 foreach($array as $key => $value) {\r
167                         $j++;\r
168                         if (is_array($value)) {\r
169                                 $level++;\r
170                                 $value = retar($value, $html, $level);\r
171                                 $level--;\r
172                         }\r
173                         else $value="'$value'";\r
174                         $output .=  "$tabs'$key'=> $value";\r
175                         if($j<$cnt)$output .=  ',';\r
176                         $output .=  $newline;\r
177                 }\r
178                 $output.=$tabs.')'.$newline;\r
179         }\r
180         else{\r
181                 $output="'$array'";\r
182         }\r
183         return $output;\r
184 }\r
185 \r
186 \r
187 // Klasse for lesing og tilrettelegging av YR data\r
188 class YRComms{\r
189 \r
190         //Generer gyldig yr.no array med værdata byttet ut med en enkel feilmelding\r
191         private function getYrDataErrorMessage($msg="Feil"){\r
192                 return Array(\r
193       '0'=> Array('tag'=> 'WEATHERDATA','type'=> 'open','level'=> '1'),\r
194       '1'=> Array('tag'=> 'LOCATION','type'=> 'open','level'=> '2'),\r
195       '2'=> Array('tag'=> 'NAME','type'=> 'complete','level'=> '3','value'=> $msg),\r
196       '3'=> Array('tag'=> 'LOCATION','type'=> 'complete','level'=> '3'),\r
197       '4'=> Array( 'tag'=> 'LOCATION', 'type'=> 'close', 'level'=> '2'),\r
198       '5'=> Array( 'tag'=> 'FORECAST', 'type'=> 'open', 'level'=> '2'),\r
199       '6'=> Array( 'tag'=> 'ERROR', 'type'=> 'complete', 'level'=> '3', 'value'=> $msg),\r
200       '7'=> Array( 'tag'=> 'FORECAST', 'type'=> 'close', 'level'=> '2'),\r
201       '8'=> Array( 'tag'=> 'WEATHERDATA', 'type'=> 'close', 'level'=> '1')\r
202                 );\r
203         }\r
204 \r
205         //Generer gyldig yr.no XML med værdata byttet ut med en enkel feilmelding\r
206         private function getYrXMLErrorMessage($msg="Feil"){\r
207                 $msg=$this->getXMLEntities($msg);\r
208                 //die('errmsg:'.$msg);\r
209                 $data=<<<EOT\r
210 <weatherdata>\r
211   <location />\r
212   <forecast>\r
213   <error>$msg</error>\r
214     <text>\r
215       <location />\r
216     </text>\r
217   </forecast>\r
218 </weatherdata>\r
219 \r
220 EOT\r
221                 ;\r
222                 //die($data);\r
223                 return $data;\r
224         }\r
225         \r
226         // Sørger for å laste ned XML fra yr.no og leverer data tilbake i en streng\r
227         private function loadXMLData($xml_url,$try_curl=true,$timeout=10){\r
228                 global $yr_datadir;\r
229                 $xml_url.='/varsel.xml';\r
230                 // Lag en timeout på contexten\r
231                 $ctx = stream_context_create(array( 'http' => array('timeout' => $timeout)));\r
232 \r
233                 // Prøv å åpne direkte først\r
234                 //NOTE: This will spew ugly errors even when they are handled later. There is no way to avoid this but prefixing with @ (slow) or turning off error reporting\r
235                 $data=file_get_contents($xml_url,0,$ctx);\r
236 \r
237                 if(false!=$data){\r
238                         //Jippi vi klarte det med vanlig fopen url wrappers!\r
239                 }\r
240                 // Vanlig fopen_wrapper feilet, men vi har cURL tilgjengelig\r
241                 else if($try_curl && function_exists('curl_init')){\r
242                         $lokal_xml_url = $yr_datadir .'/curl.temp.xml';\r
243                         $data='';\r
244                         $ch = curl_init($xml_url);\r
245                         // Åpne den lokale temp filen for skrive tilgang (med cURL hooks enablet)\r
246                         $fp = fopen($lokal_xml_url, "w");\r
247                         // Last fra yr.no til lokal kopi med curl\r
248                         curl_setopt($ch, CURLOPT_FILE, $fp);\r
249                         curl_setopt($ch, CURLOPT_HEADER, 0);\r
250                         curl_setopt($ch, CURLOPT_POSTFIELDS, '');\r
251                         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);\r
252                         curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);\r
253                         curl_exec($ch);\r
254                         curl_close($ch);\r
255                         // Lukk lokal kopi\r
256                         fclose($fp);\r
257                         // Åpne lokal kopi igjen og les in alt innholdet\r
258                         $data=file_get_contents($lokal_xml_url,0,$ctx);\r
259                         //Slett temp data\r
260                         unlink($lokal_xml_url);\r
261                         // Sjekk for feil\r
262                         if(false==$data)$data=$this->getYrXMLErrorMessage('Det oppstod en feil mens værdata ble lest fra yr.no. Teknisk info: Mest antakelig: kobling feilet. Nest mest antakelig: Det mangler støtte for fopen wrapper, og cURL feilet også. Minst antakelig: cURL har ikke rettigheter til å lagre temp.xml');\r
263                 }\r
264                 // Vi har verken fopen_wrappers eller cURL\r
265                 else{\r
266                         $data=$this->getYrXMLErrorMessage('Det oppstod en feil mens værdata ble forsøkt lest fra yr.no. Teknisk info: Denne PHP-installasjon har verken URL enablede fopen_wrappers eller cURL. Dette gjør det umulig å hente ned værdata. Se imiddlertid følgende dokumentasjon: http://no.php.net/manual/en/wrappers.php, http://no.php.net/manual/en/book.curl.php');\r
267                         //die('<pre>LO:'.retar($data));\r
268                 }\r
269                 //die('<pre>XML for:'.$xml_url.' WAS: '.$data);\r
270                 // Når vi har kommet hit er det noe som tyder på at vi har lykkes med å laste værdata, ller i det minste lage en teilmelding som beskriver eventuelle problemer\r
271                 return $data;\r
272         }\r
273 \r
274         // Last XML til en array struktur\r
275         private function parseXMLIntoStruct($data){\r
276                 global $yr_datadir;\r
277                 $parser = xml_parser_create('ISO-8859-1');\r
278                 if((0==$parser)||(FALSE==$parser))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Teknisk info: Kunne ikke lage XML parseren.');\r
279                 $vals = array();\r
280                 //die('<pre>'.retar($data).'</pre>');\r
281                 if(FALSE==xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Teknisk info: Kunne ikke stille inn XML-parseren.');\r
282                 if(0==xml_parse_into_struct($parser, $data, $vals, $index))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Teknisk info: Parsing av XML feilet.');\r
283                 if(FALSE==xml_parser_free($parser))return $this->getYrDataErrorMessage('Det oppstod en feil mens værdata ble forsøkt hentet fra yr.no. Kunne ikke frigjøre XML-parseren.');\r
284                 //die('<pre>'.retar($vals).'</pre>');\r
285                 return $vals;\r
286         }\r
287 \r
288 \r
289         // Rense tekst data (av sikkerhetshensyn)\r
290         private function sanitizeString($in){\r
291                 //return $in;\r
292                 if(is_array($in))return $in;\r
293                 if(null==$in)return null;\r
294                 return htmlentities(strip_tags($in));\r
295         }\r
296 \r
297         // Rense tekst data (av sikkerhetshensyn)\r
298         public function reviveSafeTags($in){\r
299                 //$in=$in.'<strong>STRONG</strong> <u>UNDERLINE</u> <b>BOLD</b> <i>ITALICS</i>';\r
300                 return str_ireplace(array('&lt;strong&gt;','&lt;/strong&gt;','&lt;u&gt;','&lt;/u&gt;','&lt;b&gt;','&lt;/b&gt;','&lt;i&gt;','&lt;/i&gt;'),array('<strong>','</strong>','<u>','</u>','<b>','</b>','<i>','</i>'),$in);\r
301         }\r
302 \r
303 \r
304 \r
305         private function rearrangeChildren($vals, &$i) {\r
306                 $children = array(); // Contains node data\r
307                 // Sikkerhet: sørg for at all data som parses strippes for farlige ting\r
308                 if (isset($vals[$i]['value']))$children['VALUE'] = $this->sanitizeString($vals[$i]['value']);\r
309                 while (++$i < count($vals)){\r
310                         // Sikkerhet: sørg for at all data som parses strippes for farlige ting\r
311                         if(isset($vals[$i]['value']))$val=$this->sanitizeString($vals[$i]['value']);\r
312                         else unset($val);\r
313                         if(isset($vals[$i]['type']))$typ=$this->sanitizeString($vals[$i]['type']);\r
314                         else unset($typ);\r
315                         if(isset($vals[$i]['attributes']))$atr=$this->sanitizeString($vals[$i]['attributes']);\r
316                         else unset($atr);\r
317                         if(isset($vals[$i]['tag']))$tag=$this->sanitizeString($vals[$i]['tag']);\r
318                         else unset($tag);\r
319                         // Fyll inn strukturen vær slik vi vil ha den\r
320                         switch ($vals[$i]['type']){\r
321                                 case 'cdata': $children['VALUE']=(isset($children['VALUE']))?$val:$children['VALUE'].$val; break;\r
322                                 case 'complete':\r
323                                         if (isset($atr)) {\r
324                                                 $children[$tag][]['ATTRIBUTES'] = $atr;\r
325                                                 $index = count($children[$tag])-1;\r
326                                                 if (isset($val))$children[$tag][$index]['VALUE'] = $val;\r
327                                                 else $children[$tag][$index]['VALUE'] = '';\r
328                                         } else {\r
329                                                 if (isset($val))$children[$tag][]['VALUE'] = $val;\r
330                                                 else $children[$tag][]['VALUE'] = '';\r
331                                         }\r
332                                         break;\r
333                                 case 'open':\r
334                                         if (isset($atr)) {\r
335                                                 $children[$tag][]['ATTRIBUTES'] = $atr;\r
336                                                 $index = count($children[$tag])-1;\r
337                                                 $children[$tag][$index] = array_merge($children[$tag][$index],$this->rearrangeChildren($vals, $i));\r
338                                         } else $children[$tag][] = $this->rearrangeChildren($vals, $i);\r
339                                         break;\r
340                                 case 'close': return $children;\r
341                         }\r
342                 }\r
343         }\r
344         // Ommøbler data til å passe vårt formål, og returner\r
345         private function rearrangeDataStruct($vals){\r
346                 //die('<pre>'.$this->retar($vals).'<\pre>');\r
347                 $tree = array();\r
348                 $i = 0;\r
349                 if (isset($vals[$i]['attributes'])) {\r
350                         $tree[$vals[$i]['tag']][]['ATTRIBUTES']=$vals[$i]['attributes'];\r
351                         $index=count($tree[$vals[$i]['tag']])-1;\r
352                         $tree[$vals[$i]['tag']][$index]=array_merge($tree[$vals[$i]['tag']][$index], $this->rearrangeChildren($vals, $i));\r
353                 } else $tree[$vals[$i]['tag']][] = $this->rearrangeChildren($vals, $i);\r
354                 //die("<pre>".retar($tree));\r
355                 //Hent ut det vi bryr oss om\r
356                 if(isset($tree['WEATHERDATA'][0]['FORECAST'][0]))return $tree['WEATHERDATA'][0]['FORECAST'][0];\r
357                 else return YrComms::getYrDataErrorMessage('Det oppstod en feil ved behandling av data fra yr.no. Vennligst gjør administrator oppmerksom på dette! Teknisk: data har feil format.');\r
358         }\r
359 \r
360         // Hovedmetode. Laster XML fra en yr.no URI og parser denne\r
361         public function getXMLTree($xml_url, $try_curl, $timeout){\r
362                 // Last inn XML fil og parse til et array hierarcki, ommøbler data til å passe vårt formål, og returner\r
363                 return $this->rearrangeDataStruct($this->parseXMLIntoStruct($this->loadXMLData($xml_url,$try_curl,$timeout)));\r
364         }\r
365 \r
366         // Statisk hjelper for å parse ut tid i yr format\r
367         public function parseTime($yr_time, $do24_00=false){\r
368                 $yr_time=str_replace(":00:00", "", $yr_time);\r
369                 if($do24_00)$yr_time=str_replace("00", "24", $yr_time);\r
370                 return $yr_time;\r
371         }\r
372 \r
373         // Statisk hjelper for å besørge riktig encoding ved å oversette spesielle ISO-8859-1 karakterer til HTML/XHTML entiteter\r
374         public function convertEncodingEntities($yrraw){\r
375                 $conv=str_replace("æ", "&aelig;", $yrraw);\r
376                 $conv=str_replace("ø", "&oslash;", $conv);\r
377                 $conv=str_replace("å", "&aring;", $conv);\r
378                 $conv=str_replace("Æ", "&AElig;", $conv);\r
379                 $conv=str_replace("Ø", "&Oslash;", $conv);\r
380                 $conv=str_replace("Å", "&Aring;", $conv);\r
381                 return $conv;\r
382         }\r
383 \r
384         // Statisk hjelper for å besørge riktig encoding vedå oversette spesielle UTF karakterer til ISO-8859-1\r
385         public function convertEncodingUTF($yrraw){\r
386                 $conv=str_replace("æ", "æ", $yrraw);\r
387                 $conv=str_replace("ø", "ø", $conv);\r
388                 $conv=str_replace("Ã¥", "å", $conv);\r
389                 $conv=str_replace("Ã\86", "Æ", $conv);\r
390                 $conv=str_replace("Ã\98", "Ø", $conv);\r
391                 $conv=str_replace("Ã\85", "Å", $conv);\r
392                 return $conv;\r
393         }\r
394 \r
395 \r
396         public function getXMLEntities($string){\r
397                 return preg_replace('/[^\x09\x0A\x0D\x20-\x7F]/e', '$this->_privateXMLEntities("$0")', $string);\r
398         }\r
399 \r
400         private function _privateXMLEntities($num){\r
401                 $chars = array(\r
402                 128 => '&#8364;', 130 => '&#8218;',\r
403                 131 => '&#402;', 132 => '&#8222;',\r
404                 133 => '&#8230;', 134 => '&#8224;',\r
405                 135 => '&#8225;',136 => '&#710;',\r
406                 137 => '&#8240;',138 => '&#352;',\r
407                 139 => '&#8249;',140 => '&#338;',\r
408                 142 => '&#381;', 145 => '&#8216;',\r
409                 146 => '&#8217;',147 => '&#8220;',\r
410                 148 => '&#8221;',149 => '&#8226;',\r
411                 150 => '&#8211;',151 => '&#8212;',\r
412                 152 => '&#732;',153 => '&#8482;',\r
413                 154 => '&#353;',155 => '&#8250;',\r
414                 156 => '&#339;',158 => '&#382;',\r
415                 159 => '&#376;');\r
416                 $num = ord($num);\r
417                 return (($num > 127 && $num < 160) ? $chars[$num] : "&#".$num.";" );\r
418         }\r
419 }\r
420 \r
421 // Klasse for å vise data fra yr. Kompatibel med YRComms sin datastruktur\r
422 class YRDisplay{\r
423 \r
424         // Akkumulator variabl for å holde på generert HTML\r
425         var $ht='';\r
426         // Yr Url\r
427         var $yr_url='';\r
428         // Yr stedsnavn\r
429         var $yr_name='';\r
430         // Yr data\r
431         var $yr_data=Array();\r
432 \r
433         //Filename for cached HTML. MD5 hash will be prepended to allow caching of several pages\r
434         var $datafile='yr.html';\r
435         //The complete path to the cache file\r
436         var $datapath='';\r
437 \r
438         // Norsk grovinndeling av de 360 grader vindretning\r
439         var $yr_vindrettninger=array(\r
440     'nord','nord-nord&oslash;st','nord&oslash;st','&oslash;st-nord&oslash;st',\r
441     '&oslash;st','&oslash;st-s&oslash;r&oslash;st','s&oslash;r&oslash;st','s&oslash;r-s&oslash;r&oslash;st',\r
442     's&oslash;r','s&oslash;r-s&oslash;rvest', 's&oslash;rvest','vest-s&oslash;rvest',\r
443     'vest', 'vest-nordvest','nordvest', 'nord-nordvest', 'nord');\r
444 \r
445         // Hvor hentes bilder til symboler fra?\r
446         var $yr_imgpath='http://fil.nrk.no/yr/grafikk/sym/b38';\r
447 \r
448 \r
449         //Generer header for varselet\r
450         public function getHeader($use_full_html){\r
451                 // Her kan du endre header til hva du vil. NB! Husk å skru det på, ved å endre instillingene i toppen av dokumentet\r
452                 if($use_full_html){\r
453                         $this->ht.=<<<EOT\r
454 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
455 <html xmlns="http://www.w3.org/1999/xhtml">\r
456   <head>\r
457     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
458     <title>V&aelig;rvarsel fra yr.no</title>\r
459     <link href="http://www12.nrk.no/yr.no/yr-php.css" rel="stylesheet" type="text/css" />\r
460   </head>\r
461   <body>\r
462 \r
463 EOT\r
464                         ;\r
465                 }\r
466                 $this->ht.=<<<EOT\r
467     <div id="yr-varsel">\r
468 \r
469 EOT\r
470                 ;\r
471         }\r
472 \r
473         //Generer footer for varselet\r
474         public function getFooter($use_full_html){\r
475                 $this->ht.=<<<EOT\r
476     </div>\r
477 \r
478 EOT\r
479                 ;\r
480                 // Her kan du endre footer til hva du vil. NB! Husk å skru det på, ved å endre instillingene i toppen av dokumentet\r
481                 if($use_full_html){\r
482                         $this->ht.=<<<EOT\r
483   </body>\r
484 </html>\r
485 \r
486 EOT\r
487                         ;\r
488                 }\r
489         }\r
490 \r
491 \r
492    //Generer Copyright for data fra yr.no\r
493    public function getBanner($target='_top'){\r
494       $url=YRComms::convertEncodingEntities($this->yr_url);\r
495       $this->ht.=<<<EOT\r
496       <h1><a href="http://www.yr.no/" target="$target"><img src="http://fil.nrk.no/yr/grafikk/php-varsel/topp.png" alt="yr.no" title="yr.no er en tjeneste fra Meteorologisk institutt og NRK" /></a></h1>\r
497 \r
498 EOT\r
499       ;\r
500    }\r
501 \r
502 \r
503    //Generer Copyright for data fra yr.no\r
504    public function getCopyright($target='_top'){\r
505       $url=YRComms::convertEncodingEntities($this->yr_url);\r
506       /*\r
507        Du må ta med teksten nedenfor og ha med lenke til yr.no.\r
508        Om du fjerner denne teksten og lenkene, bryter du vilkårene for bruk av data fra yr.no.\r
509        Det er straffbart å bruke data fra yr.no i strid med vilkårene.\r
510        Du finner vilkårene på http://www.yr.no/verdata/1.3316805\r
511        */\r
512       $this->ht.=<<<EOT\r
513       <h2><a href="$url" target="$target">V&aelig;rvarsel for $this->yr_name</a></h2>\r
514       <p><a href="http://www.yr.no/" target="$target"><strong>V&aelig;rvarsel fra yr.no, levert av Meteorologisk institutt og NRK.</strong></a></p>\r
515 \r
516 EOT\r
517       ;\r
518    }\r
519 \r
520 \r
521    //Generer tekst for været\r
522         public function getWeatherText(){\r
523                 if((isset($this->yr_data['TEXT'])) && (isset($this->yr_data['TEXT'][0]['LOCATION']))&& (isset($this->yr_data['TEXT'][0]['LOCATION'][0]['ATTRIBUTES'])) ){\r
524                         $yr_place=$this->yr_data['TEXT'][0]['LOCATION'][0]['ATTRIBUTES']['NAME'];\r
525                         if(!isset($this->yr_data['TEXT'][0]['LOCATION'][0]['TIME']))return;\r
526                         foreach($this->yr_data['TEXT'][0]['LOCATION'][0]['TIME'] as $yr_var2){\r
527                                 // Små bokstaver\r
528                                 $l=(YRComms::convertEncodingUTF($yr_var2['TITLE'][0]['VALUE']));\r
529                                 // Rettet encoding\r
530                                 $e=YRComms::reviveSafeTags(YRComms::convertEncodingUTF($yr_var2['BODY'][0]['VALUE']));\r
531                                 // Spytt ut!\r
532                                 $this->ht.=<<<EOT\r
533       <p><strong>$yr_place $l</strong>:$e</p>\r
534 \r
535 EOT\r
536                                 ;\r
537                         }\r
538                 }\r
539         }\r
540 \r
541         //Generer lenker til andre varsel\r
542         public function getLinks($target='_top'){\r
543                 // Rens url\r
544                 $url=YRComms::convertEncodingEntities($this->yr_url);\r
545                 // Spytt ut\r
546                 $this->ht.=<<<EOT\r
547       <p class="yr-lenker">$this->yr_name p&aring; yr.no:\r
548         <a href="$url/" target="$target">Varsel med kart</a>\r
549         <a href="$url/time_for_time.html" target="$target">Time for time</a>\r
550         <a href="$url/helg.html" target="$target">Helg</a>\r
551         <a href="$url/langtidsvarsel.html" target="$target">Langtidsvarsel</a>\r
552       </p>\r
553 \r
554 EOT\r
555                 ;\r
556         }\r
557 \r
558         //Generer header for værdatatabellen\r
559         public function getWeatherTableHeader(){\r
560                 $name=$this->yr_name;\r
561                 $this->ht.=<<<EOT\r
562       <table summary="V&aelig;rvarsel for $name fra yr.no">\r
563         <thead>\r
564           <tr>\r
565             <th class="v" colspan="3"><strong>Varsel for $name</strong></th>\r
566             <th>Nedb&oslash;r</th>\r
567             <th>Temp.</th>\r
568             <th class="v">Vind</th>\r
569             <th>Vindstyrke</th>\r
570           </tr>\r
571         </thead>\r
572         <tbody>\r
573 \r
574 EOT\r
575                 ;\r
576         }\r
577 \r
578 \r
579         //Generer innholdet i værdatatabellen\r
580         public function getWeatherTableContent(){\r
581                 $thisdate='';\r
582                 $dayctr=0;\r
583                 if(!isset($this->yr_data['TABULAR'][0]['TIME']))return;\r
584                 $a=$this->yr_data['TABULAR'][0]['TIME'];\r
585 \r
586                 foreach($a as $yr_var3){\r
587                         list($fromdate, $fromtime)=explode('T', $yr_var3['ATTRIBUTES']['FROM']);\r
588                         list($todate, $totime)=explode('T', $yr_var3['ATTRIBUTES']['TO']);\r
589                         $fromtime=YRComms::parseTime($fromtime);\r
590                         $totime=YRComms::parseTime($totime, 1);\r
591                         if($fromdate!=$thisdate){\r
592                                 $divider=<<<EOT\r
593           <tr>\r
594             <td colspan="7" class="skilje"></td>\r
595           </tr>\r
596 \r
597 EOT\r
598                                 ;\r
599                                 list($thisyear, $thismonth, $thisdate)=explode('-', $fromdate);\r
600                                 $displaydate=$thisdate.".".$thismonth.".".$thisyear;\r
601                                 $firstcellcont=$displaydate;\r
602                                 $thisdate=$fromdate;\r
603                                 ++$dayctr;\r
604                         }else $divider=$firstcellcont='';\r
605 \r
606                         // Vis ny dato\r
607                         if($dayctr<7){\r
608                                 $this->ht.=$divider;\r
609                                 // Behandle symbol\r
610                                 $imgno=$yr_var3['SYMBOL'][0]['ATTRIBUTES']['NUMBER'];\r
611                                 if($imgno<10)$imgno='0'.$imgno;\r
612                                 switch($imgno){\r
613                                         case '01': case '02': case '03': case '05': case '06': case '07': case '08':\r
614                                                 $imgno.="d"; $do_daynight=1; break;\r
615                                         default: $do_daynight=0;\r
616                                 }\r
617                                 // Behandle regn\r
618                                 $rain=$yr_var3['PRECIPITATION'][0]['ATTRIBUTES']['VALUE'];\r
619                                 if($rain==0.0)$rain="0";\r
620                                 else{\r
621                                         $rain=intval($rain);\r
622                                         if($rain<1)$rain='&lt;1';\r
623                                         else $rain=round($rain);\r
624                                 }\r
625                                 $rain.=" mm";\r
626                                 // Behandle vind\r
627                                 $winddir=round($yr_var3['WINDDIRECTION'][0]['ATTRIBUTES']['DEG']/22.5);\r
628                                 $winddirtext=$this->yr_vindrettninger[$winddir];\r
629                                 // Behandle temperatur\r
630                                 $temper=round($yr_var3['TEMPERATURE'][0]['ATTRIBUTES']['VALUE']);\r
631                                 if($temper>=0)$tempclass='pluss';\r
632                                 else $tempclass='minus';\r
633 \r
634                                 // Rund av vindhastighet\r
635                                 $r=round($yr_var3['WINDSPEED'][0]['ATTRIBUTES']['MPS']);\r
636                                 // Så legger vi ut hele den ferdige linjen\r
637                                 $s=$yr_var3['SYMBOL'][0]['ATTRIBUTES']['NAME'];\r
638                                 $w=$yr_var3['WINDSPEED'][0]['ATTRIBUTES']['NAME'];\r
639 \r
640                                 $this->ht.=<<<EOT\r
641           <tr>\r
642             <th>$firstcellcont</th>\r
643             <th>$fromtime&#8211;$totime</th>\r
644             <td><img src="$this->yr_imgpath/$imgno.png" width="38" height="38" alt="$s" /></td>\r
645             <td>$rain</td>\r
646             <td class="$tempclass">$temper&deg;</td>\r
647             <td class="v">$w fra $winddirtext</td>\r
648             <td>$r m/s</td>\r
649           </tr>\r
650 \r
651 EOT\r
652                                 ;\r
653                         }\r
654                 }\r
655         }\r
656 \r
657         //Generer footer for værdatatabellen\r
658         public function getWeatherTableFooter($target='_top'){\r
659                 $this->ht.=<<<EOT\r
660           <tr>\r
661             <td colspan="7" class="skilje"></td>\r
662           </tr>\r
663         </tbody>\r
664       </table>\r
665       <p>V&aelig;rsymbolet og nedb&oslash;rsvarselet gjelder for hele perioden, temperatur- og vindvarselet er for det f&oslash;rste tidspunktet. &lt;1 mm betyr at det vil komme mellom 0,1 og 0,9 mm nedb&oslash;r.<br />\r
666       <a href="http://www.yr.no/1.3362862" target="$target">Slik forst&aring;r du varslene fra yr.no</a>.</p>\r
667       <p>Vil du ogs&aring; ha <a href="http://www.yr.no/verdata/" target="$target">v&aelig;rvarsel fra yr.no p&aring; dine nettsider</a>?</p>\r
668 EOT\r
669                 ;\r
670         }\r
671 \r
672 \r
673         // Handle cache directory (re)creation and cachefile name selection\r
674         private function handleDataDir($clean_datadir=false,$summary=''){\r
675                 global $yr_datadir;\r
676                 // The md5 sum is to avoid caching to the same file on parameter changes\r
677                 $this->datapath=$yr_datadir .'/'. ($summary!='' ? (md5($summary).'['.$summary.']_') : '').$this->datafile;\r
678                 // Delete cache dir\r
679                 if ($clean_datadir) {\r
680                         unlink($this->datapath);\r
681                         rmdir($yr_datadir);\r
682                 }\r
683                 // Create new cache folder with correct permissions\r
684                 if(!is_dir($yr_datadir))mkdir($yr_datadir,0300);\r
685         }\r
686 \r
687 \r
688         //Main with caching\r
689         public function generateHTMLCached($url,$name,$xml, $url, $try_curl, $useHtmlHeader=true, $useHtmlFooter=true, $useBanner=true, $useText=true, $useLinks=true, $useTable=true, $maxage=0, $timeout=10, $urlTarget='_top'){\r
690                 //Default to the name in the url\r
691                 if(null==$name||''==trim($name))$name=array_pop(explode('/',$url));\r
692                 $this->handleDataDir(false,htmlentities("$name.$useHtmlHeader.$useHtmlFooter.$useBanner.$useText.$useLinks.$useTable.$maxage.$timeout.$urlTarget"));\r
693                 $yr_cached = $this->datapath;\r
694                 // Clean name\r
695                 $name=YRComms::convertEncodingUTF($name);\r
696                 $name=YRComms::convertEncodingEntities($name);\r
697                 // Clean URL\r
698                 $url=YRComms::convertEncodingUTF($url);\r
699                 // Er mellomlagring enablet, og trenger vi egentlig laste ny data, eller holder mellomlagret data?\r
700                 if(($maxage>0)&&((file_exists($yr_cached))&&((time()-filemtime($yr_cached))<$maxage))){\r
701                         $data['value']=file_get_contents($yr_cached);\r
702                         // Sjekk for feil\r
703                         if(false==$data['value']){\r
704                 $data['value']='<p>Det oppstod en feil mens værdata ble lest fra lokalt mellomlager. Vennligst gjør administrator oppmerksom på dette! Teknisk: Sjekk at rettighetene er i orden som beskrevet i bruksanvisningen for dette scriptet</p>';\r
705                 $data['error'] = true;\r
706           }\r
707                 }\r
708                 // Vi kjører live, og saver samtidig en versjon til mellomlager\r
709                 else{\r
710                         $data=$this->generateHTML($url,$name,$xml->getXMLTree($url, $try_curl, $timeout),$useHtmlHeader,$useHtmlFooter,$useBanner,$useText,$useLinks,$useTable,$urlTarget);\r
711                         // Lagre til mellomlager\r
712                         if($maxage>0 && !$data['error'] ){\r
713                                 $f=fopen($yr_cached,"w");\r
714                                 if(null!=$f){\r
715                                         fwrite($f,$data['value']);\r
716                                         fclose($f);\r
717                                 }\r
718                         }\r
719                 }\r
720                 // Returner resultat\r
721                 return $data['value'];\r
722         }\r
723 \r
724         private function getErrorMessage(){\r
725                 if(isset($this->yr_data['ERROR'])){\r
726                         $error=$this->yr_data['ERROR'][0]['VALUE'];\r
727                         //die(retar($error));\r
728                         $this->ht.='<p style="color:red; background:black; font-weight:900px">' .$error.'</p>';\r
729           return true;\r
730                 }\r
731                 return false;\r
732         }\r
733 \r
734         //Main\r
735         public function generateHTML($url,$name,$data,$useHtmlHeader=true,$useHtmlFooter=true,$useBanner=true,$useText=true,$useLinks=true,$useTable=true,$urlTarget='_top'){\r
736                 // Fyll inn data fra parametrene\r
737                 $this->ht='';\r
738                 $this->yr_url=$url;\r
739                 $this->yr_name=$name;\r
740                 $this->yr_data=$data;\r
741 \r
742                 // Generer HTML i $ht\r
743                 $this->getHeader($useHtmlHeader);\r
744                 $data['error'] = $this->getErrorMessage();\r
745                 if($useBanner)$this->getBanner($urlTarget);\r
746                 $this->getCopyright($urlTarget);\r
747                 if($useText)$this->getWeatherText();\r
748                 if($useLinks)$this->getLinks($urlTarget);\r
749                 if($useTable){\r
750                         $this->getWeatherTableHeader();\r
751                         $this->getWeatherTableContent();\r
752                         $this->getWeatherTableFooter($urlTarget);\r
753                 }\r
754                 $this->getFooter($useHtmlFooter);\r
755 \r
756                 // Returner resultat\r
757                 //return YRComms::convertEncodingEntities($this->ht);\r
758                 $data['value'] = $this->ht;\r
759                 return $data;\r
760         }\r
761 }\r
762 \r
763 ?>