Source for file buildMetarDB.php
Documentation is available at buildMetarDB.php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
* This script downloads, saves and processes the textfiles needed for
* the building the databases to enable searching for METAR stations.
* You can download the locations, which is a database of about 12000 world-
* wide locations, which can be used to determine the coordinates of your
* city or you can download a file with 6500 airports providing the metar
* data. This database is used for the next-METAR-station search. Please see
* the apropriate documentation in the Services_Weather_Metar class.
* For usage of this script, invoke with '-h'.
* Copyright (c) 2005-2011, Alexander Wirtz
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* o Neither the name of the software nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* @package Services_Weather
* @subpackage buildMetarDB
* @author Alexander Wirtz <eru@php.net>
* @copyright 2005-2011 Alexander Wirtz
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @link http://pear.php.net/package/Services_Weather
* @link http://weather.noaa.gov/tg/site.shtml
// {{{ natural constants and measures
define("SERVICES_WEATHER_RADIUS_EARTH", 6378.15 );
// {{{ Services_Weather_checkData()
* Services_Weather_checkData
* Checks the data for a certain string-length and if it either consists of
* a certain char-type or a string of "-" as replacement.
* @param array $data The data to be checked
* @param array $dataOrder Because the data is in different locations, we provide this
foreach ($dataOrder as $type => $idx) {
if ((strlen($data[$idx]) != $len) || (!$func($data[$idx]) && ($data[$idx] != str_repeat("-", $len)))) {
// {{{ Services_Weather_getNextArg()
* Services_Weather_getNextArg
* Checks, if the next argument is a parameter to a predecessing option.
* Returns either that parameter or false, if the next argument is an option
* @param int $c Internal argument counter
if ((($c + 1 ) < $_SERVER["argc"]) && ($_SERVER["argv"][$c + 1 ]{0 } != "-")) {
return $_SERVER["argv"][$c];
// First set a few variables for processing the options
$dbName = "servicesWeatherDB";
// Iterate through the arguments and check their validity
for ($c = 1; $c < $_SERVER["argc"]; $c++ ) {
switch ($_SERVER["argv"][$c]{1 }) {
// location-mode, if another mode is set, bail out
$tableName = "metarLocations";
$dataOrder = array ("b" => 0 , "s" => 1 , "i" => 2 );
$tableName = "metarAirports";
$dataOrder = array ("b" => 1 , "s" => 2 , "i" => 0 );
// file-flag was provided, check if next argument is a string
// If you download the file, it will be saved to disk
// The type of the DB to be used
// The protocol of the DB to be used
// The name of the DB to be used
// The user of the DB to be used
// The password of the DB to be used
// The host of the DB to be used
foreach ($options as $option) {
$dbOptions[$optPair[0 ]] = $optPair[1 ];
for ($i = 1; $i < strlen($_SERVER["argv"][$c]); $i++ ) {
if ($_SERVER["argv"][$c]{$i} == "v") {
// argument not valid, bail out
echo "Invalid option: '". $_SERVER["argv"][$c]. "'\n";
if (!$modeSet || $printHelp) {
echo "Usage: ". basename($_SERVER["argv"][0 ], ".php"). " -l|-a [options]\n";
echo " -l build locationsDB\n";
echo " -a build airportsDB\n";
echo " -f <file> use <file> as input\n";
echo " -s save downloaded file to disk\n";
echo " -t <dbtype> type of the DB to be used\n";
echo " -r <dbprotocol> protocol -----\"----------\n";
echo " -d <dbname> name ---------\"----------\n";
echo " -u <dbuser> user ---------\"----------\n";
echo " -p <dbpass> pass ---------\"----------\n";
echo " -h <dbhost> host ---------\"----------\n";
echo " -o <dboptions> options ------\"----------\n";
echo " in the notation option=value,...\n";
echo " -v display verbose debugging messages\n";
echo " multiple -v increases verbosity\n";
// check, if zlib is available
$userFile, "nsd_". $filePart, "nsd_". $filePart. ".txt",
"nsd_". $filePart. ".gz", "http://weather.noaa.gov/data/nsd_". $filePart. ".gz"
$userFile, "nsd_". $filePart, "nsd_". $filePart. ".txt",
"http://weather.noaa.gov/data/nsd_". $filePart. ".txt"
// then try to open a source in the given order
foreach ($files as $file) {
$fp = @$open($file, "rb");
echo "Services_Weather: Using '". $file. "' as source.\n";
// apparently we want to save the file, and it's a remote file
$fps = @$open($file, "wb");
echo "Services_Weather: Couldn't save to '". $file. "'!\n";
echo "Services_Weather: Saving source to '". $file. "'.\n";
// read from filepointer and save to disk
while ($line = fread($fp, 1024 )) {
// unfortunately zlib does not support r/w on a resource,
// so no rewind -> move $fp to new file on disk
$fp = @$open($file, "rb");
// no files found, or connection not available... bail out
die ("Services_Weather: Sourcefile nsd_". $filePart. " not found!\n");
$dsn = $dbType. "://". $dbUser. ":". $dbPass. "@". $dbProt. "+". $dbHost. "/". $dbName;
$db = DB ::connect ($dsninfo, $dbOptions);
echo "Services_Weather: Connection to DB with '". $dbType. "://". $dbUser. ":PASS@". $dbHost. "/". $dbName. "' failed!\n";
die ($db->getMessage (). "\n");
// Test, if we have to swipe or create the table first
$select = "SELECT * FROM ". $tableName;
$result = $db->query ($select);
if (DB ::isError ($result)) {
$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)";
echo "Services_Weather: Creating table '". $tableName. "'.\n";
$result = $db->query ($create);
if (DB ::isError ($result)) {
die ($result->getMessage (). "\n");
$delete = "DELETE FROM ". $tableName;
echo "Services_Weather: Deleting from table '". $tableName. "'.\n";
$result = $db->query ($delete);
if (DB ::isError ($result)) {
die ($result->getMessage (). "\n");
// Ok, DB should be up and running now, let's shove in the data
while ($data = fgetcsv($fp, 1000 , ";")) {
echo "Services_Weather: Invalid data in file!\n";
echo "\tLine ". ($line + 1 ). ": ". implode(";", $data). "\n";
// calculate latitude and longitude
// it comes in a ddd-mm[-ss]N|S|E|W format
$coord = array ( "latitude" => 7 , "longitude" => 8 );
foreach ($coord as $latlon => $aId) {
preg_match("/^(\d{1,3})-(\d{1,2})(-(\d{1,2}))?([NSEW])$/", $data[$aId], $result);
$ {$latlon} = 0; $factor = 1;
foreach ($result as $var) {
$ {$latlon} += $var / $factor;
// Calculate the cartesian coordinates for latitude and longitude
// Check for elevation in data
$elevation = is_numeric($data[11 ]) ? $data[11 ] : 0;
// integers: convert "--" fields to null, empty fields to 0
foreach (array ($dataOrder["b"], $dataOrder["s"], 6 ) as $i) {
if (strpos($data[$i], "--") !== false ) {
} elseif ($data[$i] == "") {
foreach (array ($dataOrder["i"], 3 , 4 , 5 ) as $i) {
$data[$i] = $db->quote ($data[$i]);
$insert = "INSERT INTO ". $tableName. " VALUES(". ($line - $error). ",";
$insert .= $data[$dataOrder["b"]]. ",". $data[$dataOrder["s"]]. ",";
$insert .= $data[$dataOrder["i"]]. ",". $data[3 ]. ",". $data[4 ]. ",";
$insert .= $data[5 ]. ",". $data[6 ]. ",". round($latitude, 4 ). ",";
$insert .= round($longitude, 4 ). ",". $elevation. ",". round($x, 4 ). ",";
$result = $db->query ($insert);
if (DB ::isError ($result)) {
echo "\tLine ". ($line + 1 ). ": ". $insert. "\n";
echo $result->getMessage (). "\n";
if ($verbose > 0 || $error > 0 ) {
echo "Services_Weather: ". ($line - $error). " ". $tableName. " added ";
echo "to database '". $dbName. "' (". $error. " error(s)).\n";
Documentation generated on Mon, 11 Mar 2019 15:50:57 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|