strpos with array_key_search - php

i have a code to search for array keys, but only if the message is the exact message, i want it to use strpos so it can detect the message but i don't know how to do it:
My Code:
$message = $_POST['message'];
$responses = array("hi" => "whats up?");
if (array_key_exists($message,$responses)){
$msg = strtolower($message);
$answer = $responses[$msg];
echo $answer;
}
So this only works if the whole posted data was "hi". I want it to use strpos so it can detect hi anywhere, how would i do that?

I'm not 100% sure, but is this what you want?
$foundKey = null;
foreach ($responses as $key => $value) {
if (strpos($message, $key) !== false) {
$foundKey = $key;
break;
}
}
if ($foundKey !== null) {
echo "Found key: " . $responses[$key];
}
Edit:
If you want a case insensitive version, of course you can use this instead:
$foundKey = null;
foreach ($responses as $key => $value) {
if (stripos($message, $key) !== false) {
$foundKey = strtolower($key);
break;
}
}
if ($foundKey !== null) {
echo "Found key: " . $responses[$key];
}

strpos(firststring,secondstring,startposition[Optional]) function is return num.if num>=0 mean second string in first string.
$message = $_POST['message'];
$responses = array("hi" => "whats up?");
if (strpos($message,$responses)>=0){
$msg = strtolower($message);
$answer = $responses[$msg];
echo $answer;
}

Related

PHP strpos array

I am trying to loop through a string that contains html from a scraped webpage. First I look to return all links that contain the word "result" and then I would like to organize all the links that contain one of four cases, "base", "second", "third" or "latest" and create a fluid array.
Below is what I have come up with but it returns "Warning: strpos(): needle is not a string or an integer". I cannot seem to get the array cases to work.
Any help would be greatly appreciated. Thank you
$key = "results";
$reportKey = array("base", "second", "third","latest");
$keyArray = array();
foreach($html->find('a') as $element){
if (strpos($element->href, $key) !== false){
if (strpos($element->href, $reportKey) !== false){
$keyArray[] = $element->href;
}
}
}
echo "<pre>" . print_r($keyArray) . "</pre> ";
You can't use an array as a needle in strpos. Change second if to:
if (str_replace($reportKey, "", $element->href) === $element->href) {
$keyArray[] = $element->href;
}
strpos() does not allow more than one needle, you can do this:
$key = "results";
$reportKey = array("base", "second", "third","latest");
$keyArray = array();
foreach($html->find('a') as $element)
{
if (strpos($element->href, $key) !== false){
if (
strpos($element->href, $reportKey[0]) !== false
|| strpos($element->href, $reportKey[1]) !== false
|| strpos($element->href, $reportKey[2]) !== false
|| strpos($element->href, $reportKey[3]) !== false
){
$keyArray[] = $element->href;
}
}
}
echo "<pre>" . print_r($keyArray) . "</pre> ";
You could also do your own function, this is only an example:
function multi_strpos($string, $check, $getResults = false)
{
$result = array();
$check = (array) $check;
foreach ($check as $s)
{
$pos = strpos($string, $s);
if ($pos !== false)
{
if ($getResults)
{
$result[$s] = $pos;
}
else
{
return $pos;
}
}
}
return empty($result) ? false : $result;
}
A solution using array_map() and in_array():
$key = 'results';
$reportKey = ['base', 'second', 'third', 'latest'];
$keyArray = [];
foreach($html->find('a') as $element) {
if (false !== strpos($element->href, $key)) {
// I changed the condition here
$pos = array_map(fn($k) => strpos($element->href, $k) !== false, $reportKey);
if (in_array(true, $pos)){
$keyArray[] = $element->href;
}
}
}
$pos will be an array containing booleans based on matches between $element->href and $reportKey items.
Then we check with in_array() if it matched at least one time.

How to repeat the same action for diffrent variables

