Thursday, October 24, 2013

Java Cryptography Architecture and common encryption usages

JCA can be really tricky to perform simple, common tasks. After latest usage of java cryptography I'd like to present below the simplest usage of cryptography methods, involving mainly symmetric (AES) and asymmetric (RSA/DSA) encryption plus some helper methods.

I don't use specific JCA provider, but let it choose appropriate one. If you want to select specific provider, you must provide additional parameters, usually to getInstance() methods of various algorithm elements. In examples I use RSA1024 (you might change it to DSA) and AES256.

Note about AES256 - to enable this for your VM you need Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files. With default policy you can only use AES128.

The amount of "things can go wrong" is pretty big, so if you write your own cryptography util, there's a good thing to wrap JCA exception in something that can be easy caught in the user code.

public class EncryptionException extends Exception {
 
 public EncryptionException() {
 }
 
 public EncryptionException(String message) {
  super(message);
 }
 
 public EncryptionException(String message, Throwable cause) {
  super(message, cause);
 }
 
 public EncryptionException(Throwable cause) {
  super(cause);
 }
 
}

Firstly a simple thing, BASE64 encoding wrappers (to be able to switch implementation, what of course will be never used):

public static String encodeBase64(byte[] data) {
 return new BASE64Encoder().encode(data);
}
 
public static byte[] decodeBase64(String data) throws EncryptionException {
 try {
  return new BASE64Decoder().decodeBuffer(data);
 } catch (IOException e) {
  throw new EncryptionException("Error decoding base64", e);
 }
}

How to generate RSA 1024 keys with SecureRandom:

/**
 * Generates new keypair
 */
public static KeyPair generateKeys() throws EncryptionException {
 try {
  KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
  SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
  keyGen.initialize(1024, random);
  return keyGen.generateKeyPair();
 } catch (Exception e) {
  throw new EncryptionException("Error generating keypair", e);
 }
}

How to encrypt with asymmetric key (public or private):

/**
 * Encrypts data with key
 */
public static byte[] encryptAsymmetric(Key key, byte[] data)
throws EncryptionException {
 try {
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.ENCRYPT_MODE, key);
  return cipher.doFinal(data);
 } catch (Exception e) {
  throw new EncryptionException("Error key encrypting", e);
 }
}

For above, how to decrypt with asymmetric key (public or private, the different one than used for encryption):

/**
 * Decrypts data with key
 */
public static byte[] decryptAsymmetric(Key key, byte[] data)
throws EncryptionException {
 try {
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.DECRYPT_MODE, key);
  return cipher.doFinal(data);
 } catch (Exception e) {
  throw new EncryptionException("Error key decrypting", e);
 }
}

How to build symmetric key for AES256 encryption:

/**
 * Builds a random secret key for symmetric algorithm
 */
public static Key buildSymmetricKey() throws EncryptionException {
 try {
  KeyGenerator keyGen = KeyGenerator.getInstance("AES");
  keyGen.init(256, SecureRandom.getInstance("SHA1PRNG"));
  return keyGen.generateKey();
 } catch (Exception e) {
  throw new EncryptionException("Error generating secret key", e);
 }
}

The building of the AES key based on user password is a little tricky. You need to have a salt (N-bytes array) that is used to generate a proper AES key (with a proper length). If you need to recover this key in the future, using just the same user password, you need to use exactly the same salt, so it's probably best to hardcode it somewhere and use for further keys generation (random 8 bytes):

private static byte[] SALT = new byte[]{
 (byte) 0xa1, (byte) 0x22, (byte) 0x33, (byte) 0xa4,
 (byte) 0x11, (byte) 0x22, (byte) 0x12, (byte) 0x22};
 
/**
 * Builds a secret key for symmetric algorithm recoverable by password
 */
public static Key buildSymmetricKey(String password)
throws EncryptionException {
 try {
  SecretKeyFactory factory =
   SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
  KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, 256,
   256);
  SecretKey tmp = factory.generateSecret(spec);
  return new SecretKeySpec(tmp.getEncoded(), "AES");
 } catch (Exception e) {
  throw new EncryptionException("Error encoding secret key", e);
 }
}

Now, how to encrypt the arbitrary length data block with AES:

/**
 * Encrypts data with symmetric algorithm and password
 */
public static byte[] encryptSymmetric(Key key, byte[] data)
throws EncryptionException {
 try {
  Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  cipher.init(Cipher.ENCRYPT_MODE, key);
  return cipher.doFinal(data);
 } catch (Exception e) {
  throw new EncryptionException("Error symmetric encrypting", e);
 }
}

Note, that I use ECB as block cipher mode of operation. This is not the safest one, better would be CBC (refer wikipedia). But if you need to recover your data only by AES key, you can't do this. To recover from CBC you need to store your CBC initialization vector together with the password. So, I use ECB for this simple example, to make all it working only with keys.

The decryption for above symmetric encryption is similar:

/**
 * Decrypts data with symmetric algorithm and password
 */
public static byte[] decryptSymmetric(Key key, byte[] data)
throws EncryptionException {
 try {
  Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  cipher.init(Cipher.DECRYPT_MODE, key);
  return cipher.doFinal(data);
 } catch (Exception e) {
  throw new EncryptionException("Error symmetric descrypting", e);
 }
}

This is all about working encryption/decryption. Now about storing the keys in db. If you'd like to use BASE64 encoding or even to hold everything in BLOB-s, methods below will be useful.

Converting the key to BASE64 is easy:

/**
 * Converts key to base64 encoded string
 */
public static String keyToString(Key key) {
 return encodeBase64(key.getEncoded());
}

But recovering the key from BASE64 or byte[] is another tricky part:

/**
 * Converts base64 encoded string to assymetric key
 *
 * @param publicKey if true returns public key, private key otherwise
 */
public static Key asymmetricKeyFromString(String s, boolean publicKey)
throws EncryptionException {
 return asymmetricKeyFromBytes(decodeBase64(s), publicKey);
}
 
/**
 * Converts bytes to assymetric key
 *
 * @param publicKey if true returns public key, private key otherwise
 */
public static Key asymmetricKeyFromBytes(byte[] bytes, boolean publicKey)
throws EncryptionException {
 try {
  if (publicKey) {
   return KeyFactory.getInstance("RSA").generatePublic(
    new X509EncodedKeySpec(bytes));
  } else {
   return KeyFactory.getInstance("RSA").generatePrivate(
    new PKCS8EncodedKeySpec(bytes));
  }
 } catch (Exception e) {
  throw new EncryptionException("Can't decode assymetric key", e);
 }
}

The same for symmetric key looks much easier:

/**
 * Converts base64 encoded string to symmetric key
 */
public static Key symmetricKeyFromString(String s) throws
EncryptionException {
 return symmetricKeyFromBytes(decodeBase64(s));
}
 
/**
 * Converts bytes to symmetric key
 */
public static Key symmetricKeyFromBytes(byte[] bytes)
throws EncryptionException {
 return new SecretKeySpec(bytes, "AES");
}

Sometimes you also need to convert your private/public keys to PEM format for exporting. Without bouncycastle you need your own method for this:

public static String getPem(Key key) {
 StringBuilder sb = new StringBuilder();
 if (key instanceof PrivateKey || key instanceof PublicKey)
  sb.append(String.format("-----BEGIN %s %s KEY-----\n", "RSA",
   key instanceof PublicKey ? "PUBLIC" : "PRIVATE"));
 else
  sb.append("-----BEGIN KEY-----");
 sb.append(encodeBase64(key.getEncoded()));
 if (key instanceof PrivateKey || key instanceof PublicKey)
  sb.append(String.format("\n-----END %s %s KEY-----", "RSA",
   key instanceof PublicKey ? "PUBLIC" : "PRIVATE"));
 else
  sb.append("\n-----END KEY-----");
 return sb.toString();
}

And this was just last example of simple Java cryptography API.

Friday, October 18, 2013

Convert document to HTML with Apache Tika

Apache Tika has a wonderful feature, that can transform source document (PDF, MSOffice, Open Office etc.) into HTML during content extraction. Sound pretty simple, but I've dug through a lot of google search results and I can't find a simple working example anywhere.

But, here is a working snippet I extracted from tika-app:

ByteArrayOutputStream out = new ByteArrayOutputStream();
SAXTransformerFactory factory = (SAXTransformerFactory)
 SAXTransformerFactory.newInstance();
TransformerHandler handler = factory.newTransformerHandler();
handler.getTransformer().setOutputProperty(OutputKeys.METHOD, "html");
handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
handler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8");
handler.setResult(new StreamResult(out));
ExpandedTitleContentHandler handler1 = new ExpandedTitleContentHandler(handler);
 
tikaParser.parse(new ByteArrayInputStream(file), handler1, new Metadata());
return new String(out.toByteArray(), "UTF-8");
 
It works pretty nicely. Here is an example of original MSOffice document:

And here how the above looks in my webapp as HTML preview:


Wednesday, October 16, 2013

Play Framework on Heroku and custom dependencies

Today I was playing a little about Play Framework. This is very nice lightweight application framework for Java and Scala. I was trying to make an app and deploy to Heroku, which is a PaaS platform where you can host you Play applications for free (with some limitations of course).

And here the problem happened. For the project I use my own lib, managed by maven, let's say:

<groupId>com.blogspot.lifeinide</groupId>
<artifactId>mylib</artifactId>
<version>1.0-SNAPSHOT</version>
 
Now, how to use this lib for local Play project and then deploy it to Heroku with this dependency too? I don't want to put each time the new version to Play lib/ folder (it can be anyway cleaned up by "play dependencies") because this is still under development too. How to automate this? It is a bit tricky.

Play Framework uses its own dependency resolving mechanism based on dependencies.yml file, but internally it uses maven too. The key here is to configure appropriately dependencies.yml to use different maven repository, for example:

require:
    - play 1.2.5.3
    - com.blogspot.lifeinide -> mylib 1.0-SNAPSHOT
 
repositories:
    - jboss:
        type: iBiblio
        root: "file://${user.home}/.m2/repository/"
        contains:
            - com.blogspot.lifeinide -> *
 

Now you can "mvn install" your project to your local maven repository, and Play dependency system can find it.

But Heroku can't...

But here is the trick for Heroku. In my heroku project I have following structure:

|- heroku    // my heroku project
  |- .git    // git repository for heroku deployment
  |- repo    // this is my local maven repository

Now for the mylib project pom.xml I can configure appropriate deployment:

<build>
  <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.7</version>
        </plugin>
    </plugins>
</build>
 
<distributionManagement>
  <repository>
    <id>local-lib-unmanaged</id>
    <name>local-lib-unmanaged</name>
    <url>file:///path/to/heroku/repo</url>
  </repository>
</distributionManagement>

So it basically deploys the artifact to my local "repo" repository under heroku project on "mvn deploy". Now the changes in dependencies.yml:

require:
    - play 1.2.5.3
    - com.blogspot.lifeinide -> mylib 1.0-SNAPSHOT
 
repositories:
    - jboss:
        type: iBiblio
        root: "file://${application.path}/repo/"
        contains:
            - com.blogspot.lifeinide -> *

And here you are. After adding the "repo" to git and pushing all this stuff to Heroku, it can resolve dependencies.

Monday, October 7, 2013

SOA vs. Domain design and OpenSessionInThreadExecution pattern

This article describes some complementation for Open Session In View pattern for Java/Spring. But first I want to show just my point of view about the pattern itself.

Many people consider this as an anti-pattern and tell that it never should be used. I think exactly opposite, and here are some explanations.

I code java (JEE) almost 10 years and in general after this experience I can tell that there are two architectures for Java webapps which I worked in (and many variations of course): service oriented architecture (or SOA/service design) and domain driven design (DDD).

Service oriented architecure is a perflectly layered application, with each layer with its own, and only one responsibility: we mostly have views, controllers, services and daos. A lot of people encourage this design, as the only valid one. It indeed looks very good on the paper and in diagrams - this is the cleanest one. But here are my experiences in working with such applications.

I'm talking about standard design with such design guidelines (the most common):
  • DAOs handle with persistence layer using Hibernate/JPA as the low level DB access API
  • services provide business interfaces, and uses DAOs internally
  • the usual session and transaction model is session-per-transaction, and transactions are established  by AOP, when service methods are invoked
Second thing is that I'm talking about standard small-medium size webapps, they can be web portals or business application, they can be clustered using eg. standard tomcat clustering with load balancer. But I'm not talking about very big systems eg. for banking with 30 developers team and 2 mln of code lines, working on the server farm and integrating inside 15 standalone systems for various purposes. For such requirements I think the SOA is the right choice.

