Stack Overflow em Português Asked by gustavox on January 31, 2021
Estou tentando validar um campo de horário em PHP, e com a ajuda deste tópico num site externo cheguei a este script:
function validaHoras($campo){
if (preg_match('/^[0-9]{2}:[0-9]{2}$/', $campo)) {
$horas = substr($campo, 0, 2);
$minutos = substr($campo, 3, 2);
if (($horas > "23") OR ($minutos > "59")) {
$campo = false;
}
}
}
O input
deve receber o campo no formato ’00:00′, mas não tem validação em JS, e o usuário pode entrar com um horário inválido.
Então o que quero é mudar o valor da variável para false
quando vier com um horário errado (tipo 99:99), mas não está funcionando. Testando o script abaixo com o input
99:99, o valor da variável não é alterado…
function validaHoras($campo){
if (preg_match('/^[0-9]{2}:[0-9]{2}$/', $campo)) {
$horas = substr($campo, 0, 2);
$minutos = substr($campo, 3, 2);
if (($horas > "23") OR ($minutos > "59")) {
$campo = false;
}
}
}
// SEGUNDA
$val1 = isset($_POST["Tsegs"]) && !empty($_POST["Tsegs"]) ? $_POST["Tsegs"] : false;
validaHoras($val1);
echo $val1;
//saida: 99:99
//saida desejada: false
Segue um "protótipo" bem sucinto, usando o mais básico do básico, que é validação com if
.
(sem precisar de RegEx, conversões ou mesmo de operações modificando string)
function pareceHora($str)
{
return strlen($str) == 5
&& $str[2] == ':'
&& $str[0] >= '0' && $str[0] <= '2'
&& $str[1] >= '0' && $str[1] <= ($str[0]=='2'?'3':'9')
&& $str[3] >= '0' && $str[3] <= '5'
&& $str[4] >= '0' && $str[4] <= '9';
}
Veja funcionando: IDEONE
A sintaxe $string[n]
acessa o byte de numero n
da string diretamente
na 3ª linha nos certificamos do tamanho ser 5 caracteres
na 4ª de ter :
no meio
na 5ª e 6ª linhas verificamos a hora entre 00 e 23, usando comparação ASCII. É feito um dígito por vez para que uma string '1A' não seja considerada válida (se testássemos '00' a '23' daria estes efeitos colaterais)
na 7ª e 8ª linhas é a mesma coisa, só que para os minutos.
Desta forma, validamos os 5 caracteres da string completamente (faixa e forma) com operações básicas e eficientes.
Answered by Bacco on January 31, 2021
Se você estiver considerando horas apenas de 00:00
e 23:59
, você pode utilizar simplesmente o método DateTime::createFromFormat
ou a função, que é o apelido para esta primeira, date_create_from_format
Assim:
date_create_from_format('!H:i', $valor);
Se retornar DateTime
, é um valor válido. Se retornar false
, é inválido.
Porém temos um problema aqui. Essa função aceita valores como 24:99
como hora válida, convertendo seus valores para horas corretas quando passados. No caso de 24:99
, seria convertido para 1970-01-02 01:39:00
.
Para contornar isso, poderíamos usar a função que cria a data a partir do formato e depois, usando o mesmo formato para a saída, comparar com o valor de entrada.
Veja:
function validar_hora($hora)
{
$formato = 'H:i';
$data = date_create_from_format('!'. $formato, $hora);
return $data && $data->format($formato) === $hora;
}
validar_hora('23:55'); // true
validar_hora('24:00'); // false
Isso ocorre porque:
Ao aplicar 'H:i'
em '24:00'
é convertido para '1970-01-02 00:00:00'
, que é convertido para 00:00
ao chamar 'H:i'
para formatá-lo.
No caso de '23:55'
, é convertido para '1970-01-01 23:55:00'
, que é convertido para '23:55'
ao chamar format
.
Veja funcionando no IDEONE.
Essa é uma solução alternativa se não quiser utilizar REGEX.
Nota:: O
!
, conforme a documentação, redefine todos os campos para a "época" Unix (1970-01-01)
Ainda pensando numa solução que gaste menos linhas do que a primeira que apresentei, apliquei os "mesmos fundamentos" às funções date
e strtotime
. A função strtotime
converte uma string
para timestamp. Já a função date
retorna a data formatada a partir do timestamp
, quando passado o segundo parâmetro.
Podemos fazer dessa forma:
function validar_hora($hora)
{
return date('H:i', strtotime($hora)) == $hora;
}
Answered by Wallace Maxters on January 31, 2021
Uma opção com sanitização.
A rotina sanitiza a entrada do usuário, removendo tudo que não for número, porém, preserva o caracter :
.
Converte também caracteres numéricos full-width (zenkaku) e aceita hora e minuto com 1 dígito. Exemplo: 1:10, 1:6 (01:10, 01:06)
A sanitização torna a validação mais amigável ao usuário.
function numbers_only($str, $exception = '')
{
return preg_replace('#[^0-9'.$exception.']#', '', mb_convert_kana($str, 'n'));
}
function valid_hour($n)
{
$n = str_replace(':', ':', $n);
$n = numbers_only($n, ':');
$arr = explode(':', $n);
if (count($arr) == 2) {
$h = intval($arr[0]);
$m = intval($arr[1]);
if ($h <= 23 && $h >= 0 && $m <= 59 && $m >= 0) {
return str_pad($h, 2, '0', STR_PAD_LEFT).':'.str_pad($m, 2, '0', STR_PAD_LEFT);
}
}
return false;
}
$str[0] = '0000'; // (inválido pois é necessário o separador : )
$str[1] = '00:09'; // caracteres zenkaku (válido)
$str[2] = '00:00'; // (válido)
$str[3] = '0:06'; // (válido)
$str[4] = '0:0'; // (válido)
$str[5] = '00:0'; // (válido)
$str[6] = '01:60'; // (inválido pois os minutos ultrapassaram o limite)
$str[7] = '01:6.'; // (válido, pois o ponto no final é removido na sanitização)
/*
Quando for inválido, retorna booleano false.
Quando for válido, retorna a string do usuário sanitizada e formatada como hh:mm, mesmo que o usuário insira apenas 1 dígito para hora ou minuto.
*/
var_dump(valid_hour($str[7]));
Answered by Daniel Omine on January 31, 2021
É possível validar o formato e o contéudo somente com expressões regulares caso deseje. ^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])
.
^(0[0-9]|1[0-9]|2[0-3])
=> O primeiro grupo captura a hora no formato (00-23) ele define três tipos 'categorias' a primeira indentifica valores de 00 a 09, o segundo de 10 a 19 e o último de 20 até 23.
([0-5][0-9])
=> O segundo grupo cobre os minutos que tem um lógica um pouco diferente das horas. Captura um dígito que pode estar entre zero e cinco e outro que pode estar entre zero e nove, o que cobre 00 a 59
function validaHoras($campo){
return preg_match('/^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])/', $campo) ? $campo : false;
}
$arr = array('00:00', '19:59', '20:34', '24:33', '28:64', '07:59', '000:30', '30:50');
foreach($arr as $item) var_dump(validaHoras($item)) .'<br>';
Answered by rray on January 31, 2021
Há um equivoco na chamada da função validaHoras, ela está passando o parametro mas não retorna retorna nada após a execução. A variavel que você imprime é a mesma que você passsa como parametro (por valor), ela não vai sofrer alteração. Tente assim:
<?php
function validaHoras($campo){
if (preg_match('/^[0-9]{2}:[0-9]{2}$/', $campo)) {
$horas = substr($campo, 0, 2);
$minutos = substr($campo, 3, 2);
if (($horas > "23") OR ($minutos > "59")) {
return false;
}
return true;
}
return false;
}
// SEGUNDA
$val1 = isset($_POST["Tsegs"]) && !empty($_POST["Tsegs"]) ? $_POST["Tsegs"] : false;
if(validaHoras($val1) === true){
echo 'hora valida ' . $val1;
}else {
echo 'hora invalida ' . $val1;
}
Answered by Juven_v on January 31, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP