Check if string is a comma-separated list of digits - php

In my table1 i have varchar field where i store an id-list of other table2 (id - INT UNSIGNED AUTOINCREMENT), separated by comma.
For example: 1,3,5,12,90
Also ids should not be repeated.
I need to check if a string (coming from outside) matches this rule.
For example i need to check $_POST['id_list']
Data consistency is not important for now (for example insert this value without checking if this ids really exist in table2)
Any advice will be helpful.

The easiest way to do such check is to use regular expression (preg_match).
Lets try to find a pattern matching our rule.
Just comma-separated digits:
^[0-9]+(,[0-9]*)*$
^ - means start of string.
$ - means end of string.
[0-9]+ - means that our string MUST starts with a digits.
(,[0-9]+)* - means that our string CAN continue itself with ",$someDigits" manner, from 0 to as many you wish times.
But if our digits are "INT UNSIGNED AUTOINCREMENT" we should modify our pattern this way:
^[1-9][0-9]*(,[1-9][0-9]+)*$
to exclude cases like: 0,01,02,009,000,012
As for unique values, i think more clear will be to use splitting (explode) string by comma to array, pass it through array_unique and compare.
So the result check-function will be:
function isComaSeparatedIds($string, $allowEmpty = false) {
if ($allowEmpty AND $string === '') {
return true;
}
if (!preg_match('#^[1-9][0-9]*(,[1-9][0-9]*)*$#', $string)) {
return false;
}
$idsArray = explode(',', $string);
return count($idsArray) == count(array_unique($idsArray));
}
Also added $allowEmpty argument if u would like to allow empty strings.

For the sake of completeness I would like to mention the following solution:
<?php
$check = explode(',', $string);
if ($diff = array_diff_key($check, array_filter($check, 'ctype_digit'))) {
// at least one is not a digit
foreach ($diff as $failIndex => $failValue) {
// handle
}
}
For less than 1000 digits in the string this is a little faster than preg_match and as little extra you get the positions and the values that are not a digit.

This is a bit of a cheeky solution,but it sure does the work.
<?php
$a="1,3,5,12,90";
$b=explode(",",$a);
$str='';
for($c=0;$c<count($b);$c++)
{
if (preg_match('/^[0-9]+$/', $b[$c]))
{
$str=$str."Y";
}
}
if(count(array_unique($b))==count($b) && (count($b)==strlen($str)))
{
echo $str;
//FURTHER CODE HERE WHEN ALL ELEMENTS UNIQUE AND VALID NUMBERS
}
else
{
//FURTHER CODE HERE WHEN NOT UNIQUE OR NOT A VALID NUMBERS
}
?>

Related

PHP - Check for leading 0's in 2 comma-delimited integers

I have a user-input string with 2 comma-delimited integers.
Example (OK):
3,5
I want to reject any user input that contains leading 0's for either number.
Examples (Bad):
03,5
00005,3
05,003
Now what I could do is separate the two numbers into 2 separate string's and use ltrim on each one, then see if they have changed from before ltrim was executed:
$string = "03,5";
$string_arr = explode(",",$string);
$string_orig1 = $string_arr[0];
$string_orig2 = $string_arr[1];
$string_mod1 = ltrim($string_orig1, '0');
$string_mod2 = ltrim($string_orig2, '0');
if (($string_mod1 !== $string_orig1) || ($string_mod2 !== $string_orig2)){
// One of them had leading zeros!
}
..but this seems unnecessarily verbose. Is there a cleaner way to do this? Perhaps with preg_match?
You could shorten the code and check if the first character of each part is a zero:
$string = "03,5";
$string_arr = explode(",",$string);
if ($string_arr[0][0] === "0" || $string_arr[1][0] === "0") {
echo "not valid";
} else {
echo "valid";
}
Here is one approach using preg_match. We can try matching for the pattern:
\b0\d+
The \b would match either the start of the string, or a preceding comma separator.
If we find such a match, it means that we found one or more numbers in the CSV list (or a single number, if only one number present) which had a leading zero.
$input = "00005,3";
if (preg_match("/\b0\d+/", $input)) {
echo "no match";
}
You can do a simple check that if the first character is 0 (using [0]) or that ,0 exists in the string
if ( $string[0] == "0" || strpos($string, ",0") !== false ) {
// One of them had leading zeros!
}
All the current answers fail if any of the values are simply 0.
You can just convert to integer and back and compare the result.
$arr = explode(',', $input);
foreach($arr as $item) {
if( (str)intval($item) !== $item ) {
oh_noes();
}
}
However I am more curious as to why this check matters at all.
One way would be with /^([1-9]+),(\d+)/; a regex that checks the string starts with one or more non-zero digits, followed by a comma, then one or more digits.
preg_match('/^([1-9]+),(\d+)/', $input_line, $output_array);
This separates the digits into two groups and explicitly avoids leading zeros.
This can be seen on Regex101 here and PHPLiveRegex here.

