I am trying to search and check for the duplicate details that is available in the database using php.The user enters several names and then a phone number to check for the duplicates. Below is my function. I just cropped out some parts because it was too long.
function gtc($names,$phone)
{
$pageNumb=20;
$position = array(5);
$sepname=explode(",","$names");
foreach ($sepname as $sepname1)
{
for ($page=0;$page<=$pageNumb;$page=$page + 1)
{
$turl="http://192.168.111.2119/search.php?qry=$sepname1&page=$page";
$search=curl_init();
curl_setopt($search,CURLOPT_URL,$turl);
curl_setopt($search,CURLOPT_RETURNTRANSFER,1);
curl_setopt($search,CURLOPT_FAILONERROR,true);
curl_setopt($search,CURLOPT_AUTOREFERER,true);
$result=curl_exec($search);
$dom = new DOMDocument();
#$dom->loadHTML($result);
$xpath=new DOMXPath($dom);
$elements = $xpath->evaluate("//div[#id='inf']");
foreach ($elements as $element)
{
$position[$sepname1] = $position[$sepname1] + 1;
foreach($position as $key=>$val)
$contct = $element->getElementsByTagName("contact")->item(0)->nodeValue;
if (preg_match("/$phone/i",$contct)) {
echo "Found In Database>";
}
}
ob_flush();
flush();
}
}
}
?>
The function works perfectly but the only problem that I am having is although a match is found it goes until the last page which is given in the for loop and then goes through the next name. I would like to know is it possible to make when a match is found stop processing and then search for the next name?
I don’t want to use exit(); because it completely stops the execution
The input format is as below
User inputs names: john, Sam, Michael, Steve
Phone number:0084554741
Any help will be appreciated
You are likely looking for break
break ends execution of the current for, foreach, while, do-while or switch structure.
// output numbers 1,2,3,4
foreach( range(1,10) as $number) {
if($number === 5) break;
echo $number, PHP_EOL;
}
and/or continue
continue is used within looping structures to skip the rest of the current loop iteration and continue execution at the condition evaluation and then the beginning of the next iteration.
// output only even numbers
foreach( range(1,10) as $number) {
if($number % 2) continue;
echo $number, PHP_EOL;
}
#Gordon offered the formally correct answer, a "best practices" answer would be to split your function into logical parts (especially as you mention it's too long), for example:
function search($term) {
$xml = loadXmlFromRemoteHost();
if(!$xml)
echo "An error occured";
$found = findTermInXml($xml, $term);
if($found)
echo "Found In Database>";
The search function contains the loop in question and uses "return" to exit the loop (and the function) when it finds something:
function findTermInXml($xml, $term) {
foreach(...whatever...) {
if(...some condition...)
return true;
}
return false; // nothing found
}
Take a look at:
http://pl.php.net/break
http://pl.php.net/continue
Related
i'm sorry if my english not good.
I have a problem in my code. how I can stop access when in my array have duplicate. I mean, when one or more data in array have duplicate, user must repeat input from first page. and when array have not duplicate, user can access next page.
this is my code I have try.
$no_id=array('100100','100200','100300','100200','100200','100100');
$array = array();
foreach ($no_id as $key => $value)
{
if(isset($array[$value]))
{
$array[$value] += 1;
} else
{
$array[$value] = 1;
}
}
foreach ($array as $alert => $n)
{
if($n >= 2)
{
header('location:../../home');
} else
{
header('location:../../questionnair');
}
}
but when found the duplicate data (in array 100100 have two data and 100200 three data), the system still bring user to access questionnair page, not home.
thanks for helping.
I think the main problem is that you should always use exit() after using header() with location, otherwise the page will continue to execute.
This would still cause a problem though if the first value was a unique value as the first loop would always exit;.
You could fix this (only ever call header() if the value is > 2, then the default of all are unique is after the loop), but an alternative is to use array_count_values() which counts how many each value exists in the list and then use max() to find the most occurring one, then test against that...
$no_id=array('100100','100200','100300','100200','100200','100100');
$n = max(array_count_values($no_id));
if($n >= 2)
{
header('location:../../home');
exit;
} else
{
header('location:../../questionnair');
exit;
}
Update:
An alternative and slightly quicker version would be to use your original first loop, but as soon as it detects the value is already set, then it can stop working and just return then...
$no_id=array('100100','100200','100300','100200','100200','100100');
$array = array();
foreach ($no_id as $key => $value)
{
if(isset($array[$value]))
{
header('location:../../home');
exit;
} else
{
$array[$value] = 1;
}
}
header('location:../../questionnair');
exit;
If you just need to check if the array does have dupliate, you can use array_unique and compare the new array with the old array. If the arrays are not the same, it means there are duplicates.
With code:
$no_id = array('100100','100200','100300','100200','100200','100100');
$new_array = array_unique($no_id);
if (count($no_id) == count($new_array)) {
// 2 arrays have same number of items => they are equal => no duplicates
$redirect = "questionnair.php";
} else {
// 2 arrays have different number of items => they are not equal => duplicates
$redirect = "home.php";
}
header("location: {$redirect}");
NOTE
You have to redirect to an another PHP page (ex. home.php and not just home).
First of all, it's simplier to use array_unique function, which will remove all duplicated values.
After that you can make checks, if nothing was changed, then there is no duplicated items.
Like this:
$no_id=array('100100','100200','100300','100200','100200','100100');
$no_id_unique = array_unique($no_id);
if(count($no_id)===count($no_id_unique)){
header('location:../../questionnair');
}else{
header('location:../../home');
}
exit();
Next thing that you using ../ in path which means go to parent directory.
I don't know your environment, but must likely it's a bad idea.
According to documentation it's better to specify full url of page where user must be forwarded:
header("Location: http://www.example.com/home/");
Also, please be aware, that you need to prevent all others output from a script, especcially before the header() call. Read more here.
you can use foreach (array_unique($no_id) as $key => $value)
You can use array_count_values for this, not tested, but could be like:
$counts = array_count_values($no_id);
$duplicate = false;
foreach ($no_id as $value) {
if ($counts[$value] > 1) {
$duplicate = true;
break; // found a duplicate, no need to check further.
}
}
if ($duplicate === true) {
header('location:../../home');
} else {
header('location:../../questionnair');
}
Using array_flip()
$no_id = array('100100','100200','100300','100200','100200','100100');
$no_id_unique = array_flip($no_id);
if(count($no_id) === count($no_id_unique)){
header('location:../../questionnair');
}else{
header('location:../../home');
}
exit();
The typical algorithm of search until found, in PHP and for some arrays where we can't use the language array search functions (I think), could be implemented in this way:
$found = false;
while (list($key, $alreadyRP) = each($this->relatedProducts) && !$found) {
if ($alreadyRP->getProduct()->getId() === $rp->getProduct()->getId()) {
$found = true;
}
}
if (!$found) {
// Do something here
}
Please, take it as pseudocode, I didn't executed it. What I like about it, is that it gracefully stops if it is found what we are looking for.
Now, due to the "each" function is deprecated, I have to code something like this:
$found = false;
foreach ($this->relatedProducts as $alreadyRP) {
if ($alreadyRP->getProduct()->getId() === $rp->getProduct()->getId()) {
$found = true;
break;
}
}
if (!$found) {
// Do something here
}
To put a "break" statement inside a "for" loop is ugly in structured programming. Yes, it is optional, but if we avoid it, the "foreach" will go through all the array, which is not the most efficient way.
Any idea to recover the efficiency and structure that "each" gives in this case?
Thank you.
The beauty of the each() method is in the eye of the beholder, but there are other reasons to prefer foreach, including this interesting bit of information from the RFC that led to the deprecation of each()
The each() function is inferior to foreach in pretty much every imaginable way, including being more than 10 times slower.
If the purpose of the method is to // Do something here if the $rp is not found in $this->relatedProducts, I think a more "beautiful" way to handle it would be to extract the search through related products into a separate method.
protected function inRelatedProducts($id) {
foreach ($this->relatedProducts as $alreadyRP) {
if ($alreadyRP->getProduct()->getId() === $id) {
return true;
}
}
return false;
}
Moving the related products search into a separate method is advantageous because
It separates that functionality from the original method so that it becomes reusable instead of being tied to whatever // Do something here does.
It simplifies the original method so it can focus on its main task
$id = $rp->getProduct()->getId();
if (!$this->inRelatedProducts($id)) {
// Do something here
}
It simplifies the search code because if it's contained in its own method, you can just return true; as soon as you find a match, so you won't need to break, or to keep track of a $found variable at all.
On the other hand, if this was my project I would be looking for a way to remove the need for this method by populating $this->relatedProducts so that it's indexed by ID (assuming ID is unique there) so the determination could be reduced to
$id = $rp->getProduct()->getId();
if (isset($this->relatedProducts[$id])) { ...
If you're looking for a rewrite that doesn't involve extra variables, you can replace the each call with calls to current and next:
do {
$found = (current($this->relatedProducts)->getProduct()->getId() === $rp->getProduct()->getId());
} while (empty($found) && false !== next($array));
This is a mechanical translation, and it relies merely on the definition of each (emphasis mine):
Return the current key and value pair from an array and advance the array cursor
It also suffers the same deficiency of the original each version: it doesn't handle empty arrays.
That said, please don't use each, or any of its siblings, for new code. This from a guy who voted "No" on the RFC! Why? Because the performance sucks:
1017$ cat trial.php
<?php
$array = range(0, 999);
$begin = -microtime(true);
for ($i = 0; $i < 10000; $i++) {
reset($array);
$target = rand(333, 666);
do {
$found = (current($array) === $target);
} while (empty($found) && false !== next($array));
}
printf("%.5f\n", $begin + microtime(true));
$begin = -microtime(true);
for ($i = 0; $i < 10000; $i++) {
$target = rand(333, 666);
foreach ($array as $current) {
if ($current === $target) break;
}
}
printf("%.5f\n", $begin + microtime(true));
1018$ php -d error_reporting=-1 trial.php
8.87178
0.33585
That's nearly nine seconds for the next/current version while not even half a second for the foreach version. Just don't.
It looks like each is basically a version of current() and next()
http://php.net/manual/en/function.current.php
http://php.net/manual/en/function.next.php
each() gives the current array item, and moves to the next index.
current() gives the current array item, but doen't increment the index.
So, you can replace each() with current(), and inside your foreach use next() to shift the index up
next() gives the next item, and increments the index.
while (list($key, $alreadyRP) = current($this->relatedProducts) && !$found) {
if ($alreadyRP->getProduct()->getId() === $rp->getProduct()->getId()) {
$found = true;
}
next($this->relatedProducts);
}
I have a very long list of strings called $stringfilter1 $stringfilter2 etc all the way up to $stringfilter50
I have another string $reporteremail and I want to make a conditional statement whereby if any of the $stringfilter strings is present in the $reporteremail, some code is executed. At the moment my code looks like this and it works:
if (stripos($reporteremail, $stringfilter1) !== false || stripos($reporteremail, $stringfilter2) !== false || stripos($reporteremail, $stringfilter3) !== false [...]) {
runcode();
}
This is very very long though. I have cut it short here.
I was wondering if there's a cleaner, more efficient way to do this?
EDIT:
I am writing a plugin for a bug tracker. The strings are entered on another page in text boxes. I access them on this page by running a function that looks like
$t_filter = plugin_config_get( 'filter1' );
$stringfilter1 = string_attribute( $t_filter1 );
I would agree looping through an array would be the best way to do this. How can I push each new string onto the end of an array without having to write that snippet above out 50 times?
How can I push each new string onto the end of an array without having to write that snippet above out 50 times?
Try this:
$needles = [];
for ($i = 0; $i < 50; $i++) {
$t_filter = plugin_config_get("filter$i");
$needles[] = string_attribute($t_filter);
}
I have a very long list of strings called $stringfilter1 $stringfilter2 etc all the way up to $stringfilter50
[...]
This is very very long though. I have cut it short here.
I was wondering if there's a cleaner, more efficient way to do this?
Try this, it should go after the code block above.
$flag = false;
foreach ($needles as $needle) {
if (stripos($reporteremail, $needle) !== false) {
$flag = true;
break;
}
}
if ($flag) {
runcode();
}
The code above works by iterating through the $needles array and sets a flag if stripos doesn't return false. After it's finished iterating, it checks if the flag is true, if so, this means that one of the needles was found in the array.
EDIT
Alternatively, you could do it all in one loop, which is both faster and more efficient.
$flag = false;
for ($i = 0; $i < 50; $i++) {
$t_filter = plugin_config_get("filter$i");
$needle = string_attribute($t_filter);
if (stripos($reporteremail, $needle) !== false) {
// One of the needles was found in $reporteremail.
runcode();
break;
}
}
You don't need a loop. First put all your filters in an array instead of having them in separate variables. I would try to do this by modifying the input source rather than doing it in your PHP script. (Based on your comments I'm not sure if that's possible or not, so maybe you do need a loop like the one in the other answer.) Then you can use str_ireplace to check for your filter strings in the $reporteremail. (This will not modify $reporteremail.)
str_ireplace($filters, '', $reporteremail, $count);
if ($count) {
// run code
}
The $count parameter will contain a count of how many replacements were performed. If it's nonzero, then at least one of the filters was found in $reporteremail.
I was unable to break out of a foreach loop. I think the structure is correct there is something else wrong with the code. Please let me know what is the issue,(not just a working code) i want to learn from my mistakes. Thanks
I am using simple html dom for scraping some piece of information and i want the loop to break when a condition is matched. Here is my code :
<?php
$mainjob = file_get_html('link to scrap here');
$newarr = array();
foreach($mainjob->find('td[valign=middle]') as $d) {
$data = $d->innertext;
$newarr[] = $data;
echo $data . "<br>";
if($data == "Job Opportunity Description:") {
break;
}
}
print_r($newarr);
1) I guess your $data=="Job Opportunity Description:" condition wasn't true, so it didn't call the break;
2) Put your $mainjob->find('td[valign=middle]') out of your loop conditions, so it doesn't get called each iteration:
$tds = $mainjob->find('td[valign=middle]');
foreach($td as $d){}
3) Why did you add brackets to your $newarr variable?
4) Maybe your $data string still contains the html tags (which aren't shown by echo due to your browser.. so the condition would return false.
The problem is in the white space i used trim() to trim out the white space and it works. I recommend the answer from Ayman Safadi. Thanks.
I am learning how to build a parent/child category list. I found a great tutorial and have implemented the following code:
while($row = $tree_sth->fetch()){
$rows[$row['id']] = array('name'=>$row['name'], 'on'=>$row['on'], 'parent'=>$row['parent']);
}
function btree($parent){
$has_childs = false;
global $rows;
foreach ($rows as $key => $value){
if($value['parent'] == $parent){
if ($has_childs === false){
$has_childs = true;
echo '<ul>';
}
echo '<li>'.$value['name'];
btree($key);
echo '</li>';
}
}
if($has_childs === true){
echo'</ul>';
}
}
What I am having trouble understanding is how the foreach and recursive function is handled by PHP.
It appears that this causes multiple "instances??" of the function and foreach loop to run simultaneously... Is that correct?
If this is what is happening, it seems this may slow down as my list grows and child relationships get deeper. Is this true?
The short, short version is that the function is working this way:
Begin-function (first instance):
Begin-loop:
Loop...
Begin-func-again?
Begin-function (second instance):
Begin-loop:
Loop...
Begin-func-again?
Begin-function (third instance):
Begin-loop:
Loop...
Begin-func-again? (NO)
// termination point reached
End-loop
End-function (third instance)
End-loop (from second instance)
End-function (second instance)
End-loop (from first instance)
End-function(first instance)
It isn't that there are multiple versions of the function being created simultaneously, they are an expansion and contraction done in order, but they all do stem from the original function call.