<!-- language: php -->
<?php
// test variables
$l1 = "http://youtube.com/channel/";
$l2 = "http://youtube.com/channel/";
$l3 = "http://youtube.com/channel/";
$l4 = "http://youtube.com/channel/";
$fl = "http://youtube.com/channel/";
//set error false as default
$error = "false";
//check if variables are ready for use, if they are, add them to `$l` array
//I do each check as a seperate line, as it looks cleaner than 1 long if statement.
$l = [];
if(!empty($l1)) $l[] = $l1;
if(!empty($l2)) $l[] = $l2;
if(!empty($l3)) $l[] = $l3;
if(!empty($l4)) $l[] = $l4;
if(!empty($fl)) $l[] = $fl;
foreach($l as $key => $value) {
//1 line ternary is cleaner than if/else statetmnt
$errorKey = $key < 9? "0{$key}" : $key;
//each row by default has no error
$hasError = 0;
//check if this a valid url
if(!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $value)) {
$error = "true";
$hasError = 1;
}
if($hasError) {
//store error in array, to loop through later
$errors[] = $errorKey;
}
}
$search = '?sub_confirmation=1';
$searchUrl = "youtube.com/channel";
if (strpos($l, $searchUrl) !== false && strpos($l, $search) === false) {
$l = $value."".$search;
}
if($error == "false") {
echo $l1;
echo $l2;
echo $l3;
echo $l4;
echo $fl;
}
// deliver the error message
//Check if $error has been set to true at any point
if($error == "true") {
//loop through error array, echo error message if $errorNumber matches.
//at this point we KNOW there was an error at some point, no need to use a switch really
foreach($errors as $errorNumber) {
echo "Something went wrong here $errorNumber :o";
}
}
?>
Hello, my problem is at the end of the code where the strpos function is, so basically I want to check every url, once if it contains a certain url, and then add something to the end if it is so. But I don't want to repeat an if statement 4 times($fl variable doesn't has to be checked), I am quite new in all that so I hope somebody can help me, I tought about a switch statement but I guess there is a better way. And if I put it in the foreach aboth, it doesn't applies on the certain variables, only on the value variable.
You can assign $value by reference using this foreach header (notice the & in front of $value):
foreach($l as $key => &$value) {
By doing this every change you do to $value will also be done to the corresponding value in the $l array.
Then at the end of the foreach loop you put this code:
if (strpos($value, $searchUrl) !== false && strpos($value, $search) === false) {
$value .= $search;
}
So your final foreach loop should look like this:
foreach($l as $key => &$value) {
//1 line ternary is cleaner than if/else statetmnt
$errorKey = $key < 9? "0{$key}" : $key;
//each row by default has no error
$hasError = 0;
//check if this a valid url
if(!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $value)) {
$error = "true";
$hasError = 1;
}
if($hasError) {
//store error in array, to loop through later
$errors[] = $errorKey;
}
$search = '?sub_confirmation=1';
$searchUrl = "youtube.com/channel";
if (strpos($value, $searchUrl) !== false && strpos($value, $search) === false) {
$value .= $search;
}
}
You can read more about using references in foreach loops here: PHP: foreach
Edit:
To apply the changes not only to the elements of the $l array, but also to the original variables $l1, $l2 and so on, you should assign the elements to your array as references too:
$l = [];
if(!empty($l1)) $l[] = &$l1;
if(!empty($l2)) $l[] = &$l2;
if(!empty($l3)) $l[] = &$l3;
if(!empty($l4)) $l[] = &$l4;
if(!empty($fl)) $l[] = &$fl;
Personally, I think this is a good candidate for moving to a class. To be honest I'm not 100% sure what you are doing but will try to convert your code to a class.
class L {
public $raw = null;
public $modified = null;
public $error = false;
// create the class
public function __construct($data=null) {
$this->raw = $data;
// Check the raw passed in data
if ($data) {
$this->isUrl();
}
// If there was no error, check the data
if (! $this->error) {
$this->search();
}
}
// Do something ?
public function debug() {
echo '<pre>';
var_dump($this);
echo '</pre>';
}
public function getData() {
return ($this->modified) ? : $this->raw;
}
private function isUrl() {
$this->error = (! preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $this->raw));
}
// Should a failed search also be an error?
private function search() {
if ($this->raw) {
if ( (strpos($this->raw, "youtube.com/channel") !== false) &&
(strpos($this->raw, "?sub_confirmation=1") === false) ) {
$this->modified = $this->raw ."?sub_confirmation=1";
}
}
}
}
// Test data
$testList[] = "test fail";
$testList[] = "https://youtube.com/searchFail";
$testList[] = "https://youtube.com/channel/success";
$testList[] = "https://youtube.com/channel/confirmed?sub_confirmation=1";
// Testing code
foreach($testList as $key=>$val) {
$l[] = new L($val);
}
foreach($l as $key=>$val) {
// Check for an error
if ($val->error) {
$val->debug();
} else {
echo '<pre>'.$val->getData().'</pre>';
}
}
And the output would be:
object(L)#1 (3) {
["raw"]=>
string(9) "test fail"
["modified"]=>
NULL
["error"]=>
bool(true)
}
https://youtube.com/searchFail
https://youtube.com/channel/success?sub_confirmation=1
https://youtube.com/channel/confirmed?sub_confirmation=1