how to compare two string if last two character not matches then return those character

1.I have two string 1.abc and 2.abc_1 and i am comparing these two string 2nd string has two extra character, after comparing how to return these character in php.
2.If the string not ends with "_1" i want to add "_1" if the string ends with "_1 or (any numeric value)" i want to add +1 to that value,how to do this in php.
$jobref='abc';
$newjobref='abc_1';
if(strcasecmp($jobref,$newjobref)==0)
{
//here i want to add _1 to that string
}
else
{
//return last two character
if(last character == (any numeric value))
{
//add plus 1 to that value
}
}
What you do is use explode to return the final value of the string, then you can edit that value in the if/else loop and make finalblow the final outcome.
This took about 6 minutes of time to read, research and complete, it's untested but I think what you need to do is break your question into parts and then research individual parts down to solve the question.
Any issues let me know :)
$blowref = "abc";
$newblowref = "abc_1";
if(strcasecmp($blowref,$newblowref)==0)
{
$finalblow = $blowref."_1";
}
else
{
//return last two character
$bog = explode("_",$blowref);
$bog = end($bog); //the final part of the string after the `_` character
if(is_numeric($bog) || $bog === 0)
{
$finalblow = str_replace($bog,($bog+1),$blowref);
}
}
With thanks/nod to skh for the explode concept.
If the string doesnt contain an underscore add the _1, if it contains it, explode on it, increment and implode? Exploding will guarantee a full number.

How to check a string for a given format using PHP?

I have many headlines in my project like:
00.00.2014 - Headline Description e.t.c.
I want to check with php if the given strings contain the format 00.00.0000 - in front. The part after the - doesn't matter.
Can someone help me with something like:
$format = '00.00.0000 -';
if ($string MATCHES $format IN FRONT) {
// ...some code...
}
This should work:
if (preg_match("/^\d{2}\.\d{2}\.\d{4}\s\-\s.*$/", $string) === 1) {
// $string matches!
}
Explanation:
^ is "the beginning of the string"
\d is any digit (0, 1, 2, ..., 9)
{n} means "repeated n times"
\. is a dot
\s is a space
\- is a minus sign
. is "any single character"
* means "repeated 0 or more times`
$ means "end of the string"
I don't have a dev environment to test this out on but i'll give you some psuedocode:
I'm unsure of the context, but you can test this function on any given STRING:
Function:
Boolean hasCorrectFormat($myString){
//Here take the string and cut it into a char array.
$charArray = str_split($myString);
//This will give you a char array. Compare the first 12 elements of this
//array to see if they are correct. If its supposed to be number make
//sure it is, if its supposed to be a "." make sure it is..etc
//"00.00.0000 -" is 12 characters.
if(!isNumeric(charArray[0])){
return false;
}
else if(!isNumeric(charArray[1])){
return false;
}
else if(charArray[2] != "."){
return false;
}
//so on and so forth.....
else {return true}
}
Like i said i can't test this, and i can almost guarantee you this code wont run. This should give you the logic involved though.
Edit: also i wrote this assuming you dont literally mean "00.00.0000" but rather "xx.xx.xxxx" x being any number 0-9. If you need to make sure it is literally zeros then just cut your string to be the first ten chars and compare it.
Use the strpos function. Something like this:
if (strpos($string,'00.00.0000 -') !== true) {
//some code
}

