Rss

  • youtube
  • linkedin
  • google

Archives for : Desenvolvimento

Codigo de validação de CPF para Javascript

O código abaixo é de uma função em Javascript otimizada para ter o menor numero de complexidade ciclomática linhas que consegui baseado na explicação presente no artigo Algoritimo de validação de CPF brasileiro – Cadastro de Pessoa Física. Ele tem uma ligeira alteração no momento do cálculo do segundo digitido verificador. Ao invés de começar pelo segundo algarismo, o codigo começa pelo primeiro e usa o valor 11 como multiplicador. Outra alteração visivel é que para evitar a necessidade de comparação para saber se estamos no nono e decimo digitos, atribuo o valor zero ao ultimo elemento (indice 10) para reduzir mais uma comparação.

O algoritmo utilizado é o método 1 explicado no artigo e há um pequeno truque para evitar a comparação com o resto igual a 10 que é fazer o módulo de 10 do resto.

   // Codigo que valida um CPF informado quanto a validade de seus dígitos verificadores.

const validarCpf = (cpf) => {
  if (cpf.length !== 11) { // Supõe-se já vir filtrado o valor
    return false;
  }
  let elementos = cpf.split(''); // convertendo a string em array
  elementos[10] = 0; // Forçando ao valor da ultima multiplicacao ser zero
  let somaA = 0;
  let somaB = 0;

  elementos.reduce(function(i, valor, indice) {
    let multiplicador = 11 - indice;
    somaB += (valor * multiplicador);
    somaA += (valor * (multiplicador > 2 ? multiplicador - 1 : 0));
  }, somaA);
  let moduloA = ((somaA * 10) % 11) % 10;
  let moduloB = ((somaB * 10) % 11) % 10;
  return cpf.replace(/\d{9}(\d{2})$/g, '$1') == ("" + moduloA + moduloB);
}

Você pode testar esse código aqui.

Codigo de validação de CPF para PHP

O código abaixo é de uma função em PHP otimizada para ter o menor numero de complexidade ciclomática que consegui baseado na explicação presente no artigo Algoritimo de validação de CPF brasileiro – Cadastro de Pessoa Física. Ele tem uma ligeira alteração no momento do cálculo do segundo digitido verificador. Ao invés de começar pelo segundo algarismo, o codigo começa pelo primeiro e usa o valor 11 como multiplicador. Outra alteração visivel é que para evitar a necessidade de comparação para saber se estamos no nono e decimo digitos, atribuo o valor zero ao ultimo elemento (indice 10) para reduzir mais uma comparação.

O algoritmo utilizado é o método 1 explicado no artigo citado anteriormente e há um pequeno truque para evitar a comparação com o resto igual a 10 que é fazer o módulo de 10 do resto.

   // Codigo que valida um CPF informado quanto a validade de seus dígitos verificadores.

   /**
     * 
     * Verifica se um CPF é válido
     * @author Marcos Regis <marcos@marcosregis.com>
     * @param  string $cpf
     * @return bool
     */
    function validar(string $cpf): bool
    {
        if (strlen($cpf) != 11) {
            return false;
        }
        $elementos = (array)str_split($cpf);
        $elementos[10] = 0; // Reduz uma comparação no calculo de $somaB
        $somaA = 0;
        $somaB = 0;
        foreach ($elementos as $indice => $elemento) {
            $multiplicador = count($elementos) - $indice;
            $somaA += (int)$elemento * (int)($multiplicador > 2 ? $multiplicador - 1 : 0);
            $somaB += (int)$elemento * (int)$multiplicador;
        }

        $moduloA = (($somaA * 10) % 11) % 10;
        $moduloB = (($somaB * 10) % 11) % 10;

        return preg_replace('#\d{9}(\d{2})$#', '$1', $cpf) == $moduloA . $moduloB;
    }

Você pode testar esse código aqui.

Algoritimo de validação de CPF brasileiro – Cadastro de Pessoa Física

Neste artigo explicarei passo a passo na transformação de um algorítimo de verificação da validade de um CPF para código em PHP.

Se você já conhece o algorítmo e quer ir direto aos códigos disponíveis, clique aqui.

Mas o que é o CPF?

