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 :
- subject
- message
- alert (we will fill it with some alert message)
Create 2 buttons :
- _send (on click, we will send the email)
- _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!
Article très intéressent. Bonne continuation.
Man! I had very difficult in load de return from PHP. Thanks! And sorry for my poor english…
Muito Obrigado! Me ajudou muito!
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
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!
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
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
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()
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 !!!