I hate to post a thread on this since I know this topic has been discussed ad nauseum, but I've been searching for weeks and cannot find exactly the answer I've been looking for. I'm new to arrays and loops - I get the concept, but not the syntax.

Here's my conundrum: I have a list of email contacts in my DB (MySQL). I can query the DB, list every contact that has opted in, it displays as desired on my screen, I can put in an email address as "from", a message and upload an image and I can send all to one contact. Works just fine. Only took me two weeks to write that. :)

I figured if I could get one email to work, it would be an easy transition to select multiple "TOs". I've done it with comma separated inputs, easy peasy. BUT, to select from the DB and send has got me stumped. I'm pretty sure it is a combo of my lack of array/foreach/checkbox knowledge.

(If you don't recognize the mail() function, it's a PEAR module to help with file uploads => MIME types.)

Here's my code (not working); any help, as always, is appreciated.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>
<head>
<title>Test Email Distro</title>

<style>
label,a, body 
{
	font-family : Arial, Helvetica, sans-serif;
	font-size : 12px; 
}
</style>

<!-- Java form validation-->
<script language="JavaScript" src="scripts/gen_validatorv31.js" type="text/javascript"></script>	
</head>

<body>
<?php
if(!empty($errors))
{
	echo nl2br($errors);
}
?>
<form method="POST" name="testing.php" 
action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" enctype="multipart/form-data"> 
<p>
<label for='name'>Name: </label><br>
<input type="text" name="name" >
</p>
<p>
<label for='email'>Email: </label><br>
<input type="text" name="vemail" >
</p>
<p>
<label for='message'>Message:</label> <br>
<textarea name="message"></textarea>
</p>

<?php
mysql_connect($hostname,$username,$password);
mysql_select_db($dbname) or die("Unable to select database");
$query="SELECT * FROM userlist WHERE substat = 'optin'";
$result=mysql_query($query);
$num=mysql_numrows($result);


echo "<table border='1'>
<tr>
<th>Select to Mail</th>
<th>First Name</th>
<th>Email</th>
<th>Opt-In Status</th>
</tr>";

while ($row = mysql_fetch_array($result))
{
echo "<tr>";
echo "<td><input type='checkbox' name='contacts[]' value='contacts[]'></td>";
echo "<td>" . $row['other'] . "</td>";
echo "<td>" . $row['email'] . "</td>";
echo "<td>" . $row['substat'] . "</td>";
echo "</tr>";
}
echo "</table>";

?>
<p>
<label for='uploaded_file'>Select A File To Upload:</label> <br>
<input type="file" name="uploaded_file">
</p>
<input type="submit" value="Submit" name='submit'>
</form>

<?
//File Upload Settings 
$max_allowed_file_size = 100; // size in KB 
$allowed_extensions = array("jpg", "jpeg", "gif", "bmp", "png");
$upload_folder = './uploads/'; //<-- this folder must be writeable by the script
$your_email = 'jarett@thumbstakes.com';//<<--  update this to your email address

$errors ='';

if(isset($_POST['submit']))
{
	//This gets the uploaded file information
	$name_of_uploaded_file =  basename($_FILES['uploaded_file']['name']);
	
	//get the file extension of the file
	$type_of_uploaded_file = substr($name_of_uploaded_file, 
							strrpos($name_of_uploaded_file, '.') + 1);
	
	$size_of_uploaded_file = $_FILES["uploaded_file"]["size"]/1024;
	
	//Validations
	if(empty($_POST['name'])||empty($_POST['email']))
	{
		$errors .= "\n Name and Email are required fields. ";	
	}
	if(IsInjected($visitor_email))
	{
		$errors .= "\n Bad email value!";
	}
	
	if($size_of_uploaded_file > $max_allowed_file_size ) 
	{
		$errors .= "\n Size of file should be less than $max_allowed_file_size";
	}
	
	//Validate the file extension
	$allowed_ext = false;
	for($i=0; $i<sizeof($allowed_extensions); $i++) 
	{ 
		if(strcasecmp($allowed_extensions[$i],$type_of_uploaded_file) == 0)
		{
			$allowed_ext = true;		
		}
	}
	
	if(!$allowed_ext)
	{
		$errors .= "\n The uploaded file is not supported file type.".
		"Only the following file types are supported: ".implode(',',$allowed_extensions);
	}
	
	//upload the file 
	if(empty($errors))
	{
		//copy the temp. uploaded file to uploads folder
		$path_of_uploaded_file = $upload_folder . $name_of_uploaded_file;
		$tmp_path = $_FILES["uploaded_file"]["tmp_name"];
		
		if(is_uploaded_file($tmp_path))
		{
		    if(!copy($tmp_path,$path_of_uploaded_file))
		    {
		    	$errors .= '\n error while copying the uploaded file';
		    }
		}
		
		//THIS IS WHERE, I SUSPECT, IS MY DOWNFALL
		$contacts = array('other', 'email', 'substat');
		foreach ($contacts as $email) {
		$email = $to;

		if($contacts=='1')
	{
		$to = $_POST['email'];
		$name = $_POST['name'];
		$visitor_email = $_POST['vemail'];
		$user_message = $_POST['message'];
		$subject="New form submission";
		$from = $your_email;
		$text = "A user  $name has sent you this message:\n $user_message";
	
		$message = new Mail_mime(); 
		$message->setHTMLBody($text); 
		$message->addHTMLImage($path_of_uploaded_file);
		$body = $message->get();
		$extraheaders = array("From"=>$from, "Subject"=>$subject,"Reply-     To"=>$visitor_email);
		$headers = $message->headers($extraheaders);
		$mail = Mail::factory("mail");
		$mail->send($to, $headers, $body);
		//redirect to 'thank-you page
		header('Location: thank-you.html');
}
}
}
}
///////////////////////////Functions/////////////////
// Function to validate against any email injection attempts
function IsInjected($str)
{
  $injections = array('(\n+)',
              '(\r+)',
              '(\t+)',
              '(%0A+)',
              '(%0D+)',
              '(%08+)',
              '(%09+)'
              );
  $inject = join('|', $injections);
  $inject = "/$inject/i";
  if(preg_match($inject,$str))
    {
    return true;
  }
  else
    {
    return false;
  }
}
mysql_close();
?>