CPF é o acrônimo para Cadastro de Pessoa Física. Ele é um número de documento brasileiro atualmente gerenciado e emitido pela Receita Federal. Todo brasileiro tem o direito (ou o dever) de ter um e somente com ele é possível ter acesso a serviços bancários, matricular-se em cursos de graduação públicos, assumir cargo através de concurso público, ter cartão de crédito, entre outros exemplos.

Composição do CPF

O CPF é composto de onze algarismos, sendo que os ultimos três algarismos possuem significados que explicaremos a seguir.

O nono dígito, lendo da esquerda para a direita, indica a Região Fiscal onde ele foi emitido. Há dez regiões para os algarismo de zero a nove conforme tabela abaixo.

1 – DF, GO, MS, MT e TO
2 – AC, AM, AP, PA, RO e RR
3 – CE, MA e PI
4 – AL, PB, PE, RN
5 – BA e SE
6 – MG
7 – ES e RJ
8 – SP
9 – PR e SC
0 – RS

Os primeiro oito algarismos são o numero base.

Os ultimos dois algarismo são os dígitos verificadores.

Esses dígitos são gerados a partir de cálculos dos nove primeiros algarismos de acordo com a seguintes regras:

Primeiro Dígito verificador

Para o primeiro dígito, pegamos os 8 primeiros algarismos e multiplicamos cada um deles por um número iniciado em 10 e a medida em que vamos avançando para a direita, diminuimos em 1 esse multiplicador e somamos todos os resultados.

Para melhor entendimento, tomemos 123.456.789-XY como exemplo de CPF a ter o digito XY calculado.

1 x 10 = 10
2 x 9 = 18
3 x 8 = 24
4 x 7 = 28
5 x 6 = 30
6 x 5 = 30
7 x 4 = 28
8 x 3 = 24
9 x 2 = 18
Somando 10 + 18 + 24 + 28 + 30 + 30 + 28 + 24 + 18 temos 210.

Agora, com o total obtido temos duas forma de chegar ao digito verificador.

Método 1

Multiplicamos 210 por 10, dividimos por 11 e pegamos o resto.

Temos então: 210 x 10 = 2.100

2.100 / 11 = 190 com resto 10.

Se o resto for 10 o dígito verificador é zero, do contrário, o resto é o dígito verificador.

No nosso caso, como o resto é igual a 10 o primeiro dígito será 0 (zero).

Método 2

Obtemos o resto da divisão de 210 por 11.

Temos então: 210 / 11 é igual a 19 com resto 1.

Aqui temos uma regra para quando o resto for 0 (zero) ou 1 (um). Quando isso acontece o dígito verificador é zero, do contrário subtraimos o resto de 11 para obter o dígito verificador.

Para o nosso caso, como temos resto 1, o nosso primeiro dígito verificador será 0 (zero).

Segundo dígito verificador

Para obter o segundo dígito verificador, acrescentamos o primeiro dígito verificador aos 9 algarismos iniciais e fazemos novamente o mesmo processo feito para o primeiro dígito, com a diferença de que agora iniciamos a partir do segundo dígito.

Nosso CPF já está com o valor 123.456.789-0X e as operações necessárias estão abaixo.
2 x 10 = 20
3 x 9 = 27
4 x 8 = 32
5 x 7 = 35
6 x 6 = 36
7 x 5 = 35
8 x 4 = 32
9 x 3 = 27
0 x 2 = 0
Somando 20 + 27 + 32 + 35 + 36 + 35 + 32 + 27 + 0 temos 244.

Agora, com o total obtido devemos usar uma das duas formas já explicadas para chegar ao dígito verificador.

Método 1

Multiplicamos 244 por 10, dividimos por 11 e pegamos o resto.

Temos então: 244 x 10 = 2.440

2.440 / 11 = 221 com resto 9.

Se o resto for 10 o dígito verificador é zero, do contrário, o resto é o dígito verificador e no nosso caso temos 9 como segundo dígito verificador.

Método 2

Obtemos o resto da divisão de 244 por 11.

Temos então: 244 / 11 é igual a 22 com resto 2.

Lembrando que temos uma regra para quando o resto for 0 (zero) ou 1 (um) o dígito verificador é zero.

Caso seja maior que 1 subtraimos esse valor de 11 para obter o dígito verificador.

Para o nosso caso, temos 11 – 2 = 9 como nosso segundo dígito verificador que é o mesmo valor obtido no método 1.

CPF tem um limite para emissão?