PHP foreach with more condition

Is it possible to set foreach function more than 2 condition. Example like below:
$stat_cps = $_POST['stat_cp'];
$acc_idss = $_POST['acc_ids'];
$string = 'NG';
foreach ($stat_cps as $url)
{
if(strpos($string, $url) !== FALSE)
{
echo "One of the field is NG";
return true;
}
}
echo "All field is OK";
What I want is:
if $stat_cps or $acc_idss contains NG then echo "One of the field is NG";
On the above code, it's only working for $stat_cps
*stat_cps and acc_idss is from radio button form.
Anyone can give the suggestion?
"One-line" solution with array_merge, implode and strpos functions:
...
$hasNg = strpos("NG", implode(",", array_merge($stat_cps,$acc_idss)));
...
// check for 'NG' occurance
echo ($hasNg !== false)? "One of the field is NG" : "string 'NG' doesn't exists within passed data";
You can use array_merge to combine both your arrays:
http://php.net/manual/en/function.array-merge.php
$stat_cps = $_POST['stat_cp'];
$acc_idss = $_POST['acc_ids'];
$merged = array_merge($stat_cps,$acc_idss);
$string = 'NG';
foreach ($merged as $url)
{
if(strpos($string, $url) !== FALSE)
{
echo "One of the field is NG";
return true;
}
}
This will remove duplicate string keys but it doesn't look like that should be an issue here if you just want one match
From you comment try doing
$stat_cps = $_POST['stat_cp'];
$acc_idss = $_POST['acc_ids'];
$merged = array_merge($stat_cps,$acc_idss);
$match = false;
$string = 'NG';
foreach ($merged as $url)
{
if(strpos($string, $url) !== FALSE)
{
$match = true;
}
}
if($match){
echo "One of the field is NG";
}else{
echo "Everything is OK";
}
$stat_cps = $_POST['stat_cp'];
$acc_idss = $_POST['acc_ids'];
$process=0;
$string = 'NG';
foreach ($stat_cps as $url)
{
if(strpos($string, $url) !== FALSE)
{
$process=1;
}
}
foreach ($acc_idss as $url2)
{
if(strpos($string, $url2) !== FALSE)
{
$process=1;
}
}
if($process==1){
echo "One of the field is NG";
return true;
}
#header user in_array()
$stat_cps = $_POST['stat_cp'];
$acc_idss = $_POST['acc_ids'];
$string = 'NG';
foreach ($stat_cps as $url)
{
if(in_array($string, $url) !== FALSE)
{
echo "One of the field is NG";
return true;
}
}

Convert multidimensional array keys to string

