PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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