I'm trying to figure out what this piece of code is doing:

$text='';
if($struct && $struct->parts) {
	while(list($i, $substruct) = each($struct->parts)) {
		if($partNumber)
			$prefix = $partNumber . '.';
		if(($result=$this->getPart($mid, $mimeType, $encoding, $substruct, $prefix.($i+1))))
			$text.=$result;
	} //end while
}// end if
return $text;

The comments in the code says it is a recursive search and it is at the end of function getPart.

The function getPart searches through the email headers for specific mime type parts.

  • $struct is the result of imap_fetchstructure for the specific message header.

  • $mid is the message ID.

  • $mimeType is the MIME Type being sought after.

  • $encoding is the message's encoding.

I'm mostly confused by the seemingly embedded functions in this line:

while(list($i, $substruct) = each($struct->parts))

This is where my naivete in PHP comes into play. I tried looking at php.net and RTFM, but the entry for "list" doesn't include a good example of the results to help me decipher exactly how it works.

If I knew how to do a return from a foreach statement and continue processing through, this probably wouldn't be necessary.

By that, I mean, say my foreach statement looks like this:

$partNumber = null; //(re)sets $partNumber to null
foreach (new RecursiveIteratorIterator($this->zmail->getMessage($mid)) as $part) {
	$partNumber = $partNumber?$partNumber:1; //if there's a part number use it, otherwise use 1
	if ($text = $mailmsg->getPart($partNumber)->getContent()) {
		$encoding = null; //(re)set encoding to null
		$charset=null; //(re)set $charset as null
		if (isset($part->contenttransferencoding)) { //does the encoding field exist
			$encoding = $part->contenttransferencoding; //get the encoding type
			if ($encoding //if $encoding is NOT null
				&& ($encoding == 'base64' || $encoding == 'quoted-printable')) { //AND if $encoding is either base64 or qp
				$text = $this->decode($text, $encoding); //decode the content accordingly
				$charset = $part->getHeaderField('Content-Type', 'charset'); //determine the $charset to be used
				$text = $this->mime_encode($text, $charset, $encoding); //mime encode the string $text (the decoded content of $partnumber) using the $charset and $encoding method found in the message $part
			}
		} //end if encoding field exists
	} //end if the content of the message can be retrieved (by $partNumber) of the specified message (by $mid)
$partNumber++; //increase $partNumber by 1
return $text;
} // end foreach going through each mail part

Essentially, I get a message header and want to go through each part looking for a specific type of content and when I find it I need to encode/decode it as appropriate and then pass that content on to another function. If I understand my own code correctly 😉, when the code hits the line "return $text" it exits the foreach loop and sends the value of $text back to the calling function, right? Assuming that's correct, how do I send the value of $text back to the calling function without exiting the foreach loop?

Does my question make sense?

