Why do we want to detect the city?

One trend we’ve observed with forms is that users often have to fill in many fields that the software is already able to figure out, such as the country, city and cardholder’s name. To make the process more user-friendly by asking for information only once, we can detect the city once the user has submitted their area code. This reduces effort for the user and minimizes spelling mistakes.

The city-detection feature in Responsive Checkout is based on the same process as the country-detection feature, except done with the area code. To detect the city, we use the MaxMind database. It contains almost a million area codes from all over the world, each one linked to the corresponding country and city.

The search function works similar to the one for country detection. The data is stored in a file, sorted with a constant row size, which enables binary search:

05066 |DZ|Ouled Si Slimane 
05067 |DZ|Chaaba 

There is a small problem: Multiple countries could use the same area codes. To solve this, the search database returns the range of data in the file with the area code and, from among them,searches for the given area code linearly within the given country.

How we implemented that?

Below you can find the code that enables the city detection in Responsive Checkout.

 * Find city based on area code, limited to selected countries.
 * @param $postcode
 * @param array $country
 * @return array
 public function findCity($postcode, $country = array()) {
   $result = array();
   $file = fopen(self::FILE_NAME, 'rb');
	 if ($file) {
	   // Find index of matching area code (any).
	   $index = $this->findInFile($file, $postcode, self::MIN_INDEX, self::MAX_INDEX);
	   if (!is_null($index)) {
		// Got it! Now find range of area codes in file (we could have more than 1!)
		 $minIndex = $this->findMin($file, $index - 1, $postcode);
		 $maxIndex = $this->findMax($file, $index + 1, $postcode);
		 // Iterate through range and add to result only cities from specified countries
		 $count = count($country);
		  for ($index = $minIndex; $index <= $maxIndex; $index++) {
			 $data = $this->readData($file, $index);
			 if ($count && !in_array($data['country'], $country)) {
		 $result[] = $data;
 	return $result;
List of articles