Now, what is wrong with this design for me? These projects, where we used such design were unnecessarily HUGE. The development team had to be much bigger than in DDD, the simple modifications to the application took a lot of hours and people spent 80% of time for doing mokey jobs, like moving data from one type of objects to another or struggling with LazyInitializationException. Sincerely, if I had chosen this design few years ago when I created my own application, I would have been out of the market already. I already know people who give up Java, and switched to different techs (like Python or Ruby) because "Java became the technology where you cannot do anything efficiently". I believe this is not true, this is only the design problem.

Where does all this bloat come from? The main problem here is exactly the hibernate session management design. I consider that almost 90% of this bloat code come from this way of handling with Hibernate. I think all this design was created when there was no sensible ORM yet, but when it appeared, people just don't understand how it could help to create applications really rapidly, using all benefits of ORM. And to create them with 20% of original team, and to have the product that really quickly can answer for the constantly changing requirements from the market.

So, what are my problems with SOA? Here are they:
  1. Hibernate gives you the database abstraction, which is the implementation of DAO pattern itself. I cannot undestand why still to write yet another DAO layer, doing the same things as Hibernate already does (the DAO over DAO). If you resign from this, you have a one pretty big layer less, what reduce your code significantly. And still the DAO is preserved - you can always switch to another database implementation changing the Hibernate engine (this is what the DAO is for).
  2. If you spent a lot of time to design your beautiful domain model, why to give up using these objects in your whole application, and to develop another structure of objects? This problem comes from the session management design. If you close you session after leaving service layer, you can't rely on your domain objects anymore. You need to develop another structure of DTO objects and use DTO in higher layers. You need to develop also a lot of conversion code as well, which tosses the data between the Domain and DTO objects (in both ways). You finally end up with hundred of tons of code, two objects model hierarchies that looks almost exactly the same (Domain and DTO), that might just not be right there, if another model of session management had been choosen.
  3. Another problem that if you write the standard web application, I mean the app which has the HTML user interface etc. (not pure service application, like web-services app only),  the service layer becomes quickly very artifical and cluttered. For example let's say that I have the BlogEntry entity with collections of Comment. What is problem with this? If you have eg. service method:
    BlogEntryDTO getBlogEntry(long id) {..}
    What version of DTO object you should return from such service - with filled lazy comments collection or not? There is some client code that needs these comments, and others not. So, should you always load comments with another SQL, even for the BlogEntry entity usage for the client code which doesn't need them? Hmm... no, and you finally end up with:
    BlogEntryDTO getBlogEntry(long id) {..} 
    BlogEntryDTO getBlogEntryWithComments(long id) {..}
    And with another dozen of getBlogEntry() methods in a service, plus fifty other services. Finally to do a simple thing you need to dig through hundreds of code lines, to find what you exactly need (or write another getBlogEntry() method if you can't).
  4. Another example is getting collections from services. Let's consider a simple one:
    List<BlogEntryDTO> getUserBlogEntries(long userid) {..}
    Looks nice and clean... but, wait a moment. We also needs the count(*) calculation and limits for pagination, and the sorting capability as well. How many method do we need to write more to achieve this? It's crazy.
And how does it look in the DDD design?
  1. You don't have to write the DAO layer. You may use your Hibernate DAO. This doesn't prevent you from having nice and well designed DAO layer. What you exactly need is the Session API and @NamedQueries for fetching items by queries.
  2. Your service layer doesn't close the Session after each method invocation, but it's held opened to the end of the request. You don't have to write this unnecessary DTO and conversion code. This doesn't prevent you from having nice and well designed service layer.
  3. You don't bother about this. If you client code decides that it needs comments, it invokes getComments() and have them on demand, because session is still opened.
  4. You also don't bother about this. You can use Query or Criteria objects to transfer collections from the service layer, and you can parametrize them later, depending on what your controller layer wants to achieve.
For the people who advise anyway to use SOA, I can tell that I know that DDD is not a pure layered solution. But greater benefits for me is to have an application that have 30% of original (SOA) lines of code (and all benefits from this - time and cost of development, time and cost of modification, testing etc), than have a big bloat, but "pure layered" medal on my chest.

Of course, every pot has two handles. Now few words about when the SOA might be better than DDD in my opinion. It's when you have a big part of application, where you don't handle with web requests (like standard user request, or webservice request), but the work is done in internal threads (eg. schedulers, ESB listeners etc). DDD is highly bound to open-session-in-view pattern, usualy done by OpenSessionInViewFilter (eg. from the Spring) and the holding session opened just don't work for internal threads. So in DDD you can imagine that you may have inconsistent design, because you need to handle with service layer in different way from request-bound threads and from internal threads. While in SOA, if you already developed all this stuff required to implement this pattern, everything is handled in the same way from both kinds of threads. Well, you're right, but...

I have at least two solutions for this problem. The internal mechanisms usually use just some subset of your total business logic (like receiving tasks from some server and putting them to the db periodically). You can easily create small and thin layer of services, dedicated to work with internal threads, and expose the subset of logic that they need, in these services. Your internal services can be designed in standard SOA pattern, ie. to have session per transaction and AOP-ly defined transaction boundaries on methods. Your scheduler or whatever else can always start the work from some service method invocation, that does its job.

Another solution is my OpenSessionInThreadExecution pattern, which is just the remake of OpenSessionOnViewFilter from Spring. It assumes, that you always have some entry point in some background tasks, where you start doing you background work (like Runnable.run()) - and this is perflectly true because somewhere you join to the internal thread with your logic. Using this bean you can simply wrap your execution with Runnable, and pass to the execute() method, to be executed with opened session throughout whole execution. Here is the code:


package com.blogspot.lifeinide;
 
import org.apache.log4j.Logger;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
 
/**
 * This is a util class to keep session opened during whole single thread  
 * execution (like scheduler or mule service thread), works in the same manner 
 * as {@link OpenSessionInViewFilter}.
 */
public class OpenSessionInThreadExecution implements InitializingBean {
 
  protected static final Logger logger = 
    Logger.getLogger(OpenSessionInThreadExecution.class);
  protected static OpenSessionInThreadExecution instance = null;
 
  protected boolean singleSession = true;
  protected FlushMode flushMode = FlushMode.MANUAL;
  protected SessionFactory sessionFactory;
 
  @Override
  public void afterPropertiesSet() throws Exception {
    if (instance == null)
      instance = this;
    else
      throw new IllegalStateException(
        "OpenSessionInThreadExecution should be defined as " +
        "the only one singleton bean.");
  }
 
  public SessionFactory getSessionFactory() {
    return sessionFactory;
  }
 
  @Required
  public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
  }
 
  /**
   * Set whether to use a single session for each request. Default is "true".
   * <p>If set to "false", each data access operation or transaction will use
   * its own session (like without Open Session in View). Each of those
   * sessions will be registered for deferred close, though, actually
   * processed at request completion.
   *
   * @see SessionFactoryUtils#initDeferredClose
   * @see SessionFactoryUtils#processDeferredClose
   */
  public void setSingleSession(boolean singleSession) {
    this.singleSession = singleSession;
  }
 
  /**
   * Return whether to use a single session for each request.
   */
  protected boolean isSingleSession() {
    return this.singleSession;
  }
 
  /**
   * Specify the Hibernate FlushMode to apply to this filter's
   * {@link org.hibernate.Session}. Only applied in single session mode.
   * <p>Can be populated with the corresponding constant name in XML bean
   * definitions: e.g. "AUTO".
   * <p>The default is "MANUAL". Specify "AUTO" if you intend to use
   * this filter without service layer transactions.
   *
   * @see org.hibernate.Session#setFlushMode
   * @see org.hibernate.FlushMode#MANUAL
   * @see org.hibernate.FlushMode#AUTO
   */
  public void setFlushMode(FlushMode flushMode) {
    this.flushMode = flushMode;
  }
 
  /**
   * Return the Hibernate FlushMode that this filter applies to its
   * {@link org.hibernate.Session} (in single session mode).
   */
  protected FlushMode getFlushMode() {
    return this.flushMode;
  }
 
  public void execute(Runnable command) {
    boolean participate = false;
 
    if (isSingleSession()) {
      // single session mode
      if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
        // Do not modify the Session: just set the participate flag.
        participate = true;
      } else {
        logger.debug("Opening single Hibernate Session in " +
          "OpenSessionInViewFilter");
        Session session = getSession(sessionFactory);
        TransactionSynchronizationManager.bindResource(
          sessionFactory, new SessionHolder(session));
      }
    } else {
      // deferred close mode
      if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
        // Do not modify deferred close: just set the participate flag.
        participate = true;
      } else {
        SessionFactoryUtils.initDeferredClose(sessionFactory);
      }
    }
 
    try {
      command.run();
    } finally {
      if (!participate) {
        if (isSingleSession()) {
          // single session mode
          SessionHolder sessionHolder =
            (SessionHolder) TransactionSynchronizationManager.
              unbindResource(sessionFactory);
          logger.debug("Closing single Hibernate Session in " +
            "OpenSessionInViewFilter");
          closeSession(sessionHolder.getSession(), sessionFactory);
        } else {
          // deferred close mode
          SessionFactoryUtils.processDeferredClose(sessionFactory);
        }
      }
    }
  }
 
  /**
   * Get a Session for the SessionFactory that this filter uses.
   * Note that this just applies in single session mode!
   * <p>The default implementation delegates to the
   * <code>SessionFactoryUtils.getSession</code> method and
   * sets the <code>Session</code>'s flush mode to "MANUAL".
   * <p>Can be overridden in subclasses for creating a Session with a
   * custom entity interceptor or JDBC exception translator.
   *
   * @param sessionFactory the SessionFactory that this filter uses
   * @return the Session to use
   * @throws DataAccessResourceFailureException
   *          if the Session could not be created
   * @see org.springframework.orm.hibernate3.SessionFactoryUtils#
   *   getSession(SessionFactory, boolean)
   * @see org.hibernate.FlushMode#MANUAL
   */
  protected Session getSession(SessionFactory sessionFactory) 
  throws DataAccessResourceFailureException {
    Session session = SessionFactoryUtils.getSession(sessionFactory, true);
    FlushMode flushMode = getFlushMode();
    if (flushMode != null) {
      session.setFlushMode(flushMode);
    }
    return session;
  }
 
  /**
   * Close the given Session.
   * Note that this just applies in single session mode!
   * <p>Can be overridden in subclasses, e.g. for flushing the Session before
   * closing it. See class-level javadoc for a discussion of flush handling.
   * Note that you should also override getSession accordingly, to set
   * the flush mode to something else than NEVER.
   *
   * @param session        the Session used for filtering
   * @param sessionFactory the SessionFactory that this filter uses
   */
  protected void closeSession(Session session, SessionFactory sessionFactory) {
    SessionFactoryUtils.closeSession(session);
  }
 
  public static OpenSessionInThreadExecution getInstance() {
    return instance;
  }
 
}
 

Friday, September 20, 2013

Map Accepted-Language language codes to country codes in PHP

Today I needed to perform some small task regarding country detection by Accepted-Language header in PHP. It quickly turned out that there's no (or I cannot find) the reliable source for such mapping. Finally I've found it here.

I parsed it to the php format, that can be used in the code. Here are the sources. First one is a country code to country info mapping:

