Função para cálculo de frete dos correios

PHP
Enviado por Pedro Faria em Seg, 22/10/2007 - 08:15.PHP

Trocando uma idéia com Diego Hermes (um camarada lá do fórum drupal-br) resolvi pesquisar se alguém já havia feito isso e descobri que existe uma url que você acessa e recebe os valores e parâmetros via GET.

Então eu resolvi fazer uma função BEEEEEEEEEM SIMPLES que pega os valores.

  1. <?php
  2.  
  3. define('FRETE_PAC',        '41106');
  4. define('FRETE_SEDEX',      '40010');
  5. define('FRETE_SEDEX_10',   '40215');
  6. define('FRETE_SEDEX_HOJE', '40290');
  7. define('FRETE_E_SEDEX',    '81019');
  8. define('FRETE_MALOTE',     '44105');
  9.  
  10. /**
  11. * calcula_frete
  12. *
  13. * @param mixed $servico
  14. * @param mixed $origem CEP da origem
  15. * @param mixed $destino CEP do destino
  16. * @param mixed $peso Peso em Kg
  17. * @access public
  18. * @return array
  19. */
  20. function calcula_frete ($servico, $origem, $destino, $peso) {
  21.   if (!$sock = fsockopen('www.correios.com.br', 80, $errornro, $error, 60)) {
  22.     throw new Exception($error, $errornro);
  23.   }
  24.    
  25.   $msg = "GET /encomendas/precos/calculo.cfm?"
  26.         ."Servico={$servico}&cepOrigem={$origem}&cepDestino={$destino}"
  27.         ."&peso={$peso}&resposta=localhost HTTP/1.1\n"
  28.         ."Host: www.correios.com.br\nConnection: Close\n\n";
  29.  
  30.   fwrite($sock, $msg);
  31.  
  32.   while (!feof($sock)) {
  33.     $line = fgets($sock);
  34.     if (!preg_match('/^Location: \w+\?(.*)$/i',$line, $match)) continue;
  35.  
  36.     $data = array();
  37.     foreach(split('&', $match[1]) as $item) {
  38.       $t = split('=', $item);
  39.       $data[$t[0]] = trim($t[1]);
  40.     }
  41.  
  42.     break;
  43.   }
  44.   $data['Servico'] = urldecode($data['Servico']);
  45.   $data['erro'] = urldecode($data['erro']);
  46.  
  47.   return $data;
  48. }
  49.  
  50. $result = calcula_frete(FRETE_SEDEX, '20512170', '78053378', '2');
  51. var_dump($result);
  52.  
  53. ?>

Bem simples né? agora, $result contém o seguinte estrutura:

array(13) {
  ["Servico"]=>
  string(5) "SEDEX"
  ["cepOrigem"]=>
  string(8) "20512170"
  ["cepDestino"]=>
  string(8) "78053378"
  ["UFOrigem"]=>
  string(2) "RJ"
  ["LocalOrigem"]=>
  string(7) "Capital"
  ["UFdestino"]=>
  string(2) "MT"
  ["LocalDestino"]=>
  string(7) "Capital"
  ["Peso"]=>
  string(1) "1"
  ["MaoPropria"]=>
  string(1) "0"
  ["AvisoRecebimento"]=>
  string(1) "0"
  ["valorDeclarado"]=>
  string(1) "0"
  ["Tarifa"]=>
  string(4) "27.5"
  ["erro"]=>
  string(0) ""
}

Espero que seja util para alguém e se você criar algo mais elaborado, me avisa que eu posto aqui!

T+



Enviado por guest (não verificado(a)) em Ter, 27/11/2007 - 19:30.

fiz um upload para um host e só mudou o tipo de erro

Parse error: syntax error, unexpected T_NEW in /home/ipifila/public_html/frete.php on line 22

será que tem jeito de ver o que seria ou tem esse arquivo rodando em algum lugar?

Enviado por Pedro Faria em Ter, 27/11/2007 - 21:14.

provavelmente seu php eh 4 e este código eh para php 5.. soh adaptar a linha 22...

flw!

Enviado por guest (não verificado(a)) em Ter, 11/12/2007 - 23:37.

E ai amigo, você não tem esse script sem ser em classe e para PHP4 não?

Se tiver, me avise.

Bruno Estevao
www.sempihost.com.br

Enviado por Marlon Parizzotto (não verificado(a)) em Ter, 12/02/2008 - 10:43.

tive q fazer uma alteraçao para funcionar,
a funçao nao estava retornando nd,
entao olhando o retorno verifiquei que a para encontrar os valores
tem q mudar a linha:

if (!preg_match('/^Location: \w+\?(.*)$/',$line, $match)) continue;

para:

if (!preg_match('/^location: \w+\?(.*)$/',$line, $match)) continue;

trocar o "L" maiusculo de Location para "l" minusculo

Enviado por Pedro Faria em Qua, 20/02/2008 - 12:41.

Caro Marlon,

Você pode só colocar o modificador i na expressão regular também.

Valeu pelo comentário.

Pedro.

Enviado por Insonia (não verificado(a)) em Sáb, 10/05/2008 - 13:30.

Olá, náo tem como criar um exemplo com o cep vindo do form e chamando as paginas e colocando o nome em cada página, pois não entendi bem se uso todo o codigo numa página só eu separa.

To bem leigo nesse esquema de calculo de frete

Enviado por Pedro (não verificado(a)) em Ter, 24/06/2008 - 14:53.

Warning: pfsockopen() [function.pfsockopen]: unable to connect to www.correios.com.br:80 (Connection timed out) in /var/www/vhosts/americanbrasil.com.br/httpdocs/site/correio.php on line 21
boa tarde, alguem sabe como resolvo esse prrobleminha com o script q eu peguei acima??
eu uso o php 5
Fatal error: Uncaught exception 'Exception' with message 'Connection timed out' in /var/www/vhosts/americanbrasil.com.br/httpdocs/site/correio.php:22 Stack trace: #0 /var/www/vhosts/americanbrasil.com.br/httpdocs/site/correio.php(50): calcula_frete('40010', '13140000', '13061100', '2') #1 {main} thrown in /var/www/vhosts/americanbrasil.com.br/httpdocs/site/correio.php on line 22

Enviado por Pedro Faria em Ter, 24/06/2008 - 15:02.

É PROVÁVEL que seu host nao permita fsockopen pra fora...

imagino que seja isso!

Enviado por Anderson Henrique (não verificado(a)) em Qua, 03/09/2008 - 13:28.

quando eu rodo este script localmente pelo xammp ele funciona sem problemas, mas quando eu trasfiro para o servidor ele da um loop sem fim e trava a pagina, acho que é algumca coisa com permissao no chmod, só que nao se onde coloco a permissao, se algum poder me ajudar fico grato.

Enviado por guest (não verificado(a)) em Sex, 12/09/2008 - 14:35.

Opa pedro,

testei esse seu script e não funcionou mto bem. Chegou a dar timeout. Ae acabei adaptando algo do seu codigo num script que funcionou aqui:

<?php

define('FRETE_PAC', '41106');
define('FRETE_SEDEX', '40010');
define('FRETE_SEDEX_10', '40215');
define('FRETE_SEDEX_HOJE', '40290');
define('FRETE_E_SEDEX', '81019');
define('FRETE_MALOTE', '44105');
/**
* calcula_frete
*
* @param mixed $servico
* @param mixed $origem CEP da origem
* @param mixed $destino CEP do destino
* @param mixed $peso Peso em Kg
* @access public
* @return array
*/
calcula_frete(FRETE_SEDEX, "30840280", "30840300", "2");

function calcula_frete ($servico, $origem, $destino, $peso) {
$url = "http://www.correios.com.br/encomendas/precos/calculo.cfm?Servico=$servico&cepOrigem=$origem&cepDestino=$destino&peso=$peso&resposta=localhost";
$url = parse_url($url);

$timeout = 30;
$fp = fsockopen ($url['host'], 80, $errno, $errstr, $timeout);

if (!$fp) {
return;
echo "$errstr ($errno)<br>\n";
} else {
fputs ($fp, "GET /".$url['path'].($url['query'] ? '?'.$url['query'] : '')." HTTP/1.0\r\nHost: ".$url['host']."\r\n\r\n");
$result = "";
while (!feof($fp)) {
$result .= fgets($fp);
}
fclose ($fp);

preg_match("/localhost\?(.*)/", $result, $matches );

foreach (split("&", $matches[1]) as $key) {
$values = split("=", $key);
$output[$values[0]] = trim($values[1]);
}

return ($output);
}
}

?>

Espero ter ajudado.

Abração!

Enviado por Pedro Faria em Sex, 12/09/2008 - 16:19.

Acho que foi seis por meia... mas se funcionou pra você... Bom d+ :)

flw!

Enviado por Marcus (não verificado(a)) em Sex, 23/01/2009 - 17:37.

Muito bom mas tenho uma dúvia, como faço para pegar o prazo de entrega (2 dias, 6 dias, etc...) e informar ao meu cliente?

Enviado por Pedro Faria em Sáb, 24/01/2009 - 00:12.

Estes valores são fixos. Imagino que no próprio site do Correios você encontre estas informações.

Pedro.

Enviado por guest (não verificado(a)) em Ter, 13/04/2010 - 11:57.