PHP Regex - Value of 1 or more integers [duplicate]

This question already has answers here:
php validate integer
(7 answers)
Closed 9 years ago.
Hey I'm trying to perform input validation in PHP to ensure that the stock values that are typed in are at least 1 positive integer and from 0-9. Should not contain any special characters.
For example, any of the following values should be valid:
7
0
32
47534
The following SHOULD NOT be valid:
asdf
35/gdf
../34.
etc..
I'm using the following if statement to check for the positive integer value of "$original_stock".
if (preg_match("/^[0-9]$/", $original_stock))
{
$error .="Original stock must be numerical.";
}
Additionally, I have a price field which should be validated as either an int or a double.
If there's an easier alternative to using regex, that's okay too!
Thanks in advance :)
Try this regexp:
/^\d+$/
The issue with your existing regexp is that it only matches strings with exactly one digit.
As for validating an int or a double:
/^\d+\.?\d*$/
Note that that regexp requires that there be at least one digit.
Use:
/^[0-9]+$/
The + means "one or more". Without it, your regex will only match a single digit. Or you could use the simpler variant:
/^\d+$/
For floats, try something like:
/^\d+(\.\d{1,2})?/
This will match one or more digits, optionally followed by a . and one or two digits. (i.e. .12 will not match.)
To save yourself some headaches, you can also use the is_int and is_float functions.
Lastly; note that your check is wrong. preg_match will return 0 if it fails, so you should write it as:
if (!preg_match("/^\+$/", $original_stock)) {
// error
}
(note the !).
You may want to use the
is_int
Don't reinvent a wheel slower than an existing one, use a motorcycle: is_int.
#Assuming $original_stock is a single value...
if (is_int($original_stock)) {
#Valid, do stuff
}
else {
#Invalid, do stuff
}
#Assuming $original_stock is an array...
$valid = true;
foreach ($original_stock as $s) {
if (!is_int($s)) {
$valid = false;
break;
}
}
if ($valid) {...}
else {...}
I just ran into this exact problem and solved it this way using the regex.
I think the problem is your caret ^.
/^[0-9]$/
I moved it inside the class and got the results I needed.
function validate_int($subject)
{
//Pattern is numbers
//if it matches anything but numbers, we want a fail
$pattern = '/[^0-9]/';
$matches = preg_match($pattern, $subject);
if($matches > 0)
return false;
else
return true;
}

Regex to match Youtube URL's