Na teoria, podemos ter até 10^8 ou 100.000.000 (cem milhões) de combinações possíveis para cada região. Na prática temos um pouco menos devido ao não uso de algarismos repetidos, por exemplo. Embora pareça um número bem grande, ele deverá ser remodelado em algum momento, já que não pode ser reutilizado mesmo quando uma pessoa falece.

Supondo que já existam na região 8 (estadao de São Paulo) cerca de 40 milhões de CPFs emitidos (não consegui dados fidedignos em 2022 por isso estou usando um número aproximado da população residente que é de 44,5 milhões de pessoas), restariam aproximadamente 60 milhões de CPFs disponíveis. Com a atual taxa de crescimento de CPFs (ano de 2022) em cerca de 600 mil por ano, o sistema deve aguentar pouco menos de 100 anos.

Chegamos aqui ao final da explicação e do exemplo sobre a composição do CPF. O nosso CPF de exemplo ficou como 123.456.789-09. Abaixo temos alguns exemplos de códigos tanto para gerar os dígitos verificadores, quanto para validá-los.

Códigos

Versão PHP.

Versão Javascript.

Docker on Ubuntu. Service nginx failed to build: ADD failed: stat /var/lib/docker/tmp/docker-builder(…)/startup.sh: no such file or directory

Docker in Ubuntu

Sometimes, when using Laradock, this error occurs after trying a container rebuild with no such file or directory message on docker-compose up -d –build nginx command.

Its not clear to me what is the actual issue, but running the command with sudo, we can run it sucessfully.

Seems that the regular user need access rights to directory /var/lib/docker/tmp/ but do not have. So, running with sudo the trouble is bypassed and the build can finished normally.

After build containers with sudo, is possible to unload it and reload without sudo.

Datatables + HTML 5 Export Buttons + Laravel-Mix (Webpack)

In the last days, I have experienced a problem trying to use Datatables and Bootstrap 4 with support for exporting results to Excel and PDF using Laravel-Mix. After hours and hours trying to put all scripts to work together, I finally win. So, I decide to write this little how to for those with same kind of troubles.



Continue Reading >>

Using jQueryMask Plugin to format dates in different patterns

jQuery Mask Plugin is a great Javascript library to format fields for presentation and/or to force a properly input by users.

Here, I show how to deal with input or another HTML element to display dates when the source date has a different format from target element.

Example:

  • We have a datetime with Year-Month-Day Hour:Minute:Seconds and need to show only the Year/Month/Day part.
  • We have da date in Year-Month-Day and need to format to Day/Month/Year.

jQueryMask is very simple to use. It do not need to much to mask whatever you need. Take a look at examples on his website.

If you need to format a simple date field (even in a non-input element), just use the code below.

jQuery('[data-role="date"]).mask("TC99/M9/D9", {
        placeholder: "____/__/__",
        translation: {
            "D": {pattern: /[0-3]/, optional: false, recursive: true},
            "M": {pattern: /[01]/, optional: false, recursive: true},
            "T": {pattern: /[12]/, optional: false, recursive: true},
            "C": {pattern: /[09]/, optional: false, recursive: true}
        }
    });

The code above can mask and pre-validate dates in YEAR/MONTH/DAY format.

With an input like

<input type="text" data-role="date" value="2018-06-11 15:47" />

would be changed his value to 2018/06/11.

If you try to type another date (after clear, of course) you cannot begin with a number different from 1 or 2. This reason is that our mask have a translation to be done when allowing chars. If the pattern does not match, the char is erased.

The meaning of “TC99/M9/D9” mask is:

  • Must begin with 1 or 2 (Translation T: /[12]/ – Custom format)
  • Must have number 0 or 9 (Translation C: /[09]/ – Custom format)
  • Must have a number (any) (Translation 9 – MaskPlugin Core format)
  • Must have a number (any) (Translation 9 – MaskPlugin Core format)
  • A slash will be added automatic ( / )
  • Must have number 0 or 1 (Translation M: /[01]/ – Custom format)
  • Must have a number (any) (Translation 9: MaskPlugin Core format)
  • A slash will be added automatic ( / )
  • Must have number 0, 1, 2 or 3 (Translation D: /[0-3]/ – Custom format)
  • Must have a number (any) (Translation 9: MaskPlugin Core format)

Of course, there is no real validation. You can type “2999/19/39” and this is not a valid date, but is almost done.