Ambos nao funcionaram!!!

Enviado por Carlos Eduardo (não verificado(a)) em Sáb, 02/05/2009 - 01:29.

Olá pessoal, acabei descobrir um webservice para calculo de frete dos correios (sedex e PAC). Vou postar a função para se fazer o calculo, muito simples:

<?php

/*
| Função para calculo de frete, Sedex e Encomenda PAC
|
| @Autor Natanael L. Freire
| @E-mail natanael@w21studio.com
| @Site w21studio.com
| @service http://frete.w21studio.com
| @Apoio http://www.comocriarsites.com.br
| @Licença Gratis
|
|
| @servico 1:sedex, 2:pac, 3:sedex e pac
| @cod código de usuário (você receberá este número ao se cadastrar gratuitamente no site http://frete.w21studio.com)
| @cep cep de destino - somente números (8 digitos)
| @peso peso do volume. Peso máximo: 30. Use '.' ponto para separar as casas decimais, exemplo: 0.3
| @comprimento comprimento do volume em cm. Comprimento máximo 60. Formato aceito: somente números
| @largura largura do volume em cm. Largura máxima 60. Formato aceito: somente números
| @altura altura do volume em cm. Altura máxima 60. Formato aceito: somente números
| O resultado de comprimento + largura + altura NÃO pode ser superior a 150
|
| OBS: Todos os parametros devem ser passados dentro de aspas - preferencialmente simples
|
*/

function calcularFrete($servico, $cod, $cep, $peso, $comprimento, $largura, $altura)
{
return simplexml_load_file("http://frete.w21studio.com/calFrete.xml?cep=$cep&cod=$cod&peso=$peso&comprimento=$comprimento&largura=$largura&altura=$altura&servico=$servico");

}

$frete = calcularFrete('1', '1000', '72853035', '15', '20', '10', '5');

foreach($frete as $key => $value)
{
echo "$key = $value<br />";
}

A função é auto explicativa, mas para reforçar é importante que você faça o cadastro no site http://frete.w21studio.com e informe o seu cep de origem e peque seu código.

Enviado por Matz (não verificado(a)) em Sáb, 22/08/2009 - 00:30.

Muito bom mesmo, só uma duvida simples.
e o form?
seria algo relacionado com as ($servico, $origem, $destino, $peso)???

Enviado por radames kremer (não verificado(a)) em Sáb, 30/01/2010 - 15:56.

<?php
/*
Formatacao basica
_____________________________________________________________________________________________________
| |servico|cepori|cepdes|peso|valorD|form|comp|larg|alt|diameter|mpro|valdec|arec|emba|
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
| PAC | X | X | X | * | | X | * | * | * | * | X | * | X | * |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
| SEDEX | X | X | X | * | | | | | | | X | * | X | * |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
| SEDEX10 | X | X | X | * | | | | | | | X | * | X | * |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
| SEDEXHOJE | X | X | X | * | | | | | | | X | * | X | * |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
|SEDEX A COBRAR | X | X | X | * | * | | | | | | X | | | * |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
| eSEDEX | X | X | X | | | | | | | | | | | |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
| MALOTE | X | X | X | | | | | | | | | | | |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
X nao pode ser Nulo
* pode ser Nulo
O que estiver em branco deve ser nulo.

Valores admiciveis
servico = PAC = 41106 | SEDEX = 40010 | SEDEX10 = 40215 | SEDEXHOJE = 40290 | SEDEX A COBRAR = 40045 | eSEDEX = 81019 | MALOTE = 44105
mpro = S para entregar em mao propia e N para Nao entregar caso seja fora da area de entrega
arec = Avisar recebimento S para sim N para nao
valdec = Valor declarado valido para sedex, sedex10, sedexhoje, pac
valorD = valor declarado para sedex a cobrar
form = valido somente para pac, 1 para caixa/pacote ou 2 para rolo/prisma
peso = no site as opcoes sao 0.300 e 1 a 30 kg
com = comprimento da caixa ou do cilindro
larg = largura da caixa
alt = altura da caixa
diameter = diametro do cilindro -- para mais informaçoes de diametro e medidas verifique no site
emba - embalagens 116600055 = Caixa Encomenda 01 (18x13,5x9 cm)
116600063 = Caixa Encomenda 02 (27x18x9 cm)
870100203 = Caixa Encomenda 03 (27x22,5x13,5 cm)
116600080 = Caixa Encomenda 04 (36x27x18 cm)
116600160 = Caixa Encomenda 05 (54x36x27 cm)
765000652 = Envelope Bolha para CD
765000660 = Envelope Bolha para DVD
870200313 = Envelope SEDEX cartonado Grande (40x28 cm)
870200330 = Envelope SEDEX plástico Grande (40x28 cm)
cepori = cep de origem
cepdes = cep de destino
*/

