String confusion 1) OR in if cond. and strtolower not lowering - php

Trying to convert times such as - 215pm or 2:15 am or whatever to a 14:15 or 02:15 type string. (I am NOT using a TIME format for reasons to tedious to go into.)
Have managed to get an array output that contains hours, minutes and am/pm (but only if characters are present).
I want to allow erroneous characters through so I can EXPLICITLY fire an error message but a) I cannot get a "simple" OR test to work and b) strtolower is not working for me - I don't know why.
$hour= $matches['h'];
$minute=$matches['m'];
if(!array_key_exists('ap', $matches)){$matches ['ap'] ="am";};
$ampm=$matches['ap'];
strtolower ($ampm);
debug ($hour,"hr");
debug ($minute,"min");
debug ($ampm,"ampm");
if ($ampm=="am" or $ampm=="pm") {echo "fine";}; // ALWAYS TRUE
if ($ampm==="am" or $ampm==="pm") {echo "fine";}; // FAILS WITH UPPER CASE AM AND PM
if ($hour<12 and $ampm=="pm") {$hour = $hour+12;};
debug ($hour,"hr");
debug ($minute,"min");
debug ($ampm,"ampm");
So I do not understand why the simple string test $ampm=="am" or $ampm=="pm" is always true but that is just academic. But I REALLY do not understand why strtolower does not change "AM" to "am" so that I cannot even use a === congruence test.
Any thoughts?

Simple mistake in your code. Change:
strtolower ($ampm);
To:
$ampm = strtolower ($ampm);

Do this to replace the variable:
$ampm = strtolower($ampm);
Also, $ampm is always true because the condition says
"if it is am, it is true OR if it is pm, it is true"
so what you want to do is:
if(isset($ampm) && $ampm === "am")
{
//its am
} else if(isset($ampm) && $ampm === "pm")
{
//its pm
} else
{
//its neither
}

Related

How to validate time string in hh:mm using preg match?

Below are the following possiblities. Time is for 12 hours
Inputs Output should as
"05:30" True
"asasds" FALSE
"05:30:sads" FALSE
"ADAS:05:40" FALSE
"04:30:40" FALSE
Below is the code that I wrote,
$value = "05:30" ;
if(!preg_match("/(1[012]|0[0-9]):([0-5][0-9])/", $value)){
echo "failed"; exit;
}
echo "passed"; exit;
But it prints as passed if I give the $value = "05:30:asdsa". However I need the output to be "failed".
Use anchors to match the start and the end, e.g.
!preg_match("/^(1[012]|0[0-9]):([0-5][0-9])$/", $value)
//^ See here ^
I just coded it for myself some minutes ago. It is basically controlling that is between 00:00 and 23:59
edit
preg_match("/(0?\d|1\d|2[0-3]):[0-5]\d/", $line, $matches_time);
You need to be sure that 25:30 is not valid. 24:00 is not valid but 00:00 is valid.
this code can make it perfect:
$string='00:34';
$pattern='%^([0-1][0-9])|([2][0-3]):[0-5][0-9]$%';
if(preg_match($pattern,$string))
echo '<b>'.$string.'</b> is a valid time in 24 hours format';
If you want to check only 12 hours format, you can use this one:
$string='09:24';
$pattern='%^([0][0-9])|([1][0-2]):[0-5][0-9]$%';
if(preg_match($pattern,$string))
echo '<b>'.$string.'</b> is a valid time in 12 hours format';

Check whether day is specified in a date string

Test case scenario - User clicks on one of two links: 2012/10, or 2012/10/15.
I need to know whether the DAY is specified within the link. I am already stripping the rest of the link (except above) out of my URL, am I am passing the value to an AJAX request to change days on an archive page.
I can do this in either JS or PHP - is checking against the regex /\d{4}\/\d{2}\/\d{2}/ the only approach to seeing if the day was specified or not?
You can also do this if you always get this format: 2012/10 or 2012/10/15
if( str.split("/").length == 3 ) { }
But than there is no guaranty it will be numbers. If you want to be sure they are numbers you do need that kind of regex to match the String.
You could explode the date by the "/" delimiter, then count the items:
$str = "2012/10";
$str2 = "2012/10/5";
echo count(explode("/", $str)); // 2
echo count(explode("/", $str2)); // 3
Or, turn it into a function:
<?php
function getDateParts($date) {
$date = explode("/", $date);
$y = !empty($date[0]) ? $date[0] : date("Y");
$m = !empty($date[1]) ? $date[1] : date("m");
$d = !empty($date[2]) ? $date[2] : date("d");
return array($y, $m, $d);
}
?>
I would personally use a regex, it is a great way of testing this sort of thing. Alternatively, you can split/implode the string on /, you will have an array of 3 strings (hopefully) which you can then test. I'd probably use that technique if I was going to do work with it later.
The easiest and fastest way is to check the length of the string!
In fact, you need to distinguish between: yyyy/mm/dd (which is 10 characters long) and yyyy/mm (which is 7 characters).
if(strlen($str) > 7) {
// Contains day
}
else {
// Does not contain day
}
This will work EVEN if you do not use leading zeros!
In fact:
2013/7/6 -> 8 characters (> 7 -> success)
2013/7 -> 6 characters (< 7 -> success)
This is certainly the fastest code too, as it does not require PHP to iterate over the whole string (as using explode() does).

