PageRenderTime 169ms CodeModel.GetById 81ms app.highlight 49ms RepoModel.GetById 31ms app.codeStats 1ms

/concrete/core/controllers/blocks/form.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 510 lines | 432 code | 42 blank | 36 comment | 25 complexity | c0097464873417335297d0a7021e1f4f MD5 | raw file
  1<?php  
  2defined('C5_EXECUTE') or die("Access Denied.");
  3/**
  4 * @package Blocks
  5 * @subpackage Form
  6 * @author Tony Trupp <tony@concrete5.org>
  7 * @author Andrew Embler <andrew@concrete5.org>
  8 * @copyright  Copyright (c) 2003-2012 Concrete5. (http://www.concrete5.org)
  9 * @license    http://www.concrete5.org/license/     MIT License
 10 *
 11 */
 12class Concrete5_Controller_Block_Form extends BlockController {
 13
 14	public $btTable = 'btForm';
 15	public $btQuestionsTablename = 'btFormQuestions';
 16	public $btAnswerSetTablename = 'btFormAnswerSet';
 17	public $btAnswersTablename = 'btFormAnswers'; 	
 18	public $btInterfaceWidth = '420';
 19	public $btInterfaceHeight = '430';
 20	public $thankyouMsg='';
 21	public $noSubmitFormRedirect=0;
 22	
 23	protected $btExportTables = array('btForm', 'btFormQuestions');
 24	protected $btExportPageColumns = array('redirectCID');
 25	protected $lastAnswerSetId=0;
 26		
 27	/** 
 28	 * Used for localization. If we want to localize the name/description we have to include this
 29	 */
 30	public function getBlockTypeDescription() {
 31		return t("Build simple forms and surveys.");
 32	}
 33	
 34	public function getBlockTypeName() {
 35		return t("Form");
 36	}
 37	
 38	public function getJavaScriptStrings() {
 39		return array(
 40			'delete-question' => t('Are you sure you want to delete this question?'),
 41			'form-name' => t('Your form must have a name.'),
 42			'complete-required' => t('Please complete all required fields.'),
 43			'ajax-error' => t('AJAX Error.'),
 44			'form-min-1' => t('Please add at least one question to your form.')			
 45		);
 46	}
 47
 48	protected function importAdditionalData($b, $blockNode) {
 49		if (isset($blockNode->data)) {
 50			foreach($blockNode->data as $data) {
 51				if ($data['table'] != $this->getBlockTypeDatabaseTable()) {
 52					$table = (string) $data['table'];
 53					if (isset($data->record)) {
 54						foreach($data->record as $record) {
 55							$aar = new ADODB_Active_Record($table);
 56							$aar->bID = $b->getBlockID();
 57							foreach($record->children() as $node) {
 58								$nodeName = $node->getName();
 59								$aar->{$nodeName} = (string) $node;
 60							}
 61							if ($table == 'btFormQuestions') {
 62								$db = Loader::db();
 63								$aar->questionSetId = $db->GetOne('select questionSetId from btForm where bID = ?', array($b->getBlockID()));
 64							}
 65							$aar->Save();
 66						}
 67					}								
 68				}
 69			}
 70		}
 71	}
 72	
 73	public function __construct($b = null){ 
 74		parent::__construct($b);
 75		//$this->bID = intval($this->_bID);
 76		if(is_string($this->thankyouMsg) && !strlen($this->thankyouMsg)){ 
 77			$this->thankyouMsg = $this->getDefaultThankYouMsg();
 78		}
 79	}
 80	
 81	public function on_page_view() {
 82		if ($this->viewRequiresJqueryUI()) {
 83			$this->addHeaderItem(Loader::helper('html')->css('jquery.ui.css'));
 84			$this->addFooterItem(Loader::helper('html')->javascript('jquery.ui.js'));
 85		}
 86	}
 87	
 88	//Internal helper function
 89	private function viewRequiresJqueryUI() {
 90		$whereInputTypes = "inputType = 'date' OR inputType = 'datetime'";
 91		$sql = "SELECT COUNT(*) FROM {$this->btQuestionsTablename} WHERE questionSetID = ? AND bID = ? AND ({$whereInputTypes})";
 92		$vals = array(intval($this->questionSetId), intval($this->bID));
 93		$JQUIFieldCount = Loader::db()->GetOne($sql, $vals);
 94		return (bool)$JQUIFieldCount;
 95	}
 96	
 97	public function getDefaultThankYouMsg() {
 98		return t("Thanks!");
 99	}
100	
101	//form add or edit submit 
102	//(run after the duplicate method on first block edit of new page version)
103	function save( $data=array() ) { 
104		if( !$data || count($data)==0 ) $data=$_POST;  
105		
106		$b=$this->getBlockObject(); 
107		$c=$b->getBlockCollectionObject();
108		
109		$db = Loader::db();
110		if(intval($this->bID)>0){	 
111			$q = "select count(*) as total from {$this->btTable} where bID = ".intval($this->bID);
112			$total = $db->getOne($q);
113		}else $total = 0; 
114			
115		if($_POST['qsID']) $data['qsID']=$_POST['qsID'];
116		if( !$data['qsID'] ) $data['qsID']=time(); 	
117		if(!$data['oldQsID']) $data['oldQsID']=$data['qsID']; 
118		$data['bID']=intval($this->bID); 
119		
120		if(!empty($data['redirectCID'])) {
121			$data['redirect'] = 1;
122		} else {
123			$data['redirect'] = 0;
124			$data['redirectCID'] = 0;
125		}
126
127		if(empty($data['addFilesToSet'])) {
128			$data['addFilesToSet'] = 0;
129		}
130		
131		$v = array( $data['qsID'], $data['surveyName'], intval($data['notifyMeOnSubmission']), $data['recipientEmail'], $data['thankyouMsg'], intval($data['displayCaptcha']), intval($data['redirectCID']), intval($data['addFilesToSet']), intval($this->bID) );
132 		
133		//is it new? 
134		if( intval($total)==0 ){
135			$q = "insert into {$this->btTable} (questionSetId, surveyName, notifyMeOnSubmission, recipientEmail, thankyouMsg, displayCaptcha, redirectCID, addFilesToSet, bID) values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
136		}else{
137			$q = "update {$this->btTable} set questionSetId = ?, surveyName=?, notifyMeOnSubmission=?, recipientEmail=?, thankyouMsg=?, displayCaptcha=?, redirectCID=?, addFilesToSet=? where bID = ? AND questionSetId=".$data['qsID'];
138		}
139		
140		$rs = $db->query($q,$v);  
141		
142		//Add Questions (for programmatically creating forms, such as during the site install)
143		if( count($data['questions'])>0 ){
144			$miniSurvey = new MiniSurvey();
145			foreach( $data['questions'] as $questionData )
146				$miniSurvey->addEditQuestion($questionData,0);
147		}
148 
149 		$this->questionVersioning($data);
150		
151		return true;
152	}
153	
154	//Ties the new or edited questions to the new block number
155	//New and edited questions are temporarily given bID=0, until the block is saved... painfully complicated
156	protected function questionVersioning( $data=array() ){
157		$db = Loader::db();
158		$oldBID = intval($data['bID']);
159		
160		//if this block is being edited a second time, remove edited questions with the current bID that are pending replacement
161		//if( intval($oldBID) == intval($this->bID) ){  
162			$vals=array( intval($data['oldQsID']) );  
163			$pendingQuestions=$db->getAll('SELECT msqID FROM btFormQuestions WHERE bID=0 && questionSetId=?',$vals); 
164			foreach($pendingQuestions as $pendingQuestion){  
165				$vals=array( intval($this->bID), intval($pendingQuestion['msqID']) );  
166				$db->query('DELETE FROM btFormQuestions WHERE bID=? AND msqID=?',$vals);
167			}
168		//} 
169	
170		//assign any new questions the new block id 
171		$vals=array( intval($data['bID']), intval($data['qsID']), intval($data['oldQsID']) );  
172		$rs=$db->query('UPDATE btFormQuestions SET bID=?, questionSetId=? WHERE bID=0 && questionSetId=?',$vals);
173 
174 		//These are deleted or edited questions.  (edited questions have already been created with the new bID).
175 		$ignoreQuestionIDsDirty=explode( ',', $data['ignoreQuestionIDs'] );
176		$ignoreQuestionIDs=array(0);
177		foreach($ignoreQuestionIDsDirty as $msqID)
178			$ignoreQuestionIDs[]=intval($msqID);	
179		$ignoreQuestionIDstr=join(',',$ignoreQuestionIDs); 
180		
181		//remove any questions that are pending deletion, that already have this current bID 
182 		$pendingDeleteQIDsDirty=explode( ',', $data['pendingDeleteIDs'] );
183		$pendingDeleteQIDs=array();
184		foreach($pendingDeleteQIDsDirty as $msqID)
185			$pendingDeleteQIDs[]=intval($msqID);		
186		$vals=array( $this->bID, intval($data['qsID']), join(',',$pendingDeleteQIDs) );  
187		$unchangedQuestions=$db->query('DELETE FROM btFormQuestions WHERE bID=? AND questionSetId=? AND msqID IN (?)',$vals);			
188	} 
189	
190	//Duplicate will run when copying a page with a block, or editing a block for the first time within a page version (before the save).
191	function duplicate($newBID) { 
192	
193		$b=$this->getBlockObject(); 
194		$c=$b->getBlockCollectionObject();	 
195		 
196		$db = Loader::db();
197		$v = array($this->bID);
198		$q = "select * from {$this->btTable} where bID = ? LIMIT 1";
199		$r = $db->query($q, $v);
200		$row = $r->fetchRow();
201		
202		//if the same block exists in multiple collections with the same questionSetID
203		if(count($row)>0){ 
204			$oldQuestionSetId=$row['questionSetId']; 
205			
206			//It should only generate a new question set id if the block is copied to a new page,
207			//otherwise it will loose all of its answer sets (from all the people who've used the form on this page)
208			$questionSetCIDs=$db->getCol("SELECT distinct cID FROM {$this->btTable} AS f, CollectionVersionBlocks AS cvb ".
209						"WHERE f.bID=cvb.bID AND questionSetId=".intval($row['questionSetId']) );
210			
211			//this question set id is used on other pages, so make a new one for this page block 
212			if( count( $questionSetCIDs ) >1 || !in_array( $c->cID, $questionSetCIDs ) ){ 
213				$newQuestionSetId=time(); 
214				$_POST['qsID']=$newQuestionSetId; 
215			}else{
216				//otherwise the question set id stays the same
217				$newQuestionSetId=$row['questionSetId']; 
218			}
219			
220			//duplicate survey block record 
221			//with a new Block ID and a new Question 
222			$v = array($newQuestionSetId,$row['surveyName'],$newBID,$row['thankyouMsg'],intval($row['notifyMeOnSubmission']),$row['recipientEmail'],$row['displayCaptcha'], $row['addFilesToSet']);
223			$q = "insert into {$this->btTable} ( questionSetId, surveyName, bID,thankyouMsg,notifyMeOnSubmission,recipientEmail,displayCaptcha,addFilesToSet) values (?, ?, ?, ?, ?, ?, ?,?)";
224			$result=$db->Execute($q, $v); 
225			
226			$rs=$db->query("SELECT * FROM {$this->btQuestionsTablename} WHERE questionSetId=$oldQuestionSetId AND bID=".intval($this->bID) );
227			while( $row=$rs->fetchRow() ){
228				$v=array($newQuestionSetId,intval($row['msqID']), intval($newBID), $row['question'],$row['inputType'],$row['options'],$row['position'],$row['width'],$row['height'],$row['required']);
229				$sql= "INSERT INTO {$this->btQuestionsTablename} (questionSetId,msqID,bID,question,inputType,options,position,width,height,required) VALUES (?,?,?,?,?,?,?,?,?,?)";
230				$db->Execute($sql, $v);
231			}
232			
233			return $newQuestionSetId;
234		}
235		return 0;	
236	}
237	
238
239	//users submits the completed survey
240	function action_submit_form() { 
241	
242		$ip = Loader::helper('validation/ip');
243		Loader::library("file/importer");
244		
245		if (!$ip->check()) {
246			$this->set('invalidIP', $ip->getErrorMessage());			
247			return;
248		}	
249
250		$txt = Loader::helper('text');
251		$db = Loader::db();
252		
253		//question set id
254		$qsID=intval($_POST['qsID']); 
255		if($qsID==0)
256			throw new Exception(t("Oops, something is wrong with the form you posted (it doesn't have a question set id)."));
257			
258		//get all questions for this question set
259		$rows=$db->GetArray("SELECT * FROM {$this->btQuestionsTablename} WHERE questionSetId=? AND bID=? order by position asc, msqID", array( $qsID, intval($this->bID)));			
260
261		// check captcha if activated
262		if ($this->displayCaptcha) {
263			$captcha = Loader::helper('validation/captcha');
264			if (!$captcha->check()) {
265				$errors['captcha'] = t("Incorrect captcha code");
266				$_REQUEST['ccmCaptchaCode']='';
267			}
268		}
269		
270		//checked required fields
271		foreach($rows as $row){
272			if ($row['inputType']=='datetime'){
273				if (!isset($datetime)) {
274					$datetime = Loader::helper("form/date_time");
275				}
276				$translated = $datetime->translate('Question'.$row['msqID']);
277				if ($translated) {
278					$_POST['Question'.$row['msqID']] = $translated;
279				}
280			}
281			if( intval($row['required'])==1 ){
282				$notCompleted=0;
283				if ($row['inputType'] == 'email') {
284					if (!Loader::helper('validation/strings')->email($_POST['Question' . $row['msqID']])) {
285						$errors['emails'] = t('You must enter a valid email address.');
286					}
287				}
288				if($row['inputType']=='checkboxlist'){
289					$answerFound=0;
290					foreach($_POST as $key=>$val){
291						if( strstr($key,'Question'.$row['msqID'].'_') && strlen($val) ){
292							$answerFound=1;
293						} 
294					}
295					if(!$answerFound) $notCompleted=1;
296				}elseif($row['inputType']=='fileupload'){		
297					if( !isset($_FILES['Question'.$row['msqID']]) || !is_uploaded_file($_FILES['Question'.$row['msqID']]['tmp_name']) )					
298						$notCompleted=1;
299				}elseif( !strlen(trim($_POST['Question'.$row['msqID']])) ){
300					$notCompleted=1;
301				} 
302				if($notCompleted) $errors['CompleteRequired'] = t("Complete required fields *") ; 
303			}
304		}
305		
306		//try importing the file if everything else went ok	
307		$tmpFileIds=array();	
308		if(!count($errors))	foreach($rows as $row){
309			if( $row['inputType']!='fileupload' ) continue;
310			$questionName='Question'.$row['msqID']; 			
311			if	( !intval($row['required']) && 
312			   		( 
313			   		!isset($_FILES[$questionName]['tmp_name']) || !is_uploaded_file($_FILES[$questionName]['tmp_name'])
314			   		) 
315				){
316					continue;
317			}
318			$fi = new FileImporter();
319			$resp = $fi->import($_FILES[$questionName]['tmp_name'], $_FILES[$questionName]['name']);
320			if (!($resp instanceof FileVersion)) {
321				switch($resp) {
322					case FileImporter::E_FILE_INVALID_EXTENSION:
323						$errors['fileupload'] = t('Invalid file extension.');
324						break;
325					case FileImporter::E_FILE_INVALID:
326						$errors['fileupload'] = t('Invalid file.');
327						break;
328					
329				}
330			}else{
331				$tmpFileIds[intval($row['msqID'])] = $resp->getFileID();
332				if(intval($this->addFilesToSet)) {
333					Loader::model('file_set');
334					$fs = new FileSet();
335					$fs = $fs->getByID($this->addFilesToSet);
336					if($fs->getFileSetID()) {
337						$fs->addFileToSet($resp);
338					}
339				}
340			}
341		}
342		
343		if(count($errors)){			
344			$this->set('formResponse', t('Please correct the following errors:') );
345			$this->set('errors',$errors);
346		}else{ //no form errors			
347			//save main survey record	
348			$u = new User();
349			$uID = 0;
350			if ($u->isRegistered()) {
351				$uID = $u->getUserID();
352			}
353			$q="insert into {$this->btAnswerSetTablename} (questionSetId, uID) values (?,?)";
354			$db->query($q,array($qsID, $uID));
355			$answerSetID=$db->Insert_ID();
356			$this->lastAnswerSetId=$answerSetID;
357			
358			$questionAnswerPairs=array();
359
360			if( strlen(FORM_BLOCK_SENDER_EMAIL)>1 && strstr(FORM_BLOCK_SENDER_EMAIL,'@') ){
361				$formFormEmailAddress = FORM_BLOCK_SENDER_EMAIL;
362			}else{
363				$adminUserInfo=UserInfo::getByID(USER_SUPER_ID);
364				$formFormEmailAddress = $adminUserInfo->getUserEmail();
365			}
366			$replyToEmailAddress = $formFormEmailAddress;
367			//loop through each question and get the answers 
368			foreach( $rows as $row ){	
369				//save each answer
370				if($row['inputType']=='checkboxlist'){
371					$answer = Array();
372					$answerLong="";
373					$keys = array_keys($_POST);
374					foreach ($keys as $key){
375						if (strpos($key, 'Question'.$row['msqID'].'_') === 0){
376							$answer[]=$txt->sanitize($_POST[$key]);
377						}
378					}
379				}elseif($row['inputType']=='text'){
380					$answerLong=$txt->sanitize($_POST['Question'.$row['msqID']]);
381					$answer='';
382				}elseif($row['inputType']=='fileupload'){
383					$answerLong="";
384					$answer=intval( $tmpFileIds[intval($row['msqID'])] );
385				}elseif($row['inputType']=='url'){
386					$answerLong="";
387					$answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
388				}elseif($row['inputType']=='email'){
389					$answerLong="";
390					$answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
391					if(!empty($row['options'])) {
392						$settings = unserialize($row['options']);
393						if(is_array($settings) && array_key_exists('send_notification_from', $settings) && $settings['send_notification_from'] == 1) {
394							$email = $txt->email($answer);
395							if(!empty($email)) {
396								$replyToEmailAddress = $email;
397							}
398						}
399					}
400				}elseif($row['inputType']=='telephone'){
401					$answerLong="";
402					$answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
403				}else{
404					$answerLong="";
405					$answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
406				}
407				
408				if( is_array($answer) ) 
409					$answer=join(',',$answer);
410									
411				$questionAnswerPairs[$row['msqID']]['question']=$row['question'];
412				$questionAnswerPairs[$row['msqID']]['answer']=$txt->sanitize( $answer.$answerLong );
413				
414				$v=array($row['msqID'],$answerSetID,$answer,$answerLong);
415				$q="insert into {$this->btAnswersTablename} (msqID,asID,answer,answerLong) values (?,?,?,?)";
416				$db->query($q,$v);
417			}
418			$foundSpam = false;
419			
420			$submittedData = '';
421			foreach($questionAnswerPairs as $questionAnswerPair){
422				$submittedData .= $questionAnswerPair['question']."\r\n".$questionAnswerPair['answer']."\r\n"."\r\n";
423			} 
424			$antispam = Loader::helper('validation/antispam');
425			if (!$antispam->check($submittedData, 'form_block')) { 
426				// found to be spam. We remove it
427				$foundSpam = true;
428				$q="delete from {$this->btAnswerSetTablename} where asID = ?";
429				$v = array($this->lastAnswerSetId);
430				$db->Execute($q, $v);
431				$db->Execute("delete from {$this->btAnswersTablename} where asID = ?", array($this->lastAnswerSetId));
432			}
433			
434			if(intval($this->notifyMeOnSubmission)>0 && !$foundSpam){	
435				if ($this->sendEmailFrom !== false) {
436					$formFormEmailAddress = $this->sendEmailFrom;
437				} else if( strlen(FORM_BLOCK_SENDER_EMAIL)>1 && strstr(FORM_BLOCK_SENDER_EMAIL,'@') ){
438					$formFormEmailAddress = FORM_BLOCK_SENDER_EMAIL;  
439				}else{ 
440					$adminUserInfo=UserInfo::getByID(USER_SUPER_ID);
441					$formFormEmailAddress = $adminUserInfo->getUserEmail(); 
442				}
443				
444				$mh = Loader::helper('mail');
445				$mh->to( $this->recipientEmail ); 
446				$mh->from( $formFormEmailAddress ); 
447				$mh->replyto( $replyToEmailAddress ); 
448				$mh->addParameter('formName', $this->surveyName);
449				$mh->addParameter('questionSetId', $this->questionSetId);
450				$mh->addParameter('questionAnswerPairs', $questionAnswerPairs); 
451				$mh->load('block_form_submission');
452				$mh->setSubject(t('%s Form Submission', $this->surveyName));
453				//echo $mh->body.'<br>';
454				@$mh->sendMail(); 
455			} 
456			
457			if (!$this->noSubmitFormRedirect) {
458				if ($this->redirectCID > 0) {
459					$pg = Page::getByID($this->redirectCID);
460					if (is_object($pg) && $pg->cID) {
461						$this->redirect($pg->getCollectionPath());
462					}
463				}
464				$c = Page::getCurrentPage();
465				header("Location: ".Loader::helper('navigation')->getLinkToCollection($c, true)."?surveySuccess=1&qsid=".$this->questionSetId."#".$this->questionSetId);
466				exit;
467			}
468		}
469	}		
470	
471	function delete() { 
472	
473		$db = Loader::db();
474
475		$deleteData['questionsIDs']=array();
476		$deleteData['strandedAnswerSetIDs']=array();
477
478		$miniSurvey=new MiniSurvey();
479		$info=$miniSurvey->getMiniSurveyBlockInfo($this->bID);
480		
481		//get all answer sets
482		$q = "SELECT asID FROM {$this->btAnswerSetTablename} WHERE questionSetId = ".intval($info['questionSetId']);
483		$answerSetsRS = $db->query($q); 
484 
485		//delete the questions
486		$deleteData['questionsIDs']=$db->getAll( "SELECT qID FROM {$this->btQuestionsTablename} WHERE questionSetId = ".intval($info['questionSetId']).' AND bID='.intval($this->bID) );
487		foreach($deleteData['questionsIDs'] as $questionData)
488			$db->query("DELETE FROM {$this->btQuestionsTablename} WHERE qID=".intval($questionData['qID']));			
489		
490		//delete left over answers
491		$strandedAnswerIDs = $db->getAll('SELECT fa.aID FROM `btFormAnswers` AS fa LEFT JOIN btFormQuestions as fq ON fq.msqID=fa.msqID WHERE fq.msqID IS NULL');
492		foreach($strandedAnswerIDs as $strandedAnswerIDs)
493			$db->query('DELETE FROM `btFormAnswers` WHERE aID='.intval($strandedAnswer['aID']));
494			
495		//delete the left over answer sets
496		$deleteData['strandedAnswerSetIDs'] = $db->getAll('SELECT aset.asID FROM btFormAnswerSet AS aset LEFT JOIN btFormAnswers AS fa ON aset.asID=fa.asID WHERE fa.asID IS NULL');
497		foreach($deleteData['strandedAnswerSetIDs'] as $strandedAnswerSetIDs)
498			$db->query('DELETE FROM btFormAnswerSet WHERE asID='.intval($strandedAnswerSetIDs['asID']));		
499		
500		//delete the form block		
501		$q = "delete from {$this->btTable} where bID = '{$this->bID}'";
502		$r = $db->query($q);		
503		
504		parent::delete();
505		
506		return $deleteData;
507	}
508}
509
510