Rss

  • youtube
  • linkedin
  • google

Archives for : PHP

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.

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 >>

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 >>

Convertendo xor, shr e shl de Delphi para PHP

Estou migrando um software feito em Delphi para PHP e me deparei com um problema em uma maldita bendita função de criptografia.

Sofri um bocado tentando reescrever a função não pela complexidade do código e sim com as diferenças nos resultados.

A função faz uso dos operadores XOR e SHR na versão Delphi. O SHR foi relativamente fácil graças a experiência com operadores bit a bit e como a documentação do Delphi diz que o operador retira bits à direita

Continue Reading >>