Regex matching a date and time

I'm trying to match a specific datetime format in PHP's regex:
dd-mm-YYYY HH:ii:ss
It should always be in that format. Meaning that for example when it is the first day of the month there must be a leading zero. E.g.:
01-01-2013 01:01:01
I tried it with the following pattern:
^[0-12]{2}-[0-31]{2}-[0-9]{4} [0-23]{2}:[0-59]{2}:[0-59]{2}$
But the above pattern fails on timestamps like: 09-05-2013 19:45:10.
http://rubular.com/r/eGBAhwiNCR
I understand this may not be the correct approach to validate a date time like this, but I really want to know what is wrong with the above.
[0-12]{2} matches not the numbers 0 till 12. Instead it's a character class allowing 0 to 1 and also the number 2. The subsequent quantifier just allows the repetition of those, meanding 0,1 or 2 repeated two times.
Your other placeholders follow the same non-functioning scheme.
It's best to resort to \d{2} or \d{4} if you can't google a better regex. Even better yet, just use DateTime to verify the format.
The problem is when you are checking the "ranges", for example [0-12] at the beginning. That is a character class, and it is telling the regex to match 0 through 1, and then 2. So if you added more numbers in after the 1st one, it isn't working as you are expecting. Changing your regex slightly (focused on the [0-12] initial), [0-319]{2}-[0-12]{2}-[0-9]{4} [0-23]{2}:[0-59]{2}:[0-59]{2}$, would match 09-01-2011 11:11:10.
Ensuring there are valid numbers for each of those spaces requires a little thinking outside the box. The regex:
(0[1-9]|[12][\d]|3[0-2])-(0[1-9]|1[0-2])-[\d]{4} (0[1-9]|1[\d]|2[0-3]):(0[1-9]|[1-5][\d]):(0[1-9]|[1-5][\d])$
will work for what you are expecting with the regex you attempted.
If you break it down into smaller pieces it makes sense (it looks really scary at the beginning). Looking at the first piece (0-31 for "days").
(0[1-9]|[12][\d]|3[0-2])
This is using an or to handle 3 different cases.
0[1-9] - a zero followed by any number between 1-9. We don't want [0-9]{2} since that will allow numbers like 00. So a number is valid if it starts with 0 and has any other number after it (for single digit days).
[12][\d] - a 1 or 2 followed by any digit. This allows the numbers 10-29 to be valid.
3[0-2] - a 3 followed by anything 0 through 2 matching 30, 31, and 32.
Broken down, it's not too bad but this pattern is then carried out for each "field" in your date. So this regex validates on each field being valid... but a better way to confirm valid dates maybe needed. This doesn't get into the complexity of checking if you can have 30-02 for example, where February doesn't have 30 days.
^[0-9]{2}-[0-9]{2}-[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2}$
The example of validation is in php but the regex is standard
/*pass the date you wanna validate as parameter to the function.
The function returns true if it is valid and false if the date passed is not valid
*/
function DateValid($date){
//format will be fr if the date is in french format and en if the date is in en format
$format='';
//regex that tests if the date is in french format or english, if not in one of these two then it is not valid
if(preg_match("#^(\d{1,2})[\-./ ](\d{1,2})[\-./ ](\d{4})(?: (\d{1,2})(?:[ .-](\d{1,2})){1,2})?$#",$date,$m)){
$format='fr';
}elseif (preg_match('#^(\d{4})[-. ](\d{1,2})[-. ](\d{1,2})(?: (\d{1,2})(?:[ .-](\d{1,2})){1,2})?$#', $date, $m)) {
$format='en';
}else{
echo '<p style="font-size:150px">not english nor french</p>';
return false;
}
//If it is french format or English then check if the date is correct
if($format=='fr'){
if (checkdate($m[2], $m[1], $m[3]) == false || $m[4] >= 24 || $m[5] >= 60 || $m[6] >= 60) {
echo '<p style="font-size:150px">Not valid french</p>';
return false;
}else{
echo '<p style="font-size:150px">Valid french</p>';
return true;
}
}elseif($format=='en'){
if (checkdate($m[2], $m[3], $m[1]) == false || $m[4] >= 24 || $m[5] >= 60 || $m[6] >= 60) {
echo '<p style="font-size:150px">Not valid english</p>';
return false;
}else{
echo '<p style="font-size:150px">Valid english</p>';
return true;
}
}
}

unable to determine if a string is currently an integer or not

