A PHP package for searching Portugal zipcodes using a SQLite database. This package provides tools to import zipcode data from CSV files and perform searches based on zipcode, locality, or street name.
- SQLite database for efficient storage and querying
- Symfony Console commands for easy interaction
- Import data from standard Portugal zipcode CSV files
- Search by zipcode, locality, or street name
- Detailed results with district and municipality information
- Facade implementation for programmatic usage
composer require tuxonice/pt-zipcode-finderThe zipcode data can be obtained from the CTT website. You need register and log in to access the data.
The downloaded file is a zip file containing the following files:
| File | Description | Rename to |
|---|---|---|
| concelhos.txt | Municipalities list | municipalities.csv |
| distritos.txt | Districs list | districts.csv |
| todos_cp.txt | Zipcodes list | zipcodes.csv |
| leiame.txt | Readme file |
Extract the files from the zip file and rename them to the expected names.
Before you can search for zipcodes, you need to import the data from the CSV files:
# Import from a CSV directory into a database directory
# Syntax: php bin/zipcode-importer import <csv-source-dir> <database-dir> [--dbname=zipcodes]
# Example: import CSVs from ./source-dir and create ./data-dir/zipcodes.sqlite
php bin/zipcode-importer import source-dir data-dir --dbname=zipcodes
# Using absolute paths
php bin/zipcode-importer import /abs/path/to/csv /abs/path/to/data --dbname=mydbYou can use the ZipcodeFinder facade in your PHP code for programmatic access to the zipcode data:
<?php
require_once 'vendor/autoload.php';
use Tlab\PtZipcodeFinder\Facade\ZipcodeFinder;
// Initialize the facade with the database path created by the import step
$finder = new ZipcodeFinder(__DIR__ . '/data/zipcodes.sqlite');
// Search by zipcode
$zipcodeResults = $finder->searchByZipcode('1000');
// Search by locality
$localityResults = $finder->searchByLocality('porto');
// Search by street name
$streetResults = $finder->searchByStreet('liberdade');
// Search across all fields
$allResults = $finder->searchAll('lisboa');
// Iterate ArrayCollection of Zipcode models
foreach ($zipcodeResults as $zipcode) {
echo $zipcode->getFullZipcode() . ' - ' . $zipcode->getPostalDesignation() . PHP_EOL;
}Here's how you might integrate the ZipcodeFinder with a web application:
<?php
require_once 'vendor/autoload.php';
use Tlab\PtZipcodeFinder\Facade\ZipcodeFinder;
// Handle form submission
if (isset($_POST['search'])) {
$query = $_POST['query'] ?? '';
$type = $_POST['type'] ?? 'all';
$finder = new ZipcodeFinder(__DIR__ . '/data/zipcodes.sqlite');
// Perform search based on type
switch ($type) {
case 'zipcode':
$results = $finder->searchByZipcode($query);
break;
case 'locality':
$results = $finder->searchByLocality($query);
break;
case 'street':
$results = $finder->searchByStreet($query);
break;
case 'all':
default:
$results = $finder->searchAll($query);
break;
}
// Display count
echo 'Found ' . $results->count() . ' results';
}The package uses three main data files:
todos_cp.txt- Main zipcode data with 17 fields per linedistritos.txt- District codes and namesconcelhos.txt- Municipality codes and names
The data format is described in detail in the leiame.txt file included with the data files.
The package creates three tables in the SQLite database:
districts- District informationmunicipalities- Municipality informationzipcodes- Main zipcode data
This package includes a Docker environment to make development and testing easier.
docker-compose build# Run the test service (installs dependencies)
docker-compose run test
# Run the app service (provides a shell)
docker-compose run app
docker-compose run app vendor/bin/phpunit
# Import data
docker-compose run app importdocker-compose run testMIT