You are here

weather_es_parser.inc in Weather_es 5

Same filename and directory in other branches
  1. 6 weather_es_parser.inc
  2. 6.2 weather_es_parser.inc

Gets the data from the AEMET web

The module is compatible with Drupal 6.x

@author José Mª Sirvent

File

weather_es_parser.inc
View source
<?php

/**
 * Weather_es shows the weather forecast of 8112 cities of Spain using the AEMET web information.
 * Copyright (C) 2008 José Mª Sirvent <drupal@hykrion.com>
 *
 * This file is part of the Drupal weather_es module.
 * It is based on the Weather module which was written in 2006 by
 * Tobias Toedter <t.toedter@gmx.net>.
 *
 * Weather_es 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 2 of the License, or
 * (at your option) any later version.
 *
 * Weather_es 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 Weather_es; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/**
 * @file
 * Gets the data from the AEMET web
 *
 * The module is compatible with Drupal 6.x
 *
 * @author José Mª Sirvent
 */

/**
 * Get the td info: rain probability, tmax, tmin...
 */
function _weather_es_get_td_info($captured_td, $ampm) {
  $lon = sizeof($captured_td);

  // Sky state
  if ($ampm == 'am') {
    $end = 9;
  }
  else {
    $end = 8;
  }

  // In images
  for ($i = 0; $i <= $end; $i++) {
    preg_match('/[0-9]{2}.gif/', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $sky_img[] = substr($data[0], 0, $data_lon - 4);
  }

  // In text
  for ($i = 0; $i <= $end; $i++) {
    preg_match('/alt=".+"/', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $sky_txt[] = substr($data[0], 5, $data_lon - 6);
  }

  // Begining of wind direction
  $beg = $end + 1;
  for ($i = $beg; $i <= $lon; $i++) {
    if (preg_match('/[A-Z]{1,2}.gif/', $captured_td[$i])) {
      break;
    }
  }
  $win_beg = $i;

  // Get all the data between the rain probability and the wind direction
  $end = $win_beg - 1;
  for ($i = $beg; $i <= $end; $i++) {
    preg_match('/>[0-9]{1,4}/', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $rain_tmin[] = substr($data[0], 1, $data_lon);
  }
  $beg = $win_beg;

  // Wind direction
  if ($ampm == 'am') {
    $end = $beg + 9;
  }
  else {
    $end = $beg + 8;
  }
  for ($i = $beg; $i <= $end; $i++) {
    preg_match('/alt=".+"/', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $win_dir[] = substr($data[0], 5, $data_lon - 6);
  }
  $beg = $end + 1;

  // Wind speed
  if ($ampm == 'am') {
    $end = $beg + 9;
  }
  else {
    $end = $beg + 8;
  }
  for ($i = $beg; $i <= $end; $i++) {
    preg_match('/>[0-9]{1,3}/', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $win_spd[] = substr($data[0], 1, $data_lon);
  }

  // Violet index
  $beg = $end + 1;
  $end = $beg + 2;
  for ($i = $beg; $i <= $end; $i++) {
    preg_match('/[0-9]{1,2}</', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $vi[] = substr($data[0], 0, $data_lon - 1);
  }

  // Risk level
  $beg = $beg + 7;
  $end = $beg + 2;
  for ($i = $beg; $i <= $end; $i++) {
    preg_match('/alt=".+?"/', $captured_td[$i], $data);
    $data_lon = strlen($data[0]);
    $rsk[] = substr($data[0], 5, $data_lon - 6);
  }
  return array(
    $sky_img,
    $sky_txt,
    $rain_tmin,
    $win_dir,
    $win_spd,
    $vi,
    $rsk,
  );
}

/**
 * Clean the data and save it
 */
function _weather_es_aemet($wuid, $city_cod, $lan, $city_nam) {

  // Raw data of AEMET
  $array_text = _weather_es_retrieve_data($wuid, $city_cod, $lan, $city_nam);
  if ($array_text != -1) {

    // Get the days
    preg_match_all('/<th.+th>/', $array_text[0][0][0], $captured_th);
    for ($i = 1; $i < 8; $i++) {
      preg_match('/>.+</', $captured_th[0][$i], $data);
      $data_lon = strlen($data[0]);
      $ori_str = substr($data[0], 1, $data_lon - 2);
      $htm_str = htmlentities($ori_str);
      $days[] = $htm_str;
    }

    // Get ampm (we don't really need that...)
    preg_match_all('/<th.+th>/', $array_text[0][0][1], $captured_th);
    for ($i = 0; $i < sizeof($captured_th[0]); $i++) {
      preg_match('/>.+</', $captured_th[0][$i], $data);
      $data_lon = strlen($data[0]);
      $ampm[] = substr($data[0], 1, $data_lon - 2);
    }

    // Get the data types and the data
    for ($i = 2; $i < sizeof($array_text[0][0]); $i++) {

      // Data type
      preg_match_all('/<th.+th>/', $array_text[0][0][$i], $captured_th);
      preg_match('/>.+</', $captured_th[0][0], $data);
      $data_lon = strlen($data[0]);
      $ori_data_type[] = substr($data[0], 1, $data_lon - 2);
      if (preg_match('/cielo|cel|ceo|egoera|Sky|ciel/', $array_text[0][0][$i])) {
        $ii = 0;
      }
      elseif (preg_match('#\\(%\\)#', $array_text[0][0][$i])) {
        $ii = 1;
      }
      elseif (preg_match('#\\(m\\)#', $array_text[0][0][$i])) {
        $ii = 2;
      }
      elseif (preg_match('#\\(.C\\)#', $array_text[0][0][$i])) {
        if (!isset($jj)) {
          $ii = 3;
          $jj = 0;
        }
        else {
          $ii = 4;
        }
      }
      elseif (preg_match('/Viento|Vent|Vento|Haizeak|Wind/', $array_text[0][0][$i])) {
        $ii = 5;
      }
      elseif (preg_match('#\\(km/h\\)#', $array_text[0][0][$i])) {
        $ii = 6;
      }
      elseif (preg_match('/UV/', $array_text[0][0][$i])) {
        $ii = 7;
      }
      elseif (preg_match('/Nivel|Nivell|Gehinezko|Level|Niveau/', $array_text[0][0][$i])) {
        $ii = 8;
      }
      else {
        $ii = 99;
      }
      switch ($ii) {

        // Sky
        case 0:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);

          // Images
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/[0-9]{2}.gif/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $sky_img[] = substr($data[0], 0, $data_lon - 4);
          }

          // Text
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/alt=".+"/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $sky_txt[] = substr($data[0], 5, $data_lon - 6);
          }
          break;

        // Rain
        case 1:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/>[0-9]{1,3}/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $rain[] = substr($data[0], 1, $data_lon);
          }
          break;

        // Snow
        case 2:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/>[0-9]{1,4}/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            if (sizeof($data[0]) != 0) {
              $snow[] = substr($data[0], 1, $data_lon);
            }
            else {
              $snow[] = 9999;
            }
          }
          break;

        // Tmax
        case 3:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/>[0-9]{1,4}/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $tmax[] = substr($data[0], 1, $data_lon);
          }
          break;

        // Tmin
        case 4:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/>[0-9]{1,4}/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $tmin[] = substr($data[0], 1, $data_lon);
          }
          break;

        // Wind direction
        case 5:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/alt=".+"/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $win_dir[] = substr($data[0], 5, $data_lon - 6);
          }
          break;

        // Wind speed
        case 6:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/>[0-9]{1,4}/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $win_spd[] = substr($data[0], 1, $data_lon);
          }
          break;

        // UI
        case 7:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/[0-9]{1,2}</', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $ui[] = substr($data[0], 0, $data_lon - 1);
          }
          break;

        // Risk level
        case 8:
          preg_match_all('/<td.+td>/', $array_text[0][0][$i], $captured_th);
          for ($j = 0; $j < sizeof($captured_th[0]); $j++) {
            preg_match('/alt=".+?"/', $captured_th[0][$j], $data);
            $data_lon = strlen($data[0]);
            $rsk[] = substr($data[0], 5, $data_lon - 6);
          }
          break;
      }
    }
    if (!isset($snow)) {
      for ($i = 0; $i < 7; $i++) {
        $snow[$i] = 9999;
      }
    }
    for ($i = 0; $i < sizeof($ori_data_type); $i++) {
      $htm_str = htmlentities($ori_data_type[$i]);
      $data_type[] = $htm_str;
    }
    $aemet = array(
      $days,
      $ampm,
      $data_type,
      $sky_img,
      $sky_txt,
      $rain,
      $snow,
      $tmax,
      $tmin,
      $win_dir,
      $win_spd,
      $ui,
      $rsk,
    );
  }
  else {
    $aemet = -1;
  }
  return $aemet;
}

/**
 * Get the data from AEMET
 */
function _weather_es_retrieve_data($wuid, $city_cod, $lan, $city_nam) {
  global $user;
  $response = -1;

  // Web direction example (until 2009/12/10): http://www.aemet.es/es/eltiempo/prediccion/localidades?l=03410&p=03
  // New web direction example: http://www.aemet.es/es/eltiempo/prediccion/localidades/jijona-xixona-03410
  // www.aemet.es: 193.144.152.138
  // Languages are: es, ca/va, gl, eu, en and fr.
  // This is what we get from the bad boys of aemet (30-01-2010)

  /*
  <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
  <html><head>
  <title>301 Moved Permanently</title>
  </head><body>
  <h1>Moved Permanently</h1>
  <p>The document has moved <a href="http://www.aemet.es/es/eltiempo/prediccion/localidades/Aramaio-01030">here</a>.</p>
  </body></html>
  */
  $page = '/' . $lan . '/eltiempo/prediccion/localidades/' . $city_nam . '-' . $city_cod;
  $url = 'http://www.aemet.es' . $page;
  if (function_exists('fsockopen')) {
    $result = drupal_http_request($url);
    switch ($result->code) {
      case '200':
      case '304':

        // Get the table
        preg_match('/<table.+table>/s', $result->data, $captured);

        // Pass it to a string
        $data_string = implode(" ", $captured);
        $length = strlen($data_string);
        $position = strpos($data_string, "table>");
        $data_string = substr($data_string, 0, $position - $length);
        preg_match_all('/<tr.+tr>/sU', $data_string, $captured_tr);
        $response = array(
          $captured_tr,
        );
        break;
      case '301':
      case '302':
      case '307':
        $result = drupal_http_request('http://www.aemet.es' . $result->redirect_url);

        // Get the table
        preg_match('/<table.+table>/s', $result->data, $captured);

        // Pass it to a string
        $data_string = implode(" ", $captured);
        $length = strlen($data_string);
        $position = strpos($data_string, "table>");
        $data_string = substr($data_string, 0, $position - $length);
        preg_match_all('/<tr.+tr>/sU', $data_string, $captured_tr);
        $response = array(
          $captured_tr,
        );
        break;
      default:
        if ($user->uid) {
          drupal_set_message(t('fsockopen fail to open AEMET.'), 'error');
        }
    }
  }
  else {
    if ($user->uid) {
      drupal_set_message(t('Function fsockopen does not exist, you can\'t use this module...'), 'error');
    }
  }
  return $response;
}