<script language="JavaScript">
// Code for validating the form
// Visit http://www.javascript-coder.com/html-form/javascript-form-validation.phtml
// for details
var frmvalidator  = new Validator("testing.php");
frmvalidator.addValidation("name","req","Please provide your name"); 
frmvalidator.addValidation("email","req","Please provide your email"); 
frmvalidator.addValidation("email","email","Please enter a valid email address"); 
</script>
</body>
</html>

Recommended Answers

All 7 Replies

Hi all, just wanted to give this a bump. Any and all suggestions welcome and appreciated!

Thanks

gj

currently I see the following on line 148: $to = $_POST['email']; but on line 33 you have: <input type="text" name="vemail" > Notice that the name of the input text box does NOT match the key in the $_POST array. If you fix the name of the input field (get rid of that "v"), then you should be able to type a comma-separated list of email addresses and all of them will get the same email message.

As far as the foreach goes, given this:

$contacts = array('other', 'email', 'substat');
foreach ($contacts as $email) {
  $email = $to;
}

A. assigning the variable $to to the varialbe $email doesn't make sense since on the very first time that statement is executed $to doesn't exist at that point.

B. as far as understanding arrays, it will make more sense if you can see/understand that this:

$contacts = array('other', 'email', 'substat');

is equivalent to:

$contacts = array('0'=>'other', '1'=>'email', '2'=>'substat');

Armed with that knowledge, look up the foreach on the manual:
http://us3.php.net/manual/en/control-structures.foreach.php

Notice the second syntax?
So basically if you do:

$contacts = array('other', 'email', 'substat');
foreach($contacts as $index=>$value)
{
  echo $index.'='.$value.'<br/>';
}
//output should be:
0=other
1=email
2=substat

So, I hope that clarifies how the foreach works.

C. As far as your project goes, I suspect what you actually want is for the user to be able to check multiple users and then email only the checked individuals. If that is the case, then the problem is in the checkbox you are generating. Given this:

while ($row = mysql_fetch_array($result))
{
echo "<tr>";
echo "<td><input type='checkbox' name='contacts[]' value='contacts[]'></td>";
echo "<td>" . $row['other'] . "</td>";
echo "<td>" . $row['email'] . "</td>";
echo "<td>" . $row['substat'] . "</td>";
echo "</tr>";
}

/*
If you look at the browser's source code, it should be generating something SIMILAR to:
<tr><td><input type="checkbox" name="contacts[]" value="contacts[]"/></td><td>A</td><td>a@b.com</td><td>W</td></tr>
<tr><td><input type="checkbox" name="contacts[]" value="contacts[]"/></td><td>B</td><td>b@b.com</td><td>X</td></tr>
<tr><td><input type="checkbox" name="contacts[]" value="contacts[]"/></td><td>C</td><td>c@b.com</td><td>Y</td></tr>
<tr><td><input type="checkbox" name="contacts[]" value="contacts[]"/></td><td>D</td><td>d@b.com</td><td>Z</td></tr>
*/