The following funciton drove me nuts. How on earth 100x could be equal to 100 and then 100x is reported as an integer?
For the life of me, I cannot figure it out.
You can copy and paste the whole thing and see it for yourself.
I'm missing a simple point somewhere here, help me out guys.
function blp_int($val) {
$orgval = $val;
$num = (int)$val;
echo "<li><font color=red>val: ". $val . " is being checked to see if it's an integer or not";
echo "<li><font color=red>orgval: ". $orgval ;
echo "<li><font color=red>num: ". $num ;
if ($orgval==$num) {
echo "<li><font color=red><b>YES IT IS! the [{$orgval}] is equal to [{$num}]</b>";
return true;
}
return false;
}
if (blp_int("100"))
{
echo "<h1>100 is an integer!</h1>";
}
else
{
echo "<h1>100 is NOT an integer!</h1>";
}
if (blp_int("100x"))
{
echo "<h1>100x is an integer!</h1>";
}
else
{
echo "<h1>100x is NOT an integer!</h1>";
}
the above code, when run returns the following;
val: 100 is being checked to see if it's an integer or not
orgval: 100
num: 100
YES IT IS. the [100] is equal to [100]
100 is an integer!
val: 100x is being checked to see if it's an integer or not
orgval: 100x
num: 100
YES IT IS. the [100x] is equal to [100]
100x is an integer!
I can remedy the situation by adding the following bits
if (!is_numeric($val))
{
return false;
}
to the top of the blp_int function right off the bat but,.. I'm still super curious to find out why on earth php thinks 100x=100 are equals.
As you can see in this example, casting 100x as an integer converts it to 100. Since you are not using strict comparison, '100x' == 100 is true. PHP removes the x from it to make just 100.
You could use strict comparison (which also compares the types), such that '100x' === 100 would return false. Using it, any time a string was compared to an integer, it would return false.
As per your edit: is_numeric may not be the most reliable, as it will return true for numbers formatted as a string, such as '100'. If you want the number to be an integer (and never a string), you could use is_integer instead. I'm not quite sure what exactly you're doing, but i thought I'd add this note.
I think you should use three equal signs in your IF:
if ($orgval===$num) {
Otherwise PHP casts the value 100x to 100 and 100=100.
Documentation: Comparison Operators
What kind of check do you want to do? There are a few ways you could go about it:
if (preg_match('!^[0-9]+$!', $input))
if (intval($input) == $input)
if (intval($input) === $input)
if ('x'.intval($input) === 'x'.$input)
It depends on how closely you want to check if it's an integer. Does it matter if you need to trim() it first?
Either cast it to an int or try http://php.net/manual/en/function.ctype-digit.php. You also need === in your if.

PHP validation question

How do I check and see if a user enters only numbers and is at least 4 numbers long using PHP?
Mark Byers' suggestion is good, but here's another way:
$valid = ctype_digit($number) && strlen($number) >= 4;
You could use a regular expression:
/^\d{4,}$/
Example usage:
$s = "7325";
if (preg_match('/^\d{4,}$/', $s)) {
echo "matches";
}
ctype_digit() && strlen() wins
<?php
function benchmark($callback){
echo sprintf('%-30s: ', $callback);
$t = microtime(true);
foreach(range(1, 10000) as $n){
call_user_func($callback);
}
echo (microtime(true)-$t)."\n";
}
function mark_byers_preg_match(){
$s = "7325";
preg_match('/^\d{4,}$/', $s);
}
function notjim_ctype_digit_strlen(){
$number = 7325;
ctype_digit($number) && strlen($number) >= 4;
}
function tomalak_intval_broken(){
$check = 7325;
intval($check) == $check && $check >= 1000 && $check <= 9999;
}
benchmark('mark_byers_preg_match');
benchmark('notjim_ctype_digit_strlen');
benchmark('tomalak_intval_broken');
?>
results
mark_byers_preg_match : 0.029040098190308
notjim_ctype_digit_strlen : 0.026585817337036
tomalak_intval_broken : 0.019872903823853
Note: #Tomalak's does not work with numbers starting with 0 so it does not qualify
Edit: #kiethjgrant's solution was removed because intval(0000) evaluates as false when it should be true.
Do you have any example code to start with?
To strictly answer your question, you could use a regex like if(preg_match('/^\d{4,}$/', $input)....
But there's a lot more to consider here: you need to consider both validation and filtering (and you're best to keep the two separate issues). If you're strictly checking for an integer, then I suppose you're safe from SQL injection, XSS, etc., but you really need to have a handle on those issues, because sooner or later you're going to need to filter & validate something other than a simple integer.
you should always use the most efficient way to do it
if ( is_numeric($imput) && isset($input[3]) )
{
// your code
}
isset() is a language construct, which is always faster than strlen().
isset($input[n-1]) tells you whether string(data which passes through form is always string) has at least n long.
is_numeric() checks it is a valid num string.
i think it is better than ctype_digit() && strlen().

Categories