-
Total de itens
1865 -
Registro em
-
Última visita
-
Dias vencidos
32
Tudo que Matheus Tavares postou
-
Proteger código fonte contra cópias.
Matheus Tavares respondeu ao tópico de 4Unknow em Desenvolvimento frontend
Olá @4Unknow. O que você deve buscar é ofuscar o JS para ficar como nesse exemplo aqui: https://forum.imasters.com.br/topic/587904-desofuscar-javascript-para-jogo/ É bem simples, existem ferramentas que você roda na sua própria máquina ou até direto no navegador. O Google tinha uma API para fazer isso também. O HTML/CSS você não consegue ofuscar, mas o JS com certeza, e isso dificulta muito para fazer uma engenharia reversa no código.- 8 respostas
-
- segurança
- códigofonte
-
(e mais 3 )
Tags:
-
Erro ao migrar código de php 5.6 para pdo
Matheus Tavares respondeu ao tópico de Marcones Borges em PHP
Olá @Marcones Borges. Essa linha você precisa trocar para: while( $dados = $result->fetch(PDO::FETCH_ASSOC) ) Já para a contagem de registros, geralmente iriam te recomendar usar fetchAll e contar os registros usando PHP com count() ou sizeof(), desse jeito: $rows = $stmt->fetchAll(); $num_rows = count($rows); Outra opção (talvez melhor) seria fazer uma consulta ao banco apenas para recuperar a quantidade de itens: $numRows = $conn->query("SELECT COUNT(*) FROM tabela")->fetchColumn(); echo $numRows; Mas eu lhe dou uma terceira opção, que considero melhor: 1 - Antes do loop registramos a quantidade de itens já processados, no caso 0: $qtd = 0; 2 - Em cada iteração do loop, incrementamos 1 a essa variável: // dentro do loop: ++$qtd; Depois, verificamos se $qtd ainda é 0, pois isso significaria que o conjunto obtido pela consulta era vazio: if ( !$qtd ) { echo 'Nenhum registro encontrado.'; } Outro problema é que antes a conexão ao mysql era comumente utilizada de forma global como no seu código antigo, onde você chamava a função mysql_query. Perceba que com o PDO você precisa da variável $con, que você criou e que contém a conexão com o banco. Então precisamos passar a variável de conexão para dentro da função, uma vez que funções possuem um contexto fechado e desconhecem variáveis externas. Um exemplo disso seria inserindo o parâmetro na declaração da função. Seria assim: function montaSelect( $con ) { ... } // Agora chamamos: montaSelect( $con ); Mas observe que sempre que quisermos chamar a função montaSelect agora devemos enviar a variável pra dentro da função. Meio chato, né? Nesse caso podemos utilizar funções anônimas e explicitar o conhecimento global da conexão ao PDO. Ficaria assim: $montaSelect = function () use ( $con ) { ... } // Agora chamamos: $montaSelect(); Isso tudo desconsiderando orientação a objetos, que tornaria tudo mais profissional. Mas para um uso comum, rápido e prático deve servir :) Reunindo tudo, ficaria assim: $montaSelect = function () use ( $con ) { $sql = "SELECT * FROM membros"; $result = $con->query($sql); $qtd = 0; $opt = ''; while( $dados = $result->fetch( \PDO::FETCH_ASSOC ) ) { ++$qtd; $opt .= '<option value="'.$dados['id'].'">'.$dados['nome'].'</option>'; } if ( !$qtd ) { $opt = '<option value="0">Nenhum Membro cadastrado</option>'; } return $opt; }; echo $montaSelect(); -
Duvida sobre estrutura de return function
Matheus Tavares respondeu ao tópico de luiz monteiro em Javascript
Ops... me dei conta após postar que eu não respondi inteiramente sua pergunta. Perdoe minha falta de atenção. Ao invés de editar o post anterior, vou complementar: o ponto principal da sua dúvida deve estar girando em torno do retorno de uma função, mas não é tão difícil quanto parece. Imagine uma função qualquer, como a do meu exemplo acima. Você chama ela e ela geralmente retorna algum valor primitivo ou objeto. No caso a função debounce, que é muito utilizada no JS, junto com a throttle, com a implementação que você postou faz um setup e retorna uma função para ser a substituta da sua função original. O que quero dizer é que quando você chama a debounce, você envia a função que você quer aplicar o algoritmo de "atraso" da debounce junto à quantidade de tempo desejada e a função lhe retorna a nova função que você deve passar a chamar, ou seja, uma função "infectada". Como diria Linus, "Talk is cheap, show me the code". Então vamos à prática com um exemplo bobo, mas que deve servir: // Funcao original function numAleatorio( min, max ) { return parseInt( Math.random() * ( max - min ) + min ); } // Essa funcao pega uma função genérica que retorne um inteiro e soma 10 ao seu resultado // Simples, bobo, mas eficaz e reutilizável function adiciona10AoRetorno( umaFuncao ) { return function( ...args ) { return umaFuncao( ...args ) + 10; } } // Agora criamos uma função infectada: // Perceba que não executamos a função numAleatorio, senão teríamos mandado numAleatorio() // Enviamos apenas a referência dela, para ser utilizada posteriormente const aleatorioMais10 = adiciona10AoRetorno( numAleatorio ); // Agora chamamos sempre que quiser e o número sempre será MODIFICADO com a soma por 10: // Nesse exemplo enviamos minimo como 50 e maximo como 60, // mas o número retornado sempre fica entre 60 e 70 console.log( aleatorioMais10( 50, 60 ) ); No caso da debounce, você envia a função e depois fica com uma "debouncedMinhaFuncao", que é a nova função, infectada com o comportamento provido por debounce. Espero ter ajudado :) -
Duvida sobre estrutura de return function
Matheus Tavares respondeu ao tópico de luiz monteiro em Javascript
Olá! Isso chama-se Rest Parameters e serve para agrupar (em um array) um conjunto indeterminado e indefinido de parâmetros em uma variável para ser utilizado dentro da função. Um exemplo bem simples: function teste( ...args ) { console.log( args ); } // Chamamos a função enviando alguns parâmetros de teste teste( 'string', 2, 3.5, 'outra string' ); // Retorno: Array(4) [ "string", 2, 3.5, "outra string" ] -
Olá @JeffSalles, seja bem-vindo. Hoje é o seu dia de sorte! O PHP já possui a função que você quer implementar :) Chama-se levenshtein(). Veja como é simples usar ela: <?php $strOriginal = 'Apenas um teste'; $strDigitada = 'Axenas un test'; $qtdChars = strlen( $strOriginal ); $diferencas = levenshtein( $strOriginal, $strDigitada ); printf( "Diferenças: %d \nPercentual de acertos: %.2f%% \nPontuação: %.2f", $diferencas, ( ( $qtdChars - $diferencas ) / $qtdChars ) * 100, $diferencas * .05 ); Resultado: Diferenças: 3 Percentual de acertos: 80.00% Pontuação: 0.15
- 3 respostas
-
- escrevente
- comparar textos
- (e mais 5 )
-
Olá @Biel.. Desculpe, mas isso não faz sentido. Você não pode incluir um arquivo PHP de um servidor externo, e mesmo que mexesse no PHP.INI e bolasse alguma gambiarra habilitando o já obsoleto e inseguro allow_url_include, não impediria de o arquivo que inclui o php externo manipulá-lo de alguma forma (ou vice-versa). O mais correto e alinhado a boas práticas seria você configurar no banco de dados um usuário com acesso limitado, liberando apenas os recursos que você deseja, como a leitura dos dados por exemplo. Veja: https://docs.cluvio.com/hc/en-us/articles/115000968069-Creating-a-read-only-user-in-the-database
-
Olá @old-dev, seja bem-vindo. Depende inteiramente do propósito da sanitização que você busca promover no input. Existe esse leque de opções: https://www.php.net/manual/en/filter.filters.sanitize.php Para manter o uso do filter_input_array, você poderia utilizar a constante FILTER_SANITIZE_FULL_SPECIAL_CHARS, que é o que mais se aproxima do já obsoleto FILTER_SANITIZE_STRING e ajuda a proteger contra XSS, Mysql Injection e outros abusos. Outras opções seriam as funções htmlentities() e htmlspecialchars(). Sugiro ler esses materiais para entender melhor sobre eles: https://www.php.net/manual/pt_BR/filter.filters.sanitize.php https://www.php.net/manual/pt_BR/function.htmlentities https://www.php.net/manual/pt_BR/function.htmlspecialchars.php Esse material também é interessante: https://forum.imasters.com.br/topic/563187-resolvido-sql-inject-quando-não-dar-para-impedir/
-
Acessar imagem de Câmera IP (JavaScript)
Matheus Tavares respondeu ao tópico de Andre74 em Javascript
Olá, seja bem-vindo! Segundo esse artigo o suporte a credenciais em URLs de subrecursos foi desativado desde o Chrome 59 (estamos na versão 99 nesse momento). Você precisa ver se encontra dentro do seu servidor de Câmera IP uma forma alternativa para fazer a autenticação. Exemplo: http://192.168.15.119 /mjpg/video.mjpg?user=root&pwd=pass- 3 respostas
-
- câmera
- javascript
-
(e mais 1 )
Tags:
-
Linguagem plataforma R&S
Matheus Tavares respondeu ao tópico de fbrandao84 em Desenvolvimento frontend
Olá amigo, seja bem-vindo. O HTML e CSS é um excelente pontapé inicial, mas para fazer um sistema como o descrito no seu post você precisa aprender uma linguagem de programação para o back-end, que é onde a lógica e dados da sua aplicação trabalhariam. Você teria algumas opções como PHP, Node.js, Python, C#, Java, por exemplo. MInha sugestão é começar pelo PHP pelo vasto mercado de trabalho e conteúdo de estudos na internet, ou seja, popularidade da linguagem em geral. Você também vai precisar aprender um banco de dados, mas isso é bem tranquilo e caminha junto com a linguagem de programação. Recomendo o MariaDb/MySQL. Comece por tutoriais/cursos da linguagem em si e depois tente desenvolver pequenas aplicações para desafiar e cimentar seus conhecimentos.- 4 respostas
-
@Biel., tente utilizar localhost ao invés do IP externo da máquina. Existem configurações que podem impedir a conexão pelo IP externo por segurança e uma vez que seu código está rodando na mesma máquina que o banco de dados é o mesmo princípio de você testar na sua máquina de desenvolvimento, onde você utiliza "localhost".
-
MySQL pegar o primeiro registro sem 2 filhoa (parent)
Matheus Tavares respondeu ao tópico de arthursanno em MySQL
Aí que tá. Na primeira query que postei é exatamente isso que é feito também. Então, ao menos que essa query não lhe atenda por alguma razão ou esteja funcionando incorretamente, acredito que ela seja a melhor opção para você, levando em consideração que possui menos código e performa um pouco melhor (no seu fiddle dá para notar a diferença em ms na execução): SELECT * FROM pool p1 WHERE ( SELECT COUNT(1) FROM pool p2 WHERE p1.id = p2.idPai ) <= 1 LIMIT 1 Aqui retorna: #5 | 2 | "Pedro", assim como as demais consultas. O mesmo serve para a consulta que você elaborou. Ela é uma boa opção se retirarmos a primeira condição do WHERE, que eu acredito que esteja ali sem necessidade. Nesse caso teríamos isso, que é muito parecido com o que eu fiz, mas utilizando o IN/GROUP/HAVING como alternativas ao depenent subquery: SELECT * FROM pool a WHERE a.id IN ( SELECT idPai FROM pool WHERE id <> 1 GROUP BY idPai HAVING COUNT(*) < 2) ORDER BY id ASC LIMIT 1; Essa consulta gera o mesmo resultado também. Tudo certo. Entende onde eu quero chegar? Ao menos que eu não tenha entendido alguma coisa, acredito que essas consultas fazem o que você precisa, mas esse pequeno trecho é desnecessário e pode ser removido. Estou me referindo a isso aqui: [...] a.id > (select idPai from pool ORDER BY idPai DESC LIMIT 1) OR [...] Mas que bom que está resolvido. Você mesmo solucionou a questão :) -
MySQL pegar o primeiro registro sem 2 filhoa (parent)
Matheus Tavares respondeu ao tópico de arthursanno em MySQL
Pelo que entendi você está solicitando ao banco os pais com menos de 2 filhos (através da sua segunda subquery) e caso não existam, o último pai criado no sistema (sua primeira subquery), é isso? Dessa forma você teoricamente teria o pai apropriado para a inserção do próximo filho na árvore. Mas você ainda não está livre de cair na situação de todos os pais terem 2 filhos, inclusive o último pai (sua primeira subquery). Caso sua intenção seja de não permitir mais que 2 filhos, aqui haveria uma exceção, que provavelmente seria criar um pai virtual, por exemplo. Além disso, não tenho certeza, mas acredito que dessa forma sua consulta seria mais performática: SELECT * FROM pool p1 WHERE (SELECT COUNT(1) FROM pool p2 WHERE p1.id = p2.idPai) <= 1 OR id > (select idPai from pool ORDER BY idPai DESC LIMIT 1) ORDER BY id ASC LIMIT 1 Outra coisa que poderia ser feita é manter em cache a lista dos pais que ainda não possuem 2 filhos. Imagine essa sua segunda SUBQUERY: SELECT idPai FROM pool WHERE id <> 1 GROUP BY idPai HAVING COUNT(*) < 2 Basicamente ela faz isso: para todos os pais que não possuam ID 1, agrupe-os e remova os que possuirem 2 filhos ou mais. Perceba que essa consulta será repetida múltiplas vezes, sempre que você precisar consultar o banco. Sua consulta ficaria assim, se estes registros estivessem em cache: SELECT * FROM pool a WHERE a.id > (select idPai from pool ORDER BY idPai DESC LIMIT 1) OR a.id IN ( 3 ) ORDER BY id ASC LIMIT 1; Eu apenas copiei sua consulta e substitui a segunda SUBQUERY pelo id 3, que é o resultado da consulta quando executada. Isso você poderia fazer com MATERIALIZED VIEW ou cache a nível de aplicação (APCu por exemplo, se estivermos falando de PHP). De resto, acho que está tudo ok, mas iria sugerir de você popular melhor sua tabela para testar melhor sua consulta. Algo como uns 20 a 30 registros, pelo menos. Isso iria prover uma maior confiabilidade no desenvolvimento. -
MySQL pegar o primeiro registro sem 2 filhoa (parent)
Matheus Tavares respondeu ao tópico de arthursanno em MySQL
Olá! Caso você precise consultar quando não possui nenhum filho, no caso os IDS 4, 5 e 6, você poderia fazer assim: SELECT id FROM pool p1 WHERE NOT EXISTS ( SELECT idPai FROM pool p2 WHERE p1.id = p2.idPai ) Indo nessa lógica, para restringirmos para os registros que não possuem 2 filhos para casar com o ID 3, poderíamos fazer assim: SELECT id FROM pool p1 WHERE ( SELECT COUNT(1) FROM pool p2 WHERE p1.id = p2.idPai ) <= 1 LIMIT 1 Mas eu não acho que resolver esse tipo de questão diretamente no banco seja a melhor solução. Depende muito do que você precisa fazer. Outro detalhe é que do jeito que seu banco está estruturado nesse momento, problemas de performance futuros seriam inevitáveis. Para contornar isso você deve criar um índice/chave na coluna idPai. Há um exemplo de SQL aqui: https://forum.imasters.com.br/topic/562468-resolvido-estrutura-de-um-projeto-de-marketing-multinível-com-php-e-mysql/ -
Olá @Gimenez, tudo bem? Seja bem-vindo. Esse tipo de problema é comumente causado por diferenças em configurações do PHP (como a flag error_reporting, por ex) ou versões que você rodou no MAMP e no Xampp (PHP 7 vs PHP 5.6, por ex). Já usei Xampp ao desenvolver no Windows, assim como MAMP no Mac, mas hoje em dia recomendaria abandonar esse tipo de ferramenta e utilizar Docker, pois dessa forma você garante não apenas que sua aplicação seja igual ao mudar de sistema operacional / ambiente, como ainda garante que seja igual se comparado ao seu PC de desenvolvimento em relação ao servidor de produção. Dá menos dor de cabeça. Peço que poste o erro em questão e o trecho de código acusado pela mensagem de erro para podermos ajudar você :)
-
Olá @Biel., tudo bem? Não sei se era um requisito seguir o código que você já tinha, mas resolvi reescrevê-lo utilizando uma lógica diferente. Espero que sirva. 1 - Definimos os nomes das cores e suas respectivas quantidades: $cores = [ 'blue' => 5, 'green' => 8, 'red' => 3, 'orange' => 4, ]; 2 - Fazemos o loop principal, desmembrando o nome da cor da quantidade de vezes a exibi-la: foreach ( $cores as $cor => $qtd ) { 3 - Logo após fazemos o loop repetindo a cor x vezes, onde x = $qtd. for ( $j = 1 ; $j <= $qtd ; ++$j ) { Reunindo tudo e adicionando uma variável $j para contar as iterações gerais (1 a 20), ficaria assim: <?php $cores = [ 'blue' => 5, 'green' => 8, 'red' => 3, 'orange' => 4, ]; $i = 1; foreach ( $cores as $cor => $qtd ) { for ( $j = 1 ; $j <= $qtd ; ++$i, ++$j ) { echo "{$i}-{$cor}-{$j}\n"; } } Resultado: 1-blue-1 2-blue-2 3-blue-3 4-blue-4 5-blue-5 6-green-1 7-green-2 8-green-3 9-green-4 10-green-5 11-green-6 12-green-7 13-green-8 14-red-1 15-red-2 16-red-3 17-orange-1 18-orange-2 19-orange-3 20-orange-4 * No caso você iria provavelmente querer trocar \n por <br>, para quebrar as linhas em html.
-
Crontab - como executar mais de um script de uma só vez
Matheus Tavares respondeu ao tópico de biakelly em PHP
Hehe, que bom que deu certo! Acredito que esteja ok sim, apenas acho que você deveria rodar as crons em um servidor e não na sua máquina local. Na AWS você poderia rodar de graça por 1 ano inteiro essas crons (depois pode criar uma conta nova e aproveitar outro ano :P). Para isso você iria criar uma instância no EC2 chamado t2.micro, que possui 1gb de ram e 1 vCPU. https://aws.amazon.com/pt/ec2/instance-types/ Poderia ser manualmente pelo EC2 ou através do Elastic Beanstalk (que cria a máquina EC2 para você de forma automática e coloca seu código pra rodar). Vale a pena dar uma olhada nesses serviços. -
Olá @notax, tudo bem? Isso não faz sentido, meu amigo. Sua hospedagem não deve interferir nos seus arquivos JS, ao menos que seu código possua falhas de segurança ou códigos maliciosos que possam afetar os demais clientes, e ainda assim isso deve estar explicitamente descrito nos termos de uso dessa empresa. Pode usar window.location.href sim.
-
Crontab - como executar mais de um script de uma só vez
Matheus Tavares respondeu ao tópico de biakelly em PHP
Olá @biakelly, tudo bem? :) 1 - Geralmente você precisa reiniciar o servidor de cron para que suas alterações sejam efetivadas. Acho que no ubuntu você faz com o systemctl, então seria isso: systemctl restart *seu software de cron* Onde o software pode ser: cron, dcron, cronie, fcron, anacron. Eu particularmente uso o cronie na minha máquina e nunca tive problemas, mas já utilizei outras em máquinas com diferentes sistemas. O procedimento não é diferente. Você pode desinstalar sua implementação de cron e instalar uma nova para testar também. 2 - Utilize o comando crontab -e para fazer a definição das suas tarefas. crontab -l para listá-las. Você não deve precisar mais do que esses 2 comandos e a reinicialização do serviço. Veja: https://www.digitalocean.com/community/tutorials/how-to-use-cron-to-automate-tasks-ubuntu-1804-pt 3 - E por fim, a tarefa cron não deveria estar na sua máquina local, mas no seu servidor. Sua máquina é para desenvolvimento. Você deveria poder desligá-la e saber que suas tarefas continuam rodando. Quem deve fazer a execução dos scripts é o seu servidor. Se o seu servidor é cPanel, se não me engano geralmente há uma seção do painel destinada apenas para isso, de forma gráfica, sem necessidade de comandos de terminal. E você não deve usar o curl, pois ao fazer isso você cria uma requisição, e isso chama o servidor web, que torna tudo mais lento e consome mais recursos de máquina. Certa vez desenvolvi um sistema de disparo de e-mails que estava muito lento. Resolvi com algumas leves mudanças, mas a principal foi essa. Você deveria criar suas crons mais ou menos assim: */30 * * * * /usr/bin/php /home/bia/cronjobs/aquivo1.php > /home/bia/log_arquivo1.log * * * * * /usr/bin/php /home/bia/cronjobs/aquivo2.php > /home/bia/log_arquivo2.log * * * * * /usr/bin/php /home/bia/cronjobs/aquivo3.php > /home/bia/log_arquivo3.log * * * * * /usr/bin/php /home/bia/cronjobs/aquivo4.php > /home/bia/log_arquivo4.log * * * * * /usr/bin/php /home/bia/cronjobs/aquivo5.php > /home/bia/log_arquivo5.log Isso se for para rodar diretamente na sua máquina. Observe que /usr/bin/php é o caminho do binário do php. Você pode descobrir esse caminho rodando no seu terminal isso: which php. Daí você substitui pelo caminho que coloquei ali, que é o meu caso, mas pode ser diferente do seu. Em um cPanel o comando seria diferente e o caminho do seu arquivo php também. Perceba que defini um caminho para registro dos logs. Você deve verificar se esse arquivo está sendo criado. Se os arquivos de log estiverem sendo criados, sua cron está rodando, mas provavelmente está ocorrendo algum erro no seu PHP. Isso o log vai dizer. Lembre-se de que para o PHP exibir os erros, você precisa habilitá-los, com error_reporting( E_ALL ); Ao fazer isso >/dev/null 2>&1, você estava descartando os logs, que são importantes para verificar se tudo está rodando como esperado. -
Em tempo: citei o S3 também pela facilidade de uso. Veja como é simples fazer um upload pra lá: https://devcenter.heroku.com/articles/s3-upload-php
-
Fala @Omar~, tudo certo? Vamos lá: Mais ou menos. Pelo menos não de olhos fechados. Segurança para upload de arquivos é um assunto um pouco mais profundo. Não basta se preocupar com o mime do arquivo, pois ele é manipulável. Veja um exemplo (imagem png com código php/js embutido): https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/ Lembre-se de que camuflar arquivos maliciosos em arquivos aparentemente inofensivos não é exclusivo a aplicações web. Os anti-vírus estão há decadas criando soluções para evitar esse tipo de problema. A questão é: você se preocupa que um usuário baixe um vírus enviado anteriormente por um usuário, ou apenas se preocupa com a segurança de sua aplicação? Pois para o primeiro caso, eu iria sugerir que você rodasse em uma solução como no virustotal, por exemplo, mas isso seria no caso de permitir aos usuários que enviassem arquivos mais genéricos como zip, rar, 7zip, iso, exe, msi, gzip, tar, rpm, etc. É um ponto que não devemos ignorar, mas acredito que suas preocupações estejam na aplicação em si, então vamos prosseguir: Você não deve confiar no $_FILES, pois ele é literalmente informado pelo navegador, mas isso você já sabia. A partir do momento que você passa a utilizar o módulo Fileinfo (finfo), você transfere a responsabilidade de analisar o conteúdo do arquivo ao servidor, e isso promove sua aplicação de 10% de segurança para uns bons 50~60% de segurança (no que tange o upload dos arquivos). Você poderia ainda, no entanto, se preocupar com alguns pontos importantes: 1 - Não nomear os arquivos enviados com extensões sugeridas pelo nome original do arquivo. Exemplo do arquivo enviado: meu_arquivo.php.png Essa dupla extensão pode ser explorada através de Null byte injection ou mod_mime do PHP (que pode processar arquivos PHP com dupla extensão). Então vamos supor que você upou o arquivo com o nome acima. Caso o mod_mime não o ajude arbitrariamente, você poderia ainda assim processá-lo como PHP assim: http://site.com/uploads/meu_arquivo.php%00 Uma boa prática seria aplicar um UUID e uma tabela de extensões. Exemplo: Mime: image/jpeg Arquivo: 123e4567-e89b-12d3-a456-426614174000.jpg Perceba que .jpg não é por causa do nome original do arquivo, mas pq eu inferi através do mime. Isso você faria com um array associativo de mimes/extensões, por exemplo. Caso você não queira modificar o nome do arquivo, não tem problema, mas não permita caracteres fora do range do alfabeto, números e alguns poucos caracteres como underscore "_" ----> [a-zA-Z0-9_-] Isso já iria automaticamente remover as extensões, uma vez que você estaria removendo os pontos. Por algum tempo em uma aplicação eu literalmente não aplicava extensão nenhuma nos arquivos. Os arquivos tinham nomes assim: 8ats9d786astn9d8 8nyda08f7tn2h98z ... Eu fazia isso em uma CDN onde eu informava o mime/type na resposta da requisição, nunca gerando problemas para acessá-los. Mas quis apenas compartilhar mesmo, pois não é uma boa prática. Deixei de fazer isso depois que tive problemas de cache por parte da Cloudflare, que não reconhecia os arquivos corretamente. Apenas não confie na extensão que o usuário informa, mas aplique uma extensão coerente ao conteúdo do arquivo, baseada no MIME. 2 - Bom, mime verificado, extensão não influenciada, o próximo passo é pensarmos: qual o real risco para a minha aplicação se alguém enviar um arquivo contendo códigos que possa ser interpretado pelo servidor? O risco são na verdade dois: - LFI, ou Local File Inclusion. É quando temos inclusões variáveis com dados originados na requisição, como nesse exemplo: <?php $pagina = $_GET[ 'pag' ]; include( "paginas/{$pagina}.php" ); Daí você acessa o site assim: http://site.com/?pag=../../../../../etc/passwd%00 Ou: http://site.com/?pag=../uploads/arquivo_que_acabei_de_enviar Isso é facilmente corrigido filtrando a string $pagina, mas você sabe disso. - O outro caso seria de literalmente acessarmos o arquivo como no exemplo do primeiro link que citei nesse post: http://example.org/images/test.png?zz=alert("this is xss :("); Observe neste exemplo que o arquivo chamado é o próprio enviado, e ele inclusive é um png, mas com PHP injetado. Isso poderia ser evitado, mesmo com um png malicioso, desativando a execução do PHP nesse diretório, o que torna todo aquele esforço do artigo sem sentido, entende? É aí que vamos diminuindo drasticamente os riscos de brechas de segurança. Isso poderia ser feito criando um .htaccess (falando de Apache. Outros webservers = outras soluções) no diretório com o seguinte conteúdo: php_flag engine off Veja mais: http://docs.php.net/manual/en/apache.configuration.php#ini.engine Em muitos artigos você vai encontrar as seguinte sugestões ainda, que se você analisar com calma, vai perceber que são apenas redundâncias para as medidas que já citei acima (mas é bom lembrar que redundância em segurança não é nada ruim!): Varrer o arquivo para verificar se possui abertura de tags PHP "<?", mas acho um método muito falho, pois é abrangente demais e pode acabar gerando falsos-positivos. Reprocessar as imagens usando GD ou imagick. Também não é uma solução absoluta, pois podemos ter comentários e metadados em arquivos de imagens que podem ser explorados com a finalidade de injetar códigos maliciosos, mas ajuda, principalmente se você chamar essas funções habilitando configurações de compressão e remoção de lixo. A questão é que isso só é válido para imagens, o que não é o seu caso. Criar uma espécie de pequeno web firewall, onde você colocaria seus arquivos em uma pasta absolutamente fora de public e os traria apenas quando solicitado, manualmente, via código PHP, com readfile, por exemplo. Na minha opinião, um grande desperdício de recursos de máquina e tempo de programação em cima disso, mas não deixa de ter o seu valor. Ler o cabeçalho do arquivo (primeiros ~20 bytes) e comparar com a tabela Magic, mas isso é exatamente o que o Fileinfo faz. Você estaria sendo redundante e perdendo tempo com algo que não deveria ser uma preocupação sua. Mas o mais importante eu guardei para a conclusão: não salve os arquivos no mesmo servidor que processa a lógica da aplicação! Por diversas razões, e não apenas por segurança. Você desacopla seu código (lógica) de dados de execução, o que é um grande avanço para aplicações escaláveis (que podem crescer indefinidamente em quantidade de máquinas), uma vez que os acessos aos arquivos agora seriam apenas urls externas de servidores que apenas entregam arquivos, e não arquivos armazenados na mesma máquina. Exemplo: http://site.com.br/uploads/arquivo.xls Agora seria: http://arquivos.site.com.br/arquivo.xls Perceba que arquivos.site.com.br não é apenas um subdomínio ou redirecionamento, mas um servidor à parte, que pode ser universalmente utilizado por todas as máquinas. E como você faria isso? É muito difícil? Muito caro? Fácil e barato: S3 + Cloudflare. Custos do S3: https://aws.amazon.com/pt/s3/pricing/ Cloudflare pode ser o plano gratuito. Citei o S3 pois estou mais acostumado, mas tem ainda as soluções da Microsoft (Azure), Google Cloud Computing, e aquele outro que tem nome de Pokémon, mas não lembro agora =P Basta mandar os arquivos para o S3 e depois aplicar o cache pela Cloudflare. Isso garantirá custos baixos de tráfego se os arquivos não forem muito grandes e estiverem dentro da cota de cache da Cloudflare. Digo isso pois manter os arquivos na S3 é barato, mas o custo do tráfego pode surpreender dependendo do seu uso. Por isso a cloudflare ajuda (e muito). Resumindo: Fileinfo, junto a boas práticas para evitar vulnerabilidades no upload vão te dar uma confiabilidade altíssima, mas construir uma pequena CDN e mandar arquivos para serem servidos por ela leva seu app a outro nível com muito mais facilidade :)
-
Erro: Cannot modify header information - headers already sent by
Matheus Tavares respondeu ao tópico de Sapinn em PHP
Em tempo... preciso chamar atenção para essa função: header("Location: ".URL.DIRECTORY_SEPARATOR.$url); A constante DIRECTORY_SEPARATOR é para ser substituida por barra / (notação Unix) ou contra-barra \ (notação Windows), de acordo com o sistema do servidor. Exemplo: Caminho no Linux: /home/sapinn/Downloads/arquivo.pdf Caminho no Win: C:\Users\sapinn\Downloads\arquivo.pdf Perceba que não tem relação com URL, onde sempre utilizamos a barra normal, exemplo: google.com/link-qualquer. Portanto, assim seria mais correto: header('Location: ' . URL . '/' . $url); E por fim, você deve inserir um exit() logo após a linha do header, pois dificilmente iria querer que seu código PHP continuasse sendo executado após uma declaração de redirecionamento. Isso é importante. header('Location: ' . URL . '/' . $url); exit(); -
Erro: Cannot modify header information - headers already sent by
Matheus Tavares respondeu ao tópico de Sapinn em PHP
Olá @Sapinn. Muito provavelmente você possui um desses cenários: 1 - Algum(ns) arquivo(s) com codificação UTF-8 BOM (byte-order mark). Preferencialmente seus arquivos devem estar em UTF-8. Essa print é no Notepad++, onde você pode fazer a remoção do BOM com facilidade. ANSI também é aceitável. Se o seu arquivo estiver em ANSI, mantenha-o assim para evitar problemas com acentos. 2 - Alguma quebra de linha após um fechamento de tag ?>. No PHP, a tag de fechamento ?> é opcional, ou seja, se você não deseja inserir nenhum HTML após o PHP, basta finalizar suas linhas de código e omitir o fechamento. Por que isso seria uma boa prática? Porque evita que seu código envie à resposta caracteres indesejados. Veja um exemplo: <?php class MinhaClasse { } ?> *aqui é onde pode ter caracteres invisíveis desnecessários* Seus arquivos podem perfeitamente ser escritos assim: <?php class MinhaClasse { } 3 - Alguma saída, caractere, quebra de linha ou chamada de funções como echo, imagejpeg, printf, print_r, etc... É com bastante confiança que afirmo que o warning que você está recebendo seja oriundo de um desses fatores. Aqui é discutido em mais detalhes essa questão: https://pt.stackoverflow.com/questions/4251/erro-cannot-modify-header-information-headers-already-sent -
Erro: Cannot modify header information - headers already sent by
Matheus Tavares respondeu ao tópico de Sapinn em PHP
Olá @Sapinn. Você não pode chamar a session_start() depois de ter escrito alguma coisa na resposta. Certifique-se de não ter quebras de linha, html, echos e coisas assim no código que antecede o session_start. Se você não encontrar nada de anormal, peço que poste exatamente a linha e o trecho do seu código apontado pela mensagem de erro, para lhe ajudar. -
Olá @Marcos Vinícius. Sim, seria exatamente como você descreveu. No entanto, embora eu não seja estatístico, não vejo muita utilidade na soma das médias. Talvez eu esteja enganado, mas acredito que você queira a média entre todas as médias, e isso você poderia conseguir assim: $qtd = 0; $soma = 0; while($dados = mysqli_fetch_array($resultado)){ $valor = $dados["valor"]; $dias = $dados["dias"]; $perc = $valor / $dias; $soma += $perc; ++$qtd; } echo $soma / $qtd;// média entre as médias
-
Imagina, @biakelly, ninguém nasce sabendo. :P Lembrando que bcmul é apenas uma multiplicação como qualquer outra, com duas diferenças-chave: 1 - Ele vai permitir definir a escala, ou seja, quantos dígitos eu gostaria de visualizar. Exemplo: <?php $precototal = '0.002822102460892938'; $totalemitido = '10,454,760.506412'; $precototal = str_replace( ',', '', $precototal ); $totalemitido = str_replace( ',', '', $totalemitido ); echo $precototal * $totalemitido; echo "\n"; echo bcmul( $precototal, $totalemitido, 25 ); Saída: 29504.405353192 29504.4053531916039105945184560 2 - Ele vai ser mais preciso do que as operações comuns. https://www.php.net/manual/pt_BR/language.types.float.php https://www.leaseweb.com/labs/2013/06/the-php-floating-point-precision-is-wrong-by-default/ Principalmente falando de dinheiro, você sempre vai querer utilizar funções com precisão, como as da biblioteca BCMath ou gmp.