Services_Weather
[ class tree: Services_Weather ] [ index: Services_Weather ] [ all elements ]

Source for file buildMetarDB.php

Documentation is available at buildMetarDB.php

  1. #!/usr/local/bin/php
  2. <?php
  3. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  4. // +----------------------------------------------------------------------+
  5. // | PHP version 4                                                        |
  6. // +----------------------------------------------------------------------+
  7. // | Copyright (c) 1997-2004 The PHP Group                                |
  8. // +----------------------------------------------------------------------+
  9. // | This source file is subject to version 2.0 of the PHP license,       |
  10. // | that is bundled with this package in the file LICENSE, and is        |
  11. // | available through the world-wide-web at                              |
  12. // | http://www.php.net/license/2_02.txt.                                 |
  13. // | If you did not receive a copy of the PHP license and are unable to   |
  14. // | obtain it through the world-wide-web, please send a note to          |
  15. // | license@php.net so we can mail you a copy immediately.               |
  16. // +----------------------------------------------------------------------+
  17. // | Authors: Alexander Wirtz <alex@pc4p.net>                             |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: buildMetarDB.php,v 1.16 2004/01/06 19:36:28 eru Exp $
  21.  
  22. require_once "DB.php";
  23.  
  24. // {{{ constants
  25. // {{{ natural constants and measures
  26. define("SERVICES_WEATHER_RADIUS_EARTH"6378.15);
  27. // }}}
  28. // }}}
  29.  
  30. /**
  31. * This script downloads, saves and processes the textfiles needed for
  32. * the building the databases to enable searching for METAR stations.
  33. *
  34. * You can download the locations, which is a database of about 12000 world-
  35. * wide locations, which can be used to determine the coordinates of your
  36. * city or you can download a file with 6500 airports providing the metar
  37. * data. This database is used for the next-METAR-station search. Please see
  38. * the apropriate documentation in the Services_Weather_Metar class.
  39. *
  40. * For usage of this script, invoke with '-h'.
  41. *
  42. @author       Alexander Wirtz <alex@pc4p.net>
  43. @link         http://weather.noaa.gov/tg/site.shtml
  44. @package      Services_Weather
  45. @version      1.2
  46. */
  47.  
  48. // {{{ Services_Weather_checkData()
  49. /**
  50. * Services_Weather_checkData
  51. *
  52. * Checks the data for a certain string-length and if it either consists of
  53. * a certain char-type or a string of "-" as replacement.
  54. *
  55. @param    array                           $data           The data to be checked
  56. @param    array                           $dataOrder      Because the data is in different locations, we provide this
  57. @return   bool 
  58. */
  59. function Services_Weather_checkData($data$dataOrder)
  60. {
  61.     $return = true;
  62.     foreach ($dataOrder as $type => $idx{
  63.         switch (strtolower($type)) {
  64.             case "b":
  65.                 $len  = 2;
  66.                 $func "ctype_digit";
  67.                 break;
  68.             case "s":
  69.                 $len  = 3;
  70.                 $func "ctype_digit";
  71.                 break;
  72.             case "i":
  73.                 $len  = 4;
  74.                 $func "ctype_alnum";
  75.                 break;
  76.             default:
  77.                 break;
  78.         }
  79.         if ((strlen($data[$idx]!= $len|| (!$func($data[$idx]&& ($data[$idx!= str_repeat("-"$len)))) {
  80.             $return = false;
  81.             break;
  82.         }
  83.     }
  84.     return $return;
  85. }
  86. // }}}
  87.  
  88. // {{{ Services_Weather_getNextArg()
  89. /**
  90. * Services_Weather_getNextArg
  91. *
  92. * Checks, if the next argument is a parameter to a predecessing option.
  93. * Returns either that parameter or false, if the next argument is an option
  94. *
  95. @param    int                             $c              Internal argument counter
  96. @return   string|bool
  97. */
  98. {
  99.     if ((($c + 1$_SERVER["argc"]&& ($_SERVER["argv"][$c + 1]{0!= "-")) {
  100.         $c++;
  101.         return $_SERVER["argv"][$c];
  102.     else {
  103.         return false;
  104.     }    
  105. }
  106. // }}}
  107.  
  108. // First set a few variables for processing the options
  109. $modeSet   = false;
  110. $saveFile  = false;
  111. $printHelp = false;
  112. $invOpt    = false;
  113. $verbose   = 0;
  114. $dbType    "mysql";
  115. $dbProt    "unix";
  116. $dbName    "servicesWeatherDB";
  117. $dbUser    "root";
  118. $dbPass    "";
  119. $dbHost    "localhost";
  120. $dbOptions = array();
  121. $userFile  "";
  122.  
  123. // Iterate through the arguments and check their validity
  124. for ($c = 1; $c $_SERVER["argc"]$c++{
  125.     switch ($_SERVER["argv"][$c]{1}{
  126.         case "l":
  127.             // location-mode, if another mode is set, bail out
  128.             if ($modeSet{
  129.                 $printHelp = true;
  130.             else {
  131.                 $modeSet   = true;
  132.                 $filePart  "bbsss";
  133.                 $tableName "metarLocations";
  134.                 $dataOrder = array("b" => 0"s" => 1"i" => 2);
  135.             }
  136.             break;
  137.         case "a":
  138.             // dito for airport-mode
  139.             if ($modeSet{
  140.                 $printHelp = true;
  141.             else {
  142.                 $modeSet   = true;
  143.                 $filePart  "cccc";
  144.                 $tableName "metarAirports";
  145.                 $dataOrder = array("b" => 1"s" => 2"i" => 0);
  146.             }
  147.             break;
  148.         case "f":
  149.             // file-flag was provided, check if next argument is a string
  150.             if (($userFile Services_Weather_getNextArg($c)) === false{
  151.                 $printHelp = true;
  152.             }
  153.             break;
  154.         case "s":
  155.             // If you download the file, it will be saved to disk
  156.             $saveFile      = true;
  157.             break;
  158.         case "t":
  159.             // The type of the DB to be used
  160.             if (($dbType Services_Weather_getNextArg($c)) === false{
  161.                 $printHelp = true;
  162.             }
  163.             break;
  164.         case "r":
  165.             // The protocol of the DB to be used
  166.             if (($dbProt Services_Weather_getNextArg($c)) === false{
  167.                 $printHelp = true;
  168.             }
  169.             break;
  170.         case "d":
  171.             // The name of the DB to be used
  172.             if (($dbName Services_Weather_getNextArg($c)) === false{
  173.                 $printHelp = true;
  174.             }
  175.             break;
  176.         case "u":
  177.             // The user of the DB to be used
  178.             if (($dbUser Services_Weather_getNextArg($c)) === false{
  179.                 $printHelp = true;
  180.             }
  181.             break;
  182.         case "p":
  183.             // The password of the DB to be used
  184.             if (($dbPass Services_Weather_getNextArg($c)) === false{
  185.                 $printHelp = true;
  186.             }
  187.             break;
  188.         case "h":
  189.             // The host of the DB to be used
  190.             if (($dbHost Services_Weather_getNextArg($c)) === false{
  191.                 $printHelp = true;
  192.             }
  193.             break;
  194.         case "o":
  195.             // Options for the DB
  196.             if (($options Services_Weather_getNextArg($c)) === false{
  197.                 $printHelp = true;
  198.             else {
  199.                 $options   explode(","$options);
  200.                 foreach ($options as $option{
  201.                     $optPair explode("="$option);
  202.                     $dbOptions[$optPair[0]] $optPair[1];
  203.                 }
  204.             }
  205.             break;
  206.         case "v":
  207.             // increase verbosity
  208.             for ($i = 1; $i strlen($_SERVER["argv"][$c])$i++{
  209.                 if ($_SERVER["argv"][$c]{$i== "v"{
  210.                     $verbose++;
  211.                 else {
  212.                     $invOpt    = true;
  213.                     break;
  214.                 }
  215.             }
  216.             break;
  217.         default:
  218.             // argument not valid, bail out
  219.             $invOpt    = true;
  220.             break;
  221.     }
  222.     if ($invOpt{
  223.         // see above
  224.         $printHelp = true;
  225.         echo "Invalid option: '".$_SERVER["argv"][$c]."'\n";
  226.         break;
  227.     }
  228. }
  229.  
  230. // help-message
  231. if (!$modeSet || $printHelp{
  232.     echo "Usage: ".basename($_SERVER["argv"][0]".php")." -l|-a [options]\n";
  233.     echo "Options:\n";
  234.     echo "  -l              build locationsDB\n";
  235.     echo "  -a              build airportsDB\n";
  236.     echo "  -f <file>       use <file> as input\n";
  237.     echo "  -s              save downloaded file to disk\n";
  238.     echo "  -t <dbtype>     type of the DB to be used\n";
  239.     echo "  -r <dbprotocol> protocol -----\"----------\n";
  240.     echo "  -d <dbname>     name ---------\"----------\n";
  241.     echo "  -u <dbuser>     user ---------\"----------\n";
  242.     echo "  -p <dbpass>     pass ---------\"----------\n";
  243.     echo "  -h <dbhost>     host ---------\"----------\n";
  244.     echo "  -o <dboptions>  options ------\"----------\n";
  245.     echo "                  in the notation option=value,...\n";
  246.     echo "  -v              display verbose debugging messages\n";
  247.     echo "                  multiple -v increases verbosity\n";
  248.     exit(255);
  249. }
  250.  
  251. // check, if zlib is available
  252. if (extension_loaded("zlib")) {
  253.     $open  "gzopen";
  254.     $close "gzclose";
  255.     $files = array(
  256.         $userFile"nsd_".$filePart"nsd_".$filePart.".txt",
  257.         "nsd_".$filePart.".gz""http://weather.noaa.gov/data/nsd_".$filePart.".gz"
  258.     );
  259. else {
  260.     $open  "fopen";
  261.     $close "fclose";
  262.     $files = array(
  263.         $userFile"nsd_".$filePart"nsd_".$filePart.".txt",
  264.         "http://weather.noaa.gov/data/nsd_".$filePart.".txt"
  265.     );
  266. }
  267. // then try to open a source in the given order
  268. foreach ($files as $file{
  269.     $fp @$open($file"rb");
  270.     if ($fp{
  271.         // found a valid source
  272.         if ($verbose > 0{
  273.             echo "Services_Weather: Using '".$file."' as source.\n";
  274.         }
  275.         if ($saveFile && !file_exists($file)) {
  276.             // apparently we want to save the file, and it's a remote file
  277.             $file basename($file);
  278.             $fps @$open($file"wb");
  279.             if (!$fps{
  280.                 echo "Services_Weather: Couldn't save to '".$file."'!\n";
  281.             else {
  282.                 if ($verbose > 0{
  283.                     echo "Services_Weather: Saving source to '".$file."'.\n";
  284.                 }
  285.                 // read from filepointer and save to disk
  286.                 while ($line fread($fp1024)) {
  287.                     fwrite($fps$linestrlen($line));
  288.                 }
  289.                 // unfortunately zlib does not support r/w on a resource,
  290.                 // so no rewind -> move $fp to new file on disk
  291.                 $close($fp);
  292.                 $close($fps);
  293.                 $fp @$open($file"rb");
  294.             }
  295.         }
  296.         break;
  297.     }
  298. }
  299. if (!$fp{
  300.     // no files found, or connection not available... bail out
  301.     die("Services_Weather: Sourcefile nsd_".$filePart." not found!\n");
  302. }
  303.  
  304. $dsn     $dbType."://".$dbUser.":".$dbPass."@".$dbProt."+".$dbHost."/".$dbName;
  305. $dsninfo = array(
  306.     "phptype"  => $dbType,
  307.     "protocol" => $dbProt,
  308.     "username" => $dbUser,
  309.     "password" => $dbPass,
  310.     "hostspec" => $dbHost,
  311.     "database" => $dbName,
  312.     "mode"     => 0644
  313. );
  314.  
  315. $db  = DB::connect($dsninfo$dbOptions);
  316. if (DB::isError($db)) {
  317.     echo "Services_Weather: Connection to DB with '".$dbType."://".$dbUser.":PASS@".$dbHost."/".$dbName."' failed!\n";
  318.     die($db->getMessage()."\n");
  319. else {
  320.     // Test, if we have to swipe or create the table first
  321.     $select "SELECT * FROM ".$tableName;
  322.     $result $db->query($select);
  323.  
  324.     if (DB::isError($result)) {
  325.         // Create new table
  326.         $create "CREATE TABLE ".$tableName."(id int,block int,station int,icao varchar(4),name varchar(80),state varchar(2),country varchar(50),wmo int,latitude float,longitude float,elevation float,x float,y float,z float)";
  327.         if ($verbose > 0{
  328.             echo "Services_Weather: Creating table '".$tableName."'.\n";
  329.         }
  330.         $result  $db->query($create);
  331.         if (DB::isError($result)) {
  332.             die($result->getMessage()."\n");
  333.         }
  334.     else {
  335.         // Delete the old stuff
  336.         $delete "DELETE FROM ".$tableName;
  337.         if ($verbose > 0{
  338.             echo "Services_Weather: Deleting from table '".$tableName."'.\n";
  339.         }
  340.         $result $db->query($delete);
  341.         if (DB::isError($result)) {
  342.             die($result->getMessage()."\n");
  343.         }
  344.     }
  345.  
  346.     // Ok, DB should be up and running now, let's shove in the data
  347.     $line   = 0;
  348.     $error  = 0;
  349.     // read data from file
  350.     while ($data fgetcsv($fp1000";")) {
  351.         // Check for valid data
  352.         if ((sizeof($data< 9|| !Services_Weather_checkData($data$dataOrder)) {
  353.                 echo "Services_Weather: Invalid data in file!\n";
  354.                 echo "\tLine ".($line + 1).": ".implode(";"$data)."\n";
  355.                 $error++;
  356.         else {
  357.             // calculate latitude and longitude
  358.             // it comes in a ddd-mm[-ss]N|S|E|W format
  359.             $coord = array"latitude" => 7"longitude" => 8);
  360.             foreach ($coord as $latlon => $aId{
  361.                 preg_match("/^(\d{1,3})-(\d{1,2})(-(\d{1,2}))?([NSEW])$/"$data[$aId]$result);
  362.                 ${$latlon= 0; $factor = 1;
  363.                 foreach ($result as $var{
  364.                     if ((strlen($var> 0&& ctype_digit($var)) {
  365.                         ${$latlon+= $var $factor;
  366.                         $factor *= 60;
  367.                     elseif (ctype_alpha($var&& in_array($vararray("S""W"))) {
  368.                         ${$latlon*= (-1);
  369.                     }
  370.                 }
  371.             }
  372.  
  373.             // Calculate the cartesian coordinates for latitude and longitude
  374.             $theta deg2rad($latitude);
  375.             $phi   deg2rad($longitude);
  376.  
  377.             $x SERVICES_WEATHER_RADIUS_EARTH * cos($phicos($theta);
  378.             $y SERVICES_WEATHER_RADIUS_EARTH * sin($phicos($theta);
  379.             $z SERVICES_WEATHER_RADIUS_EARTH             * sin($theta);
  380.  
  381.             // Check for elevation in data
  382.             $elevation is_numeric($data[11]$data[11: 0;
  383.  
  384.             // integers: convert "--" fields to null, empty fields to 0
  385.             foreach (array($dataOrder["b"]$dataOrder["s"]6as $i{
  386.                 if (strpos($data[$i]"--"!== false
  387.                     $data[$i"null"
  388.                 elseif ($data[$i== ""
  389.                     $data[$i= 0; 
  390.                 }
  391.             }
  392.  
  393.             // strings: quote
  394.             foreach (array($dataOrder["i"]345as $i{
  395.                 $data[$i$db->quote($data[$i]);
  396.             }
  397.  
  398.             // insert data
  399.             $insert  "INSERT INTO ".$tableName." VALUES(".($line $error).",";
  400.             $insert .= $data[$dataOrder["b"]].",".$data[$dataOrder["s"]].",";
  401.             $insert .= $data[$dataOrder["i"]].",".$data[3].",".$data[4].",";
  402.             $insert .= $data[5].",".$data[6].",".round($latitude4).",";
  403.             $insert .= round($longitude4).",".$elevation.",".round($x4).",";
  404.             $insert .= round($y4).",".round($z4).")";
  405.  
  406.             $result $db->query($insert);
  407.             if (DB::isError($result)) {
  408.                 echo "\tLine ".($line + 1).": ".$insert."\n";
  409.                 echo $result->getMessage()."\n";
  410.                 $error++;
  411.             elseif($verbose > 2{
  412.                 echo $insert."\n";
  413.             }
  414.         }
  415.         $line++;
  416.     }
  417.     // commit and close
  418.     $db->disconnect();
  419.     if ($verbose > 0 || $error > 0{
  420.         echo "Services_Weather: ".($line $error)." ".$tableName." added ";
  421.         echo "to database '".$dbName."' (".$error." error(s)).\n";
  422.     }
  423. }
  424. $close($fp);
  425. ?>

Documentation generated on Mon, 11 Mar 2019 10:14:18 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.