$countries = array(
  'ad'=>array(
    'iso3'=>'and',
    'name'=>'Andorra',
    'capital'=>'Andorra la Vella',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'ae'=>array(
    'iso3'=>'are',
    'name'=>'United Arab Emirates',
    'capital'=>'Abu Dhabi',
    'currencyCode'=>'aed',
    'currencyName'=>'Dirham',
  ),
  'af'=>array(
    'iso3'=>'afg',
    'name'=>'Afghanistan',
    'capital'=>'Kabul',
    'currencyCode'=>'afn',
    'currencyName'=>'Afghani',
  ),
  'ag'=>array(
    'iso3'=>'atg',
    'name'=>'Antigua and Barbuda',
    'capital'=>"St. John's",
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'ai'=>array(
    'iso3'=>'aia',
    'name'=>'Anguilla',
    'capital'=>'The Valley',
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'al'=>array(
    'iso3'=>'alb',
    'name'=>'Albania',
    'capital'=>'Tirana',
    'currencyCode'=>'all',
    'currencyName'=>'Lek',
  ),
  'am'=>array(
    'iso3'=>'arm',
    'name'=>'Armenia',
    'capital'=>'Yerevan',
    'currencyCode'=>'amd',
    'currencyName'=>'Dram',
  ),
  'ao'=>array(
    'iso3'=>'ago',
    'name'=>'Angola',
    'capital'=>'Luanda',
    'currencyCode'=>'aoa',
    'currencyName'=>'Kwanza',
  ),
  'aq'=>array(
    'iso3'=>'ata',
    'name'=>'Antarctica',
    'capital'=>'',
    'currencyCode'=>'',
    'currencyName'=>'',
  ),
  'ar'=>array(
    'iso3'=>'arg',
    'name'=>'Argentina',
    'capital'=>'Buenos Aires',
    'currencyCode'=>'ars',
    'currencyName'=>'Peso',
  ),
  'as'=>array(
    'iso3'=>'asm',
    'name'=>'American Samoa',
    'capital'=>'Pago Pago',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'at'=>array(
    'iso3'=>'aut',
    'name'=>'Austria',
    'capital'=>'Vienna',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'au'=>array(
    'iso3'=>'aus',
    'name'=>'Australia',
    'capital'=>'Canberra',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'aw'=>array(
    'iso3'=>'abw',
    'name'=>'Aruba',
    'capital'=>'Oranjestad',
    'currencyCode'=>'awg',
    'currencyName'=>'Guilder',
  ),
  'ax'=>array(
    'iso3'=>'ala',
    'name'=>'Aland Islands',
    'capital'=>'Mariehamn',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'az'=>array(
    'iso3'=>'aze',
    'name'=>'Azerbaijan',
    'capital'=>'Baku',
    'currencyCode'=>'azn',
    'currencyName'=>'Manat',
  ),
  'ba'=>array(
    'iso3'=>'bih',
    'name'=>'Bosnia and Herzegovina',
    'capital'=>'Sarajevo',
    'currencyCode'=>'bam',
    'currencyName'=>'Marka',
  ),
  'bb'=>array(
    'iso3'=>'brb',
    'name'=>'Barbados',
    'capital'=>'Bridgetown',
    'currencyCode'=>'bbd',
    'currencyName'=>'Dollar',
  ),
  'bd'=>array(
    'iso3'=>'bgd',
    'name'=>'Bangladesh',
    'capital'=>'Dhaka',
    'currencyCode'=>'bdt',
    'currencyName'=>'Taka',
  ),
  'be'=>array(
    'iso3'=>'bel',
    'name'=>'Belgium',
    'capital'=>'Brussels',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'bf'=>array(
    'iso3'=>'bfa',
    'name'=>'Burkina Faso',
    'capital'=>'Ouagadougou',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'bg'=>array(
    'iso3'=>'bgr',
    'name'=>'Bulgaria',
    'capital'=>'Sofia',
    'currencyCode'=>'bgn',
    'currencyName'=>'Lev',
  ),
  'bh'=>array(
    'iso3'=>'bhr',
    'name'=>'Bahrain',
    'capital'=>'Manama',
    'currencyCode'=>'bhd',
    'currencyName'=>'Dinar',
  ),
  'bi'=>array(
    'iso3'=>'bdi',
    'name'=>'Burundi',
    'capital'=>'Bujumbura',
    'currencyCode'=>'bif',
    'currencyName'=>'Franc',
  ),
  'bj'=>array(
    'iso3'=>'ben',
    'name'=>'Benin',
    'capital'=>'Porto-Novo',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'bl'=>array(
    'iso3'=>'blm',
    'name'=>'Saint Barthelemy',
    'capital'=>'Gustavia',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'bm'=>array(
    'iso3'=>'bmu',
    'name'=>'Bermuda',
    'capital'=>'Hamilton',
    'currencyCode'=>'bmd',
    'currencyName'=>'Dollar',
  ),
  'bn'=>array(
    'iso3'=>'brn',
    'name'=>'Brunei',
    'capital'=>'Bandar Seri Begawan',
    'currencyCode'=>'bnd',
    'currencyName'=>'Dollar',
  ),
  'bo'=>array(
    'iso3'=>'bol',
    'name'=>'Bolivia',
    'capital'=>'Sucre',
    'currencyCode'=>'bob',
    'currencyName'=>'Boliviano',
  ),
  'bq'=>array(
    'iso3'=>'bes',
    'name'=>'Bonaire, Saint Eustatius and Saba ',
    'capital'=>'',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'br'=>array(
    'iso3'=>'bra',
    'name'=>'Brazil',
    'capital'=>'Brasilia',
    'currencyCode'=>'brl',
    'currencyName'=>'Real',
  ),
  'bs'=>array(
    'iso3'=>'bhs',
    'name'=>'Bahamas',
    'capital'=>'Nassau',
    'currencyCode'=>'bsd',
    'currencyName'=>'Dollar',
  ),
  'bt'=>array(
    'iso3'=>'btn',
    'name'=>'Bhutan',
    'capital'=>'Thimphu',
    'currencyCode'=>'btn',
    'currencyName'=>'Ngultrum',
  ),
  'bv'=>array(
    'iso3'=>'bvt',
    'name'=>'Bouvet Island',
    'capital'=>'',
    'currencyCode'=>'nok',
    'currencyName'=>'Krone',
  ),
  'bw'=>array(
    'iso3'=>'bwa',
    'name'=>'Botswana',
    'capital'=>'Gaborone',
    'currencyCode'=>'bwp',
    'currencyName'=>'Pula',
  ),
  'by'=>array(
    'iso3'=>'blr',
    'name'=>'Belarus',
    'capital'=>'Minsk',
    'currencyCode'=>'byr',
    'currencyName'=>'Ruble',
  ),
  'bz'=>array(
    'iso3'=>'blz',
    'name'=>'Belize',
    'capital'=>'Belmopan',
    'currencyCode'=>'bzd',
    'currencyName'=>'Dollar',
  ),
  'ca'=>array(
    'iso3'=>'can',
    'name'=>'Canada',
    'capital'=>'Ottawa',
    'currencyCode'=>'cad',
    'currencyName'=>'Dollar',
  ),
  'cc'=>array(
    'iso3'=>'cck',
    'name'=>'Cocos Islands',
    'capital'=>'West Island',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'cd'=>array(
    'iso3'=>'cod',
    'name'=>'Democratic Republic of the Congo',
    'capital'=>'Kinshasa',
    'currencyCode'=>'cdf',
    'currencyName'=>'Franc',
  ),
  'cf'=>array(
    'iso3'=>'caf',
    'name'=>'Central African Republic',
    'capital'=>'Bangui',
    'currencyCode'=>'xaf',
    'currencyName'=>'Franc',
  ),
  'cg'=>array(
    'iso3'=>'cog',
    'name'=>'Republic of the Congo',
    'capital'=>'Brazzaville',
    'currencyCode'=>'xaf',
    'currencyName'=>'Franc',
  ),
  'ch'=>array(
    'iso3'=>'che',
    'name'=>'Switzerland',
    'capital'=>'Berne',
    'currencyCode'=>'chf',
    'currencyName'=>'Franc',
  ),
  'ci'=>array(
    'iso3'=>'civ',
    'name'=>'Ivory Coast',
    'capital'=>'Yamoussoukro',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'ck'=>array(
    'iso3'=>'cok',
    'name'=>'Cook Islands',
    'capital'=>'Avarua',
    'currencyCode'=>'nzd',
    'currencyName'=>'Dollar',
  ),
  'cl'=>array(
    'iso3'=>'chl',
    'name'=>'Chile',
    'capital'=>'Santiago',
    'currencyCode'=>'clp',
    'currencyName'=>'Peso',
  ),
  'cm'=>array(
    'iso3'=>'cmr',
    'name'=>'Cameroon',
    'capital'=>'Yaounde',
    'currencyCode'=>'xaf',
    'currencyName'=>'Franc',
  ),
  'cn'=>array(
    'iso3'=>'chn',
    'name'=>'China',
    'capital'=>'Beijing',
    'currencyCode'=>'cny',
    'currencyName'=>'Yuan Renminbi',
  ),
  'co'=>array(
    'iso3'=>'col',
    'name'=>'Colombia',
    'capital'=>'Bogota',
    'currencyCode'=>'cop',
    'currencyName'=>'Peso',
  ),
  'cr'=>array(
    'iso3'=>'cri',
    'name'=>'Costa Rica',
    'capital'=>'San Jose',
    'currencyCode'=>'crc',
    'currencyName'=>'Colon',
  ),
  'cu'=>array(
    'iso3'=>'cub',
    'name'=>'Cuba',
    'capital'=>'Havana',
    'currencyCode'=>'cup',
    'currencyName'=>'Peso',
  ),
  'cv'=>array(
    'iso3'=>'cpv',
    'name'=>'Cape Verde',
    'capital'=>'Praia',
    'currencyCode'=>'cve',
    'currencyName'=>'Escudo',
  ),
  'cw'=>array(
    'iso3'=>'cuw',
    'name'=>'Curacao',
    'capital'=>'Willemstad',
    'currencyCode'=>'ang',
    'currencyName'=>'Guilder',
  ),
  'cx'=>array(
    'iso3'=>'cxr',
    'name'=>'Christmas Island',
    'capital'=>'Flying Fish Cove',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'cy'=>array(
    'iso3'=>'cyp',
    'name'=>'Cyprus',
    'capital'=>'Nicosia',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'cz'=>array(
    'iso3'=>'cze',
    'name'=>'Czech Republic',
    'capital'=>'Prague',
    'currencyCode'=>'czk',
    'currencyName'=>'Koruna',
  ),
  'de'=>array(
    'iso3'=>'deu',
    'name'=>'Germany',
    'capital'=>'Berlin',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'dj'=>array(
    'iso3'=>'dji',
    'name'=>'Djibouti',
    'capital'=>'Djibouti',
    'currencyCode'=>'djf',
    'currencyName'=>'Franc',
  ),
  'dk'=>array(
    'iso3'=>'dnk',
    'name'=>'Denmark',
    'capital'=>'Copenhagen',
    'currencyCode'=>'dkk',
    'currencyName'=>'Krone',
  ),
  'dm'=>array(
    'iso3'=>'dma',
    'name'=>'Dominica',
    'capital'=>'Roseau',
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'do'=>array(
    'iso3'=>'dom',
    'name'=>'Dominican Republic',
    'capital'=>'Santo Domingo',
    'currencyCode'=>'dop',
    'currencyName'=>'Peso',
  ),
  'dz'=>array(
    'iso3'=>'dza',
    'name'=>'Algeria',
    'capital'=>'Algiers',
    'currencyCode'=>'dzd',
    'currencyName'=>'Dinar',
  ),
  'ec'=>array(
    'iso3'=>'ecu',
    'name'=>'Ecuador',
    'capital'=>'Quito',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'ee'=>array(
    'iso3'=>'est',
    'name'=>'Estonia',
    'capital'=>'Tallinn',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'eg'=>array(
    'iso3'=>'egy',
    'name'=>'Egypt',
    'capital'=>'Cairo',
    'currencyCode'=>'egp',
    'currencyName'=>'Pound',
  ),
  'eh'=>array(
    'iso3'=>'esh',
    'name'=>'Western Sahara',
    'capital'=>'El-Aaiun',
    'currencyCode'=>'mad',
    'currencyName'=>'Dirham',
  ),
  'er'=>array(
    'iso3'=>'eri',
    'name'=>'Eritrea',
    'capital'=>'Asmara',
    'currencyCode'=>'ern',
    'currencyName'=>'Nakfa',
  ),
  'es'=>array(
    'iso3'=>'esp',
    'name'=>'Spain',
    'capital'=>'Madrid',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'et'=>array(
    'iso3'=>'eth',
    'name'=>'Ethiopia',
    'capital'=>'Addis Ababa',
    'currencyCode'=>'etb',
    'currencyName'=>'Birr',
  ),
  'fi'=>array(
    'iso3'=>'fin',
    'name'=>'Finland',
    'capital'=>'Helsinki',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'fj'=>array(
    'iso3'=>'fji',
    'name'=>'Fiji',
    'capital'=>'Suva',
    'currencyCode'=>'fjd',
    'currencyName'=>'Dollar',
  ),
  'fk'=>array(
    'iso3'=>'flk',
    'name'=>'Falkland Islands',
    'capital'=>'Stanley',
    'currencyCode'=>'fkp',
    'currencyName'=>'Pound',
  ),
  'fm'=>array(
    'iso3'=>'fsm',
    'name'=>'Micronesia',
    'capital'=>'Palikir',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'fo'=>array(
    'iso3'=>'fro',
    'name'=>'Faroe Islands',
    'capital'=>'Torshavn',
    'currencyCode'=>'dkk',
    'currencyName'=>'Krone',
  ),
  'fr'=>array(
    'iso3'=>'fra',
    'name'=>'France',
    'capital'=>'Paris',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'ga'=>array(
    'iso3'=>'gab',
    'name'=>'Gabon',
    'capital'=>'Libreville',
    'currencyCode'=>'xaf',
    'currencyName'=>'Franc',
  ),
  'gb'=>array(
    'iso3'=>'gbr',
    'name'=>'United Kingdom',
    'capital'=>'London',
    'currencyCode'=>'gbp',
    'currencyName'=>'Pound',
  ),
  'gd'=>array(
    'iso3'=>'grd',
    'name'=>'Grenada',
    'capital'=>"St. George's",
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'ge'=>array(
    'iso3'=>'geo',
    'name'=>'Georgia',
    'capital'=>'Tbilisi',
    'currencyCode'=>'gel',
    'currencyName'=>'Lari',
  ),
  'gf'=>array(
    'iso3'=>'guf',
    'name'=>'French Guiana',
    'capital'=>'Cayenne',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'gg'=>array(
    'iso3'=>'ggy',
    'name'=>'Guernsey',
    'capital'=>'St Peter Port',
    'currencyCode'=>'gbp',
    'currencyName'=>'Pound',
  ),
  'gh'=>array(
    'iso3'=>'gha',
    'name'=>'Ghana',
    'capital'=>'Accra',
    'currencyCode'=>'ghs',
    'currencyName'=>'Cedi',
  ),
  'gi'=>array(
    'iso3'=>'gib',
    'name'=>'Gibraltar',
    'capital'=>'Gibraltar',
    'currencyCode'=>'gip',
    'currencyName'=>'Pound',
  ),
  'gl'=>array(
    'iso3'=>'grl',
    'name'=>'Greenland',
    'capital'=>'Nuuk',
    'currencyCode'=>'dkk',
    'currencyName'=>'Krone',
  ),
  'gm'=>array(
    'iso3'=>'gmb',
    'name'=>'Gambia',
    'capital'=>'Banjul',
    'currencyCode'=>'gmd',
    'currencyName'=>'Dalasi',
  ),
  'gn'=>array(
    'iso3'=>'gin',
    'name'=>'Guinea',
    'capital'=>'Conakry',
    'currencyCode'=>'gnf',
    'currencyName'=>'Franc',
  ),
  'gp'=>array(
    'iso3'=>'glp',
    'name'=>'Guadeloupe',
    'capital'=>'Basse-Terre',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'gq'=>array(
    'iso3'=>'gnq',
    'name'=>'Equatorial Guinea',
    'capital'=>'Malabo',
    'currencyCode'=>'xaf',
    'currencyName'=>'Franc',
  ),
  'gr'=>array(
    'iso3'=>'grc',
    'name'=>'Greece',
    'capital'=>'Athens',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'gs'=>array(
    'iso3'=>'sgs',
    'name'=>'South Georgia and the South Sandwich Islands',
    'capital'=>'Grytviken',
    'currencyCode'=>'gbp',
    'currencyName'=>'Pound',
  ),
  'gt'=>array(
    'iso3'=>'gtm',
    'name'=>'Guatemala',
    'capital'=>'Guatemala City',
    'currencyCode'=>'gtq',
    'currencyName'=>'Quetzal',
  ),
  'gu'=>array(
    'iso3'=>'gum',
    'name'=>'Guam',
    'capital'=>'Hagatna',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'gw'=>array(
    'iso3'=>'gnb',
    'name'=>'Guinea-Bissau',
    'capital'=>'Bissau',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'gy'=>array(
    'iso3'=>'guy',
    'name'=>'Guyana',
    'capital'=>'Georgetown',
    'currencyCode'=>'gyd',
    'currencyName'=>'Dollar',
  ),
  'hk'=>array(
    'iso3'=>'hkg',
    'name'=>'Hong Kong',
    'capital'=>'Hong Kong',
    'currencyCode'=>'hkd',
    'currencyName'=>'Dollar',
  ),
  'hm'=>array(
    'iso3'=>'hmd',
    'name'=>'Heard Island and McDonald Islands',
    'capital'=>'',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'hn'=>array(
    'iso3'=>'hnd',
    'name'=>'Honduras',
    'capital'=>'Tegucigalpa',
    'currencyCode'=>'hnl',
    'currencyName'=>'Lempira',
  ),
  'hr'=>array(
    'iso3'=>'hrv',
    'name'=>'Croatia',
    'capital'=>'Zagreb',
    'currencyCode'=>'hrk',
    'currencyName'=>'Kuna',
  ),
  'ht'=>array(
    'iso3'=>'hti',
    'name'=>'Haiti',
    'capital'=>'Port-au-Prince',
    'currencyCode'=>'htg',
    'currencyName'=>'Gourde',
  ),
  'hu'=>array(
    'iso3'=>'hun',
    'name'=>'Hungary',
    'capital'=>'Budapest',
    'currencyCode'=>'huf',
    'currencyName'=>'Forint',
  ),
  'id'=>array(
    'iso3'=>'idn',
    'name'=>'Indonesia',
    'capital'=>'Jakarta',
    'currencyCode'=>'idr',
    'currencyName'=>'Rupiah',
  ),
  'ie'=>array(
    'iso3'=>'irl',
    'name'=>'Ireland',
    'capital'=>'Dublin',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'il'=>array(
    'iso3'=>'isr',
    'name'=>'Israel',
    'capital'=>'Jerusalem',
    'currencyCode'=>'ils',
    'currencyName'=>'Shekel',
  ),
  'im'=>array(
    'iso3'=>'imn',
    'name'=>'Isle of Man',
    'capital'=>'Douglas, Isle of Man',
    'currencyCode'=>'gbp',
    'currencyName'=>'Pound',
  ),
  'in'=>array(
    'iso3'=>'ind',
    'name'=>'India',
    'capital'=>'New Delhi',
    'currencyCode'=>'inr',
    'currencyName'=>'Rupee',
  ),
  'io'=>array(
    'iso3'=>'iot',
    'name'=>'British Indian Ocean Territory',
    'capital'=>'Diego Garcia',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'iq'=>array(
    'iso3'=>'irq',
    'name'=>'Iraq',
    'capital'=>'Baghdad',
    'currencyCode'=>'iqd',
    'currencyName'=>'Dinar',
  ),
  'ir'=>array(
    'iso3'=>'irn',
    'name'=>'Iran',
    'capital'=>'Tehran',
    'currencyCode'=>'irr',
    'currencyName'=>'Rial',
  ),
  'is'=>array(
    'iso3'=>'isl',
    'name'=>'Iceland',
    'capital'=>'Reykjavik',
    'currencyCode'=>'isk',
    'currencyName'=>'Krona',
  ),
  'it'=>array(
    'iso3'=>'ita',
    'name'=>'Italy',
    'capital'=>'Rome',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'je'=>array(
    'iso3'=>'jey',
    'name'=>'Jersey',
    'capital'=>'Saint Helier',
    'currencyCode'=>'gbp',
    'currencyName'=>'Pound',
  ),
  'jm'=>array(
    'iso3'=>'jam',
    'name'=>'Jamaica',
    'capital'=>'Kingston',
    'currencyCode'=>'jmd',
    'currencyName'=>'Dollar',
  ),
  'jo'=>array(
    'iso3'=>'jor',
    'name'=>'Jordan',
    'capital'=>'Amman',
    'currencyCode'=>'jod',
    'currencyName'=>'Dinar',
  ),
  'jp'=>array(
    'iso3'=>'jpn',
    'name'=>'Japan',
    'capital'=>'Tokyo',
    'currencyCode'=>'jpy',
    'currencyName'=>'Yen',
  ),
  'ke'=>array(
    'iso3'=>'ken',
    'name'=>'Kenya',
    'capital'=>'Nairobi',
    'currencyCode'=>'kes',
    'currencyName'=>'Shilling',
  ),
  'kg'=>array(
    'iso3'=>'kgz',
    'name'=>'Kyrgyzstan',
    'capital'=>'Bishkek',
    'currencyCode'=>'kgs',
    'currencyName'=>'Som',
  ),
  'kh'=>array(
    'iso3'=>'khm',
    'name'=>'Cambodia',
    'capital'=>'Phnom Penh',
    'currencyCode'=>'khr',
    'currencyName'=>'Riels',
  ),
  'ki'=>array(
    'iso3'=>'kir',
    'name'=>'Kiribati',
    'capital'=>'Tarawa',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'km'=>array(
    'iso3'=>'com',
    'name'=>'Comoros',
    'capital'=>'Moroni',
    'currencyCode'=>'kmf',
    'currencyName'=>'Franc',
  ),
  'kn'=>array(
    'iso3'=>'kna',
    'name'=>'Saint Kitts and Nevis',
    'capital'=>'Basseterre',
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'kp'=>array(
    'iso3'=>'prk',
    'name'=>'North Korea',
    'capital'=>'Pyongyang',
    'currencyCode'=>'kpw',
    'currencyName'=>'Won',
  ),
  'kr'=>array(
    'iso3'=>'kor',
    'name'=>'South Korea',
    'capital'=>'Seoul',
    'currencyCode'=>'krw',
    'currencyName'=>'Won',
  ),
  'xk'=>array(
    'iso3'=>'xkx',
    'name'=>'Kosovo',
    'capital'=>'Pristina',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'kw'=>array(
    'iso3'=>'kwt',
    'name'=>'Kuwait',
    'capital'=>'Kuwait City',
    'currencyCode'=>'kwd',
    'currencyName'=>'Dinar',
  ),
  'ky'=>array(
    'iso3'=>'cym',
    'name'=>'Cayman Islands',
    'capital'=>'George Town',
    'currencyCode'=>'kyd',
    'currencyName'=>'Dollar',
  ),
  'kz'=>array(
    'iso3'=>'kaz',
    'name'=>'Kazakhstan',
    'capital'=>'Astana',
    'currencyCode'=>'kzt',
    'currencyName'=>'Tenge',
  ),
  'la'=>array(
    'iso3'=>'lao',
    'name'=>'Laos',
    'capital'=>'Vientiane',
    'currencyCode'=>'lak',
    'currencyName'=>'Kip',
  ),
  'lb'=>array(
    'iso3'=>'lbn',
    'name'=>'Lebanon',
    'capital'=>'Beirut',
    'currencyCode'=>'lbp',
    'currencyName'=>'Pound',
  ),
  'lc'=>array(
    'iso3'=>'lca',
    'name'=>'Saint Lucia',
    'capital'=>'Castries',
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'li'=>array(
    'iso3'=>'lie',
    'name'=>'Liechtenstein',
    'capital'=>'Vaduz',
    'currencyCode'=>'chf',
    'currencyName'=>'Franc',
  ),
  'lk'=>array(
    'iso3'=>'lka',
    'name'=>'Sri Lanka',
    'capital'=>'Colombo',
    'currencyCode'=>'lkr',
    'currencyName'=>'Rupee',
  ),
  'lr'=>array(
    'iso3'=>'lbr',
    'name'=>'Liberia',
    'capital'=>'Monrovia',
    'currencyCode'=>'lrd',
    'currencyName'=>'Dollar',
  ),
  'ls'=>array(
    'iso3'=>'lso',
    'name'=>'Lesotho',
    'capital'=>'Maseru',
    'currencyCode'=>'lsl',
    'currencyName'=>'Loti',
  ),
  'lt'=>array(
    'iso3'=>'ltu',
    'name'=>'Lithuania',
    'capital'=>'Vilnius',
    'currencyCode'=>'ltl',
    'currencyName'=>'Litas',
  ),
  'lu'=>array(
    'iso3'=>'lux',
    'name'=>'Luxembourg',
    'capital'=>'Luxembourg',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'lv'=>array(
    'iso3'=>'lva',
    'name'=>'Latvia',
    'capital'=>'Riga',
    'currencyCode'=>'lvl',
    'currencyName'=>'Lat',
  ),
  'ly'=>array(
    'iso3'=>'lby',
    'name'=>'Libya',
    'capital'=>'Tripolis',
    'currencyCode'=>'lyd',
    'currencyName'=>'Dinar',
  ),
  'ma'=>array(
    'iso3'=>'mar',
    'name'=>'Morocco',
    'capital'=>'Rabat',
    'currencyCode'=>'mad',
    'currencyName'=>'Dirham',
  ),
  'mc'=>array(
    'iso3'=>'mco',
    'name'=>'Monaco',
    'capital'=>'Monaco',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'md'=>array(
    'iso3'=>'mda',
    'name'=>'Moldova',
    'capital'=>'Chisinau',
    'currencyCode'=>'mdl',
    'currencyName'=>'Leu',
  ),
  'me'=>array(
    'iso3'=>'mne',
    'name'=>'Montenegro',
    'capital'=>'Podgorica',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'mf'=>array(
    'iso3'=>'maf',
    'name'=>'Saint Martin',
    'capital'=>'Marigot',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'mg'=>array(
    'iso3'=>'mdg',
    'name'=>'Madagascar',
    'capital'=>'Antananarivo',
    'currencyCode'=>'mga',
    'currencyName'=>'Ariary',
  ),
  'mh'=>array(
    'iso3'=>'mhl',
    'name'=>'Marshall Islands',
    'capital'=>'Majuro',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'mk'=>array(
    'iso3'=>'mkd',
    'name'=>'Macedonia',
    'capital'=>'Skopje',
    'currencyCode'=>'mkd',
    'currencyName'=>'Denar',
  ),
  'ml'=>array(
    'iso3'=>'mli',
    'name'=>'Mali',
    'capital'=>'Bamako',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'mm'=>array(
    'iso3'=>'mmr',
    'name'=>'Myanmar',
    'capital'=>'Nay Pyi Taw',
    'currencyCode'=>'mmk',
    'currencyName'=>'Kyat',
  ),
  'mn'=>array(
    'iso3'=>'mng',
    'name'=>'Mongolia',
    'capital'=>'Ulan Bator',
    'currencyCode'=>'mnt',
    'currencyName'=>'Tugrik',
  ),
  'mo'=>array(
    'iso3'=>'mac',
    'name'=>'Macao',
    'capital'=>'Macao',
    'currencyCode'=>'mop',
    'currencyName'=>'Pataca',
  ),
  'mp'=>array(
    'iso3'=>'mnp',
    'name'=>'Northern Mariana Islands',
    'capital'=>'Saipan',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'mq'=>array(
    'iso3'=>'mtq',
    'name'=>'Martinique',
    'capital'=>'Fort-de-France',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'mr'=>array(
    'iso3'=>'mrt',
    'name'=>'Mauritania',
    'capital'=>'Nouakchott',
    'currencyCode'=>'mro',
    'currencyName'=>'Ouguiya',
  ),
  'ms'=>array(
    'iso3'=>'msr',
    'name'=>'Montserrat',
    'capital'=>'Plymouth',
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  'mt'=>array(
    'iso3'=>'mlt',
    'name'=>'Malta',
    'capital'=>'Valletta',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'mu'=>array(
    'iso3'=>'mus',
    'name'=>'Mauritius',
    'capital'=>'Port Louis',
    'currencyCode'=>'mur',
    'currencyName'=>'Rupee',
  ),
  'mv'=>array(
    'iso3'=>'mdv',
    'name'=>'Maldives',
    'capital'=>'Male',
    'currencyCode'=>'mvr',
    'currencyName'=>'Rufiyaa',
  ),
  'mw'=>array(
    'iso3'=>'mwi',
    'name'=>'Malawi',
    'capital'=>'Lilongwe',
    'currencyCode'=>'mwk',
    'currencyName'=>'Kwacha',
  ),
  'mx'=>array(
    'iso3'=>'mex',
    'name'=>'Mexico',
    'capital'=>'Mexico City',
    'currencyCode'=>'mxn',
    'currencyName'=>'Peso',
  ),
  'my'=>array(
    'iso3'=>'mys',
    'name'=>'Malaysia',
    'capital'=>'Kuala Lumpur',
    'currencyCode'=>'myr',
    'currencyName'=>'Ringgit',
  ),
  'mz'=>array(
    'iso3'=>'moz',
    'name'=>'Mozambique',
    'capital'=>'Maputo',
    'currencyCode'=>'mzn',
    'currencyName'=>'Metical',
  ),
  'na'=>array(
    'iso3'=>'nam',
    'name'=>'Namibia',
    'capital'=>'Windhoek',
    'currencyCode'=>'nad',
    'currencyName'=>'Dollar',
  ),
  'nc'=>array(
    'iso3'=>'ncl',
    'name'=>'New Caledonia',
    'capital'=>'Noumea',
    'currencyCode'=>'xpf',
    'currencyName'=>'Franc',
  ),
  'ne'=>array(
    'iso3'=>'ner',
    'name'=>'Niger',
    'capital'=>'Niamey',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'nf'=>array(
    'iso3'=>'nfk',
    'name'=>'Norfolk Island',
    'capital'=>'Kingston',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'ng'=>array(
    'iso3'=>'nga',
    'name'=>'Nigeria',
    'capital'=>'Abuja',
    'currencyCode'=>'ngn',
    'currencyName'=>'Naira',
  ),
  'ni'=>array(
    'iso3'=>'nic',
    'name'=>'Nicaragua',
    'capital'=>'Managua',
    'currencyCode'=>'nio',
    'currencyName'=>'Cordoba',
  ),
  'nl'=>array(
    'iso3'=>'nld',
    'name'=>'Netherlands',
    'capital'=>'Amsterdam',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'no'=>array(
    'iso3'=>'nor',
    'name'=>'Norway',
    'capital'=>'Oslo',
    'currencyCode'=>'nok',
    'currencyName'=>'Krone',
  ),
  'np'=>array(
    'iso3'=>'npl',
    'name'=>'Nepal',
    'capital'=>'Kathmandu',
    'currencyCode'=>'npr',
    'currencyName'=>'Rupee',
  ),
  'nr'=>array(
    'iso3'=>'nru',
    'name'=>'Nauru',
    'capital'=>'Yaren',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'nu'=>array(
    'iso3'=>'niu',
    'name'=>'Niue',
    'capital'=>'Alofi',
    'currencyCode'=>'nzd',
    'currencyName'=>'Dollar',
  ),
  'nz'=>array(
    'iso3'=>'nzl',
    'name'=>'New Zealand',
    'capital'=>'Wellington',
    'currencyCode'=>'nzd',
    'currencyName'=>'Dollar',
  ),
  'om'=>array(
    'iso3'=>'omn',
    'name'=>'Oman',
    'capital'=>'Muscat',
    'currencyCode'=>'omr',
    'currencyName'=>'Rial',
  ),
  'pa'=>array(
    'iso3'=>'pan',
    'name'=>'Panama',
    'capital'=>'Panama City',
    'currencyCode'=>'pab',
    'currencyName'=>'Balboa',
  ),
  'pe'=>array(
    'iso3'=>'per',
    'name'=>'Peru',
    'capital'=>'Lima',
    'currencyCode'=>'pen',
    'currencyName'=>'Sol',
  ),
  'pf'=>array(
    'iso3'=>'pyf',
    'name'=>'French Polynesia',
    'capital'=>'Papeete',
    'currencyCode'=>'xpf',
    'currencyName'=>'Franc',
  ),
  'pg'=>array(
    'iso3'=>'png',
    'name'=>'Papua New Guinea',
    'capital'=>'Port Moresby',
    'currencyCode'=>'pgk',
    'currencyName'=>'Kina',
  ),
  'ph'=>array(
    'iso3'=>'phl',
    'name'=>'Philippines',
    'capital'=>'Manila',
    'currencyCode'=>'php',
    'currencyName'=>'Peso',
  ),
  'pk'=>array(
    'iso3'=>'pak',
    'name'=>'Pakistan',
    'capital'=>'Islamabad',
    'currencyCode'=>'pkr',
    'currencyName'=>'Rupee',
  ),
  'pl'=>array(
    'iso3'=>'pol',
    'name'=>'Poland',
    'capital'=>'Warsaw',
    'currencyCode'=>'pln',
    'currencyName'=>'Zloty',
  ),
  'pm'=>array(
    'iso3'=>'spm',
    'name'=>'Saint Pierre and Miquelon',
    'capital'=>'Saint-Pierre',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'pn'=>array(
    'iso3'=>'pcn',
    'name'=>'Pitcairn',
    'capital'=>'Adamstown',
    'currencyCode'=>'nzd',
    'currencyName'=>'Dollar',
  ),
  'pr'=>array(
    'iso3'=>'pri',
    'name'=>'Puerto Rico',
    'capital'=>'San Juan',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'ps'=>array(
    'iso3'=>'pse',
    'name'=>'Palestinian Territory',
    'capital'=>'East Jerusalem',
    'currencyCode'=>'ils',
    'currencyName'=>'Shekel',
  ),
  'pt'=>array(
    'iso3'=>'prt',
    'name'=>'Portugal',
    'capital'=>'Lisbon',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'pw'=>array(
    'iso3'=>'plw',
    'name'=>'Palau',
    'capital'=>'Melekeok',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'py'=>array(
    'iso3'=>'pry',
    'name'=>'Paraguay',
    'capital'=>'Asuncion',
    'currencyCode'=>'pyg',
    'currencyName'=>'Guarani',
  ),
  'qa'=>array(
    'iso3'=>'qat',
    'name'=>'Qatar',
    'capital'=>'Doha',
    'currencyCode'=>'qar',
    'currencyName'=>'Rial',
  ),
  're'=>array(
    'iso3'=>'reu',
    'name'=>'Reunion',
    'capital'=>'Saint-Denis',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'ro'=>array(
    'iso3'=>'rou',
    'name'=>'Romania',
    'capital'=>'Bucharest',
    'currencyCode'=>'ron',
    'currencyName'=>'Leu',
  ),
  'rs'=>array(
    'iso3'=>'srb',
    'name'=>'Serbia',
    'capital'=>'Belgrade',
    'currencyCode'=>'rsd',
    'currencyName'=>'Dinar',
  ),
  'ru'=>array(
    'iso3'=>'rus',
    'name'=>'Russia',
    'capital'=>'Moscow',
    'currencyCode'=>'rub',
    'currencyName'=>'Ruble',
  ),
  'rw'=>array(
    'iso3'=>'rwa',
    'name'=>'Rwanda',
    'capital'=>'Kigali',
    'currencyCode'=>'rwf',
    'currencyName'=>'Franc',
  ),
  'sa'=>array(
    'iso3'=>'sau',
    'name'=>'Saudi Arabia',
    'capital'=>'Riyadh',
    'currencyCode'=>'sar',
    'currencyName'=>'Rial',
  ),
  'sb'=>array(
    'iso3'=>'slb',
    'name'=>'Solomon Islands',
    'capital'=>'Honiara',
    'currencyCode'=>'sbd',
    'currencyName'=>'Dollar',
  ),
  'sc'=>array(
    'iso3'=>'syc',
    'name'=>'Seychelles',
    'capital'=>'Victoria',
    'currencyCode'=>'scr',
    'currencyName'=>'Rupee',
  ),
  'sd'=>array(
    'iso3'=>'sdn',
    'name'=>'Sudan',
    'capital'=>'Khartoum',
    'currencyCode'=>'sdg',
    'currencyName'=>'Pound',
  ),
  'ss'=>array(
    'iso3'=>'ssd',
    'name'=>'South Sudan',
    'capital'=>'Juba',
    'currencyCode'=>'ssp',
    'currencyName'=>'Pound',
  ),
  'se'=>array(
    'iso3'=>'swe',
    'name'=>'Sweden',
    'capital'=>'Stockholm',
    'currencyCode'=>'sek',
    'currencyName'=>'Krona',
  ),
  'sg'=>array(
    'iso3'=>'sgp',
    'name'=>'Singapore',
    'capital'=>'Singapur',
    'currencyCode'=>'sgd',
    'currencyName'=>'Dollar',
  ),
  'sh'=>array(
    'iso3'=>'shn',
    'name'=>'Saint Helena',
    'capital'=>'Jamestown',
    'currencyCode'=>'shp',
    'currencyName'=>'Pound',
  ),
  'si'=>array(
    'iso3'=>'svn',
    'name'=>'Slovenia',
    'capital'=>'Ljubljana',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'sj'=>array(
    'iso3'=>'sjm',
    'name'=>'Svalbard and Jan Mayen',
    'capital'=>'Longyearbyen',
    'currencyCode'=>'nok',
    'currencyName'=>'Krone',
  ),
  'sk'=>array(
    'iso3'=>'svk',
    'name'=>'Slovakia',
    'capital'=>'Bratislava',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'sl'=>array(
    'iso3'=>'sle',
    'name'=>'Sierra Leone',
    'capital'=>'Freetown',
    'currencyCode'=>'sll',
    'currencyName'=>'Leone',
  ),
  'sm'=>array(
    'iso3'=>'smr',
    'name'=>'San Marino',
    'capital'=>'San Marino',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'sn'=>array(
    'iso3'=>'sen',
    'name'=>'Senegal',
    'capital'=>'Dakar',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'so'=>array(
    'iso3'=>'som',
    'name'=>'Somalia',
    'capital'=>'Mogadishu',
    'currencyCode'=>'sos',
    'currencyName'=>'Shilling',
  ),
  'sr'=>array(
    'iso3'=>'sur',
    'name'=>'Suriname',
    'capital'=>'Paramaribo',
    'currencyCode'=>'srd',
    'currencyName'=>'Dollar',
  ),
  'st'=>array(
    'iso3'=>'stp',
    'name'=>'Sao Tome and Principe',
    'capital'=>'Sao Tome',
    'currencyCode'=>'std',
    'currencyName'=>'Dobra',
  ),
  'sv'=>array(
    'iso3'=>'slv',
    'name'=>'El Salvador',
    'capital'=>'San Salvador',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'sx'=>array(
    'iso3'=>'sxm',
    'name'=>'Sint Maarten',
    'capital'=>'Philipsburg',
    'currencyCode'=>'ang',
    'currencyName'=>'Guilder',
  ),
  'sy'=>array(
    'iso3'=>'syr',
    'name'=>'Syria',
    'capital'=>'Damascus',
    'currencyCode'=>'syp',
    'currencyName'=>'Pound',
  ),
  'sz'=>array(
    'iso3'=>'swz',
    'name'=>'Swaziland',
    'capital'=>'Mbabane',
    'currencyCode'=>'szl',
    'currencyName'=>'Lilangeni',
  ),
  'tc'=>array(
    'iso3'=>'tca',
    'name'=>'Turks and Caicos Islands',
    'capital'=>'Cockburn Town',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'td'=>array(
    'iso3'=>'tcd',
    'name'=>'Chad',
    'capital'=>"N'Djamena",
    'currencyCode'=>'xaf',
    'currencyName'=>'Franc',
  ),
  'tf'=>array(
    'iso3'=>'atf',
    'name'=>'French Southern Territories',
    'capital'=>'Port-aux-Francais',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro  ',
  ),
  'tg'=>array(
    'iso3'=>'tgo',
    'name'=>'Togo',
    'capital'=>'Lome',
    'currencyCode'=>'xof',
    'currencyName'=>'Franc',
  ),
  'th'=>array(
    'iso3'=>'tha',
    'name'=>'Thailand',
    'capital'=>'Bangkok',
    'currencyCode'=>'thb',
    'currencyName'=>'Baht',
  ),
  'tj'=>array(
    'iso3'=>'tjk',
    'name'=>'Tajikistan',
    'capital'=>'Dushanbe',
    'currencyCode'=>'tjs',
    'currencyName'=>'Somoni',
  ),
  'tk'=>array(
    'iso3'=>'tkl',
    'name'=>'Tokelau',
    'capital'=>'',
    'currencyCode'=>'nzd',
    'currencyName'=>'Dollar',
  ),
  'tl'=>array(
    'iso3'=>'tls',
    'name'=>'East Timor',
    'capital'=>'Dili',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'tm'=>array(
    'iso3'=>'tkm',
    'name'=>'Turkmenistan',
    'capital'=>'Ashgabat',
    'currencyCode'=>'tmt',
    'currencyName'=>'Manat',
  ),
  'tn'=>array(
    'iso3'=>'tun',
    'name'=>'Tunisia',
    'capital'=>'Tunis',
    'currencyCode'=>'tnd',
    'currencyName'=>'Dinar',
  ),
  'to'=>array(
    'iso3'=>'ton',
    'name'=>'Tonga',
    'capital'=>"Nuku'alofa",
    'currencyCode'=>'top',
    'currencyName'=>"Pa'anga",
  ),
  'tr'=>array(
    'iso3'=>'tur',
    'name'=>'Turkey',
    'capital'=>'Ankara',
    'currencyCode'=>'try',
    'currencyName'=>'Lira',
  ),
  'tt'=>array(
    'iso3'=>'tto',
    'name'=>'Trinidad and Tobago',
    'capital'=>'Port of Spain',
    'currencyCode'=>'ttd',
    'currencyName'=>'Dollar',
  ),
  'tv'=>array(
    'iso3'=>'tuv',
    'name'=>'Tuvalu',
    'capital'=>'Funafuti',
    'currencyCode'=>'aud',
    'currencyName'=>'Dollar',
  ),
  'tw'=>array(
    'iso3'=>'twn',
    'name'=>'Taiwan',
    'capital'=>'Taipei',
    'currencyCode'=>'twd',
    'currencyName'=>'Dollar',
  ),
  'tz'=>array(
    'iso3'=>'tza',
    'name'=>'Tanzania',
    'capital'=>'Dodoma',
    'currencyCode'=>'tzs',
    'currencyName'=>'Shilling',
  ),
  'ua'=>array(
    'iso3'=>'ukr',
    'name'=>'Ukraine',
    'capital'=>'Kiev',
    'currencyCode'=>'uah',
    'currencyName'=>'Hryvnia',
  ),
  'ug'=>array(
    'iso3'=>'uga',
    'name'=>'Uganda',
    'capital'=>'Kampala',
    'currencyCode'=>'ugx',
    'currencyName'=>'Shilling',
  ),
  'um'=>array(
    'iso3'=>'umi',
    'name'=>'United States Minor Outlying Islands',
    'capital'=>'',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar ',
  ),
  'us'=>array(
    'iso3'=>'usa',
    'name'=>'United States',
    'capital'=>'Washington',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'uy'=>array(
    'iso3'=>'ury',
    'name'=>'Uruguay',
    'capital'=>'Montevideo',
    'currencyCode'=>'uyu',
    'currencyName'=>'Peso',
  ),
  'uz'=>array(
    'iso3'=>'uzb',
    'name'=>'Uzbekistan',
    'capital'=>'Tashkent',
    'currencyCode'=>'uzs',
    'currencyName'=>'Som',
  ),
  'va'=>array(
    'iso3'=>'vat',
    'name'=>'Vatican',
    'capital'=>'Vatican City',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'vc'=>array(
    'iso3'=>'vct',
    'name'=>'Saint Vincent and the Grenadines',
    'capital'=>'Kingstown',
    'currencyCode'=>'xcd',
    'currencyName'=>'Dollar',
  ),
  've'=>array(
    'iso3'=>'ven',
    'name'=>'Venezuela',
    'capital'=>'Caracas',
    'currencyCode'=>'vef',
    'currencyName'=>'Bolivar',
  ),
  'vg'=>array(
    'iso3'=>'vgb',
    'name'=>'British Virgin Islands',
    'capital'=>'Road Town',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'vi'=>array(
    'iso3'=>'vir',
    'name'=>'U.S. Virgin Islands',
    'capital'=>'Charlotte Amalie',
    'currencyCode'=>'usd',
    'currencyName'=>'Dollar',
  ),
  'vn'=>array(
    'iso3'=>'vnm',
    'name'=>'Vietnam',
    'capital'=>'Hanoi',
    'currencyCode'=>'vnd',
    'currencyName'=>'Dong',
  ),
  'vu'=>array(
    'iso3'=>'vut',
    'name'=>'Vanuatu',
    'capital'=>'Port Vila',
    'currencyCode'=>'vuv',
    'currencyName'=>'Vatu',
  ),
  'wf'=>array(
    'iso3'=>'wlf',
    'name'=>'Wallis and Futuna',
    'capital'=>'Mata Utu',
    'currencyCode'=>'xpf',
    'currencyName'=>'Franc',
  ),
  'ws'=>array(
    'iso3'=>'wsm',
    'name'=>'Samoa',
    'capital'=>'Apia',
    'currencyCode'=>'wst',
    'currencyName'=>'Tala',
  ),
  'ye'=>array(
    'iso3'=>'yem',
    'name'=>'Yemen',
    'capital'=>'Sanaa',
    'currencyCode'=>'yer',
    'currencyName'=>'Rial',
  ),
  'yt'=>array(
    'iso3'=>'myt',
    'name'=>'Mayotte',
    'capital'=>'Mamoudzou',
    'currencyCode'=>'eur',
    'currencyName'=>'Euro',
  ),
  'za'=>array(
    'iso3'=>'zaf',
    'name'=>'South Africa',
    'capital'=>'Pretoria',
    'currencyCode'=>'zar',
    'currencyName'=>'Rand',
  ),
  'zm'=>array(
    'iso3'=>'zmb',
    'name'=>'Zambia',
    'capital'=>'Lusaka',
    'currencyCode'=>'zmk',
    'currencyName'=>'Kwacha',
  ),
  'zw'=>array(
    'iso3'=>'zwe',
    'name'=>'Zimbabwe',
    'capital'=>'Harare',
    'currencyCode'=>'zwl',
    'currencyName'=>'Dollar',
  ),
  'cs'=>array(
    'iso3'=>'scg',
    'name'=>'Serbia and Montenegro',
    'capital'=>'Belgrade',
    'currencyCode'=>'rsd',
    'currencyName'=>'Dinar',
  ),
  'an'=>array(
    'iso3'=>'ant',
    'name'=>'Netherlands Antilles',
    'capital'=>'Willemstad',
    'currencyCode'=>'ang',
    'currencyName'=>'Guilder',
  ),
);
 
Second one is the Accepted-Language language code to country code:

$languages = array(
  'aa'=>array(
    'dj',
  ),
  'aa-er'=>array(
    'er',
  ),
  'ady'=>array(
    'ru',
  ),
  'af'=>array(
    'na','za',
  ),
  'ak'=>array(
    'gh',
  ),
  'am'=>array(
    'et',
  ),
  'ar'=>array(
    'dj','eh','er','km','tz','ug',
  ),
  'ar-ae'=>array(
    'ae',
  ),
  'ar-bh'=>array(
    'bh',
  ),
  'ar-dz'=>array(
    'dz',
  ),
  'ar-eg'=>array(
    'eg',
  ),
  'ar-il'=>array(
    'il',
  ),
  'ar-iq'=>array(
    'iq',
  ),
  'ar-jo'=>array(
    'jo',
  ),
  'ar-kw'=>array(
    'kw',
  ),
  'ar-lb'=>array(
    'lb',
  ),
  'ar-ly'=>array(
    'ly',
  ),
  'ar-ma'=>array(
    'ma',
  ),
  'ar-mr'=>array(
    'mr',
  ),
  'ar-om'=>array(
    'om',
  ),
  'ar-ps'=>array(
    'ps',
  ),
  'ar-qa'=>array(
    'qa',
  ),
  'ar-sa'=>array(
    'sa',
  ),
  'ar-sd'=>array(
    'sd',
  ),
  'ar-so'=>array(
    'so',
  ),
  'ar-sy'=>array(
    'sy',
  ),
  'ar-td'=>array(
    'td',
  ),
  'ar-tn'=>array(
    'tn',
  ),
  'ar-ye'=>array(
    'ye',
  ),
  'arc'=>array(
    'sy',
  ),
  'as'=>array(
    'in',
  ),
  'av'=>array(
    'tr',
  ),
  'ava'=>array(
    'ru',
  ),
  'ay'=>array(
    'bo','pe',
  ),
  'az'=>array(
    'az','ge','tr',
  ),
  'ba'=>array(
    'ru',
  ),
  'bal'=>array(
    'om',
  ),
  'be'=>array(
    'by',
  ),
  'bem'=>array(
    'zm',
  ),
  'bg'=>array(
    'bg',
  ),
  'bh'=>array(
    'in',
  ),
  'bho'=>array(
    'mu',
  ),
  'bi'=>array(
    'vu',
  ),
  'bm'=>array(
    'ml',
  ),
  'bn'=>array(
    'in',
  ),
  'bn-bd'=>array(
    'bd',
  ),
  'br'=>array(
    'fr',
  ),
  'brh'=>array(
    'pk',
  ),
  'bs'=>array(
    'ba','me','rs',
  ),
  'bua'=>array(
    'ru',
  ),
  'ca'=>array(
    'es','fr','ad','it',
  ),
  'cau'=>array(
    'ru',
  ),
  'ce'=>array(
    'ru',
  ),
  'ch-gu'=>array(
    'gu',
  ),
  'ch-mp'=>array(
    'mp',
  ),
  'chk'=>array(
    'fm',
  ),
  'chm'=>array(
    'ru',
  ),
  'cmn'=>array(
    'sg',
  ),
  'co'=>array(
    'fr','it',
  ),
  'cs'=>array(
    'cz',
  ),
  'cu'=>array(
    'cs',
  ),
  'cv'=>array(
    'ru',
  ),
  'cy-gb'=>array(
    'gb',
  ),
  'da'=>array(
    'is',
  ),
  'da-dk'=>array(
    'dk',
  ),
  'da-fo'=>array(
    'fo',
  ),
  'da-gl'=>array(
    'gl',
  ),
  'dag'=>array(
    'tg',
  ),
  'de'=>array(
    'de','ar','is','na',
  ),
  'de-at'=>array(
    'at',
  ),
  'de-be'=>array(
    'be',
  ),
  'de-ch'=>array(
    'ch',
  ),
  'de-dk'=>array(
    'dk',
  ),
  'de-it'=>array(
    'it',
  ),
  'de-li'=>array(
    'li',
  ),
  'de-lu'=>array(
    'lu',
  ),
  'diq'=>array(
    'tr',
  ),
  'dje'=>array(
    'ne',
  ),
  'doi'=>array(
    'in',
  ),
  'dta'=>array(
    'cn',
  ),
  'dv'=>array(
    'mv',
  ),
  'dz'=>array(
    'bt',
  ),
  'ee'=>array(
    'gh','tg',
  ),
  'el'=>array(
    'al',
  ),
  'el-cy'=>array(
    'cy',
  ),
  'el-gr'=>array(
    'gr',
  ),
  'en'=>array(
    'gb', 'ae','ar','aw','bd','bh','bq','br','cc','cr','cx','cy','dk','eg','gg','gl','gr','gs','hk','id','im','is','je','jo','kh','kr','kw','la','lb','lk','ly','mc','mv','my','ni','np','om','pa','sd','ss','sr','sx','sy','th','tl','tv','tz','vn','an',
  ),
  'en-ag'=>array(
    'ag',
  ),
  'en-ai'=>array(
    'ai',
  ),
  'en-as'=>array(
    'as',
  ),
  'en-au'=>array(
    'au',
  ),
  'en-bb'=>array(
    'bb',
  ),
  'en-bm'=>array(
    'bm',
  ),
  'en-bn'=>array(
    'bn',
  ),
  'en-bs'=>array(
    'bs',
  ),
  'en-bw'=>array(
    'bw',
  ),
  'en-bz'=>array(
    'bz',
  ),
  'en-ca'=>array(
    'ca',
  ),
  'en-ck'=>array(
    'ck',
  ),
  'en-cm'=>array(
    'cm',
  ),
  'en-dm'=>array(
    'dm',
  ),
  'en-et'=>array(
    'et',
  ),
  'en-fj'=>array(
    'fj',
  ),
  'en-fk'=>array(
    'fk',
  ),
  'en-fm'=>array(
    'fm',
  ),
  'en-gb'=>array(
    'gb',
  ),
  'en-gd'=>array(
    'gd',
  ),
  'en-gh'=>array(
    'gh',
  ),
  'en-gi'=>array(
    'gi',
  ),
  'en-gm'=>array(
    'gm',
  ),
  'en-gu'=>array(
    'gu',
  ),
  'en-gy'=>array(
    'gy',
  ),
  'en-ie'=>array(
    'ie',
  ),
  'en-il'=>array(
    'il',
  ),
  'en-in'=>array(
    'in',
  ),
  'en-io'=>array(
    'io',
  ),
  'en-jm'=>array(
    'jm',
  ),
  'en-ke'=>array(
    'ke',
  ),
  'en-ki'=>array(
    'ki',
  ),
  'en-kn'=>array(
    'kn',
  ),
  'en-ky'=>array(
    'ky',
  ),
  'en-lc'=>array(
    'lc',
  ),
  'en-lr'=>array(
    'lr',
  ),
  'en-ls'=>array(
    'ls',
  ),
  'en-mh'=>array(
    'mh',
  ),
  'en-mp'=>array(
    'mp',
  ),
  'en-ms'=>array(
    'ms',
  ),
  'en-mt'=>array(
    'mt',
  ),
  'en-mu'=>array(
    'mu',
  ),
  'en-na'=>array(
    'na',
  ),
  'en-nf'=>array(
    'nf',
  ),
  'en-ng'=>array(
    'ng',
  ),
  'en-nr'=>array(
    'nr',
  ),
  'en-nu'=>array(
    'nu',
  ),
  'en-nz'=>array(
    'nz',
  ),
  'en-pg'=>array(
    'pg',
  ),
  'en-ph'=>array(
    'ph',
  ),
  'en-pk'=>array(
    'pk',
  ),
  'en-pn'=>array(
    'pn',
  ),
  'en-pr'=>array(
    'pr',
  ),
  'en-pw'=>array(
    'pw',
  ),
  'en-rw'=>array(
    'rw',
  ),
  'en-sb'=>array(
    'sb',
  ),
  'en-sc'=>array(
    'sc',
  ),
  'en-sg'=>array(
    'sg',
  ),
  'en-sh'=>array(
    'sh',
  ),
  'en-sl'=>array(
    'sl',
  ),
  'en-so'=>array(
    'so',
  ),
  'en-sz'=>array(
    'sz',
  ),
  'en-tc'=>array(
    'tc',
  ),
  'en-tk'=>array(
    'tk',
  ),
  'en-to'=>array(
    'to',
  ),
  'en-tt'=>array(
    'tt',
  ),
  'en-ug'=>array(
    'ug',
  ),
  'en-um'=>array(
    'um',
  ),
  'en-us'=>array(
    'us',
  ),
  'en-vc'=>array(
    'vc',
  ),
  'en-vg'=>array(
    'vg',
  ),
  'en-vi'=>array(
    'vi',
  ),
  'en-vu'=>array(
    'vu',
  ),
  'en-ws'=>array(
    'ws',
  ),
  'en-za'=>array(
    'za',
  ),
  'en-zm'=>array(
    'zm',
  ),
  'en-zw'=>array(
    'zw',
  ),
  'es'=>array(
    'es','aw','br','bz','gi','qa','tt','an',
  ),
  'es-ar'=>array(
    'ar',
  ),
  'es-bo'=>array(
    'bo',
  ),
  'es-cl'=>array(
    'cl',
  ),
  'es-co'=>array(
    'co',
  ),
  'es-cr'=>array(
    'cr',
  ),
  'es-cu'=>array(
    'cu',
  ),
  'es-do'=>array(
    'do',
  ),
  'es-ec'=>array(
    'ec',
  ),
  'es-es'=>array(
    'es',
  ),
  'es-gq'=>array(
    'gq',
  ),
  'es-gt'=>array(
    'gt',
  ),
  'es-hn'=>array(
    'hn',
  ),
  'es-mx'=>array(
    'mx',
  ),
  'es-ni'=>array(
    'ni',
  ),
  'es-pa'=>array(
    'pa',
  ),
  'es-pe'=>array(
    'pe',
  ),
  'es-pr'=>array(
    'pr',
  ),
  'es-py'=>array(
    'py',
  ),
  'es-sv'=>array(
    'sv',
  ),
  'es-us'=>array(
    'us',
  ),
  'es-uy'=>array(
    'uy',
  ),
  'es-ve'=>array(
    've',
  ),
  'et'=>array(
    'ee',
  ),
  'eu'=>array(
    'es','fr',
  ),
  'fa'=>array(
    'ae','bh',
  ),
  'fa-af'=>array(
    'af',
  ),
  'fa-ir'=>array(
    'ir',
  ),
  'ff'=>array(
    'gm','ng',
  ),
  'fi'=>array(
    'no',
  ),
  'fi-fi'=>array(
    'fi',
  ),
  'fi-se'=>array(
    'se',
  ),
  'fia'=>array(
    'sd',
  ),
  'fil'=>array(
    'mp','ph','pw',
  ),
  'fj'=>array(
    'fj',
  ),
  'fo'=>array(
    'dk','fo',
  ),
  'fr'=>array(
    'fr','ar','bl','br','eg','gg','gq','gr','in','kh','la','ma','mf','mr','mu','sy','tf','tn','tt','us','va','vc','vn',
  ),
  'fr-be'=>array(
    'be',
  ),
  'fr-bf'=>array(
    'bf',
  ),
  'fr-bi'=>array(
    'bi',
  ),
  'fr-bj'=>array(
    'bj',
  ),
  'fr-ca'=>array(
    'ca',
  ),
  'fr-cd'=>array(
    'cd',
  ),
  'fr-cf'=>array(
    'cf',
  ),
  'fr-cg'=>array(
    'cg',
  ),
  'fr-ch'=>array(
    'ch',
  ),
  'fr-ci'=>array(
    'ci',
  ),
  'fr-cm'=>array(
    'cm',
  ),
  'fr-dj'=>array(
    'dj',
  ),
  'fr-fr'=>array(
    'fr',
  ),
  'fr-ga'=>array(
    'ga',
  ),
  'fr-gf'=>array(
    'gf',
  ),
  'fr-gn'=>array(
    'gn',
  ),
  'fr-gp'=>array(
    'gp',
  ),
  'fr-ht'=>array(
    'ht',
  ),
  'fr-it'=>array(
    'it',
  ),
  'fr-km'=>array(
    'km',
  ),
  'fr-lb'=>array(
    'lb',
  ),
  'fr-lu'=>array(
    'lu',
  ),
  'fr-mc'=>array(
    'mc',
  ),
  'fr-mg'=>array(
    'mg',
  ),
  'fr-ml'=>array(
    'ml',
  ),
  'fr-mq'=>array(
    'mq',
  ),
  'fr-nc'=>array(
    'nc',
  ),
  'fr-ne'=>array(
    'ne',
  ),
  'fr-pf'=>array(
    'pf',
  ),
  'fr-pm'=>array(
    'pm',
  ),
  'fr-re'=>array(
    're',
  ),
  'fr-rw'=>array(
    'rw',
  ),
  'fr-sc'=>array(
    'sc',
  ),
  'fr-sn'=>array(
    'sn',
  ),
  'fr-td'=>array(
    'td',
  ),
  'fr-tg'=>array(
    'tg',
  ),
  'fr-vu'=>array(
    'vu',
  ),
  'fr-wf'=>array(
    'wf',
  ),
  'fr-yt'=>array(
    'yt',
  ),
  'frp'=>array(
    'fr',
  ),
  'fuc'=>array(
    'mr','sn',
  ),
  'fud'=>array(
    'wf',
  ),
  'fy-nl'=>array(
    'nl',
  ),
  'ga-ie'=>array(
    'ie',
  ),
  'gag'=>array(
    'md',
  ),
  'gd'=>array(
    'gb',
  ),
  'gil'=>array(
    'ki','tv',
  ),
  'gl'=>array(
    'es',
  ),
  'gn'=>array(
    'ar','py',
  ),
  'gu'=>array(
    'in',
  ),
  'gv'=>array(
    'im',
  ),
  'ha'=>array(
    'ne','ng','tg',
  ),
  'hak'=>array(
    'tw',
  ),
  'haw'=>array(
    'us',
  ),
  'he'=>array(
    'il',
  ),
  'hi'=>array(
    'ae','in',
  ),
  'hna'=>array(
    'tg',
  ),
  'hns'=>array(
    'sr','tt',
  ),
  'ho'=>array(
    'pg',
  ),
  'hr'=>array(
    'at','me',
  ),
  'hr-ba'=>array(
    'ba',
  ),
  'hr-hr'=>array(
    'hr',
  ),
  'ht'=>array(
    'ht',
  ),
  'hu'=>array(
    'hu','at','me','ro','rs','sk','ua','cs',
  ),
  'hu-hu'=>array(
    'hu',
  ),
  'hy'=>array(
    'am','az','ge','iq','lb','sy',
  ),
  'hz'=>array(
    'na',
  ),
  'id'=>array(
    'id','tl',
  ),
  'ig'=>array(
    'ng',
  ),
  'inc'=>array(
    'in',
  ),
  'inh'=>array(
    'ru',
  ),
  'is'=>array(
    'is',
  ),
  'it'=>array(
    'it','ar','gi','ly','mc','so','va',
  ),
  'it-ch'=>array(
    'ch',
  ),
  'it-it'=>array(
    'it',
  ),
  'it-sm'=>array(
    'sm',
  ),
  'iu'=>array(
    'ca',
  ),
  'ja'=>array(
    'jp','pw',
  ),
  'jv'=>array(
    'id','sr',
  ),
  'ka'=>array(
    'ge',
  ),
  'kbd'=>array(
    'ru',
  ),
  'kbp'=>array(
    'tg',
  ),
  'kg'=>array(
    'cd','cf','cg',
  ),
  'kk'=>array(
    'kz',
  ),
  'kl'=>array(
    'gl',
  ),
  'km'=>array(
    'kh','vn',
  ),
  'kn'=>array(
    'in',
  ),
  'ko-kp'=>array(
    'kp',
  ),
  'ko-kr'=>array(
    'kr',
  ),
  'kok'=>array(
    'in',
  ),
  'kos'=>array(
    'fm',
  ),
  'kpg'=>array(
    'fm',
  ),
  'kr'=>array(
    'ne',
  ),
  'krc'=>array(
    'ru',
  ),
  'ks'=>array(
    'in',
  ),
  'ku'=>array(
    'iq','ir','sy','tr',
  ),
  'kun'=>array(
    'er',
  ),
  'kv'=>array(
    'ru',
  ),
  'ky'=>array(
    'kg',
  ),
  'la'=>array(
    'va',
  ),
  'lb'=>array(
    'lu',
  ),
  'lg'=>array(
    'ug',
  ),
  'ln'=>array(
    'cd','cf',
  ),
  'ln-cg'=>array(
    'cg',
  ),
  'lo'=>array(
    'la',
  ),
  'loz'=>array(
    'zm',
  ),
  'lt'=>array(
    'lt','lv',
  ),
  'lue'=>array(
    'zm',
  ),
  'lun'=>array(
    'zm',
  ),
  'lus'=>array(
    'in',
  ),
  'lv'=>array(
    'lv',
  ),
  'mdf'=>array(
    'ru',
  ),
  'men'=>array(
    'sl',
  ),
  'meu'=>array(
    'pg',
  ),
  'mey'=>array(
    'eh','mr',
  ),
  'mg'=>array(
    'mg',
  ),
  'mh'=>array(
    'mh',
  ),
  'mi'=>array(
    'ck','nz',
  ),
  'mk'=>array(
    'mk',
  ),
  'ml'=>array(
    'in','my',
  ),
  'mn'=>array(
    'mn',
  ),
  'mni'=>array(
    'in',
  ),
  'mnk'=>array(
    'gm','sn',
  ),
  'mns'=>array(
    'ru',
  ),
  'mr'=>array(
    'in',
  ),
  'ms-bn'=>array(
    'bn',
  ),
  'ms-cc'=>array(
    'cc','cx',
  ),
  'ms-my'=>array(
    'my',
  ),
  'ms-sg'=>array(
    'sg',
  ),
  'mt'=>array(
    'mt',
  ),
  'mwl'=>array(
    'pt',
  ),
  'my'=>array(
    'mm',
  ),
  'myv'=>array(
    'ru',
  ),
  'na'=>array(
    'nr',
  ),
  'nan'=>array(
    'tw',
  ),
  'naq'=>array(
    'na',
  ),
  'nb'=>array(
    'no',
  ),
  'nd'=>array(
    'zw',
  ),
  'ne'=>array(
    'in','np',
  ),
  'niu'=>array(
    'nu',
  ),
  'nkr'=>array(
    'fm',
  ),
  'nl'=>array(
    'nl','bq','cw','id','sx',
  ),
  'nl-an'=>array(
    'an',
  ),
  'nl-aw'=>array(
    'aw',
  ),
  'nl-be'=>array(
    'be',
  ),
  'nl-nl'=>array(
    'nl',
  ),
  'nl-sr'=>array(
    'sr',
  ),
  'nn'=>array(
    'no',
  ),
  'no'=>array(
    'is','no','sj',
  ),
  'nog'=>array(
    'ru',
  ),
  'nr'=>array(
    'za','zw',
  ),
  'nso'=>array(
    'za',
  ),
  'ny'=>array(
    'mw','zm',
  ),
  'oc'=>array(
    'es','fr',
  ),
  'om-et'=>array(
    'et',
  ),
  'or'=>array(
    'in',
  ),
  'pa'=>array(
    'in','my','pk',
  ),
  'pap'=>array(
    'bq','cw',
  ),
  'pau'=>array(
    'pw',
  ),
  'pl'=>array(
    'pl','lt','ua',
  ),
  'pl-pl'=>array(
    'pl',
  ),
  'pon'=>array(
    'fm',
  ),
  'pov'=>array(
    'gw',
  ),
  'ps'=>array(
    'af','pk',
  ),
  'pt'=>array(
    'pt','bm','gi','je','mo',
  ),
  'pt-ao'=>array(
    'ao',
  ),
  'pt-br'=>array(
    'br',
  ),
  'pt-cv'=>array(
    'cv',
  ),
  'pt-gw'=>array(
    'gw',
  ),
  'pt-mz'=>array(
    'mz',
  ),
  'pt-pt'=>array(
    'pt',
  ),
  'pt-st'=>array(
    'st',
  ),
  'pt-tl'=>array(
    'tl',
  ),
  'qu'=>array(
    'bo','pe',
  ),
  'rm'=>array(
    'ch',
  ),
  'rmm'=>array(
    'mk',
  ),
  'rn'=>array(
    'bi',
  ),
  'ro'=>array(
    'md','ro',
  ),
  'rom'=>array(
    'me','ro','rs','ua',
  ),
  'ru'=>array(
    'ru','az','by','ee','ge','kg','kz','lt','lv','md','mn','ru','sj','tj','tm','uz',
  ),
  'ru-ua'=>array(
    'ua',
  ),
  'rw'=>array(
    'rw',
  ),
  'sa'=>array(
    'in',
  ),
  'sah'=>array(
    'ru',
  ),
  'sat'=>array(
    'in',
  ),
  'sc'=>array(
    'it',
  ),
  'sd'=>array(
    'in','pk',
  ),
  'se'=>array(
    'no','se',
  ),
  'sg'=>array(
    'cf',
  ),
  'sh'=>array(
    'si',
  ),
  'si'=>array(
    'lk',
  ),
  'sid'=>array(
    'et',
  ),
  'sit'=>array(
    'in',
  ),
  'sk'=>array(
    'cz','sk',
  ),
  'sl'=>array(
    'at','it','si',
  ),
  'sm'=>array(
    'as','tv','ws',
  ),
  'sma'=>array(
    'se',
  ),
  'smn'=>array(
    'fi',
  ),
  'sn'=>array(
    'zw',
  ),
  'snk'=>array(
    'mr',
  ),
  'so-dj'=>array(
    'dj',
  ),
  'so-et'=>array(
    'et',
  ),
  'so-so'=>array(
    'so',
  ),
  'sov'=>array(
    'pw',
  ),
  'sq'=>array(
    'al','xk','me','mk','cs',
  ),
  'sr'=>array(
    'rs','hr','xk','me','mk','cs',
  ),
  'sr-ba'=>array(
    'ba',
  ),
  'sre'=>array(
    'td',
  ),
  'srn'=>array(
    'sr',
  ),
  'ss'=>array(
    'za',
  ),
  'ss-sz'=>array(
    'sz',
  ),
  'st'=>array(
    'ls','za',
  ),
  'sv'=>array(
    'is',
  ),
  'sv-ax'=>array(
    'ax',
  ),
  'sv-fi'=>array(
    'fi',
  ),
  'sv-se'=>array(
    'se',
  ),
  'sw'=>array(
    'rw','ug',
  ),
  'sw-ke'=>array(
    'ke',
  ),
  'sw-tz'=>array(
    'tz',
  ),
  'swk'=>array(
    'mw',
  ),
  'ta'=>array(
    'in','lk','my',
  ),
  'ta-sg'=>array(
    'sg',
  ),
  'te'=>array(
    'in','my',
  ),
  'tem'=>array(
    'sl',
  ),
  'tet'=>array(
    'tl',
  ),
  'tg'=>array(
    'tj','uz',
  ),
  'th'=>array(
    'my','th',
  ),
  'ti-er'=>array(
    'er',
  ),
  'ti-et'=>array(
    'et',
  ),
  'tig'=>array(
    'er',
  ),
  'tk'=>array(
    'af','tm',
  ),
  'tkl'=>array(
    'tk',
  ),
  'tl'=>array(
    'mp','ph',
  ),
  'tn'=>array(
    'za',
  ),
  'tn-bw'=>array(
    'bw',
  ),
  'to'=>array(
    'as','to',
  ),
  'toi'=>array(
    'zm',
  ),
  'tox'=>array(
    'pw',
  ),
  'tpi'=>array(
    'pg','sb',
  ),
  'tr'=>array(
    'md','mk',
  ),
  'tr-bg'=>array(
    'bg',
  ),
  'tr-cy'=>array(
    'cy',
  ),
  'tr-tr'=>array(
    'tr',
  ),
  'ts'=>array(
    'za',
  ),
  'tt'=>array(
    'ru',
  ),
  'tum'=>array(
    'mw',
  ),
  'tut'=>array(
    'ru','ru',
  ),
  'tvl'=>array(
    'tv',
  ),
  'tw'=>array(
    'gh',
  ),
  'ty'=>array(
    'pf',
  ),
  'tyv'=>array(
    'ru',
  ),
  'udm'=>array(
    'ru',
  ),
  'ug'=>array(
    'cn',
  ),
  'uk'=>array(
    'ua',
  ),
  'uli'=>array(
    'fm',
  ),
  'ur'=>array(
    'ae','bh','in','om',
  ),
  'ur-pk'=>array(
    'pk',
  ),
  'uz'=>array(
    'kg','tm','uz',
  ),
  'uz-af'=>array(
    'af',
  ),
  've'=>array(
    'za',
  ),
  'vi'=>array(
    'vn',
  ),
  'vmw'=>array(
    'mz',
  ),
  'wls'=>array(
    'wf',
  ),
  'wo'=>array(
    'gm','mr','sn',
  ),
  'woe'=>array(
    'fm',
  ),
  'wof'=>array(
    'gm',
  ),
  'wuu'=>array(
    'cn',
  ),
  'xal'=>array(
    'ru',
  ),
  'xh'=>array(
    'ls','za',
  ),
  'yao'=>array(
    'mw',
  ),
  'yap'=>array(
    'fm',
  ),
  'yo'=>array(
    'ng',
  ),
  'yue'=>array(
    'cn','hk',
  ),
  'za'=>array(
    'cn',
  ),
  'zh'=>array(
    'cn','cx','hk','mo','mp','my','pw','tt','tw','vn',
  ),
  'zh-cn'=>array(
    'cn',
  ),
  'zh-hk'=>array(
    'hk',
  ),
  'zh-mo'=>array(
    'mo',
  ),
  'zh-sg'=>array(
    'sg',
  ),
  'zh-tw'=>array(
    'tw',
  ),
  'zu'=>array(
    'ls','za',
  ),
);
 
And here is the parser for source file:

#!/usr/bin/php
<?
 
$handle = fopen('langcodes.txt', 'r');
$codes = array();
while (($code = fgetcsv($handle, 0, "t"))!==FALSE)
  $codes[] = $code;
fclose($handle);
 
$langs = array();
 
echo "$countries = array(n";
foreach($codes as $code) {
  $c = strtolower($code[0]);
  echo "  '".$c."'=>array(n";
 
  echo "    'iso3'=>'".strtolower($code[1])."',n";
  echo "    'name'=>'".$code[4]."',n";
  echo "    'capital'=>'".$code[5]."',n";
  echo "    'currencyCode'=>'".strtolower($code[10])."',n";
  echo "    'currencyName'=>'".$code[11]."',n";
 
  echo "  ),n";
 
  // parse language
  $lang = explode(",", strtolower($code[15]));
  foreach($lang as $l) {
    if (!isset($langs[$l]))
      $langs[$l] = array();
    $langs[$l][] = $c;
  }
}
echo ");n";
 
ksort($langs);
echo "$languages = array(n";
foreach($langs as $langKey=>$lang) {
  echo "  '".$langKey."'=>array(n    ";
  foreach($lang as $l) {
    echo "'".$l."',";
  }
  echo "n  ),n";
}
echo ");n";