Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
dpovshed committed Oct 24, 2016
0 parents commit 009f562
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 0 deletions.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# United States Zipcode Lookup database

This is a Laravel 5 package for easy and simple lookup for geographic data by U.S. zipcode. While there are a few nice solutions like http://zippopotam.us for online lookup, sometimes i might be preferable to have all the data locally.

The package using the data from http://federalgovernmentzipcodes.us/ . There is an Artisan command implemented to perform automatic update of the data.

## Installation

### Step 1

Add this to your `composer.json`

{
"require": {
"dpovshed/zipus": "1.*"
}
}

then install package as usual.

### Step 2

Run the following command:

php artisan zipus-import

If everything is fine, as a result in your cache directory you'll have JSONed arrays with the data.

If your application is in debug mode, i.e. APP_DEBUG is set to true in the .env file, you may visit
http://example.com/zipus-test to check the lookup process.

## Usage

Lookup functionality is provided as a service, so use construction like

$city = app()->make('zipcode')->getCity('10282');

to get city name for a particular zipcode. Result is a string with a city name.
To get the all data available please use function named getData:

$city = app()->make('zipcode')->getData('10282');

You will get a result like:
[
'ZipCodeType' => string 'STANDARD' (length=8)
'City' => string 'NEW YORK' (length=8)
'State' => string 'NY' (length=2)
'LocationType' => string 'PRIMARY' (length=7)
'Lat' => string '40.71' (length=5)
...
];

All the elements of an array would be named exactly as a column in original CSV file form http://federalgovernmentzipcodes.us . Please note that package used a database where a patricular zipcode is resolved only to one primary address.

In case passed string is not a valid U.S. zipcode, as a result you will get unchanged zipcode with getCity() and an empty array with getData().
24 changes: 24 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "dpovshed/zipus",
"description": "US zipcode static database.",
"type": "library",
"keywords": ["zip code","usa","geodata"],
"homepage": "https://github.com/dpovshed/zipus",
"license": "MIT",
"authors": [
{
"name": "Dennis Povshedny",
"email": "basturma@gmail.com"
}
],
"require": {
"php": ">=5.6.3",
"illuminate/console": "~5.2"
},
"autoload": {
"psr-4": {
"Dpovshed\\Zipus\\": "src/"
}
},
"minimum-stability": "dev"
}
76 changes: 76 additions & 0 deletions src/Console/Commands/ZipusImport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Dpovshed\Zipus\Console\Commands;

use Illuminate\Console\Command;
use Symfony\Component\Console\Output\OutputInterface;
use League\Flysystem\Exception;

class ZipusImport extends Command
{
const CSVFILE = "http://federalgovernmentzipcodes.us/free-zipcode-database-Primary.csv";

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'zipus-import {--filename=}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Import the primary locations only CSV file from federalgovernmentzipcodes.us';

/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$filename = (($this->option('filename')) ?: self::CSVFILE);
try {
$lines = file($filename);
$headers = explode(',', trim($lines[0]));
$headers = str_replace('"', '', $headers);
$countColumns = count($headers);
$countMalformed = 0;
$zipusCity = [];
$zipusAll = [];
$this->comment("Columns found: $countColumns" . PHP_EOL, OutputInterface::VERBOSITY_VERBOSE);
// Skip first line and first column.
unset($lines[0]);
unset($headers[0]);
foreach ($lines as $line) {
$item = explode(',', trim($line));
$item = str_replace('"', '', $item);
if (count($item) != $countColumns) {
$this->comment("Malformed row, bad number of columns: $line", OutputInterface::VERBOSITY_VERY_VERBOSE);
$countMalformed++;
continue;
}
$zipcode = str_replace('"', '', $item[0]);
$zipusCity[$zipcode] = ucwords(strtolower(str_replace('"', '', $item[2])));
$itemNamed = [];
foreach ($headers as $i => $header) {
$itemNamed[$header] = $item[$i];
}
$zipusAll[$zipcode] = $itemNamed;
}
$filenameCity = storage_path('framework/cache/zipus_city.json');
$filenameAll = storage_path('framework/cache/zipus_all.json');
$jsonCity = json_encode($zipusCity);
$jsonAll = json_encode($zipusAll);
file_put_contents($filenameCity, $jsonCity);
file_put_contents($filenameAll, $jsonAll);
$count = count($lines) - $countMalformed;
$this->comment("Zip data cached locally, $count items.");
}
catch (Exception $e) {
$this->comment(PHP_EOL . 'Import error: ' . $e->getMessage());
}
}
}
16 changes: 16 additions & 0 deletions src/Http/routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

if (config('app.debug')) {
Route::get('/zipus-test', function() {
$zipcode = '10282';
$city = app()->make('zipcode')->getCity($zipcode);
echo "Lookup for \"ucword'ed\" City name for zipcode $zipcode: ";
var_dump($city);
echo PHP_EOL;

$data = app()->make('zipcode')->getData($zipcode);
echo "Lookup for all data for zipcode $zipcode: ";
var_dump($data);
echo PHP_EOL;
});
}
80 changes: 80 additions & 0 deletions src/Providers/ZipServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

namespace Dpovshed\Zipus\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Routing\Router;
use Dpovshed\Zipus\Console\Commands\ZipusImport;
use Dpovshed\Zipus\ZipCityLookup;

class ZipServiceProvider extends ServiceProvider
{
/**
* Create a new service provider instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
*/
public function __construct($app)
{
$this->defer = !config('app.debug');
parent::__construct($app);
}

/**
* Boot and configure the application paths
*
* @return void
*/
public function boot()
{
$this->setupRoutes($this->app->router);

// Register commands
$this->commands('command.zipus.import');
}

/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->singleton('zipcode', function ($app) {
return new ZipCityLookup;
});

$this->app->singleton('command.zipus.import', function ($app) {
return new ZipusImport;
});
}

/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['zipcode', 'command.zipus.import'];
}


/**
* Define the routes for the application.
*
* @param \Illuminate\Routing\Router $router
*
* @return void
*/
protected function setupRoutes(Router $router)
{
$router->group(
['namespace' => 'Dpovshed\Zipus\Http\Controllers'],
function ($router) {
include __DIR__.'/../Http/routes.php';
}
);
}

}
59 changes: 59 additions & 0 deletions src/ZipCityLookup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Dpovshed\Zipus;

use Log;

class ZipCityLookup
{

/**
* @var array $data
*
* All the details for zipcode.
*/
static protected $data = false;

/**
* @var array $cities
*
* Mapping zipcode to city name.
*/
static protected $cities = false;

/**
* @param string $zip
* Zip code to lookup.
*
* @return string
* City name if found, original zipcode otherwise.
*/
public function getCity($zip)
{
if (empty(self::$cities)) {
self::$cities = json_decode(file_get_contents(storage_path('framework/cache/zipus_city.json')), true);
}
if (isset(self::$cities[$zip])) {
return self::$cities[$zip];
}
return $zip;
}

/**
* @param string $zip
* Zip code to lookup.
*
* @return array
* If zipcode is known, return all the data. Otherwise return empty array.
*/
public function getData($zip)
{
if (empty(self::$data)) {
self::$data = json_decode(file_get_contents(storage_path('framework/cache/zipus_all.json')), true);
}
if (isset(self::$data[$zip])) {
return self::$data[$zip];
}
return [];
}
}

0 comments on commit 009f562

Please sign in to comment.