Ir para conteúdo
Fórum Script Brasil

Frank K Hosaka

Membros
  • Total de itens

    1.622
  • Registro em

  • Última visita

Tudo que Frank K Hosaka postou

  1. Eu tenho um arquivo chamado helpers.php no Laravel, onde defini a função apuração: function apuracao ( ) { $array = ['teste'=>14]; return json_decode(json_encode($array)); } Mas na hora que preciso dele no controlador, ele não funciona quando executo dd($array->teste); o Laravel reclama que estou tentando pegar um atributo de um array. Depois de várias tentativas e erros, acredito que você só pode usar a função json dentro do controlador, mas não pode passar o valor dele para frente através de um return. Claro que é bem possível que o erro seja só meu, mas depois de quatro horas de tentativa, pedi para o arquivo helpers.php só mandar o array, e eu converto o array em json só lá no controlador.
  2. O meu conhecimento em HTML é precário, o máximo que eu aprendi foi usar o marcador <table>. Eu criei três <table>, um dentro do outro. Eu acreditava que era impossível colocar um <table> do lado do outro, mas a Gemini disse que é possível, assim: <table style=float:left> <tr> <td> <tr> <td> <table style=float:right> Como a Gemini é 50% confiável, fiz o teste, e funcionou! Arquivo MVC.php (provisório, estou usando no lugar do Index.php) <?php ini_set('display_errors', 1); require __DIR__ . '/Modelos/Config.php'; if($_GET) { $comando=explode('_',key($_GET)); $controle=new $comando[0]; $funcao=$comando[1]; if(count($comando)==3) { $_GET[$funcao]=$comando[2]; } call_user_func(array($controle,$funcao)); } else { $login=new ControleLogin(); $login->login(); } Arquivo Modelos / Config.php <?php date_default_timezone_set('America/Sao_Paulo'); defined('PROJETO') || define('PROJETO',$_SERVER['DOCUMENT_ROOT'].'/Frank/'); defined('CONTROLES') || define('CONTROLES',PROJETO.'/Controles/'); defined('MODELOS') || define('MODELO',PROJETO.'/Modelos/'); defined('VISOES') || define('VISOES',PROJETO.'/Visoes/'); defined('HOST') || define('HOST','localhost'); defined('DBNAME') || define('DBNAME','Diario'); defined('USER') || define('USER','Root'); defined('PASSWORD') || define('PASSWORD','14061406'); spl_autoload_register(function($Class) { $includeDir = false; $findDir = ['Controles','Modelos','Visoes']; foreach ($findDir as $DirName) { if (!$includeDir && file_exists(FindClass($DirName, $Class)) && !is_dir(FindClass($DirName, $Class))) { include_once (FindClass($DirName, $Class)); $includeDir = true; } } if (!$includeDir) { die("$Class - Erro interno no servidor ao encontrar dados cruciais de funcionamento!"); } }); function FindClass($dir, $class) { return ( $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . '/frank/' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR . $class . '.php'); } 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 dec($value) { if($value==null) { return null; } return number_format($value,2,',','.'); } function deca($num) { $value=str_replace(".","",$num); return str_replace(",",".",$value); } function fmt($date) { return date('d/m/y',strtotime($date)); } Arquivo Controles / ControleVenda.php <?php class ControleVenda extends Controle { public function inicio() { $detalhes=[];$detalhe=""; if(isset($_GET['inicio'])) { $detalhe=$_GET['inicio']; $detalhes=$this->Conexao->select("* from tbpedido where dia='$detalhe' and horavenda is not null group by horavenda order by horavenda desc"); } if(!isset($_SESSION['apuracao'])) { $_SESSION['apuracao']=date('Y-m-1'); } $primeiroDia=apuracao($_SESSION['apuracao'])->primeiroDia; $ultimoDia=apuracao($_SESSION['apuracao'])->ultimoDia; $grupos=$this->Conexao->select("date(horavenda) as ddia,sum(total) as ttotal from tbpedido where date(horavenda) between '$primeiroDia' and '$ultimoDia' and horavenda is not null group by ddia order by ddia desc"); $vendaMensal=$this->Conexao->select("date_format(horavenda,'%Y-%m') as mes, sum(total) as total from tbpedido where horavenda is not null group by mes order by mes desc"); return $this->view('Venda',['grupos'=>$grupos, 'vendaMensal'=>$vendaMensal,'detalhes'=>$detalhes,'detalhe'=>$detalhe]); } public function apuracao() { $_SESSION['apuracao']=$_GET['apuracao']."-1"; return $this->inicio(); } } Arquivo Visoes / Venda.php <?php include VISOES . "Menu.php"; ?> <script> document.title="Relatório de Vendas" btmenu.innerHTML="Relatório de Vendas" </script> <table class='table table-striped linha w-25' style=float:left> <tr><td colspan=2>Detalhe por mês <?php foreach($vendaMensal as $venda): ?> <tr><td><a href=?ControleVenda.apuracao.<?=$venda->mes?>><?=$venda->mes?></a> => R$ <td class='text-danger text-end'> <?=dec($venda->total)?> <?php endforeach; ?> </table> <table class='table table-striped linha w-25' style=float:right> <tr><td colspan=2>Detalhe por dia <tr class=fw-semibold><td>Dia<td class=text-end>Total <?php foreach($grupos as $grupo): ?> <tr class=fw-semibold onclick="location.replace('?ControleVenda.inicio.<?=$grupo->ddia?>')"> <td><?=date('d/m/y',strtotime($grupo->ddia))?> <td class=text-end><a href=?ControleVenda.inicio><?=dec($grupo->ttotal)?></a> <?php if($detalhe==$grupo->ddia): ?> <tr><td> <table class="table table-striped linha"> <tr class=fw-semibold><td><?=$grupo->ddia?><td>Pedido<td>Total<td>dinheiro<td>troco<td>cartão<td>pix <?php foreach($detalhes as $grupo): ?> <tr> <td class=text-end><?=date('H:i',strtotime($grupo->horavenda))?> <td class=text-end><?=$grupo->ped?> <td class=text-end><?=dec($grupo->total)?> <td class=text-end> <?php if(abs($grupo->dinheiro)>0): ?> <?=dec($grupo->dinheiro)?> <?php endif; ?> <td class=text-end> <?php if(abs($grupo->troco)>0): ?> <?=dec($grupo->troco)?> <?php endif; ?> <td class=text-center> <?php if($grupo->cartao==1): ?> x <?php endif; ?> <td class=text-center> <?php if($grupo->pix==1): ?> x <?php endif; ?> <?php endforeach; ?> </table> <?php endif; ?> <?php endforeach; ?>
  3. Eu não consegui colocar o HTML dentro de uma função do PHP, mas consegui fazer o contrário. Com a ajuda da Gemini consegui montar o seguinte código: arquivo teste.html <meta charset="UTF-8"> <style> #divMensagem {width:500;margin:0 auto} .numero {color:blue} .numero:hover{color:red} </style> <script> function enviar(apuracao) { dialog=document.createElement("dialog") dialog.innerHTML="o período selecionado foi o " + apuracao document.body.appendChild(dialog) dialog.showModal() } async function apuracao() { response = await fetch('apuracao.php') dados = await response.json() array=dados.toString().split(",") ano=array[0].substring(0,4) divMensagem.innerHTML="Selecione um período de apuração:<br>" divMensagem.innerHTML+=ano + " " for(i=0;i<array.length;i++) { if(array[i].substring(0,4)!=ano) { ano=array[i].substring(0,4) divMensagem.innerHTML+="<br>" + array[i].substring(0,4) + " " } divMensagem.innerHTML+="<spam class=numero id=" + array[i] + " onclick=enviar(this.id)>" + array[i].slice(-2) + "</spam> " } } apuracao() </script> <div id="divMensagem" ></div> arquivo Apuracao.php <?php require 'Config.php'; class Apuracao extends Controle { public function inicio() { $primeiroDia=$this->Conexao->select('dia from tbdiario order by dia')[0]->dia; $ultimoDia=$this->Conexao->select('dia from tbdiario order by dia desc')[0]->dia; $apuracoes=[]; while($primeiroDia<=$ultimoDia) { $apuracoes[]=date('Y-m',strtotime($primeiroDia)); $data=new DateTime($primeiroDia); $primeiroDia=date_modify($data,'+1 month')->format('Y-m-1'); } rsort($apuracoes); echo json_encode($apuracoes); } } $Controle=new Apuracao(); $Controle->inicio();
  4. Sempre que eu encontro informações desencontradas, eu preciso logar na Hostinger, digitar a senha, passar pela autenticação de dupla etapa, passar por um labirinto de painéis até chegar no painel de banco de dados. Chegando lá, me dá um branco, e eu me pergunto: o que eu vim fazer aqui? Hoje decidi acabar com esse constrangimento. Toda vez que eu encontrar algo estranho na tela do meu projeto, eu duplico a página, e numa delas eu vou no Painel SQL: Arquivo Controles / Controle.php <?php session_start(); require_once $_SERVER['DOCUMENT_ROOT'].'/Modelos/Config.php'; class Controle { public function painel() { $sql=""; $resposta=""; if(isset($_POST['sql'])) { $sql=$_POST['sql']; $resposta=$this->Conexao->select($sql); } return $this->view('PainelSQL',['sql'=>$sql,'resposta'=>$resposta]); } Arquivo Visoes / PainelSQL.php <?php include VISOES . 'Menu.php'; ?> <script>btmenu.innerHTML='Painel SQL'</script> SQL => SELECT <form method=post action=?Controle.painel> <textarea name=sql rows=5 cols=60> <?=$sql?> </textarea> <p></p> <input type=submit> </form> <hr> <p class=text-danger>Resposta</p> <div><?=var_dump($resposta)?></div>
  5. Frank K Hosaka

    PHP readline

    Ontem, eu perguntei para a Gemini se é possível colocar um HTML dentro de uma função do PHP. Ela disse que sim, e sugeriu esse código: <?php function solicitarPeriodoApuracao() { echo "Selecione o período de apuração:\n"; $apuracao = readline("Data inicial (dd/mm/aaaa): "); return [ 'apuracao' => $apuracao ]; } $teste=solicitarPeriodoApuracao(); var_dump($teste); Eu testei e não funcionou. Reclamei com a Gemini, e ela disse que eu preciso instalar a extensão readline no PHP. Eu procurei a extensão, e não achei. O problema da Gemini é o mesmo do Bard, ela não testa os códigos que ela divulga. Isso me fez lembrar do Basic que eu vi na década de 1980, ele usava o comando Input para aguardar informações do usuário. Na década de 1990, a Microsoft inventou o Office e com ele o Visual Basic. O Visual Basic apresentou o InputBox, ele é muito bacana, você pode botar a caixa aonde você quiser. Mas em 2020 eu conheci o PHP. Para o meu desespero, não existe nenhum meio do PHP conversar com o usuário senão usando o HTML. Ao invés de descartar a ideia da Gemini, tentei criar um projeto assim: <?php function solicitarPeriodoApuracao() { if(isset($_POST)) { return $_POST; } ob_start(); ?> <form method=post> Entre com a data da apuração AAAA-mm-dd <input name=apuracao> </form> <?php ob_flush(); } $teste=solicitarPeriodoApuracao(); var_dump($teste); Pura perda de tempo! Não funciona!
  6. Eu tenho um código que ajuda o usuário a escolher um período de apuração. O problema é que eu tenho um código chamado balancete, outro chamado razão e finalmente um chamado Mercado Pago. Os três precisam da rotina para escolher o período de apuração. A pergunta é: como o código da apuração vai saber quem iniciou o serviço? No PHP, temos o comando function ( ), ele devolve o comando para quem lhe chamou, sem precisar de nenhum código adicional. Eu tentei colocar um view dentro da function ( ) e o resultado foi um desastre. A minha saída foi criar um roteador dentro da função apuração. Para chamar a função, usei o comando <a href=?ControleDiario.apuracao.razao> dentro do view balancete e do view razão e <a href=?ControleDiario.apuracao.mercado> dentro do view Mercado Pago. Para melhorar mais ainda, a própria função apuração recebe o valor escolhido pelo usuário, coisa do tipo <a href=?ControleDiario.apuracao.2024-02> dentro do view Apuracao. Ou seja, eu coloquei o nome do solicitante bem como a apuração escolhida pelo usuário dentro da mesma chave. Olha só a baderna que ficou: Arquivo Controles/ControleDiario.php <?php class ControleDiario extends Controle { public function apuracao() { if(isset($_GET['apuracao'])) { if(is_numeric(substr($_GET['apuracao'],0,4))) { $apuracao=apuracao($_GET['apuracao']."-1"); $_SESSION['dia']=$apuracao->primeiroDia; if($_SESSION['endereco']=="mercado") { return $this->mercado(); } return $this->razao(); } else { $_SESSION['endereco']=$_GET['apuracao']; } } $primeiroDia=$this->Conexao->select('dia from tbdiario order by dia')[0]->dia; $ultimoDia=$this->Conexao->select('dia from tbdiario order by dia desc')[0]->dia; $apuracoes=[]; while($primeiroDia<=$ultimoDia) { $apuracoes[]=date('Y-m',strtotime($primeiroDia)); $data=new DateTime($primeiroDia); $primeiroDia=date_modify($data,'+1 month')->format('Y-m-1'); } rsort($apuracoes); $this->view('Apuracao',['apuracoes'=>$apuracoes]); } // ... } Arquivo Views/Apuracao.php <?php include VISOES . 'Menu.php'; echo "<table class='table table-striped'> <tr class='fw-semibold'><td><td>Selecione o período de apuração"; foreach($apuracoes as $apuracao) { $ano = substr($apuracao,0,4); $mes = substr($apuracao,5,2); if(!isset($anoAnterior)) { echo "<tr><td>$ano<td>";$anoAnterior=$ano; } if($ano!==$anoAnterior) { echo "<tr><td>" . $ano ."<td><a href=?ControleDiario.apuracao.$apuracao>$mes</a> "; $anoAnterior=$ano; } else { echo " <a href=?ControleDiario.apuracao.$apuracao>$mes</a> "; } } echo "</table>"; Isso é uma grande gambiarra, mas funciona.
  7. Para eu ter um site preciso pagar R$ 74,98 todo ano, eles chamam o produto de Dominio. O plano de hospedagem é basicamente dois: o compartilhado "Premium Web Hosting" e o VPS (aqui tem várias subcategorias, eu peguei o mais barato). O valor do plano VPS é de 24.99 por mês, mas eu paguei R$ 719,16 para os anos de 2024 e 2025. A Hostinger mudou o preço sem eu perceber, eles cobraram todo o valor do pacote de uma só vez. Isso é um péssimo negócio. Agora, eles voltaram a cobrar por mês, mas o meu dinheiro já foi para o saco. Para testar o VPS, eu não precisei comprar um Domínio novo, eu criei vários subdomínios, e eles funcionaram sem nenhum problema. O problema foi na hora de apontar o domínio para o novo IP do servidor VPS. Eu consegui criar o site baseado no domínio, mas não consegui instalar o certificado de credibilidade Let's Encrypt. Eu pedi ajuda, e eles me informaram que o erro está no servidor, o único que pode consertar isso era somente eu, pois eles não têm acesso ao conteúdo do servidor. Eu fiquei indignado. Fui pesquisar na internet, e só obtive mais orientações confusas, do tipo que eu deveria verificar o IPv6. Sem a ajuda da Hostinger e sem a ajuda da internet, tudo o que restou foi o famoso método científico da tentativa e erro. Eu imaginei que o problema estava fora do servidor. Não basta apontar o domínio para o novo IP. Então eu decidi destruir todo o site que eu criei dentro do Premium Web Hosting. Tentei instalar o certificado, e outra vez eu não consegui. Mas pelo menos eu consegui abrir o domínio no navegador, apesar dele reclamar que o site não é nada confiável. Depois de várias horas, eu tentei de novo, e finalmente consegui instalar o certificado. Agora o navegador abre o domínio sem reclamar e com a clássica mensagem do index.php "Hello World!". Para administrar os sites criados no VPS, eu uso o painel CloudPanel, pois eu não entendo nada de servidor. Não é fácil se familiarizar com essa ferramenta, eu tive que destruir os sites umas três vezes, até pegar o jeito, e aprendi da pior maneira que não é para ficar brincando com o Gerenciador de DNS, você não pode criar um DNS, destruir e recriar o mesmo DNS por mais de três vezes. A maior diferença entre a hospedagem VPS e o compartilhado além do preço é um novo recurso chamado Ubuntu. Eu tenho pavor dele, e a Hostinger já deixou bem claro que não dá nenhuma assistência com essa ferramenta. Já brinquei com ele e me dei mal, eu tive que destruir os sites e começar do zero. O meu conhecimento em Linux é mais precário do que eu sei de PHP, HTML, JavaScript e Laravel, mas preciso instalar o programa npm, e só assim eu poderei estudar melhor o Laravel. O Laravel usa o Taiwinds CSS e só dá para mexer nele somente com a ajuda do Linux. E eu nem sei como logar nele.
  8. Em 2020 eu criei uma planilha que faz auditoria no MySQL usando um view chamado vw_balancete. No código PHP, eu também usei o vw_balancete para montar o demonstrativo contábil, só que eu percebi que é mais rápido usar os recursos do PHP para montar o demonstrativo do que utilizar o recurso do MySQL. Em 2024, eu decidi não trabalhar mais com o view do MySQL. O problema é saber como a planilha iria fazer a auditoria. A minha ideia foi pedir para o PHP montar o demonstrativo dentro de uma tabela que eu chamei de tbw. Para a minha alegria, agora a planilha não demora mais cinco minutos para fazer a auditoria, ela é instantânea! Mas eu ainda não sei se é possível conectar a planilha à tabela tbw hospedado no VPS do Hostinger. Primeiro eu tenho que baixar uma cópia do banco de dados do servidor, depois atualizo o meu banco de dados no meu PC, e finalmente eu peço para a planilha fazer a auditoria. Isso é muita burocracia, mas eu pedi para o PHP pelo menos abrir o banco de dados, assim que ele terminar de montar a tabela tbw, e de lá eu começo o serviço de exportação. Arquivo Modelos / Config.php <?php 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])); } Arquivo Controles / ControleDiario.php <?php class ControleDiario extends Controle { public function balancete() { $receita=0; $despesa=0; $anterior=0; $balancete=[]; $contas=$this->Conexao->select("* from tbconta"); if(!isset($_SESSION['dia'])){$_SESSION['dia']=date('Y-m-d');} $apuracao=apuracao($_SESSION['dia']); $primeiroDia=$apuracao->primeiroDia; $ultimoDia=$apuracao->ultimoDia; foreach($contas as $conta) { $debitoAnterior=$this->Conexao->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia<'$primeiroDia'")[0]->soma; $creditoAnterior=$this->Conexao->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia<'$primeiroDia'")[0]->soma; $inicio=$debitoAnterior-$creditoAnterior; $anterior+=$inicio; $debito=$this->Conexao->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia between '$primeiroDia' and '$ultimoDia'")[0]->soma; $credito=$this->Conexao->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia between '$primeiroDia' and '$ultimoDia'")[0]->soma; $debitoFim=$this->Conexao->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia<='$ultimoDia'")[0]->soma; $creditoFim=$this->Conexao->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia<='$ultimoDia'")[0]->soma; $fim=$debitoFim-$creditoFim; if($conta->conta>=301 and $conta->conta<=304) { $receita+=$fim; } if($conta->conta>304) { $despesa+=$fim; } array_push($balancete,['conta'=>$conta->conta,'descricao'=>$conta->descricao, 'inicio'=>$inicio,'debito'=>$debito,'credito'=>$credito,'fim'=>$fim]); } $resultado=$receita+$despesa; if($resultado<0){$nota="Lucro";} else {$nota="Prejuízo";} $balancete=json_decode(json_encode($balancete)); return json_decode(json_encode(['balancete'=>$balancete,'apuracao'=>$apuracao, 'anterior'=>$anterior,'despesa'=>$despesa,'receita'=>$receita, 'resultado'=>$resultado,'nota'=>$nota])); } public function tbw() { $ultimoDia=$this->Conexao->select("dia from tbdiario order by dia desc")[0]->dia; $_SESSION['dia']=$ultimoDia; $balancete=$this->balancete()->balancete; $this->Conexao->exec("drop table if exists tbw"); $this->Conexao->exec("create table tbw (conta int not null, descricao varchar(45) default null, inicio decimal(13,2) default null, debito decimal(13,2) default null, credito decimal(13,2) default null, fim decimal(13,2) default null, primary key (conta)) engine=InnoDB default charset=utf8mb4 collate=utf8mb4_0900_ai_ci"); foreach($balancete as $conta) { $inicio=$conta->inicio; $debito=$conta->debito; $credito=$conta->credito; $fim=$conta->fim; if($inicio==null) { $inicio='null'; } if($debito==null) { $debito='null'; } if($credito==null) { $credito='null'; } if($fim==null) { $fim='null'; } $this->Conexao->insert("tbw values ($conta->conta,'$conta->descricao', $inicio,$debito,$credito,$fim)"); } return header("location:https://123.123.123.123:8443/phpmyadmin/index.php?route=/database/export&db=Diario"); } }
  9. Arquivo Index.php <?php $mysqli=new mysqli("localhost","root","","diario"); function query($sql) { $mysqli=$GLOBALS['mysqli']; $query=$mysqli->query($sql); return json_decode(json_encode($query->fetch_all(MYSQLI_ASSOC))); } arquivo Exemplo.php <?php require 'Index.php'; $exemplo=query("select * from tbprod where prod like '%maçã%'"); foreach($exemplo as $ex) { echo $ex->prod . "<br>"; }
  10. Com a ajuda da Gemini, ontem eu descobri que o Bootstrap tem uma forma mais suave para destacar um texto. A seguir fiz um código de como usei o destaque nos últimos quatro anos: <!DOCTYPE html> <html lang="en"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script> <style>body {width:200px;margin:0 auto} .linha {line-height:0px}</style> <table> <tr><th align="right">A conta binária 1.0</th><td></td></tr> <tr><td></td><td align=right>1</td></tr> <tr><td></td><td align=right>+1</td></tr> <tr align="right"><td><b>total</td><td><b>10</td></tr> </table> <p></p> <table class="table table-striped border"> <tr class="fw-bold text-end" ><td>A conta binária 2.0<td> <tr><td><td class="text-end">1 <tr><td><td class="text-end">+1 <tr class="fw-bold text-end"><td>total<td>10 </table> <p></p> <table class="table table-striped linha border"> <tr class="fw-semibold text-end"><td>A conta binária 3.0<td> <tr><td><td class="text-end">1 <tr><td><td class="text-end">+1 <tr class="fw-semibold text-end"><td>total<td>10 </table>
  11. Lá em 2020, eu usei $_GET para montar o meu orçamento em PHP. Aqui em 2024 estou estudando o MVC, onde você separa os códigos por partes em modelo, visão e controle. O problema é que eu ainda preciso da gambiarra do $_GET para a visão funcionar (eu não sei usar o JavaScript). Para a minha sorte, acabei descobrindo que é bem mais fácil manusear o $_GET pelo MVC do que pelo PHP convencional. O código a seguir está incompleto, mas a rotina que trabalha com o $_GET já funciona: arquivo Controles > ControleOrcamento.php <?php class ControleOrcamento extends Controle { public function inicio() { $prod=$this->Conexao->select("* from tbprod order by prod"); $maquina=strpos($_SERVER['HTTP_USER_AGENT'],"Windows"); $hoje=date('Y-m-d'); $vr=['ped'=>'','diaped'=>$hoje,'totalped'=>'','codp'=>'','pessoa'=>'', 'end'=>'','cnpj'=>'','tel'=>'','nota'=>'','codprod'=>'','un'=>'', 'prod'=>'','preço'=>'','horavenda'=>'']; $where=""; if(isset($_GET['inicio'])){ if($_GET['inicio']=="novo"){ $vr['ped']=$_GET['novo'];$_SESSION['ped']=$_GET['novo']; $histped=[]; return $this->view('Orcamento',['vr'=>$vr,'histped'=>$histped, 'prod'=>$prod,'maquina'=>$maquina]);} if($_GET['inicio']=="produto"){ $vr['prod']=$_SESSION['prod']; $vr['un']=$_SESSION['un']; $vr['preço']=$_SESSION['preço'];} if($_GET['inicio']!=="novo" && $_GET['inicio']!=="produto"){ $ped=$_GET['inicio']; $_SESSION['ped']=$ped; $where="where ped=$ped"; unset($_GET['inicio']);} } $ped=$this->Conexao->select("* from tbpedido $where order by ped desc")[0]; $vr['ped']=$ped->ped; $_SESSION['ped']=$ped->ped; $vr['diaped']=$ped->dia; $vr['horavenda']=$ped->horavenda; $vr['totalped']=$ped->total; $vr['codp']=$ped->codp; if($vr['codp']){ $pessoa=$this->Conexao->select("* from tbpessoa where codp=". $vr['codp'])[0]; $vr['pessoa']=$pessoa->pessoa; $vr['end']=$pessoa->end; $vr['cnpj']=$pessoa->cnpj; $vr['tel']=$pessoa->tel; $vr['nota']=$pessoa->nota;} $histped=$this->Conexao->select("tbhistped.id,tbhistped.ped, tbhistped.codprod, tbhistped.qt as qt, tbhistped.unitario as unitario, tbhistped.subtotal, tbprod.prod as prod, tbprod.un as un from tbhistped inner join tbprod on tbhistped.codprod = tbprod.codprod and tbhistped.ped = $ped->ped order by tbhistped.id"); return $this->view('Orcamento',['vr'=>$vr,'histped'=>$histped,'prod'=>$prod,'maquina'=>$maquina]); } public function historicoOrc() { $where=""; if(isset($_GET['historicoOrc'])){ $ped=$_SESSION['referencia']+$_GET['historicoOrc']; $where="where ped <= $ped";} $pedidos=$this->Conexao->select("* from tbpedido left join tbpessoa on tbpedido.codp = tbpessoa.codp $where order by ped desc limit 20"); $_SESSION['referencia']=$pedidos[0]->ped; return $this->view('HistoricoOrc',['pedidos'=>$pedidos]); } public function novo() { $pedido=$this->Conexao->select("* from tbpedido order by ped desc")[0]; $ped=$pedido->ped; $total=$pedido->total; if($total!==null){$ped++;} return header("location:?ControleOrcamento.inicio.novo&novo=$ped"); } public function produto() { $produto=$_POST['produto']; $tamanho=strlen($produto); $posicao=strpos($produto,":"); if($posicao==0){ $_SESSION['filtro']=$produto; $_SESSION['endereco']="Orcamento"; return header('location:?ControleProduto.produto');} $_SESSION['codprod']=substr($produto,$posicao+1,$tamanho-$posicao); $produto=$this->Conexao->select("* from tbprod where codprod=" . $_SESSION['codprod'])[0]; $_SESSION['prod']=$produto->prod; $_SESSION['un']=$produto->un; $_SESSION['unitario']=pvenda($produto->custo,$produto->marg); return header('location:?ControleOrcamento.inicio.produto'); } public function qt() { $qt=$_POST['qt']; $ped=$_SESSION['ped']; $un=$_SESSION['un']; $unitario=deca($_SESSION['unitario']); $subtotal=$qt*$unitario; $codprod=$_SESSION['codprod']; $this->Conexao->insert("tbhistped (ped,codprod,un,unitario,subtotal,qt) values ($ped,$codprod,'$un',$unitario,$subtotal,$qt)"); $this->inicio(); } } arquivo Visoes > Orcamento.php <?php include VISOES . 'Menu.php';?> <script>document.title="Orçamento" btmenu.innerHTML='Orçamento' </script> <table class='table table-striped'> <td><a href=?ControleOrcamento.historicoOrc>Historico</a> <td class=text-danger>Pedido <?=$vr['ped']?> de <?=fmt($vr['diaped'])?> <td><a href=?ControleOrcamento.novo>Novo</a> <?php if($maquina===13): ?> <td><a href=controlid?pedido.<?=$vr['ped']?>>Imprimir</a> <?php endif; ?> </table> <table class='table table-striped'> <th>Produto<th style=text-align:right>Qt<th>Un<th>Preço<th>Total <?php foreach($histped as $item): ?> <tr> <td nowrap><?=$item->prod?> <td class=text-end> <form> <?php if($item->qt==intval($item->qt)): ?> <input name=aqt value='<?=$item->qt?>' onchange=submit() size=1 style=text-align:right;border:none;background:transparent> <?php else: ?> <input name=aqt value='<?=dec($item->qt)?>' onchange=submit() size=1 style=text-align:right;border:none;background:transparent> <?php endif; ?> <input type=hidden name=id value=<?=$item->id?>> <input type=hidden name=ped value=<?=$item->ped?>> </form> <td><a href=?ControleOrcamento.excluir.<?=$item->id?>&pedido=<?=$item->ped?>><?=$item->un?></a> <td class=text-end><?=dec($item->unitario)?> <td class=text-end><?=dec($item->subtotal)?> <?php endforeach; ?> <tr> <?php if(!isset($_GET['inicio'])):?> <td> <form action=?ControleOrcamento.produto method=post> <input list=lsproduto name=produto placeholder=produto onchange=submit() size=40 autofocus> <datalist id='lsproduto'> <?php foreach($prod as $pr): ?> <option value='<?=$pr->prod?> :<?=$pr->codprod?>'> <?php endforeach; ?> </datalist> </form> <?php else: ?> <td><?=$vr['prod']?> <?php endif; ?> <?php if(!isset($_GET['qt'])): ?> <td class=text-end> <form action=?ControleOrcamento.qt method=post> <input id=qt name=qt onchange=submit() size=1 placeholder=qt autofocus> <input type=hidden name=texto value="<?=fmt($vr['preço'])?>,<?=$vr['ped']?>,<?=$vr['un']?>"> </form> <td><?=$vr['un']?><td class=text-end><?=$vr['preço']?><td> <?php endif; ?> <tr><td> <?php if(empty($vr['codp'])): ?> <a href=pessoa>Selecione um cliente</a> <?php else: ?> <details> <summary><b><?=$vr['pessoa']?></b></summary> Endereço <b><?=$vr['end']?></b> <br> CNPJ <b><?=$vr['cnpj']?></b> <br> Telefone <b><?=$vr['tel']?></b> <br> Nota <b><?=$vr['nota']?></b> <br> <a href=pessoa>Mudar cliente</a> <br> <a href="pessoa?busca=<?=$vr['pessoa']?>">Atualizar cliente</a> </details> <?php endif; ?> <td><td><td><td><b><?=dec($vr['totalped'])?> </table>
  12. Nossa, que coisa complicada. Eu não sou profissional, eu só sei fazer gambiarra, eu tentaria algo do tipo: <?php $teste=get_file_contents("https://api.awin.com/publisher/915215/promotions?accessToken=XXXXXX"); var_dump($teste);
  13. Lá embaixo está escrito "add these headers to your local app", você tentou usá-lo?
  14. O meu conhecimento em HTML é bastante precário. Eu estava fazendo um código em MVC para navegar entre os registros dos orçamentos, mas eu não consegui publicar três links assim "< ped >". Antes de entrar em desespero, pedi ajuda para a Gemini, e ela me aconselhou a usar um marcador <div> dentro de uma célula <td>, assim: arquivo Controles > ControleOrcamento.php <?php // ... public function historicoOrc() { $where=""; if(isset($_GET['historicoOrc'])){ $ped=$_SESSION['referencia']+$_GET['historicoOrc']; $where="where ped <= $ped";} $pedidos=$this->Conexao->select("* from tbpedido left join tbpessoa on tbpedido.codp = tbpessoa.codp $where order by ped desc limit 20"); $_SESSION['referencia']=$pedidos[0]->ped; return $this->view('historicoOrc',['pedidos'=>$pedidos]); } arquivo Visoes > HistoricoOrc.php <?php include VISOES . 'Menu.php'; ?> <script>btmenu.innerHTML='Histórico dos Orçamentos'</script> <table class='table table-striped linha'> <th>Dia <th><div style="display:flex;width:20px"> <a href="?ControleOrcamento.historicoOrc.-19"><</a>&nbsp; <a href="?ControleOrcamento.inicio">Ped</a>&nbsp; <a href="?ControleOrcamento.historicoOrc.19">></a> </div> <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=?ControleOrcamento.inicio.<?=$ped->ped?>><?=$ped->ped?></a> <td class=text-end><?=dec($ped->total)?> <td><?=$ped->pessoa?> <?php endforeach; ?>
  15. Não consegui adicionar o manipulador .fail( ), e testei o $.get( ).done( ), e depois de um minuto apareceu a mensagem de que o canal foi fechado mesmo obtendo a confirmação da consulta, se bem que tudo que era esperado foi publicado no navegador.
  16. A primeira vez que eu vi essa mensagem foi em 2020, quando comecei a estudar o PHP. A orientação que eu recebi é de procurar um espaço mal digitado no código. Eu não achei. Para a minha sorte eu encontrei um código JScript que me ajudou a contornar o problema: <?php // ... echo "<script>location.replace('diario.php')</script>"; Finalmente, cheguei em 2024, e comecei a estudar o MVC, é uma gramática que trabalha com pastas, classes, métodos e propriedades, mais conhecido como objetos. O problema é encontrar tutorial fácil de compreender, e isso é bem difícil. Assim, tomei a iniciativa de tentar por conta própria. É claro que eu não consegui. Tanto é que eu precisei usar novamente o comando do PHP header, e novamente surgiu a velha mensagem de erro. Dessa vez, eu não queria usar o JScript. O erro aconteceu nesse código: <?php // ... public function lcto(){ if(isset($_GET['lcto'])){ $_SESSION['lcto']=$_GET['lcto']; $this->entraProduto();} $_SESSION['endereco']="entraProduto"; header("location:?ControleDiario.inicio");exit;} O erro é muito sutil, difícil de enxergar. O trabalho da função lcto é mudar a rota do serviço, ele precisa espionar o ControleDiário para procurar o número do lançamento contábil. No ControleDiário eu pedi para ele devolver o comando para o ControleEstoque se encontrar a variável $_SESSION['endereço'] ativada, usando o mesmo recurso do header. O problema da função lcto é que ele está mal escrito, ele deveria espionar o ControleDiario ou receber a informação dele, mas não os dois ao mesmo tempo. Foi isso que aconteceu, o certo é escrever assim if(condição){faça isso, e mais nada}, ou: <?php // ... public function lcto(){ if(isset($_GET['lcto'])){ $_SESSION['lcto']=$_GET['lcto']; $this->entraProduto(); exit; } $_SESSION['endereco']="entraProduto"; header("location:?ControleDiario.inicio");exit;}
  17. Estou apanhando demais, montando o meu projeto orçamento na gramática do MVC PHP, principalmente na hora de redirecionar os comandos. Redirecionar é bem fácil, o difícil é voltar para o ponto de partida. Compartilhei o meu problema com a Gemini, e ela me aconselhou a usar o Ajax, e com a ajuda dela eu montei o meu projeto. Ele funciona, só que depois de um minuto a caixa de inspeção do navegador reclama que encontrou um erro, e a Gemini só me orienta a estudar mais. Agora eu entendo porque a Script Brasil tirou o tópico JScript do fórum. Aqui está o meu código: arquivo Index.php <?php $mysqli=new mysqli("localhost","root","","diario"); $query=$mysqli->query("select * from tbprod where prod like '%pão%'"); $produtos=json_encode($query->fetch_all(MYSQLI_ASSOC)); echo $produtos; arquivo teste.html <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script> $(document).ready(function() { $.get("Index.php", function(resultado) { $("#mensagem").html("json: <br>" + resultado) $("#tamanho").html("<br>tamanho:<br>" + resultado.length) produto=JSON.parse(resultado) $("#primeiroProduto").html("<br>primeiro produto:<br>" + produto[0].prod)})}) </script> <style>body {width:800;margin:0 auto}</style> <div id="mensagem"></div> <div id="tamanho"></div> <div id="primeiroProduto"></div> <!-- mensagem de erro na inspeção do navegador, depois de um minuto: Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received -->
  18. Testar o código PHP no PC é uma coisa, e testar o mesmo código lá no servidor VPS da Hostinger é bem diferente. Como ainda não terminei o código MVC, eu copiei o código Index.php como MVC.php. A resposta que eu obtive foi o de que a página se recusa a responder, HTTP 500. O PHP do PC é mais didático, ele sempre aponta o endereço exato de onde está o problema. Para ter o mesmo recurso na Hostinger, eu acrescentei o comando ini_set('display_errors',1); no arquivo MVC.php. Outro problema é a variável $_SERVER['DOCUMENT_ROOT'], o PHP do Hostinger inclui o nome da pasta que contém os códigos, e o do PC não. Logo, o autoload e o roteador não podem ser iguais como no PC. Finalmente, o que me deixou surpreso são as rotas que eu defini nos formulários. Tenho algo do tipo <a href=?ControleDiario.inicio>Diário</a>. No PC, isso vai direto no roteador que está no arquivo Index.php. Para a minha surpresa, o PHP do Hostinger entendeu como MVC.php?ControleDiario.inicio. Ou seja, não preciso mexer nos formulários, tudo indica que o PHP do Hostinger sabe aonde está o roteador.
  19. Ontem eu consegui montar o balancete. Eu já tenho a consulta que monta o balancete no MySQL e eu chamei de vw_balancete, mas até ele aparecer na tela do navegador é bastante tempo, coisa de um minuto. Isso é muito tempo. Descobri que é bem mais rápido eu pedir para o PHP montar o balancete do que pegar um já pronto no MySQL. O código ficou assim: <?php // ... public function balancete(){ $balancete=[]; $contas=$this->Conexao->select("* from tbconta"); if(!isset($_SESSION['dia'])){$_SESSION['dia']=date('Y-m-d');} $apuracao=apuracao($_SESSION['dia']); $primeiroDia=$apuracao->primeiroDia; $ultimoDia=$apuracao->ultimoDia; foreach($contas as $conta){ $debitoAnterior=$this->Conexao->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia<'$primeiroDia'")[0]->soma; $creditoAnterior=$this->Conexao->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia<'$primeiroDia'")[0]->soma; $inicio=$debitoAnterior-$creditoAnterior; $debito=$this->Conexao->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia between '$primeiroDia' and '$ultimoDia'")[0]->soma; $credito=$this->Conexao->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia between '$primeiroDia' and '$ultimoDia'")[0]->soma; $debitoFim=$this->Conexao->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia<='$ultimoDia'")[0]->soma; $creditoFim=$this->Conexao->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia<='$ultimoDia'")[0]->soma; $fim=$debitoFim-$creditoFim; array_push($balancete,['conta'=>$conta->conta,'descricao'=>$conta->descricao, 'inicio'=>$inicio,'debito'=>$debito,'credito'=>$credito,'fim'=>$fim]);} $balancete=json_decode(json_encode($balancete)); $_SESSION['balancete']=$balancete; $this->view('balancete',['balancete'=>$balancete,'apuracao'=>$apuracao]);} O problema foi pegar os valores correspondentes à conta selecionada nesse view: <?php require VISAO . '/menu.php'; $_SESSION['uri']=$_SERVER['REQUEST_URI'];?> <table class='table table-striped linha'> <th><th><a href='?ControleDiario.apuracao'><?=$apuracao->apuracao?></a> <th class=text-end>Inicial<th class=text-end>Débito <th class=text-end>Crédito<th class=text-end>Saldo <?php foreach($balancete as $conta): ?> <tr> <td><a href=?ControleDiario.razao.<?=$conta->conta?>><?=$conta->conta?></a> <td nowrap><?=$conta->descricao?> <td class=text-end><?=dec($conta->inicio)?> <td class=text-end><?=dec($conta->debito)?> <td class=text-end><?=dec($conta->credito)?> <td class=text-end><?=dec($conta->fim)?> <?php endforeach; ?> Tentei criar um vetor, tentei montar um <form> com um monte de <input type=hidden>, nada deu certo. É uma péssima ideia tentar colocar um <form> no meio da tabela. Agora que eu vi que não tentei colocar toda a tabela dentro do <form>, talvez essa seja a melhor resposta. Mas, enfim, eu desisti. Ao invés de pegar os valores de uma view, achei melhor pegar uma cópia do $balancete e colocar dentro do $_SESSION['balancete'], e a rotina do razão ficou assim: <?php // ... public function razao(){ $conta=$_GET['razao']; $balancete=$_SESSION['balancete']; $razao=array_column($balancete, null, 'conta')[$conta] ?? false; var_dump($razao);exit; }
  20. Eu nunca mexi numa função geradora, assim eu pedi para a Gemini me explicar. Foi pior, ela deu um exemplo que não funcionou. Para ela existe um método chamado next( ) que faz a função geradora executar o próximo comando. Se você quer usar um temporizador para exibir uma linha de cada vez o conteúdo do arquivo f.txt, acho melhor usar o JavaScript e não o PHP. O PHP publica tudo de uma vez e não uma linha de cada vez, ao contrário do JavaScript que o desenvolvedor pode amarrar junto com o cronômetro.
  21. O código que eu publiquei é simplista, ele não usa o objeto Request e nem o objeto Contato que aparecem no tutorial original, isso porque reduzi todo o PDO para o método query, e deixei de lado o conceito de objeto estático, não sei quando vou usar esse tipo de objeto ou quando vou usar outros métodos do PDO. O que eu mais gostei do tutorial foi do roteador, ele é o mais simples que eu encontrei na internet, ele usa duas chaves para identificar o destino do código, o controle e o seu método. Na minha versão, eu tirei as chaves. Outra coisa bacana é autoload, o do tutorial só serve para quem colocar todos os arquivos no diretório raiz. Eu distribui os arquivos em pastas diferentes, logo o autoload tem que ser mais robusto, e tive a sorte de encontrar na internet. O problema é que a vida do autoload é bem curta. O melhor lugar para colocar o autoload é no controle principal, pois todas as outras classes vão invocá-lo, através do comando extends na hora de definir a classe. E sem dúvida o controle também é o mehor lugar para manter conectado todo o projeto à sessão. O tutorial não usa a sessão, mas eu usei no meu projeto. A sessão é importante para mim, essa foi a única forma que eu encontrei para voltar ao ponto de partida.
  22. PHP $query=$mysqli->query("select date(horavenda) as vendido , sum(total) as total from tbpedido where horavenda is not null group by date(horavenda) order by date(horavenda) desc"); $groups=json_decode(json_encode($query->fetch_all(MYSQLI_ASSOC))); Laravel $groups=tbpedido::whereNotNull('horavenda') ->select(DB::raw('date(horavenda) as vendido, sum(total) as total')) ->groupBy(DB::raw('date(horavenda)')) ->orderBy(DB::raw('date(horavenda)'),'desc')->get();
  23. Depois de resolver o problema do autoload e do roteador sem Composer, hoje eu consegui resolver o problema da página anterior. Por exemplo, eu tenho uma página chamada Lançamentos.php, lá dentro tenho uma lista de produtos que fazem parte dos detalhes daquele lançamento; para acrescentar, alterar ou excluir o produto, eu vou ter que ir até outro controle que faça esse serviço. O problema é como voltar na página que deu origem ao serviço. Olha só a solução: Arquivo Visoes > Lancamento.php <?php include 'menu.php'; $_SESSION['uri']=$_SERVER['REQUEST_URI']; ?> <!-- ... --> <a href="?controller=ControleProduto&method=excluirItem&excluirItem=<?=$prod->id?>"> <?=$prod->un?></a> Arquivo Controles > ControleProduto.php <?php session_start(); class ControleProduto extends Controller { private $Conexao; public function __construct(){ $this->Conexao=new Conexao();} public function excluirItem(){ $id=$_GET['excluirItem']; $this->Conexao->delete("tbhistprod where id=$id"); return header("location:".$_SESSION['uri']);} }
  24. Fiz mais uma tentativa, acrescentando <tr><td colspan=5>, ou seja, inclui o cabeçalho dentro da <table> e deu certo. A minha tese é de que só dá para colocar um <form> dentro do <td> para apresentar numa só "linha". Essa solução funcionou no Laravel, mas no MVC não funcionou. Nessa nova tentativa, estou tentando colocar quatro controles numa só linha, só que nenhum deles é <form>: <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> <style>body{width:500px;margin:10 auto} .linha{line-height:0px}</style> <?php $dia='2024-02-06'; $mensagem=""; ?> <table class='table table-striped'> <tr><td colspan=5> <input type=submit value=Lançamentos onclick="location.replace('?controller=ControleDiario&method=novoLcto')"> do dia <input type=date name=novaData value=<?=$dia?> onchange="location.replace('?controller=ControleDiario&method=novaData&novaData='+this.value)"> <?=$mensagem?> <tr><th>Lçto<th>CtaD<th>CtaC<th>Valor<th>Histórico <tr class='linha'><td>111<td>100<td>200<td>12,00<td>Teste <tr class='linha'><td>111<td>100<td>200<td>12,00<td>Teste </table> Importante: na codificação convencional, só dá para criar uma solicitação através do <form>. No meu caso, deu para criar uma solicitação com o JavaScript embutido no <input>, porque tenho um roteador dentro do arquivo index.php. Ou seja, se eu soubesse como desenhar o HTML com o <div>, toda essa gambiarra não seria necessária. O problema é o tempo, eu sou um programador desesperado que apela para soluções desesperadas.
×
×
  • Criar Novo...