PageRenderTime 60ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/assets/snippets/eform/eform.inc.php

https://github.com/good-web-master/modx.evo.custom
PHP | 1139 lines | 835 code | 132 blank | 172 comment | 237 complexity | a51516c66042decfc6209bf3d7442d68 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0, MIT, BSD-3-Clause
  1. <?php
  2. # eForm 1.4.4.7 - Electronic Form Snippet
  3. # Original created by: Raymond Irving 15-Dec-2004.
  4. # Extended by: Jelle Jager (TobyL) September 2006
  5. # -----------------------------------------------------
  6. #
  7. #
  8. # Captcha image support - thanks to Djamoer
  9. # Multi checkbox, radio, select support - thanks to Djamoer
  10. # Form Parser and extended validation - by Jelle Jager
  11. #
  12. # see docs/eform.htm for installation and usage information
  13. #
  14. # VERSION HISTORY
  15. # Work around for setting required class on check & radio labels
  16. # fixed bug: If eform attibute is set on multiple check boxes only the last
  17. # value is set in values list
  18. # For a full version history see the eform_history.htm file in the docs directory
  19. #
  20. # Some more fixes and problems:
  21. # FIXED: reg expression failed for select and textarea boxes which have regex special
  22. # characters in their name attribute. eg name="multipleSelection[]"
  23. # FIXED: validation of multiple values with #LIST & #SELECT stopped after 1st value
  24. # Caused by repeating $v variable naming (overwriting $v array)
  25. # e.g.
  26. # <select name="multipleSelection[]" multiple="multiple" eform="::1::"/>
  27. # <option value="1">1</option>
  28. # <option value="2">2</option>
  29. # <option value="3">3</option>
  30. # </select>
  31. # would only have the first selected value validated!
  32. #
  33. # bugfix: &jScript parameter doesn't accept chunks, only a link to a JS file if more than one chunk is declared (eg &jScript=`chunk1,chunk2)
  34. # bugfix: &protectSubmit creates hash for all fields instead of fields declared in &protectSubmit
  35. # bugfix: Auto respond email didn't honour the &sendAsText parameter
  36. # bugfix: The #FUNCTION validation rule for select boxes never calls the function
  37. # bugfix: Validation css class isn't being added to labels.
  38. #
  39. # SECURITY FIX: add additional sanitization to fields after stripping slashes to avoid remote tag execution
  40. ##
  41. $GLOBALS['optionsName'] = "eform"; //name of pseudo attribute used for format settings
  42. $GLOBALS['efPostBack'] = false;
  43. function eForm($modx,$params) {
  44. global $_lang;
  45. global $debugText;
  46. global $formats,$fields,$efPostBack;
  47. $fields = array(); //reset fields array - needed in case of multiple forms
  48. // define some variables used as array index
  49. $_dfnMaxlength = 6;
  50. extract($params,EXTR_SKIP); // extract params into variables
  51. $fileVersion = '1.4.4';
  52. $version = isset($version)?$version:'prior to 1.4.2';
  53. #include default language file
  54. include_once($snipPath."lang/english.inc.php");
  55. #include other language file if set.
  56. $form_language = isset($language)?$language:$modx->config['manager_language'];
  57. if($form_language!="english" && $form_language!='') {
  58. if(file_exists($snipPath ."lang/".$form_language.".inc.php"))
  59. include_once $snipPath ."lang/".$form_language.".inc.php";
  60. else
  61. if( $isDebug ) $debugText .= "<strong>Language file '$form_language.inc.php' not found!</strong><br />"; //always in english!
  62. }
  63. # add debug warning - moved again...
  64. if( $isDebug ) $debugText .= $_lang['ef_debug_warning'];
  65. //check version differences
  66. if( $version != $fileVersion )
  67. return $_lang['ef_version_error'];
  68. # check for valid form key - moved to below fetching form template to allow id coming from form template
  69. $nomail = $noemail; //adjust variable name confusion
  70. # activate nomail if missing $to
  71. if (!$to) $nomail = 1;
  72. # load templates
  73. if($tpl==$modx->documentIdentifier) return $_lang['ef_is_own_id']."'$tpl'";
  74. //required
  75. if( $tmp=efLoadTemplate($tpl) ) $tpl=$tmp; else return $_lang['ef_no_doc'] . " '$tpl'";
  76. # check for valid form key
  77. if ($formid=="") return $_lang['ef_error_formid'];
  78. // try to get formid from <form> tag id
  79. preg_match('/<form[^>]*?id=[\'"]([^\'"]*?)[\'"]/i',$tpl,$matches);
  80. $form_id = isset($matches[1])?$matches[1]:'';
  81. //check for <input type='hidden name='formid'...>
  82. if( !preg_match('/<input[^>]*?name=[\'"]formid[\'"]/i',$tpl) ){
  83. //insert hidden formid field
  84. $tpl = str_replace('</form>',"<input type=\"hidden\" name=\"formid\" value=\"$form_id\" /></form>",$tpl);
  85. }
  86. $validFormId = ($formid==$_POST['formid'])?1:0;
  87. # check if postback mode
  88. $efPostBack = ($validFormId && count($_POST)>0)? true:false; //retain old variable?
  89. if($efPostBack){
  90. $report = (($tmp=efLoadTemplate($report))!==false)?$tmp:$_lang['ef_no_doc'] . " '$report'";
  91. if($thankyou) $thankyou = (($tmp=efLoadTemplate($thankyou))!==false )?$tmp:$_lang['ef_no_doc'] . " '$thankyou'";
  92. if($autotext) $autotext = (($tmp=efLoadTemplate($autotext))!==false )?$tmp:$_lang['ef_no_doc'] . " '$autotext'";
  93. }
  94. //these will be added to the HEAD section of the document when the form is displayed!
  95. if($cssStyle){
  96. $cssStyle = ( strpos($cssStyle,',') && strpos($cssStyle,'<style')===false ) ? explode(',',$cssStyle) : array($cssStyle);
  97. foreach( $cssStyle as $tmp ) $startupSource[]= array($tmp,'css');
  98. }
  99. if($jScript){
  100. $jScript = ( strpos($jScript,',') && strpos($jScript,'<script')===false ) ? explode(',',$jScript) : array($jScript);
  101. foreach( $jScript as $tmp )
  102. $startupSource[]= array($tmp,'javascript');
  103. }
  104. #New in 1.4.4 - run snippet to include 'event' functions
  105. if( strlen($runSnippet)>0 ){
  106. $modx->runSnippet($runSnippet, array('formid'=>$formid));
  107. //Sadly we cannot know if the snippet fails or if it exists as modx->runsnippet's return value
  108. //is ambiguous
  109. }
  110. # invoke onBeforeFormParse event set by another script
  111. if ($eFormOnBeforeFormParse) {
  112. if( $isDebug && !function_exists($eFormOnBeforeFormParse))
  113. $fields['debug'] .= "eFormOnBeforeFormParse event: Could not find the function " . $eFormOnBeforeFormParse;
  114. else{
  115. $templates = array('tpl'=>$tpl,'report'=>$report,'thankyou'=>$thankyou,'autotext'=>$autotext);
  116. if( $eFormOnBeforeFormParse($fields,$templates)===false )
  117. return "";
  118. elseif(is_array($templates))
  119. extract($templates); // extract back into original variables
  120. }
  121. }
  122. # parse form for formats and generate placeholders
  123. $tpl = eFormParseTemplate($tpl,$isDebug);
  124. if ($efPostBack) {
  125. foreach($formats as $k => $discard)
  126. if(!isset($fields[$k])) $fields[$k] = ""; // store dummy value inside $fields
  127. $disclaimer = (($tmp=efLoadTemplate($disclaimer))!==false )? $tmp:'';
  128. //error message containers
  129. $vMsg = $rMsg = $rClass = array();
  130. # get user post back data
  131. foreach($_POST as $name => $value){
  132. if(is_array($value)){
  133. //remove empty values
  134. $fields[$name] = array_filter($value,create_function('$v','return (!empty($v));'));
  135. } else {
  136. if ($allowhtml || $formats[$name][2]=='html') {
  137. $fields[$name] = stripslashes($value);
  138. } else {
  139. $fields[$name] = strip_tags(stripslashes($value));
  140. }
  141. }
  142. }
  143. # get uploaded files
  144. foreach($_FILES as $name => $value){
  145. $fields[$name] = $value;
  146. }
  147. # check vericode
  148. if($vericode) {
  149. //add support for captcha code - thanks to Djamoer
  150. $code = $_SESSION['veriword'] ? $_SESSION['veriword'] : $_SESSION['eForm.VeriCode'];
  151. if($fields['vericode']!=$code) {
  152. $vMsg[count($vMsg)]=$_lang['ef_failed_vericode'];
  153. $rClass['vericode']=$invalidClass; //added in 1.4.4
  154. }
  155. }
  156. # sanitize the values with slashes stripped to avoid remote execution of Snippets
  157. modx_sanitize_gpc($fields, array (
  158. '@<script[^>]*?>.*?</script>@si',
  159. '@&#(\d+);@e',
  160. '@\[\~(.*?)\~\]@si',
  161. '@\[\((.*?)\)\]@si',
  162. '@{{(.*?)}}@si',
  163. '@\[\+(.*?)\+\]@si',
  164. '@\[\*(.*?)\*\]@si',
  165. '@\[\[(.*?)\]\]@si',
  166. '@\[!(.*?)!\]@si'
  167. ));
  168. # validate fields
  169. foreach($fields as $name => $value) {
  170. $fld = $formats[$name];
  171. if ($fld) {
  172. $desc = $fld[1];
  173. $datatype = $fld[2];
  174. $isRequired = $fld[3];
  175. if ($isRequired==1 && $value=="" && $datatype!="file"){
  176. $rMsg[count($rMsg)]="$desc";
  177. $rClass[$name]=$requiredClass;
  178. }elseif( !empty($fld[5]) && $value!="" && $datatype!="file" ) {
  179. $value = validateField($value,$fld,$vMsg,$isDebug);
  180. if($value===false) $rClass[$name]=$invalidClass;
  181. //if returned value is not of type boolean replace value...
  182. elseif($value!==true) $fields[$name]=$value; //replace value.
  183. }else{ //value check
  184. switch ($datatype){
  185. case "integer":
  186. case "float":
  187. if (strlen($value)>0 && !is_numeric($value)){
  188. $vMsg[count($vMsg)]=$desc . $_lang["ef_invalid_number"];
  189. $rClass[$name]=$invalidClass;
  190. }
  191. break;
  192. case "date":
  193. if(strlen($value)==0) break;
  194. //corrected by xwisdom for php version differences
  195. $rt = strtotime($value); //php 5.1.0+ returns false while < 5.1.0 returns -1
  196. if ($rt===false||$rt===-1){
  197. $vMsg[count($vMsg)]=$desc . $_lang["ef_invalid_date"];
  198. $rClass[$name]=$invalidClass;
  199. }
  200. break;
  201. case "email":
  202. //stricter email validation - udated to allow + in local name part
  203. if (strlen($value)>0 && !preg_match(
  204. '/^(?:[a-z0-9+_-]+?\.)*?[a-z0-9_+-]+?@(?:[a-z0-9_-]+?\.)*?[a-z0-9_-]+?\.[a-z0-9]{2,5}$/i', $value) ){
  205. $vMsg[count($vMsg)] = isset($formats[$name][4]) ? $formats[$name][4] : $desc . $_lang["ef_invalid_email"];
  206. $rClass[$name]=$invalidClass;
  207. }
  208. break;
  209. case "file":
  210. if ($_FILES[$name]['error']==1 || $_FILES[$name]['error']==2){
  211. $vMsg[count($vMsg)]=$desc . $_lang['ef_upload_exceeded'];
  212. $rClass[$name]=$invalidClass;
  213. }elseif ($isRequired==1 && ($_FILES[$name] && $_FILES[$name]['type']=='')){
  214. $rMsg[count($rMsg)]=$desc;
  215. $rClass[$name]=$requiredClass;
  216. }elseif ($_FILES[$name]['tmp_name']){
  217. if( substr($fld[5],0,5)!="#LIST" || validateField($_FILES[$name]['name'],$fld,$vMsg,$isDebug) )
  218. $attachments[count($attachments)] = $_FILES[$name]['tmp_name'];
  219. else $rClass[$name]=$invalidClass;
  220. }
  221. break;
  222. case "html":
  223. case "checkbox":
  224. case "string":
  225. default:
  226. break;
  227. }
  228. }//end required test
  229. }
  230. }
  231. // Changed in 1.4.4.5 - now expects 4 parameters
  232. if ($eFormOnValidate) {
  233. if( $isDebug && !function_exists($eFormOnValidate))
  234. $fields['debug'] .= "eformOnValidate event: Could not find the function " . $eFormOnValidate;
  235. else
  236. if ($eFormOnValidate($fields,$vMsg,$rMsg,$rClass)===false) return;
  237. }
  238. if(count($vMsg)>0 || count($rMsg)>0){
  239. //New in 1.4.2 - classes are set in labels and form elements for invalid fields
  240. foreach($rClass as $n => $class){
  241. $fields[$n.'_class'] = $fields[$n.'_class']?$fields[$n.'_class'].' '. $class:$class;
  242. $fields[$n.'_vClass'] = $fields[$n.'_vClass']?$fields[$n.'_vClass'].' '. $class:$class;
  243. //work around for checkboxes
  244. if( isset($formats[$n][6] )){ //have separate id's for check and option tags - set classes as well
  245. foreach( explode(',',$formats[$n][6]) as $id)
  246. $fields[$id.'_vClass'] = $fields[$id.'_vClass'] ? $fields[$id.'_vClass'].' '. $class : $class;
  247. }
  248. }
  249. //add debugging info to fields array
  250. if($isDebug){
  251. ksort($fields);
  252. if($isDebug>1){
  253. $debugText .= "<br /><strong>Formats array:</strong><pre>". var_export($formats,true).'</pre>';
  254. $debugText .= "<br /><strong>Fields array:</strong><pre>". var_export($fields,true).'</pre>';
  255. $debugText .= "<br /><strong>Classes parsed :</strong><pre>" . var_export($rClass,true) ."</pre>";
  256. }
  257. $debugText .= "<br /><strong>eForm configuration:</strong><pre>\n". var_export($params,true).'</pre>';
  258. $fields['debug']=$debugText;
  259. }
  260. #set validation message
  261. $tmp = (count($rMsg)>0)?str_replace("{fields}", implode(", ",$rMsg),$_lang['ef_required_message']):"";
  262. $tmp .= implode("<br />",$vMsg);
  263. if(!strstr($tpl,'[+validationmessage+]'))
  264. $modx->setPlaceholder('validationmessage',str_replace('[+ef_wrapper+]', $tmp, $_lang['ef_validation_message']));
  265. else
  266. $fields['validationmessage'] .= str_replace('[+ef_wrapper+]', $tmp, $_lang['ef_validation_message']);
  267. } else {
  268. # format report fields
  269. foreach($fields as $name => $value) {
  270. $fld = $formats[$name];
  271. if ($fld) {
  272. $datatype = $fld[2];
  273. switch ($datatype) {
  274. case "integer":
  275. $value = number_format($value);
  276. break;
  277. case "float":
  278. $localeInfo = localeconv();
  279. $th_sep = empty($_lang['ef_thousands_separator'])?$localeInfo['thousands_sep']:$_lang['ef_thousands_separator'];
  280. $dec_point= $localeInfo['decimal_point'];
  281. $debugText .= 'Locale<pre>'.var_export($localeInfo,true).'</pre>';
  282. $value = number_format($value, 2, $dec_point, $th_sep);
  283. break;
  284. case "date":
  285. $format_string = isset($_lang['ef_date_format']) ? $_lang['ef_date_format'] : '%d-%b-%Y %H:%M:%S';
  286. $value = ($value)? strftime($format_string,strtotime($value)):"";
  287. $value=str_replace("00:00:00","",$value);// remove trailing zero time values
  288. break;
  289. case "html":
  290. // convert \n to <br />
  291. if(!$sendAsText ) $value = preg_replace('#(\n<br[ /]*?>|<br[ /]*?>\n|\n)#i','<br />',$value);
  292. break;
  293. case "file":
  294. // set file name
  295. if($value['type']!="" && $value['type']!=""){
  296. $value = $value["name"];
  297. $patharray = explode(((strpos($value,"/")===false)? "\\":"/"), $value);
  298. $value = $patharray[count($patharray)-1];
  299. }
  300. else {
  301. $value = "";
  302. }
  303. break;
  304. }
  305. $fields[$name] = $value;
  306. }
  307. }
  308. # set postdate
  309. $fields['postdate'] = strftime("%d-%b-%Y %H:%M:%S",time());
  310. //check against email injection and replace suspect content
  311. if( hasMailHeaders($fields) ){
  312. //send email to webmaster??
  313. if ($reportAbuse){ //set in snippet configuration tab
  314. $body = $_lang['ef_mail_abuse_message'];
  315. $body .="<table>";
  316. foreach($fields as $key => $value)
  317. $body .= "<tr><td>$key</td><td><pre>$value</pre></td></tr>";
  318. $body .="</table>";
  319. include_once "manager/includes/controls/class.phpmailer.php";
  320. # send abuse alert
  321. $mail = new PHPMailer();
  322. $mail->IsMail();
  323. $mail->IsHTML($isHtml);
  324. $mail->From = $modx->config['emailsender'];
  325. $mail->FromName = $modx->config['site_name'];
  326. $mail->Subject = $_lang['ef_mail_abuse_subject'];
  327. $mail->Body = $body;
  328. AddAddressToMailer($mail,"to",$modx->config['emailsender']);
  329. $mail->send(); //ignore mail errors in this case
  330. }
  331. //return empty form with error message
  332. //register css and/or javascript
  333. if( isset($startupSource) ) efRegisterStartupBlock($startupSource);
  334. return formMerge($tpl,array('validationmessage'=> $_lang['ef_mail_abuse_error']));
  335. }
  336. # added in 1.4.2 - Limit the time between form submissions
  337. if($submitLimit>0){
  338. if( time()<$submitLimit+$_SESSION[$formid.'_limit'] ){
  339. return formMerge($_lang['ef_submit_time_limit'],$fields);
  340. }
  341. else unset($_SESSION[$formid.'_limit'], $_SESSION[$formid.'_hash']); //time expired
  342. }
  343. # invoke OnBeforeMailSent event set by another script
  344. if ($eFormOnBeforeMailSent) {
  345. if( $isDebug && !function_exists($eFormOnBeforeMailSent))
  346. $fields['debug'] .= "eFormOnBeforeMailSent event: Could not find the function " . $eFormOnBeforeMailSent;
  347. elseif ($eFormOnBeforeMailSent($fields)===false) {
  348. if( isset($fields['validationmessage']) && !empty($fields['validationmessage']) ){
  349. //register css and/or javascript
  350. if( isset($startupSource) ) efRegisterStartupBlock($startupSource);
  351. return formMerge($tpl,$fields);
  352. }
  353. else
  354. return;
  355. }
  356. }
  357. if( $protectSubmit ){
  358. $hash = '';
  359. # create a hash of key data
  360. if(!is_numeric($protectSubmit)){ //supplied field names
  361. $protectSubmit = (strpos($protectSubmit,','))? explode(',',$protectSubmit):array($protectSubmit);
  362. foreach($protectSubmit as $fld) $hash .= isset($fields[$fld]) ? $fields[$fld] : '';
  363. }else //all required fields
  364. foreach($formats as $fld) $hash .= ($fld[3]==1) ? $fields[$fld[0]] : '';
  365. if($hash) $hash = md5($hash);
  366. if( $isDebug ) $debugText .= "<strong>SESSION HASH</strong>:".$_SESSION[$formid.'_hash']."<br />"."<b>FORM HASH</b>:".$hash."<br />";
  367. # check if already succesfully submitted with same data
  368. if( isset($_SESSION[$formid.'_hash']) && $_SESSION[$formid.'_hash'] == $hash && $hash!='' )
  369. return formMerge($_lang['ef_multiple_submit'],$fields);
  370. }
  371. $fields['disclaimer'] = ($disclaimer)? formMerge($disclaimer,$fields):"";
  372. $subject = isset($fields['subject'])?$fields['subject']:(($subject)? formMerge($subject,$fields):$category);
  373. $fields['subject'] = $subject; //make subject available in report & thank you page
  374. $report = ($report)? formMerge($report,$fields):"";
  375. $keywords = ($keywords)? formMerge($keywords,$fields):"";
  376. $from = ($from)? formMerge($from,$fields):"";
  377. $fromname = ($from)? formMerge($fromname,$fields):"";
  378. $to = formMerge($to,$fields);
  379. if(empty($to) || !strpos($to,'@')) $nomail=1;
  380. if(!$nomail){
  381. # check for mail selector field - select an email from to list
  382. if ($mselector && $fields[$mselector]) {
  383. $i = (int)$fields[$mselector];
  384. $ar = explode(",",$to);
  385. if ($i>0) $i--;
  386. if ($ar[$i]) $to = $ar[$i];
  387. else $to = $ar[0];
  388. }
  389. //set reply-to address
  390. //$replyto snippet parameter must contain email or fieldname
  391. if(!strstr($replyto,'@'))
  392. $replyto = ( $fields[$replyto] && strstr($fields[$replyto],'@') )?$fields[$replyto]:$from;
  393. # include PHP Mailer
  394. include_once "manager/includes/controls/class.phpmailer.php";
  395. # send form
  396. //defaults to html so only test sendasText
  397. $isHtml = ($sendAsText==1 || strstr($sendAsText,'report'))?false:true;
  398. if(!$noemail) {
  399. if($sendirect) $to = $fields['email'];
  400. $mail = new PHPMailer();
  401. $mail->IsMail();
  402. $mail->CharSet = $modx->config['modx_charset'];
  403. $mail->IsHTML($isHtml);
  404. $mail->From = $from;
  405. $mail->FromName = $fromname;
  406. $mail->Subject = $subject;
  407. $mail->Body = $report;
  408. AddAddressToMailer($mail,"replyto",$replyto);
  409. AddAddressToMailer($mail,"to",$to);
  410. AddAddressToMailer($mail,"cc",$cc);
  411. AddAddressToMailer($mail,"bcc",$bcc);
  412. AttachFilesToMailer($mail,$attachments);
  413. if(!$mail->send()) return 'Main mail: ' . $_lang['ef_mail_error'] . $mail->ErrorInfo;
  414. }
  415. # send user a copy of the report
  416. if($ccsender && $fields['email']) {
  417. $mail = new PHPMailer();
  418. $mail->IsMail();
  419. $mail->CharSet = $modx->config['modx_charset'];
  420. $mail->IsHTML($isHtml);
  421. $mail->From = $from;
  422. $mail->FromName = $fromname;
  423. $mail->Subject = $subject;
  424. $mail->Body = $report;
  425. AddAddressToMailer($mail,"to",$fields['email']);
  426. AttachFilesToMailer($mail,$attachments);
  427. if(!$mail->send()) return 'CCSender: ' . $_lang['ef_mail_error'] . $mail->ErrorInfo;
  428. }
  429. # send auto-respond email
  430. //defaults to html so only test sendasText
  431. $isHtml = ($sendAsText==1 || strstr($sendAsText,'autotext'))?false:true;
  432. if ($autotext && $fields['email']!='') {
  433. $autotext = formMerge($autotext,$fields);
  434. $mail = new PHPMailer();
  435. $mail->IsMail();
  436. $mail->CharSet = $modx->config['modx_charset'];
  437. $mail->IsHTML($isHtml);
  438. $mail->From = ($autosender)? $autosender:$from;
  439. $mail->FromName = ($autoSenderName)?$autoSenderName:$fromname;
  440. $mail->Subject = $subject;
  441. $mail->Body = $autotext;
  442. AddAddressToMailer($mail,"to",$fields['email']);
  443. if(!$mail->send()) return 'AutoText: ' . $_lang['ef_mail_error'] . $mail->ErrorInfo;
  444. }
  445. //defaults to text - test for sendAsHtml
  446. $isHTML = ($sendAsHTML==1 || strstr($sendAsHtml,'mobile'))?true:false;
  447. # send mobile email
  448. if ($mobile && $mobiletext) {
  449. $mobiletext = formMerge($mobiletext,$fields);
  450. $mail = new PHPMailer();
  451. $mail->IsMail();
  452. $mail->CharSet = $modx->config['modx_charset'];
  453. $mail->IsHTML($isHtml);
  454. $mail->From = $from;
  455. $mail->FromName = $fromname;
  456. $mail->Subject = $subject;
  457. $mail->Body = $mobiletext;
  458. AddAddressToMailer($mail,"to",$mobile);
  459. $mail->send();
  460. }
  461. }//end test nomail
  462. # added in 1.4.2 - Protection against multiple submit with same form data
  463. if($protectSubmit) $_SESSION[$formid.'_hash'] = $hash; //hash is set earlier
  464. # added in 1.4.2 - Limit the time between form submissions
  465. if($submitLimit>0) $_SESSION[$formid.'_limit'] = time();
  466. # invoke OnMailSent event set by another script
  467. if ($eFormOnMailSent) {
  468. if( $isDebug && !function_exists($eFormOnMailSent) )
  469. $fields['debug'] .= "eFormOnMailSent event: Could not find the function" . $eFormOnMailSent;
  470. else
  471. if ($eFormOnMailSent($fields)===false) return;
  472. }
  473. if($isDebug){
  474. $debugText .="<strong>Mail Headers:</strong><br />From: $from ($fromname)<br />Reply-to:$replyto<br />To: $to<br />Subject: $subject<br />CC: $cc<br /> BCC:$bcc<br />";
  475. if($isDebug>1){
  476. $debugText .= "<br /><strong>Formats array:</strong><pre>". var_export($formats,true).'</pre>';
  477. $debugText .= "<br /><strong>Fields array:</strong><pre>". var_export($fields,true).'</pre>';
  478. }
  479. $fields['debug'] = $debugText;
  480. }
  481. # show or redirect to thank you page
  482. if ($gid==$modx->documentIdentifier){
  483. if(!empty($thankyou) ){
  484. if($isDebug && !strstr($thankyou,'[+debug+]')) $thankyou .= '[+debug+]';
  485. if( isset($startupSource) ) efRegisterStartupBlock($startupSource,true); //skip scripts
  486. if( $sendAsText ){
  487. foreach($formats as $key => $fmt)
  488. if($fmt[2]=='html') $fields[$key] = str_replace("\n",'<br />',$fields[$key]);
  489. }
  490. $thankyou = formMerge($thankyou,$fields);
  491. return $thankyou;
  492. }else{
  493. return $_lang['ef_thankyou_message'];
  494. }
  495. }
  496. else {
  497. $url = $modx->makeURL($gid);
  498. $modx->sendRedirect($url);
  499. }
  500. return; // stop here
  501. }
  502. }else{ //not postback
  503. //add debugging info to fields array
  504. if($isDebug){
  505. $debugText .= "<br /><strong>eForm configuration:</strong><pre>". var_export($params,true).'</pre>';
  506. $fields['debug']=$debugText;
  507. }
  508. //strip the eform attribute
  509. $regExpr = "#eform=([\"'])[^\\1]*?\\1#si";
  510. $tpl = preg_replace($regExpr,'',$tpl);
  511. }
  512. // set vericode
  513. if($vericode) {
  514. $_SESSION['eForm.VeriCode'] = $fields['vericode'] = substr(uniqid(''),-5);
  515. $fields['verimageurl'] = $modx->config['base_url'].'manager/includes/veriword.php?rand='.rand();
  516. }
  517. # get SESSION data - thanks to sottwell
  518. if($sessionVars){
  519. $sessionVars = (strpos($sessionVars,',',0))?explode(',',$sessionVars):array($sessionVars);
  520. foreach( $sessionVars as $varName ){
  521. if( empty($varName) ) continue;
  522. $varName = trim($varName);
  523. if( isset($_SESSION[$varName]) && !empty($_SESSION[$varName]) )
  524. $fields[$varName] = ( isset($fields[$varName]) && $postOverides )?$fields[$varName]:$_SESSION[$varName];
  525. }
  526. }
  527. # invoke OnBeforeFormMerge event set by another script
  528. if ($eFormOnBeforeFormMerge) {
  529. if( $isDebug && !function_exists($eFormOnBeforeFormMerge))
  530. $fields['debug'] .= "eFormOnBeforeFormMerge event: Could not find the function " . $eFormOnBeforeFormMerge;
  531. else
  532. if ($eFormOnBeforeFormMerge($fields)===false) return;
  533. }
  534. # build form
  535. if($isDebug && !$fields['debug']) $fields['debug'] = $debugText;
  536. if($isDebug && !strstr($tpl,'[+debug+]')) $tpl .= '[+debug+]';
  537. //register css and/or javascript
  538. if( isset($startupSource) ) efRegisterStartupBlock($startupSource);
  539. return formMerge($tpl,$fields);
  540. }
  541. # Form Merge
  542. function formMerge($docText, $docFields, $vClasses='') {
  543. global $formats;
  544. $lastitems;
  545. if(!$docText) return '';
  546. preg_match_all('~\[\+(.*?)\+\]~', $docText, $matches);
  547. for($i=0;$i<count($matches[1]);$i++) {
  548. $name = $matches[1][$i];
  549. list($listName,$listValue) = explode(":",$name);
  550. $value = isset($docFields[$listName])? $docFields[$listName]:'';
  551. // support for multi checkbox, radio and select - Djamoer
  552. if(is_array($value)) $value=implode(', ', $value);
  553. $fld = $formats[$name];
  554. if (!isset($fld)){
  555. // listbox, checkbox, radio select
  556. $colonPost = strpos($name, ':');
  557. $listName = substr($name, 0, $colonPost);
  558. $listValue = substr($name, $colonPost+1);
  559. $datatype = $formats[$listName][2];
  560. if(is_array($docFields[$listName])) {
  561. if($datatype=="listbox" && in_array($listValue, $docFields[$listName])) $docText = str_replace("[+$listName:$listValue+]","selected='selected'",$docText);
  562. if(($datatype=="checkbox"||$datatype=="radio") && in_array($listValue, $docFields[$listName])) $docText = str_replace("[+$listName:$listValue+]","checked='checked'",$docText);
  563. }
  564. else {
  565. if($datatype=="listbox" && $listValue==$docFields[$listName]) $docText = str_replace("[+$listName:$listValue+]","selected='selected'",$docText);
  566. if(($datatype=="checkbox"||$datatype=="radio") && $listValue==$docFields[$listName]) $docText = str_replace("[+$listName:$listValue+]","checked='checked'",$docText);
  567. }
  568. }
  569. if(strpos($name,":")===false) $docText = str_replace("[+$name+]",$value,$docText);
  570. else {
  571. // this might be a listbox item.
  572. // we'll remove this field later
  573. $lastitems[count($lastitems)]="[+$name+]";
  574. }
  575. }
  576. $lastitems[count($lastitems)] = "class=\"\""; //removal off empty class attributes
  577. $docText = str_replace($lastitems,"",$docText);
  578. return $docText;
  579. }
  580. # Adds Addresses to Mailer
  581. function AddAddressToMailer(&$mail,$type,$addr){
  582. $a = explode(",",$addr);
  583. for($i=0;$i<count($a);$i++){
  584. if(!empty($a[$i])) {
  585. if ($type=="to") $mail->AddAddress($a[$i]);
  586. elseif ($type=="cc") $mail->AddCC($a[$i]);
  587. elseif ($type=="bcc") $mail->AddBCC($a[$i]);
  588. elseif ($type=="replyto") $mail->AddReplyTo($a[$i]);
  589. }
  590. }
  591. }
  592. # Attach Files to Mailer
  593. function AttachFilesToMailer(&$mail,&$attachFiles) {
  594. if(count($attachFiles)>0){
  595. foreach($attachFiles as $attachFile){
  596. if(!file_exists($attachFile)) continue;
  597. $FileName = $attachFile;
  598. $contentType = "application/octetstream";
  599. if (is_uploaded_file($attachFile)){
  600. foreach($_FILES as $n => $v){
  601. if($_FILES[$n]['tmp_name']==$attachFile) {
  602. $FileName = $_FILES[$n]['name'];
  603. $contentType = $_FILES[$n]['type'];
  604. }
  605. }
  606. }
  607. $patharray = explode(((strpos($FileName,"/")===false)? "\\":"/"), $FileName);
  608. $FileName = $patharray[count($patharray)-1];
  609. $mail->AddAttachment($attachFile,$FileName,"base64",$contentType);
  610. }
  611. }
  612. }
  613. /*--- Form Parser stuff----------------------*/
  614. function eFormParseTemplate($tpl, $isDebug=false ){
  615. global $modx,$formats,$optionsName,$_lang,$debugText,$fields,$validFormId;
  616. global $efPostBack;
  617. $formats =""; //clear formats so values don't persist through multiple snippet calls
  618. $labels = "";
  619. $regExpr = "#(<label[^>]*?>)(.*?)</label>#si";;
  620. preg_match_all($regExpr,$tpl,$matches);
  621. foreach($matches[1] as $key => $fld){
  622. $attr = attr2array($fld);
  623. if(isset($attr['for'])){
  624. $name = substr($attr['for'],1,-1);
  625. //add class to fields array
  626. $fields[$name."_vClass"] = isset($attr['class'])?substr($attr['class'],1,-1):'';
  627. $labels[$name] = strip_tags($matches[2][$key]);
  628. //create placeholder for class
  629. $attr['class'] = '"[+'.$name.'_vClass+]"';
  630. $newTag = buildTagPlaceholder('label',$attr,$name);
  631. $tpl = str_replace($fld,$newTag,$tpl);
  632. }
  633. }
  634. //retrieve all the form fields
  635. $regExpr = "#(<(input|select|textarea)[^>]*?>)#si";
  636. preg_match_all($regExpr,$tpl,$matches);
  637. $fieldTypes = $matches[2];
  638. $fieldTags = $matches[1];
  639. for($i=0;$i<count($fieldTypes);$i++){
  640. $type = $fieldTypes[$i];
  641. //get array of html attributes
  642. $tagAttributes = attr2array($fieldTags[$i]);
  643. //attribute values are stored including quotes
  644. //strip quotes as well as any brackets to get the raw name
  645. $name = str_replace(array("'",'"','[',']'),'',$tagAttributes['name']);
  646. #skip vericode field - updated in 1.4.4
  647. #special case. We need to set the class placeholder but forget about the rest
  648. if($name=="vericode"){
  649. if(isset($tagAttributes['class'])){
  650. $fields[$name.'_class'] = substr($tagAttributes['class'],1,-1);
  651. }
  652. $tagAttributes['class'] = '"[+'.$name.'_class+]"';
  653. $tagAttributes['value'] = '';
  654. $newTag = buildTagPlaceholder('input',$tagAttributes,$name);
  655. $tpl = str_replace($fieldTags[$i],$newTag,$tpl);
  656. continue;
  657. }
  658. //store the field options
  659. if (isset($tagAttributes[$optionsName])){
  660. //split to max of 5 so validation rule can contain ':'
  661. $formats[$name] = explode(":",stripTagQuotes($tagAttributes[$optionsName]),5) ;
  662. array_unshift($formats[$name],$name);
  663. }else{
  664. if(!isset($formats[$name])) $formats[$name]=array($name,'','',0);
  665. }
  666. //added for 1.4 - use label if it is defined
  667. if(empty($formats[$name][1]))
  668. $formats[$name][1]=(isset($labels[$name])) ? $labels[$name] : $name;
  669. if(isset($id)) $formats[6] = $id; //added in 1.4.4.1
  670. unset($tagAttributes[$optionsName]);
  671. //added in 1.4.2 - add placeholder to class attribute
  672. if(isset($tagAttributes['class'])){
  673. $fields[$name.'_class'] = substr($tagAttributes['class'],1,-1);
  674. }
  675. $tagAttributes['class'] = '"[+'.$name.'_class+]"';
  676. switch($type){
  677. case "select":
  678. //replace with 'cleaned' tag and added placeholder
  679. $newTag = buildTagPlaceholder('select',$tagAttributes,$name);
  680. $tpl = str_replace($fieldTags[$i],$newTag,$tpl);
  681. if($formats[$name]) $formats[$name][2]='listbox';
  682. //Get the whole select block with option tags
  683. //escape any regex characters!
  684. $regExp = "#<select [^><]*?name=".preg_quote($tagAttributes['name'],'#')."[^>]*?".">(.*?)</select>#si";
  685. preg_match($regExp,$tpl,$matches);
  686. $optionTags = $matches[1];
  687. $select = $newSelect = $matches[0];
  688. //get separate option tags and split them up
  689. preg_match_all("#(<option [^>]*?>)#si",$optionTags,$matches);
  690. $validValues = array();
  691. foreach($matches[1] as $option){
  692. $attr = attr2array($option);
  693. //* debug */ print __LINE__.': <pre>'.print_r($attr,true) .'</pre><br />';
  694. $value = substr($attr['value'],1,-1); //strip outer quotes
  695. if( trim($value)!='' ) $validValues[] = $value;
  696. $newTag = buildTagPlaceholder('option',$attr,$name);
  697. $newSelect = str_replace($option,$newTag,$newSelect);
  698. //if no postback, retain any checked values
  699. if(!$efPostBack && !empty($attr['selected'])) $fields[$name][]=$value;
  700. }
  701. //replace complete select block
  702. $tpl = str_replace($select,$newSelect,$tpl);
  703. //add valid values to formats... (extension to $formats)
  704. if($formats[$name] && !$formats[$name][5]){
  705. $formats[$name][4] = $_lang['ef_failed_default'];
  706. //convert commas in values to something else !
  707. $formats[$name][5]= "#LIST " . implode(",",str_replace(',','&#44;',$validValues));
  708. }
  709. break;
  710. case "textarea":
  711. // add support for maxlength attribute for textarea
  712. // attribute get's stripped form form //
  713. if( $tagAttributes['maxlength'] ){
  714. $formats[$name][$_dfnMaxlength] == $tagAttributes['maxlength'];
  715. unset($tagAttributes['maxlength']);
  716. }
  717. $newTag = buildTagPlaceholder($type,$tagAttributes,$name);
  718. $regExp = "#<textarea [^>]*?name=" . $tagAttributes["name"] . "[^>]*?" . ">(.*?)</textarea>#si";
  719. preg_match($regExp,$tpl,$matches);
  720. //if nothing Posted retain the content between start/end tags
  721. $placeholderValue = ($efPostBack)?"[+$name+]":$matches[1];
  722. $tpl = str_replace($matches[0],$newTag.$placeholderValue."</textarea>",$tpl);
  723. break;
  724. default: //all the rest, ie. "input"
  725. $newTag = buildTagPlaceholder($type,$tagAttributes,$name);
  726. $fieldType = stripTagQuotes($tagAttributes['type']);
  727. //validate on maxlength...
  728. if( $fieldType=='text' && $tagAttributes['maxlength'] ){
  729. $formats[$name][$_dfnMaxlength] == $tagAttributes['maxlength'];
  730. }
  731. if($formats[$name] && !$formats[$name][2]) $formats[$name][2]=($fieldType=='text')?"string":$fieldType;
  732. //populate automatic validation values for hidden, checkbox and radio fields
  733. if($fieldType=='hidden'){
  734. if(!$isDebug) $formats[$name][1] = "[undefined]"; //do not want to disclose hidden field names
  735. if(!isset($formats[$name][4])) $formats[$name][4]= $_lang['ef_tamper_attempt'];
  736. if(!isset($formats[$name][5])) $formats[$name][5]= "#VALUE ". stripTagQuotes($tagAttributes['value']);
  737. }elseif($fieldType=='checkbox' || $fieldType=='radio'){
  738. $formats[$name][4]= $_lang['ef_failed_default'];
  739. $formats[$name][5] .= isset($formats[$name][5])?",":"#LIST ";
  740. //convert embedded comma's in values!
  741. $formats[$name][5] .= str_replace(',','&#44;',stripTagQuotes($tagAttributes['value']));
  742. //store the id as well
  743. //if no postback, retain any checked values
  744. if(!$efPostBack && !empty($tagAttributes['checked'])) $fields[$name][]=stripTagQuotes($tagAttributes['value']);
  745. //
  746. $formats[$name][6] .= ( isset($formats[$name][6])?",":"").stripTagQuotes($tagAttributes['id']);
  747. }elseif(empty($fields[$name])){ //plain old text input field
  748. //retain default value set in form template if not already set in code
  749. $fields[$name] = stripTagQuotes($tagAttributes['value']);
  750. }
  751. $tpl = str_replace($fieldTags[$i],$newTag,$tpl);
  752. break;
  753. }
  754. }
  755. if($isDebug>2) $debugText .= "<strong>Parsed template</strong><p style=\"border:1px solid black;padding:2px;\">" . str_replace("\n",'<br />',str_replace('+','&#043;',htmlspecialchars($tpl)))."</p><hr>";
  756. return $tpl;
  757. }
  758. function stripTagQuotes($value){
  759. return substr($value,1,-1);
  760. }
  761. function buildTagPlaceholder($tag,$attributes,$name){
  762. $type = stripTagQuotes($attributes["type"]);
  763. $quotedValue = $attributes['value'];
  764. $val = stripTagQuotes($quotedValue);
  765. foreach ($attributes as $k => $v)
  766. $t .= ($k!='value' && $k!='checked' && $k!='selected')?" $k=$v":"";
  767. switch($tag){
  768. case "select":
  769. return "<$tag$t>"; //only the start tag mind you
  770. case "option":
  771. return "<$tag$t value=".$quotedValue." [+$name:$val+]>";
  772. case "input":
  773. switch($type){
  774. case 'radio':
  775. case 'checkbox':
  776. return "<input$t value=".$quotedValue." [+$name:$val+] />";
  777. case 'text':
  778. if($name=='vericode') return "<input$t value=\"\" />";
  779. //else pass on to next
  780. case 'password':
  781. return "<input$t value=\"[+$name+]\" />";
  782. default: //leave as is - no placeholder
  783. return "<input$t value=".$quotedValue." />";
  784. }
  785. case "file": //no placeholder!
  786. case "textarea": //placeholder needs to be added in calling code
  787. return "<$tag$t>";
  788. case "label":
  789. return "<$tag$t>";
  790. default:
  791. return "<input$t value=\"[+$name+]\" />";
  792. } // switch
  793. return ""; //if we've arrived here we're in trouble
  794. }
  795. function attr2array($tag){
  796. $expr = "#([a-z0-9_]*?)=(([\"'])[^\\3]*?\\3)#si";
  797. preg_match_all($expr,$tag,$matches);
  798. foreach($matches[1] as $i => $key)
  799. $rt[$key]= $matches[2][$i];
  800. return $rt;
  801. }
  802. function validateField($value,$fld,&$vMsg,$isDebug=false){
  803. global $modx,$_lang, $debugText,$fields;
  804. $output = true;
  805. $desc = $fld[1];
  806. $fldMsg = trim($fld[4]);
  807. if(empty($fld[5])) return $output; //if no rule value validates
  808. list($cmd,$param) = explode(" ",trim($fld[5]),2);
  809. $cmd = strtoupper(trim($cmd));
  810. if (substr($cmd,0,1)!='#'){
  811. $vMsg[count($vMsg)] = "$desc &raquo;" . $_lang['ef_error_validation_rule'];
  812. return false;
  813. }
  814. $valList = (is_array($value))?$value:array($value);
  815. //init vars
  816. $errMsg='';
  817. unset($vlist);
  818. for($i=0;$i<count($valList);$i++){
  819. $value = $valList[$i]; //re-using $value, destroying original!!
  820. switch ($cmd) {
  821. //really only used internally for hidden fields
  822. case "#VALUE":
  823. if($value!=$param) $errMsg = $_lang['ef_failed_default'];
  824. break;
  825. case "#RANGE":
  826. if(!isset($vlist)) $vlist = explode(',',strtolower(trim($param))); //cached
  827. //the crude way first - will have to refine this
  828. foreach($vlist as $p){
  829. if( strpos($p,'~')>0)
  830. $range = explode('~',$p);
  831. else
  832. $range = array($p,$p); //yes,.. I know - cheating :)
  833. if($isDebug && (!is_numeric($range[0]) || !is_numeric($range[1])) )
  834. $modx->messageQuit('Error in validating form field!', '',$false,E_USER_WARNING,__FILE__,'','#RANGE rule contains non-numeric values: '.$fld[5],__LINE__);
  835. sort($range);
  836. if( $value>=$range[0] && $value<=$range[1] ) break 2; //valid
  837. }
  838. $errMsg = $_lang['ef_failed_range'];
  839. break;
  840. case "#LIST": // List of comma separated values (not case sensitive)
  841. //added in 1.4 - file upload filetype test
  842. //FS#960 - removed trimming of $param - values with leading or trailing spaces would always fail validation
  843. if($fld[2]=='file')$value = substr($value,strrpos($value,'.')+1); //file extension
  844. if(!isset($vlist)){
  845. $vlist = explode(',',strtolower($param)); //cached
  846. foreach($vlist as $k =>$v ) $vlist[$k]=str_replace('&#44;',',',$v);
  847. } //changes to make sure embedded commma's in values are recognized
  848. if( $isDebug && count($vlist)==1 && empty($vlist[0]) ){
  849. //if debugging bail out big time
  850. $modx->messageQuit('Error in validating form field!', '',$false,E_USER_WARNING,__FILE__,'','#LIST rule declared but no list values supplied: '.$fld[5],__LINE__);
  851. }elseif(!in_array(strtolower($value),$vlist))
  852. $errMsg = ($fld[2]=='file')? $_lang["ef_failed_upload"]: $_lang['ef_failed_list'];
  853. break;
  854. case "#SELECT": //validates against a list of values from the cms database
  855. #cache all this
  856. if( !isset($vlist) ) {
  857. $rt = array();
  858. $param = str_replace('{DBASE}',$modx->db->config['dbase'],$param);
  859. $param = str_replace('{PREFIX}',$modx->db->config['table_prefix'],$param);
  860. //added in 1.4
  861. if( preg_match("/{([^}]*?)\}/",$param,$matches) ){
  862. $tmp = $modx->db->escape(formMerge('[+'.$matches[1].'+]',$fields));
  863. $param = str_replace('{'.$matches[1].'}',$tmp,$param);
  864. }
  865. $rs = $modx->db->query("SELECT $param;");
  866. //select value from 1st field in records only (not case sensitive)
  867. while( $v = $modx->db->getValue($rs) ) $vlist[]=strtolower($v);
  868. }
  869. if(!is_array($vlist)){
  870. //WARNING! if not debugging (and query fails) error is ignored, and value will validate!!
  871. //version 1.4 - replaced fatal error with friendly debug message when debugging
  872. $debugText .= ($isDebug)? "'<strong>$fld[1]</strong>' ".$_lang['ef_sql_no_result'].'<br />':'';
  873. }elseif(!in_array(strtolower($value),$vlist)){
  874. $errMsg = $_lang['ef_failed_list'];
  875. }
  876. break;
  877. case "#EVAL": // php code should return true or false
  878. $tmp = $cmd; //just in case eval destroys cmd
  879. if( eval($param)===false )
  880. $errMsg = $_lang['ef_failed_eval'];
  881. if($isDebug) $debugText .= "<strong>$fld[1]</strong>: ".$_lang['ef_eval_deprecated']." $param";
  882. $cmd = $tmp;
  883. break;
  884. //added in 1.4
  885. case "#FUNCTION":
  886. $tmp = $cmd; //just in case function destroys cmd
  887. if( function_exists($param) )
  888. if( !@$param($value) ) $errMsg = $_lang['ef_failed_eval'];
  889. else
  890. if($isDebug) $debugText .= "<strong>$fld[1]</strong>: ".$_lang['ef_no_function']." $param";
  891. $cmd = $tmp;
  892. break;
  893. case "#REGEX":
  894. if( !$tmp=preg_match($param,$value) )
  895. $errMsg = $_lang['ef_failed_ereg'];
  896. if($isDebug && $tmp===false ) $debugText .= "<strong>$fld[1]</strong>: ".$_lang['ef_regex_error']." $param";
  897. break;
  898. case "#FILTER":
  899. $valList[$i] = filterEformValue($value,$param);
  900. break;
  901. default:
  902. $errMsg = $_lang['ef_error_validation_rule'];
  903. }//end switch
  904. if($isDebug) {
  905. $debugText .="'<strong>$fld[1]</strong>' ";
  906. $debugText .= (empty($errMsg))?'passed':'<span style="color:red;">Failed</span>';
  907. $debugText .= " using rule: $cmd ".$param.', (input='.htmlspecialchars($valList[$i]).")<br />\n";
  908. }
  909. if(!empty($errMsg)){
  910. $errMsg = ($fldMsg)?"$desc &raquo; $fldMsg":"$desc &raquo; $errMsg";
  911. $vMsg[count($vMsg)] = $errMsg;
  912. $output=false;
  913. break; //quit testing more values
  914. }
  915. }//end for
  916. //make sure we have correct return value in case of #filter
  917. $valList = (!is_array($value))?implode('',$valList):$valList;
  918. return ($cmd=="#FILTER")?$valList:$output;
  919. }//end validateField
  920. function filterEformValue($value,$param){
  921. list($cmd,$param) = explode(" ",trim($param),2);
  922. $cmd = trim($cmd);
  923. switch(strtoupper($cmd)){
  924. case "#REGEX":
  925. list($src,$dst) = explode("||",$param,2);
  926. $value = ( $v = preg_replace($src,$dst,$value) )?$v:$value;
  927. break;
  928. case "#LIST":
  929. $param = explode("||",$param,2);
  930. $src = strpos($param[0],',')?explode(',',$param[0]):$param[0];
  931. $dst = strpos($param[1],',')?explode(',',$param[1]):$param[1];
  932. $value = str_replace($src,$dst,$value);
  933. break;
  934. case "#EVAL":
  935. $value = ($v = @eval($param))?$v:$value;
  936. break;
  937. }
  938. return $value;
  939. }
  940. function efLoadTemplate($key){
  941. global $modx;
  942. if( strlen($key)>50 ) return $key;
  943. $tpl = false;
  944. if( is_numeric($key) ) { //get from document id
  945. //try unpublished docs first
  946. $tpl = ( $doc=$modx->getDocument($key,'content',0) )? $doc['content'] :false;
  947. if(!$tpl )
  948. $tpl = ( $doc=$modx->getDocument($key,'content',1) )? $doc['content'] : false;
  949. }elseif( $key ){
  950. $tpl = ( $doc=$modx->getChunk($key) )? $doc : false;
  951. //try snippet if chunk is not found
  952. if(!$tpl) $tpl = ( $doc=$modx->runSnippet($key) )? $doc : false;
  953. }
  954. return $tpl;
  955. }
  956. # registers css and/or javascript to modx class
  957. function efRegisterStartupBlock($src_array,$noScript=false){
  958. global $modx;
  959. if(!array($src_array)) return;
  960. foreach($src_array as $item){
  961. list($src,$type) = $item;
  962. //skip scripts if told to do so
  963. if($type=='javascript' && $noScript) continue;
  964. //try to load from document or chunk
  965. if( $tmp = efLoadtemplate($src) )
  966. $src = $tmp;
  967. $src=trim($src);
  968. if ( $type=='css' )
  969. $modx->regClientCSS($src);
  970. elseif ( $type == 'javascript' )
  971. $modx->regClientStartupScript($src);
  972. else
  973. $modx->regClientStartupHTMLBlock($src);
  974. }//end foreach
  975. }
  976. /**
  977. * adapted from http://php.mirrors.ilisys.com.au/manual/en/ref.mail.php
  978. * If any field contains newline followed by email-header specific string it is replaced by a harmless substitute
  979. * (we hope) If any subsitutiosn are made the function returns true
  980. * Currently tests for
  981. * Content-Transfer-Encoding:
  982. * MIME-Version:
  983. * content-type:
  984. * to:
  985. * cc:
  986. * bcc:
  987. */
  988. function hasMailHeaders( &$fields ){
  989. $injectionAttempt = false;
  990. $re = "/(%0A|%0D|\n+|\r+)(Content-Transfer-Encoding:|MIME-Version:|content-type:|to:|cc:|bcc:)/i";
  991. foreach($fields as $fld => $text){
  992. if( ($match = preg_replace($re,'\\[\2]\\', $text))!=$text ){
  993. $injectionAttempt = true;
  994. $fields[$fld]=$match; //replace with 'disabled' version
  995. }
  996. }
  997. return ($injectionAttempt)?true:false;
  998. }
  999. ?>