How to validate the format of a string? - php
Basically, I have a variable that is built from a multidimensional array via a foreach loop.
I need to somehow validate the format that it is in, although I am not to sure how to go about this since I am still quite a newbie when it comes to PHP.
This is how my string will look:
question1,answer1,answer2,answer3,answer4
question2,answer1,answer2,answer3,answer4
question3,answer1,answer2,answer3,answer4
I need to validate that exact format, being:
string[comma]string[comma]string[comma]string[comma]string
string[comma]string[comma]string[comma]string[comma]string
string[comma]string[comma]string[comma]string[comma]string
I need to validate it with a boolean variable if possible, to return true or false if it matches the format or not. These strings can contain anything such as letters, numbers, special characters, etc.
Each line will ALWAYS have 5 strings and 4 commas, never more and never less.
If needed, this is the code that builds the multidimensional array and then converts it into a string. It is grabbing an uploaded CSV file, transferring it into a multidimensional array, and then building the string afterwards. As you can see, my array is starting at 1 instead of 0, no point explaining why since that is off topic.
$csv_array = array(array());
if (!empty($_FILES['upload_csv']['tmp_name']))
{
$file = fopen($_FILES['upload_csv']['tmp_name'], 'r');
}
if($file)
{
while (($line = fgetcsv($file)) !== FALSE)
{
$csv_array[] = array_combine(range(1, count($line)), array_values($line));
}
fclose($file);
}
if(!empty($csv_array[1]))
{
foreach (array_slice($csv_array,1) as $row)
{
$all_questions = $all_questions . $row[1] . ",";
$all_questions = $all_questions . $row[2] . ",";
$all_questions = $all_questions . $row[3] . ",";
$all_questions = $all_questions . $row[4] . ",";
$all_questions = $all_questions . $row[5];
$all_questions = $all_questions . "\n";
}
}
All help is greatly appreciated.
Thanks in advance!
Sounds like a regex could do the job:
$match_ok = preg_match('/^([^,]+,){4}[^,]+$/', $test_string);
If you want to allow [string] to be empty, you may change all + to *.
Explanation: The first ^ matches the line start, then one or more characters, that are not commas, are expected followed by a comma. This sequence has to be there 4 times and has to be followed by another string not terminated by a comma. The $ matches the end of the line.
If you want to match the while multiline string, you may use:
$match_ok = preg_match('/^(([^,]+,){4}[^,]+\n){3}$/', $test_string);
(since preg_match works in multiline mode by default)
Edit 2: You may even make the regex match to a string not ending with a newline by handling the last line separately, just as it is done with the cols:
$match_ok = preg_match('/^(([^,]+,){4}[^,]+\n){2}([^,]+,){4}[^,]+$/', $test_string);
Try This simple one, May be so many other solutions possible for this
<?php
$test_string = "question1,answer1,answer2,answer3,answer4";
$newarray=explode(',',$test_string);
if(count($newarray)=='5'){
your code......;
}
?>
--------------------TRUE FALSE-------------
<?php
$test_string = "questionAsdAD1###,234234,answer2,answer3,answer4";
function ToCheckMyStrung($test_string){
$newarray=explode(',',$test_string);
if(count($newarray)=='5'){
return true;
} else {
return false;
}
}
?>
in foreach
use
implode(',',$row); for proper formatting.
You can do it while you are creating your string variable,
$count=1;
$trace=array();
if(!empty($csv_array[1]))
{
foreach (array_slice($csv_array,1) as $row)
{
$all_questions = $all_questions . $row[1] . ",";
$all_questions = $all_questions . $row[2] . ",";
$all_questions = $all_questions . $row[3] . ",";
$all_questions = $all_questions . $row[4] . ",";
$all_questions = $all_questions . $row[5];
$all_questions = $all_questions . "\n";
if($row[1]=="" || $row[2]=="" || $row[3]=="" || $row[4]=="" || $row[5]=="")
{
$trace[]=$count;
}
$count++;
}
}
and than just make use of $trace array whenever you want.
A regular expression will help you out:
$test_string = "Some,string,you,want,to,test";
if(preg_match('#^([a-zA-Z0-9]+\,)+([a-zA-Z0-9])+$#', $test_string)) {
echo 'All ok';
}
Related
PHP prevent extra empty line when writing text to file
I'm having a small issue regarding a foreach() loop and writing an array to a text file within. The loop gives me the format in the file that I want but it also adds (as I was told) an unwanted empty line at the end of the file. Here is my piece of code: foreach($data_arr as $data => $input) { fwrite($fh, $data . ":" . $input . "\n") or die("something went wrong here"); } Is there a way to prevent this from happening and not add the \n when it reaches the end of the array?
You can do something like this : $data_array = ['c', 'h', "hf"]; $last = count($data_array) - 1; #size of the array foreach($data_array as $data => $input) { $separator = $data == $last ? "" : "\n"; #if is last, then seperator isn't a back to line fwrite($fh, $data . ":" . $input . $separator); }
Just check if current index is the last one, then eventually add "\n" to the string $last_index = count($data_arr)-1; foreach ($data_arr as $data => $input) { $string = $data . ":" . $input; if ($data != $last_index) { $string .= "\n"; } fwrite($fh, $string) or die("something went wrong here"); }
Determining whether you are doing something for the last time, is cumbersome - for starters, you need to count your items, and then you need a loop index to compare to that count … Much easier to determine, whether you are doing something for the first time. So just reverse your logic here - do not try to output “all lines, followed by a newline each, except the last one”, but instead, output “all lines preceded by a newline each, except the first one.” You could use a simple boolean flag for that: $is_first_line = true; foreach($data_arr as $data => $input) { fwrite($fh, ($is_first_line ? "" : "\n") . $data . ":" . $input); $is_first_line = false; } Or you just append a variable before the line data all the time - and simply make that variable “empty” on the first iteration, and then fill it with a newline character for all the following ones: $prefix = ""; foreach($data_arr as $data => $input) { fwrite($fh, $prefix . $data . ":" . $input); $prefix = "\n"; }
Query produces data, but the export is blank
I was recently tasked to update some older sites from MySQL to MySQLi. Though slow and steady, the update has been ok until I ran into an issue when exporting some data to an excel document. This code was written by a previous developer. There's a lot going on in the file, and I hope I'm grabbing the part that is supposed to be creating the excel document: <?php $export = mysqli_query ( $session->connDB(),$sql ) or die ( "Sql error : " . mysqli_error( ) ); $fields = mysqli_num_fields ( $export ); $num_rows = mysqli_num_rows( $export ); $pattern = '/[A-Z0-9][A-Z0-9._-]+#[A-Z0-9][A-Z0-9.-]{0,61}[A-Z0-9]\.[A-Z.]{2,6}/i'; //email $phonpat = '/(\(?([0-9]{3})+\)?[\-\s\.]?([0-9]{3})+[\-\s\.]?([0-9]{4})(( |-|\.)?[ext\.]+ ?\d+)|\(?([0-9]{3})+\)?[\-\s\.]?([0-9]{3})+[\-\s\.]?([0-9]{4}))/i'; //telephone $phPat = '/([0-9]{3})([0-9]{3})([0-9]{4})/'; $vippatt = '/VIP/i'; for($f=0; $f<$fields; $f++){ $header.='"'.mysqli_fetch_fields($export, $f).'"'."\t"; } for($i=0; $i<$num_rows; $i++){ for($x=0; $x<$fields; $x++){ $email = mysqli_fetch_assoc($export,$i,"EMAIL"); $phone = mysqli_fetch_assoc($export,$i,"PHONE"); $viprm = mysqli_fetch_assoc($export,$i,"VIP"); preg_match ($pattern, $email, $matches); preg_match ($phonpat, $phone, $phoneno); preg_match ($vippatt, $viprm, $vpmatch); if(isset($matches[0])) {$emal=strtolower($matches[0]);} else {$emal="";} if(isset($vpmatch[0])) {$vips=strtoupper($vpmatch[0]);} else {$vips="";} if(isset($phoneno[0])) {$phne=preg_replace($phPat,'($1) $2-$3 ',formatPhone($phoneno[0],false,false));} else {$phne="";} if(mysqli_fetch_fields($export, $x)=='EMAIL'){ $fld=$emal; } else { if(mysqli_fetch_fields($export, $x)=='PHONE'){ $fld=$phne; } else { if(mysqli_fetch_fields($export, $x)=='VIP'){ $fld=$vips; } else { if(mysqli_fetch_fields($export, $x)=='UNITS'){ $fld=1; } else { $fld = mysqli_fetch_assoc($export,$i,mysqli_fetch_fields($export, $x)); } } } } $data.= '"'.$fld.'"'."\t"; } $data.="\n"; } ?> Here is where the code checks if the data is blank or not, and then exports the spreadsheet: <?php if ($data == "") { $data = "\nNo records found for your search parameters.\n\n".$sql; } else { echo "should show data"; } global $time; $time = time(); header("Content-Disposition: attachment; filename=CargoManagementCustomReport-$time.xls"); header("Pragma: no-cache"); header("Expires: 0"); print "$header\n$data"; ?> When the spreadsheet gets exported, I see "should show data". This tells me the $data variable obviously has data. It's just not getting into the spreadsheet. If you'll notice in the above, I'm using mysqli_fetch_fields. This was used to replace mysql_field_name (in my attempt to update to MySQLi). I also tried mysqli_fetch_field, but got the same results. I am getting no errors, but the spreadsheet is still blank. I can echo $sql to get the query, and I can run the query in the database and it returns data. What am I doing wrong and how can I fix it?
That whole code is gibberish, so I hope I understood what it is that it was meant to do. Here are the main problems: mysqli_fetch_fields() takes only 1 argument and returns an array of objects. You can't cast an array to a string. I assume you wanted to get the field name. mysqli_fetch_assoc() takes only 1 argument and returns an array of data in an associative array as the name suggests. It also moves the internal pointer to the next row every time it is called. You are trying to use it as if it was mysql_result(). Your nested loops are very messy. I replaced them with simple foreach loops and replaced the nested if statements with a switch. While I would normally stay away from such constructs, this is the easiest way to migrate this code. After removing all the mysqli nonsense, the code is now readable. It iterates over every field of every row, applying some transformations to some fields and concatenating the result into a string. Fixed code: $conn = $session->connDB(); $export = mysqli_query($conn, $sql); $pattern = '/[A-Z0-9][A-Z0-9._-]+#[A-Z0-9][A-Z0-9.-]{0,61}[A-Z0-9]\.[A-Z.]{2,6}/i'; //email $phonpat = '/(\(?([0-9]{3})+\)?[\-\s\.]?([0-9]{3})+[\-\s\.]?([0-9]{4})(( |-|\.)?[ext\.]+ ?\d+)|\(?([0-9]{3})+\)?[\-\s\.]?([0-9]{3})+[\-\s\.]?([0-9]{4}))/i'; //telephone $phPat = '/([0-9]{3})([0-9]{3})([0-9]{4})/'; $vippatt = '/VIP/i'; foreach (mysqli_fetch_fields($result) as $field) { $header .= '"' . $field->name . '"' . "\t"; } $data = ''; foreach ($export as $row) { foreach ($rows as $fieldName => $value) { switch ($fieldName) { case 'EMAIL': preg_match($pattern, $value, $matches); $data .= '"' . (isset($matches[0]) ? strtolower($matches[0]) : '') . '"' . "\t"; break; case 'PHONE': preg_match($phonpat, $value, $phoneno); $phne = ""; if (isset($phoneno[0])) { $phne = preg_replace($phPat, '($1) $2-$3 ', formatPhone($phoneno[0], false, false)); } $data .= '"' . $phne . '"' . "\t"; break; case 'VIP': preg_match($vippatt, $value, $vpmatch); $data .= '"' . (isset($vpmatch[0]) ? strtolower($vpmatch[0]) : '') . '"' . "\t"; break; case 'UNITS': $data .= '"1"' . "\t"; break; default: $data .= '"' . $value . '"' . "\t"; break; } } $data .= "\n"; }
Unexpected result using OR operator in regular expression
I've a problem with a regular expression. I have a text which is read from a file. The text can contain one or more IDs separated by comma. And then I have a list of IDs and want to check if one of these IDs match with my text so I try to use an OR operator: $idString = '2561,3,261,6,540,33,3105,2085,38,42,1066,49,3377,53,3161,91,356,3179,3695,3184,370,123,3451,124,3710,2188,141,404,1435,160,1443,432,435,440,1721,3261,2498,205,3282,476,482,3301,486,749,3309,243,3059,759,2046,4,262,785,534,541,3360,34,3106,2086,39,43,50,3378,54,1337,61,1351,3157,3162,360,3696,3185,631,3450,3200,666,1436,673,1444,3748,3262,2499,206,3279,3283,470,477,483,3302,490,755,760,2047,2562,1029,263,23,542,35,3107,2087,40,552,553,1321,47,51,3379,55,1338,3163,361,3697,3186,633,3452,639,143,3223,1445,3749,1450,3263,2500,207,3284,478,484,3303,2559,264,1297,22,543,36,44,57,1339,3389,62,3164,3677,362,3180,634,144,1685,1446,430,700,208,3286,479,1249,485,3306,2558,255,265,524,30,288,46,2095,63,2375,3165,403,1447,3242,696,1724,3557,3304,1770,3066,2563,266,544,2338,555,3131,3166,2204,415,1448,1239,3288,480,3305,754,267,545,3370,2378,3152,3170,648,147,679,1449,2537,753,2546,505,2564,3335,268,535,537,539,546,549,65,69,3167,148,3244,744,3068,2565,269,286,547,292,1334,1340,3659,3168,383,153,1705,3267,3060,2566,270,271,3099,548,1660,398,154,1706,2511,746,3332,2568,272,3148,422,3269,752,768,273,3381,3153,3199,155,468,784,274,3093,325,1657,3319,510,3329,3333,275,1432,2230,441,1722,773,3338,276,3641,2108,491,3339,277,2398,107,3181,2245,757,3346,2100,619,1760,2050,3351,2103,667,19,3372,2534,1064,351,1726,2394,2508,2538,2104,3147,2083,2097,2042,2096,2165,2049,2525,2526,1774,2392,2080,2043,2542,2547,2129,2540,2536,2190,2226,2569,2572,2373,2507'; $idString = str_replace(',', '|', $idString); $text = '1453,2018'; if (preg_match('/' . $idString . '/', $text)) { echo 'yes' . PHP_EOL; } else { echo 'no' . PHP_EOL; } I'm expecting that nothing matches because the IDs 1453 and 2018 are not found in my lookup string but it matches. I think that's because the ID 3 matches with 1453 but this is not correct for my use case.
That's too easy to work around it using arrays. You shouldn't use Regular Expressions if you can work with them but it seems this is not your real problem but an MCVE for a different one. You should use word boundaries \b otherwise a number like 4 is found in 1453. preg_match() third argument holds results to analyze what is going on. preg_match('/\b(?:' . $idString . ')\b/', $text, $match)
The syntax for preg_match is ($pattern, $text). Change it as follows, worked for me. <?php $idString = '2561,3,261,6,540,33,3105,2085,38,42,1066,49,3377,53,3161,91,356,3179,3695,3184,370,123,3451,124,3710,2188,141,404,1435,160,1443,432,435,440,1721,3261,2498,205,3282,476,482,3301,486,749,3309,243,3059,759,2046,4,262,785,534,541,3360,34,3106,2086,39,43,50,3378,54,1337,61,1351,3157,3162,360,3696,3185,631,3450,3200,666,1436,673,1444,3748,3262,2499,206,3279,3283,470,477,483,3302,490,755,760,2047,2562,1029,263,23,542,35,3107,2087,40,552,553,1321,47,51,3379,55,1338,3163,361,3697,3186,633,3452,639,143,3223,1445,3749,1450,3263,2500,207,3284,478,484,3303,2559,264,1297,22,543,36,44,57,1339,3389,62,3164,3677,362,3180,634,144,1685,1446,430,700,208,3286,479,1249,485,3306,2558,255,265,524,30,288,46,2095,63,2375,3165,403,1447,3242,696,1724,3557,3304,1770,3066,2563,266,544,2338,555,3131,3166,2204,415,1448,1239,3288,480,3305,754,267,545,3370,2378,3152,3170,648,147,679,1449,2537,753,2546,505,2564,3335,268,535,537,539,546,549,65,69,3167,148,3244,744,3068,2565,269,286,547,292,1334,1340,3659,3168,383,153,1705,3267,3060,2566,270,271,3099,548,1660,398,154,1706,2511,746,3332,2568,272,3148,422,3269,752,768,273,3381,3153,3199,155,468,784,274,3093,325,1657,3319,510,3329,3333,275,1432,2230,441,1722,773,3338,276,3641,2108,491,3339,277,2398,107,3181,2245,757,3346,2100,619,1760,2050,3351,2103,667,19,3372,2534,1064,351,1726,2394,2508,2538,2104,3147,2083,2097,2042,2096,2165,2049,2525,2526,1774,2392,2080,2043,2542,2547,2129,2540,2536,2190,2226,2569,2572,2373,2507'; $idString = str_replace(',', '|', $idString); $text = '1453,2018'; if (preg_match('/(' . $text . ')/', $idString)) { echo 'yes' . PHP_EOL; } else { echo 'no' . PHP_EOL; } ?>
You can see what gets matched by your Regex by outputting the matches, eg: if (preg_match('/' . $idString . '/', $text, $matches)) { echo 'yes' . PHP_EOL; print_r($matches); } else { echo 'no' . PHP_EOL; } You'd have to adapt your regex to match against whole words only... for example like this: if (preg_match('/\b(' . $idString . ')\b/', $text)) { https://regex101.com/r/M1Pieb/2/ Or you could avoid using regex altogether (recommended, its getting a bit crazy..) by using explode $idString = '2561,3,261,6,540,33,3105,2085,38,42,1066,49,3377,53,3161,91,356,3179,3695,3184,370,123,3451,124,3710,2188,141,404,1435,160,1443,432,435,440,1721,3261,2498,205,3282,476,482,3301,486,749,3309,243,3059,759,2046,4,262,785,534,541,3360,34,3106,2086,39,43,50,3378,54,1337,61,1351,3157,3162,360,3696,3185,631,3450,3200,666,1436,673,1444,3748,3262,2499,206,3279,3283,470,477,483,3302,490,755,760,2047,2562,1029,263,23,542,35,3107,2087,40,552,553,1321,47,51,3379,55,1338,3163,361,3697,3186,633,3452,639,143,3223,1445,3749,1450,3263,2500,207,3284,478,484,3303,2559,264,1297,22,543,36,44,57,1339,3389,62,3164,3677,362,3180,634,144,1685,1446,430,700,208,3286,479,1249,485,3306,2558,255,265,524,30,288,46,2095,63,2375,3165,403,1447,3242,696,1724,3557,3304,1770,3066,2563,266,544,2338,555,3131,3166,2204,415,1448,1239,3288,480,3305,754,267,545,3370,2378,3152,3170,648,147,679,1449,2537,753,2546,505,2564,3335,268,535,537,539,546,549,65,69,3167,148,3244,744,3068,2565,269,286,547,292,1334,1340,3659,3168,383,153,1705,3267,3060,2566,270,271,3099,548,1660,398,154,1706,2511,746,3332,2568,272,3148,422,3269,752,768,273,3381,3153,3199,155,468,784,274,3093,325,1657,3319,510,3329,3333,275,1432,2230,441,1722,773,3338,276,3641,2108,491,3339,277,2398,107,3181,2245,757,3346,2100,619,1760,2050,3351,2103,667,19,3372,2534,1064,351,1726,2394,2508,2538,2104,3147,2083,2097,2042,2096,2165,2049,2525,2526,1774,2392,2080,2043,2542,2547,2129,2540,2536,2190,2226,2569,2572,2373,2507'; $idStrings = explode(',', $idString); $values = ['1453', '2018']; $matchedValue = null; foreach ($values as $value) { if (in_array($value, $idStrings)) { $matchedValue = $value; break; } } if ($matchedValue !== null) { echo 'yes: ' . $matchedValue; } else { echo 'no'; }
double quotes inside single quotes in MYSQL result?
I'm trying to do something very basic but I can't figure out how. basically i'm trying to convert the mysql result ($row) into the following format (literal strings): "0784562627828" => "James", "0786636363663" => "David", I have all the data stored in the database and I can get them echoed on my page like so: $phone = $row['phone']; $name = $row['name']; $list .=''.$phone.''; echo $list; could someone please advise on this? Thanks
Just assign them inside an array like you normally would: $array = array(); while(your fetch here) { $array[$row['phone']] = $row['name']; } To check its contents, you can use var_dump($array) or print_r($array) Or just straight up show them, like the one you formatted: while(your fetch here) { echo '"' . $row['phone'] . '"' . ' => ' . '"' . $row['name'] . '"' . '<br/>'; }
you mean something like this? $list = array(); $list[$phone] = $name;
Can you do something like $list = []; foreach($rows as $row) { $list[$row['phone']] = $row['name']; }
Need some help with XML parsing
The XML feed is located at: http://xml.betclick.com/odds_fr.xml I need a php loop to echo the name of the match, the hour, and the bets options and the odds links. The function will select and display ONLY the matchs of the day with streaming="1" and the bets type "Ftb_Mr3". I'm new to xpath and simplexml. Thanks in advance. So far I have: <?php $xml_str = file_get_contents("http://xml.betclick.com/odds_fr.xml"); $xml = simplexml_load_string($xml_str); // need xpath magic $xml->xpath(); // display ?>
Xpath is pretty simple once you get the hang of it you basically want to get every match tag with a certain attribute //match[#streaming=1] will work pefectly, it gets every match tag from underneath the parent tag with the attribute streaming equal to 1 And i just realised you also want matches with a bets type of "Ftb_Mr3" //match[#streaming=1]/bets/bet[#code="Ftb_Mr3"] This will return the bet node though, we want the match, which we know is the grandparent //match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../.. the two dots work like they do in file paths, and gets the match. now to work this into your sample just change the final bit to // need xpath magic $nodes = $xml->xpath('//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..'); foreach($nodes as $node) { echo $node['name'].'<br/>'; } to print all the match names.
I don't know how to work xpath really, but if you want to 'loop it', this should get you started: <?php $xml = simplexml_load_file("odds_fr.xml"); foreach ($xml->children() as $child) { foreach ($child->children() as $child2) { foreach ($child2->children() as $child3) { foreach($child3->attributes() as $a => $b) { echo $a,'="',$b,"\"</br>"; } } } } ?> That gets you to the 'match' tag which has the 'streaming' attribute. I don't really know what 'matches of the day' are, either, but... It's basically right out of the w3c reference: http://www.w3schools.com/PHP/php_ref_simplexml.asp
I am using this on a project. Scraping Beclic odds with: <?php $match_csv = fopen('matches.csv', 'w'); $bet_csv = fopen('bets.csv', 'w'); $xml = simplexml_load_file('http://xml.cdn.betclic.com/odds_en.xml'); $bookmaker = 'Betclick'; foreach ($xml as $sport) { $sport_name = $sport->attributes()->name; foreach ($sport as $event) { $event_name = $event->attributes()->name; foreach ($event as $match) { $match_name = $match->attributes()->name; $match_id = $match->attributes()->id; $match_start_date_str = str_replace('T', ' ', $match->attributes()->start_date); $match_start_date = strtotime($match_start_date_str); if (!empty($match->attributes()->live_id)) { $match_is_live = 1; } else { $match_is_live = 0; } if ($match->attributes()->streaming == 1) { $match_is_running = 1; } else { $match_is_running = 0; } $match_row = $match_id . ',' . $bookmaker . ',' . $sport_name . ',' . $event_name . ',' . $match_name . ',' . $match_start_date . ',' . $match_is_live . ',' . $match_is_running; fputcsv($match_csv, explode(',', $match_row)); foreach ($match as $bets) { foreach ($bets as $bet) { $bet_name = $bet->attributes()->name; foreach ($bet as $choice) { // team numbers are surrounded by %, we strip them $choice_name = str_replace('%', '', $choice->attributes()->name); // get the float value of odss $odd = (float)$choice->attributes()->odd; // concat the row to be put to csv file $bet_row = $match_id . ',' . $bet_name . ',' . $choice_name . ',' . $odd; fputcsv($bet_csv, explode(',', $bet_row)); } } } } } } fclose($match_csv); fclose($bet_csv); ?> Then loading the csv files into mysql. Running it once a minute, works great so far.