dalecosp Thanks I'll have a look at that. Typically the if/else case is where there should be a result from querying the database and if it doesn't find what I'm looking for because someone is trying something that isn't what I'm looking for or they say misstyped an item number or the item they are looking for is not in stock then I want to leave the routine that is going to process the thing if it is right. Did that make sense? ie:
if(item is found){
we display the info about said item.
}else{
we go back to the beginning page and you can try again.
}
Also some places there are a couple of choices that could be made for different things. Those are typically you chose the thing or not, which may add up to a variety of choices but the are usually like y/n kind of thing. which then shapes the way the output is formatted or what is included. not really multiple processes. Mostly pretty simple logic. Like did you want to view thumbnails or a list. The process is the same just one instance you see pics the other not. Same query, same results just small differences in the output.

From what I found on the subject it is addressing making what we used to call spagetti code. I really try not to do that.

    NogDog
    Thanks. Yes I realize that the header won't execute if anything has been already sent to the browser. When I want to put an error message or whatever out there I just want it to quit when I'm done. I post the headers, the error or notice, and then the page footer then want it to quit. Either that or I'll pass a code in the headers for the program to post the message when it gets to where the header is taking it.
    So I'll use exit; then and that will totally leave the case, program, loop whatever and be done.

    won't closing the session screw things up if there are session variables that you want to carry along? For example if they are collecting stuff in a shopping cart. Wouldn't closing the session make that in accessible when they went to say another category or the shop front?

    One other Question. If you get a true result from is_object($result) does that mean that there is then one or more $rows available if you do a $row=$result->fetch_object ? or do you still need to ask how many rows there are?

    minifairy

    The session_write_close() does not destroy the session, it just ensures that the current session data is saved before the header()/exit. I'm not sure why, but I've had issues where the $_SESSION does not show any changes made by the redirecting script if I don't do that. 🤷

    A true response will only mean that the query successfully ran without any errors, but says nothing about whether anything in the DB actually matched -- so it could be anything between 0 - n rows. You'd still need a row-count check or such, if you need to know that. (That's one reason you might want to treat a false for the is_object() as an exception, since in theory it should never happen unless there's a bug, as opposed to a potentially valid result of no rows being returned.)

    NogDog
    Ok thanks for that it does clear up a few things. For the most part in the past I just asked if the $result->num_rows>='1' so now that generates the warning ...property of non-object or some such so I added the is_object($result) before that. I was just curious if I still needed the num_rows bit. I haven't removed it but was curious.

    ok so the session_write_close() does not destroy the session that's cool. (something more to add lol) how about secure sessions do they persist if you say go from a secure to non-secure page then say back to a different page that is secure? Would the previous $SESSION variables from the secure session still be intact, assuming the same browser, and it hasn't been shut down or anything yet. Just curious I like the $SESSION variables they make a lot of stuff easier.

      If you're using PHP's session stuff (i.e. using session_start(), I think the only gotcha you need to look out for is the domain and sub-domain being used to access the pages in question. For instance, if one uses "example.com" and another uses "www.example.com" (or "secure.www.example.com", etc.), the session cookie might not be sent by the browser. Therefore, if you in fact want the session to persist across all possible sub-domains, you may want to either use session_set_cookie_params() to set the domain a ".example.com" (note leading dot), or do so in your PHP environment via the session.cookie_domain setting.

      5 days later

      NogDog Thank you. You are most helpful and I greatly appreciate it.

      One thing that I am finding confusing of late chasing down these php 7 notices. Getting the undefined index on $POST variables I thought that if it was POSTed from a form that the variable was defined but if nothing was entered it would be empty ie '' unless specifically set to NULL is this not true? I have always tested for empty $POST values if it was something I needed to know but expected them to be empty if not entered. Now I'm getting these warnings if I say try to insert them in a query to a file or various other things if they are not set to an actual value.

      So if I need to ask if(isset($_POST['xxx']) does this follow with the is_object from above that if it isset it doesn't necessarily have a value??? Seems if I have to ask if it isset that should mean it does have a value?

        One "gotcha" is checkboxes: if unchecked, they're not sent at all, so you'll need to do an isset() or !empty() check on them before trying to use them. In general, it's probably good to check all of the $_POST elements you want to check; since bots, malicious users, incorrect HTML, etc. may cause things to not be as you would normally expect them to be. Where feasible, maybe try to put such checks into a function or such to keep the code D.R.Y.

          As NogDog said; you can't assume anything about the contents of $_POST nor whatever elements it may or may not have; it's user input: it could be anything.

          Well, you can assume that it's given to you as an array of strings. isset($_POST['foo']) is enough to determine if an element named foo is present; its value won't be null, because that isn't a string, and that is the only way the array could contain an element that isset would return false for (think of null as meaning "value explicltly absent").

          My rule of thumb is: if I have to check the type of a variable in order to avoid an error, then I should look upstream to see if I can avoid assigning the variable a value of the wrong type in the first place. Treat the cause rather than the symptom.

            Thanks guys.

            I do try to check what is coming in and to use the escape function on everything but I was sort of confused when I'm trying to check some $POST things and I'm getting an undefined index warning. Like I might have something like if($POST['xxx']=='print') do such and such. Well if its not 'print' I'm typically throwing it away or doing a display page in this case but if I'm getting an undefined index when I know that 'xxx' was in the form it was just weird I thought it would be empty or set to something. The check boxes thing could be the case in some of them.

            The function idea is a good one I do try to put things in functions when its something that I re-use. I'm learning a lot of stuff on this quest to eliminate warnings. Hopefully the code will be better in the end, but it does help with the logic if I understand it better.

            Thanks again.

              Ok still plugging away on what is set/defined and what is not.
              I'm updating a table in one db based on info from another db. In this case I'm updating a mailing list based on customers that have recently purchased. So I collect the customer info (which was already checked and validated) from the db that keeps the sales, customers, etc. And I put it into an array incrementing $x as I go.

              $mlist[$x]=$row->id."|".$row->email."|".$row->fname."|".$row->lname."|".$row->bonus."|".$custtype."|";

              then I close that connection and open the connection to the other db and step through all the $x's in a for loop.
              exploding each $mlist[$x] on '|' $cust=explode('|',$mlist[$x])

              Now the question comes. I've just loaded 6 elements into this array. Some of them could be NULL (ie bonus doesn't apply to everyone) , however, the index should be defined should it not? ie: $cust[4] should be defined although it could be 5.00 or could be 0 or could be NULL. Is this not correct? Yet I'm getting notices like index 4 not defined

              minifairy

              We may need to see the exact error message text, along with the line of code it references with any preceding lines we may need to see how/where that index (hypothetically) was set -- preferably wrapped in this forum's [code]...[/code] tags for readability. Maybe you just need a foreach() loop instead of a for() loop, so that you only iterate on existing indexes?

              PS: not sure if this might be the case without some debugging, but depending on how you are testing and what the PHP type is of the value in question, a value of "0" will return true from empty() and true from isset(), but an actual null will be true from empty() but false from isset() -- however, it should still be "defined", i.e. not throwing a warning.

              NogDog
              Thanks. Yes that is what I thought it should not throw a warning. I was looking for that code bit but didn't see it as an option thought maybe it had been removed on this new update of the forum. So here is the code that I was working on at the time I asked that question.

              $custshop=(isset($cnfig['cust_shop']))?$cnfig['cust_shop']:$_SESSIOn['shop'];
              		$query="select bonus.id, bonus.custid, bonus.bonus, bonus.wdisc,cust.lname, cust.fname, cust.email, bonus.pdate,bonus.maillist from `bonus`, `cust` where bonus.custid=cust.id and bonus.shop='".$custshop."'and cust.email!=''";
              		$x=1;
              		$result=querymeres($query);
              		if(is_object($result)and $result->num_rows>='1'){
              			while($row =$result->fetch_object()){
              				if($row->wdisc>"1"){
              					$custtype="wholesale";
              				}else{
              					$custtype="retail";
              				}
              				#accumulate the ones to be updated into an array. and update bonus file.
              				if(($row->pdate>$row->maillist )| $row->maillist==NULL){#recent purchase
              				$mlist[$x]=$row->id."|".$row->email."|".$row->fname."|".$row->lname."|".$row->bonus."|".$custtype."|";
              				$queryub="update `bonus` set `maillist`='".$tday."' where `id`='".$row->id."'";
              				queryme($queryub);
              				$x++;
              				}
              			}
              			mysqli_close($mysqli);
              			#now update the mailing list.
              			include('./bits/connect.dada.php');
              			for($m=1;$m<=$x-1;$m++){
              				$custinfo=explode('|',$mlist[$m]);
              				$queryf="select * from `dada_subscribers` where `email`='".$custinfo[1]."' and `list`='".$cnfig['mlist']."'";
              				$resultf=querymeres($queryf);
              				if(is_object($resultf)and $resultf->num_rows>='1'){;
              					$queryu="update `dada_profile_fields` set `firstname`='".$custinfo[2]."', `lastname`='".$custinfo[3]."',`choice1`='".$custinfo[4]."',`choice2`='".$custinfo[5]."',`sub_source`='".substr($cnfig['domain'],0,-4)."Sales',`choice3`=NOW() where `email`='".$custinfo[1]."'";
              					echo $custinfo[1]." Name and Date Updated<br>\n";
              					queryme($queryu);
              				}else{
              					$query2="insert into `dada_subscribers` (`email`,`list`,`list_type`,`list_status`)values('".$custinfo[1]."','".$cnfig['mlist']."','list','1')";
              					echo $custinfo[1]." Added to list<br>\n";
              					queryme($query2);
              					$queryf2="select * from `dada_profile_fields` where `email`='".$custinfo[1]."'";
              					$resultf2=querymeres($queryf2);
              					if(is_object($resultf2)and $resultf2->num_rows>='1'){;
              						$queryu2="update `dada_profile_fields` set `firstname`='".$custinfo[2]."', `lastname`='".$custinfo[3]."',`choice1`='".$custinfo[4]."',`choice2`='".$custinfo[5]."',`sub_source`='".substr($cnfig['domain'],0,-4)."Sales',`choice3`=NOW() where `email`='".$custinfo[1]."'";
              						queryme($queryu2);
              					}else{
              						$query3="insert into dada_profile_fields (`email`,`firstname`,`lastname`,`choice1`,`choice2`,`sub_source`,`choice3`)values('".$custinfo[1]."','".$custinfo[2]."','".$custinfo[3]."','".$custinfo[4]."','".$custinfo[5]."','".substr($cnfig['domain'],0,-4)."Sales', NOW())";
              						queryme($query3);
              					}
              				}
              			}
              			mysqli_close($mysqli);
              

              as for the exact warning. Well I've been trying to eliminate these warnings and I delete the error log as I go so all I can tell you is as near as I recall. It said "index 5 undefined" or "index 4 undefined" either of which could easily be NULL or ''. As I recall I eliminated the warning by adding another | to the end of the array load. So would it not comeback as set if it is the last item in the explode and is say NULL or ''?

              bonus  Index 	decimal(6,2) 	can be NULL
              wdisc  Index 	float(5,2)  defaults to 0.00 but also set as can be NULL
                  pdate                       date           can be NULL
                 maillist 	               date             can be NULL

              OH I'm running Bitnami on my local machine. PHP version: 7.1.19

              I always get the weird stuff.

                The join-explode thing is a waste of effort - taking pieces and putting them together, but the only thing being done with the string is taking it apart and getting the pieces back.

                Instead of

                $mlist[$x]=$row->id."|"....$custtype."|";
                for($m=1; $m<=$x-1; $m++) {...
                $custinfo=explode('|',$mlist[$m]);
                echo $custinfo[1]

                Have

                $customers[]=['id' => $row->id, ..., 'custtype' => $custtype];
                foreach($customers as $custinfo) {...
                
                echo $custinfo['email'];

                Even better, the whole "convert wdisc to custtype" thing could be done by the database, and then the oddity of adding $custtype to the record separately can be avoided. The row object itself can be stored in the array. Then, apart from the update bit (doing a query inside a loop is a code smell), the entire loop collapses into a single fetch_all call. Then iterate over the resulting array.

                As for the update bit, "Update bonus set maillist='".$tday."' where id in (Select b.id from bonus b, cust c where (b.pdate>b.maillist or b.maillist is null) and b.custid=c.id and b.shop='".$custshop."' and c.email<>'') looks like it would do the job but at this stage I wouldn't quote me on that.

                Couple more things from the lines like this: is_object($result)and $result->num_rows>='1'
                and doesn't necessarily mean the same thing as &&, and if you're comparing numbers you should be comparing with numbers, not strings.

                More significantly, in if(($row->pdate>$row->maillist )| $row->maillist==NULL){ the | should be ||.

                Weedpacket Thank you
                The logical operators tend to ellude me sometimes. In the php documentation I don't see the difference between '&&' and 'and' in the table of operators and precedence they are both listed as left and logical. The || is listed as logical as is the 'or' the | as bitwise. I don't exactly understand the bitwise one. I comprehend that it is compared a bit at a time but that doesn't really help me much. I for sure should be using the logical one.

                As for the wdisc bit I'm basically converting that because the database is storing a discount value and it can be different for different customers but they are still wholesale customers. Their status is stored by the database as in the amount of the discount, but suffice it to say that if they have a discount larger that 1 they are wholesale otherwise they are retail. In the mailing list I want to be able to pick out wholesale and retail not have to choose by various discount levels. The routine works but I was just getting warnings on some of the indexes in the exploded array. I would guess that whether I loaded it into a multi dimensional array in the beginning or exploded the array as I step through it the result in that case would be the same. For me loading a single array with the pipe delimiters (|) is easy, and I find it easier to follow in the code. I suppose there is one extra step the exploding but I don't have to worry about overlapping variables with variables already used etc. or come up with something short and sweet to call the secondary keys.

                update bit (doing a query inside a loop is a code smell), the entire loop collapses into a single fetch_all call. Then iterate over the resulting array.

                Not sure what you meant by this? the mailing list is a separate db with a separate connect and password not a table in the same db. So not sure how I could fetch it all at once for updating. Which is why I created the first array $mlist and closed the connection before looking for records in the mailing list.

                minifairy in the table of operators and precedence they are both listed as left and logical.

                But and has significantly lower precedence.

                minifairy Not sure what you meant by this? the mailing list is a separate db with a separate connect and password not a table in the same db.

                I'm talking about this update:

                		$queryub="update `bonus` set `maillist`='".$tday."' where `id`='".$row->id."'";
                

                I assumed the bonus table was in the same database as the bonus table.

                minifairy The routine works but I was just getting warnings on some of the indexes in the exploded array. I would guess that whether I loaded it into a multi dimensional array in the beginning or exploded the array as I step through it the result in that case would be the same. For me loading a single array with the pipe delimiters (|) is easy, and I find it easier to follow in the code. I suppose there is one extra step the exploding but I don't have to worry about overlapping variables with variables already used etc. or come up with something short and sweet to call the secondary keys.

                "Easy" is a matter of debate but in that very same paragraph you say you were having problems with it.

                I was suggesting this bit:

                $custshop=(isset($cnfig['cust_shop']))?$cnfig['cust_shop']:$_SESSIOn['shop'];
                		$query="select bonus.id, bonus.custid, bonus.bonus, bonus.wdisc,cust.lname, cust.fname, cust.email, bonus.pdate,bonus.maillist from `bonus`, `cust` where bonus.custid=cust.id and bonus.shop='".$custshop."'and cust.email!=''";
                		$x=1;
                		$result=querymeres($query);
                		if(is_object($result)and $result->num_rows>='1'){
                			while($row =$result->fetch_object()){
                				if($row->wdisc>"1"){
                					$custtype="wholesale";
                				}else{
                					$custtype="retail";
                				}
                				#accumulate the ones to be updated into an array. and update bonus file.
                				if(($row->pdate>$row->maillist )| $row->maillist==NULL){#recent purchase
                				$mlist[$x]=$row->id."|".$row->email."|".$row->fname."|".$row->lname."|".$row->bonus."|".$custtype."|";
                				$queryub="update `bonus` set `maillist`='".$tday."' where `id`='".$row->id."'";
                				queryme($queryub);
                				$x++;
                				}
                			}
                

                becoming this:

                $custshop = $cnfig['cust_shop'] ?? $_SESSIOn['shop']; // "$SESSIOn"?
                
                $list_query = "Select
                	bonus.id,
                	bonus.custid,
                	bonus.bonus,
                	IF(bonus.wdisc>1, 'wholesale', 'retail') AS wdisc,
                	cust.lname,
                	cust.fname,
                	cust.email,
                	bonus.pdate,
                	bonus.maillist
                From
                	bonus,
                	cust
                Where
                	bonus.custid=cust.id
                	and bonus.shop='$custshop'
                	and cust.email!=''
                	and (bonus.maillist is null or bonus.pdate > bonus.maillist)";
                	// Apparently pdate can also be null. What is supposed to happen here if it is?
                
                $result = querymeres($list_query);
                
                $mlist = $result->fetch_all(MYSQLI_ASSOC);
                
                if(!empty($mlist))
                {
                	$ub_query = "Update bonus set maillist='$tday'
                	Where id in (" . join(', ', array_column($mlist, 'id')) . ")";
                	queryme($ub_query);
                }
                

                And then in the next part

                for($m=1;$m<=$x-1;$m++)
                {
                	$custinfo=explode('|',$mlist[$m]);
                

                would be

                foreach($mlist as $custinfo)
                {
                

                and things like $custinfo[2] would be $custinfo['fname']. Names provided automatically.

                Weedpacket Ok thanks
                I see that now. Never thought of the bit for wdisc that you did. That would be good. Also have never really used the associative array. always used the $row->field name form so that is an interesting variation.

                The $SESSIOn is a typo that could be part of my issue with the whole thing. Funny that didn't generate a warning.
                not familiar with the form of your statement there, however, and what if cust_shop is not defined in $cnfig don't I need to check for that (it is not defined in all instances)

                $custshop = $cnfig['cust_shop'] ?? $_SESSIOn['shop'];

                Yes pdate can be NULL I pretty much overlooked if it and maillist are NULL basically if they are both NULL I want to ignore that record.

                I need to really look at this example more. I have trouble with the join statement. I need to work with it more and get to understand it better. I know there are times it would be a better way than the way I am doing it but usually I don't have the time to really fiddle with it. I read and re-read the join info in the mysql book and think I have it but not always. The outside and inside joins, left and right.

                Thank you for your time and effort I really do appreciate it.

                minifairy The $SESSIOn is a typo that could be part of my issue with the whole thing. Funny that didn't generate a warning.
                not familiar with the form of your statement there, however, and what if cust_shop is not defined in $cnfig don't I need to check for that (it is not defined in all instances)

                Null Coalescing Operator

                Weedpacket
                Thanks again.
                OH WOW that shortens it up. Brand new in php7 no wonder I had no idea.

                If only I had more time to study it but alas I'm an artist and part time programmer. Really need to get back to the art at the moment. Never enough hours in a day.

                  Write a Reply...