So, to format in another way, just change mask parameter order.

But, if the source date is in a different pattern, like MONTH/DAY/YEAR, the mask do not work. The date output for “06/11/2018 15:40” will be weird “1018/15/0“.

To handle different date formats will be needed more than simple mask. We will need a function.

Look the code below

        var maskBehaviorDateTime = function (val, e, field) { // This function must return a MASK
                    var msk = "TC99/M9/D9"; // Our desired format
                    var v = field.is('input') ? field.val() : field.text(); // is a input or another html element??
                    v = v.replace(/\D/g, ''); // stripe non digits
                    if (v != '') { // has value?
                        if ((/^[01]\d[0-3]\d\d{4}$/).test(v)) { //test if pattern match Month/Day/Year only
                            v = v.replace(/^(\d{4})(\d{2})(\d{2})$/, '$3/$2/$1');
                        } else if ((/^[01]\d[0-3]\d\d{4}[012]\d[0-5]\d$/).test(v)) { //test if pattern match Month/Day/Year Hour:Minute
                            v = v.replace(/^(\d{2})(\d{2})(\d{4})(\d{2})(\d{2})$/, '$3/$2/$1');
                            // If we need to show hour and minute, returned mask must be changed too
                            // v = v.replace(/^(\d{2})(\d{2})(\d{4})(\d{2})(\d{2})$/, '$3/$2/$1 $4:$5');
                            // msk = 'TC99/M9/D9 h9:m9'; // h and m must be exists in Translation options
                        }
                        field.is('input') ? field.val(v) : field.text(v);
                    }
                    return msk;
                },
                optionsDateTime = {
                    placeholder: "____/__/__",
                    translation: {
                        "D": {pattern: /[0-3]/, optional: false, recursive: true},
                        "M": {pattern: /[01]/, optional: false, recursive: true},
                        "T": {pattern: /[12]/, optional: false, recursive: true},
                        "C": {pattern: /[09]/, optional: false, recursive: true},
                        "h": {pattern: /[0-2]/, optional: true, recursive: true},
                        "m": {pattern: /[0-5]/, optional: true, recursive: true}
                    }
                };
        jQuery('[data-role="date"]').mask(maskBehaviorDateTime,  optionsDateTime);

Now we have two more Translation Pattern (h and m). h means that the n-index position must have numbers 0, 1 or 2 and m numbers between 0 and 5. Keep in mind that CASE matters.

With the above code, we can format and show date in several ways. just change .test() and .replace() pattern to fill your desired pattern.

This is the code that I am using to format Database datetime fields with YEAR-MONTH-DAY HOUR:MINUTE:SECOND in html elements with DAY/YEAR/MONTH HOUR:MINUTE

    var maskBehaviorDateTime = function (val, e, field) {
            // Caso já exista um valor, o formata no padrão dd/mm/yyyy com o opcional hh:mm:ss
            var msk = "TC99/M9/D9 h9:m9:s9";
            if (field.attr("data-original-value") == undefined) {
                var o = field.is('input') ? field.val() : field.text();
            } else {
                var o = field.attr("data-original-value");
            }
            v = o.replace(/\D/g, '');
            if (v != '') {
                field.attr("data-original-value") == undefined && field.attr("data-original-value", o);
                if ((/^[12][09]\d{2}[01]\d[0123]\d$/).test(v)) { // year/month/day
                    v = v.replace(/^(\d{4})(\d{2})(\d{2})$/, '$3/$2/$1');
                    msk = "D9/M9/TC99";
                } else  if ((/^[12][09]\d{2}[01]\d[0123]\d[012]\d[0-5]\d$/).test(v)) { // year/month/day hour:minute
                    v = v.replace(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})$/, '$3/$2/$1 $4:$5');
                    msk = "D9/M9/TC99 h9:m9";
                } else if ((/^[12][09]\d{2}[01]\d[0123]\d[012]\d[0-5]\d[0-5]\d$/).test(v)) { // year/month/day hour:minute:second
                    v = v.replace(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/, '$3/$2/$1 $4:$5:$6');
                    msk = "D9/M9/TC99 h9:m9:s9";
                }
                field.is('input') ? field.val(v) : field.text(v);
            }

            return msk;
        },
        optionsDateTime = {
            placeholder: "__/__/____",
            translation: {
                "D": {pattern: /[0-3]/, optional: false, recursive: true},
                "M": {pattern: /[01]/, optional: false, recursive: true},
                "T": {pattern: /[12]/, optional: false, recursive: true},
                "C": {pattern: /[09]/, optional: false, recursive: true},
                "h": {pattern: /[0-2]/, optional: true, recursive: true},
                "m": {pattern: /[0-5]/, optional: true, recursive: true},
                "s": {pattern: /[0-5]/, optional: true, recursive: true}
            },
        };
    jQuery('[data-role="date"]').mask(maskBehaviorDateTime,  optionsDateTime);