function calc_frete($servico,$cepori,$cepdes,$peso,$valorD,$form,$comp,$larg,$alt,$diameter,$mpro,$valdec,$arec,$emba) {

//conteudo do Post
$data = "resposta=paginaCorreios&servico={$servico}&cepOrigem={$cepori}&cepDestino={$cepdes}&peso={$peso}&valorD={$valorD}&Formato={$form}&Comprimento={$comp}&Largura={$larg}&Altura={$alt}&Diametro={$diameter}&MaoPropia={$mpro}&valorDeclarado={$valdec}&avisoRecebimento={$arec}&embalagem={$emba}";

//Envia o Post e resgata html de resposta
$html = curl_init('http://www.correios.com.br/encomendas/prazo/prazo.cfm');
curl_setopt($html, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1");
curl_setopt($html, CURLOPT_TIMEOUT, 30);
curl_setopt($html, CURLOPT_POSTFIELDS, $data);
curl_setopt($html, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($html, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($html, CURLOPT_POST, 1);
$return = curl_exec($html);
curl_close($html);

//tratamento inicial do html
$return = explode('<!--/buscaCorreios-->', $return);
$return = $return[1];
$return = explode('<!--buscaCorreios-->', $return);
$return = $return[0];
$seg1 = explode('<tr class="tdAmarelo">', $return);
$seg2 = explode('<tr class="tdAzul">', $return);
//total do frete
$tfrete = explode('<td colspan="2">', $seg1[2]);
$tfrete = explode('</td>', $tfrete[1]);
$tfrete = substr($tfrete[0], 3);
//origem e destino
$ordes = explode('<td align="center">', $seg1[1]);
$origem = explode('</td>', $ordes[1]);
$origem = $origem[0];
$destino = explode('</td>', $ordes[2]);
$destino = $destino[0];
//prazo de Entrega
$prazo = explode('<b>', $seg2[2]);
$prazo = explode('</b>', $prazo[2]);
$prazo = substr($prazo[0], 0, -17);

//Resultados
$result = "O frete de $origem ate $destino tera o custo de R$:$tfrete, e chegara em $prazo Dias Apos a postagem";
return $result;
}

function busca_cep($cep) {
//dados do post
$data = "resposta=paginaCorreios&servico=41106&cepOrigem=93880970&cepDestino={$cep}&peso=&valorD=&Formato=1&Comprimento=&Largura=&Altura=&Diametro=&MaoPropia=N&valorDeclarado=&avisoRecebimento=N&embalagem=";
//envia e receb
$html = curl_init('http://www.correios.com.br/encomendas/prazo/prazo.cfm');
curl_setopt($html, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1");
curl_setopt($html, CURLOPT_TIMEOUT, 30);
curl_setopt($html, CURLOPT_POSTFIELDS, $data);
curl_setopt($html, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($html, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($html, CURLOPT_POST, 1);
$return = curl_exec($html);
curl_close($html);
//tratamento inicial
$return = explode('<!--/buscaCorreios-->', $return);
$return = $return[1];
$return = explode('<!--buscaCorreios-->', $return);
$return = $return[0];
$seg2 = explode('<tr class="tdAzul">', $return);
$cidabai = explode('<td align="center">', $seg2[1]);
//busca logradouro
$logradouro = explode('</td>', $cidabai[4]);
$logradouro = $logradouro[0];
//busca bairro
$bairro = explode('</td>', $cidabai[6]);
$bairro = $bairro[0];
//busca cidade e estado
$cidaes = explode('</td>', $cidabai[8]);
$cidaes = $cidaes[0];
$estado = substr($cidaes, -2);
$cidade = substr($cidaes, 0, -3);
//reultados
$result = "<li>Cidade:$cidade</li><li>Estado:$estado</li><li>Bairro:$bairro</li><li>Logradouro:$logradouro</li>";
return $result;
}

echo calc_frete("41106","93880970","69075840","2","","1","","","","","N","","N","");
echo busca_cep("93010010");
?>

Enviado por Diogo (não verificado(a)) em Seg, 08/02/2010 - 12:52.

Não testei o script, mas eu uso um similar e não está mais funcionando o calculo do PAC. Parece que os correios removeu o PAC desse calculo. Já tentei passar as variaveis que agora sao obrigatorias para calcular o pac: o formato, comprimento, largura, altura, mas nada. Se alguem souber de algo, da um toque, farei o mesmo. valeu.

Enviado por guest (não verificado(a)) em Qui, 09/09/2010 - 13:26.

tbem nao consegui calcular o PAC
alguem sabe ?