/**
 * Get the user configuration
 */
function _weather_es_get_config($uid) {
  $sql = "SELECT cod_pro, cod_loc FROM {weather_es_config} WHERE uid = %d";
  $result = db_query($sql, $uid);
  while ($data = db_fetch_object($result)) {
    (string) ($cities[] = $data->cod_pro . $data->cod_loc);
  }
  return $cities;
}

/**
 * Get the diferent cities of the user
 */
function _weather_es_filter_cities($loc, $cit) {
  $user_cities = array();
  for ($i = 0; $i < sizeof($cit); $i++) {

    // Upper PHP 4.0.6

    //if (array_key_exist($cit[$i], $arrayOfKeys))
    if (key_exists($cit[$i], $loc)) {
      $user_cities[] = $loc[$cit[$i]];
    }
  }
  return $user_cities;
}

/**
 * Next data update. AEMET refresh the data at Spanish local time, about 07:00am
 *
 * Using this code your server will look for the AEMET data once a day but I think its too much
 * overhead to avoid getting the data from AEMET Web 6 times a day...
 */
function _weather_es_next_act() {
  $now = spanish_time();
  $hour = strftime('%H', $now);
  $dif = 7 - $hour;
  if ($dif >= 0) {
    $next_act_in = $dif;
  }
  else {
    $next_act_in = 24 - $hour + 7;
  }
  $ran = rand(0, 60) * 60;
  $next_act_in *= 3600;
  $next_act = $now + $next_act_in + $ran;
  return $next_act;
}