With an input like

<input type="text" data-role="date" value="2018-06-11 15:40">

Output will be

11/06/2018 15:40

Hope this help you!

Binding several values in PDO SQL Statement (PDOStatement)

Sometimes we need to search a single value through several columns when building SQL instructions.

Suppose the table below

  • [ENTITY_ONE]
    • ID
    • COLUMN_A
    • COLUMN_B
    • COLUMN_C
    • COLUMN_D
    • COLUMN_E

If we need search a single value on columns B,D and E we will need use the following instruction

SELECT ID, COLUMN_A,(...COLUMNS..), COLUMN_E 
FROM ENTITY_ONE WHERE COLUMN_B LIKE '%search_value%' OR COLUMN_D LIKE '%search_value%' OR COLUMN_E LIKE '%search_value%';

In PHP code we can do

$q = '%search_value%';
$sql = "SELECT * FROM ENTITY_ONE WHERE COLUMN_B LIKE '$q' OR COLUMN_D LIKE '$q' OR COLUMN_E LIKE '$q'; 
$pdo = new PDO($dsn, $user, $pass); 
$stmt = $pdo->query($sql);

Well, this can work but we know that isn’t the best approach. We need use Binding Values to avoid SQL injection and other malicious treats.

So, the code can be modified to

$q = '%search_value%'; 
$sql = "SELECT * FROM ENTITY_ONE WHERE COLUMN_B LIKE ? OR COLUMN_D LIKE ? OR COLUMN_E LIKE ?; 
$args = [$q, $q, $q]; // We need one entry for each "?" on instruction
$pdo = new PDO($dsn, $user, $pass); 
$stmt = $pdo->prepare($sql);
$stmt->execute($args);

Much better, but, when building complex SQL instruction, things can be confusing with lots of arguments and don’t forget: ORDER MATTERS.

Happily PDO can bind values in different order when using named bindings.

$q = '%search_value%'; 
$sql = "SELECT * FROM ENTITY_ONE WHERE COLUMN_B LIKE :first_arg OR COLUMN_D LIKE :second_arg OR COLUMN_E LIKE :third_arg; 

$pdo = new PDO($dsn, $user, $pass); 
$stmt = $pdo->prepare($sql); 
// One way
$args = [':first_arg' => $q, ':third_arg' =>$q, ':second_arg' => $q]; // We need one entry for each ":name" on instruction 
$stmt->execute($args); 
// Another way
$stmt->bindValue(':third_arg'. $q);
$stmt->bindValue(':first_arg', $q); 
$stmt->bindValue(':second_arg', $q);

$stmt->execute(); 

Hmm, seems that this isn’t good enough. We only change the use of 1-indexed placeholder to a :named placeholder. There’s no gain beyond of code readable and the possibility to bind in any order.

Yes, but now we can do the best approach when using one unique search term in several columns. We can use only one bind to one or more :named placeholders ’cause PDO is smart and clever. Look our final code here.

$q = '%search_value%'; 
$sql = "SELECT * FROM ENTITY_ONE WHERE COLUMN_B LIKE :unique_arg OR COLUMN_D LIKE :unique_arg OR COLUMN_E LIKE :unique_arg; 
$pdo = new PDO($dsn, $user, $pass); 
$stmt = $pdo->prepare($sql); 
// One way 
$args = [':unique_arg' => $q]; // We can bind all :name with only one term 
$stmt->execute($args); 
// Another way 
$stmt->bindValue(':unique_arg', $q); 
$stmt->execute(); 

Can save a lot of typing when writing many SQL instruction using same argument.

Naming files using list from 0 to Z

Today I was coding some scripts and found a little trouble to use a defined pattern.

The pattern is to create files where the sequence starts in 0 (zero) and cannot be repeated until Z.

Example:

myfile0.ext, myfile1.ext, myfile2.ext, (...), myfile9.ext, myfileA.ext, myfileB.txt, (...), myfileZ.txt

Well, this is not a big trouble so I did use this code.

// Filename
$seq = $last_used_seq = '';
$seqs = array_merge(range('0','9'), range('A', 'Z'));]
$l = 1;
while (!in_array($seq, $seqs)) {
    $seq = chr(ord($last_used_seq) + $l++);
}

But

$seq

did not gave the expected value of 0 (zero) on first run. Instead, it was blank.

Debugging the variables, I saw that the while never evaluates to true. Attempting to reproduce on command line I saw that

in_array($seq, $seqs);

always return true. I tryed to use “”, “R” and no matter what value I used, still returning true.

So I change to use STRICT argument for in_array to true and works for ‘A’ through ‘Z’, but not for ‘0’ through ‘9’.

while (!in_array($seq, $seqs, true)) {
    $seq = chr(ord($last_used_seq) + $l++);
}

Damn… PHP is right, “0” is not strictly equals to 0. The Chr function return string and

range('0', '9')

creates an array with integer values.

So, I changed the approach to evaluate all values with STRICT, because I would like to create a nice and clean code without no other functions to be used.

This is the final code that I’m using:

// Initial values 
$seq = '';
$seqs = array_merge(range(ord('0'),ord('9')), range(ord('A'), ord('Z')));
$seqs = array_map('chr', $seqs);
$l = 1;
while (!in_array($seq, $seqs, true)) {
    $seq = chr(ord($infos['last_seq']) + $l++);
}

// Filenames
foreach ($itens_for_files as $key => $itens) {
    // ... Another codes to fill file    
    $seq = chr(ord($seq) + 1);
    while (!in_array($seq, $seqs, true)) {
    $seq = chr(ord($seq) + 1);
    $filename = 'myfile' . $seq . '.ext';
    // ...
}

How you can see, I changed the $seqs initial values from ‘0’ to your ASCII code and get back to your value that gave me an array with all values in string type.

See you!

PHP Comparison Error

Today, I was writing a script in PHP to be used in the command line when I came across unexpected behavior (at least on my part).
The script should receive three arguments, the last of them a list containing one or more numeric codes.
Trying to validate this last argument was getting a different result than imagined.
See the code snippet that I was using:

// test.php
if (php_sapi_name() == 'cli') {
    $di = isset($argv[1]) ? $argv[1] : date('Y-m-d'); // Initial Date
    $df = isset($argv[2]) ? $argv[2] : date('Y-m-d'); // Final Date
    $prods = isset($argv[3]) ? explode(',', $argv[3]) : array(); // Code List

    ##### Validating
    // Initial Date
    if ($di != date('Y-m-d', strtotime($di))) {
        echo "\n";
        echo "ERROR! Invalid INITIAL DATE!\n";
        exit;
    }
    // Final Date
    if ($df != date('Y-m-d', strtotime($df))) {
        echo "\n";
        echo "ERRO! Invalid FINAL DATE!\n";
        exit;    
    }

    // Codes
    if (count($prods) > 0) {
        foreach ($prods as $prod) {
            if ($prod != (int)$prod) {
                echo "\n";
                echo "ERROR! The CODE " . $prod . " is invalid!\n" ;
                exit;
            }
        }
    }
    echo "DONE!";
}

Continue Reading >>

jQuery.html() não funciona em Internet Explorer

Recentemente tive problemas com um código javascript que utiliza jQuery e que funcionava em diversos navegadores como o Chrome, o Firefox e algumas versões do Internet Explorer, mas que teimava em não funcionar em Internet Explorer 7 e 8.
Segue o código:

$.post(url,{ options }, 
  function (response) {
     $('#myElement').html(response);
  },
'text');

Após alguns testes percebi que não era um problema do método, pois em outros códigos ele se comportava como o esperado.
Então debugando minuciosamente o código e as respostas do método Ajax percebi um pequeno erro de sintaxe no HTML e foi só o corrigir que o IE 7 exibiu corretamente a resposta.
Segue então a dica, caso tenha problemas com o método jQuery.html(), verifique antes de tudo se o conteúdo a ser escrito no elemento é um código html sem erros, pois a validação do IE 7/8 não permitirá escrever HTML com nenhum erro, por menor que seja.