since ALL your checkboxes have exactly the same value, you will not be able to know which item the user checked. What you need to do is provide a unique value foreach checkbox. You can even provide both a UNIQUE key in the name attribute of the checkbox, and a unique value in the value attribute - ex:

<tr><td><input type="checkbox" name="contacts[a@b.com]" value="77"/></td><td>A</td><td>a@b.com</td><td>W</td></tr>
<tr><td><input type="checkbox" name="contacts[b@b.com]" value="32"/></td><td>B</td><td>b@b.com</td><td>X</td></tr>
<tr><td><input type="checkbox" name="contacts[c@c.com]" value="12"/></td><td>C</td><td>c@b.com</td><td>Y</td></tr>
<tr><td><input type="checkbox" name="contacts[d@d.com]" value="45"/></td><td>D</td><td>d@b.com</td><td>Z</td></tr>

On that html example, the idea is that every user will have a unique id and a unique email address in the database. The id is in the VALUE of the checkbox, and the email address is the index in the contacts array. Why did I use an email as the string and not the numeric id? Because I can!!! I am trying to make a point. You are NOT limited to numeric indexes! But if you want to swap them it is perfectly OK as well.

So given the markup I presented above, once submitted only the checked items will be sent to the server. Assuming I checked A and C, then you can do the following:

foreach($_POST['contacts'] as $emailAddress=>$id)
{
  echo $emailAddress.'='.$id.'<br/>';
}
//output:
a@b.com=77
c@b.com=12

If you fix the HTML markup as I suggested above, you can get rid of line 142, and your foreach would then be:

foreach($_POST['contacts'] as $email=>$value){...}

Hopefully, that is clear. If so, then it should be obvious that if you were to change the HTML markup I used so that the value contains the email and the index (to $contacts[] ) be the numeric id, then your foreach only needs to be:

foreach($_POST['contacts'] as $email){...}

Wow, hielo, that was awesome; thank you for taking the time to help me (and anyone else struggling with this) and for sharing your knowledge.

I will give this a shot and post a follow-up.

Thanks again!

Hielo, and anyone else that might be interested, I wrote this line, and the rest of the foreach and array explanations fell into place.

echo "<td><input type='checkbox' name='contacts[" . $row['email'] . "]'" . "value='contacts[" . $row['id'] . "]'" . "></td>";

I had to figure out a way to fetch the data into the array (contacts[]) without manually assigning each a key/index, so this does it automatically. Now each "contact[]" has a unique name and value directly from the DB. I also set the DB to auto increment, so each new contact will have a unique number ("id") assigned as I pull in the data.

Thanks again, hielo!

A. You need a space immediately before the value "keyword"
B. The value does NOT require the contacts prefix. Assuming the email is a@b.com and the id is 3, once submitted then:
echo $_POST will give you "contacts[3]" instead of just "3";

The changes below will "fix" this so that it give you only "3":

echo "<td><input type='checkbox' name='contacts[" . $row['email'] . "]'" . "  value='" . $row['id'] . "'" . "></td>";

Yes, that proved true, but the email failed to send. It output a numeric string.

This is how I have the array and foreach written with the code I posted:

$contacts = array('id', 'other', 'email', 'substat');
foreach($_POST['contacts'] as $email=>$value)
{
		$to = $email;
//the rest of the mailer code...

Were you assuming I used another foreach method? What does the extra space do, by the way?

I don't see the need for $contacts = array('id', 'other', 'email', 'substat'); I don't see the point of the if($contacts=='1') condition on your original post. If three items were checked, the code below should send an email to all three (it includes some lines I commented out from your original post:

//THIS IS WHERE, I SUSPECT, IS MY DOWNFALL
		//$contacts = array('other', 'email', 'substat');
		foreach ($_POST['contacts'] as $email=>$value)
		{
			$to=$email;
 
			//if($contacts=='1')
			//{
				//$to = $_POST['email'];
				$name = $_POST['name'];
				$visitor_email = $_POST['email'];
				$user_message = $_POST['message'];
				$subject="New form submission";
				$from = $your_email;
				$text = "A user  $name has sent you this message:\n $user_message";
 
				$message = new Mail_mime(); 
				$message->setHTMLBody($text); 
				$message->addHTMLImage($path_of_uploaded_file);
				$body = $message->get();
				$extraheaders = array("From"=>$from, "Subject"=>$subject,"Reply-     To"=>$visitor_email);
				$headers = $message->headers($extraheaders);
				$mail = Mail::factory("mail");
				$mail->send($to, $headers, $body);
				$mail=NULL;
			//}/*On your original post you are missing this HERE, on this line. You probably have it somewhere else, but it should be here. */

			//redirect to 'thank-you page
			header('Location: thank-you.html');
			exit;
		}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.