/**
 * Return the Spanish (peninsula) time
 */
function spanish_time() {

  // get the server time and change it to Spanish time
  if (function_exists('date_default_timezone_get')) {
    $server_time = date_default_timezone_get();
    date_default_timezone_set('Europe/Madrid');
  }
  else {
    $server_time = ini_get('date.timezone');
    ini_set('date.timezone', 'Europe/Madrid');
  }
  $now = time();

  // save the original server timezone
  if (function_exists('date_default_timezone_set')) {
    date_default_timezone_set('$server_time');
  }
  else {
    ini_set('date.timezone', '$server_time');
  }
  return $now;
}

/**
 * Redirect the user to his correct path
 */
function _weather_es_redirect($wuid) {

  // User cities list
  if ($wuid == 0) {
    $path = 'admin/settings/weather_es';
  }
  else {
    $path = 'user/' . $wuid . '/weather_es';
  }
  return $path;
}

/**
 * Available provinces
 */
function _weather_es_provincies() {
  $provincies = array(
    '00' => "---",
    '15' => "A Coruña",
    '01' => "Álava",
    '02' => "Albacete",
    '03' => "Alicante",
    '04' => "Almería",
    '33' => "Asturias",
    '05' => "Ávila",
    '06' => "Badajoz",
    '08' => "Barcelona",
    '09' => "Burgos",
    '10' => "Cáceres",
    '11' => "Cádiz",
    '39' => "Cantabria",
    '12' => "Castellón",
    '51' => "Ceuta",
    '13' => "Ciudad Real",
    '14' => "Córdoba",
    '16' => "Cuenca",
    '17' => "Girona",
    '18' => "Granada",
    '19' => "Guadalajara",
    '20' => "Guipúzcoa",
    '21' => "Huelva",
    '22' => "Huesca",
    '07' => "Illes Balears",
    '23' => "Jaén",
    '26' => "La Rioja",
    '35' => "Las Palmas",
    '24' => "León",
    '25' => "Lleida",
    '27' => "Lugo",
    '28' => "Madrid",
    '29' => "Málaga",
    '52' => "Melilla",
    '30' => "Murcia",
    '31' => "Navarra",
    '32' => "Ourense",
    '34' => "Palencia",
    '36' => "Pontevedra",
    '37' => "Salamanca",
    '38' => "Santa Cruz de Tenerife",
    '40' => "Segovia",
    '41' => "Sevilla",
    '42' => "Soria",
    '43' => "Tarragona",
    '44' => "Teruel",
    '45' => "Toledo",
    '46' => "Valencia",
    '47' => "Valladolid",
    '48' => "Vizcaya",
    '49' => "Zamora",
    '50' => "Zaragoza",
  );
  return $provincies;
}

/**
 * Available cities.
 */
function _weather_es_cities($pro) {
  $sql = "SELECT * FROM {weather_es_aemet} wea WHERE wea.cod_pro = %d";
  $result = db_query($sql, $pro);
  while ($row = db_fetch_array($result)) {
    $aemet_cod = $row['cod_pro'] . $row['cod_loc'];
    $cities[$aemet_cod] = $row['cit_nam'];
  }
  return $cities;
}

Functions

Namesort descending Description
spanish_time Return the Spanish (peninsula) time
_weather_es_aemet Clean the data and save it
_weather_es_cities Available cities.
_weather_es_filter_cities Get the diferent cities of the user
_weather_es_get_config Get the user configuration
_weather_es_get_td_info Get the td info: rain probability, tmax, tmin...
_weather_es_next_act Next data update. AEMET refresh the data at Spanish local time, about 07:00am
_weather_es_provincies Available provinces
_weather_es_redirect Redirect the user to his correct path
_weather_es_retrieve_data Get the data from AEMET