Skip to content

Instantly share code, notes, and snippets.

@luizvaz
Last active March 7, 2021 23:03
Show Gist options
  • Select an option

  • Save luizvaz/ace093ac3a4323906484b337a0c66df0 to your computer and use it in GitHub Desktop.

Select an option

Save luizvaz/ace093ac3a4323906484b337a0c66df0 to your computer and use it in GitHub Desktop.

Revisions

  1. luizvaz revised this gist Mar 7, 2021. No changes.
  2. luizvaz renamed this gist Mar 7, 2021. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. luizvaz created this gist Mar 7, 2021.
    565 changes: 565 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,565 @@
    <?php
    /**
    * User: LuizVAz
    * Date: 22/04/2019
    * Time: 21:46
    */

    namespace Provedores\webService;

    use DOMDocument;
    use DOMXPath;
    use Exception;
    use Slim\App;
    use Slim\Http\Request;
    use Slim\Http\Response;
    use stdClass;

    class d2ti_v001 extends \Provedores\webService\webService
    {
    private $cnpj;
    private $dir;
    private $nfs_dir;
    private $rps_dir;
    private $rps_id;
    private $rps_serie;
    private $user;

    public function __construct(Request $request, Response $response, App $app){
    parent::__construct($request, $response, $app);

    //Cabeçalho v 1.00
    $this->cabecalho = '<cabecalhoNfseLote xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.ctaconsult.com/nfse">'.
    '<versao>1.00</versao>'.
    "<ambiente>%amb%</ambiente>".
    '</cabecalhoNfseLote>';

    $ym = date('Ym');
    $this->dir = $dir = getenv('BASE_PATH');
    $this->user = $user = str_replace(':', '',$this->request->getUri()->getUserInfo());
    $this->cnpj = $cnpj = $request->getAttribute('cnpj');
    $this->rps_dir = "$dir/$cnpj/rps/$ym/";
    $this->nfs_dir = "$dir/$cnpj/nfse/$ym/";

    $this->rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0');
    $this->rps_serie = "ws1";
    }

    public function emitir(stdClass $rps){
    $this->rps = $rps;
    return $this->gerarNfse();
    }

    public function gerarNfse(){
    //Retorno
    $return = new stdClass();
    $return->status = 500;
    $return->data = array("success" => false);

    $rps_dir = $this->rps_dir;

    //rps_id ou idExterno
    $rps_id = (property_exists($this->rps, 'idExterno'))?$this->rps->idExterno:$this->rps_id;
    if (!$rps_id){
    $rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0');
    $this->rps_id = $rps_id;
    } else
    $this->rps_id = $rps_id;

    //Garante que o diretório exista
    $fname = "${rps_dir}${rps_id}.xml";
    if (!file_exists("${rps_dir}")) {
    mkdir("${rps_dir}", 0777, true);
    }

    $envelope =
    "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsn=\"http://wsnfselote.ctaconsult.com.br/\">\n".
    " <soapenv:Header/>".
    " <soapenv:Body>\n".
    " <wsn:executar>\n".
    " <arg0>%CabMsg%</arg0>\n".
    " <arg1>%DadMsg%</arg1>\n".
    " </wsn:executar>\n".
    " </soapenv:Body>\n".
    "</soapenv:Envelope>";

    //Ambiente: 1 = Produção, 2 = Homologação
    $amb = '1';
    if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){
    $amb = '2';
    }
    $cab = $this->cabecalho;
    $cab = str_replace('%amb%', $amb, $cab);

    //xml
    $xml = $this->rpsAsXML();
    file_put_contents("$fname", $xml);


    $cab = htmlentities($cab, ENT_XML1 | ENT_NOQUOTES);
    $xml = htmlentities($xml, ENT_XML1 | ENT_NOQUOTES);
    $envelope = str_replace('%CabMsg%', $cab, $envelope);
    $envelope = str_replace('%DadMsg%', $xml, $envelope);
    file_put_contents("${rps_dir}${rps_id}.soap", $envelope);

    $headers = array(
    "Content-type: text/xml;charset=UTF-8",
    "Accept-Encoding: gzip,deflate",
    "SOAPAction: \"\"",
    "Content-length: ".strlen($envelope),
    );

    $url = $this->end_prod;


    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 300);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $envelope);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    //A prefeitura bloqueia os IPs externos
    //$proxy = '200.255.122.174:8080';
    //$proxy = '200.222.211.54:8080';
    //curl_setopt($ch, CURLOPT_PROXY, $proxy);
    //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

    $live = true;
    if ($live) {
    //Live Mode
    $html = curl_exec($ch);
    // Converte de UTF-8 para ISO-8859
    //$html = utf8_decode(curl_exec($ch));
    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    $return->status = $httpcode;
    file_put_contents("$fname.ret", $html);
    } else {
    //Test Mode
    curl_close($ch);
    $httpcode = 200;
    $return->status = $httpcode;
    $html = file_get_contents("$fname.ret");
    }

    if ($httpcode!=200){
    preg_match_all('/<faultstring>(.*?)<\/faultstring>/s', html_entity_decode($html), $matches);
    $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html);

    $return->data['errors'][] = [
    "codigo" => $httpcode,
    "mensagem" => $response,
    "correcao" => ""
    ];

    return $return;
    }

    //Extrai
    preg_match_all('/<return>(.*?)<\/return>/s', html_entity_decode($html), $matches);
    $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html);

    $return = $this->parseGerarNfseResponse($response, $return);

    return $return;
    }

    public function parseGerarNfseResponse($response, $return){

    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    $dom->loadXML($response);

    $xp = new DOMXPath($dom);
    $xp->registerNamespace('fake', "http://www.ctaconsult.com/nfse");

    // /retornoNfseLote/errors/erro
    $nodes = $xp->query("/*/*/*[name()='erro']");
    if ($nodes->length != 0){
    if (!array_key_exists('errors', $return->data))
    $return->data['errors'] = [];

    for ($i = 0; $i<$nodes->length; $i++){
    $msg = $nodes->item($i);

    //Tags
    $cod = $msg->getElementsByTagName("codigo");
    if ($cod->length>0) {
    $cod = $cod->item(0);
    $cod = $cod->nodeValue;
    if (strlen($cod)>5) $cod = "E00"; //Texto redundante
    } else
    $cod = "E00";

    $txt = $msg->getElementsByTagName("descricao");
    if ($txt->length>0) {
    $txt = $txt->item(0);
    $txt = $txt->nodeValue;
    } else
    $txt = "";

    $cor = $msg->getElementsByTagName("ns:correcao");
    if ($cor->length>0) {
    $cor = $cor->item(0);
    $cor = $cor->nodeValue;
    } else
    $cor = "";

    //Retorno
    $return->data['errors'][] = [
    "codigo" => $cod,
    "mensagem" => $txt,
    "correcao" => $cor
    ];
    }
    return $return;
    }

    //Gerou a Nota Fiscal

    $nodes = $xp->query("/*[name()='retornoNfseLote']");
    if ($nodes->length != 0){
    $nfseId = "";
    $msg = $nodes->item(0);

    $id = $msg->getElementsByTagName("protocolo");
    $id = ($id->length>0)?$id = $id->item(0)->nodeValue:"0";
    $num = $msg->getElementsByTagName("numeroNota");
    $num = ($num->length>0)?$num = $num->item(0)->nodeValue:"0";
    $cod = $msg->getElementsByTagName("chaveSeguranca");
    $cod = ($cod->length>0)?$cod = $cod->item(0)->nodeValue:"0";
    $link = $msg->getElementsByTagName("linkPdfNota");
    $link = ($link->length>0)?$link = $link->item(0)->nodeValue:"0";

    //Garante que o diretório exista
    $nfs_dir = $this->nfs_dir;
    $fname = "${nfs_dir}${num}.xml";
    if (!file_exists(dirname("$fname"))) {
    mkdir(dirname("$fname"), 0777, true);
    }
    file_put_contents($fname, $msg->ownerDocument->saveXML());

    $return->data['nfseId'] = $id;
    $return->data['numero'] = $num;
    $return->data['codigoVerificacao'] = $cod;
    $return->data['url'] = "http://$link";
    $return->data['success'] = true;
    }


    return $return;
    }

    public function rpsAsXML()
    {
    //DOM
    $dom = new DOMDocument('1.0', 'utf-8');
    $dom->formatOutput = true;
    $dom->preserveWhiteSpace = true;

    //<nfseLote xmlns="http://www.ctaconsult.com/nfse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    $nfseLote = $dom->createElement("nfseLote");
    $nfseLote->setAttribute("xmlns", "http://www.ctaconsult.com/nfse");
    $nfseLote->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    $dom->appendChild($nfseLote);

    //Formato yyyy-mm-dd
    $dataEmissao = date("'Y-m-d\TH:i:s");
    if ($this->rps->dataEmissao)
    $dataEmissao = $this->rps->dataEmissao;

    $nfseLote->appendChild($dom->createElement("codigoMunicipio",803));
    $nfseLote->appendChild($dom->createElement("dtEmissao", $dataEmissao));
    $nfseLote->appendChild($dom->createElement("notaIntermediada", 1)); //1-Sim, 2-Não

    //Autenticacao
    $auth = $dom->createElement("autenticacao");
    $auth->appendChild($dom->createElement("token", 'SEU_TOKEN'));
    $nfseLote->appendChild($auth);

    //prestador
    $prestador = $dom->createElement("prestador");
    $nfseLote->appendChild($prestador);

    $tipoPessoa = $dom->createElement("tipoPessoa", 2); //1- Pessoa Fisica, 2 - Juridica
    $prestador->appendChild($tipoPessoa);
    $cnpj = $dom->createElement("cnpj", $this->conf->cnpj);
    $prestador->appendChild($cnpj);
    $im = $dom->createElement("inscricaoMunicipal", $this->conf->inscricaoMunicipal);
    $prestador->appendChild($im);
    $razaoSocial = $dom->createElement("razaoSocial", $this->conf->razaoSocial);
    $prestador->appendChild($razaoSocial);

    //Endereço
    $endereco = $dom->createElement("endereco");
    $prestador->appendChild($endereco);

    $endereco->appendChild($dom->createElement("logradouro", 'RUA'));
    $endereco->appendChild($dom->createElement("complemento", 'COMPLEMENTO'));
    $endereco->appendChild($dom->createElement("bairro", 'JUCARA'));
    $endereco->appendChild($dom->createElement("cep", '65919170'));
    $endereco->appendChild($dom->createElement("codigoMunipio", 803));
    $endereco->appendChild($dom->createElement("descricaoMunicipio", 'IMPERATRIZ'));
    $endereco->appendChild($dom->createElement("codigoEstado", 'MA'));
    $endereco->appendChild($dom->createElement("descricaoEstado", 'MA'));

    $prestador->appendChild($dom->createElement("email", 'mail@exemplo.com.br'));
    $prestador->appendChild($dom->createElement("telefoneDdd", '98'));
    $prestador->appendChild($dom->createElement("telefoneNumero", '12345678'));

    //Tomador
    $tomador = $dom->createElement("tomador");
    $tomador->appendChild($dom->createElement("tomadorIdentificado", 1)); //1-Sim, 2-Não

    if (strlen($this->rps->cliente->cpfCnpj)==11){
    $tomador->appendChild($dom->createElement("tipoPessoa", 1)); //1- Pessoa Fisica, 2 - Juridica
    $tomador->appendChild($dom->createElement("cpf", $this->rps->cliente->cpfCnpj));
    } else{
    $tomador->appendChild($dom->createElement("tipoPessoa", 2));
    $tomador->appendChild($dom->createElement("cnpj", $this->rps->cliente->cpfCnpj));
    }

    if (property_exists($this->rps->cliente, 'inscricaoMunicipal'))
    if ($this->rps->cliente->inscricaoMunicipal)
    $tomador->appendChild($dom->createElement("inscricaoMunicipal", $this->rps->cliente->inscricaoMunicipal));

    $tomador->appendChild($dom->createElement("razaoSocial", $this->rps->cliente->nome));

    //Endereço
    $cidade = $this->ibgeToTOM($this->rps->cliente->endereco); //Converter de IBGE para TOM

    $endereco = $dom->createElement("endereco");
    $endereco->appendChild($dom->createElement("logradouro", $this->rps->cliente->endereco->logradouro));
    $endereco->appendChild($dom->createElement("complemento", $this->rps->cliente->endereco->numero));
    $endereco->appendChild($dom->createElement("bairro", $this->rps->cliente->endereco->bairro));
    $endereco->appendChild($dom->createElement("cep", $this->rps->cliente->endereco->cep));
    if ($cidade->codigoMunicipio){
    $endereco->appendChild($dom->createElement("codigoMunipio", $cidade->codigoMunicipio));
    $endereco->appendChild($dom->createElement("descricaoMunicipio", $cidade->descricaoMunicipio));
    $endereco->appendChild($dom->createElement("codigoEstado", $cidade->codigoEstado));
    $endereco->appendChild($dom->createElement("descricaoEstado", $cidade->descricaoEstado));
    }
    $tomador->appendChild($endereco);

    $nfseLote->appendChild($tomador);

    //atividadeExecutada
    $atividadeExecutada = $dom->createElement("atividadeExecutada");

    $atividadeExecutada->appendChild($dom->createElement("codigoServico", '0901'));
    $atividadeExecutada->appendChild($dom->createElement("descricaoServico", 'HOSPEDAGEM DE QUALQUER NATUREZA EM HOTEIS APART SERVICE CONDOMINIAIS FLAT APART HOTEIS HOTEIS RESIDENCIA RESIDENCE SERVICE SUITE SERVICE HOTELARIA MARITIMA MOTEIS PENSOES E CONGENERES; OCUPACAO POR TEMPORADA COM FORNECIMENTO DE SERVICO (O VALOR DA ALIMENTACAO E GORJETA QUANDO INCLUIDO NO PRECO DA DIARIA FICA SUJEITO AO IMPOSTO SOBRE SERVICOS)'));
    $atividadeExecutada->appendChild($dom->createElement("codigoAtividade", '551080100'));
    $atividadeExecutada->appendChild($dom->createElement("descricaoAtividade", 'HOTEIS'));
    $local = $dom->createElement("localPrestacao");
    $local->appendChild($dom->createElement("codigoEstado", 'MA'));
    $local->appendChild($dom->createElement("descricaoEstado", 'MA'));
    $local->appendChild($dom->createElement("codigoMunipio", 803));
    $local->appendChild($dom->createElement("descricaoMunicipio", 'IMPERATRIZ'));
    $atividadeExecutada->appendChild($local);
    $atividadeExecutada->appendChild($dom->createElement("tipoTributacao", 4)); //Tipo tributacao 1 - Isento de ISSQN, 2 - IMUNE, 3 - EXIGIBILIDADE SUSPENSA, 4 - TRIBUTÁVEL, 5 - NÃO INCIDENTE NO MUNICÍPIO, 6 - TRIBUTÁVEL S.N., 7 - TRIBUTÁVEL FIXO, 8 - NÃO TRIBUTÁVEL, 9 - TRIBUTÁVEL MEI
    $atividadeExecutada->appendChild($dom->createElement("tipoRecolhimento", 1)); //Tipo recolhimento 1 - PRÓPRIO, 2 - RETIDO, 3 - ISENTO DE RECOLHIMENTO

    $aliquotaIss = 0;
    if (property_exists($this->rps->servico, 'aliquotaIss'))
    $aliquotaIss = $this->rps->servico->aliquotaIss;
    if ($aliquotaIss == 0)
    $aliquotaIss = (0.00+$this->conf->aliquotaIss);
    if ($aliquotaIss == 0)
    throw new Exception("Informação aliquotaIss não encontrada.");
    if ($aliquotaIss >= 1)
    throw new Exception("Informação aliquotaIss ($aliquotaIss) está fora do padrão.");

    //Formato da TAG aliquota 5% = 5.00 ao invés de 0.05
    $atividadeExecutada->appendChild($dom->createElement("aliquota", $aliquotaIss*100));

    $nfseLote->appendChild($atividadeExecutada);

    //deducoes
    $deducoes = $dom->createElement("deducoes");
    $deducoes->appendChild($dom->createElement("tipo", 1)); //Tipo recolhimento 1 - SEM DEDUÇÃO, 2 - MAPA DE MATERIAIS, 3 - PERCENTUAL, 4 - POR VALOR, 5 - PERCENTUAL / MAPA DE MATERIAIS, 6 - PUBLICIDADE, 7 - MAPA DE DEDUÇÕES PARA INTERMEDIAÇÃO

    $nfseLote->appendChild($deducoes);

    //detalhamentoNota
    $descricao = $this->rps->servico->descricao;
    $detalhamentoNota = $dom->createElement("detalhamentoNota");
    $nfseLote->appendChild($detalhamentoNota);

    $detalhamentoNota->appendChild($dom->createElement("descricaoNota", $descricao));
    $itensServico = $dom->createElement("itensServico");
    $detalhamentoNota->appendChild($itensServico);

    $valorTotal = (0.00+$this->rps->valorTotal);
    if ($valorTotal == 0)
    throw new Exception("Informação rps->ValorServicos não encontrada.");

    $valorIss = round($valorTotal * $aliquotaIss, 3, PHP_ROUND_HALF_EVEN);

    $item = $dom->createElement("item");
    $item->setAttribute("nItem", "1");
    $item->appendChild($dom->createElement("tributavel", 1));
    $item->appendChild($dom->createElement("descricao", 'SERVIÇOS PRESTADOS'));
    $item->appendChild($dom->createElement("quantidade", 1));
    $item->appendChild($dom->createElement("valorUnitario", $valorTotal));
    $item->appendChild($dom->createElement("valorTotal", $valorTotal));
    $itensServico->appendChild($item);

    $totais = $dom->createElement("totais");
    $totais->appendChild($dom->createElement("valotTotalNota", $valorTotal));
    $totais->appendChild($dom->createElement("valorTotalServico", $valorTotal));
    $totais->appendChild($dom->createElement("valorTotalDeducao", 0));
    $totais->appendChild($dom->createElement("valorTotalISS", $valorIss));
    $totais->appendChild($dom->createElement("valorReducaoBC", 0));
    $detalhamentoNota->appendChild($totais);

    //Retorna o RPS em formato XML sem o XML Declaration
    return $dom->saveXML($dom->documentElement);
    }

    function ibgeToTOM($endereco){

    $dir = dirname(dirname(__DIR__));

    $cidade = new stdClass();
    $cidade->codigoMunicipio = null;
    $cidade->descricaoMunicipio = null;
    $cidade->codigoEstado = null;
    $cidade->descricaoEstado = null;

    if ($endereco->cidade > 0){

    //CoRelacionamento
    $codigo_IBGE_TOM = [];
    require_once $dir."/consts/codigoIbgeTom.php";

    if (array_key_exists($endereco->cidade, $codigo_IBGE_TOM)){
    $tom = $codigo_IBGE_TOM[$endereco->cidade];
    $cidade->codigoMunicipio = $tom[0];
    $cidade->descricaoMunicipio = $tom[1];
    }

    //CoRelacionamento
    $codigo_IBGE_UF = [];
    require_once $dir."/consts/codigoIbgeUf.php";

    $id = substr(''.$endereco->cidade, 0, 2)+0;
    if (array_key_exists($id, $codigo_IBGE_UF)) {
    $uf = $codigo_IBGE_UF[$id];
    $cidade->codigoEstado = $id;
    $cidade->descricaoEstado = strtoupper($this->remove_accents($uf[0]));
    }
    }

    return $cidade;
    }

    function remove_accents($string) {
    if ( !preg_match('/[\x80-\xff]/', $string) )
    return $string;

    $chars = array(
    // Decompositions for Latin-1 Supplement
    chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
    chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
    chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
    chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
    chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
    chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
    chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
    chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
    chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
    chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
    chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
    chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
    chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
    chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
    chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
    chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
    chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
    chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
    chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
    chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
    chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
    chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
    chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
    chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
    chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
    chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
    chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
    chr(195).chr(191) => 'y',
    // Decompositions for Latin Extended-A
    chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
    chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
    chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
    chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
    chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
    chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
    chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
    chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
    chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
    chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
    chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
    chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
    chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
    chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
    chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
    chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
    chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
    chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
    chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
    chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
    chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
    chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
    chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
    chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
    chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
    chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
    chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
    chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
    chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
    chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
    chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
    chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
    chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
    chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
    chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
    chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
    chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
    chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
    chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
    chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
    chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
    chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
    chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
    chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
    chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
    chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
    chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
    chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
    chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
    chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
    chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
    chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
    chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
    chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
    chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
    chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
    chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
    chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
    chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
    chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
    chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
    chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
    chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
    chr(197).chr(190) => 'z', chr(197).chr(191) => 's'
    );

    $string = strtr($string, $chars);

    return $string;
    }

    }