I am trying to validate a Youtube URL using regex:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]+~', $videoLink)
It kind of works, but it can match URL's that are malformed. For example, this will match ok:
http://www.youtube.com/watch?v=Zu4WXiPRek
But so will this:
http://www.youtube.com/watch?v=Zu4WX£&P!ek
And this wont:
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
I think it's because of the + operator. It's matching what seems to be the first character after v=, when it needs to try and match everything behind v= with [a-zA-Z0-9-]. Any help is appreciated, thanks.
To provide an alternative that is larger and much less elegant than a regex, but works with PHP's native URL parsing functions so it might be a bit more reliable in the long run:
$url = "http://www.youtube.com/watch?v=Zu4WXiPRek";
$query_string = parse_url($url, PHP_URL_QUERY); // v=Zu4WXiPRek
$query_string_parsed = array();
parse_str($query_string, $query_string_parsed); // an array with all GET params
echo($query_string_parsed["v"]); // Will output Zu4WXiPRek that you can then
// validate for [a-zA-Z0-9] using a regex
The problem is that you are not requiring any particular number of characters in the v= part of the URL. So, for instance, checking
http://www.youtube.com/watch?v=Zu4WX£&P!ek
will match
http://www.youtube.com/watch?v=Zu4WX
and therefore return true. You need to either specify the number of characters you need in the v= part:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]{10}~', $videoLink)
or specify that the group [a-zA-Z0-9-] must be the last part of the string:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]+$~', $videoLink)
Your other example
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
does not match, because the + sign requires that at least one character must match [a-zA-Z0-9-].
Short answer:
preg_match('%(http://www.youtube.com/watch\?v=(?:[a-zA-Z0-9-])+)(?:[&"\'\s])%', $videoLink)
There are a few assumptions made here, so let me explain:
I added a capturing group ( ... ) around the entire http://www.youtube.com/watch?v=blah part of the link, so that we can say "I want get the whole validated link up to and including the ?v=movieHash"
I added the non-capturing group (?: ... ) around your character set [a-zA-Z0-9-] and left the + sign outside of that. This will allow us to match all allowable characters up to a certain point.
Most importantly, you need to tell it how you expect your link to terminate. I'm taking a guess for you with (?:[&"\'\s])
?) Will it be in html format (e.g. anchor tag) ? If so, the link in href will obviously end with a " or '.
?) Or maybe there's more to the query string, so there would be an & after the value of v.
?) Maybe there's a space or line break after the end of the link \s.
The important piece is that you can get much more accurate results if you know what's surrounding what you are searching for, as is the case with many regular expressions.
This non-capturing group (in which I'm making assumptions for you) will take a stab at finding and ignoring all the extra junk after what you care about (the ?v=awesomeMovieHash).
Results:
http://www.youtube.com/watch?v=Zu4WXiPRek
- Group 1 contains the http://www.youtube.com/watch?v=Zu4WXiPRek
http://www.youtube.com/watch?v=Zu4WX&a=b
- Group 1 contains http://www.youtube.com/watch?v=Zu4WX
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
- No match
a href="http://www.youtube.com/watch?v=Zu4WX&size=large"
- Group 1 contains http://www.youtube.com/watch?v=Zu4WX
http://www.youtube.com/watch?v=Zu4WX£&P!ek
- No match
The "v=..." blob is not guaranteed to be the first parameter in the query part of the URL. I'd recommend using PHP's parse_url() function to break the URL into its component parts. You can also reassemble a pristine URL if someone began the string with "https://" or simply used "youtube.com" instead of "www.youtube.com", etc.
function get_youtube_vidid ($url) {
$vidid = false;
$valid_schemes = array ('http', 'https');
$valid_hosts = array ('www.youtube.com', 'youtube.com');
$valid_paths = array ('/watch');
$bits = parse_url ($url);
if (! is_array ($bits)) {
return false;
}
if (! (array_key_exists ('scheme', $bits)
and array_key_exists ('host', $bits)
and array_key_exists ('path', $bits)
and array_key_exists ('query', $bits))) {
return false;
}
if (! in_array ($bits['scheme'], $valid_schemes)) {
return false;
}
if (! in_array ($bits['host'], $valid_hosts)) {
return false;
}
if (! in_array ($bits['path'], $valid_paths)) {
return false;
}
$querypairs = explode ('&', $bits['query']);
if (count ($querypairs) < 1) {
return false;
}
foreach ($querypairs as $querypair) {
list ($key, $value) = explode ('=', $querypair);
if ($key == 'v') {
if (preg_match ('/^[a-zA-Z0-9\-_]+$/', $value)) {
# Set the return value
$vidid = $value;
}
}
}
return $vidid;
}
Following regex will match any youtube link:
$pattern='#(((http(s)?://(www\.)?)|(www\.)|\s)(youtu\.be|youtube\.com)/(embed/|v/|watch(\?v=|\?.+&v=|/))?([a-zA-Z0-9._\/~#&=;%+?-\!]+))#si';

Categories