Appreciate all the help you guys have offered so far on this little project of mine and am looking forward to your responses to this little inquiry. 🙂

    $struct->parts is an array. each() runs through it, one key=>value pair at a time, and the key is assigned to $i and the value assigned to $substruct by list(). Then the loop operates on that key value pair represented by $i and $substruct.

    Does that help?

      It's an obsolete form from before [man]foreach[/man] was added to the language.

        dalecosp;11038947 wrote:

        $struct->parts is an array. each() runs through it, one key=>value pair at a time, and the key is assigned to $i and the value assigned to $substruct by list(). Then the loop operates on that key value pair represented by $i and $substruct.

        Does that help?

        Thanks, Dale. I knew $struct->parts was an array and on some level understood that each() was working its way through that array, it was what list was doing to $i & $substruct and the if statements that were really throwing me for a loop (no pun intended).

        So, Weedpacket, if it's obsolete, if I drop it, could I expect my foreach statement to do essentially the same thing without missing anything? Am I understanding correctly what happens with that "return $text" statement at the end?

          The equivalent foreach() would be:

          foreach ($struct->parts as $i=>$substruct) {
          
          //do same stuff as before
          
          }//end foreach

            If I knew how to do a return from a foreach statement and continue processing through, this probably wouldn't be necessary.

            Take a look at [man]break/man and [man]continue/man. 🙂

              dalecosp;11038965 wrote:

              Take a look at [man]break/man and [man]continue/man. 🙂

              Funny you should mention those. I looked at those previously, but couldn't figure out how to incorporate them.

              I think I understand break(), especially in switch/case, but I couldn't figure out how to incorporate continue() with return().

                mittra;11038973 wrote:

                Funny you should mention those. I looked at those previously, but couldn't figure out how to incorporate them.

                [man]continue[/man] skips the current iteration of the loop, and continues at the beginning of the next iteration. [man]break[/man] stops the loop completely and moves on to the next line of code.

                mittra;11038973 wrote:

                … I couldn't figure out how to incorporate continue() with return().

                Unless you're doing something else after the loop (and before you return), then there is no need: simply use [man]return[/man].
                To clarify:

                <?php
                
                function pointless_use_of_break(){
                    $a = array( 0,1,2,3,4,5,6,7,8,9 );
                    shuffle( $a );
                    foreach( $a as $i ){
                        if( $i > 4 ){
                            break;
                        }
                    }
                    return $i;
                }
                
                // as compared to:
                
                function no_need_to_use_break(){
                    $a = array( 0,1,2,3,4,5,6,7,8,9 );
                    shuffle( $a );
                    foreach( $a as $i ){
                        if( $i > 4 ){
                            return $i;
                        }
                    }
                }
                
                // or
                
                function use_break_if_you_need_to_do_something_else_after_loop_and_before_return(){
                    $a = array( 0,1,2,3,4,5,6,7,8,9 );
                    shuffle( $a );
                    foreach( $a as $i ){
                        if( $i > 4 ){
                            break;
                        }
                    }
                    $a2 = array( 'zero','one','two','three','four','five','six','seven','eight','nine' );
                    $s = "The first number found greater than four was {$a2[$i]}";
                    return $s;
                }

                  Okay, so the existing code I am trying to modify keeps sticking these segments in that are supposed to perform a recursive search, but I'm not sure how to incorporate those segments in because Zend\Mail doesn't have a direct replacement for imap_fetchstructure, so I can't just insert the Zend equivalent into my modified code and be done with it.

                  I may not be explaining what I'm trying to do very well.... let me try it this way:

                  My function is supposed to go through each part of a multipart message and find the attachments. If it finds one, it's supposed to return the attachment's name.

                  So supposed I have a message with more than one attachment?

                  My code looks kind of like this:

                  function getAttachments($msg, $index=0) {
                  	foreach (new RecursiveIteratorIterator($mail_msg) as $msg_part) {
                  		$filename = false;
                  		if (isset($msg_part->contentdisposition)) {
                  			if(in_array(strtolower(strtok($msg_part->contentdisposition, ';')),array('attachment', 'inline'))){
                  				$filename = $msg_part->getHeaderField('Content-Disposition', 'filename');
                  			}
                  		}
                  
                  	if ($filename) {
                  		return $filename;
                  	}
                  
                  }
                  }
                  
                  $mid = $mail->countMessages();
                  foreach ($mail as $message) {
                      $msg = $mail->getMessage($mid);
                      $attachments = getAttachments($msg);
                      print($attachments);
                      $mid--;
                  }
                  

                  Let's assume for a moment that I have a message that has an inline image within the body of the message and then a document attached. If I understand how the message parts work, it might look something like this:

                  Part 1: text
                  Part 2: inline image
                  Part 3: text
                  Part 4: attached document

                  Now, if I understand my code correctly, it would go to the getAttachments function and it would ignore Part 1, then it would identify the attachment in Part 2 and exit the function (return) with the filename and completely skip even looking at Part 3 and Part 4. Am I understanding that correctly?

                  How would I use break() and continue() to make sure to go back and look at Part 3 and Part 4?

                    Write a Reply...