I have a multidimensional array like this:
$array1['first']='myvalue1';
$array1['second']=array();
$array1['second']['first']='myvalue21';
$array1['second']['second']='myvalue22';
$array1['second']['third']=array();
$array1['second']['third']['first']='myvalue231';
$array1['second']['fourth']='myvalue24';
$array1['third']='myvalue3';
And another array like:
$array2['second-first']='newvalue21';
$array2['second-third-first']='newvalue231';
And I can't get the way to walk $array1 recursively to check, in each iteration, if exist any element in $array2 with a key equivalent to the current element key and their parents converted to string.
To simplify the question, I will have enough with a function that prints something like:
// walking $array1:
first
second-first
second-second
second-third-first
second-fourth
third
Thank you.
Solution based on Clément Malet answer
function print_array_reccur ($array1, $array2, $str = '')
{
foreach ($array1 as $key => $val) {
if (is_array($val)) {
if ($str == '') {
print_array_reccur($val, $array2, $key);
} else {
print_array_reccur($val, $array2, $str . '-' . $key);
}
} else {
if ($str == '') {
$result = $key;
} else {
$result = $str . '-' . $key;
}
if(isset($array2[$result]))
{
echo 'Found $array2['.$result.'] = ' . $array2[$result] . "\n";
}
}
}
}
print_array_reccur ($array1, $array2);
/* OUTPUT:
Found $array2[second-first] = newvalue21
Found $array2[second-third-first] = newvalue231
*/
I really didn't understand what you wanted in the very end, and what you want to achieve later on with your second array.
But since you are looking for a way to print something (glad you simplified that way), here it is :
$array1['first']='myvalue1';
$array1['second']=array();
$array1['second']['first']='myvalue21';
$array1['second']['second']='myvalue22';
$array1['second']['third']=array();
$array1['second']['third']['first']='myvalue231';
$array1['second']['fourth']='myvalue24';
$array1['third']='myvalue3';
function print_array_reccur ($array, $str = '') {
foreach ($array as $key => $val) {
if (is_array($val)) {
if ($str == '') {
print_array_reccur($val, $key);
} else {
print_array_reccur($val, $str . '-' . $key);
}
} else {
if ($str == '') {
echo $key . "\n";
} else {
echo $str . '-' . $key . "\n";
}
}
}
}
print_array_reccur ($array1);
Output :
first
second-first
second-second
second-third-first
second-fourth
third

in_array function, why this doesn't work?

I'm trying to validate a string to an array of numbers. If the string only contains numbers then the function should validate, but in_array isn't working, any suggestions?
$list = array(0,1,2,3,4,5,6,7,8,9);
$word = 'word';
$split = str_split($word);
foreach ($split as $s) {
if (!in_array($s, $list)) {
print 'asdf';
}
}
here is the class:
class Validate_Rule_Whitelist {
public function validate($data, $whitelist) {
if (!Validate_Rule_Type_Character::getInstance()->validate($data)) {
return false;
}
$invalids = array();
$data_array = str_split($data);
foreach ($data_array as $k => $char) {
if (!in_array($char, $whitelist)) {
$invalids[] = 'Invalid character at position '.$k.'.';
}
}
if (!empty($invalids)) {
$message = implode(' ', $invalids);
return $message;
}
return true;
}
}
in_array comparison with loosely typed values is somewhat strange. What would work in your case is:
$list = array('0','1','2','3','4','5','6','7','8','9');
$word = 'word';
$split = str_split($word);
foreach ($split as $s) {
if (!in_array($s, $list, true)) {
print 'asdf';
}
}
This compares strings with strings and results in no surprises.
But, as noted in the comments already, this is quite wrong way to do things and it is much better to use filter_var() or regular expressions** to achieve what you're trying.
it's ugly as sin but it works, no elegant solution here, just a double loop, if you see any problems please let me know
$match = array();
foreach ($data_array as $k => $char) {
foreach ($whitelist as $w) {
if (!isset($match[$k])) {
if ($char === $w) {
$match[$k] = true;
}
}
}
if (!isset($match[$k]) || $match[$k] !== true) {
$invalids[$k] = 'Invalid character at position '.$k.'.';
}
}
Something along the lines of this should work:
<?php
$validate_me = '123xyz';
if(preg_match("/[^0-9]/", $validate_me, $matches))
print "non-digit detected";
?>
update: add the $type = gettype ... settype($char, $type) to allow === to function correctly when checking for integers
foreach ($data_array as $k => $char) {
foreach ($whitelist as $w) {
if (!isset($match[$k])) {
$type = gettype($w);
if (gettype($char) !== $type) {
settype($char, $type);
}
if ($char === $w) {
$match[$k] = true;
}
}
}
...

Categories