
Frank K Hosaka
Membros-
Total de itens
1.622 -
Registro em
-
Última visita
Tudo que Frank K Hosaka postou
-
Ajuda com ajax e php
pergunta respondeu ao Gimenez de Frank K Hosaka em Repositório de Scripts - PHP
A resposta do Wash é super bacana, mas eu não consegui executar o Ajax por aqui. Por outro lado, eu encontrei um código JavaScript sem o Ajax que funcionou, mas ao invés de consultar o MySQL, simplifiquei só para fazer uma simples multiplicação, para demonstrar que o problema é o Ajax: arquivo index.php <script> async function teste() { form = new FormData() form.append('ch', ch.value) form.append('pontos',pontos.value) response=await fetch('funcFinancas.php',{method:"POST",body: form}) responseData = await response.json(); pto.value=responseData.pto base.value=responseData.base } </script> <table> Tabuada do 2 <tr><td>ch<td><input id=ch value=1><td><input type=button id=base> <tr><td>pontos<td><input id=pontos value=2><td><input type=button id=pto> <tr><td><input type=submit onclick=teste()> </table> arquivo funcFinancas.php <?php $ch=$_POST['ch']; $pontos=$_POST['pontos']; $dados['base']=$ch*2; $dados['pto']=$pontos*2; echo json_encode($dados); -
Para testar um arquivo zipado, eu usei o seguinte código: <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <form method=post class="w-50 m-auto" enctype="multipart/form-data"> <h5>Nota Faltante</h5> <label for=arquivo>Escolha o arquivo Zipado</label> <input type=file name=arquivo> <input type=submit> </form> <?php if(isset($_FILES['arquivo'])) { print_r($_FILES['arquivo']); } exit; Testei o código no meu notebook com Windows 11, e a resposta foi a seguinte: Array ( [name] => xml_nfe_2024-07-03-10-21-15.zip [full_path] => xml_nfe_2024-07-03-10-21-15.zip [type] => [tmp_name] => [error] => 1 [size] => 0 ) Ou seja, não dá para usar o ZipArchive do PHP. Testei o mesmo código no Hostinger, e a resposta foi a seguinte: Array ( [name] => xml_nfe_2024-07-03-10-21-15.zip [full_path] => xml_nfe_2024-07-03-10-21-15.zip [type] => application/x-zip-compressed [tmp_name] => /tmp/phpCURRDH [error] => 0 [size] => 2575504 ) Ou seja, o ZipArchive funciona no ambiente Linux. De acordo com a primeira lei de Murphy, o problema não é o Windows e nem o Linux, mas sim daquela famosa pecinha que fica na frente do monitor que espera que o PHP apresente a mesma resposta para sistemas operacionais diferentes.
-
Não consigo mais abrir sessão num sistema interno após certificado SSL.
pergunta respondeu ao Emanuelle de Frank K Hosaka em PHP
Eu não entendo nada de SSL, mas a Gemini disse o quanto segue: Possíveis causas da falha de sessão após a instalação do SSL: Embora a instalação do SSL (Secure Sockets Layer) deva aprimorar a segurança do site, em alguns casos, pode afetar o funcionamento da sessão do usuário, principalmente se as configurações não forem adequadas. Vamos analisar as principais causas: 1. Falta de redirecionamento para HTTPS: Se o site ainda permite acesso por HTTP, mesmo após a instalação do SSL, as sessões HTTP não serão transferidas para HTTPS, causando perda de dados da sessão. Solução: Verifique se o site está redirecionando todo o tráfego para HTTPS usando o código 301 ou a configuração de redirecionamento permanente no servidor web. 2. Cookies não seguros: Por padrão, as sessões PHP usam cookies para armazenar dados no navegador do usuário. Se os cookies estiverem configurados como "não seguros", eles não serão enviados para o site quando o protocolo HTTPS for usado, interrompendo as sessões. Solução: Configure os cookies da sessão para "seguros" usando a diretiva session.cookie_secure no arquivo de configuração do PHP (php.ini). 3. Domínio incorreto do cookie: O domínio do cookie da sessão deve corresponder ao domínio do site para funcionar corretamente com HTTPS. Se o domínio do cookie estiver definido incorretamente, ele não será enviado para o site quando o protocolo HTTPS for usado. Solução: Verifique se a diretiva session.cookie_domain no php.ini está configurada com o domínio correto do seu site. 4. Falta de configuração do SameSite: O atributo SameSite nos cookies é importante para a segurança em sites HTTPS. Se não estiver configurado corretamente, os cookies da sessão podem não ser enviados pelo navegador, interrompendo as sessões. Solução: Configure a diretiva session.cookie_samesite no php.ini com um valor adequado (por exemplo, SameSite=Lax ou SameSite=Strict). 5. Problemas de cache do navegador: Em alguns casos, o navegador pode armazenar em cache versões antigas do site que não suportam HTTPS, causando problemas com as sessões. Solução: Limpe o cache do navegador do usuário e peça para ele tentar novamente acessar o site. Recomendações: Teste minuciosamente: Após fazer qualquer alteração nas configurações, teste o site em diferentes navegadores e dispositivos para garantir que as sessões estejam funcionando corretamente. Verifique logs de erros: Consulte os logs de erros do servidor web e do PHP para identificar possíveis problemas relacionados às sessões. Busque ajuda profissional: Se o problema persistir, considere buscar ajuda de um desenvolvedor web experiente para analisar e solucionar a falha de sessão. Lembre-se que a segurança é crucial para sites que lidam com dados de usuários. A instalação do SSL é essencial, mas deve ser feita com cuidado e as configurações adequadas para evitar problemas com sessões e outras funcionalidades do site. -
Ontem, eu baixei um arquivo zipado da Bling com todas as notas de junho, só que o ZipArchive do PHP não conseguiu abrir. Usando var_dump($_FILES['arquivo']) encontrei uma chave error com int 1. Mandei o arquivo para a Bling, pedindo socorro. Apesar do ZipArchive não poder trabalhar com um arquivo corrompido, eu vi que o Windows é capaz de extrair o arquivo. E o PHP é capaz de olhar todos os arquivos da nova pasta que foi extraída com o comando scandir. O problema é como pegar o nome da pasta. A Gemini disse que o JavaScript não é capaz de obter o nome da pasta que você quer selecionar, mas ela sugeriu usar <input type=file> para selecionar um arquivo dentro da pasta, e depois obter o nome da pasta. Para fazer esse tipo de gambiarra, o PHP é tão bom quanto o JavaScript. Eu vi que o Windows cria a pasta com o mesmo nome do arquivo zipado, logo o nome da pasta é C:/Users/frank/Downloads/pasta, onde pasta é igual ao nome do arquivo zipado sem a extensão zip: Arquivo notaFaltante.php: <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <form method=post class="w-50 m-auto" enctype="multipart/form-data"> <h5>Nota Faltante</h5> <label for=arquivo>Escolha o arquivo Zipado</label> <input type=file name=arquivo> <input type=submit> </form> <?php if(isset($_GET['pasta'])) { $diretorio=$_GET['pasta']; $contaArquivos = count(scandir($diretorio)) - 2; $notasFiscais = []; $nfces = scandir($diretorio); $somaTotal=0; foreach($nfces as $nfce) { if($nfce !== '.' && $nfce !=='..' ) { $notasFiscais[]=intval(substr($nfce,28,6)); $dom = new DOMDocument(); $dom->load("$diretorio/$nfce"); $nfe=$dom->documentElement; $somaTotal+=$nfe->getElementsByTagName('vNF')->item(0)->textContent; } } goto Continua; } if(!isset($_FILES['arquivo'])) { exit; } if($_FILES['arquivo']['error']) { $pasta="C:/Users/frank/Downloads/" . substr($_FILES['arquivo']['name'],0,-4); ?> <form class="w-50 m-auto"> <p></p> <p>Arquivo corrompido, tente extrair pelo Windows</p> <p>Se der certo, volte aqui e pressione [Continuar]</p> <input type=hidden name=pasta value=<?=$pasta?>> <input type=submit value=Continuar> </form> <?php exit; } $zip=new ZipArchive(); $zip->open($_FILES['arquivo']['tmp_name']); $contaArquivos = $zip->count(); $notasFiscais = []; $somaTotal = 0; for($i=0;$i<$contaArquivos;$i++) { $nfce=$zip->getFromIndex($i); $dom=new DOMDocument(); $dom->loadXML($nfce); $nfe=$dom->documentElement; $notasFiscais[]=$nfe->getElementsByTagName('nNF')->item(0)->textContent; $somaTotal+=$nfe->getElementsByTagName('vNF')->item(0)->textContent; } Continua: sort($notasFiscais); $primeiraNota=intval($notasFiscais[0]); $ultimaNota=intval($notasFiscais[$contaArquivos-1]); ?> <table class="table table-striped w-50 m-auto"> <tr><td>Número de arquivos xml<td class=text-end><?=$contaArquivos?> <tr><td>Total das Notas Fiscais<td class=text-end><?=number_format($somaTotal,2,',','.')?> <tr><td>Primeira Nota<td class=text-end><?=$primeiraNota?> <tr><td>Última Nota<td class=text-end><?=$ultimaNota?> <tr><td>Notas Faltantes<td class=text-end><?=$ultimaNota-$primeiraNota+1-$contaArquivos?> <?php for($i=$primeiraNota;$i<=$ultimaNota;$i++) { if(!in_array($i,$notasFiscais)) { ?> <tr><td><?=$i?> <?php } } ?> </table>
-
De acordo com a Gemini, existem roteadores para o PHP que simulam mais ou menos a funcionalidade do roteador do Laravel que são instalados através do Composer. Eu testei isso, mas eu não consegui chegar no conceito de classe. Para quem está começando a estudar a classe como é o meu caso, o melhor caminho é pegar um autoload e um roteador o mais simples possível: arquivo index.php <?php spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'); // requer php 8.2 $rota='Login_login'; if($_GET) { if(strpos(key($_GET),"_")==0) { exit; } $rota=isset($_GET) ? key($_GET) : $rota; } $segmentos=explode('_',$rota); $nomeClasse=$segmentos[0] ?? 'Login'; $metodo=$segmentos[1] ?? 'login'; $parametro=$segmentos[2] ?? null; $classe=new $nomeClasse(); $classe->$metodo($parametro); Apesar de ter poucas linhas, só agora é que eu começo a entender o que é classe. O código é bem abstrato, mas já dá para ver como associar um <form> do html com as classes do PHP. Para quem está começando a estudar as classes, ele precisa entender como as classes são chamadas. O programador pode chamar a classe dentro do código através do comando (new Classe) graças ao autoload ou dentro do <form method=post action="?classe.metodo.argumento"> graças ao roteador. O ponto de interrogação definido no action vai garantir que o fluxo do programa passe pelo arquivo index.php. Já o Laravel é bem obscuro, não dá para ver como <form action="teste"> chega no router::get('teste',[testeController::class,'teste'). Outro problema bem obscuro é a tal da vulnerabilidade, todo mundo recomenda migrar para o Laravel porque ele tem um colete a prova de bala. Certamente o meu código não tem colete a prova de bala, mas eu sou incapaz de enxergar a possibilidade de ser baleado ou ter a carteira de dados roubado. O máximo que eu consegui fazer foi isso: arquivo index.php <?php session_start(); if(!isset($_SESSION['nome']) { header("location:?Login_login"); } else { header("location:?Menu_inicio"); } Ou seja, o bandido precisa estar logado para poder ver alguma coisa, isso na minha cabeça. Isso não é um colete a prova de bala, mas como vou medir a vulnerabilidade dele? Usar o composer para instalar o Laravel não ajuda muito, pois eu sou incapaz de enxergar o colete a prova de bala, se bem que a pasta Vendor do Laravel assusta qualquer bandido, e principalmente o programador de PHP que quer usar as classes como estilo de codificação.
-
Você tem razão, o correto é usar "_" no action do <form> para ser mais consistente com o código do roteador, mas eu queria usar o "." para definir o parâmetro como "classe.metodo.argumento". O HTML é um papel em branco, ele permite usar o ".", logo eu usei o "." O chato é o $_GET que transforma o ponto em underline. A melhor solução é escrever assim: <form action="?classe_metodo_argumento"> para dar consistência ao código do roteador, mas eu preferi usar o estilo <form action="?classe.metodo.argumento"> para mostrar ao mundo que o HTML e o PHP não respeitam a lei do Wyswyg What You See What You Get
-
arquivo index.php <?php class Teste { public function teste() { echo "olá mundo"; } public function nada(){} } $rota='Teste_nada'; if($_GET) { if(strpos(key($_GET),"_")==0) { exit; } $rota=isset($_GET) ? key($_GET) : $rota; } $segmentos=explode('_',$rota); $nomeControle=$segmentos[0] ?? 'Teste'; $metodo=$segmentos[1] ?? 'nada'; $parametro=$segmentos[2] ?? null; $controle=new $nomeControle(); $controle->$metodo($parametro); ?> <form action=?Teste.teste><input type=submit></form> O formulário acima não funciona, eu só consegui fazer funcionar, quando alterei o formulário: <form method=post action=?Teste.teste><input type=submit></form>
-
Usando o método da tentativa e erro, estou mudando o meu projeto PHP para o projeto Classe. No antigo projeto, eu tinha os arquivos login.php, alterarSenha.php, sair.php. Estudando as classes, consegui diminuir o serviço para dois arquivos: o login.php e loginView.php, assim: arquivo config.php <?php session_start(); date_default_timezone_set('America/Sao_Paulo'); $baseDir = $_SERVER['SERVER_NAME'] === 'frank.com' ? $_SERVER['DOCUMENT_ROOT'] : $_SERVER['DOCUMENT_ROOT'].'/Frank/'; defined('HOST') || define('HOST', 'localhost'); defined('DBNAME') || define('DBNAME', $baseDir === $_SERVER['DOCUMENT_ROOT'] ? 'Diario' : 'diario'); defined('USER') || define('USER', $baseDir === $_SERVER['DOCUMENT_ROOT'] ? 'Root' : 'root'); defined('PASSWORD') || define('PASSWORD', $baseDir === $_SERVER['DOCUMENT_ROOT'] ? '1234' : ''); defined('lctoBaixaEstoque') || define('lctoBaixaEstoque',12234); defined('lctoAcertoMais') || define('lctoAcertoMais',12235); defined('lctoAcertoMenos') || define('lctoAcertoMenos',12531); defined('diaAcerto') || define('diaAcerto','2024-06-30'); spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'); class Conexao { private static $pdo; public static function instancia() { if(!self::$pdo) { self::$pdo=new PDO("mysql:host=".HOST.";dbname=".DBNAME,USER,PASSWORD); } return self::$pdo; } function delete($sql) { return $this->instancia()->query("delete from $sql"); } function exec($sql) { return $this->instancia()->query($sql); } public function insert($sql) { return $this->instancia()->query("insert into $sql"); } function select($sql) { $stmt=$this->instancia()->query("select $sql"); return $stmt->fetchAll(PDO::FETCH_OBJ); } function update($sql) { return $this->instancia()->query("update $sql"); } } function apuracao($dia) { $ano=date('Y',strtotime($dia)); $mes=date('m',strtotime($dia)); $mesVetor=['Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho', 'Agosto','Setembro','Outubro','Novembro','Dezembro']; $apuracao=$mesVetor[$mes-1] . " de $ano"; $primeiroDia="$ano-$mes-01"; $ultimoDia=date('Y-m-t',strtotime($primeiroDia)); return json_decode(json_encode(['apuracao'=>$apuracao,'primeiroDia'=>$primeiroDia, 'ultimoDia'=>$ultimoDia])); } function aspas($bling) { $primeiroCaractere=$bling[0]; $ultimoCaractere=$bling[-1]; if($primeiroCaractere==='"' && $ultimoCaractere==='"') { $bling=substr($bling,1,-1); return str_replace('""','"',$bling); } } function dec($value) { return ($value) ? number_format($value,2,',','.') : null; } function deca($num) { $value=str_replace(".","",$num); return str_replace(",",".",$value); } function decv($num) { return str_replace(".",",",$num); } function fmt($date) { return date('d/m/y',strtotime($date)); } function fmt2($data) { return date('m/Y',strtotime($data)); } function fmt3($data) { return date('d/m',strtotime($data));} function pvenda($custo,$margem) { $calculo=intval($custo*(1+$margem/100)*100)/100; $fracao=$calculo-intval($calculo); if ($fracao < 0.09) { $pvenda=intval($calculo); } else { if ($fracao <= 0.59) { $pvenda=intval($calculo)+0.5; } else { $pvenda=intval($calculo)+1; } } return dec($pvenda); } function view($arquivo, $array = null) { if (!is_null($array)) { foreach ($array as $var => $value) { ${$var} = $value; } } ob_start(); include $arquivo . ".php"; ob_flush(); } ?> <!DOCTYPE html> <html lang="en"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Projeto PHP</title> <style> @media (min-width: 768px) { main, header {width: 25%;margin: auto} } @media (max-width: 767px) { main, header {width: 75%;margin: auto} } a {color:blue;text-decoration:none} a:hover {color:black;} form {margin:0} .linha {line-height:0px} summary{list-style:none} td {white-space: nowrap} </style> <body class="bg-body-tertiary"> arquivo index.php <?php ini_set('display_errors', 1); require 'config.php'; $rota='Login_login'; if($_GET) { if(strpos(key($_GET),"_")==0) { exit; } $rota=isset($_GET) ? key($_GET) : $rota; } $segmentos=explode('_',$rota); $nomeControle=$segmentos[0] ?? 'Login'; $metodo=$segmentos[1] ?? 'login'; $parametro=$segmentos[2] ?? null; $controle=new $nomeControle(); $controle->$metodo($parametro); arquivo login.php <?php class Login { public function alterarSenha() { return view('loginView', ['mensagem'=>null,'titulo'=>'Alterar senha']); } public function login() { if(!isset($_SESSION['nome'])) { return view('loginView', ['mensagem'=>null,'titulo'=>'Projeto Classe']); } else { return view('menuView'); } } public function sair() { session_destroy(); return view('loginView', ['mensagem'=>null,'titulo'=>'Projeto Classe']); } public function senhaAlterada() { $senhaAlterada=$_POST['senhaAlterada']; $hash=password_hash($senhaAlterada,PASSWORD_BCRYPT,['cost'=>12]); $id=$_SESSION['id']; (new Conexao)->update("tbusuarios set senha='$hash' where id=$id"); return view('loginView', ['mensagem'=>null,'titulo'=>'Projeto Classe']); } public function verificar() { $email=$_POST['email']; $senha=$_POST['senha']; $usuario=(new Conexao)->select("* from tbusuarios where email='$email'"); if(!$usuario) { return view('loginView', ['mensagem'=>'Email inválido!','titulo'=>'Projeto Classe']); } $confirmar=$usuario[0]->senha; $validaSenha=password_verify($senha,$confirmar); if(!$validaSenha) { return view('loginView', ['mensagem'=>'Senha inválida!','titulo'=>'Projeto Classe']); } $_SESSION['id']=$usuario[0]->id; $_SESSION['nome']=$usuario[0]->nome; return view('menuView'); } } arquivo loginView.php <div style="height:150px"></div> <!--empurrar o form para o meio da tela--> <main> <?php if($mensagem): ?> <div class="alert alert-success"><?=$mensagem?></div> <?php endif; $action=($titulo=="Alterar senha") ? "?Login.senhaAlterada" : "?Login.verificar"; ?> <form method=post action=<?=$action?>> <h1 class="h3 mb-3 fw-normal"><?=$titulo?></h1> <div class="form-floating"> <input type="email" class="form-control" name=email autofocus> <label>Email</label> </div> <div class="my-1"></div> <div class="form-floating"> <?php $chave=($titulo=="Alterar senha") ? "senhaAlterada" : "senha"; ?> <input type="password" class="form-control" name=<?=$chave?> required ondblclick="this.type='text'"> <label>Duplo clique para ver a Senha</label> <!--Google Chrome não mostra o olho--> </div> <div class="my-3"></div> <button class="w-100 btn btn-lg btn-primary" type="submit">Entrar</button> </form> </main> arquivo menuView.php <header class="navbar navbar-light sticky-top bg-light flex-md-nowrap p-0"> Classe <div class=dropdown> <button type=button class="btn btn-outline-primary dropdown-toggle" data-bs-toggle=dropdown id=btmenu> Menu </button> <ul class="dropdown-menu"> <?php if($_SESSION['id']==1): ?> <li><a class=dropdown-item href=?Diario.inicio>Diário</a></li> <li><a class=dropdown-item href=?Balancete.inicio>Balancete</a></li> <li><a class=dropdown-item href=?Pagar.inicio>Pagar</a></li> <li><a class=dropdown-item href=?Outros.inicio>Outros</a></li> <?php endif; ?> <li><a class=dropdown-item href=?Orcamento.inicio>Orçamento</a></li> <li><a class=dropdown-item href=?Pessoa.inicio>Pessoa</a></li> <li><a class=dropdown-item href=?Produto.inicio>Produto</a></li> <li><a class=dropdown-item href=?Venda.inicio>Relatório de Venda</a></li> <li><a class=dropdown-item href=?MercadoPago.inicio>Mercado Pago</a></li> </ul> </div> <div class="dropdown"> <button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <?=$_SESSION['nome']?> </button> <ul class="dropdown-menu"> <li><a class=dropdown-item href=?Login.sair>Sair</a></li> <li><a class=dropdown-item href=?Login.alterarSenha>Alterar senha</a></li> </ul> </div> </header>
-
Eu tenho um código que puxa todos os pedidos, mas peço para exibir apenas 20 de cada vez, assim: arquivo historico.php <?php include 'menu.php'; if(isset($_GET['ped'])) { $_SESSION['ped']=$_GET['ped']; return header("location:orcamento.php"); } $where=""; if(isset($_GET['hist'])) { $hist=$_GET['hist']; $ped=$_SESSION['referencia']+$hist; $where="where ped <= $ped"; } $query=$mysqli->query("select * from tbpedido left join tbpessoa on tbpedido.codp = tbpessoa.codp $where order by ped desc limit 20"); $pedidos=$query->fetch_all(MYSQLI_ASSOC); $_SESSION['referencia']=$pedidos[0]['ped']; ?> <script>btmenu.innerHTML='Histórico Orçamentos';document.title='Histórico Orçamento'</script> <main> <table class='table table-striped linha'> <th style=width:20px>Dia <th style=width:40px>Pedido <th>Vendido<th>Bling <th class=text-end>Total<th>Cliente <?php foreach($pedidos as $ped) : ?> <tr><td><?=date('d/m/y',strtotime($ped['dia']))?> <td class=text-end><a href=?ped=<?=$ped['ped']?>><?=$ped['ped']?></a> <td> <?php if($ped['horavenda']): ?> <?=date('d/m H:i',strtotime($ped['horavenda']))?> <?php endif; ?> <td><?=$ped['bling']?> <td class=text-end><?=dec($ped['total'])?> <td><?=$ped['pessoa']?> <?php endforeach; ?> </table> <div style="display:flex;width:30px;margin-right:15px"> <a href="?hist=-19">Anterior</a> <a href="orcamento.php">Voltar</a> <a href="?hist=19" >Posterior</a> </div> </main>
-
Trabalhar com classes no PHP não é nada fácil, eu apanhei muito para fazer os meus códigos funcionarem, eu fui obrigado a criar três pastas: Modelos, Visoes e Controles. Mas nesse mês, o Iowys apresentou um novo autoload que permite ao programador trabalhar com as classes sem a necessidade de criar pastas, mas a versão do PHP tem que ser a 8.2 para cima. O meu primeiro projeto foi criado na base da tentativa e erro, ele recebeu o nome de orcamento.php, mas eu tive que fazer várias adaptações, quando o meu irmão começou a utilizar. Em seguida, apareceram divergências entre o relatório da vendas do meu código com o da Bling (o meu programa não emite nota fiscal, já a Bling emite a Nota Fiscal). A Bling tem uma rotina para montar o pedido de venda, mas ele acha bem mais fácil usar o meu código num antigo tablet da Apple, e depois ele exporta o meu pedido para a Bling. Para tentar eliminar a divergência, eu criei dois arquivos: orcamentoGet.php e OrcamentoVenda.php. Graças a esses dois arquivos, eu consigo fazer os relatórios de vendas serem iguais. Com o novo autoload eu posso melhorar os códigos assim: orcamentoControle.php orcamentoView.php A ideia básica das classes é separar o formulário HTML do código PHP e definir dentro do código quem vai fazer o quê. Falar é fácil, mas o novo autoload já ajuda bastante. arquivo index.php <?php spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'); (new Teste)->inicio(); arquivo Teste.php <?php class Teste { public function inicio() { echo "olá mundo"; } }
-
O meu projeto de orçamento é basicamente isso: <?php date_default_timezone_set('America/Sao_Paulo'); $mysqli=new mysqli("localhost","root","","teste"); if(isset($_GET['vendido'])) { $horaVenda=date('Y-m-d H:i:s'); $mysqli->query("update tbpedido set horavenda='$horaVenda' where ped=1"); $horaVendida=$mysqli->query("select horavenda from tbpedido where ped=1") ->fetch_assoc()['horavenda']; echo $horaVendida . "<br>"; } ?> <form> <input type=submit value=Vendido> <input type=hidden name=vendido value='vendido'> </form> É um programa simples, mas encontrei divergência com o relatório da Bling. O último pedido que foi vendido no dia 20 aparece como dia 21. Olhando o código, tudo me leva a crer que alguém atualizou a tela do navegador no dia seguinte. Eu criei uma rotina para ver se alguém apertou o botão vendido. Isso acontece sempre mas não o último pedido. Desconfio que o problema é o navegador, de algum modo ele traz todas as informações do dia anterior e não sei como ele consegue executar esse código. Hoje, dividi o programa em dois arquivos. Um para apertar o botão e o outro para atualizar o banco de dados. Ou seja, não há mais como o navegador executar o código sem a ajuda do usuário, penso eu. O código final ficou assim: arquivo index.php <form action=registraVenda.php> <input type=submit value=Vendido> <input type=hidden name=vendido value='vendido'> </form> arquivo registraVenda.php <?php date_default_timezone_set('America/Sao_Paulo'); $mysqli=new mysqli("localhost","root","","teste"); $horaVenda=date('Y-m-d H:i:s'); $mysqli->query("update tbpedido set horavenda='$horaVenda' where ped=1"); $horaVendida=$mysqli->query("select horavenda from tbpedido where ped=1") ->fetch_assoc()['horavenda']; echo $horaVendida . "<br>";
-
Faz três meses que estou procurando um erro eventual no meu projeto orçamento, de noite o relatório de vendas do PHP e do Bling batem, mas no dia seguinte não bate, não é sempre que isso acontece, daí dei o nome de erro eventual. Eu sei que sou um péssimo programador, mas hoje eu levei um baita susto. Alterei o programa orçamento assim: <?php exit; Ou seja, tudo o que ele tinha que fazer é não fazer absolutamente nada. Mas ele executou toda a rotina do orçamento, o PHP simplesmente não considerou as minhas alterações. Eu fiquei desesperado. Estou há três meses procurando o erro, e agora o PHP não aceita as minhas últimas alterações. Fiz o teste São Tomé, mudei o nome do arquivo do orcamento.php para qualquercoisa.php, e na hora de chamar o orçamento, o PHP reclamou que o arquivo não existia. Fui lá no Hostinger, fiz alteração no orçamento, e lá tudo funcionou como eu esperava. O meu notebook tem cinco anos, eu acho que não é tão velho assim. A minha última tentativa para o PHP aceitar as alterações no arquivo foi reiniciar o Windows. Graças a Deus deu certo, agora o PHP executa as minhas alterações.
-
how to make a php variable increase when clicking on an html button?
pergunta respondeu ao Rafael Cravcenco de Frank K Hosaka em Tutoriais & Dicas - PHP
<?php session_start(); if(!isset($_SESSION['var'])) { $_SESSION['var']=0; } if(isset($_GET['test'])) { $_SESSION['var']++; } ?> <form> <input type=submit name=test value=<?=$_SESSION['var']?> /> </form> -
Exibir data oriunda do MYSQL
pergunta respondeu ao diogoml de Frank K Hosaka em Tutoriais & Dicas - PHP
<?php $data = '2024-06-20 23:07'; echo $dia = date('d/m/Y', strtotime($data)); // 20/06/2024 echo "<br>" . $hora = date('H:i:s', strtotime($data)); // 23:07 -
Isso não tem nada a ver com o PHP, mas acredito que muita gente usa esse programa para verificar se os valores lançados no MySQL através do PHP chegam no valor esperado. Hoje, a Gemini e o motor do Google me informaram que o Excel não tem recurso para saber a cor da fonte de uma célula sem a ajuda de uma macro. Eu tenho uma coluna de despesas previstas tudo em vermelho, quando a despesa era realizada eu pintava de preto, e a macro calculava a soma dos valores em vermelho. Ao invés de pintar a fonte, agora testei o sinal do valor da célula. Todas as despesas são negativas, quando a despesa é realizada, mudo o sinal para positivo, e o total das despesas em aberto é calculado através da fórmula =Somase([Intervalo],"<0") Para mudar a cor da fonte, eu criei duas regras na formatação condicional, se o valor é menor que 0 então a cor da fonte é vermelha; a outra regra é se o valor é maior ou igual a 0 então a cor da fonte é preta. Isso deu certo na versão desktop e na versão web do Excel. Já a versão Android do Excel disse "O Microsoft Office 365 encontrou um problema", mesmo assim ele conseguiu abrir o arquivo, somar os valores negativos e alterar a cor da fonte, apesar dele não ter o recurso da formatação condicional na versão Android.
-
A Gemini afirmou que é impossível o PHP impedir o navegador de utilizar o recurso de preencher os campos email e password, mesmo assim ela sugeriu utilizar os atributos autocomplete e placeholder no marcador <input> na esperança do navegador entender as prioridades do programador. Eu fiz o teste, e só perdi tempo. A única saída é você pedir para o cliente entrar no navegador e pedir para excluir a sua conta do gerenciador de senhas que você usou na máquina dele e por besteira você autorizou o navegador a gravar a sua credencial.
-
Esse é um código bem sofisticado e engenhoso. Não sabia que a variável "protected" tornava visível o $connection na subclasse. Mas eu acho que faz mais sentido a classe Conecta iniciar a conexão, do que pedir para a classe Metodos ou outra subclasse iniciar a conexão, ou seja, eu mudaria a função conectar( ) para __construct( ) na classe Conecta.
-
Insert_id PHP duplicando INSERT
pergunta respondeu ao chiquito de Frank K Hosaka em Tutoriais & Dicas - PHP
arquivo index.php Esse código vai criar para cada novo grupo os privilégios 1, 2 e 3 <form method=post> <input name=grupo placeholder='Nome do Grupo'><br> <input type=submit> </form> <?php // grupo (id auto_increment,nome) // grupo_privilegio (id auto_increment,idGrupo,idPrivilegio) if(!isset($_POST['grupo'])) { exit; } $grupo = $_POST['grupo']; $conexao=new mysqli("localhost","root","","teste"); $sql = "SELECT id FROM grupo WHERE nome = '$grupo'"; $result = $conexao->query($sql); if ($result->num_rows > 0) { echo "O grupo '$grupo' já existe."; } else { // Inserir dados na tabela grupo $smt = "INSERT INTO grupo (nome) VALUES ('$grupo')"; $inseregrupo = $conexao->query($smt); if ($conexao->affected_rows > 0) { // Pegar o ID do último grupo inserido $id_grupo = $conexao->insert_id; for($i=1; $i<=3; $i++ ) { // definindo privilégio 1,2,3 para cada novo grupo $insere = "INSERT INTO grupo_privilegio(idGrupo,idPrivilegio) VALUES ($id_grupo,$i)"; $resultado = $conexao->query($insere); } if ($conexao->affected_rows > 0) { echo "cadastro realizado com sucesso"; } } } ?> NUNCA deixe o usuário definir o id de uma tabela. -
Como faço a mudança nessa programação abaixo?
pergunta respondeu ao danielambrosiobr de Frank K Hosaka em PHP
Veja se isso funciona: <?=$sorteio['valor']?> -
Classes são bem difíceis de trabalhar e o banco de dados é pior ainda. Aconselho a fazer coisas mais simples primeiro. O que segue é um péssimo exemplo de programação, ele não contempla tratamento de erro, ele não contempla a convenção da documentação do código, mas ele funciona! <?php define('Servidor','localhost'); define('Usuario','root'); define('Senha',''); define('BD','teste'); class Conexao { private $conexao; public function __construct() { $this->conexao = new mysqli(Servidor,Usuario,Senha,BD); } public function consulta($sql) { $query = $this->conexao->query($sql); return $query->fetch_assoc(); } } $teste = (new Conexao)->consulta("select message from chirps where id=1"); var_dump($teste); echo $teste['message']; Eu comecei a estudar o PHP em 2020, mas só estudei as classes em 2024, quando apareceu a Gemini. Tem sugestões dela que faz perder muito tempo, mas tem outras que funcionam, os meus primeiros códigos eram assim: <?php $mysqli=new mysqli("localhost","root","","teste"); $query=$mysqli->query("select message from chirps where id=1"); $row=$query->fetch_assoc(); echo $row['message'] Em 2020, eu não tinha a menor ideia do que era a palavra "new", só em 2024 é que aprendi que mysqli é o nome de uma classe do PHP, ele tem centenas de métodos, mas eu só conheço o método query e o fetch. Para saber de outros métodos, é preciso ler o manual do PHP, ele é enorme e difícil de entender. Eu prefiro a Gemini, ontem, por exemplo, ela disse que o PHP tem outra classe chamada ZipArchive, Nossa, como eu gostei dele! Enfim, para utilizar uma classe é necessário usar a palavra new.
-
Com a ajuda da Gemini, fiquei sabendo que o PHP trabalha com o arquivo zipado. Graças a esse recurso, não preciso mais extrair um arquivo zipado e depois mandar centenas de arquivos numa pasta reservada para o PHP. arquivo index.php <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <form method=post class="w-50 m-auto" enctype="multipart/form-data"> <label for=arquivo>Escolha o arquivo Zipado</label> <input type=file name=arquivo> <input type=submit> </form> <?php if(!isset($_FILES['arquivo'])) { exit; } if($_FILES['arquivo']['error']) { echo "O arquivo " . $_FILES['arquivo']['name'] . " tem problemas"; exit; } $zip=new ZipArchive(); $zip->open($_FILES['arquivo']['tmp_name']); $contaArquivos = $zip->count(); $notasFiscais = []; $somaTotal = 0; for($i=0;$i<$contaArquivos;$i++) { $nfce=$zip->getFromIndex($i); $dom=new DOMDocument(); $dom->loadXML($nfce); $nfe=$dom->documentElement; $notasFiscais[]=$nfe->getElementsByTagName('nNF')->item(0)->textContent; $somaTotal+=$nfe->getElementsByTagName('vNF')->item(0)->textContent; } sort($notasFiscais); $primeiraNota=intval($notasFiscais[0]); $ultimaNota=intval($notasFiscais[$contaArquivos-1]); ?> <table class="table table-striped w-50 m-auto"> <tr><td>Número de arquivos xml<td class=text-end><?=$contaArquivos?> <tr><td>Total das Notas Fiscais<td class=text-end><?=number_format($somaTotal,2,',','.')?> <tr><td>Primeira Nota<td class=text-end><?=$primeiraNota?> <tr><td>Última Nota<td class=text-end><?=$ultimaNota?> <tr><td>Notas Faltantes<td class=text-end><?=$ultimaNota-$primeiraNota+1-$contaArquivos?> <?php for($i=$primeiraNota;$i<=$ultimaNota;$i++) { if(!in_array($i,$notasFiscais)) { ?> <tr><td><?=$i?> <?php } } ?> </table>
-
Localização de funções no código do projeto
pergunta respondeu ao wendelmsilva de Frank K Hosaka em PHP
Para quem está começando no PHP eu sugiro estudar primeiro o arquivo index.php, geralmente ele começa com o marcador <?php. Em 2024 você conta com a ajuda da gemini@google.com e você pergunta para ela: o que é <?php. Se você não conseguir entender, tente mudar a pergunta: o que é um marcador. E assim vai. -
Eu tenho o seguinte código: <?php session_start(); require 'app.php'; require 'config.php'; ?> <style> @media (min-width: 768px) { main, header {width: 50%;margin: auto} } @media (max-width: 767px) { main, header {width: 100%;margin: auto} } a {color:blue;text-decoration:none} a:hover {color:black;} form {margin:0} .linha {line-height:0px} summary{list-style:none} td {white-space: nowrap} </style> <header class="navbar navbar-light sticky-top bg-light flex-md-nowrap p-0"> PHP <div class=dropdown> <button type=button class="btn btn-outline-primary dropdown-toggle" data-bs-toggle=dropdown id=btmenu> Menu </button> <ul class="dropdown-menu"> <?php if($_SESSION['id']==1): ?> <li><a class=dropdown-item href=diario.php>Diário</a></li> <li><a class=dropdown-item href=balancete.php?balancete>Balancete</a></li> <li><a class=dropdown-item href=pagar.php>Pagar</a></li> <li><a class=dropdown-item href=outros.php>Outros</a></li> <?php endif; ?> <li><a class=dropdown-item href=orcamento.php>Orçamento</a></li> <li><a class=dropdown-item href=pessoa.php>Pessoa</a></li> <li><a class=dropdown-item href=produto.php>Produto</a></li> <li><a class=dropdown-item href=venda.php>Relatório de Venda</a></li> <li><a class=dropdown-item href=mercadopago.php>Mercado Pago</a></li> </ul> </div> <div class="dropdown"> <button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <?=$_SESSION['nome']?> </button> <ul class="dropdown-menu"> <li><a class=dropdown-item href=sair.php>Sair</a></li> <li><a class=dropdown-item href=alterarSenha.php>Mudar Senha</a></li> </ul> </div> </header> Tenho mais dois projetos que fazem a mesma coisa, mas usam recursos diferentes: o projeto Classe e o projeto Laravel. Esses dois últimos eu sempre tive problema com o alinhamento da barra de navegação no celular. Eu pensei que o problema era o CSS, mas hoje eu fiz um teste, eu tirei a palavra "Projeto" da barra de navegação, e assim consegui alinhar:
-
Todas as colunas da tabela são retornadas, menos a de id
pergunta respondeu ao iNosuKe 么 de Frank K Hosaka em Tutoriais & Dicas - PHP
Não entendi a sua questão, o id é o primeiro item que aparece no seu depurador. Mesmo assim, eu gostei do código. Eu nunca tinha visto declare(strict_types=1), eu tirei ele do código, e isso me deu um baita trabalho na hora de criar o public function setId, precisei fazer assim: public function setId(int $id): int { $this->id=$id; return $id;} Com essa declaração, você não precisa retornar o $id explicitamente. Para quem quer fazer o teste, fiz algumas modificações: arquivo index.php <?php declare(strict_types=1); class User { private string $name, $email, $password; private int $id; public function __construct(string $name, string $email, string $password, int $id = 0) { $this->name = $name; $this->email = $email; $this->password = $password; $this->id = $id; } public function getId(): int { return $this->id; } public function setId(int $id): int { $this->id=$id; } public function getName(): string { return $this->name; } public function setName(string $name): void { $this->name = $name; } public function getEmail(): string { return $this->email; } public function setEmail(string $email): void { $this->email = $email; } public function getPassword(): string { return $this->password; } public function setPassword(string $password): void { $this->password = $password; } } class LoginModel { public static function getUser(User $user) { try { $instance = new PDO("mysql:host=localhost;dbname=teste","root",""); $SQL = "SELECT * FROM user WHERE email = :e AND password = :p"; $state = $instance->prepare($SQL); $state->bindValue(":e", $user->getEmail()); $state->bindValue(":p", $user->getPassword()); $state->execute(); $result = $state->fetch(PDO::FETCH_ASSOC); if ($result) { return new User($result["name"],$result["email"],$result["password"],$result["id"]); } } catch (PDOException $e) { echo $e->getMessage(); } } } $user=new User("Matheus","teteu@gmail.com","12345678"); $loggedInUser=LoginModel::getUser($user); if($loggedInUser) { echo "Você entrou, bem vindo ". $loggedInUser->getName() . "o seu id é " .$loggedInUser->getId(); } else { echo "Favor verificar nome e senha"; } -
Depois de várias horas pesquisando a Gemini e o motor de busca do Google sem nenhum resultado, eu decidi usar a minha intuição científica da tentativa e erro. Primeiro procurei a pasta Illuminate na pasta Vendor. Eu não achei. Voltei no motor do Google, e descobri que o caminho é /vendor/laravel/framework/src/Illuminate Depois abri a subpasta Auth e abri logo o primeiro arquivo que encontrei: Authenticatable.php, e mudei o código assim: <?php namespace Illuminate\Auth; trait Authenticatable { /** * The column name of the password field using during authentication. * * @var string */ protected $authPasswordName = 'senha'; e assim tentei realizar a milésima tentativa, e para o meu espanto consegui entrar no projeto. O Laravel é bacana, mas fazer funcionar que é o problema.