Build an email form in AS3 and PHP with infinite attachements

Hey everyone!
I’m very pleased to attend to Aymeric’s blog, I hope it will not be the first and last time!

So, today, we will see how to build a simple, but efficient, email form with infinite attachement files in AS3 and PHP.

Setting up :

Before starting to code, we have to wonder how will be our tree structure, even it’s pretty simple.  On big projects, obviously bigger than this one, you can easily spend many hours on your tree structure. Here is what I suggest :

Simple, again. A “php” directory, with your php files (yeah, call me Cptn. Obvious), with a sub-directory where you will move your temporary uploaded files.

Let’s start coding!

On your stage, create 4 dynamic textfields :

  1. subject
  2. email
  3. message
  4. alert (we will fill it with some alert message)

Create 2 buttons :

  1. _send (on click, we will send the email)
  2. _attachement (on click, we will add a new attachement)

Here is the Main class file, it’s full of comments, so just read it 🙂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
package  {
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.events.Event;
	import flash.events.DataEvent;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.net.FileReference;
	import flash.net.FileReferenceList;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	import flash.net.URLLoaderDataFormat;
 
	/**
	 * ...
	 * @author Pierrick Pluchon
	 */
	public class Main extends Sprite{
 
		//List of files 
		private var pendingFiles:Vector.<FileReference>;
		//List of unique filenames
		private var uniqueFileNames:Vector.<String>;
		private var myFileReferenceList:FileReferenceList;
		//clip with filename
		private var attachedFile:MovieClip;
		//
		private var attachedList:Vector.<MovieClip>;
		private var emailRequest:URLRequest;
		private var uploadRequest:URLRequest;
		private var variables:URLVariables;
		private var loader:URLLoader;
		//if there is somes files attached
		private var filesAttached:Boolean = false;
		// Boolean : if the form is ready to be send (ie: no files still being uploaded)
		private var readyToSend:Boolean = true;
		//Number of files currently uploaded
		private var nbFilesUploaded:uint = 0;
		private var nbCurrentFiles:uint;
		private var nbTotalFiles:uint;
 
		//Max size for uploading files
		// 2Mo is the standard limit on many hosters
		private const MAX_SIZE:uint = 2000 * 1024; 
 
 
		public function Main() {
			// constructor code
			if (stage) init();
			else this.addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void
		{
			if (e != null) this.removeEventListener(Event.ADDED_TO_STAGE, init);
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			uploadRequest = new URLRequest("php/upload.php");
			uploadRequest.method = URLRequestMethod.POST;
			myFileReferenceList = new FileReferenceList();
			// Set a vector of whole filereference objects
			pendingFiles = new Vector.<FileReference>();
			//Set a vector for whole files clip
			attachedList = new Vector.<MovieClip>();
			//Set a vector for whole unique file names (returned by PHP);
			uniqueFileNames = new Vector.<String>();
			initFormListeners();
			//Set the focus on the first field : subject
			stage.focus = subject;
		}
 
		private function initFormListeners():void
		{
			//Files manager events
			myFileReferenceList.addEventListener(Event.SELECT, onSelect);
			myFileReferenceList.addEventListener(Event.CANCEL, onCancel);
			//User Interface Events
			_send.buttonMode = true;
			_send.addEventListener(MouseEvent.CLICK, sendHandler);
			_attachement.buttonMode = true;
			_attachement.addEventListener(MouseEvent.CLICK, browseFiles);
		}
 
		private function browseFiles(e:MouseEvent):void
		{
			// Open the browse window
			myFileReferenceList.browse();
		}
 
		private function onSelect(e:Event):void
		{
			var file:FileReference;
			//Get the whole number of files
			nbTotalFiles = myFileReferenceList.fileList.length + nbCurrentFiles;
			for (var i:uint = 0; i < myFileReferenceList.fileList.length; i++) 
			{
				file = FileReference(myFileReferenceList.fileList[i]);
				attachedFile = new AttachedFile();
				this.addChild(attachedFile);
				attachedFile.x = _attachement.x;
				attachedFile.y = _attachement.y + _attachement.height + (attachedFile.height * nbCurrentFiles)
				attachedList.push(attachedFile);
				addPendingFile(file);
			}
		}
 
		private function addPendingFile(file:FileReference):void {
			nbCurrentFiles++;
			pendingFiles.push(file);
			if (file.size < MAX_SIZE)
			{
				//Set events for tracking upload
				file.addEventListener(Event.COMPLETE, completeHandler);
				file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
				file.addEventListener ( DataEvent.UPLOAD_COMPLETE_DATA, onUploadComplete );
				//And then start upload
				file.upload(uploadRequest);
				readyToSend = false;
			} 
				else 
			{
				//Then the file is too big
				var id:uint = pendingFiles.indexOf(file);
				attachedList[id].filename.text = "File too big";
				//Since the las element is too big, remove it
				pendingFiles.pop();
				// And replace it by null
				pendingFiles.push(null);
				nbFilesUploaded++;
			}
		}
 
		private function progressHandler(e:ProgressEvent):void
		{
			//Get the id of the current FileRefence in pendingFiles
			var id:uint = pendingFiles.indexOf(e.currentTarget);
			var pct:uint = e.bytesLoaded * 100 / e.bytesTotal;
			attachedList[id].filename.text = "Uploading :" + String(pct)+"%";
		}
 
		//Execute when a file has been uploaded
		private function completeHandler(e:Event):void
		{
 
		}
 
		//Executes on server response after upload
		private function onUploadComplete(e:DataEvent):void
		{
			filesAttached = true;
			nbFilesUploaded++;
			if (nbFilesUploaded == nbTotalFiles)
			{
				readyToSend = true;
			}
			//Get the unique fileName returned by PHP
			var response:URLVariables = new URLVariables(e.data);
			var fileName:String = response.fileName;
			//Get the id of the current FileRefence in pendingFiles
			var id:uint = pendingFiles.indexOf(e.currentTarget);
			//The set the filename in the textfield
			attachedList[id].filename.text = fileName;
			uniqueFileNames.push(fileName);
		}
 
		private function onCancel(e:Event):void
		{
 
		}
 
		private function sendHandler(e:MouseEvent):void
		{
			if (isValidForm())
			{
				if (readyToSend)
				{
					//Set a new URLLoader 
					loader= new URLLoader();  
					emailRequest = new URLRequest("php/send.php");  
					// Set the method to POST (we will get these var with the $_POST  array in php
					emailRequest.method = URLRequestMethod.POST;
					variables = new URLVariables();  
					variables.email = email.text;  
					variables.message = message.text;  
					variables.subject = subject.text;
					for (var i:uint = 0; i < uniqueFileNames.length; i++)
					{
						//for every pendingFiles
						//set a new property to variables with the filename
						variables["myUploadedFile" + String(i)] = uniqueFileNames[i];
					}
					emailRequest.data = variables;
					loader.addEventListener(Event.COMPLETE, onResponse);
					loader.load(emailRequest);  
 
				} 
					else 
				{
					alert.text = "Files are still uploading";
				}
			} 
				else 
			{
				alert.text = "Please fill the form correctly";
			}
		}
 
		// On server response
		// Displays an alert depending on the server response
		private function onResponse(e:Event):void
		{
			if (e.target.data == "1") alert.text = "Your mail has been sent";
			else alert.text = "An error occured while sending your mail";
			resetForm();
		}
 
		//Simply resets the form and removes files name
		private function resetForm():void
		{
			subject.text="";
			message.text="";
			email.text="";
			//if(filesAttached)
			//{
				var i:uint=attachedList.length;
				while(i--)
				{
					this.removeChild(attachedList[i])
				}
			//}
		}
 
		// Check if all field are filled
		private function isValidForm():Boolean
		{
			if (subject.text!="" && message.text!="" && isValidEmail(email.text)==true) return true;
			else return false;
		}
 
		//Regexp for checking email
		function isValidEmail(email:String):Boolean {
			var emailExpression:RegExp = /^[a-z][\w.-]+@\w[\w.-]+\.[\w.-]*[a-z][a-z]$/i;
			return emailExpression.test(email);
		}
 
 
	}
 
}

Here is the main idea : for every selected files, we create a new FileReference object (thanks to the fileList property of FileReferenceList) and we upload it.

The trick is simply to wait the “upload complete event” (aka “DataEvent.UPLOAD_COMPLETE_DATA”) and get the unique filename generate by php. Then, we simply have to give to the other php file (aka “send.php”) this unique filename.
upload.php (remember, it must be in your php directory):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
$mimeArray = array('application/msword', 'application/word', 'application/pdf', 'image/gif', 'image/jpeg', 'image/png');
$file = $_FILES["Filedata"]; 
if ( isset ( $file  ) ) 
{
	//Get the mime type of the uploaded file
	$mime = mime_content_type($file ['tmp_name']);
	if(in_array($mime, $mimeArray) )
	{
		$fileName = getName($file ['name']); 
		move_uploaded_file ( $file ['tmp_name'], "mailing/".$fileName); 
		echo "fileName=".$fileName;
	}
}
 
//Return a unique filename
function getName($name)
{
	$filename="mailing/".$name;
	if(file_exists($filename))
	{
		//If the filename exists, adding "-" in front of it
		$name = "-".$name;
		return getName($name);
	}
		return ($name);
}
?>

send.php (still in your php directory):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php
 
// email fields: to, from, subject, and so on
$to = "youradress@domain.com";
$from = $_POST['email'];
 
$message =  $_POST['message'];
$headers = "From: $from";
$subject = $_POST['subject'];
 
// array with filenames to be sent as attachment
$files = array(); 
 foreach($_POST as $key => $value)
 {
	if(stristr($key, "myUploadedFile"))array_push($files, $value);
 }
// boundary 
$semi_rand = md5(time()); 
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; 
 
// headers for attachment 
$headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\""; 
 
// multipart boundary 
$message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n"; 
$message .= "--{$mime_boundary}\n";
 
// preparing attachments
for($x=0;$x<count($files);$x++){
	$file = fopen("mailing/".$files[$x],"rb");
	$data = fread($file,filesize("mailing/".$files[$x]));
	fclose($file);
	$data = chunk_split(base64_encode($data));
	$message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"$files[$x]\"\n" . 
	"Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" . 
	"Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
	$message .= "--{$mime_boundary}\n";
}
 
// send email
$ok = @mail($to, $subject, $message, $headers);
 
//For every file attached
foreach($files as  $file)
{
	//delete it
	unlink("mailing/".$file);
}
if ($ok) { 
	echo "1"; 
} else { 
	echo "0"; 
} 
 
?>

On line 4, please set your correct email! Moreover, when you will upload your php files on the server, don’t forget to set the chmod to 777 (read, write, execute) of you tmp directory (here, it’s named “mailing”). Otherwise, you won’t be able to upload any file!

You can download the files here.

Any question? comment below!

8 thoughts on “Build an email form in AS3 and PHP with infinite attachements

  1. Man! I had very difficult in load de return from PHP. Thanks! And sorry for my poor english…
    Muito Obrigado! Me ajudou muito!

  2. Hi This is working great!!! thanks very much.
    But I am struggling adding another field.
    I need to add a ‘telephone’ filed to collect telephone numbers.

    I have amended the Main.as with additional variables and added the text field to the stage with instance ‘telephone’.

    The issue is the code in the sen.php file its got me beat !
    Added the :
    $telephone = $_POST[‘telephone’];

    At the top but just cant get the lower section yo work?
    any comments

    Thanks
    Phil

  3. Hi.
    In actionscript there is an error:
    private var attachedFile:MovieClip;
    but in function onSelect
    attachedFile = new AttachedFile();
    why you do it. it’s not work. I tryed to change but it do is not work. help me to resolve this problem!

  4. Hi, my question is, i try to add this file inside from another flash project, but that not works because show me errors as : call to attachfile no register and the mail not end, could you help me please or tell me what i could to do? thank you very much

  5. i use windows, when i try to execute the form the error show me so: Error #2044: Unhandled IOErrorEvent:. text=Error #2038: File I/O Error.
    and i dunno why… can you help me please?
    i really appreciate your sooner request

  6. and otherwise is this another error :S

    Error #2044: Unhandled ioError:. text=Error #2032: Stream Error. URL: file:///C|/Users/Monicapc/Desktop/email%5Fadjunto/bin/bin/php/send.php
    at Main/sendHandler()

  7. hi, i was find fill all and now the AS3 works with the class, but the problem is after UPLOAD the file attached, this stopped and not send, what is the problem? please help me i beg !!!

Leave a Reply

Your email address will not be published. Required fields are marked *